Skip to content

Commit

Permalink
Input: ads7846 - improve filtering for thumb press accuracy
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Imre Deak authored and Dmitry Torokhov committed Apr 26, 2006
1 parent ae82d5a commit d5b415c
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 17 deletions.
72 changes: 57 additions & 15 deletions drivers/input/touchscreen/ads7846.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ struct ts_event {
__be16 x;
__be16 y;
__be16 z1, z2;
int ignore;
};

struct ads7846 {
Expand All @@ -81,19 +82,23 @@ struct ads7846 {
u16 model;
u16 vref_delay_usecs;
u16 x_plate_ohms;
u16 pressure_max;

u8 read_x, read_y, read_z1, read_z2, pwrdown;
u16 dummy; /* for the pwrdown read */
struct ts_event tc;

struct spi_transfer xfer[10];
struct spi_message msg[5];
struct spi_message *last_msg;
int msg_idx;
int read_cnt;
int read_rep;
int last_read;

u16 debounce_max;
u16 debounce_tol;
u16 debounce_rep;

spinlock_t lock;
struct timer_list timer; /* P: lock */
Expand Down Expand Up @@ -354,6 +359,14 @@ static void ads7846_rx(void *ads)
} else
Rt = 0;

/* Sample found inconsistent by debouncing or pressure is beyond
* the maximum. Don't report it to user space, repeat at least
* once more the measurement */
if (ts->tc.ignore || Rt > ts->pressure_max) {
mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
return;
}

/* NOTE: "pendown" is inferred from pressure; we don't rely on
* being able to check nPENIRQ status, or "friendly" trigger modes
* (both-edges is much better than just-falling or low-level).
Expand Down Expand Up @@ -402,25 +415,45 @@ static void ads7846_debounce(void *ads)
struct ads7846 *ts = ads;
struct spi_message *m;
struct spi_transfer *t;
u16 val;
int val;
int status;

m = &ts->msg[ts->msg_idx];
t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
val = (*(u16 *)t->rx_buf) >> 3;

if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol
&& ts->read_cnt < ts->debounce_max)) {
/* Repeat it, if this was the first read or the read wasn't
* consistent enough
*/
ts->read_cnt++;
ts->last_read = val;
if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol)) {
/* Repeat it, if this was the first read or the read
* wasn't consistent enough. */
if (ts->read_cnt < ts->debounce_max) {
ts->last_read = val;
ts->read_cnt++;
} else {
/* Maximum number of debouncing reached and still
* not enough number of consistent readings. Abort
* the whole sample, repeat it in the next sampling
* period.
*/
ts->tc.ignore = 1;
ts->read_cnt = 0;
/* Last message will contain ads7846_rx() as the
* completion function.
*/
m = ts->last_msg;
}
/* Start over collecting consistent readings. */
ts->read_rep = 0;
} else {
/* Go for the next read */
ts->msg_idx++;
ts->read_cnt = 0;
m++;
if (++ts->read_rep > ts->debounce_rep) {
/* Got a good reading for this coordinate,
* go for the next one. */
ts->tc.ignore = 0;
ts->msg_idx++;
ts->read_cnt = 0;
ts->read_rep = 0;
m++;
} else
/* Read more values that are consistent. */
ts->read_cnt++;
}
status = spi_async(ts->spi, m);
if (status)
Expand Down Expand Up @@ -609,8 +642,15 @@ static int __devinit ads7846_probe(struct spi_device *spi)
ts->model = pdata->model ? : 7846;
ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
ts->debounce_max = pdata->debounce_max ? : 1;
ts->debounce_tol = pdata->debounce_tol ? : 10;
ts->pressure_max = pdata->pressure_max ? : ~0;
if (pdata->debounce_max) {
ts->debounce_max = pdata->debounce_max;
ts->debounce_tol = pdata->debounce_tol;
ts->debounce_rep = pdata->debounce_rep;
if (ts->debounce_rep > ts->debounce_max + 1)
ts->debounce_rep = ts->debounce_max - 1;
} else
ts->debounce_tol = ~0;
ts->get_pendown_state = pdata->get_pendown_state;

snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id);
Expand Down Expand Up @@ -728,6 +768,8 @@ static int __devinit ads7846_probe(struct spi_device *spi)
m->complete = ads7846_rx;
m->context = ts;

ts->last_msg = m;

if (request_irq(spi->irq, ads7846_irq,
SA_SAMPLE_RANDOM | SA_TRIGGER_FALLING,
spi->dev.bus_id, ts)) {
Expand Down
6 changes: 4 additions & 2 deletions include/linux/spi/ads7846.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ struct ads7846_platform_data {
u16 y_min, y_max;
u16 pressure_min, pressure_max;

u16 debounce_max; /* max number of readings per sample */
u16 debounce_max; /* max number of additional readings
* per sample */
u16 debounce_tol; /* tolerance used for filtering */

u16 debounce_rep; /* additional consecutive good readings
* required after the first two */
int (*get_pendown_state)(void);
};

0 comments on commit d5b415c

Please sign in to comment.