.. | .. |
---|
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 | {}, |
---|