]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
ads7846: Implement debouncing and rudimentary sample filtering
authorImre Deak <imre.deak@nokia.com>
Tue, 14 Feb 2006 14:00:15 +0000 (16:00 +0200)
committerJuha Yrjola <juha.yrjola@nokia.com>
Tue, 14 Feb 2006 14:00:15 +0000 (16:00 +0200)
Some touchscreens seem to oscillate heavily for a while after
touching the screen.  Implement support for sampling the screen
until we get two consecutive values that are close enough.

Signed-off-by: Imre Deak <imre.deak@nokia.com>
Signed-off-by: Juha Yrjölä <juha.yrjola@nokia.com>
arch/arm/mach-omap1/board-nokia770.c
drivers/input/touchscreen/ads7846.c
include/linux/spi/ads7846.h

index 2c583d1949a40df8feb05fbc621570b52c2cd942..3298864ab633965b918e90926fc12e1fa1c2e38b 100644 (file)
@@ -82,7 +82,8 @@ static struct ads7846_platform_data nokia770_ads7846_platform_data __initdata =
        .y_max          = 0x0fff,
        .x_plate_ohms   = 120,
        .pressure_max   = 200,
-
+       .debounce_max   = 10,
+       .debounce_tol   = 3,
 };
 
 static struct spi_board_info nokia770_spi_board_info[] __initdata = {
index 45823dce755c1cae426ab063a10ec29d4a31dc76..0aedb93c4e044392b6861e3520dc1b1333c5d3b2 100644 (file)
@@ -76,7 +76,13 @@ struct ads7846 {
        struct ts_event         tc;
 
        struct spi_transfer     xfer[10];
-       struct spi_message      msg;
+       struct spi_message      msg[5];
+       int                     msg_idx;
+       int                     read_cnt;
+       int                     last_read;
+
+       u16                     debounce_max;
+       u16                     debounce_tol;
 
        spinlock_t              lock;
        struct timer_list       timer;          /* P: lock */
@@ -343,31 +349,71 @@ static void ads7846_rx(void *ads)
        spin_unlock_irqrestore(&ts->lock, flags);
 }
 
+static void ads7846_debounce(void *ads)
+{
+       struct ads7846          *ts = ads;
+       struct spi_message      *m;
+       struct spi_transfer     *t;
+       u16                     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;
+       } else {
+               /* Go for the next read */
+               ts->msg_idx++;
+               ts->read_cnt = 0;
+               m++;
+       }
+       status = spi_async(ts->spi, m);
+       if (status)
+               dev_err(&ts->spi->dev, "spi_async --> %d\n",
+                               status);
+}
+
 static void ads7846_timer(unsigned long handle)
 {
        struct ads7846  *ts = (void *)handle;
        int             status = 0;
-       unsigned long   flags;
+
+       ts->msg_idx = 0;
+       status = spi_async(ts->spi, &ts->msg[0]);
+       if (status)
+               dev_err(&ts->spi->dev, "spi_async --> %d\n", status);
+}
+
+static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs)
+{
+       struct ads7846 *ts = handle;
+       unsigned long flags;
+       int r = IRQ_HANDLED;
 
        spin_lock_irqsave(&ts->lock, flags);
-       if (!ts->pending) {
-               ts->pending = 1;
+       if (ts->irq_disabled)
+               r = IRQ_HANDLED;
+       else {
                if (!ts->irq_disabled) {
                        ts->irq_disabled = 1;
+                       /* The following has at the moment no effect whatsoever
+                        * on OMAP, that's why we maintain the disabled
+                        * state ourselves */
                        disable_irq(ts->spi->irq);
                }
-               status = spi_async(ts->spi, &ts->msg);
-               if (status)
-                       dev_err(&ts->spi->dev, "spi_async --> %d\n",
-                                       status);
+               if (!ts->pending) {
+                       ts->pending = 1;
+                       mod_timer(&ts->timer, jiffies);
+               }
        }
        spin_unlock_irqrestore(&ts->lock, flags);
-}
-
-static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs)
-{
-       ads7846_timer((unsigned long) handle);
-       return IRQ_HANDLED;
+       return r;
 }
 
 /*--------------------------------------------------------------------------*/
@@ -425,6 +471,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        struct ads7846                  *ts;
        struct input_dev                *input_dev;
        struct ads7846_platform_data    *pdata = spi->dev.platform_data;
+       struct spi_message              *m;
        struct spi_transfer             *x;
        int                             err;
 
@@ -471,6 +518,8 @@ 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;
 
        snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id);
 
@@ -494,72 +543,98 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        /* set up the transfers to read touchscreen state; this assumes we
         * use formula #2 for pressure, not #3.
         */
-       spi_message_init(&ts->msg);
+       m = &ts->msg[0];
        x = ts->xfer;
 
+       spi_message_init(m);
+
        /* y- still on; turn on only y+ (and ADC) */
        ts->read_y = READ_Y;
        x->tx_buf = &ts->read_y;
        x->len = 1;
-       spi_message_add_tail(x, &ts->msg);
+       spi_message_add_tail(x, m);
 
        x++;
        x->rx_buf = &ts->tc.y;
        x->len = 2;
-       spi_message_add_tail(x, &ts->msg);
+       spi_message_add_tail(x, m);
+
+       m->complete = ads7846_debounce;
+       m->context = ts;
+
+       m++;
+       spi_message_init(m);
+
+       /* turn y- off, x+ on, then leave in lowpower */
+       x++;
+       ts->read_x = READ_X;
+       x->tx_buf = &ts->read_x;
+       x->len = 1;
+       spi_message_add_tail(x, m);
+
+       x++;
+       x->rx_buf = &ts->tc.x;
+       x->len = 2;
+       spi_message_add_tail(x, m);
+
+       m->complete = ads7846_debounce;
+       m->context = ts;
 
        /* turn y+ off, x- on; we'll use formula #2 */
        if (ts->model == 7846) {
+               m++;
+               spi_message_init(m);
+
                x++;
                ts->read_z1 = READ_Z1;
                x->tx_buf = &ts->read_z1;
                x->len = 1;
-               spi_message_add_tail(x, &ts->msg);
+               spi_message_add_tail(x, m);
 
                x++;
                x->rx_buf = &ts->tc.z1;
                x->len = 2;
-               spi_message_add_tail(x, &ts->msg);
+               spi_message_add_tail(x, m);
+
+               m->complete = ads7846_debounce;
+               m->context = ts;
+
+               m++;
+               spi_message_init(m);
 
                x++;
                ts->read_z2 = READ_Z2;
                x->tx_buf = &ts->read_z2;
                x->len = 1;
-               spi_message_add_tail(x, &ts->msg);
+               spi_message_add_tail(x, m);
 
                x++;
                x->rx_buf = &ts->tc.z2;
                x->len = 2;
-               spi_message_add_tail(x, &ts->msg);
-       }
+               spi_message_add_tail(x, m);
 
-       /* turn y- off, x+ on, then leave in lowpower */
-       x++;
-       ts->read_x = READ_X;
-       x->tx_buf = &ts->read_x;
-       x->len = 1;
-       spi_message_add_tail(x, &ts->msg);
-
-       x++;
-       x->rx_buf = &ts->tc.x;
-       x->len = 2;
-       spi_message_add_tail(x, &ts->msg);
+               m->complete = ads7846_debounce;
+               m->context = ts;
+       }
 
        /* power down */
+       m++;
+       spi_message_init(m);
+
        x++;
        ts->pwrdown = PWRDOWN;
        x->tx_buf = &ts->pwrdown;
        x->len = 1;
-       spi_message_add_tail(x, &ts->msg);
+       spi_message_add_tail(x, m);
 
        x++;
        x->rx_buf = &ts->dummy;
        x->len = 2;
        CS_CHANGE(*x);
-       spi_message_add_tail(x, &ts->msg);
+       spi_message_add_tail(x, m);
 
-       ts->msg.complete = ads7846_rx;
-       ts->msg.context = ts;
+       m->complete = ads7846_rx;
+       m->context = ts;
 
        if (request_irq(spi->irq, ads7846_irq,
                        SA_SAMPLE_RANDOM | SA_TRIGGER_FALLING,
index 72261e0f2ac19f29932ef36a154ae273a680eca2..3f76649512564de13bafbef74a3b3ea5df53c54e 100644 (file)
@@ -14,5 +14,8 @@ struct ads7846_platform_data {
        u16     x_min, x_max;
        u16     y_min, y_max;
        u16     pressure_min, pressure_max;
+
+       u16     debounce_max;           /* max number of readings per sample */
+       u16     debounce_tol;           /* tolerance used for filtering */
 };