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>
This commit is contained in:
committed by
Dmitry Torokhov
parent
ae82d5ab05
commit
d5b415c95f
@@ -71,6 +71,7 @@ struct ts_event {
|
|||||||
__be16 x;
|
__be16 x;
|
||||||
__be16 y;
|
__be16 y;
|
||||||
__be16 z1, z2;
|
__be16 z1, z2;
|
||||||
|
int ignore;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ads7846 {
|
struct ads7846 {
|
||||||
@@ -81,6 +82,7 @@ struct ads7846 {
|
|||||||
u16 model;
|
u16 model;
|
||||||
u16 vref_delay_usecs;
|
u16 vref_delay_usecs;
|
||||||
u16 x_plate_ohms;
|
u16 x_plate_ohms;
|
||||||
|
u16 pressure_max;
|
||||||
|
|
||||||
u8 read_x, read_y, read_z1, read_z2, pwrdown;
|
u8 read_x, read_y, read_z1, read_z2, pwrdown;
|
||||||
u16 dummy; /* for the pwrdown read */
|
u16 dummy; /* for the pwrdown read */
|
||||||
@@ -88,12 +90,15 @@ struct ads7846 {
|
|||||||
|
|
||||||
struct spi_transfer xfer[10];
|
struct spi_transfer xfer[10];
|
||||||
struct spi_message msg[5];
|
struct spi_message msg[5];
|
||||||
|
struct spi_message *last_msg;
|
||||||
int msg_idx;
|
int msg_idx;
|
||||||
int read_cnt;
|
int read_cnt;
|
||||||
|
int read_rep;
|
||||||
int last_read;
|
int last_read;
|
||||||
|
|
||||||
u16 debounce_max;
|
u16 debounce_max;
|
||||||
u16 debounce_tol;
|
u16 debounce_tol;
|
||||||
|
u16 debounce_rep;
|
||||||
|
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
struct timer_list timer; /* P: lock */
|
struct timer_list timer; /* P: lock */
|
||||||
@@ -354,6 +359,14 @@ static void ads7846_rx(void *ads)
|
|||||||
} else
|
} else
|
||||||
Rt = 0;
|
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
|
/* NOTE: "pendown" is inferred from pressure; we don't rely on
|
||||||
* being able to check nPENIRQ status, or "friendly" trigger modes
|
* being able to check nPENIRQ status, or "friendly" trigger modes
|
||||||
* (both-edges is much better than just-falling or low-level).
|
* (both-edges is much better than just-falling or low-level).
|
||||||
@@ -402,25 +415,45 @@ static void ads7846_debounce(void *ads)
|
|||||||
struct ads7846 *ts = ads;
|
struct ads7846 *ts = ads;
|
||||||
struct spi_message *m;
|
struct spi_message *m;
|
||||||
struct spi_transfer *t;
|
struct spi_transfer *t;
|
||||||
u16 val;
|
int val;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
m = &ts->msg[ts->msg_idx];
|
m = &ts->msg[ts->msg_idx];
|
||||||
t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
|
t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
|
||||||
val = (*(u16 *)t->rx_buf) >> 3;
|
val = (*(u16 *)t->rx_buf) >> 3;
|
||||||
|
if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol)) {
|
||||||
if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol
|
/* Repeat it, if this was the first read or the read
|
||||||
&& ts->read_cnt < ts->debounce_max)) {
|
* wasn't consistent enough. */
|
||||||
/* Repeat it, if this was the first read or the read wasn't
|
if (ts->read_cnt < ts->debounce_max) {
|
||||||
* consistent enough
|
ts->last_read = val;
|
||||||
*/
|
ts->read_cnt++;
|
||||||
ts->read_cnt++;
|
} else {
|
||||||
ts->last_read = val;
|
/* 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 {
|
} else {
|
||||||
/* Go for the next read */
|
if (++ts->read_rep > ts->debounce_rep) {
|
||||||
ts->msg_idx++;
|
/* Got a good reading for this coordinate,
|
||||||
ts->read_cnt = 0;
|
* go for the next one. */
|
||||||
m++;
|
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);
|
status = spi_async(ts->spi, m);
|
||||||
if (status)
|
if (status)
|
||||||
@@ -609,8 +642,15 @@ static int __devinit ads7846_probe(struct spi_device *spi)
|
|||||||
ts->model = pdata->model ? : 7846;
|
ts->model = pdata->model ? : 7846;
|
||||||
ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
|
ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
|
||||||
ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
|
ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
|
||||||
ts->debounce_max = pdata->debounce_max ? : 1;
|
ts->pressure_max = pdata->pressure_max ? : ~0;
|
||||||
ts->debounce_tol = pdata->debounce_tol ? : 10;
|
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;
|
ts->get_pendown_state = pdata->get_pendown_state;
|
||||||
|
|
||||||
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id);
|
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)
|
|||||||
m->complete = ads7846_rx;
|
m->complete = ads7846_rx;
|
||||||
m->context = ts;
|
m->context = ts;
|
||||||
|
|
||||||
|
ts->last_msg = m;
|
||||||
|
|
||||||
if (request_irq(spi->irq, ads7846_irq,
|
if (request_irq(spi->irq, ads7846_irq,
|
||||||
SA_SAMPLE_RANDOM | SA_TRIGGER_FALLING,
|
SA_SAMPLE_RANDOM | SA_TRIGGER_FALLING,
|
||||||
spi->dev.bus_id, ts)) {
|
spi->dev.bus_id, ts)) {
|
||||||
|
@@ -15,9 +15,11 @@ struct ads7846_platform_data {
|
|||||||
u16 y_min, y_max;
|
u16 y_min, y_max;
|
||||||
u16 pressure_min, pressure_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_tol; /* tolerance used for filtering */
|
||||||
|
u16 debounce_rep; /* additional consecutive good readings
|
||||||
|
* required after the first two */
|
||||||
int (*get_pendown_state)(void);
|
int (*get_pendown_state)(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user