diff options
author | Roshni Shah <roshni.shah@timesys.com> | 2014-01-05 11:50:19 -0500 |
---|---|---|
committer | Roshni Shah <roshni.shah@timesys.com> | 2014-01-05 13:04:02 -0500 |
commit | f2a0b753bc57f2d40119762879071cbdd0a215fe (patch) | |
tree | f17cde8e9e6fd30197c287de74775d1cf851e3f4 | |
parent | b609471386808e9996877ca99a8c5219ae8e924f (diff) |
Quartz: Modified the LVDS touchscreen driver (egalax) to use Falling Edge GPIO
interrupt instead of level triggered (low) to fix the following issue seen on
MVF platform.
Level Triggered interrupts are not One Shot in nature, resulting in interrupt
handler being called continusouly until a GPIO state change.
-rw-r--r-- | drivers/input/touchscreen/egalax_ts.c | 197 |
1 files changed, 105 insertions, 92 deletions
diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c index fff8afe1b41a..9d9fa5ab6d3a 100644 --- a/drivers/input/touchscreen/egalax_ts.c +++ b/drivers/input/touchscreen/egalax_ts.c @@ -57,6 +57,7 @@ #define MAX_I2C_DATA_LEN 10 +#define FORCE_SINGLE_POINTER_SUPPORT struct egalax_pointer { bool valid; bool status; @@ -80,103 +81,115 @@ static irqreturn_t egalax_ts_interrupt(int irq, void *dev_id) int i, id, ret, x, y; bool down, valid; u8 state; + int irqStatus = 0; -retry: - ret = i2c_master_recv(client, buf, MAX_I2C_DATA_LEN); - if (ret == -EAGAIN) - goto retry; + irqStatus = gpio_get_value(irq_to_gpio(irq)); - if (ret < 0) - return IRQ_HANDLED; + while(irqStatus == 0) + { +retry: + ret = i2c_master_recv(client, buf, MAX_I2C_DATA_LEN); + if (ret == -EAGAIN) + goto retry; + + if (ret < 0) + { + printk("EGALAX: error receiving i2c data\n"); + return IRQ_HANDLED; + } - dev_dbg(&client->dev, "recv ret:%d", ret); - for (i = 0; i < MAX_I2C_DATA_LEN; i++) - dev_dbg(&client->dev, " %x ", buf[i]); + dev_dbg(&client->dev, "recv ret:%d", ret); + for (i = 0; i < MAX_I2C_DATA_LEN; i++) + dev_dbg(&client->dev, " %x ", buf[i]); - if (buf[0] != REPORT_MODE_VENDOR - && buf[0] != REPORT_MODE_SINGLE - && buf[0] != REPORT_MODE_MTTOUCH) { - /* invalid point */ - return IRQ_HANDLED; - } + if (buf[0] != REPORT_MODE_VENDOR + && buf[0] != REPORT_MODE_SINGLE + && buf[0] != REPORT_MODE_MTTOUCH) { + /* invalid point */ + printk("EGALAX: Invalid point\n"); + return IRQ_HANDLED; + } - if (buf[0] == REPORT_MODE_VENDOR) { - dev_dbg(&client->dev, "vendor message, ignored\n"); - return IRQ_HANDLED; - } + if (buf[0] == REPORT_MODE_VENDOR) { + dev_dbg(&client->dev, "vendor message, ignored\n"); + return IRQ_HANDLED; + } - state = buf[1]; - x = (buf[3] << 8) | buf[2]; - y = (buf[5] << 8) | buf[4]; - - /* Currently, the panel Freescale using on SMD board _NOT_ - * support single pointer mode. All event are going to - * multiple pointer mode. Add single pointer mode according - * to EETI eGalax I2C programming manual. - */ - if (buf[0] == REPORT_MODE_SINGLE) { - input_report_abs(input_dev, ABS_X, x); - input_report_abs(input_dev, ABS_Y, y); - input_report_key(input_dev, BTN_TOUCH, !!state); - input_sync(input_dev); - return IRQ_HANDLED; - } + state = buf[1]; + x = (buf[3] << 8) | buf[2]; + y = (buf[5] << 8) | buf[4]; + + /* Currently, the panel Freescale using on SMD board _NOT_ + * support single pointer mode. All event are going to + * multiple pointer mode. Add single pointer mode according + * to EETI eGalax I2C programming manual. + */ + if (buf[0] == REPORT_MODE_SINGLE) { + input_report_abs(input_dev, ABS_X, x); + input_report_abs(input_dev, ABS_Y, y); + input_report_key(input_dev, BTN_TOUCH, !!state); + input_sync(input_dev); + return IRQ_HANDLED; + } - /* deal with multiple touch */ - valid = state & EVENT_VAILD_MASK; - id = (state & EVENT_ID_MASK) >> EVENT_ID_OFFSET; - down = state & EVENT_DOWN_UP; + /* deal with multiple touch */ + valid = state & EVENT_VAILD_MASK; + id = (state & EVENT_ID_MASK) >> EVENT_ID_OFFSET; + down = state & EVENT_DOWN_UP; - if (!valid || id > MAX_SUPPORT_POINTS) { - dev_dbg(&client->dev, "point invalid\n"); - return IRQ_HANDLED; - } + if (!valid || id > MAX_SUPPORT_POINTS) { + dev_dbg(&client->dev, "point invalid\n"); + return IRQ_HANDLED; + } - if (down) { - /* should also report old pointers */ - events[id].valid = valid; - events[id].status = down; - events[id].x = x; - events[id].y = y; - -#ifdef FORCE_SINGLE_POINTER_SUPPORT - input_report_abs(input_dev, ABS_X, x); - input_report_abs(input_dev, ABS_Y, y); - input_event(data->input_dev, EV_KEY, BTN_TOUCH, 1); - input_report_abs(input_dev, ABS_PRESSURE, 1); -#else - for (i = 0; i < MAX_SUPPORT_POINTS; i++) { - if (!events[i].valid) - continue; - dev_dbg(&client->dev, "report id:%d valid:%d x:%d y:%d", - i, valid, x, y); - - input_report_abs(input_dev, - ABS_MT_TRACKING_ID, i); - input_report_abs(input_dev, - ABS_MT_TOUCH_MAJOR, 1); - input_report_abs(input_dev, - ABS_MT_POSITION_X, events[i].x); - input_report_abs(input_dev, - ABS_MT_POSITION_Y, events[i].y); + if (down) { + /* should also report old pointers */ + events[id].valid = valid; + events[id].status = down; + events[id].x = x; + events[id].y = y; + + #ifdef FORCE_SINGLE_POINTER_SUPPORT + input_report_abs(input_dev, ABS_X, x); + input_report_abs(input_dev, ABS_Y, y); + input_event(data->input_dev, EV_KEY, BTN_TOUCH, 1); + input_report_abs(input_dev, ABS_PRESSURE, 1); + #else + for (i = 0; i < MAX_SUPPORT_POINTS; i++) { + if (!events[i].valid) + continue; + dev_dbg(&client->dev, "report id:%d valid:%d x:%d y:%d", + i, valid, x, y); + + input_report_abs(input_dev, + ABS_MT_TRACKING_ID, i); + input_report_abs(input_dev, + ABS_MT_TOUCH_MAJOR, 1); + input_report_abs(input_dev, + ABS_MT_POSITION_X, events[i].x); + input_report_abs(input_dev, + ABS_MT_POSITION_Y, events[i].y); + input_mt_sync(input_dev); + } + #endif + } else { + dev_dbg(&client->dev, "release id:%d\n", id); + events[id].valid = 0; + events[id].status = 0; + #ifdef FORCE_SINGLE_POINTER_SUPPORT + input_report_key(input_dev, BTN_TOUCH, 0); + input_report_abs(input_dev, ABS_PRESSURE, 0); + #else + input_report_abs(input_dev, ABS_MT_TRACKING_ID, id); + input_event(input_dev, EV_ABS, ABS_MT_TOUCH_MAJOR, 0); input_mt_sync(input_dev); + #endif } -#endif - } else { - dev_dbg(&client->dev, "release id:%d\n", id); - events[id].valid = 0; - events[id].status = 0; -#ifdef FORCE_SINGLE_POINTER_SUPPORT - input_report_key(input_dev, BTN_TOUCH, 0); - input_report_abs(input_dev, ABS_PRESSURE, 0); -#else - input_report_abs(input_dev, ABS_MT_TRACKING_ID, id); - input_event(input_dev, EV_ABS, ABS_MT_TOUCH_MAJOR, 0); - input_mt_sync(input_dev); -#endif + + input_sync(input_dev); + irqStatus = gpio_get_value(irq_to_gpio(irq)); } - input_sync(input_dev); return IRQ_HANDLED; } @@ -232,13 +245,6 @@ static int __devinit egalax_ts_probe(struct i2c_client *client, data->client = client; data->input_dev = input_dev; egalax_wake_up_device(client); - ret = egalax_7200_firmware_version(client); - if (ret < 0) { - dev_err(&client->dev, - "egalax_ts: failed to read firmware version\n"); - ret = -EIO; - goto err_free_dev; - } input_dev->name = "eGalax Touch Screen"; input_dev->phys = "I2C", @@ -266,9 +272,16 @@ static int __devinit egalax_ts_probe(struct i2c_client *client, MAX_SUPPORT_POINTS, 0, 0); #endif input_set_drvdata(input_dev, data); + ret = egalax_7200_firmware_version(client); + if (ret < 0) { + dev_err(&client->dev, + "egalax_ts: failed to read firmware version\n"); + ret = -EIO; + goto err_free_dev; + } ret = request_threaded_irq(client->irq, NULL, egalax_ts_interrupt, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, + (IRQF_TRIGGER_FALLING | IRQF_ONESHOT), "egalax_ts", data); if (ret < 0) { dev_err(&client->dev, "Failed to register interrupt\n"); |