diff options
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/touchscreen/tsc2005.c | 218 |
1 files changed, 124 insertions, 94 deletions
diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 5a15919ec4c7..3e1c9c297f33 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c | |||
@@ -133,13 +133,14 @@ struct tsc2005 { | |||
133 | struct timer_list penup_timer; | 133 | struct timer_list penup_timer; |
134 | 134 | ||
135 | unsigned int esd_timeout; | 135 | unsigned int esd_timeout; |
136 | struct timer_list esd_timer; | 136 | struct delayed_work esd_work; |
137 | struct work_struct esd_work; | 137 | unsigned long last_valid_interrupt; |
138 | 138 | ||
139 | unsigned int x_plate_ohm; | 139 | unsigned int x_plate_ohm; |
140 | 140 | ||
141 | bool disabled; | 141 | bool disabled; |
142 | unsigned int disable_depth; | 142 | bool opened; |
143 | bool suspended; | ||
143 | 144 | ||
144 | bool pen_down; | 145 | bool pen_down; |
145 | 146 | ||
@@ -258,11 +259,6 @@ static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) | |||
258 | u32 z1, z2; | 259 | u32 z1, z2; |
259 | int error; | 260 | int error; |
260 | 261 | ||
261 | mutex_lock(&ts->mutex); | ||
262 | |||
263 | if (unlikely(ts->disable_depth)) | ||
264 | goto out; | ||
265 | |||
266 | /* read the coordinates */ | 262 | /* read the coordinates */ |
267 | error = spi_sync(ts->spi, &ts->spi_read_msg); | 263 | error = spi_sync(ts->spi, &ts->spi_read_msg); |
268 | if (unlikely(error)) | 264 | if (unlikely(error)) |
@@ -309,21 +305,13 @@ static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) | |||
309 | spin_lock_irqsave(&ts->lock, flags); | 305 | spin_lock_irqsave(&ts->lock, flags); |
310 | 306 | ||
311 | tsc2005_update_pen_state(ts, x, y, pressure); | 307 | tsc2005_update_pen_state(ts, x, y, pressure); |
312 | |||
313 | /* set the penup timer */ | ||
314 | mod_timer(&ts->penup_timer, | 308 | mod_timer(&ts->penup_timer, |
315 | jiffies + msecs_to_jiffies(TSC2005_PENUP_TIME_MS)); | 309 | jiffies + msecs_to_jiffies(TSC2005_PENUP_TIME_MS)); |
316 | 310 | ||
317 | if (ts->esd_timeout && ts->set_reset) { | ||
318 | /* update the watchdog timer */ | ||
319 | mod_timer(&ts->esd_timer, round_jiffies(jiffies + | ||
320 | msecs_to_jiffies(ts->esd_timeout))); | ||
321 | } | ||
322 | |||
323 | spin_unlock_irqrestore(&ts->lock, flags); | 311 | spin_unlock_irqrestore(&ts->lock, flags); |
324 | 312 | ||
313 | ts->last_valid_interrupt = jiffies; | ||
325 | out: | 314 | out: |
326 | mutex_unlock(&ts->mutex); | ||
327 | return IRQ_HANDLED; | 315 | return IRQ_HANDLED; |
328 | } | 316 | } |
329 | 317 | ||
@@ -350,29 +338,31 @@ static void tsc2005_stop_scan(struct tsc2005 *ts) | |||
350 | tsc2005_cmd(ts, TSC2005_CMD_STOP); | 338 | tsc2005_cmd(ts, TSC2005_CMD_STOP); |
351 | } | 339 | } |
352 | 340 | ||
353 | /* must be called with mutex held */ | 341 | /* must be called with ts->mutex held */ |
354 | static void tsc2005_disable(struct tsc2005 *ts) | 342 | static void __tsc2005_disable(struct tsc2005 *ts) |
355 | { | 343 | { |
356 | if (ts->disable_depth++ != 0) | 344 | tsc2005_stop_scan(ts); |
357 | return; | 345 | |
358 | disable_irq(ts->spi->irq); | 346 | disable_irq(ts->spi->irq); |
359 | if (ts->esd_timeout) | ||
360 | del_timer_sync(&ts->esd_timer); | ||
361 | del_timer_sync(&ts->penup_timer); | 347 | del_timer_sync(&ts->penup_timer); |
362 | tsc2005_stop_scan(ts); | 348 | |
349 | cancel_delayed_work_sync(&ts->esd_work); | ||
350 | |||
351 | enable_irq(ts->spi->irq); | ||
363 | } | 352 | } |
364 | 353 | ||
365 | /* must be called with mutex held */ | 354 | /* must be called with ts->mutex held */ |
366 | static void tsc2005_enable(struct tsc2005 *ts) | 355 | static void __tsc2005_enable(struct tsc2005 *ts) |
367 | { | 356 | { |
368 | if (--ts->disable_depth != 0) | ||
369 | return; | ||
370 | tsc2005_start_scan(ts); | 357 | tsc2005_start_scan(ts); |
371 | enable_irq(ts->spi->irq); | 358 | |
372 | if (!ts->esd_timeout) | 359 | if (ts->esd_timeout && ts->set_reset) { |
373 | return; | 360 | ts->last_valid_interrupt = jiffies; |
374 | mod_timer(&ts->esd_timer, | 361 | schedule_delayed_work(&ts->esd_work, |
375 | round_jiffies(jiffies + msecs_to_jiffies(ts->esd_timeout))); | 362 | round_jiffies(jiffies + |
363 | msecs_to_jiffies(ts->esd_timeout))); | ||
364 | } | ||
365 | |||
376 | } | 366 | } |
377 | 367 | ||
378 | static ssize_t tsc2005_disable_show(struct device *dev, | 368 | static ssize_t tsc2005_disable_show(struct device *dev, |
@@ -390,23 +380,29 @@ static ssize_t tsc2005_disable_store(struct device *dev, | |||
390 | { | 380 | { |
391 | struct spi_device *spi = to_spi_device(dev); | 381 | struct spi_device *spi = to_spi_device(dev); |
392 | struct tsc2005 *ts = spi_get_drvdata(spi); | 382 | struct tsc2005 *ts = spi_get_drvdata(spi); |
393 | unsigned long res; | 383 | unsigned long val; |
394 | int i; | 384 | int error; |
395 | 385 | ||
396 | if (strict_strtoul(buf, 10, &res) < 0) | 386 | error = strict_strtoul(buf, 10, &val); |
397 | return -EINVAL; | 387 | if (error) |
398 | i = res ? 1 : 0; | 388 | return error; |
399 | 389 | ||
400 | mutex_lock(&ts->mutex); | 390 | mutex_lock(&ts->mutex); |
401 | if (i == ts->disabled) | 391 | |
402 | goto out; | 392 | if (!ts->suspended && ts->opened) { |
403 | ts->disabled = i; | 393 | if (val) { |
404 | if (i) | 394 | if (!ts->disabled) |
405 | tsc2005_disable(ts); | 395 | __tsc2005_disable(ts); |
406 | else | 396 | } else { |
407 | tsc2005_enable(ts); | 397 | if (ts->disabled) |
408 | out: | 398 | __tsc2005_enable(ts); |
399 | } | ||
400 | } | ||
401 | |||
402 | ts->disabled = !!val; | ||
403 | |||
409 | mutex_unlock(&ts->mutex); | 404 | mutex_unlock(&ts->mutex); |
405 | |||
410 | return count; | 406 | return count; |
411 | } | 407 | } |
412 | static DEVICE_ATTR(disable, 0664, tsc2005_disable_show, tsc2005_disable_store); | 408 | static DEVICE_ATTR(disable, 0664, tsc2005_disable_show, tsc2005_disable_store); |
@@ -428,7 +424,7 @@ static ssize_t tsc2005_selftest_show(struct device *dev, | |||
428 | /* | 424 | /* |
429 | * Test TSC2005 communications via temp high register. | 425 | * Test TSC2005 communications via temp high register. |
430 | */ | 426 | */ |
431 | tsc2005_disable(ts); | 427 | __tsc2005_disable(ts); |
432 | 428 | ||
433 | error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high_orig); | 429 | error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high_orig); |
434 | if (error) { | 430 | if (error) { |
@@ -484,7 +480,7 @@ static ssize_t tsc2005_selftest_show(struct device *dev, | |||
484 | } | 480 | } |
485 | 481 | ||
486 | out: | 482 | out: |
487 | tsc2005_enable(ts); | 483 | __tsc2005_enable(ts); |
488 | mutex_unlock(&ts->mutex); | 484 | mutex_unlock(&ts->mutex); |
489 | 485 | ||
490 | return sprintf(buf, "%d\n", success); | 486 | return sprintf(buf, "%d\n", success); |
@@ -519,44 +515,79 @@ static const struct attribute_group tsc2005_attr_group = { | |||
519 | .attrs = tsc2005_attrs, | 515 | .attrs = tsc2005_attrs, |
520 | }; | 516 | }; |
521 | 517 | ||
522 | static void tsc2005_esd_timer(unsigned long data) | ||
523 | { | ||
524 | struct tsc2005 *ts = (struct tsc2005 *)data; | ||
525 | |||
526 | schedule_work(&ts->esd_work); | ||
527 | } | ||
528 | |||
529 | static void tsc2005_esd_work(struct work_struct *work) | 518 | static void tsc2005_esd_work(struct work_struct *work) |
530 | { | 519 | { |
531 | struct tsc2005 *ts = container_of(work, struct tsc2005, esd_work); | 520 | struct tsc2005 *ts = container_of(work, struct tsc2005, esd_work.work); |
532 | int error; | 521 | int error; |
533 | u16 r; | 522 | u16 r; |
534 | 523 | ||
535 | mutex_lock(&ts->mutex); | 524 | mutex_lock(&ts->mutex); |
536 | 525 | ||
537 | if (ts->disable_depth) | 526 | if (time_is_after_jiffies(ts->last_valid_interrupt + |
527 | msecs_to_jiffies(ts->esd_timeout))) | ||
538 | goto out; | 528 | goto out; |
539 | 529 | ||
540 | /* | 530 | /* We should be able to read register without disabling interrupts. */ |
541 | * If we cannot read our known value from configuration register 0 then | ||
542 | * reset the controller as if from power-up and start scanning again. | ||
543 | */ | ||
544 | error = tsc2005_read(ts, TSC2005_REG_CFR0, &r); | 531 | error = tsc2005_read(ts, TSC2005_REG_CFR0, &r); |
545 | if (error || | 532 | if (!error && |
546 | ((r ^ TSC2005_CFR0_INITVALUE) & TSC2005_CFR0_RW_MASK)) { | 533 | !((r ^ TSC2005_CFR0_INITVALUE) & TSC2005_CFR0_RW_MASK)) { |
547 | dev_info(&ts->spi->dev, "TSC2005 not responding - resetting\n"); | 534 | goto out; |
548 | ts->set_reset(false); | ||
549 | tsc2005_update_pen_state(ts, 0, 0, 0); | ||
550 | usleep_range(100, 500); /* only 10us required */ | ||
551 | ts->set_reset(true); | ||
552 | tsc2005_start_scan(ts); | ||
553 | } | 535 | } |
554 | 536 | ||
555 | /* re-arm the watchdog */ | 537 | /* |
556 | mod_timer(&ts->esd_timer, | 538 | * If we could not read our known value from configuration register 0 |
557 | round_jiffies(jiffies + msecs_to_jiffies(ts->esd_timeout))); | 539 | * then we should reset the controller as if from power-up and start |
540 | * scanning again. | ||
541 | */ | ||
542 | dev_info(&ts->spi->dev, "TSC2005 not responding - resetting\n"); | ||
543 | |||
544 | disable_irq(ts->spi->irq); | ||
545 | del_timer_sync(&ts->penup_timer); | ||
546 | |||
547 | tsc2005_update_pen_state(ts, 0, 0, 0); | ||
548 | |||
549 | ts->set_reset(false); | ||
550 | usleep_range(100, 500); /* only 10us required */ | ||
551 | ts->set_reset(true); | ||
552 | |||
553 | enable_irq(ts->spi->irq); | ||
554 | tsc2005_start_scan(ts); | ||
558 | 555 | ||
559 | out: | 556 | out: |
557 | /* re-arm the watchdog */ | ||
558 | schedule_delayed_work(&ts->esd_work, | ||
559 | round_jiffies(jiffies + | ||
560 | msecs_to_jiffies(ts->esd_timeout))); | ||
561 | mutex_unlock(&ts->mutex); | ||
562 | } | ||
563 | |||
564 | static int tsc2005_open(struct input_dev *input) | ||
565 | { | ||
566 | struct tsc2005 *ts = input_get_drvdata(input); | ||
567 | |||
568 | mutex_lock(&ts->mutex); | ||
569 | |||
570 | if (!ts->suspended && !ts->disabled) | ||
571 | __tsc2005_enable(ts); | ||
572 | |||
573 | ts->opened = true; | ||
574 | |||
575 | mutex_unlock(&ts->mutex); | ||
576 | |||
577 | return 0; | ||
578 | } | ||
579 | |||
580 | static void tsc2005_close(struct input_dev *input) | ||
581 | { | ||
582 | struct tsc2005 *ts = input_get_drvdata(input); | ||
583 | |||
584 | mutex_lock(&ts->mutex); | ||
585 | |||
586 | if (!ts->suspended && !ts->disabled) | ||
587 | __tsc2005_disable(ts); | ||
588 | |||
589 | ts->opened = false; | ||
590 | |||
560 | mutex_unlock(&ts->mutex); | 591 | mutex_unlock(&ts->mutex); |
561 | } | 592 | } |
562 | 593 | ||
@@ -628,8 +659,7 @@ static int __devinit tsc2005_probe(struct spi_device *spi) | |||
628 | spin_lock_init(&ts->lock); | 659 | spin_lock_init(&ts->lock); |
629 | setup_timer(&ts->penup_timer, tsc2005_penup_timer, (unsigned long)ts); | 660 | setup_timer(&ts->penup_timer, tsc2005_penup_timer, (unsigned long)ts); |
630 | 661 | ||
631 | setup_timer(&ts->esd_timer, tsc2005_esd_timer, (unsigned long)ts); | 662 | INIT_DELAYED_WORK(&ts->esd_work, tsc2005_esd_work); |
632 | INIT_WORK(&ts->esd_work, tsc2005_esd_work); | ||
633 | 663 | ||
634 | tsc2005_setup_spi_xfer(ts); | 664 | tsc2005_setup_spi_xfer(ts); |
635 | 665 | ||
@@ -647,6 +677,14 @@ static int __devinit tsc2005_probe(struct spi_device *spi) | |||
647 | input_set_abs_params(input_dev, ABS_Y, 0, max_y, fudge_y, 0); | 677 | input_set_abs_params(input_dev, ABS_Y, 0, max_y, fudge_y, 0); |
648 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0); | 678 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0); |
649 | 679 | ||
680 | input_dev->open = tsc2005_open; | ||
681 | input_dev->close = tsc2005_close; | ||
682 | |||
683 | input_set_drvdata(input_dev, ts); | ||
684 | |||
685 | /* Ensure the touchscreen is off */ | ||
686 | tsc2005_stop_scan(ts); | ||
687 | |||
650 | error = request_threaded_irq(spi->irq, NULL, tsc2005_irq_thread, | 688 | error = request_threaded_irq(spi->irq, NULL, tsc2005_irq_thread, |
651 | IRQF_TRIGGER_RISING, "tsc2005", ts); | 689 | IRQF_TRIGGER_RISING, "tsc2005", ts); |
652 | if (error) { | 690 | if (error) { |
@@ -669,14 +707,6 @@ static int __devinit tsc2005_probe(struct spi_device *spi) | |||
669 | goto err_remove_sysfs; | 707 | goto err_remove_sysfs; |
670 | } | 708 | } |
671 | 709 | ||
672 | tsc2005_start_scan(ts); | ||
673 | |||
674 | if (ts->esd_timeout && ts->set_reset) { | ||
675 | /* start the optional ESD watchdog */ | ||
676 | mod_timer(&ts->esd_timer, round_jiffies(jiffies + | ||
677 | msecs_to_jiffies(ts->esd_timeout))); | ||
678 | } | ||
679 | |||
680 | set_irq_wake(spi->irq, 1); | 710 | set_irq_wake(spi->irq, 1); |
681 | return 0; | 711 | return 0; |
682 | 712 | ||
@@ -697,16 +727,6 @@ static int __devexit tsc2005_remove(struct spi_device *spi) | |||
697 | 727 | ||
698 | sysfs_remove_group(&ts->spi->dev.kobj, &tsc2005_attr_group); | 728 | sysfs_remove_group(&ts->spi->dev.kobj, &tsc2005_attr_group); |
699 | 729 | ||
700 | mutex_lock(&ts->mutex); | ||
701 | tsc2005_disable(ts); | ||
702 | mutex_unlock(&ts->mutex); | ||
703 | |||
704 | if (ts->esd_timeout) | ||
705 | del_timer_sync(&ts->esd_timer); | ||
706 | del_timer_sync(&ts->penup_timer); | ||
707 | |||
708 | flush_work(&ts->esd_work); | ||
709 | |||
710 | free_irq(ts->spi->irq, ts); | 730 | free_irq(ts->spi->irq, ts); |
711 | input_unregister_device(ts->idev); | 731 | input_unregister_device(ts->idev); |
712 | kfree(ts); | 732 | kfree(ts); |
@@ -722,7 +742,12 @@ static int tsc2005_suspend(struct device *dev) | |||
722 | struct tsc2005 *ts = spi_get_drvdata(spi); | 742 | struct tsc2005 *ts = spi_get_drvdata(spi); |
723 | 743 | ||
724 | mutex_lock(&ts->mutex); | 744 | mutex_lock(&ts->mutex); |
725 | tsc2005_disable(ts); | 745 | |
746 | if (!ts->suspended && !ts->disabled && ts->opened) | ||
747 | __tsc2005_disable(ts); | ||
748 | |||
749 | ts->suspended = true; | ||
750 | |||
726 | mutex_unlock(&ts->mutex); | 751 | mutex_unlock(&ts->mutex); |
727 | 752 | ||
728 | return 0; | 753 | return 0; |
@@ -734,7 +759,12 @@ static int tsc2005_resume(struct device *dev) | |||
734 | struct tsc2005 *ts = spi_get_drvdata(spi); | 759 | struct tsc2005 *ts = spi_get_drvdata(spi); |
735 | 760 | ||
736 | mutex_lock(&ts->mutex); | 761 | mutex_lock(&ts->mutex); |
737 | tsc2005_enable(ts); | 762 | |
763 | if (ts->suspended && !ts->disabled && ts->opened) | ||
764 | __tsc2005_enable(ts); | ||
765 | |||
766 | ts->suspended = false; | ||
767 | |||
738 | mutex_unlock(&ts->mutex); | 768 | mutex_unlock(&ts->mutex); |
739 | 769 | ||
740 | return 0; | 770 | return 0; |