diff options
author | Imre Deak <imre.deak@nokia.com> | 2006-04-26 00:13:18 -0400 |
---|---|---|
committer | Dmitry Torokhov <dtor_core@ameritech.net> | 2006-04-26 00:13:18 -0400 |
commit | d5b415c95f0e6510451f1446cea832c1f77bd7ea (patch) | |
tree | 39bd4140c5e80082c20a1a6a4a0bad1df83b63ca | |
parent | ae82d5ab05068fccef2329f4607670f24c41606f (diff) |
Input: ads7846 - improve filtering for thumb press accuracy
Providing more accurate coordinates for thumb press requires additional
steps in the filtering logic:
- Ignore samples found invalid by the debouncing logic, or the ones that
have out of bound pressure value.
- Add a parameter to repeat debouncing, so that more then two consecutive
good readings are required for a valid sample.
Signed-off-by: Imre Deak <imre.deak@nokia.com>
Acked-by: Juha Yrjola <juha.yrjola@nokia.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r-- | drivers/input/touchscreen/ads7846.c | 72 | ||||
-rw-r--r-- | include/linux/spi/ads7846.h | 6 |
2 files changed, 61 insertions, 17 deletions
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 1aaa153a2774..1494175ac6fe 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c | |||
@@ -71,6 +71,7 @@ struct ts_event { | |||
71 | __be16 x; | 71 | __be16 x; |
72 | __be16 y; | 72 | __be16 y; |
73 | __be16 z1, z2; | 73 | __be16 z1, z2; |
74 | int ignore; | ||
74 | }; | 75 | }; |
75 | 76 | ||
76 | struct ads7846 { | 77 | struct ads7846 { |
@@ -81,6 +82,7 @@ struct ads7846 { | |||
81 | u16 model; | 82 | u16 model; |
82 | u16 vref_delay_usecs; | 83 | u16 vref_delay_usecs; |
83 | u16 x_plate_ohms; | 84 | u16 x_plate_ohms; |
85 | u16 pressure_max; | ||
84 | 86 | ||
85 | u8 read_x, read_y, read_z1, read_z2, pwrdown; | 87 | u8 read_x, read_y, read_z1, read_z2, pwrdown; |
86 | u16 dummy; /* for the pwrdown read */ | 88 | u16 dummy; /* for the pwrdown read */ |
@@ -88,12 +90,15 @@ struct ads7846 { | |||
88 | 90 | ||
89 | struct spi_transfer xfer[10]; | 91 | struct spi_transfer xfer[10]; |
90 | struct spi_message msg[5]; | 92 | struct spi_message msg[5]; |
93 | struct spi_message *last_msg; | ||
91 | int msg_idx; | 94 | int msg_idx; |
92 | int read_cnt; | 95 | int read_cnt; |
96 | int read_rep; | ||
93 | int last_read; | 97 | int last_read; |
94 | 98 | ||
95 | u16 debounce_max; | 99 | u16 debounce_max; |
96 | u16 debounce_tol; | 100 | u16 debounce_tol; |
101 | u16 debounce_rep; | ||
97 | 102 | ||
98 | spinlock_t lock; | 103 | spinlock_t lock; |
99 | struct timer_list timer; /* P: lock */ | 104 | struct timer_list timer; /* P: lock */ |
@@ -354,6 +359,14 @@ static void ads7846_rx(void *ads) | |||
354 | } else | 359 | } else |
355 | Rt = 0; | 360 | Rt = 0; |
356 | 361 | ||
362 | /* Sample found inconsistent by debouncing or pressure is beyond | ||
363 | * the maximum. Don't report it to user space, repeat at least | ||
364 | * once more the measurement */ | ||
365 | if (ts->tc.ignore || Rt > ts->pressure_max) { | ||
366 | mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD); | ||
367 | return; | ||
368 | } | ||
369 | |||
357 | /* NOTE: "pendown" is inferred from pressure; we don't rely on | 370 | /* NOTE: "pendown" is inferred from pressure; we don't rely on |
358 | * being able to check nPENIRQ status, or "friendly" trigger modes | 371 | * being able to check nPENIRQ status, or "friendly" trigger modes |
359 | * (both-edges is much better than just-falling or low-level). | 372 | * (both-edges is much better than just-falling or low-level). |
@@ -402,25 +415,45 @@ static void ads7846_debounce(void *ads) | |||
402 | struct ads7846 *ts = ads; | 415 | struct ads7846 *ts = ads; |
403 | struct spi_message *m; | 416 | struct spi_message *m; |
404 | struct spi_transfer *t; | 417 | struct spi_transfer *t; |
405 | u16 val; | 418 | int val; |
406 | int status; | 419 | int status; |
407 | 420 | ||
408 | m = &ts->msg[ts->msg_idx]; | 421 | m = &ts->msg[ts->msg_idx]; |
409 | t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list); | 422 | t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list); |
410 | val = (*(u16 *)t->rx_buf) >> 3; | 423 | val = (*(u16 *)t->rx_buf) >> 3; |
411 | 424 | if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol)) { | |
412 | if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol | 425 | /* Repeat it, if this was the first read or the read |
413 | && ts->read_cnt < ts->debounce_max)) { | 426 | * wasn't consistent enough. */ |
414 | /* Repeat it, if this was the first read or the read wasn't | 427 | if (ts->read_cnt < ts->debounce_max) { |
415 | * consistent enough | 428 | ts->last_read = val; |
416 | */ | 429 | ts->read_cnt++; |
417 | ts->read_cnt++; | 430 | } else { |
418 | ts->last_read = val; | 431 | /* Maximum number of debouncing reached and still |
432 | * not enough number of consistent readings. Abort | ||
433 | * the whole sample, repeat it in the next sampling | ||
434 | * period. | ||
435 | */ | ||
436 | ts->tc.ignore = 1; | ||
437 | ts->read_cnt = 0; | ||
438 | /* Last message will contain ads7846_rx() as the | ||
439 | * completion function. | ||
440 | */ | ||
441 | m = ts->last_msg; | ||
442 | } | ||
443 | /* Start over collecting consistent readings. */ | ||
444 | ts->read_rep = 0; | ||
419 | } else { | 445 | } else { |
420 | /* Go for the next read */ | 446 | if (++ts->read_rep > ts->debounce_rep) { |
421 | ts->msg_idx++; | 447 | /* Got a good reading for this coordinate, |
422 | ts->read_cnt = 0; | 448 | * go for the next one. */ |
423 | m++; | 449 | ts->tc.ignore = 0; |
450 | ts->msg_idx++; | ||
451 | ts->read_cnt = 0; | ||
452 | ts->read_rep = 0; | ||
453 | m++; | ||
454 | } else | ||
455 | /* Read more values that are consistent. */ | ||
456 | ts->read_cnt++; | ||
424 | } | 457 | } |
425 | status = spi_async(ts->spi, m); | 458 | status = spi_async(ts->spi, m); |
426 | if (status) | 459 | if (status) |
@@ -609,8 +642,15 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
609 | ts->model = pdata->model ? : 7846; | 642 | ts->model = pdata->model ? : 7846; |
610 | ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100; | 643 | ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100; |
611 | ts->x_plate_ohms = pdata->x_plate_ohms ? : 400; | 644 | ts->x_plate_ohms = pdata->x_plate_ohms ? : 400; |
612 | ts->debounce_max = pdata->debounce_max ? : 1; | 645 | ts->pressure_max = pdata->pressure_max ? : ~0; |
613 | ts->debounce_tol = pdata->debounce_tol ? : 10; | 646 | if (pdata->debounce_max) { |
647 | ts->debounce_max = pdata->debounce_max; | ||
648 | ts->debounce_tol = pdata->debounce_tol; | ||
649 | ts->debounce_rep = pdata->debounce_rep; | ||
650 | if (ts->debounce_rep > ts->debounce_max + 1) | ||
651 | ts->debounce_rep = ts->debounce_max - 1; | ||
652 | } else | ||
653 | ts->debounce_tol = ~0; | ||
614 | ts->get_pendown_state = pdata->get_pendown_state; | 654 | ts->get_pendown_state = pdata->get_pendown_state; |
615 | 655 | ||
616 | snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id); | 656 | snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id); |
@@ -728,6 +768,8 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
728 | m->complete = ads7846_rx; | 768 | m->complete = ads7846_rx; |
729 | m->context = ts; | 769 | m->context = ts; |
730 | 770 | ||
771 | ts->last_msg = m; | ||
772 | |||
731 | if (request_irq(spi->irq, ads7846_irq, | 773 | if (request_irq(spi->irq, ads7846_irq, |
732 | SA_SAMPLE_RANDOM | SA_TRIGGER_FALLING, | 774 | SA_SAMPLE_RANDOM | SA_TRIGGER_FALLING, |
733 | spi->dev.bus_id, ts)) { | 775 | spi->dev.bus_id, ts)) { |
diff --git a/include/linux/spi/ads7846.h b/include/linux/spi/ads7846.h index d8823e237e0b..adb3dafd33e9 100644 --- a/include/linux/spi/ads7846.h +++ b/include/linux/spi/ads7846.h | |||
@@ -15,9 +15,11 @@ struct ads7846_platform_data { | |||
15 | u16 y_min, y_max; | 15 | u16 y_min, y_max; |
16 | u16 pressure_min, pressure_max; | 16 | u16 pressure_min, pressure_max; |
17 | 17 | ||
18 | u16 debounce_max; /* max number of readings per sample */ | 18 | u16 debounce_max; /* max number of additional readings |
19 | * per sample */ | ||
19 | u16 debounce_tol; /* tolerance used for filtering */ | 20 | u16 debounce_tol; /* tolerance used for filtering */ |
20 | 21 | u16 debounce_rep; /* additional consecutive good readings | |
22 | * required after the first two */ | ||
21 | int (*get_pendown_state)(void); | 23 | int (*get_pendown_state)(void); |
22 | }; | 24 | }; |
23 | 25 | ||