diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/input/touchscreen/ads7846.c | 82 |
1 files changed, 48 insertions, 34 deletions
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index fec3b9b22309..e7cabf12c8dc 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c | |||
@@ -102,6 +102,8 @@ struct ads7846 { | |||
102 | // FIXME remove "irq_disabled" | 102 | // FIXME remove "irq_disabled" |
103 | unsigned irq_disabled:1; /* P: lock */ | 103 | unsigned irq_disabled:1; /* P: lock */ |
104 | unsigned disabled:1; | 104 | unsigned disabled:1; |
105 | |||
106 | int (*get_pendown_state)(void); | ||
105 | }; | 107 | }; |
106 | 108 | ||
107 | /* leave chip selected when we're done, for quicker re-select? */ | 109 | /* leave chip selected when we're done, for quicker re-select? */ |
@@ -175,6 +177,12 @@ struct ser_req { | |||
175 | static void ads7846_enable(struct ads7846 *ts); | 177 | static void ads7846_enable(struct ads7846 *ts); |
176 | static void ads7846_disable(struct ads7846 *ts); | 178 | static void ads7846_disable(struct ads7846 *ts); |
177 | 179 | ||
180 | static int device_suspended(struct device *dev) | ||
181 | { | ||
182 | struct ads7846 *ts = dev_get_drvdata(dev); | ||
183 | return dev->power.power_state.event != PM_EVENT_ON || ts->disabled; | ||
184 | } | ||
185 | |||
178 | static int ads7846_read12_ser(struct device *dev, unsigned command) | 186 | static int ads7846_read12_ser(struct device *dev, unsigned command) |
179 | { | 187 | { |
180 | struct spi_device *spi = to_spi_device(dev); | 188 | struct spi_device *spi = to_spi_device(dev); |
@@ -227,8 +235,10 @@ static int ads7846_read12_ser(struct device *dev, unsigned command) | |||
227 | for (i = 0; i < 6; i++) | 235 | for (i = 0; i < 6; i++) |
228 | spi_message_add_tail(&req->xfer[i], &req->msg); | 236 | spi_message_add_tail(&req->xfer[i], &req->msg); |
229 | 237 | ||
238 | ts->irq_disabled = 1; | ||
230 | disable_irq(spi->irq); | 239 | disable_irq(spi->irq); |
231 | status = spi_sync(spi, &req->msg); | 240 | status = spi_sync(spi, &req->msg); |
241 | ts->irq_disabled = 0; | ||
232 | enable_irq(spi->irq); | 242 | enable_irq(spi->irq); |
233 | 243 | ||
234 | if (req->msg.status) | 244 | if (req->msg.status) |
@@ -333,7 +343,7 @@ static void ads7846_rx(void *ads) | |||
333 | if (x == MAX_12BIT) | 343 | if (x == MAX_12BIT) |
334 | x = 0; | 344 | x = 0; |
335 | 345 | ||
336 | if (x && z1 && ts->spi->dev.power.power_state.event == PM_EVENT_ON) { | 346 | if (likely(x && z1 && !device_suspended(&ts->spi->dev))) { |
337 | /* compute touch pressure resistance using equation #2 */ | 347 | /* compute touch pressure resistance using equation #2 */ |
338 | Rt = z2; | 348 | Rt = z2; |
339 | Rt -= z1; | 349 | Rt -= z1; |
@@ -377,20 +387,10 @@ static void ads7846_rx(void *ads) | |||
377 | x, y, Rt, Rt ? "" : " UP"); | 387 | x, y, Rt, Rt ? "" : " UP"); |
378 | #endif | 388 | #endif |
379 | 389 | ||
380 | /* don't retrigger while we're suspended */ | ||
381 | spin_lock_irqsave(&ts->lock, flags); | 390 | spin_lock_irqsave(&ts->lock, flags); |
382 | 391 | ||
383 | ts->pendown = (Rt != 0); | 392 | ts->pendown = (Rt != 0); |
384 | ts->pending = 0; | 393 | mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD); |
385 | |||
386 | if (ts->spi->dev.power.power_state.event == PM_EVENT_ON) { | ||
387 | if (ts->pendown) | ||
388 | mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD); | ||
389 | else if (ts->irq_disabled) { | ||
390 | ts->irq_disabled = 0; | ||
391 | enable_irq(ts->spi->irq); | ||
392 | } | ||
393 | } | ||
394 | 394 | ||
395 | spin_unlock_irqrestore(&ts->lock, flags); | 395 | spin_unlock_irqrestore(&ts->lock, flags); |
396 | } | 396 | } |
@@ -431,10 +431,25 @@ static void ads7846_timer(unsigned long handle) | |||
431 | struct ads7846 *ts = (void *)handle; | 431 | struct ads7846 *ts = (void *)handle; |
432 | int status = 0; | 432 | int status = 0; |
433 | 433 | ||
434 | ts->msg_idx = 0; | 434 | spin_lock_irq(&ts->lock); |
435 | status = spi_async(ts->spi, &ts->msg[0]); | 435 | |
436 | if (status) | 436 | if (unlikely(ts->msg_idx && !ts->pendown)) { |
437 | dev_err(&ts->spi->dev, "spi_async --> %d\n", status); | 437 | /* measurment cycle ended */ |
438 | if (!device_suspended(&ts->spi->dev)) { | ||
439 | ts->irq_disabled = 0; | ||
440 | enable_irq(ts->spi->irq); | ||
441 | } | ||
442 | ts->pending = 0; | ||
443 | ts->msg_idx = 0; | ||
444 | } else { | ||
445 | /* pen is still down, continue with the measurement */ | ||
446 | ts->msg_idx = 0; | ||
447 | status = spi_async(ts->spi, &ts->msg[0]); | ||
448 | if (status) | ||
449 | dev_err(&ts->spi->dev, "spi_async --> %d\n", status); | ||
450 | } | ||
451 | |||
452 | spin_unlock_irq(&ts->lock); | ||
438 | } | 453 | } |
439 | 454 | ||
440 | static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs) | 455 | static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs) |
@@ -443,7 +458,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs) | |||
443 | unsigned long flags; | 458 | unsigned long flags; |
444 | 459 | ||
445 | spin_lock_irqsave(&ts->lock, flags); | 460 | spin_lock_irqsave(&ts->lock, flags); |
446 | if (likely(!ts->irq_disabled && !ts->disabled)) { | 461 | if (likely(ts->get_pendown_state())) { |
447 | if (!ts->irq_disabled) { | 462 | if (!ts->irq_disabled) { |
448 | /* REVISIT irq logic for many ARM chips has cloned a | 463 | /* REVISIT irq logic for many ARM chips has cloned a |
449 | * bug wherein disabling an irq in its handler won't | 464 | * bug wherein disabling an irq in its handler won't |
@@ -452,10 +467,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs) | |||
452 | * that state here. | 467 | * that state here. |
453 | */ | 468 | */ |
454 | ts->irq_disabled = 1; | 469 | ts->irq_disabled = 1; |
455 | |||
456 | disable_irq(ts->spi->irq); | 470 | disable_irq(ts->spi->irq); |
457 | } | ||
458 | if (!ts->pending) { | ||
459 | ts->pending = 1; | 471 | ts->pending = 1; |
460 | mod_timer(&ts->timer, jiffies); | 472 | mod_timer(&ts->timer, jiffies); |
461 | } | 473 | } |
@@ -473,20 +485,17 @@ static void ads7846_disable(struct ads7846 *ts) | |||
473 | if (ts->disabled) | 485 | if (ts->disabled) |
474 | return; | 486 | return; |
475 | 487 | ||
488 | ts->disabled = 1; | ||
489 | |||
476 | /* are we waiting for IRQ, or polling? */ | 490 | /* are we waiting for IRQ, or polling? */ |
477 | if (!ts->pendown) { | 491 | if (!ts->pending) { |
478 | if (!ts->irq_disabled) { | 492 | ts->irq_disabled = 1; |
479 | ts->irq_disabled = 1; | 493 | disable_irq(ts->spi->irq); |
480 | disable_irq(ts->spi->irq); | ||
481 | } | ||
482 | } else { | 494 | } else { |
483 | /* polling; force a final SPI completion; | 495 | /* the timer will run at least once more, and |
484 | * that will clean things up neatly | 496 | * leave everything in a clean state, IRQ disabled |
485 | */ | 497 | */ |
486 | if (!ts->pending) | 498 | while (ts->pending) { |
487 | mod_timer(&ts->timer, jiffies); | ||
488 | |||
489 | while (ts->pendown || ts->pending) { | ||
490 | spin_unlock_irq(&ts->lock); | 499 | spin_unlock_irq(&ts->lock); |
491 | msleep(1); | 500 | msleep(1); |
492 | spin_lock_irq(&ts->lock); | 501 | spin_lock_irq(&ts->lock); |
@@ -497,7 +506,6 @@ static void ads7846_disable(struct ads7846 *ts) | |||
497 | * leave it that way after every request | 506 | * leave it that way after every request |
498 | */ | 507 | */ |
499 | 508 | ||
500 | ts->disabled = 1; | ||
501 | } | 509 | } |
502 | 510 | ||
503 | /* Must be called with ts->lock held */ | 511 | /* Must be called with ts->lock held */ |
@@ -566,6 +574,11 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
566 | return -EINVAL; | 574 | return -EINVAL; |
567 | } | 575 | } |
568 | 576 | ||
577 | if (pdata->get_pendown_state == NULL) { | ||
578 | dev_dbg(&spi->dev, "no get_pendown_state function?\n"); | ||
579 | return -EINVAL; | ||
580 | } | ||
581 | |||
569 | /* We'd set the wordsize to 12 bits ... except that some controllers | 582 | /* We'd set the wordsize to 12 bits ... except that some controllers |
570 | * will then treat the 8 bit command words as 12 bits (and drop the | 583 | * will then treat the 8 bit command words as 12 bits (and drop the |
571 | * four MSBs of the 12 bit result). Result: inputs must be shifted | 584 | * four MSBs of the 12 bit result). Result: inputs must be shifted |
@@ -596,6 +609,7 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
596 | ts->x_plate_ohms = pdata->x_plate_ohms ? : 400; | 609 | ts->x_plate_ohms = pdata->x_plate_ohms ? : 400; |
597 | ts->debounce_max = pdata->debounce_max ? : 1; | 610 | ts->debounce_max = pdata->debounce_max ? : 1; |
598 | ts->debounce_tol = pdata->debounce_tol ? : 10; | 611 | ts->debounce_tol = pdata->debounce_tol ? : 10; |
612 | ts->get_pendown_state = pdata->get_pendown_state; | ||
599 | 613 | ||
600 | snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id); | 614 | snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id); |
601 | 615 | ||
@@ -786,8 +800,8 @@ static int __devexit ads7846_remove(struct spi_device *spi) | |||
786 | device_remove_file(&spi->dev, &dev_attr_vaux); | 800 | device_remove_file(&spi->dev, &dev_attr_vaux); |
787 | 801 | ||
788 | free_irq(ts->spi->irq, ts); | 802 | free_irq(ts->spi->irq, ts); |
789 | if (ts->irq_disabled) | 803 | /* suspend left the IRQ disabled */ |
790 | enable_irq(ts->spi->irq); | 804 | enable_irq(ts->spi->irq); |
791 | 805 | ||
792 | kfree(ts); | 806 | kfree(ts); |
793 | 807 | ||