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 | |
| 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')
| -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"); |
