| .. | .. |
|---|
| 25 | 25 | #define SIRF_ON_OFF_PULSE_TIME 100 |
|---|
| 26 | 26 | #define SIRF_ACTIVATE_TIMEOUT 200 |
|---|
| 27 | 27 | #define SIRF_HIBERNATE_TIMEOUT 200 |
|---|
| 28 | +/* |
|---|
| 29 | + * If no data arrives for this time, we assume that the chip is off. |
|---|
| 30 | + * REVISIT: The report cycle is configurable and can be several minutes long, |
|---|
| 31 | + * so this will only work reliably if the report cycle is set to a reasonable |
|---|
| 32 | + * low value. Also power saving settings (like send data only on movement) |
|---|
| 33 | + * might things work even worse. |
|---|
| 34 | + * Workaround might be to parse shutdown or bootup messages. |
|---|
| 35 | + */ |
|---|
| 36 | +#define SIRF_REPORT_CYCLE 2000 |
|---|
| 28 | 37 | |
|---|
| 29 | 38 | struct sirf_data { |
|---|
| 30 | 39 | struct gnss_device *gdev; |
|---|
| 31 | 40 | struct serdev_device *serdev; |
|---|
| 32 | 41 | speed_t speed; |
|---|
| 33 | 42 | struct regulator *vcc; |
|---|
| 43 | + struct regulator *lna; |
|---|
| 34 | 44 | struct gpio_desc *on_off; |
|---|
| 35 | 45 | struct gpio_desc *wakeup; |
|---|
| 36 | 46 | int irq; |
|---|
| 37 | 47 | bool active; |
|---|
| 48 | + |
|---|
| 49 | + struct mutex gdev_mutex; |
|---|
| 50 | + bool open; |
|---|
| 51 | + |
|---|
| 52 | + struct mutex serdev_mutex; |
|---|
| 53 | + int serdev_count; |
|---|
| 54 | + |
|---|
| 38 | 55 | wait_queue_head_t power_wait; |
|---|
| 39 | 56 | }; |
|---|
| 57 | + |
|---|
| 58 | +static int sirf_serdev_open(struct sirf_data *data) |
|---|
| 59 | +{ |
|---|
| 60 | + int ret = 0; |
|---|
| 61 | + |
|---|
| 62 | + mutex_lock(&data->serdev_mutex); |
|---|
| 63 | + if (++data->serdev_count == 1) { |
|---|
| 64 | + ret = serdev_device_open(data->serdev); |
|---|
| 65 | + if (ret) { |
|---|
| 66 | + data->serdev_count--; |
|---|
| 67 | + goto out_unlock; |
|---|
| 68 | + } |
|---|
| 69 | + |
|---|
| 70 | + serdev_device_set_baudrate(data->serdev, data->speed); |
|---|
| 71 | + serdev_device_set_flow_control(data->serdev, false); |
|---|
| 72 | + } |
|---|
| 73 | + |
|---|
| 74 | +out_unlock: |
|---|
| 75 | + mutex_unlock(&data->serdev_mutex); |
|---|
| 76 | + |
|---|
| 77 | + return ret; |
|---|
| 78 | +} |
|---|
| 79 | + |
|---|
| 80 | +static void sirf_serdev_close(struct sirf_data *data) |
|---|
| 81 | +{ |
|---|
| 82 | + mutex_lock(&data->serdev_mutex); |
|---|
| 83 | + if (--data->serdev_count == 0) |
|---|
| 84 | + serdev_device_close(data->serdev); |
|---|
| 85 | + mutex_unlock(&data->serdev_mutex); |
|---|
| 86 | +} |
|---|
| 40 | 87 | |
|---|
| 41 | 88 | static int sirf_open(struct gnss_device *gdev) |
|---|
| 42 | 89 | { |
|---|
| .. | .. |
|---|
| 44 | 91 | struct serdev_device *serdev = data->serdev; |
|---|
| 45 | 92 | int ret; |
|---|
| 46 | 93 | |
|---|
| 47 | | - ret = serdev_device_open(serdev); |
|---|
| 48 | | - if (ret) |
|---|
| 49 | | - return ret; |
|---|
| 94 | + mutex_lock(&data->gdev_mutex); |
|---|
| 95 | + data->open = true; |
|---|
| 96 | + mutex_unlock(&data->gdev_mutex); |
|---|
| 50 | 97 | |
|---|
| 51 | | - serdev_device_set_baudrate(serdev, data->speed); |
|---|
| 52 | | - serdev_device_set_flow_control(serdev, false); |
|---|
| 98 | + ret = sirf_serdev_open(data); |
|---|
| 99 | + if (ret) { |
|---|
| 100 | + mutex_lock(&data->gdev_mutex); |
|---|
| 101 | + data->open = false; |
|---|
| 102 | + mutex_unlock(&data->gdev_mutex); |
|---|
| 103 | + return ret; |
|---|
| 104 | + } |
|---|
| 53 | 105 | |
|---|
| 54 | 106 | ret = pm_runtime_get_sync(&serdev->dev); |
|---|
| 55 | 107 | if (ret < 0) { |
|---|
| .. | .. |
|---|
| 61 | 113 | return 0; |
|---|
| 62 | 114 | |
|---|
| 63 | 115 | err_close: |
|---|
| 64 | | - serdev_device_close(serdev); |
|---|
| 116 | + sirf_serdev_close(data); |
|---|
| 117 | + |
|---|
| 118 | + mutex_lock(&data->gdev_mutex); |
|---|
| 119 | + data->open = false; |
|---|
| 120 | + mutex_unlock(&data->gdev_mutex); |
|---|
| 65 | 121 | |
|---|
| 66 | 122 | return ret; |
|---|
| 67 | 123 | } |
|---|
| .. | .. |
|---|
| 71 | 127 | struct sirf_data *data = gnss_get_drvdata(gdev); |
|---|
| 72 | 128 | struct serdev_device *serdev = data->serdev; |
|---|
| 73 | 129 | |
|---|
| 74 | | - serdev_device_close(serdev); |
|---|
| 130 | + sirf_serdev_close(data); |
|---|
| 75 | 131 | |
|---|
| 76 | 132 | pm_runtime_put(&serdev->dev); |
|---|
| 133 | + |
|---|
| 134 | + mutex_lock(&data->gdev_mutex); |
|---|
| 135 | + data->open = false; |
|---|
| 136 | + mutex_unlock(&data->gdev_mutex); |
|---|
| 77 | 137 | } |
|---|
| 78 | 138 | |
|---|
| 79 | 139 | static int sirf_write_raw(struct gnss_device *gdev, const unsigned char *buf, |
|---|
| .. | .. |
|---|
| 85 | 145 | |
|---|
| 86 | 146 | /* write is only buffered synchronously */ |
|---|
| 87 | 147 | ret = serdev_device_write(serdev, buf, count, MAX_SCHEDULE_TIMEOUT); |
|---|
| 88 | | - if (ret < 0) |
|---|
| 148 | + if (ret < 0 || ret < count) |
|---|
| 89 | 149 | return ret; |
|---|
| 90 | 150 | |
|---|
| 91 | 151 | /* FIXME: determine if interrupted? */ |
|---|
| .. | .. |
|---|
| 105 | 165 | { |
|---|
| 106 | 166 | struct sirf_data *data = serdev_device_get_drvdata(serdev); |
|---|
| 107 | 167 | struct gnss_device *gdev = data->gdev; |
|---|
| 168 | + int ret = 0; |
|---|
| 108 | 169 | |
|---|
| 109 | | - return gnss_insert_raw(gdev, buf, count); |
|---|
| 170 | + if (!data->wakeup && !data->active) { |
|---|
| 171 | + data->active = true; |
|---|
| 172 | + wake_up_interruptible(&data->power_wait); |
|---|
| 173 | + } |
|---|
| 174 | + |
|---|
| 175 | + mutex_lock(&data->gdev_mutex); |
|---|
| 176 | + if (data->open) |
|---|
| 177 | + ret = gnss_insert_raw(gdev, buf, count); |
|---|
| 178 | + mutex_unlock(&data->gdev_mutex); |
|---|
| 179 | + |
|---|
| 180 | + return ret; |
|---|
| 110 | 181 | } |
|---|
| 111 | 182 | |
|---|
| 112 | 183 | static const struct serdev_device_ops sirf_serdev_ops = { |
|---|
| .. | .. |
|---|
| 125 | 196 | if (ret < 0) |
|---|
| 126 | 197 | goto out; |
|---|
| 127 | 198 | |
|---|
| 128 | | - data->active = !!ret; |
|---|
| 199 | + data->active = ret; |
|---|
| 129 | 200 | wake_up_interruptible(&data->power_wait); |
|---|
| 130 | 201 | out: |
|---|
| 131 | 202 | return IRQ_HANDLED; |
|---|
| 203 | +} |
|---|
| 204 | + |
|---|
| 205 | +static int sirf_wait_for_power_state_nowakeup(struct sirf_data *data, |
|---|
| 206 | + bool active, |
|---|
| 207 | + unsigned long timeout) |
|---|
| 208 | +{ |
|---|
| 209 | + int ret; |
|---|
| 210 | + |
|---|
| 211 | + /* Wait for state change (including any shutdown messages). */ |
|---|
| 212 | + msleep(timeout); |
|---|
| 213 | + |
|---|
| 214 | + /* Wait for data reception or timeout. */ |
|---|
| 215 | + data->active = false; |
|---|
| 216 | + ret = wait_event_interruptible_timeout(data->power_wait, |
|---|
| 217 | + data->active, msecs_to_jiffies(SIRF_REPORT_CYCLE)); |
|---|
| 218 | + if (ret < 0) |
|---|
| 219 | + return ret; |
|---|
| 220 | + |
|---|
| 221 | + if (ret > 0 && !active) |
|---|
| 222 | + return -ETIMEDOUT; |
|---|
| 223 | + |
|---|
| 224 | + if (ret == 0 && active) |
|---|
| 225 | + return -ETIMEDOUT; |
|---|
| 226 | + |
|---|
| 227 | + return 0; |
|---|
| 132 | 228 | } |
|---|
| 133 | 229 | |
|---|
| 134 | 230 | static int sirf_wait_for_power_state(struct sirf_data *data, bool active, |
|---|
| 135 | 231 | unsigned long timeout) |
|---|
| 136 | 232 | { |
|---|
| 137 | 233 | int ret; |
|---|
| 234 | + |
|---|
| 235 | + if (!data->wakeup) |
|---|
| 236 | + return sirf_wait_for_power_state_nowakeup(data, active, timeout); |
|---|
| 138 | 237 | |
|---|
| 139 | 238 | ret = wait_event_interruptible_timeout(data->power_wait, |
|---|
| 140 | 239 | data->active == active, msecs_to_jiffies(timeout)); |
|---|
| .. | .. |
|---|
| 168 | 267 | else |
|---|
| 169 | 268 | timeout = SIRF_HIBERNATE_TIMEOUT; |
|---|
| 170 | 269 | |
|---|
| 270 | + if (!data->wakeup) { |
|---|
| 271 | + ret = sirf_serdev_open(data); |
|---|
| 272 | + if (ret) |
|---|
| 273 | + return ret; |
|---|
| 274 | + } |
|---|
| 275 | + |
|---|
| 171 | 276 | do { |
|---|
| 172 | 277 | sirf_pulse_on_off(data); |
|---|
| 173 | 278 | ret = sirf_wait_for_power_state(data, active, timeout); |
|---|
| 174 | | - if (ret < 0) { |
|---|
| 175 | | - if (ret == -ETIMEDOUT) |
|---|
| 176 | | - continue; |
|---|
| 279 | + } while (ret == -ETIMEDOUT && retries--); |
|---|
| 177 | 280 | |
|---|
| 178 | | - return ret; |
|---|
| 179 | | - } |
|---|
| 281 | + if (!data->wakeup) |
|---|
| 282 | + sirf_serdev_close(data); |
|---|
| 180 | 283 | |
|---|
| 181 | | - break; |
|---|
| 182 | | - } while (retries--); |
|---|
| 183 | | - |
|---|
| 184 | | - if (retries < 0) |
|---|
| 185 | | - return -ETIMEDOUT; |
|---|
| 284 | + if (ret) |
|---|
| 285 | + return ret; |
|---|
| 186 | 286 | |
|---|
| 187 | 287 | return 0; |
|---|
| 188 | 288 | } |
|---|
| .. | .. |
|---|
| 190 | 290 | static int sirf_runtime_suspend(struct device *dev) |
|---|
| 191 | 291 | { |
|---|
| 192 | 292 | struct sirf_data *data = dev_get_drvdata(dev); |
|---|
| 293 | + int ret2; |
|---|
| 294 | + int ret; |
|---|
| 193 | 295 | |
|---|
| 194 | | - if (!data->on_off) |
|---|
| 195 | | - return regulator_disable(data->vcc); |
|---|
| 296 | + if (data->on_off) |
|---|
| 297 | + ret = sirf_set_active(data, false); |
|---|
| 298 | + else |
|---|
| 299 | + ret = regulator_disable(data->vcc); |
|---|
| 196 | 300 | |
|---|
| 197 | | - return sirf_set_active(data, false); |
|---|
| 301 | + if (ret) |
|---|
| 302 | + return ret; |
|---|
| 303 | + |
|---|
| 304 | + ret = regulator_disable(data->lna); |
|---|
| 305 | + if (ret) |
|---|
| 306 | + goto err_reenable; |
|---|
| 307 | + |
|---|
| 308 | + return 0; |
|---|
| 309 | + |
|---|
| 310 | +err_reenable: |
|---|
| 311 | + if (data->on_off) |
|---|
| 312 | + ret2 = sirf_set_active(data, true); |
|---|
| 313 | + else |
|---|
| 314 | + ret2 = regulator_enable(data->vcc); |
|---|
| 315 | + |
|---|
| 316 | + if (ret2) |
|---|
| 317 | + dev_err(dev, |
|---|
| 318 | + "failed to reenable power on failed suspend: %d\n", |
|---|
| 319 | + ret2); |
|---|
| 320 | + |
|---|
| 321 | + return ret; |
|---|
| 198 | 322 | } |
|---|
| 199 | 323 | |
|---|
| 200 | 324 | static int sirf_runtime_resume(struct device *dev) |
|---|
| 201 | 325 | { |
|---|
| 202 | 326 | struct sirf_data *data = dev_get_drvdata(dev); |
|---|
| 327 | + int ret; |
|---|
| 203 | 328 | |
|---|
| 204 | | - if (!data->on_off) |
|---|
| 205 | | - return regulator_enable(data->vcc); |
|---|
| 329 | + ret = regulator_enable(data->lna); |
|---|
| 330 | + if (ret) |
|---|
| 331 | + return ret; |
|---|
| 206 | 332 | |
|---|
| 207 | | - return sirf_set_active(data, true); |
|---|
| 333 | + if (data->on_off) |
|---|
| 334 | + ret = sirf_set_active(data, true); |
|---|
| 335 | + else |
|---|
| 336 | + ret = regulator_enable(data->vcc); |
|---|
| 337 | + |
|---|
| 338 | + if (ret) |
|---|
| 339 | + goto err_disable_lna; |
|---|
| 340 | + |
|---|
| 341 | + return 0; |
|---|
| 342 | + |
|---|
| 343 | +err_disable_lna: |
|---|
| 344 | + regulator_disable(data->lna); |
|---|
| 345 | + |
|---|
| 346 | + return ret; |
|---|
| 208 | 347 | } |
|---|
| 209 | 348 | |
|---|
| 210 | 349 | static int __maybe_unused sirf_suspend(struct device *dev) |
|---|
| .. | .. |
|---|
| 275 | 414 | data->serdev = serdev; |
|---|
| 276 | 415 | data->gdev = gdev; |
|---|
| 277 | 416 | |
|---|
| 417 | + mutex_init(&data->gdev_mutex); |
|---|
| 418 | + mutex_init(&data->serdev_mutex); |
|---|
| 278 | 419 | init_waitqueue_head(&data->power_wait); |
|---|
| 279 | 420 | |
|---|
| 280 | 421 | serdev_device_set_drvdata(serdev, data); |
|---|
| .. | .. |
|---|
| 287 | 428 | data->vcc = devm_regulator_get(dev, "vcc"); |
|---|
| 288 | 429 | if (IS_ERR(data->vcc)) { |
|---|
| 289 | 430 | ret = PTR_ERR(data->vcc); |
|---|
| 431 | + goto err_put_device; |
|---|
| 432 | + } |
|---|
| 433 | + |
|---|
| 434 | + data->lna = devm_regulator_get(dev, "lna"); |
|---|
| 435 | + if (IS_ERR(data->lna)) { |
|---|
| 436 | + ret = PTR_ERR(data->lna); |
|---|
| 290 | 437 | goto err_put_device; |
|---|
| 291 | 438 | } |
|---|
| 292 | 439 | |
|---|
| .. | .. |
|---|
| 305 | 452 | goto err_put_device; |
|---|
| 306 | 453 | } |
|---|
| 307 | 454 | |
|---|
| 308 | | - /* |
|---|
| 309 | | - * Configurations where WAKEUP has been left not connected, |
|---|
| 310 | | - * are currently not supported. |
|---|
| 311 | | - */ |
|---|
| 312 | | - if (!data->wakeup) { |
|---|
| 313 | | - dev_err(dev, "no wakeup gpio specified\n"); |
|---|
| 314 | | - ret = -ENODEV; |
|---|
| 315 | | - goto err_put_device; |
|---|
| 316 | | - } |
|---|
| 317 | | - |
|---|
| 318 | 455 | ret = regulator_enable(data->vcc); |
|---|
| 319 | 456 | if (ret) |
|---|
| 320 | 457 | goto err_put_device; |
|---|
| .. | .. |
|---|
| 324 | 461 | } |
|---|
| 325 | 462 | |
|---|
| 326 | 463 | if (data->wakeup) { |
|---|
| 464 | + ret = gpiod_get_value_cansleep(data->wakeup); |
|---|
| 465 | + if (ret < 0) |
|---|
| 466 | + goto err_disable_vcc; |
|---|
| 467 | + data->active = ret; |
|---|
| 468 | + |
|---|
| 327 | 469 | ret = gpiod_to_irq(data->wakeup); |
|---|
| 328 | 470 | if (ret < 0) |
|---|
| 329 | 471 | goto err_disable_vcc; |
|---|
| .. | .. |
|---|
| 334 | 476 | "wakeup", data); |
|---|
| 335 | 477 | if (ret) |
|---|
| 336 | 478 | goto err_disable_vcc; |
|---|
| 479 | + } |
|---|
| 480 | + |
|---|
| 481 | + if (data->on_off) { |
|---|
| 482 | + if (!data->wakeup) { |
|---|
| 483 | + data->active = false; |
|---|
| 484 | + |
|---|
| 485 | + ret = sirf_serdev_open(data); |
|---|
| 486 | + if (ret) |
|---|
| 487 | + goto err_disable_vcc; |
|---|
| 488 | + |
|---|
| 489 | + msleep(SIRF_REPORT_CYCLE); |
|---|
| 490 | + sirf_serdev_close(data); |
|---|
| 491 | + } |
|---|
| 492 | + |
|---|
| 493 | + /* Force hibernate mode if already active. */ |
|---|
| 494 | + if (data->active) { |
|---|
| 495 | + ret = sirf_set_active(data, false); |
|---|
| 496 | + if (ret) { |
|---|
| 497 | + dev_err(dev, "failed to set hibernate mode: %d\n", |
|---|
| 498 | + ret); |
|---|
| 499 | + goto err_free_irq; |
|---|
| 500 | + } |
|---|
| 501 | + } |
|---|
| 337 | 502 | } |
|---|
| 338 | 503 | |
|---|
| 339 | 504 | if (IS_ENABLED(CONFIG_PM)) { |
|---|
| .. | .. |
|---|
| 392 | 557 | static const struct of_device_id sirf_of_match[] = { |
|---|
| 393 | 558 | { .compatible = "fastrax,uc430" }, |
|---|
| 394 | 559 | { .compatible = "linx,r4" }, |
|---|
| 560 | + { .compatible = "wi2wi,w2sg0004" }, |
|---|
| 395 | 561 | { .compatible = "wi2wi,w2sg0008i" }, |
|---|
| 396 | 562 | { .compatible = "wi2wi,w2sg0084i" }, |
|---|
| 397 | 563 | {}, |
|---|