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 --- 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