linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] input: add EETI eGalax I2C capacitive multi touch driver.
@ 2011-07-26  9:25 Zhang Jiejing
  2011-07-26  9:47 ` Wanlong Gao
  2011-08-01  6:34 ` Dmitry Torokhov
  0 siblings, 2 replies; 22+ messages in thread
From: Zhang Jiejing @ 2011-07-26  9:25 UTC (permalink / raw)
  To: Dmitry Torokhov, linux-input, Henrik Rydberg; +Cc: kzjeef

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

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");
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH] input: add EETI eGalax I2C capacitive multi touch driver.
  2011-07-26  9:25 [PATCH] input: add EETI eGalax I2C capacitive multi touch driver Zhang Jiejing
@ 2011-07-26  9:47 ` Wanlong Gao
  2011-07-29  5:28   ` Jiejing.Zhang 
  2011-08-01  6:34 ` Dmitry Torokhov
  1 sibling, 1 reply; 22+ messages in thread
From: Wanlong Gao @ 2011-07-26  9:47 UTC (permalink / raw)
  To: Zhang Jiejing; +Cc: Dmitry Torokhov, linux-input, Henrik Rydberg, kzjeef

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 ?

-- 
Thanks
Best Regards
Wanlong Gao

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH] input: add EETI eGalax I2C capacitive multi touch driver.
  2011-07-26  9:47 ` Wanlong Gao
@ 2011-07-29  5:28   ` Jiejing.Zhang 
  2011-07-29  6:00     ` Wanlong Gao
  0 siblings, 1 reply; 22+ messages in thread
From: Jiejing.Zhang  @ 2011-07-29  5:28 UTC (permalink / raw)
  To: gaowanlong; +Cc: Zhang Jiejing, Dmitry Torokhov, linux-input, Henrik Rydberg

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

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH] input: add EETI eGalax I2C capacitive multi touch driver.
  2011-07-29  5:28   ` Jiejing.Zhang 
@ 2011-07-29  6:00     ` Wanlong Gao
  0 siblings, 0 replies; 22+ messages in thread
From: Wanlong Gao @ 2011-07-29  6:00 UTC (permalink / raw)
  To: Jiejing.Zhang; +Cc: Zhang Jiejing, Dmitry Torokhov, linux-input, Henrik Rydberg

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
>
-- 
Thanks
Best Regards
Wanlong Gao

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH] input: add EETI eGalax I2C capacitive multi touch driver.
  2011-07-26  9:25 [PATCH] input: add EETI eGalax I2C capacitive multi touch driver Zhang Jiejing
  2011-07-26  9:47 ` Wanlong Gao
@ 2011-08-01  6:34 ` Dmitry Torokhov
  2011-08-02  8:49   ` Jiejing.Zhang 
  2011-08-03 11:29   ` [PATCH v2] " Zhang Jiejing
  1 sibling, 2 replies; 22+ messages in thread
From: Dmitry Torokhov @ 2011-08-01  6:34 UTC (permalink / raw)
  To: Zhang Jiejing; +Cc: linux-input, Henrik Rydberg, kzjeef

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.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH] input: add EETI eGalax I2C capacitive multi touch driver.
  2011-08-01  6:34 ` Dmitry Torokhov
@ 2011-08-02  8:49   ` Jiejing.Zhang 
  2011-08-03 11:29   ` [PATCH v2] " Zhang Jiejing
  1 sibling, 0 replies; 22+ messages in thread
From: Jiejing.Zhang  @ 2011-08-02  8:49 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: Zhang Jiejing, linux-input, Henrik Rydberg

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

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v2] input: add EETI eGalax I2C capacitive multi touch driver.
  2011-08-01  6:34 ` Dmitry Torokhov
  2011-08-02  8:49   ` Jiejing.Zhang 
@ 2011-08-03 11:29   ` Zhang Jiejing
  2011-08-03 20:48     ` Chase Douglas
                       ` (2 more replies)
  1 sibling, 3 replies; 22+ messages in thread
From: Zhang Jiejing @ 2011-08-03 11:29 UTC (permalink / raw)
  To: Dmitry Torokhov, Henrik Rydberg, linux-input, dima; +Cc: kzjeef

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

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");
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH v2] input: add EETI eGalax I2C capacitive multi touch driver.
  2011-08-03 11:29   ` [PATCH v2] " Zhang Jiejing
@ 2011-08-03 20:48     ` Chase Douglas
  2011-08-04  0:19     ` Wanlong Gao
  2011-08-11 20:34     ` Henrik Rydberg
  2 siblings, 0 replies; 22+ messages in thread
From: Chase Douglas @ 2011-08-03 20:48 UTC (permalink / raw)
  To: Zhang Jiejing; +Cc: Dmitry Torokhov, Henrik Rydberg, linux-input, dima, kzjeef

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

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2] input: add EETI eGalax I2C capacitive multi touch driver.
  2011-08-03 11:29   ` [PATCH v2] " Zhang Jiejing
  2011-08-03 20:48     ` Chase Douglas
@ 2011-08-04  0:19     ` Wanlong Gao
  2011-08-11 20:34     ` Henrik Rydberg
  2 siblings, 0 replies; 22+ messages in thread
From: Wanlong Gao @ 2011-08-04  0:19 UTC (permalink / raw)
  To: Zhang Jiejing; +Cc: Dmitry Torokhov, Henrik Rydberg, linux-input, dima, kzjeef

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");


-- 
Thanks
Best Regards
Wanlong Gao

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2] input: add EETI eGalax I2C capacitive multi touch driver.
  2011-08-03 11:29   ` [PATCH v2] " Zhang Jiejing
  2011-08-03 20:48     ` Chase Douglas
  2011-08-04  0:19     ` Wanlong Gao
@ 2011-08-11 20:34     ` Henrik Rydberg
  2011-08-12 13:24       ` Jiejing.Zhang 
  2 siblings, 1 reply; 22+ messages in thread
From: Henrik Rydberg @ 2011-08-11 20:34 UTC (permalink / raw)
  To: Zhang Jiejing; +Cc: Dmitry Torokhov, linux-input, dima, kzjeef

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

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2] input: add EETI eGalax I2C capacitive multi touch driver.
  2011-08-11 20:34     ` Henrik Rydberg
@ 2011-08-12 13:24       ` Jiejing.Zhang 
  2011-08-12 20:30         ` Henrik Rydberg
  0 siblings, 1 reply; 22+ messages in thread
From: Jiejing.Zhang  @ 2011-08-12 13:24 UTC (permalink / raw)
  To: Henrik Rydberg; +Cc: Zhang Jiejing, Dmitry Torokhov, linux-input, dima

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

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2] input: add EETI eGalax I2C capacitive multi touch driver.
  2011-08-12 13:24       ` Jiejing.Zhang 
@ 2011-08-12 20:30         ` Henrik Rydberg
  2011-09-08 11:39           ` Jiejing.Zhang 
  2011-09-08 11:40           ` [PATCH] " Zhang Jiejing
  0 siblings, 2 replies; 22+ messages in thread
From: Henrik Rydberg @ 2011-08-12 20:30 UTC (permalink / raw)
  To: Jiejing.Zhang ; +Cc: Zhang Jiejing, Dmitry Torokhov, linux-input, dima

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

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2] input: add EETI eGalax I2C capacitive multi touch driver.
  2011-08-12 20:30         ` Henrik Rydberg
@ 2011-09-08 11:39           ` Jiejing.Zhang 
  2011-09-08 11:40           ` [PATCH] " Zhang Jiejing
  1 sibling, 0 replies; 22+ messages in thread
From: Jiejing.Zhang  @ 2011-09-08 11:39 UTC (permalink / raw)
  To: Henrik Rydberg; +Cc: Zhang Jiejing, Dmitry Torokhov, linux-input, dima

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

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH] input: add EETI eGalax I2C capacitive multi touch driver.
  2011-08-12 20:30         ` Henrik Rydberg
  2011-09-08 11:39           ` Jiejing.Zhang 
@ 2011-09-08 11:40           ` Zhang Jiejing
  2011-09-13  9:15             ` Henrik Rydberg
  1 sibling, 1 reply; 22+ messages in thread
From: Zhang Jiejing @ 2011-09-08 11:40 UTC (permalink / raw)
  To: rydberg, kzjeef, dmitry.torokhov, linux-input

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>

---
V1 changes:
* use mt protocol B for report pointer.
* get the pressure value from pointer.
* use macro to define X,Y max value.

V2 changes:
* change MODE_SINGLE to a meanful name MODE_MOUSE
* add some comment on each mode to avoid misunderstand
---
 drivers/input/touchscreen/Kconfig     |   10 +
 drivers/input/touchscreen/Makefile    |    1 +
 drivers/input/touchscreen/egalax_ts.c |  299 +++++++++++++++++++++++++++++++++
 3 files changed, 310 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 cabd9e5..92f02b0 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -177,6 +177,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 282d6f7..a787ebc 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -23,6 +23,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..9f0a527
--- /dev/null
+++ b/drivers/input/touchscreen/egalax_ts.c
@@ -0,0 +1,299 @@
+/*
+ * 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>
+
+/* Mouse Mode: some panel may configure the controller to mouse mode,
+ * which can only one point at a given time. */
+#define REPORT_MODE_MOUSE		0x1
+/* Vendor Mode: this mode is used to transfer some vendor specify
+ * messages, it was ignore in this driver. */
+#define REPORT_MODE_VENDOR		0x3
+/* Multiple Touch Mode */
+#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_MOUSE
+	    && 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_MOUSE) {
+		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,"
+			"cannot wake up controller:%d\n", ret);
+		return ret;
+	}
+	/* wake up controller via an falling edge on IRQ gpio. */
+	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");
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH] input: add EETI eGalax I2C capacitive multi touch driver.
  2011-09-08 11:40           ` [PATCH] " Zhang Jiejing
@ 2011-09-13  9:15             ` Henrik Rydberg
  2011-09-14  4:50               ` Jiejing.Zhang 
  0 siblings, 1 reply; 22+ messages in thread
From: Henrik Rydberg @ 2011-09-13  9:15 UTC (permalink / raw)
  To: Zhang Jiejing; +Cc: kzjeef, dmitry.torokhov, linux-input

Hi Zhang,

thanks for the changes, please some some comments inline.

> this patch adds EETI eGalax serial multi touch controller driver.

s/this/This/
s/adds/adds the/

> EETI eGalax serial touch screen controller is a I2C based multiple
> capacitive touch screen controller, it can supports 5 touch events maximum.

s/supports/support/

> diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c
> new file mode 100644
> index 0000000..9f0a527
> --- /dev/null
> +++ b/drivers/input/touchscreen/egalax_ts.c
> @@ -0,0 +1,299 @@
> +/*
> + * 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>
> +
> +/* Mouse Mode: some panel may configure the controller to mouse mode,
> + * which can only one point at a given time. */

s/only/only report/

> +#define REPORT_MODE_MOUSE		0x1
> +/* Vendor Mode: this mode is used to transfer some vendor specify
> + * messages, it was ignore in this driver. */
> +#define REPORT_MODE_VENDOR		0x3

Since this is ignored, it could be dropped entirely, or possibly be
mentioned in the comment.

> +/* Multiple Touch Mode */
> +#define REPORT_MODE_MTTOUCH		0x4
> +
> +#define MAX_SUPPORT_POINTS		5
> +
> +#define EVENT_VALID_OFFSET	7
> +#define EVENT_VAILD_MASK	(0x1 << EVENT_VALID_OFFSET)

s/VAILD/VALID/

> +#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_MOUSE
> +	    && 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;
> +	}

Why not merge the vendor mode with the rest of the stuff you ignore? Something like

if (buf[0] != REPORT_MODE_MOUSE && buf[0] != REPORT_MODE_MTTOUCH)
	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_MOUSE) {
> +		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,"
> +			"cannot wake up controller:%d\n", ret);
> +		return ret;
> +	}
> +	/* wake up controller via an falling edge on IRQ gpio. */
> +	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);

How do you know when the device is in MOUSE mode here? The MT
parameters should only be set up for multitouch.

> +
> +	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;
> +}

Thanks,
Henrik

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH] input: add EETI eGalax I2C capacitive multi touch driver.
  2011-09-13  9:15             ` Henrik Rydberg
@ 2011-09-14  4:50               ` Jiejing.Zhang 
  2011-09-14  4:57                 ` Dmitry Torokhov
  2011-11-10 10:01                 ` [PATCH V3] " Zhang Jiejing
  0 siblings, 2 replies; 22+ messages in thread
From: Jiejing.Zhang  @ 2011-09-14  4:50 UTC (permalink / raw)
  To: Henrik Rydberg; +Cc: Zhang Jiejing, dmitry.torokhov, linux-input

Hi Henrik,

Thanks for your review.

2011/9/13 Henrik Rydberg <rydberg@euromail.se>:
> Hi Zhang,
>
> thanks for the changes, please some some comments inline.
>
>> this patch adds EETI eGalax serial multi touch controller driver.
>
> s/this/This/
> s/adds/adds the/
Will do.
>
>> EETI eGalax serial touch screen controller is a I2C based multiple
>> capacitive touch screen controller, it can supports 5 touch events maximum.
>
> s/supports/support/
>
Will do.
>> diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c
>> new file mode 100644
>> index 0000000..9f0a527
>> --- /dev/null
>> +++ b/drivers/input/touchscreen/egalax_ts.c
>> @@ -0,0 +1,299 @@
>> +/*
>> + * 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>
>> +
>> +/* Mouse Mode: some panel may configure the controller to mouse mode,
>> + * which can only one point at a given time. */
>
> s/only/only report/
Will do.
>
>> +#define REPORT_MODE_MOUSE            0x1
>> +/* Vendor Mode: this mode is used to transfer some vendor specify
>> + * messages, it was ignore in this driver. */
>> +#define REPORT_MODE_VENDOR           0x3
>
> Since this is ignored, it could be dropped entirely, or possibly be
> mentioned in the comment.
>
>> +/* Multiple Touch Mode */
>> +#define REPORT_MODE_MTTOUCH          0x4
>> +
>> +#define MAX_SUPPORT_POINTS           5
>> +
>> +#define EVENT_VALID_OFFSET   7
>> +#define EVENT_VAILD_MASK     (0x1 << EVENT_VALID_OFFSET)
>
> s/VAILD/VALID/
>
>> +#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_MOUSE
>> +         && 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;
>> +     }
>
> Why not merge the vendor mode with the rest of the stuff you ignore? Something like
>
> if (buf[0] != REPORT_MODE_MOUSE && buf[0] != REPORT_MODE_MTTOUCH)
>        return IRQ_HANDLED;
>
Yes, this is better.
>> +
>> +     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_MOUSE) {
>> +             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,"
>> +                     "cannot wake up controller:%d\n", ret);
>> +             return ret;
>> +     }
>> +     /* wake up controller via an falling edge on IRQ gpio. */
>> +     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);
>
> How do you know when the device is in MOUSE mode here? The MT
> parameters should only be set up for multitouch.
>

I double check the document, I can't know the Chip 's mode before the
the chip start report points.

So, I think change the abs_params in runtime is not a good idea.

What about this driver only deal with MT point, and ignore the
MOUSE_MODE related code?

>> +
>> +     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;
>> +}
>
> 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

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH] input: add EETI eGalax I2C capacitive multi touch driver.
  2011-09-14  4:50               ` Jiejing.Zhang 
@ 2011-09-14  4:57                 ` Dmitry Torokhov
  2011-11-10 10:01                 ` [PATCH V3] " Zhang Jiejing
  1 sibling, 0 replies; 22+ messages in thread
From: Dmitry Torokhov @ 2011-09-14  4:57 UTC (permalink / raw)
  To: Jiejing.Zhang ; +Cc: Henrik Rydberg, Zhang Jiejing, linux-input

On Wed, Sep 14, 2011 at 12:50:30PM +0800, Jiejing.Zhang  wrote:
> 
> I double check the document, I can't know the Chip 's mode before the
> the chip start report points.
> 
> So, I think change the abs_params in runtime is not a good idea.
> 
> What about this driver only deal with MT point, and ignore the
> MOUSE_MODE related code?
> 

I think this woudl be the best, as we can easily emulate ST with MT
data.

Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH V3] input: add EETI eGalax I2C capacitive multi touch driver.
  2011-09-14  4:50               ` Jiejing.Zhang 
  2011-09-14  4:57                 ` Dmitry Torokhov
@ 2011-11-10 10:01                 ` Zhang Jiejing
  2011-11-10 18:38                   ` Dmitry Torokhov
  1 sibling, 1 reply; 22+ messages in thread
From: Zhang Jiejing @ 2011-11-10 10:01 UTC (permalink / raw)
  To: dmitry.torokhov, rydberg; +Cc: linux-input

This patch adds the EETI eGalax serial multi touch controller driver.

EETI eGalax serial touch screen controller is a I2C based multiple
capacitive touch screen controller, it can support 5 touch events maximum.

Signed-off-by: Zhang Jiejing <jiejing.zhang@freescale.com>

---
V1 changes:
* use mt protocol B for report pointer.
* get the pressure value from pointer.
* use macro to define X,Y max value.

V2 changes:
* change MODE_SINGLE to a meanful name MODE_MOUSE
* add some comment on each mode to avoid misunderstand

V3 changes:
* some typo fix
* remove MODE_MOUSE, since it can't support both mode 100% well.
  also use this chip as MODE_MOUSE is very rare case.
---
 drivers/input/touchscreen/Kconfig     |   10 ++
 drivers/input/touchscreen/Makefile    |    1 +
 drivers/input/touchscreen/egalax_ts.c |  289 +++++++++++++++++++++++++++++++++
 3 files changed, 300 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 cabd9e5..92f02b0 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -177,6 +177,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 282d6f7..a787ebc 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -23,6 +23,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..10623e8
--- /dev/null
+++ b/drivers/input/touchscreen/egalax_ts.c
@@ -0,0 +1,289 @@
+/*
+ * 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>
+
+/* Mouse Mode: some panel may configure the controller to mouse mode,
+ * which can only report one point at a given time.
+ * This driver will ignore events in this mode.
+ */
+#define REPORT_MODE_MOUSE		0x1
+/* Vendor Mode: this mode is used to transfer some vendor specify
+ * messages, it was ignore in this driver.
+ * This driver will ignore events in this mode.
+ */
+#define REPORT_MODE_VENDOR		0x3
+/* Multiple Touch Mode */
+#define REPORT_MODE_MTTOUCH		0x4
+
+#define MAX_SUPPORT_POINTS		5
+
+#define EVENT_VALID_OFFSET	7
+#define EVENT_VALID_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_MTTOUCH) {
+		/* ignore mouse events and vendor events */
+		return IRQ_HANDLED;
+	}
+
+	state = buf[1];
+	x = (buf[3] << 8) | buf[2];
+	y = (buf[5] << 8) | buf[4];
+	z = (buf[7] << 8) | buf[6];
+
+	valid = state & EVENT_VALID_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,"
+			"cannot wake up controller:%d\n", ret);
+		return ret;
+	}
+	/* wake up controller via an falling edge on IRQ gpio. */
+	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(EV_SYN, input_dev->evbit);
+	__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");
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH V3] input: add EETI eGalax I2C capacitive multi touch driver.
  2011-11-10 10:01                 ` [PATCH V3] " Zhang Jiejing
@ 2011-11-10 18:38                   ` Dmitry Torokhov
  2011-11-12  6:12                     ` [PATCH V4] " Zhang Jiejing
  0 siblings, 1 reply; 22+ messages in thread
From: Dmitry Torokhov @ 2011-11-10 18:38 UTC (permalink / raw)
  To: Zhang Jiejing; +Cc: rydberg, linux-input

Hi Zhang,

On Thu, Nov 10, 2011 at 06:01:42PM +0800, Zhang Jiejing wrote:
> This patch adds the EETI eGalax serial multi touch controller driver.
> 
> EETI eGalax serial touch screen controller is a I2C based multiple
> capacitive touch screen controller, it can support 5 touch events maximum.
> 
> Signed-off-by: Zhang Jiejing <jiejing.zhang@freescale.com>
> 
> ---
> V1 changes:
> * use mt protocol B for report pointer.
> * get the pressure value from pointer.
> * use macro to define X,Y max value.
> 
> V2 changes:
> * change MODE_SINGLE to a meanful name MODE_MOUSE
> * add some comment on each mode to avoid misunderstand
> 
> V3 changes:
> * some typo fix
> * remove MODE_MOUSE, since it can't support both mode 100% well.
>   also use this chip as MODE_MOUSE is very rare case.

Looks much nicer now.

...

>  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

'g' is before 'l'...

> +
> +/* EETI eGalax serial touch screen controller is a I2C based multiple
> + * touch screen controller, it can supports 5 pointer multiple touch. */

s/it can supports 5 pointer/it supports 5 point/

> +
> +/* 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>
> +
> +/* Mouse Mode: some panel may configure the controller to mouse mode,
> + * which can only report one point at a given time.
> + * This driver will ignore events in this mode.
> + */
> +#define REPORT_MODE_MOUSE		0x1
> +/* Vendor Mode: this mode is used to transfer some vendor specify

s/specify/specific/

> + * messages, it was ignore in this driver.

s/, it was ignore in this driver//

> + * This driver will ignore events in this mode.
> + */
> +#define REPORT_MODE_VENDOR		0x3
> +/* Multiple Touch Mode */
> +#define REPORT_MODE_MTTOUCH		0x4
> +
> +#define MAX_SUPPORT_POINTS		5
> +
> +#define EVENT_VALID_OFFSET	7
> +#define EVENT_VALID_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;
> +

Can't allow spinnig indefinitely...

	do {
		error = i2c_master_recv(client, buf, MAX_I2C_DATA_LEN);
	} while (error == -EAGAIN && tries++ < EGALAX_MAX_TRIES);

> +
> +	input_dev->name = "EETI eGalax Touch Screen";
> +	input_dev->phys = "I2C",

I'd just drop this phys, it does not provide any additional information
compared to BUS_I2C below.

> +	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(EV_SYN, input_dev->evbit);

	Not need, always set by input core.

> +	__set_bit(ABS_X, input_dev->absbit);
> +	__set_bit(ABS_Y, input_dev->absbit);

	Calls below will take care of these 2.

> +
> +	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);

No calls to input_free_device after input_unregister_device.

Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH V4] input: add EETI eGalax I2C capacitive multi touch driver.
  2011-11-10 18:38                   ` Dmitry Torokhov
@ 2011-11-12  6:12                     ` Zhang Jiejing
  2011-11-12  8:02                       ` Dmitry Torokhov
  0 siblings, 1 reply; 22+ messages in thread
From: Zhang Jiejing @ 2011-11-12  6:12 UTC (permalink / raw)
  To: Dmitry Torokhov, Henrik Rydberg; +Cc: linux-input

This patch adds the EETI eGalax serial multi touch controller driver.

EETI eGalax serial touch screen controller is a I2C based multiple
capacitive touch screen controller, it can support 5 touch events maximum.

Signed-off-by: Zhang Jiejing <jiejing.zhang@freescale.com>

---
V1 changes:
* use mt protocol B for report pointer.
* get the pressure value from pointer.
* use macro to define X,Y max value.

V2 changes:
* change MODE_SINGLE to a meanful name MODE_MOUSE
* add some comment on each mode to avoid misunderstand

V3 changes:
* some typo fix
* remove MODE_MOUSE, since it can't support both mode 100% well.
 also use this chip as MODE_MOUSE is very rare case.

V4 changes:
* fix some typo
* don't let i2c_master_recv spin indefinitely
* clean up the bit set of probe function
* clean up egalax_ts_remove  input_unregister_device order
---
 drivers/input/touchscreen/Kconfig     |   10 ++
 drivers/input/touchscreen/Makefile    |    1 +
 drivers/input/touchscreen/egalax_ts.c |  286 +++++++++++++++++++++++++++++++++
 3 files changed, 297 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 cabd9e5..92f02b0 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -177,6 +177,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 282d6f7..a787ebc 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -23,6 +23,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..f694535
--- /dev/null
+++ b/drivers/input/touchscreen/egalax_ts.c
@@ -0,0 +1,286 @@
+/*
+ * 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 supports 5 point 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>
+
+/* Mouse Mode: some panel may configure the controller to mouse mode,
+ * which can only report one point at a given time.
+ * This driver will ignore events in this mode.
+ */
+#define REPORT_MODE_MOUSE		0x1
+/* Vendor Mode: this mode is used to transfer some vendor specific
+ * messages.
+ * This driver will ignore events in this mode.
+ */
+#define REPORT_MODE_VENDOR		0x3
+/* Multiple Touch Mode */
+#define REPORT_MODE_MTTOUCH		0x4
+
+#define MAX_SUPPORT_POINTS		5
+
+#define EVENT_VALID_OFFSET	7
+#define EVENT_VALID_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
+#define EGALAX_MAX_TRIES 100
+
+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;
+	int tries = 0;
+	bool down, valid;
+	u8 state;
+
+	do {
+		ret = i2c_master_recv(client, buf, MAX_I2C_DATA_LEN);
+	} while (ret == -EAGAIN && tries++ < EGALAX_MAX_TRIES);
+
+	if (ret < 0)
+		return IRQ_HANDLED;
+
+	if (buf[0] != REPORT_MODE_MTTOUCH) {
+		/* ignore mouse events and vendor events */
+		return IRQ_HANDLED;
+	}
+
+	state = buf[1];
+	x = (buf[3] << 8) | buf[2];
+	y = (buf[5] << 8) | buf[4];
+	z = (buf[7] << 8) | buf[6];
+
+	valid = state & EVENT_VALID_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,"
+			"cannot wake up controller:%d\n", ret);
+		return ret;
+	}
+	/* wake up controller via an falling edge on IRQ gpio. */
+	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->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);
+
+	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_free_device(data->input_dev);
+	input_unregister_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");
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH V4] input: add EETI eGalax I2C capacitive multi touch driver.
  2011-11-12  6:12                     ` [PATCH V4] " Zhang Jiejing
@ 2011-11-12  8:02                       ` Dmitry Torokhov
  2011-11-12  8:45                         ` Jiejing Zhang
  0 siblings, 1 reply; 22+ messages in thread
From: Dmitry Torokhov @ 2011-11-12  8:02 UTC (permalink / raw)
  To: Zhang Jiejing; +Cc: Henrik Rydberg, linux-input

On Sat, Nov 12, 2011 at 02:12:37PM +0800, Zhang Jiejing wrote:
> This patch adds the EETI eGalax serial multi touch controller driver.
> 
> EETI eGalax serial touch screen controller is a I2C based multiple
> capacitive touch screen controller, it can support 5 touch events maximum.
> 
> Signed-off-by: Zhang Jiejing <jiejing.zhang@freescale.com>
> 
> ---
> V1 changes:
> * use mt protocol B for report pointer.
> * get the pressure value from pointer.
> * use macro to define X,Y max value.
> 
> V2 changes:
> * change MODE_SINGLE to a meanful name MODE_MOUSE
> * add some comment on each mode to avoid misunderstand
> 
> V3 changes:
> * some typo fix
> * remove MODE_MOUSE, since it can't support both mode 100% well.
>  also use this chip as MODE_MOUSE is very rare case.
> 
> V4 changes:
> * fix some typo
> * don't let i2c_master_recv spin indefinitely
> * clean up the bit set of probe function
> * clean up egalax_ts_remove  input_unregister_device order

No, it is not the order I complained about, input_free_device() shoudl
not be called at all after calling input_unregister_device().

Fixed up locally and applied.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH V4] input: add EETI eGalax I2C capacitive multi touch driver.
  2011-11-12  8:02                       ` Dmitry Torokhov
@ 2011-11-12  8:45                         ` Jiejing Zhang
  0 siblings, 0 replies; 22+ messages in thread
From: Jiejing Zhang @ 2011-11-12  8:45 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: Zhang Jiejing, Henrik Rydberg, linux-input

Hi Dmitry,

On 2011-11-12,PM4:02, Dmitry Torokhov wrote:

> On Sat, Nov 12, 2011 at 02:12:37PM +0800, Zhang Jiejing wrote
>> 
>> V4 changes:
>> * fix some typo
>> * don't let i2c_master_recv spin indefinitely
>> * clean up the bit set of probe function
>> * clean up egalax_ts_remove  input_unregister_device order
> 
> No, it is not the order I complained about, input_free_device() shoudl
> not be called at all after calling input_unregister_device().
> 

I know the input_free_device call after input_unregister_device() maybe cause NULL pointer reference, sorry for I don't tested rmmod this module, I always buildin this module in my test env.

I will pay attention to it.

Thanks for your review.

> Fixed up locally and applied.
> 
Thanks.

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

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2011-11-12  8:45 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-07-26  9:25 [PATCH] input: add EETI eGalax I2C capacitive multi touch driver Zhang Jiejing
2011-07-26  9:47 ` Wanlong Gao
2011-07-29  5:28   ` Jiejing.Zhang 
2011-07-29  6:00     ` Wanlong Gao
2011-08-01  6:34 ` Dmitry Torokhov
2011-08-02  8:49   ` Jiejing.Zhang 
2011-08-03 11:29   ` [PATCH v2] " Zhang Jiejing
2011-08-03 20:48     ` Chase Douglas
2011-08-04  0:19     ` Wanlong Gao
2011-08-11 20:34     ` Henrik Rydberg
2011-08-12 13:24       ` Jiejing.Zhang 
2011-08-12 20:30         ` Henrik Rydberg
2011-09-08 11:39           ` Jiejing.Zhang 
2011-09-08 11:40           ` [PATCH] " Zhang Jiejing
2011-09-13  9:15             ` Henrik Rydberg
2011-09-14  4:50               ` Jiejing.Zhang 
2011-09-14  4:57                 ` Dmitry Torokhov
2011-11-10 10:01                 ` [PATCH V3] " Zhang Jiejing
2011-11-10 18:38                   ` Dmitry Torokhov
2011-11-12  6:12                     ` [PATCH V4] " Zhang Jiejing
2011-11-12  8:02                       ` Dmitry Torokhov
2011-11-12  8:45                         ` Jiejing Zhang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).