]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/input/touchscreen/ads7846.c
Merge branch 'master' of git://oak/home/sfr/kernels/iseries/work
[mv-sheeva.git] / drivers / input / touchscreen / ads7846.c
index 1aaa153a2774420caeec2049d692de2d81fdd43a..66e411badf70c9f2752a2a557d973587aa5c074b 100644 (file)
 
 
 /*
- * This code has been tested on an ads7846 / N770 device.
+ * This code has been heavily tested on a Nokia 770, and lightly
+ * tested on other ads7846 devices (OSK/Mistral, Lubbock).
  * Support for ads7843 and ads7845 has only been stubbed in.
  *
- * Not yet done:  How accurate are the temperature and voltage
- * readings? (System-specific calibration should support
- * accuracy of 0.3 degrees C; otherwise it's 2.0 degrees.)
- *
  * IRQ handling needs a workaround because of a shortcoming in handling
  * edge triggered IRQs on some platforms like the OMAP1/2. These
  * platforms don't handle the ARM lazy IRQ disabling properly, thus we
@@ -71,6 +68,7 @@ struct ts_event {
        __be16 x;
        __be16 y;
        __be16 z1, z2;
+       int    ignore;
 };
 
 struct ads7846 {
@@ -81,6 +79,7 @@ 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 */
@@ -88,12 +87,15 @@ struct ads7846 {
 
        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 */
@@ -243,10 +245,13 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
 
        if (req->msg.status)
                status = req->msg.status;
+
+       /* on-wire is a must-ignore bit, a BE12 value, then padding */
        sample = be16_to_cpu(req->sample);
-       sample = sample >> 4;
-       kfree(req);
+       sample = sample >> 3;
+       sample &= 0x0fff;
 
+       kfree(req);
        return status ? status : sample;
 }
 
@@ -331,13 +336,13 @@ static void ads7846_rx(void *ads)
        u16                     x, y, z1, z2;
        unsigned long           flags;
 
-       /* adjust:  12 bit samples (left aligned), built from
-        * two 8 bit values writen msb-first.
+       /* adjust:  on-wire is a must-ignore bit, a BE12 value, then padding;
+        * built from two 8 bit values written msb-first.
         */
-       x = be16_to_cpu(ts->tc.x) >> 4;
-       y = be16_to_cpu(ts->tc.y) >> 4;
-       z1 = be16_to_cpu(ts->tc.z1) >> 4;
-       z2 = be16_to_cpu(ts->tc.z2) >> 4;
+       x = (be16_to_cpu(ts->tc.x) >> 3) & 0x0fff;
+       y = (be16_to_cpu(ts->tc.y) >> 3) & 0x0fff;
+       z1 = (be16_to_cpu(ts->tc.z1) >> 3) & 0x0fff;
+       z2 = (be16_to_cpu(ts->tc.z2) >> 3) & 0x0fff;
 
        /* range filtering */
        if (x == MAX_12BIT)
@@ -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).
@@ -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;
+       val = (be16_to_cpu(*(__be16 *)t->rx_buf) >> 3) & 0x0fff;
+       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)
@@ -436,7 +469,7 @@ static void ads7846_timer(unsigned long handle)
        spin_lock_irq(&ts->lock);
 
        if (unlikely(ts->msg_idx && !ts->pendown)) {
-               /* measurment cycle ended */
+               /* measurement cycle ended */
                if (!device_suspended(&ts->spi->dev)) {
                        ts->irq_disabled = 0;
                        enable_irq(ts->spi->irq);
@@ -462,11 +495,10 @@ static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs)
        spin_lock_irqsave(&ts->lock, flags);
        if (likely(ts->get_pendown_state())) {
                if (!ts->irq_disabled) {
-                       /* REVISIT irq logic for many ARM chips has cloned a
-                        * bug wherein disabling an irq in its handler won't
-                        * work;(it's disabled lazily, and too late to work.
-                        * until all their irq logic is fixed, we must shadow
-                        * that state here.
+                       /* The ARM do_simple_IRQ() dispatcher doesn't act
+                        * like the other dispatchers:  it will report IRQs
+                        * even after they've been disabled.  We work around
+                        * that here.  (The "generic irq" framework may help...)
                         */
                        ts->irq_disabled = 1;
                        disable_irq(ts->spi->irq);
@@ -576,16 +608,20 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                return -EINVAL;
        }
 
+       /* REVISIT when the irq can be triggered active-low, or if for some
+        * reason the touchscreen isn't hooked up, we don't need to access
+        * the pendown state.
+        */
        if (pdata->get_pendown_state == NULL) {
                dev_dbg(&spi->dev, "no get_pendown_state function?\n");
                return -EINVAL;
        }
 
-       /* We'd set the wordsize to 12 bits ... except that some controllers
-        * will then treat the 8 bit command words as 12 bits (and drop the
-        * four MSBs of the 12 bit result).  Result: inputs must be shifted
-        * to discard the four garbage LSBs.
+       /* We'd set TX wordsize 8 bits and RX wordsize to 13 bits ... except
+        * that even if the hardware can do that, the SPI controller driver
+        * may not.  So we stick to very-portable 8 bit words, both RX and TX.
         */
+       spi->bits_per_word = 8;
 
        ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);
        input_dev = input_allocate_device();
@@ -609,8 +645,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);
@@ -728,9 +771,10 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        m->complete = ads7846_rx;
        m->context = ts;
 
-       if (request_irq(spi->irq, ads7846_irq,
-                       SA_SAMPLE_RANDOM | SA_TRIGGER_FALLING,
-                       spi->dev.bus_id, ts)) {
+       ts->last_msg = m;
+
+       if (request_irq(spi->irq, ads7846_irq, IRQF_TRIGGER_FALLING,
+                       spi->dev.driver->name, ts)) {
                dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
                err = -EBUSY;
                goto err_free_mem;