Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Imre Deak and committed by
Dmitry Torokhov
d5b415c9 ae82d5ab

+61 -17
+57 -15
drivers/input/touchscreen/ads7846.c
··· 71 71 __be16 x; 72 72 __be16 y; 73 73 __be16 z1, z2; 74 + int ignore; 74 75 }; 75 76 76 77 struct ads7846 { ··· 82 81 u16 model; 83 82 u16 vref_delay_usecs; 84 83 u16 x_plate_ohms; 84 + u16 pressure_max; 85 85 86 86 u8 read_x, read_y, read_z1, read_z2, pwrdown; 87 87 u16 dummy; /* for the pwrdown read */ ··· 90 88 91 89 struct spi_transfer xfer[10]; 92 90 struct spi_message msg[5]; 91 + struct spi_message *last_msg; 93 92 int msg_idx; 94 93 int read_cnt; 94 + int read_rep; 95 95 int last_read; 96 96 97 97 u16 debounce_max; 98 98 u16 debounce_tol; 99 + u16 debounce_rep; 99 100 100 101 spinlock_t lock; 101 102 struct timer_list timer; /* P: lock */ ··· 359 354 } else 360 355 Rt = 0; 361 356 357 + /* Sample found inconsistent by debouncing or pressure is beyond 358 + * the maximum. Don't report it to user space, repeat at least 359 + * once more the measurement */ 360 + if (ts->tc.ignore || Rt > ts->pressure_max) { 361 + mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD); 362 + return; 363 + } 364 + 362 365 /* NOTE: "pendown" is inferred from pressure; we don't rely on 363 366 * being able to check nPENIRQ status, or "friendly" trigger modes 364 367 * (both-edges is much better than just-falling or low-level). ··· 415 402 struct ads7846 *ts = ads; 416 403 struct spi_message *m; 417 404 struct spi_transfer *t; 418 - u16 val; 405 + int val; 419 406 int status; 420 407 421 408 m = &ts->msg[ts->msg_idx]; 422 409 t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list); 423 410 val = (*(u16 *)t->rx_buf) >> 3; 424 - 425 - if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol 426 - && ts->read_cnt < ts->debounce_max)) { 427 - /* Repeat it, if this was the first read or the read wasn't 428 - * consistent enough 429 - */ 430 - ts->read_cnt++; 431 - ts->last_read = val; 411 + if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol)) { 412 + /* Repeat it, if this was the first read or the read 413 + * wasn't consistent enough. */ 414 + if (ts->read_cnt < ts->debounce_max) { 415 + ts->last_read = val; 416 + ts->read_cnt++; 417 + } else { 418 + /* Maximum number of debouncing reached and still 419 + * not enough number of consistent readings. Abort 420 + * the whole sample, repeat it in the next sampling 421 + * period. 422 + */ 423 + ts->tc.ignore = 1; 424 + ts->read_cnt = 0; 425 + /* Last message will contain ads7846_rx() as the 426 + * completion function. 427 + */ 428 + m = ts->last_msg; 429 + } 430 + /* Start over collecting consistent readings. */ 431 + ts->read_rep = 0; 432 432 } else { 433 - /* Go for the next read */ 434 - ts->msg_idx++; 435 - ts->read_cnt = 0; 436 - m++; 433 + if (++ts->read_rep > ts->debounce_rep) { 434 + /* Got a good reading for this coordinate, 435 + * go for the next one. */ 436 + ts->tc.ignore = 0; 437 + ts->msg_idx++; 438 + ts->read_cnt = 0; 439 + ts->read_rep = 0; 440 + m++; 441 + } else 442 + /* Read more values that are consistent. */ 443 + ts->read_cnt++; 437 444 } 438 445 status = spi_async(ts->spi, m); 439 446 if (status) ··· 642 609 ts->model = pdata->model ? : 7846; 643 610 ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100; 644 611 ts->x_plate_ohms = pdata->x_plate_ohms ? : 400; 645 - ts->debounce_max = pdata->debounce_max ? : 1; 646 - ts->debounce_tol = pdata->debounce_tol ? : 10; 612 + ts->pressure_max = pdata->pressure_max ? : ~0; 613 + if (pdata->debounce_max) { 614 + ts->debounce_max = pdata->debounce_max; 615 + ts->debounce_tol = pdata->debounce_tol; 616 + ts->debounce_rep = pdata->debounce_rep; 617 + if (ts->debounce_rep > ts->debounce_max + 1) 618 + ts->debounce_rep = ts->debounce_max - 1; 619 + } else 620 + ts->debounce_tol = ~0; 647 621 ts->get_pendown_state = pdata->get_pendown_state; 648 622 649 623 snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id); ··· 767 727 768 728 m->complete = ads7846_rx; 769 729 m->context = ts; 730 + 731 + ts->last_msg = m; 770 732 771 733 if (request_irq(spi->irq, ads7846_irq, 772 734 SA_SAMPLE_RANDOM | SA_TRIGGER_FALLING,
+4 -2
include/linux/spi/ads7846.h
··· 15 15 u16 y_min, y_max; 16 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 20 u16 debounce_tol; /* tolerance used for filtering */ 20 - 21 + u16 debounce_rep; /* additional consecutive good readings 22 + * required after the first two */ 21 23 int (*get_pendown_state)(void); 22 24 }; 23 25