[PATCH] tsc2007: suppress successive pen down states to avoidfalse reads

From: Brian Harring
Date: Sun Oct 03 2010 - 22:44:01 EST


For the russellville platform, this makes the tsc2007 actually usable.

This patch has been kicking around MeeGo 1.0 for a while; not sure why it never
made it's way to upstream, but pushing it up that way now.

Signed-off-by: Brian Harring <ferringb@xxxxxxxxx>
---
drivers/input/touchscreen/tsc2007.c | 68 ++++++++++++++++++++++++++---------
1 files changed, 51 insertions(+), 17 deletions(-)

diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c
index be23780..05314fd 100644
--- a/drivers/input/touchscreen/tsc2007.c
+++ b/drivers/input/touchscreen/tsc2007.c
@@ -29,6 +29,7 @@

#define TS_POLL_DELAY 1 /* ms delay between samples */
#define TS_POLL_PERIOD 1 /* ms delay between samples */
+#define TS_SLOW_POLL_PERIOD 20 /* ms delay between pen down check */

#define TSC2007_MEASURE_TEMP0 (0x0 << 4)
#define TSC2007_MEASURE_AUX (0x2 << 4)
@@ -77,6 +78,7 @@ struct tsc2007 {
u16 x_plate_ohms;

bool pendown;
+ bool ignore_next_irq;
int irq;

int (*get_pendown_state)(void);
@@ -228,14 +230,39 @@ static void tsc2007_work(struct work_struct *work)
if (ts->pendown)
schedule_delayed_work(&ts->work,
msecs_to_jiffies(TS_POLL_PERIOD));
- else
- enable_irq(ts->irq);
+ else {
+ /* if we don't have the get pen down state callback we
+ * ignore the next IRQ because it is provoked when we checked
+ * the touch pressure.
+ * If the user really touches the screen we will get a new
+ * interrupt anyway so it is safe to ignore it
+ *
+ * This is basically implementing this part of the manual:
+ * "In both cases previously listed, it is recommended that
+ * whenever the host writes to the TSC2007, the master
+ * processor masks the interrupt associated to PENIRQ.
+ * This masking prevents false triggering of interrupts when
+ * the PENIRQ line is disabled in the cases previously listed."
+ */
+ if (!ts->get_pendown_state)
+ ts->ignore_next_irq = true;
+ if (ts->irq)
+ enable_irq(ts->irq);
+ else
+ schedule_delayed_work(&ts->work,
+ msecs_to_jiffies(TS_SLOW_POLL_PERIOD));
+ }
}

static irqreturn_t tsc2007_irq(int irq, void *handle)
{
struct tsc2007 *ts = handle;

+ if (ts->ignore_next_irq) {
+ ts->ignore_next_irq = false;
+ return IRQ_HANDLED;
+ }
+
if (!ts->get_pendown_state || likely(ts->get_pendown_state())) {
disable_irq_nosync(ts->irq);
schedule_delayed_work(&ts->work,
@@ -250,15 +277,18 @@ static irqreturn_t tsc2007_irq(int irq, void *handle)

static void tsc2007_free_irq(struct tsc2007 *ts)
{
- free_irq(ts->irq, ts);
- if (cancel_delayed_work_sync(&ts->work)) {
- /*
- * Work was pending, therefore we need to enable
- * IRQ here to balance the disable_irq() done in the
- * interrupt handler.
- */
- enable_irq(ts->irq);
- }
+ if (ts->irq) {
+ free_irq(ts->irq, ts);
+ if (cancel_delayed_work_sync(&ts->work)) {
+ /*
+ * Work was pending, therefore we need to enable
+ * IRQ here to balance the disable_irq() done in the
+ * interrupt handler.
+ */
+ enable_irq(ts->irq);
+ }
+ } else
+ cancel_delayed_work_sync(&ts->work);
}

static int __devinit tsc2007_probe(struct i2c_client *client,
@@ -312,12 +342,16 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
if (pdata->init_platform_hw)
pdata->init_platform_hw();

- err = request_irq(ts->irq, tsc2007_irq, 0,
- client->dev.driver->name, ts);
- if (err < 0) {
- dev_err(&client->dev, "irq %d busy?\n", ts->irq);
- goto err_free_mem;
- }
+
+ if (ts->irq) {
+ err = request_irq(ts->irq, tsc2007_irq, 0,
+ client->dev.driver->name, ts);
+ if (err < 0) {
+ dev_err(&client->dev, "irq %d busy?\n", ts->irq);
+ goto err_free_mem;
+ }
+ } else
+ schedule_delayed_work(&ts->work, TS_SLOW_POLL_PERIOD);

/* Prepare for touch readings - power down ADC and enable PENIRQ */
err = tsc2007_xfer(ts, PWRDOWN);
--
1.7.2

Attachment: pgp00000.pgp
Description: PGP signature