Message ID | 1311672354-15453-1-git-send-email-jiejing.zhang@freescale.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 07/26/2011 05:25 PM, Zhang Jiejing wrote: > this patch adds EETI eGalax serial multi touch controller driver. > > EETI eGalax serial touch screen controller is a I2C based multiple > capacitive touch screen controller, it can supports 5 touch events maximum. > > Signed-off-by: Zhang Jiejing<jiejing.zhang@freescale.com> > --- > drivers/input/touchscreen/Kconfig | 10 + > drivers/input/touchscreen/Makefile | 1 + > drivers/input/touchscreen/egalax_ts.c | 314 +++++++++++++++++++++++++++++++++ > 3 files changed, 325 insertions(+), 0 deletions(-) > create mode 100644 drivers/input/touchscreen/egalax_ts.c > > + > + if (down) { > + /* since egalax only report one of multi touch event, > + * so we need record pervious event with different id > + * and report them.*/ > + events[id].valid = valid; > + events[id].status = down; > + events[id].x = x; > + events[id].y = y; > + > + 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); > + } > + } else { > + dev_dbg(&client->dev, "release id:%d\n", id); > + events[id].valid = 0; > + events[id].status = 0; > + 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); > + } > + > + input_sync(input_dev); need re-sync here ? > + data->client = client; > + data->input_dev = input_dev; > + /* controller may be in sleep, wake it up. */ > + egalax_wake_up_device(client); > + ret = egalax_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 = "EETI eGalax Touch Screen"; > + input_dev->phys = "I2C", > + input_dev->id.bustype = BUS_I2C; > + 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); > + input_set_abs_params(input_dev, ABS_X, 0, 32767, 0, 0); > + input_set_abs_params(input_dev, ABS_Y, 0, 32767, 0, 0); make 32767 to macro here ?
Hi Gao, 2011/7/26 Wanlong Gao <gaowanlong@cn.fujitsu.com> > > On 07/26/2011 05:25 PM, Zhang Jiejing wrote: >> >> this patch adds EETI eGalax serial multi touch controller driver. >> >> EETI eGalax serial touch screen controller is a I2C based multiple >> capacitive touch screen controller, it can supports 5 touch events maximum. >> >> Signed-off-by: Zhang Jiejing<jiejing.zhang@freescale.com> >> --- >> drivers/input/touchscreen/Kconfig | 10 + >> drivers/input/touchscreen/Makefile | 1 + >> drivers/input/touchscreen/egalax_ts.c | 314 +++++++++++++++++++++++++++++++++ >> 3 files changed, 325 insertions(+), 0 deletions(-) >> create mode 100644 drivers/input/touchscreen/egalax_ts.c >> > >> + >> + if (down) { >> + /* since egalax only report one of multi touch event, >> + * so we need record pervious event with different id >> + * and report them.*/ >> + events[id].valid = valid; >> + events[id].status = down; >> + events[id].x = x; >> + events[id].y = y; >> + >> + 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); >> + } >> + } else { >> + dev_dbg(&client->dev, "release id:%d\n", id); >> + events[id].valid = 0; >> + events[id].status = 0; >> + 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); >> + } >> + >> + input_sync(input_dev); > > need re-sync here ? it's not re-sync, input_mt_sync() is different from input_sync(), the mt_sync is used to notify a multi touch event is finish. but a input_sync() means a input event is finished. eg, one input event may have many multi touch event. [MT 1, x, y] [mt sync] [MT 2, x, y] [mt sync] [input sync] [MT 1, x, y] [mt sync] [MT 2, x, y] [mt sync] [input sync] ... > >> + data->client = client; >> + data->input_dev = input_dev; >> + /* controller may be in sleep, wake it up. */ >> + egalax_wake_up_device(client); >> + ret = egalax_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 = "EETI eGalax Touch Screen"; >> + input_dev->phys = "I2C", >> + input_dev->id.bustype = BUS_I2C; >> + 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); >> + input_set_abs_params(input_dev, ABS_X, 0, 32767, 0, 0); >> + input_set_abs_params(input_dev, ABS_Y, 0, 32767, 0, 0); > > make 32767 to macro here ? This is a constant to the controller, resolution of x, and y. maybe you want this become a macro, but it's just style things. you can find lots of example by grep" input_set_abs_params" under driver/input/touchscreen. > > -- > Thanks > Best Regards > Wanlong Gao Thanks. BR, Jiejing -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 07/29/2011 01:28 PM, Jiejing.Zhang wrote: > Hi Gao, > > 2011/7/26 Wanlong Gao<gaowanlong@cn.fujitsu.com> >> >> On 07/26/2011 05:25 PM, Zhang Jiejing wrote: >>> >>> this patch adds EETI eGalax serial multi touch controller driver. >>> >>> EETI eGalax serial touch screen controller is a I2C based multiple >>> capacitive touch screen controller, it can supports 5 touch events maximum. >>> >>> Signed-off-by: Zhang Jiejing<jiejing.zhang@freescale.com> >>> --- >>> drivers/input/touchscreen/Kconfig | 10 + >>> drivers/input/touchscreen/Makefile | 1 + >>> drivers/input/touchscreen/egalax_ts.c | 314 +++++++++++++++++++++++++++++++++ >>> 3 files changed, 325 insertions(+), 0 deletions(-) >>> create mode 100644 drivers/input/touchscreen/egalax_ts.c >>> >> >>> + >>> + if (down) { >>> + /* since egalax only report one of multi touch event, >>> + * so we need record pervious event with different id >>> + * and report them.*/ >>> + events[id].valid = valid; >>> + events[id].status = down; >>> + events[id].x = x; >>> + events[id].y = y; >>> + >>> + 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); >>> + } >>> + } else { >>> + dev_dbg(&client->dev, "release id:%d\n", id); >>> + events[id].valid = 0; >>> + events[id].status = 0; >>> + 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); >>> + } >>> + >>> + input_sync(input_dev); >> >> need re-sync here ? > > it's not re-sync, input_mt_sync() is different from input_sync(), the > mt_sync is used to notify a multi touch event is finish. but a > input_sync() means a input event is finished. > eg, > one input event may have many multi touch event. > [MT 1, x, y] > [mt sync] > [MT 2, x, y] > [mt sync] > [input sync] > [MT 1, x, y] > [mt sync] > [MT 2, x, y] > [mt sync] > [input sync] > ... case SYN_MT_REPORT: dev->sync = false; Yeah, I see, thanks a lot. > BR, > Jiejing >
Hi Zhang, On Tue, Jul 26, 2011 at 05:25:54PM +0800, Zhang Jiejing wrote: > + > + 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; In what cases does the device signal REPORT_MODE_SINGLE? When only one finger touches the surface? Because we should still be using MT protocol even if at the moment only one finger touches the surface. And it is nice to provide non-MT compatibility data for legacy applications regardless of the number of contacts currently active (see drivers/input/input-mt.c for helpers). > + } > + > + /* 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 (down) { > + /* since egalax only report one of multi touch event, > + * so we need record pervious event with different id > + * and report them.*/ > + events[id].valid = valid; > + events[id].status = down; > + events[id].x = x; > + events[id].y = y; > + > + 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); This does not provide any information, please drop. > + 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); It would be much better to use MT-B protocol since the device seems to provide proper tracking IDs for the contacts. > + > + __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); > + input_set_abs_params(input_dev, ABS_X, 0, 32767, 0, 0); > + input_set_abs_params(input_dev, ABS_Y, 0, 32767, 0, 0); You do not set any ABS_MT_* events here so your MT events will be suppressed by input core. > + > +static __devexit int egalax_ts_remove(struct i2c_client *client) > +{ > + struct egalax_ts *data = i2c_get_clientdata(client); > + > + free_irq(client->irq, data); > + input_unregister_device(data->input_dev); > + input_free_device(data->input_dev); No calls to input_free_device() after calling input_unregister_device(). Thanks.
Hi Dmitry, Thanks for your review. 2011/8/1 Dmitry Torokhov <dmitry.torokhov@gmail.com>: > Hi Zhang, > > On Tue, Jul 26, 2011 at 05:25:54PM +0800, Zhang Jiejing wrote: >> + >> + 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; > > In what cases does the device signal REPORT_MODE_SINGLE? When only one > finger touches the surface? Because we should still be using MT protocol > even if at the moment only one finger touches the surface. And it is > nice to provide non-MT compatibility data for legacy applications > regardless of the number of contacts currently active (see > drivers/input/input-mt.c for helpers). This report single mode was wroted in Chip's I2C programming manual. but in fact, at least in my touch panel, the event type(buf[0]) was REPORT_MODE_MTTOUCH regardless one finger or two finger pressed on panel. I add this code is in case someone's panel is configured with REPORT_MODE_SINGLE. It was no tested, maybe I should remove this part of code ? what's your opinion ? > >> + } >> + >> + /* 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 (down) { >> + /* since egalax only report one of multi touch event, >> + * so we need record pervious event with different id >> + * and report them.*/ >> + events[id].valid = valid; >> + events[id].status = down; >> + events[id].x = x; >> + events[id].y = y; >> + >> + 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); > > This does not provide any information, please drop. will do. > >> + 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); > > It would be much better to use MT-B protocol since the device seems to > provide proper tracking IDs for the contacts. I will adjust it to MT-B protocol in next version. > >> + >> + __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); >> + input_set_abs_params(input_dev, ABS_X, 0, 32767, 0, 0); >> + input_set_abs_params(input_dev, ABS_Y, 0, 32767, 0, 0); > > You do not set any ABS_MT_* events here so your MT events will be > suppressed by input core. ok. > >> + >> +static __devexit int egalax_ts_remove(struct i2c_client *client) >> +{ >> + struct egalax_ts *data = i2c_get_clientdata(client); >> + >> + free_irq(client->irq, data); >> + input_unregister_device(data->input_dev); >> + input_free_device(data->input_dev); > > No calls to input_free_device() after calling input_unregister_device(). > ok > Thanks. > > -- > Dmitry > Thanks, Jiejing -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 61834ae..cd6d01e 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -165,6 +165,16 @@ config TOUCHSCREEN_EETI To compile this driver as a module, choose M here: the module will be called eeti_ts. +config TOUCHSCREEN_EGALAX + tristate "EETI eGalax multi-touch panel support" + depends on I2C + help + Say Y here to enable support for I2C connected EETI + eGalax multi-touch panels. + + To compile this driver as a module, choose M here: the + module will be called egalax_ts. + config TOUCHSCREEN_FUJITSU tristate "Fujitsu serial touchscreen" select SERIO diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 718bcc8..ff1173f 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o +obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c new file mode 100644 index 0000000..1abdb81 --- /dev/null +++ b/drivers/input/touchscreen/egalax_ts.c @@ -0,0 +1,314 @@ +/* + * Driver for EETI eGalax Multiple Touch Controller + * + * Copyright (C) 2011 Freescale Semiconductor, Inc. + * + * based on max11801_ts.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* EETI eGalax serial touch screen controller is a I2C based multiple + * touch screen controller, it can supports 5 pointer multiple touch. */ + +/* TODO: + - auto idle mode support +*/ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/input.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/bitops.h> + +#define REPORT_MODE_SINGLE 0x1 +#define REPORT_MODE_VENDOR 0x3 +#define REPORT_MODE_MTTOUCH 0x4 + +#define MAX_SUPPORT_POINTS 5 + +#define EVENT_VALID_OFFSET 7 +#define EVENT_VAILD_MASK (0x1 << EVENT_VALID_OFFSET) +#define EVENT_ID_OFFSET 2 +#define EVENT_ID_MASK (0xf << EVENT_ID_OFFSET) +#define EVENT_IN_RANGE (0x1 << 1) +#define EVENT_DOWN_UP (0X1 << 0) + +#define MAX_I2C_DATA_LEN 10 + +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) +{ + struct egalax_ts *data = dev_id; + struct input_dev *input_dev = data->input_dev; + struct i2c_client *client = data->client; + struct egalax_pointer *events = data->events; + u8 buf[MAX_I2C_DATA_LEN]; + int i, id, ret, x, y; + bool down, valid; + u8 state; + +retry: + ret = i2c_master_recv(client, buf, MAX_I2C_DATA_LEN); + if (ret == -EAGAIN) + goto retry; + + if (ret < 0) + return IRQ_HANDLED; + + 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]; + + 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; + + if (!valid || id > MAX_SUPPORT_POINTS) { + dev_dbg(&client->dev, "point invalid\n"); + return IRQ_HANDLED; + } + + if (down) { + /* since egalax only report one of multi touch event, + * so we need record pervious event with different id + * and report them.*/ + events[id].valid = valid; + events[id].status = down; + events[id].x = x; + events[id].y = y; + + 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); + } + } else { + dev_dbg(&client->dev, "release id:%d\n", id); + events[id].valid = 0; + events[id].status = 0; + 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); + } + + input_sync(input_dev); + return IRQ_HANDLED; +} + +/* wake up controller by an falling edge of interrupt gpio. */ +static int egalax_wake_up_device(struct i2c_client *client) +{ + int gpio = irq_to_gpio(client->irq); + int ret; + + ret = gpio_request(gpio, "egalax_irq"); + if (ret < 0) { + dev_err(&client->dev, "request gpio failed:%d\n", ret); + return ret; + } + /* wake up controller via an falling edge on IRQ. */ + gpio_direction_output(gpio, 0); + gpio_set_value(gpio, 1); + /* controller should be waken up, return irq. */ + gpio_direction_input(gpio); + gpio_free(gpio); + return 0; +} + +static int egalax_firmware_version(struct i2c_client *client) +{ + static const u8 cmd[MAX_I2C_DATA_LEN] = { 0x03, 0x03, 0xa, 0x01, 0x41 }; + int ret; + ret = i2c_master_send(client, cmd, MAX_I2C_DATA_LEN); + if (ret < 0) + return ret; + return 0; +} + +static int __devinit egalax_ts_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct egalax_ts *data; + struct input_dev *input_dev; + int ret; + + data = kzalloc(sizeof(struct egalax_ts), GFP_KERNEL); + if (!data) { + dev_err(&client->dev, "Failed to allocate memory\n"); + return -ENOMEM; + } + + input_dev = input_allocate_device(); + if (!input_dev) { + dev_err(&client->dev, "Failed to allocate memory\n"); + ret = -ENOMEM; + goto err_free_data; + } + + data->client = client; + data->input_dev = input_dev; + /* controller may be in sleep, wake it up. */ + egalax_wake_up_device(client); + ret = egalax_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 = "EETI eGalax Touch Screen"; + input_dev->phys = "I2C", + input_dev->id.bustype = BUS_I2C; + 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); + input_set_abs_params(input_dev, ABS_X, 0, 32767, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 32767, 0, 0); + + input_set_drvdata(input_dev, data); + + ret = request_threaded_irq(client->irq, NULL, egalax_ts_interrupt, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "egalax_ts", data); + if (ret < 0) { + dev_err(&client->dev, "Failed to register interrupt\n"); + goto err_free_dev; + } + + ret = input_register_device(data->input_dev); + if (ret < 0) + goto err_free_irq; + i2c_set_clientdata(client, data); + return 0; + +err_free_irq: + free_irq(client->irq, data); +err_free_dev: + input_free_device(input_dev); +err_free_data: + kfree(data); + + return ret; +} + +static __devexit int egalax_ts_remove(struct i2c_client *client) +{ + struct egalax_ts *data = i2c_get_clientdata(client); + + free_irq(client->irq, data); + input_unregister_device(data->input_dev); + input_free_device(data->input_dev); + kfree(data); + + return 0; +} + +static const struct i2c_device_id egalax_ts_id[] = { + {"egalax_ts", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, egalax_ts_id); + +#ifdef CONFIG_PM_SLEEP +static int egalax_ts_suspend(struct device *dev) +{ + int ret; + u8 suspend_cmd[MAX_I2C_DATA_LEN] = {0x3, 0x6, 0xa, 0x3, 0x36, + 0x3f, 0x2, 0, 0, 0}; + struct i2c_client *client = to_i2c_client(dev); + ret = i2c_master_send(client, suspend_cmd, + MAX_I2C_DATA_LEN); + return ret > 0 ? 0 : ret; +} + +static int egalax_ts_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + return egalax_wake_up_device(client); +} +#endif + +static SIMPLE_DEV_PM_OPS(egalax_ts_pm_ops, egalax_ts_suspend, egalax_ts_resume); +static struct i2c_driver egalax_ts_driver = { + .driver = { + .name = "egalax_ts", + .pm = &egalax_ts_pm_ops, + }, + .id_table = egalax_ts_id, + .probe = egalax_ts_probe, + .remove = __devexit_p(egalax_ts_remove), +}; + +static int __init egalax_ts_init(void) +{ + return i2c_add_driver(&egalax_ts_driver); +} + +static void __exit egalax_ts_exit(void) +{ + i2c_del_driver(&egalax_ts_driver); +} + +module_init(egalax_ts_init); +module_exit(egalax_ts_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("Touchscreen driver for EETI eGalax touch controller"); +MODULE_LICENSE("GPL");
this patch adds EETI eGalax serial multi touch controller driver. EETI eGalax serial touch screen controller is a I2C based multiple capacitive touch screen controller, it can supports 5 touch events maximum. Signed-off-by: Zhang Jiejing <jiejing.zhang@freescale.com> --- drivers/input/touchscreen/Kconfig | 10 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/egalax_ts.c | 314 +++++++++++++++++++++++++++++++++ 3 files changed, 325 insertions(+), 0 deletions(-) create mode 100644 drivers/input/touchscreen/egalax_ts.c