Firstly, changed the IRQ mode to PENDAV, which acts as a heartbeat
to keep at least part of the IRQ/SPI sequence active while the pen
is down. Secondly, implemented an IRQ counting scheme so that the
SPI can lag far behind the IRQs. This requires ignoring pen-up
timeouts until you know there are no SPI requests pending. For
additional stability, lengthen the pen-up timeout, and decrease
the rate of the interrupts (increase batch delay).

Signed-off-by: Phil Carmody <[email protected]>
---
 drivers/input/touchscreen/tsc2005.c |   56 ++++++++++++++++++++++------------
 1 files changed, 36 insertions(+), 20 deletions(-)

diff --git a/drivers/input/touchscreen/tsc2005.c 
b/drivers/input/touchscreen/tsc2005.c
index e3e63a5..104ead2 100644
--- a/drivers/input/touchscreen/tsc2005.c
+++ b/drivers/input/touchscreen/tsc2005.c
@@ -145,7 +145,7 @@
 #define TSC2005_CFR1_BATCHDELAY_40MS   (0x0006)
 #define TSC2005_CFR1_BATCHDELAY_100MS  (0x0007)
 
-#define TSC2005_CFR1_INITVALUE (TSC2005_CFR1_BATCHDELAY_2MS)
+#define TSC2005_CFR1_INITVALUE (TSC2005_CFR1_BATCHDELAY_4MS)
 
 #define TSC2005_CFR2_MAVE_TEMP (0x0001)
 #define TSC2005_CFR2_MAVE_AUX  (0x0002)
@@ -160,11 +160,12 @@
 #define TSC2005_CFR2_MEDIUM_7  (0x2000)
 #define TSC2005_CFR2_MEDIUM_15 (0x3000)
 
+#define TSC2005_CFR2_IRQ_MASK   (0xC000)
 #define TSC2005_CFR2_IRQ_DAV   (0x4000)
 #define TSC2005_CFR2_IRQ_PEN   (0x8000)
 #define TSC2005_CFR2_IRQ_PENDAV        (0x0000)
 
-#define TSC2005_CFR2_INITVALUE (TSC2005_CFR2_IRQ_DAV   |       \
+#define TSC2005_CFR2_INITVALUE (TSC2005_CFR2_IRQ_PENDAV |      \
                                 TSC2005_CFR2_MAVE_X    |       \
                                 TSC2005_CFR2_MAVE_Y    |       \
                                 TSC2005_CFR2_MAVE_Z    |       \
@@ -174,7 +175,7 @@
 #define MAX_12BIT                                      ((1 << 12) - 1)
 #define TS_SAMPLES                                     4
 #define TS_RECT_SIZE                                   8
-#define TSC2005_TS_PENUP_TIME                          20
+#define TSC2005_TS_PENUP_TIME                          40
 
 static const u32 tsc2005_read_reg[] = {
        (TSC2005_REG | TSC2005_REG_X | TSC2005_REG_READ) << 16,
@@ -218,7 +219,7 @@ struct tsc2005 {
        u8                      pen_down;
        u8                      disabled;
        u8                      disable_depth;
-       u8                      spi_active;
+       u8                      spi_pending;
 };
 
 static void tsc2005_cmd(struct tsc2005 *ts, u8 cmd)
@@ -327,8 +328,8 @@ static void tsc2005_ts_rx(void *arg)
        ts->avg_z1 = 0;
        ts->avg_z2 = 0;
 
-               pressure = x * (z2 - z1) / z1;
-               pressure = pressure * ts->x_plate_ohm / 4096;
+       pressure = x * (z2 - z1) / z1;
+       pressure = pressure * ts->x_plate_ohm / 4096;
 
        pressure_limit = ts->sample_sent? ts->p_max: ts->touch_pressure;
        if (pressure > pressure_limit)
@@ -352,7 +353,19 @@ static void tsc2005_ts_rx(void *arg)
                ts->p = pressure;
        }
 out:
-       ts->spi_active = 0;
+       if (ts->spi_pending > 1) {
+               /* One or more interrupts (sometimes several dozens)
+                * occured while waiting for the SPI read - get
+                * another read going.
+                */
+               ts->spi_pending = 1;
+               if (spi_async(ts->spi, &ts->read_msg)) {
+                       dev_err(&ts->spi->dev, "ts: spi_async() failed");
+                       ts->spi_pending = 0;
+               }
+       } else
+               ts->spi_pending = 0;
+
        spin_unlock_irqrestore(&ts->lock, flags);
 
        /* kick pen up timer - to make sure it expires again(!) */
@@ -364,8 +377,7 @@ out:
 static void tsc2005_ts_penup_timer_handler(unsigned long data)
 {
        struct tsc2005 *ts = (struct tsc2005 *)data;
-
-       if (ts->sample_sent) {
+       if (!ts->spi_pending && ts->sample_sent) {
                tsc2005_ts_update_pen_state(ts, 0, 0, 0);
                ts->sample_sent = 0;
        }
@@ -373,20 +385,21 @@ static void tsc2005_ts_penup_timer_handler(unsigned long 
data)
 
 /*
  * This interrupt is called when pen is down and coordinates are
- * available. That is indicated by a falling edge on DAV line.
+ * available. That is indicated by a either:
+ * a) a rising edge on PINTDAV or (PENDAV mode)
+ * b) a falling edge on DAV line (DAV mode)
+ * depending on the setting of the IRQ bits in the CFR2 setting above.
  */
 static irqreturn_t tsc2005_ts_irq_handler(int irq, void *dev_id)
 {
        struct tsc2005 *ts = dev_id;
-       int r;
-
-       if (ts->spi_active)
-               return IRQ_HANDLED;
 
-       ts->spi_active = 1;
-       r = spi_async(ts->spi, &ts->read_msg);
-       if (r)
-               dev_err(&ts->spi->dev, "ts: spi_async() failed");
+       if (!ts->spi_pending) {
+               if (spi_async(ts->spi, &ts->read_msg))
+                       dev_err(&ts->spi->dev, "ts: spi_async() failed");
+       }
+       /* By shifting in 1s we can never wrap */
+       ts->spi_pending = (ts->spi_pending<<1)+1;
 
        /* kick pen up timer */
        mod_timer(&ts->penup_timer,
@@ -561,8 +574,11 @@ static int __devinit tsc2005_ts_init(struct tsc2005 *ts,
        tsc2005_start_scan(ts);
 
        r = request_irq(ts->spi->irq, tsc2005_ts_irq_handler,
-                       IRQF_TRIGGER_FALLING | IRQF_DISABLED |
-                       IRQF_SAMPLE_RANDOM, "tsc2005", ts);
+                       (((TSC2005_CFR2_INITVALUE & TSC2005_CFR2_IRQ_MASK) ==
+                         TSC2005_CFR2_IRQ_PENDAV)
+                        ? IRQF_TRIGGER_RISING
+                        : IRQF_TRIGGER_FALLING) |
+                       IRQF_DISABLED | IRQF_SAMPLE_RANDOM, "tsc2005", ts);
        if (r < 0) {
                dev_err(&ts->spi->dev, "unable to get DAV IRQ");
                goto err2;
-- 
1.5.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to