From 08de236406ddd03163ed03a888e767913ef089d6 Mon Sep 17 00:00:00 2001 From: Luwei Date: Thu, 8 Aug 2013 16:35:24 +0800 Subject: [PATCH] ENGR00274247: touch: add egalax touch driver support on i.MX6Q/DL AUTO/SD Copy the egalax touch screen driver from linux3.5.7.Make some modification.Remove the __devinit __devexit __devexit_p out of the file, because 3.10 does not support. Signed-off-by: Luwei Zhou --- drivers/input/touchscreen/egalax_ts.c | 129 ++++++++++++++++++++------ 1 file changed, 103 insertions(+), 26 deletions(-) diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c index 39f3df8670c3..e237bdf678e0 100644 --- a/drivers/input/touchscreen/egalax_ts.c +++ b/drivers/input/touchscreen/egalax_ts.c @@ -1,7 +1,7 @@ /* * Driver for EETI eGalax Multiple Touch Controller * - * Copyright (C) 2011 Freescale Semiconductor, Inc. + * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. * * based on max11801_ts.c * @@ -35,7 +35,7 @@ * which can only report one point at a given time. * This driver will ignore events in this mode. */ -#define REPORT_MODE_MOUSE 0x1 +#define REPORT_MODE_SINGLE 0x1 /* * Vendor Mode: this mode is used to transfer some vendor specific * messages. @@ -47,6 +47,8 @@ #define MAX_SUPPORT_POINTS 5 +#define EVENT_MODE 0 +#define EVENT_STATUS 1 #define EVENT_VALID_OFFSET 7 #define EVENT_VALID_MASK (0x1 << EVENT_VALID_OFFSET) #define EVENT_ID_OFFSET 2 @@ -56,13 +58,21 @@ #define MAX_I2C_DATA_LEN 10 -#define EGALAX_MAX_X 32760 -#define EGALAX_MAX_Y 32760 +#define EGALAX_MAX_X 32767 +#define EGALAX_MAX_Y 32767 #define EGALAX_MAX_TRIES 100 +struct egalax_pointer { + bool valid; + bool status; + u16 x; + u16 y; +}; + struct egalax_ts { struct i2c_client *client; struct input_dev *input_dev; + struct egalax_pointer events[MAX_SUPPORT_POINTS]; }; static irqreturn_t egalax_ts_interrupt(int irq, void *dev_id) @@ -70,8 +80,9 @@ static irqreturn_t egalax_ts_interrupt(int irq, void *dev_id) struct egalax_ts *ts = dev_id; struct input_dev *input_dev = ts->input_dev; struct i2c_client *client = ts->client; + struct egalax_pointer *events = ts->events; u8 buf[MAX_I2C_DATA_LEN]; - int id, ret, x, y, z; + int i, id, ret, x, y; int tries = 0; bool down, valid; u8 state; @@ -83,15 +94,38 @@ static irqreturn_t egalax_ts_interrupt(int irq, void *dev_id) if (ret < 0) return IRQ_HANDLED; - if (buf[0] != REPORT_MODE_MTTOUCH) { - /* ignore mouse events and vendor events */ + 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) { + 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]; - z = (buf[7] << 8) | buf[6]; + + /* 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; + } valid = state & EVENT_VALID_MASK; id = (state & EVENT_ID_MASK) >> EVENT_ID_OFFSET; @@ -102,19 +136,50 @@ static irqreturn_t egalax_ts_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } - input_mt_slot(input_dev, id); - input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, down); - - dev_dbg(&client->dev, "%s id:%d x:%d y:%d z:%d", - down ? "down" : "up", id, x, y, z); - if (down) { - input_report_abs(input_dev, ABS_MT_POSITION_X, x); - input_report_abs(input_dev, ABS_MT_POSITION_Y, y); - input_report_abs(input_dev, ABS_MT_PRESSURE, z); + events[id].valid = valid; + events[id].status = down; + events[id].x = x; + events[id].y = y; + +#ifdef CONFIG_TOUCHSCREEN_EGALAX_SINGLE_TOUCH + input_report_abs(input_dev, ABS_X, x); + input_report_abs(input_dev, ABS_Y, y); + input_event(ts->input_dev, EV_KEY, BTN_TOUCH, 1); + input_report_abs(input_dev, ABS_PRESSURE, 1); +#endif + } else { + dev_dbg(&client->dev, "release id:%d\n", id); + events[id].valid = 0; + events[id].status = 0; +#ifdef CONFIG_TOUCHSCREEN_EGALAX_SINGLE_TOUCH + 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_mt_report_pointer_emulation(input_dev, true); +#ifndef CONFIG_TOUCHSCREEN_EGALAX_SINGLE_TOUCH + /* report all pointers */ + 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 input_sync(input_dev); return IRQ_HANDLED; @@ -203,22 +268,34 @@ static int egalax_ts_probe(struct i2c_client *client, goto err_free_dev; } - input_dev->name = "EETI eGalax Touch Screen"; + input_dev->name = "eGalax Touch Screen"; + input_dev->phys = "I2C", input_dev->id.bustype = BUS_I2C; + input_dev->id.vendor = 0x0EEF; + input_dev->id.product = 0x0020; + input_dev->id.version = 0x0001; input_dev->dev.parent = &client->dev; __set_bit(EV_ABS, input_dev->evbit); __set_bit(EV_KEY, input_dev->evbit); __set_bit(BTN_TOUCH, input_dev->keybit); - + __set_bit(ABS_X, input_dev->absbit); + __set_bit(ABS_Y, input_dev->absbit); + __set_bit(ABS_PRESSURE, input_dev->absbit); input_set_abs_params(input_dev, ABS_X, 0, EGALAX_MAX_X, 0, 0); input_set_abs_params(input_dev, ABS_Y, 0, EGALAX_MAX_Y, 0, 0); - input_set_abs_params(input_dev, - ABS_MT_POSITION_X, 0, EGALAX_MAX_X, 0, 0); - input_set_abs_params(input_dev, - ABS_MT_POSITION_Y, 0, EGALAX_MAX_Y, 0, 0); - input_mt_init_slots(input_dev, MAX_SUPPORT_POINTS, 0); - + input_set_abs_params(input_dev, ABS_PRESSURE, 0, 1, 0, 0); + +#ifndef CONFIG_TOUCHSCREEN_EGALAX_SINGLE_TOUCH + input_set_abs_params(input_dev, ABS_MT_POSITION_X, + 0, EGALAX_MAX_X, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, + 0, EGALAX_MAX_Y, 0, 0); + input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0, + MAX_SUPPORT_POINTS, 0, 0); +#endif input_set_drvdata(input_dev, ts); error = request_threaded_irq(client->irq, NULL, egalax_ts_interrupt, -- 2.39.5