diff mbox

[v2] input: add EETI eGalax I2C capacitive multi touch driver.

Message ID 1312370963-24965-1-git-send-email-jiejing.zhang@freescale.com (mailing list archive)
State New, archived
Headers show

Commit Message

Zhang Jiejing Aug. 3, 2011, 11:29 a.m. UTC
Hi Dmitry,

This is the patch after change to mt Protocol-B.
but I have a issue with test tool, in the orignal patch, I use
android to do the test, but android still not support Protocol B.

I also have a arm based ubuntu, could you which tool can test protocol B?

Thanks,
Jiejing

Below is patch:

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>

---
change since 1st verion:
* use mt protocol B for report pointer.
* get the pressure value from pointer.
* use macro to define X,Y max value.
---
 drivers/input/touchscreen/Kconfig     |   10 +
 drivers/input/touchscreen/Makefile    |    1 +
 drivers/input/touchscreen/egalax_ts.c |  293 +++++++++++++++++++++++++++++++++
 3 files changed, 304 insertions(+), 0 deletions(-)
 create mode 100644 drivers/input/touchscreen/egalax_ts.c

Comments

Chase Douglas Aug. 3, 2011, 8:48 p.m. UTC | #1
On 08/03/2011 04:29 AM, Zhang Jiejing wrote:
> Hi Dmitry,
> 
> This is the patch after change to mt Protocol-B.
> but I have a issue with test tool, in the orignal patch, I use
> android to do the test, but android still not support Protocol B.
> 
> I also have a arm based ubuntu, could you which tool can test protocol B?

There are some tools as part of the Ubuntu uTouch stack that you could
use. If you want to see the raw touch data you can use
utouch-frame-test-mtdev from the utouch-frame-tools package. If you want
to see if gestures work you can use geistest from utouch-geis-tools.

-- Chase
--
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
Wanlong Gao Aug. 4, 2011, 12:19 a.m. UTC | #2
On 08/03/2011 07:29 PM, Zhang Jiejing wrote:
> Hi Dmitry,
>
> This is the patch after change to mt Protocol-B.
> but I have a issue with test tool, in the orignal patch, I use
> android to do the test, but android still not support Protocol B.
>
> I also have a arm based ubuntu, could you which tool can test protocol B?
>
> Thanks,
> Jiejing
>
> Below is patch:
>
> 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>
Reviewed-by: Wanlong Gao <gaowanlong@cn.fujitsu.com>
>
> ---
> change since 1st verion:
> * use mt protocol B for report pointer.
> * get the pressure value from pointer.
> * use macro to define X,Y max value.
> ---
>   drivers/input/touchscreen/Kconfig     |   10 +
>   drivers/input/touchscreen/Makefile    |    1 +
>   drivers/input/touchscreen/egalax_ts.c |  293 +++++++++++++++++++++++++++++++++
>   3 files changed, 304 insertions(+), 0 deletions(-)
>   create mode 100644 drivers/input/touchscreen/egalax_ts.c
>
> 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..153e64f
> --- /dev/null
> +++ b/drivers/input/touchscreen/egalax_ts.c
> @@ -0,0 +1,293 @@
> +/*
> + * 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>
> +#include<linux/input/mt.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
> +
> +#define EGALAX_MAX_X	32760
> +#define EGALAX_MAX_Y	32760
> +
> +struct egalax_ts {
> +	struct i2c_client		*client;
> +	struct input_dev		*input_dev;
> +};
> +
> +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;
> +	u8 buf[MAX_I2C_DATA_LEN];
> +	int id, ret, x, y, z;
> +	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, ignore...\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]; /* only valid in multitouch mode. */
> +
> +	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;
> +	}
> +
> +	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);
> +	}
> +
> +	input_mt_report_pointer_emulation(input_dev, true);
> +	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 };
In *ts_suspend(), you fill the cmd with others 0x0, but here not ?
> +	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, 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_X, 0, EGALAX_MAX_Y, 0, 0);
> +	input_mt_init_slots(input_dev, MAX_SUPPORT_POINTS);
> +
> +	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);
Maybe you've forgotten this? No input_free_device() after *unregister*
by Dmitry?
> +	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");
Henrik Rydberg Aug. 11, 2011, 8:34 p.m. UTC | #3
Hi Zhang,

> This is the patch after change to mt Protocol-B.
> but I have a issue with test tool, in the orignal patch, I use
> android to do the test, but android still not support Protocol B.

The device seems to send finger changes sequentually, resulting in one
packet (terminated with input sync) for each finger change. Is this
the intention/necessary? Some egalax firmware (hid version) seems to
work this way.

The usage of REPORT_MODE_* is unclear to me too.

Other than that, the patch looks nice (at first glance).

Thanks,
Henrik
--
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
JieJing.Zhang Aug. 12, 2011, 1:24 p.m. UTC | #4
Hi Henrik,

2011/8/12 Henrik Rydberg <rydberg@euromail.se>:
> Hi Zhang,
>
>> This is the patch after change to mt Protocol-B.
>> but I have a issue with test tool, in the orignal patch, I use
>> android to do the test, but android still not support Protocol B.
>
> The device seems to send finger changes sequentually, resulting in one
> packet (terminated with input sync) for each finger change. Is this
> the intention/necessary? Some egalax firmware (hid version) seems to
> work this way.

When I make v2 patch, I've a look the Protocol B's driver in upstream,
but there were two type of multi-point report fashion,
One type is report all the finger status in one input sync(), and
separate each mt point with mt_input_slot(), like wocom driver.

But there was some driver (like egalax hid version), send each mt
point with one input_sync(), but I'm worry about if main stream user
space frameworks(xorg mtouch etc,) support this behavior well.

What's your point of view about this ?

>
> The usage of REPORT_MODE_* is unclear to me too.

In the programming manual this mode 's name is "single touch mouse
mode", may be it will be a better name for this mode ?

>
> Other than that, the patch looks nice (at first glance).
>
> Thanks,
> Henrik
>

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
Henrik Rydberg Aug. 12, 2011, 8:30 p.m. UTC | #5
> > The device seems to send finger changes sequentually, resulting in one
> > packet (terminated with input sync) for each finger change. Is this
> > the intention/necessary? Some egalax firmware (hid version) seems to
> > work this way.
> 
> When I make v2 patch, I've a look the Protocol B's driver in upstream,
> but there were two type of multi-point report fashion,
> One type is report all the finger status in one input sync(), and
> separate each mt point with mt_input_slot(), like wocom driver.
> 
> But there was some driver (like egalax hid version), send each mt
> point with one input_sync(), but I'm worry about if main stream user
> space frameworks(xorg mtouch etc,) support this behavior well.

Sequential reporting works reasonably well, although there are
potential problems (applying methods for smooth motion, for
instance). Wakeups and cpu intensity also increases.

> What's your point of view about this ?

If possible, I think batched reporting is preferred, i.e., using the
same method as all hid drivers _but_ the egalax one.

> > The usage of REPORT_MODE_* is unclear to me too.
> 
> In the programming manual this mode 's name is "single touch mouse
> mode", may be it will be a better name for this mode ?

Ok, sounds like the equivalent of the hid generic mouse, which could
either be ignored or assigned its own input device node. Nothing out
of the ordinary, in other words, and the patch looks good in this
respect. Thanks for clarifying.

Henrik
--
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
JieJing.Zhang Sept. 8, 2011, 11:39 a.m. UTC | #6
Hi Henrik,

2011/8/13 Henrik Rydberg <rydberg@euromail.se>:
>> > The device seems to send finger changes sequentually, resulting in one
>> > packet (terminated with input sync) for each finger change. Is this
>> > the intention/necessary? Some egalax firmware (hid version) seems to
>> > work this way.
>>
>> When I make v2 patch, I've a look the Protocol B's driver in upstream,
>> but there were two type of multi-point report fashion,
>> One type is report all the finger status in one input sync(), and
>> separate each mt point with mt_input_slot(), like wocom driver.
>>
>> But there was some driver (like egalax hid version), send each mt
>> point with one input_sync(), but I'm worry about if main stream user
>> space frameworks(xorg mtouch etc,) support this behavior well.
>
> Sequential reporting works reasonably well, although there are
> potential problems (applying methods for smooth motion, for
> instance). Wakeups and cpu intensity also increases.
>
>> What's your point of view about this ?
>
> If possible, I think batched reporting is preferred, i.e., using the
> same method as all hid drivers _but_ the egalax one.
After go through the code, I found HID driver's batched report is hard
to implement in this driver.
Although, since I already use threaded irq to deal with the new event
information, and it will perform i2c read every time, i2c is a slow
bus, I think the CPU cause of this kind of device is relative lower
then some device via USB.
>
>> > The usage of REPORT_MODE_* is unclear to me too.
>>
>> In the programming manual this mode 's name is "single touch mouse
>> mode", may be it will be a better name for this mode ?
>
> Ok, sounds like the equivalent of the hid generic mouse, which could
> either be ignored or assigned its own input device node. Nothing out
> of the ordinary, in other words, and the patch looks good in this
> respect. Thanks for clarifying.
>
I've already change the MODE_SINGLE to MODE_MOUSE to avoid confusion
in next version.
> Henrik
>

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 mbox

Patch

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..153e64f
--- /dev/null
+++ b/drivers/input/touchscreen/egalax_ts.c
@@ -0,0 +1,293 @@ 
+/*
+ * 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>
+#include <linux/input/mt.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
+
+#define EGALAX_MAX_X	32760
+#define EGALAX_MAX_Y	32760
+
+struct egalax_ts {
+	struct i2c_client		*client;
+	struct input_dev		*input_dev;
+};
+
+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;
+	u8 buf[MAX_I2C_DATA_LEN];
+	int id, ret, x, y, z;
+	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, ignore...\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]; /* only valid in multitouch mode. */
+
+	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;
+	}
+
+	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);
+	}
+
+	input_mt_report_pointer_emulation(input_dev, true);
+	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, 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_X, 0, EGALAX_MAX_Y, 0, 0);
+	input_mt_init_slots(input_dev, MAX_SUPPORT_POINTS);
+
+	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");