diff options
author | Imre Deak <imre.deak@solidboot.com> | 2007-01-18 00:44:41 -0500 |
---|---|---|
committer | Dmitry Torokhov <dtor@insightbb.com> | 2007-01-18 00:44:41 -0500 |
commit | da970e69efb9fd0be0c23ace5bde42d4caf17b40 (patch) | |
tree | 8d415d9ccbf6bbdfa360146c539d8213c794a21f /drivers/input/touchscreen/ads7846.c | |
parent | 78a56aab11234e53b7e94e5a255cc3d27ab0a62b (diff) |
Input: ads7846 - pluggable filtering logic
Some LCDs like the LS041Y3 require a customized filtering
logic for reliable readings, so make the filtering function
replacable through platform specific hooks.
Signed-off-by: Imre Deak <imre.deak@solidboot.com>
Signed-off-by: Juha Yrjola <juha.yrjola@solidboot.com>
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/touchscreen/ads7846.c')
-rw-r--r-- | drivers/input/touchscreen/ads7846.c | 135 |
1 files changed, 95 insertions, 40 deletions
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index c6164b6f476a..03e527c16c23 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c | |||
@@ -63,11 +63,11 @@ struct ts_event { | |||
63 | /* For portability, we can't read 12 bit values using SPI (which | 63 | /* For portability, we can't read 12 bit values using SPI (which |
64 | * would make the controller deliver them as native byteorder u16 | 64 | * would make the controller deliver them as native byteorder u16 |
65 | * with msbs zeroed). Instead, we read them as two 8-bit values, | 65 | * with msbs zeroed). Instead, we read them as two 8-bit values, |
66 | * which need byteswapping then range adjustment. | 66 | * *** WHICH NEED BYTESWAPPING *** and range adjustment. |
67 | */ | 67 | */ |
68 | __be16 x; | 68 | u16 x; |
69 | __be16 y; | 69 | u16 y; |
70 | __be16 z1, z2; | 70 | u16 z1, z2; |
71 | int ignore; | 71 | int ignore; |
72 | }; | 72 | }; |
73 | 73 | ||
@@ -106,6 +106,9 @@ struct ads7846 { | |||
106 | unsigned irq_disabled:1; /* P: lock */ | 106 | unsigned irq_disabled:1; /* P: lock */ |
107 | unsigned disabled:1; | 107 | unsigned disabled:1; |
108 | 108 | ||
109 | int (*filter)(void *data, int data_idx, int *val); | ||
110 | void *filter_data; | ||
111 | void (*filter_cleanup)(void *data); | ||
109 | int (*get_pendown_state)(void); | 112 | int (*get_pendown_state)(void); |
110 | }; | 113 | }; |
111 | 114 | ||
@@ -379,13 +382,13 @@ static void ads7846_rx(void *ads) | |||
379 | u16 x, y, z1, z2; | 382 | u16 x, y, z1, z2; |
380 | unsigned long flags; | 383 | unsigned long flags; |
381 | 384 | ||
382 | /* adjust: on-wire is a must-ignore bit, a BE12 value, then padding; | 385 | /* ads7846_rx_val() did in-place conversion (including byteswap) from |
383 | * built from two 8 bit values written msb-first. | 386 | * on-the-wire format as part of debouncing to get stable readings. |
384 | */ | 387 | */ |
385 | x = (be16_to_cpu(ts->tc.x) >> 3) & 0x0fff; | 388 | x = ts->tc.x; |
386 | y = (be16_to_cpu(ts->tc.y) >> 3) & 0x0fff; | 389 | y = ts->tc.y; |
387 | z1 = (be16_to_cpu(ts->tc.z1) >> 3) & 0x0fff; | 390 | z1 = ts->tc.z1; |
388 | z2 = (be16_to_cpu(ts->tc.z2) >> 3) & 0x0fff; | 391 | z2 = ts->tc.z2; |
389 | 392 | ||
390 | /* range filtering */ | 393 | /* range filtering */ |
391 | if (x == MAX_12BIT) | 394 | if (x == MAX_12BIT) |
@@ -453,50 +456,85 @@ static void ads7846_rx(void *ads) | |||
453 | spin_unlock_irqrestore(&ts->lock, flags); | 456 | spin_unlock_irqrestore(&ts->lock, flags); |
454 | } | 457 | } |
455 | 458 | ||
456 | static void ads7846_debounce(void *ads) | 459 | static int ads7846_debounce(void *ads, int data_idx, int *val) |
457 | { | 460 | { |
458 | struct ads7846 *ts = ads; | 461 | struct ads7846 *ts = ads; |
459 | struct spi_message *m; | ||
460 | struct spi_transfer *t; | ||
461 | int val; | ||
462 | int status; | ||
463 | 462 | ||
464 | m = &ts->msg[ts->msg_idx]; | 463 | if (!ts->read_cnt || (abs(ts->last_read - *val) > ts->debounce_tol)) { |
465 | t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list); | 464 | /* Start over collecting consistent readings. */ |
466 | val = (be16_to_cpu(*(__be16 *)t->rx_buf) >> 3) & 0x0fff; | 465 | ts->read_rep = 0; |
467 | if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol)) { | ||
468 | /* Repeat it, if this was the first read or the read | 466 | /* Repeat it, if this was the first read or the read |
469 | * wasn't consistent enough. */ | 467 | * wasn't consistent enough. */ |
470 | if (ts->read_cnt < ts->debounce_max) { | 468 | if (ts->read_cnt < ts->debounce_max) { |
471 | ts->last_read = val; | 469 | ts->last_read = *val; |
472 | ts->read_cnt++; | 470 | ts->read_cnt++; |
471 | return ADS7846_FILTER_REPEAT; | ||
473 | } else { | 472 | } else { |
474 | /* Maximum number of debouncing reached and still | 473 | /* Maximum number of debouncing reached and still |
475 | * not enough number of consistent readings. Abort | 474 | * not enough number of consistent readings. Abort |
476 | * the whole sample, repeat it in the next sampling | 475 | * the whole sample, repeat it in the next sampling |
477 | * period. | 476 | * period. |
478 | */ | 477 | */ |
479 | ts->tc.ignore = 1; | ||
480 | ts->read_cnt = 0; | 478 | ts->read_cnt = 0; |
481 | /* Last message will contain ads7846_rx() as the | 479 | return ADS7846_FILTER_IGNORE; |
482 | * completion function. | ||
483 | */ | ||
484 | m = ts->last_msg; | ||
485 | } | 480 | } |
486 | /* Start over collecting consistent readings. */ | ||
487 | ts->read_rep = 0; | ||
488 | } else { | 481 | } else { |
489 | if (++ts->read_rep > ts->debounce_rep) { | 482 | if (++ts->read_rep > ts->debounce_rep) { |
490 | /* Got a good reading for this coordinate, | 483 | /* Got a good reading for this coordinate, |
491 | * go for the next one. */ | 484 | * go for the next one. */ |
492 | ts->tc.ignore = 0; | ||
493 | ts->msg_idx++; | ||
494 | ts->read_cnt = 0; | 485 | ts->read_cnt = 0; |
495 | ts->read_rep = 0; | 486 | ts->read_rep = 0; |
496 | m++; | 487 | return ADS7846_FILTER_OK; |
497 | } else | 488 | } else { |
498 | /* Read more values that are consistent. */ | 489 | /* Read more values that are consistent. */ |
499 | ts->read_cnt++; | 490 | ts->read_cnt++; |
491 | return ADS7846_FILTER_REPEAT; | ||
492 | } | ||
493 | } | ||
494 | } | ||
495 | |||
496 | static int ads7846_no_filter(void *ads, int data_idx, int *val) | ||
497 | { | ||
498 | return ADS7846_FILTER_OK; | ||
499 | } | ||
500 | |||
501 | static void ads7846_rx_val(void *ads) | ||
502 | { | ||
503 | struct ads7846 *ts = ads; | ||
504 | struct spi_message *m; | ||
505 | struct spi_transfer *t; | ||
506 | u16 *rx_val; | ||
507 | int val; | ||
508 | int action; | ||
509 | int status; | ||
510 | |||
511 | m = &ts->msg[ts->msg_idx]; | ||
512 | t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list); | ||
513 | rx_val = t->rx_buf; | ||
514 | |||
515 | /* adjust: on-wire is a must-ignore bit, a BE12 value, then padding; | ||
516 | * built from two 8 bit values written msb-first. | ||
517 | */ | ||
518 | val = be16_to_cpu(*rx_val) >> 3; | ||
519 | |||
520 | action = ts->filter(ts->filter_data, ts->msg_idx, &val); | ||
521 | switch (action) { | ||
522 | case ADS7846_FILTER_REPEAT: | ||
523 | break; | ||
524 | case ADS7846_FILTER_IGNORE: | ||
525 | ts->tc.ignore = 1; | ||
526 | /* Last message will contain ads7846_rx() as the | ||
527 | * completion function. | ||
528 | */ | ||
529 | m = ts->last_msg; | ||
530 | break; | ||
531 | case ADS7846_FILTER_OK: | ||
532 | *rx_val = val; | ||
533 | ts->tc.ignore = 0; | ||
534 | m = &ts->msg[++ts->msg_idx]; | ||
535 | break; | ||
536 | default: | ||
537 | BUG(); | ||
500 | } | 538 | } |
501 | status = spi_async(ts->spi, m); | 539 | status = spi_async(ts->spi, m); |
502 | if (status) | 540 | if (status) |
@@ -689,14 +727,25 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
689 | ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100; | 727 | ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100; |
690 | ts->x_plate_ohms = pdata->x_plate_ohms ? : 400; | 728 | ts->x_plate_ohms = pdata->x_plate_ohms ? : 400; |
691 | ts->pressure_max = pdata->pressure_max ? : ~0; | 729 | ts->pressure_max = pdata->pressure_max ? : ~0; |
692 | if (pdata->debounce_max) { | 730 | |
731 | if (pdata->filter != NULL) { | ||
732 | if (pdata->filter_init != NULL) { | ||
733 | err = pdata->filter_init(pdata, &ts->filter_data); | ||
734 | if (err < 0) | ||
735 | goto err_free_mem; | ||
736 | } | ||
737 | ts->filter = pdata->filter; | ||
738 | ts->filter_cleanup = pdata->filter_cleanup; | ||
739 | } else if (pdata->debounce_max) { | ||
693 | ts->debounce_max = pdata->debounce_max; | 740 | ts->debounce_max = pdata->debounce_max; |
741 | if (ts->debounce_max < 2) | ||
742 | ts->debounce_max = 2; | ||
694 | ts->debounce_tol = pdata->debounce_tol; | 743 | ts->debounce_tol = pdata->debounce_tol; |
695 | ts->debounce_rep = pdata->debounce_rep; | 744 | ts->debounce_rep = pdata->debounce_rep; |
696 | if (ts->debounce_rep > ts->debounce_max + 1) | 745 | ts->filter = ads7846_debounce; |
697 | ts->debounce_rep = ts->debounce_max - 1; | 746 | ts->filter_data = ts; |
698 | } else | 747 | } else |
699 | ts->debounce_tol = ~0; | 748 | ts->filter = ads7846_no_filter; |
700 | ts->get_pendown_state = pdata->get_pendown_state; | 749 | ts->get_pendown_state = pdata->get_pendown_state; |
701 | 750 | ||
702 | snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id); | 751 | snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id); |
@@ -737,7 +786,7 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
737 | x->len = 2; | 786 | x->len = 2; |
738 | spi_message_add_tail(x, m); | 787 | spi_message_add_tail(x, m); |
739 | 788 | ||
740 | m->complete = ads7846_debounce; | 789 | m->complete = ads7846_rx_val; |
741 | m->context = ts; | 790 | m->context = ts; |
742 | 791 | ||
743 | m++; | 792 | m++; |
@@ -755,7 +804,7 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
755 | x->len = 2; | 804 | x->len = 2; |
756 | spi_message_add_tail(x, m); | 805 | spi_message_add_tail(x, m); |
757 | 806 | ||
758 | m->complete = ads7846_debounce; | 807 | m->complete = ads7846_rx_val; |
759 | m->context = ts; | 808 | m->context = ts; |
760 | 809 | ||
761 | /* turn y+ off, x- on; we'll use formula #2 */ | 810 | /* turn y+ off, x- on; we'll use formula #2 */ |
@@ -774,7 +823,7 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
774 | x->len = 2; | 823 | x->len = 2; |
775 | spi_message_add_tail(x, m); | 824 | spi_message_add_tail(x, m); |
776 | 825 | ||
777 | m->complete = ads7846_debounce; | 826 | m->complete = ads7846_rx_val; |
778 | m->context = ts; | 827 | m->context = ts; |
779 | 828 | ||
780 | m++; | 829 | m++; |
@@ -791,7 +840,7 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
791 | x->len = 2; | 840 | x->len = 2; |
792 | spi_message_add_tail(x, m); | 841 | spi_message_add_tail(x, m); |
793 | 842 | ||
794 | m->complete = ads7846_debounce; | 843 | m->complete = ads7846_rx_val; |
795 | m->context = ts; | 844 | m->context = ts; |
796 | } | 845 | } |
797 | 846 | ||
@@ -820,7 +869,7 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
820 | spi->dev.driver->name, ts)) { | 869 | spi->dev.driver->name, ts)) { |
821 | dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); | 870 | dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); |
822 | err = -EBUSY; | 871 | err = -EBUSY; |
823 | goto err_free_mem; | 872 | goto err_cleanup_filter; |
824 | } | 873 | } |
825 | 874 | ||
826 | dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq); | 875 | dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq); |
@@ -856,6 +905,9 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
856 | sysfs_remove_group(&spi->dev.kobj, ts->attr_group); | 905 | sysfs_remove_group(&spi->dev.kobj, ts->attr_group); |
857 | err_free_irq: | 906 | err_free_irq: |
858 | free_irq(spi->irq, ts); | 907 | free_irq(spi->irq, ts); |
908 | err_cleanup_filter: | ||
909 | if (ts->filter_cleanup) | ||
910 | ts->filter_cleanup(ts->filter_data); | ||
859 | err_free_mem: | 911 | err_free_mem: |
860 | input_free_device(input_dev); | 912 | input_free_device(input_dev); |
861 | kfree(ts); | 913 | kfree(ts); |
@@ -876,6 +928,9 @@ static int __devexit ads7846_remove(struct spi_device *spi) | |||
876 | /* suspend left the IRQ disabled */ | 928 | /* suspend left the IRQ disabled */ |
877 | enable_irq(ts->spi->irq); | 929 | enable_irq(ts->spi->irq); |
878 | 930 | ||
931 | if (ts->filter_cleanup) | ||
932 | ts->filter_cleanup(ts->filter_data); | ||
933 | |||
879 | kfree(ts); | 934 | kfree(ts); |
880 | 935 | ||
881 | dev_dbg(&spi->dev, "unregistered touchscreen\n"); | 936 | dev_dbg(&spi->dev, "unregistered touchscreen\n"); |