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 | |
| 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>
| -rw-r--r-- | drivers/input/touchscreen/ads7846.c | 135 | ||||
| -rw-r--r-- | include/linux/spi/ads7846.h | 10 |
2 files changed, 105 insertions, 40 deletions
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index c6164b6f47..03e527c16c 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->d | ||
