aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorImre Deak <imre.deak@nokia.com>2006-04-26 00:13:18 -0400
committerDmitry Torokhov <dtor_core@ameritech.net>2006-04-26 00:13:18 -0400
commitd5b415c95f0e6510451f1446cea832c1f77bd7ea (patch)
tree39bd4140c5e80082c20a1a6a4a0bad1df83b63ca
parentae82d5ab05068fccef2329f4607670f24c41606f (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.c72
-rw-r--r--include/linux/spi/ads7846.h6
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
76struct ads7846 { 77struct 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