Browse Source

edt-ft5x06 patches, dts changes

Reinhard Russinger 8 năm trước cách đây
mục cha
commit
793c99713e

+ 1 - 1
board/GfA/Display001/BUILD

@@ -1 +1 @@
-371
+374

+ 1 - 38
board/GfA/Display001/DTS_4.4/Display001_7.dts

@@ -97,20 +97,6 @@
 		};
 
 
-             /* 	i2c1_pins: pinmux_i2c1_pins { 
-                        pinctrl-single,pins = <
-                                0x158 (PIN_INPUT | MUX_MODE2) */   /* spi0_d1.i2c1_sda */
-                              /*  0x15c (PIN_INPUT | MUX_MODE2) */    /* spi0_cs0.i2c1_scl */
-/*                        >;
-                };
-*/
-              	i2c2_pins: pinmux_i2c2_pins { 
-                        pinctrl-single,pins = <
-                                0x150 (PIN_INPUT_PULLUP | MUX_MODE2)    /* spi0_sclk.i2c2_sda */
-                                0x154 (PIN_INPUT_PULLUP | MUX_MODE2)    /* spi0_d0.i2c2_scl */
-                        >;
-                };
-
                 i2c_gpio_pins: pinmux_i2c_gpio_pins {
                         pinctrl-single,pins = <
                                 0x150 (PIN_INPUT | MUX_MODE7)    /* spi0_sclk.i2c2_sda */
@@ -202,28 +188,6 @@
 	};
 };
 
-/*
-&i2c2 {
-    pinctrl-names = "default";
-    pinctrl-0 = <&i2c2_pins>;
-    status = "okay";
-    clock-frequency = <400000>;
-};
-
-
-&i2c2 {
-        polytouch: edt-ft5x06@38 {
-                compatible = "edt,edt-ft5406", "edt,edt-ft5x06";
-                reg = <0x38>;
-                pinctrl-names = "default";
-                pinctrl-0 = <&edt_ft5x06_pins>;
-                interrupt-parent = <&gpio2>;
-                interrupts = <1 0>;
-                reset-gpios = <&gpio3 21 1>;
-        };
-};
-*/
-
 / {
 i2c@3 {
         compatible = "i2c-gpio";
@@ -293,8 +257,7 @@ i2c@3 {
                 sync-ctrl         = <1>;   
                 raster-order      = <0>;   
                 fifo-th           = <0>;   
-                invert-pxl-clk    = <1>;   
-                };
+               };
 
         display-timings {
 			800x480 {

+ 0 - 37
board/GfA/Display001/DTS_4.4/Display001_7_bitbang.dts

@@ -97,20 +97,6 @@
 		};
 
 
-             /* 	i2c1_pins: pinmux_i2c1_pins { 
-                        pinctrl-single,pins = <
-                                0x158 (PIN_INPUT | MUX_MODE2) */   /* spi0_d1.i2c1_sda */
-                              /*  0x15c (PIN_INPUT | MUX_MODE2) */    /* spi0_cs0.i2c1_scl */
-/*                        >;
-                };
-*/
-              	i2c2_pins: pinmux_i2c2_pins { 
-                        pinctrl-single,pins = <
-                                0x150 (PIN_INPUT_PULLUP | MUX_MODE2)    /* spi0_sclk.i2c2_sda */
-                                0x154 (PIN_INPUT_PULLUP | MUX_MODE2)    /* spi0_d0.i2c2_scl */
-                        >;
-                };
-
                 i2c_gpio_pins: pinmux_i2c_gpio_pins {
                         pinctrl-single,pins = <
                                 0x150 (PIN_INPUT | MUX_MODE7)    /* spi0_sclk.i2c2_sda */
@@ -202,28 +188,6 @@
 	};
 };
 
-/*
-&i2c2 {
-    pinctrl-names = "default";
-    pinctrl-0 = <&i2c2_pins>;
-    status = "okay";
-    clock-frequency = <400000>;
-};
-
-
-&i2c2 {
-        polytouch: edt-ft5x06@38 {
-                compatible = "edt,edt-ft5406", "edt,edt-ft5x06";
-                reg = <0x38>;
-                pinctrl-names = "default";
-                pinctrl-0 = <&edt_ft5x06_pins>;
-                interrupt-parent = <&gpio2>;
-                interrupts = <1 0>;
-                reset-gpios = <&gpio3 21 1>;
-        };
-};
-*/
-
 / {
 i2c@3 {
         compatible = "i2c-gpio";
@@ -293,7 +257,6 @@ i2c@3 {
                 sync-ctrl         = <1>;   
                 raster-order      = <0>;   
                 fifo-th           = <0>;   
-                invert-pxl-clk    = <1>;   
                 };
 
         display-timings {

+ 0 - 38
board/GfA/Display001/DTS_4.4/Display001_7_gain1.dts

@@ -97,20 +97,6 @@
 		};
 
 
-             /* 	i2c1_pins: pinmux_i2c1_pins { 
-                        pinctrl-single,pins = <
-                                0x158 (PIN_INPUT | MUX_MODE2) */   /* spi0_d1.i2c1_sda */
-                              /*  0x15c (PIN_INPUT | MUX_MODE2) */    /* spi0_cs0.i2c1_scl */
-/*                        >;
-                };
-*/
-              	i2c2_pins: pinmux_i2c2_pins { 
-                        pinctrl-single,pins = <
-                                0x150 (PIN_INPUT_PULLUP | MUX_MODE2)    /* spi0_sclk.i2c2_sda */
-                                0x154 (PIN_INPUT_PULLUP | MUX_MODE2)    /* spi0_d0.i2c2_scl */
-                        >;
-                };
-
                 i2c_gpio_pins: pinmux_i2c_gpio_pins {
                         pinctrl-single,pins = <
                                 0x150 (PIN_INPUT | MUX_MODE7)    /* spi0_sclk.i2c2_sda */
@@ -202,29 +188,6 @@
 	};
 };
 
-/*
-&i2c2 {
-    pinctrl-names = "default";
-    pinctrl-0 = <&i2c2_pins>;
-    status = "okay";
-    clock-frequency = <400000>;
-};
-
-
-&i2c2 {
-        polytouch: edt-ft5x06@38 {
-                compatible = "edt,edt-ft5406", "edt,edt-ft5x06";
-                reg = <0x38>;
-                pinctrl-names = "default";
-                pinctrl-0 = <&edt_ft5x06_pins>;
-                interrupt-parent = <&gpio2>;
-                interrupts = <1 0>;
-                reset-gpios = <&gpio3 21 1>;
-		gain = <1>
-        };
-};
-*/
-
 / {
 i2c@3 {
         compatible = "i2c-gpio";
@@ -294,7 +257,6 @@ i2c@3 {
                 sync-ctrl         = <1>;   
                 raster-order      = <0>;   
                 fifo-th           = <0>;   
-                invert-pxl-clk    = <1>;   
                 };
 
         display-timings {

+ 0 - 1
board/GfA/Display001/DTS_4.4/Display001_7_i2c2.dts

@@ -256,7 +256,6 @@
                 sync-ctrl         = <1>;   
                 raster-order      = <0>;   
                 fifo-th           = <0>;   
-                invert-pxl-clk    = <1>;   
                 };
 
         display-timings {

+ 1 - 2
board/GfA/Display001/DTS_4.4/Display001_rru.dts

@@ -191,7 +191,6 @@
                 sync-ctrl         = <1>;   
                 raster-order      = <0>;   
                 fifo-th           = <0>;   
-                invert-pxl-clk    = <1>;   
                 };
 
         display-timings {
@@ -240,7 +239,7 @@
                 compatible = "edt,edt-ft5406", "edt,edt-ft5x06";
                 reg = <0x38>;
                 interrupt-parent = <&gpio1>;
-                interrupts = <17>;
+                interrupts = <17 0>;
 		swap_xy;
 		invert_x;
 		invert_y;

+ 828 - 0
board/GfA/Display001/linux_4.4.65_rt17/linux-005-edt-ft5x06.patch

@@ -0,0 +1,828 @@
+commit ab28538ebe289c686cf357a6274c3f4a71969ca3
+Author: Reinhard Russinger <reinhard@russinger.at>
+Date:   Thu May 4 06:59:24 2017 +0200
+
+    changes edt-ft5x06 touchcontroller
+
+diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
+index 703e295..e862958 100644
+--- a/drivers/input/touchscreen/edt-ft5x06.c
++++ b/drivers/input/touchscreen/edt-ft5x06.c
+@@ -27,7 +27,6 @@
+ 
+ #include <linux/module.h>
+ #include <linux/ratelimit.h>
+-#include <linux/irq.h>
+ #include <linux/interrupt.h>
+ #include <linux/input.h>
+ #include <linux/i2c.h>
+@@ -35,10 +34,12 @@
+ #include <linux/delay.h>
+ #include <linux/debugfs.h>
+ #include <linux/slab.h>
+-#include <linux/gpio/consumer.h>
++#include <linux/gpio.h>
++#include <linux/of_gpio.h>
+ #include <linux/input/mt.h>
+-#include <linux/input/touchscreen.h>
+-#include <linux/of_device.h>
++#include <linux/input/edt-ft5x06.h>
++
++#define MAX_SUPPORT_POINTS		5
+ 
+ #define WORK_REGISTER_THRESHOLD		0x00
+ #define WORK_REGISTER_REPORT_RATE	0x08
+@@ -53,6 +54,13 @@
+ #define M09_REGISTER_NUM_X		0x94
+ #define M09_REGISTER_NUM_Y		0x95
+ 
++#define M12_REGISTER_THRESHOLD		0x80
++#define M12_REGISTER_GAIN		0x92
++#define M12_REGISTER_OFFSET		0x93
++#define M12_REGISTER_NUM_X		0x94
++#define M12_REGISTER_NUM_Y		0x95
++#define M12_REGISTER_REPORT_RATE	0x88
++
+ #define NO_REGISTER			0xff
+ 
+ #define WORK_REGISTER_OPMODE		0x3c
+@@ -72,6 +80,7 @@
+ enum edt_ver {
+ 	M06,
+ 	M09,
++	M12,
+ };
+ 
+ struct edt_reg_addr {
+@@ -86,12 +95,12 @@ struct edt_reg_addr {
+ struct edt_ft5x06_ts_data {
+ 	struct i2c_client *client;
+ 	struct input_dev *input;
+-	struct touchscreen_properties prop;
+ 	u16 num_x;
+ 	u16 num_y;
+ 
+-	struct gpio_desc *reset_gpio;
+-	struct gpio_desc *wake_gpio;
++	int reset_pin;
++	int irq_pin;
++	int wake_pin;
+ 
+ #if defined(CONFIG_DEBUG_FS)
+ 	struct dentry *debug_dir;
+@@ -105,18 +114,20 @@ struct edt_ft5x06_ts_data {
+ 	int gain;
+ 	int offset;
+ 	int report_rate;
+-	int max_support_points;
+ 
++	u32 invert_x;
++	u32 invert_y;
++	u32 swap_xy;
++	
++	u32 max_x;
++	u32 max_y;
++	
+ 	char name[EDT_NAME_LEN];
+ 
+ 	struct edt_reg_addr reg_addr;
+ 	enum edt_ver version;
+ };
+ 
+-struct edt_i2c_chip_data {
+-	int  max_support_points;
+-};
+-
+ static int edt_ft5x06_ts_readwrite(struct i2c_client *client,
+ 				   u16 wr_len, u8 *wr_buf,
+ 				   u16 rd_len, u8 *rd_buf)
+@@ -173,9 +184,9 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
+ 	struct edt_ft5x06_ts_data *tsdata = dev_id;
+ 	struct device *dev = &tsdata->client->dev;
+ 	u8 cmd;
+-	u8 rdbuf[63];
++	u8 rdbuf[29];
+ 	int i, type, x, y, id;
+-	int offset, tplen, datalen, crclen;
++	int offset, tplen, datalen;
+ 	int error;
+ 
+ 	switch (tsdata->version) {
+@@ -183,14 +194,15 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
+ 		cmd = 0xf9; /* tell the controller to send touch data */
+ 		offset = 5; /* where the actual touch data starts */
+ 		tplen = 4;  /* data comes in so called frames */
+-		crclen = 1; /* length of the crc data */
++		datalen = 26; /* how much bytes to listen for */
+ 		break;
+-
++		
++	case M12:	
+ 	case M09:
+-		cmd = 0x0;
+-		offset = 3;
++		cmd = 0x02;
++		offset = 1;
+ 		tplen = 6;
+-		crclen = 0;
++		datalen = 29;
+ 		break;
+ 
+ 	default:
+@@ -198,7 +210,6 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
+ 	}
+ 
+ 	memset(rdbuf, 0, sizeof(rdbuf));
+-	datalen = tplen * tsdata->max_support_points + offset + crclen;
+ 
+ 	error = edt_ft5x06_ts_readwrite(tsdata->client,
+ 					sizeof(cmd), &cmd,
+@@ -209,8 +220,8 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
+ 		goto out;
+ 	}
+ 
+-	/* M09 does not send header or CRC */
+-	if (tsdata->version == M06) {
++	/* M09 M12 does not send header or CRC */
++	if (tsdata->version == M06)  {
+ 		if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa ||
+ 			rdbuf[2] != datalen) {
+ 			dev_err_ratelimited(dev,
+@@ -223,7 +234,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
+ 			goto out;
+ 	}
+ 
+-	for (i = 0; i < tsdata->max_support_points; i++) {
++	for (i = 0; i < MAX_SUPPORT_POINTS; i++) {
+ 		u8 *buf = &rdbuf[i * tplen + offset];
+ 		bool down;
+ 
+@@ -236,19 +247,32 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
+ 		if (tsdata->version == M06 && type == TOUCH_EVENT_DOWN)
+ 			continue;
+ 
+-		x = ((buf[0] << 8) | buf[1]) & 0x0fff;
+-		y = ((buf[2] << 8) | buf[3]) & 0x0fff;
++		if( tsdata->swap_xy) {
++		  y = ((buf[0] << 8) | buf[1]) & 0x0fff;
++		  x = ((buf[2] << 8) | buf[3]) & 0x0fff;
++		  } else {
++		  x = ((buf[0] << 8) | buf[1]) & 0x0fff;
++		  y = ((buf[2] << 8) | buf[3]) & 0x0fff;
++		  }
+ 		id = (buf[2] >> 4) & 0x0f;
+ 		down = type != TOUCH_EVENT_UP;
+ 
++		if(tsdata->invert_x) {
++  		  x = tsdata->max_x - x; 
++ 		  }
++ 		  
++		if(tsdata->invert_y) {
++  		  y = tsdata->max_y - y; 
++ 		  }
++ 		  
+ 		input_mt_slot(tsdata->input, id);
+ 		input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, down);
+ 
+ 		if (!down)
+ 			continue;
+ 
+-		touchscreen_report_pos(tsdata->input, &tsdata->prop, x, y,
+-				       true);
++		input_report_abs(tsdata->input, ABS_MT_POSITION_X, x);
++		input_report_abs(tsdata->input, ABS_MT_POSITION_Y, y);
+ 	}
+ 
+ 	input_mt_report_pointer_emulation(tsdata->input, true);
+@@ -267,15 +291,17 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata,
+ 	case M06:
+ 		wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
+ 		wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
++		wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
+ 		wrbuf[2] = value;
+ 		wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2];
+-		return edt_ft5x06_ts_readwrite(tsdata->client, 4,
+-					wrbuf, 0, NULL);
++		return edt_ft5x06_ts_readwrite(tsdata->client, 4, wrbuf, 0, NULL);
++		
++	case M12:
+ 	case M09:
+ 		wrbuf[0] = addr;
+ 		wrbuf[1] = value;
+ 
+-		return edt_ft5x06_ts_readwrite(tsdata->client, 2,
++		return edt_ft5x06_ts_readwrite(tsdata->client, 3,
+ 					wrbuf, 0, NULL);
+ 
+ 	default:
+@@ -309,6 +335,7 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata,
+ 		}
+ 		break;
+ 
++        case M12:
+ 	case M09:
+ 		wrbuf[0] = addr;
+ 		error = edt_ft5x06_ts_readwrite(tsdata->client, 1,
+@@ -331,9 +358,10 @@ struct edt_ft5x06_attribute {
+ 	u8 limit_high;
+ 	u8 addr_m06;
+ 	u8 addr_m09;
++	u8 addr_m12;
+ };
+ 
+-#define EDT_ATTR(_field, _mode, _addr_m06, _addr_m09,			\
++#define EDT_ATTR(_field, _mode, _addr_m06, _addr_m09, _addr_m12,			\
+ 		_limit_low, _limit_high)				\
+ 	struct edt_ft5x06_attribute edt_ft5x06_attr_##_field = {	\
+ 		.dattr = __ATTR(_field, _mode,				\
+@@ -342,6 +370,7 @@ struct edt_ft5x06_attribute {
+ 		.field_offset = offsetof(struct edt_ft5x06_ts_data, _field), \
+ 		.addr_m06 = _addr_m06,					\
+ 		.addr_m09 = _addr_m09,					\
++		.addr_m12 = _addr_m12,					\
+ 		.limit_low = _limit_low,				\
+ 		.limit_high = _limit_high,				\
+ 	}
+@@ -372,6 +401,10 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev,
+ 		addr = attr->addr_m06;
+ 		break;
+ 
++        case M12:
++		addr = attr->addr_m12;
++		break;
++
+ 	case M09:
+ 		addr = attr->addr_m09;
+ 		break;
+@@ -441,6 +474,10 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev,
+ 		addr = attr->addr_m06;
+ 		break;
+ 
++        case M12:
++		addr = attr->addr_m12;
++		break;
++
+ 	case M09:
+ 		addr = attr->addr_m09;
+ 		break;
+@@ -467,13 +504,13 @@ out:
+ }
+ 
+ static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN,
+-		M09_REGISTER_GAIN, 0, 31);
++		M09_REGISTER_GAIN, M12_REGISTER_GAIN, 0, 31);
+ static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET,
+-		M09_REGISTER_OFFSET, 0, 31);
++		M09_REGISTER_OFFSET, M12_REGISTER_OFFSET, 0, 31);
+ static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD,
+-		M09_REGISTER_THRESHOLD, 20, 80);
++		M09_REGISTER_THRESHOLD, M12_REGISTER_THRESHOLD, 1, 255);
+ static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE,
+-		NO_REGISTER, 3, 14);
++		NO_REGISTER, M12_REGISTER_REPORT_RATE, 3, 14);
+ 
+ static struct attribute *edt_ft5x06_attrs[] = {
+ 	&edt_ft5x06_attr_gain.dattr.attr,
+@@ -508,7 +545,7 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
+ 	}
+ 
+ 	/* mode register is 0x3c when in the work mode */
+-	if (tsdata->version == M09)
++	if ((tsdata->version == M09) || (tsdata->version == M12)) 
+ 		goto m09_out;
+ 
+ 	error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03);
+@@ -545,7 +582,7 @@ err_out:
+ 	return error;
+ 
+ m09_out:
+-	dev_err(&client->dev, "No factory mode support for M09\n");
++	dev_err(&client->dev, "No factory mode support for M09 and M12\n");
+ 	return -EINVAL;
+ 
+ }
+@@ -721,23 +758,46 @@ static void
+ edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata,
+ 			      const char *debugfs_name)
+ {
++	struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
++
+ 	tsdata->debug_dir = debugfs_create_dir(debugfs_name, NULL);
+ 	if (!tsdata->debug_dir)
+ 		return;
+ 
+ 	debugfs_create_u16("num_x", S_IRUSR, tsdata->debug_dir, &tsdata->num_x);
+ 	debugfs_create_u16("num_y", S_IRUSR, tsdata->debug_dir, &tsdata->num_y);
++	debugfs_create_u32("threshold", S_IRUSR, tsdata->debug_dir, &tsdata->threshold);
++	debugfs_create_u32("gain", S_IRUSR, tsdata->debug_dir, &tsdata->gain);
++	debugfs_create_u32("offset", S_IRUSR, tsdata->debug_dir, &tsdata->offset);
++
+ 
+ 	debugfs_create_file("mode", S_IRUSR | S_IWUSR,
+ 			    tsdata->debug_dir, tsdata, &debugfs_mode_fops);
+ 	debugfs_create_file("raw_data", S_IRUSR,
+ 			    tsdata->debug_dir, tsdata, &debugfs_raw_data_fops);
++			    
++	if (reg_addr->reg_report_rate != NO_REGISTER)
++           debugfs_create_u32("report_rate", S_IRUSR, tsdata->debug_dir, &tsdata->report_rate);
++           
++	debugfs_create_u32("invert_x", S_IRUSR | S_IWUSR,
++			    tsdata->debug_dir, &tsdata->invert_x);
++	debugfs_create_u32("invert_y", S_IRUSR | S_IWUSR,
++			    tsdata->debug_dir, &tsdata->invert_y);
++	debugfs_create_u32("swap_xy", S_IRUSR,
++			    tsdata->debug_dir, &tsdata->swap_xy);
++	debugfs_create_u32("max_x", S_IRUSR,
++			    tsdata->debug_dir, &tsdata->max_x);
++	debugfs_create_u32("max_y", S_IRUSR,
++			    tsdata->debug_dir, &tsdata->max_y);
++
++
+ }
+ 
+ static void
+ edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
+ {
+-	debugfs_remove_recursive(tsdata->debug_dir);
++	if (tsdata->debug_dir)
++		debugfs_remove_recursive(tsdata->debug_dir);
+ 	kfree(tsdata->raw_buffer);
+ }
+ 
+@@ -756,6 +816,45 @@ edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
+ 
+ #endif /* CONFIG_DEBUGFS */
+ 
++static int edt_ft5x06_ts_reset(struct i2c_client *client,
++			struct edt_ft5x06_ts_data *tsdata)
++{
++	int error;
++
++	if (gpio_is_valid(tsdata->wake_pin)) {
++		error = devm_gpio_request_one(&client->dev,
++					tsdata->wake_pin, GPIOF_OUT_INIT_LOW,
++					"edt-ft5x06 wake");
++		if (error) {
++			dev_err(&client->dev,
++				"Failed to request GPIO %d as wake pin, error %d\n",
++				tsdata->wake_pin, error);
++			return error;
++		}
++
++		msleep(5);
++		gpio_set_value(tsdata->wake_pin, 1);
++	}
++	if (gpio_is_valid(tsdata->reset_pin)) {
++		/* this pulls reset down, enabling the low active reset */
++		error = devm_gpio_request_one(&client->dev,
++					tsdata->reset_pin, GPIOF_OUT_INIT_LOW,
++					"edt-ft5x06 reset");
++		if (error) {
++			dev_err(&client->dev,
++				"Failed to request GPIO %d as reset pin, error %d\n",
++				tsdata->reset_pin, error);
++			return error;
++		}
++
++		msleep(5);
++		gpio_set_value(tsdata->reset_pin, 1);
++		msleep(300);
++	}
++
++	return 0;
++}
++
+ static int edt_ft5x06_ts_identify(struct i2c_client *client,
+ 					struct edt_ft5x06_ts_data *tsdata,
+ 					char *fw_version)
+@@ -771,14 +870,16 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
+ 	 */
+ 	memset(rdbuf, 0, sizeof(rdbuf));
+ 	error = edt_ft5x06_ts_readwrite(client, 1, "\xbb",
+-					EDT_NAME_LEN - 1, rdbuf);
++					EDT_NAME_LEN - 1,
++					rdbuf);
+ 	if (error)
+ 		return error;
+ 
++        printk(KERN_INFO "EDT-TC:: %s ::-----%s----\n", __func__, rdbuf);
+ 	/* if we find something consistent, stay with that assumption
+ 	 * at least M09 won't send 3 bytes here
+ 	 */
+-	if (!(strncasecmp(rdbuf + 1, "EP0", 3))) {
++	if ((strncasecmp(rdbuf + 1, "EP0", 3) == 0) && (strncasecmp(rdbuf + 6, "M12", 3) != 0)) {
+ 		tsdata->version = M06;
+ 
+ 		/* remove last '$' end marker */
+@@ -792,8 +893,24 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
+ 			*p++ = '\0';
+ 		strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN);
+ 		strlcpy(fw_version, p ? p : "", EDT_NAME_LEN);
++	} else if (!(strncasecmp(rdbuf + 6, "M12", 3))) {
++		tsdata->version = M12;
++
++		error = edt_ft5x06_ts_readwrite(client, 1, "\xA6",
++						2, rdbuf);
++		if (error)
++			return error;
++
++		strlcpy(fw_version, rdbuf, 2);
++
++		error = edt_ft5x06_ts_readwrite(client, 1, "\xA8",
++						1, rdbuf);
++		if (error)
++			return error;
++
++		snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M12",
++			rdbuf[0] >> 4, rdbuf[0] & 0x0F);
+ 	} else {
+-		/* since there are only two versions around (M06, M09) */
+ 		tsdata->version = M09;
+ 
+ 		error = edt_ft5x06_ts_readwrite(client, 1, "\xA6",
+@@ -815,30 +932,58 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
+ 	return 0;
+ }
+ 
+-static void edt_ft5x06_ts_get_defaults(struct device *dev,
+-				       struct edt_ft5x06_ts_data *tsdata)
++#define EDT_ATTR_CHECKSET(name, reg) \
++	if (pdata->name >= edt_ft5x06_attr_##name.limit_low &&		\
++	    pdata->name <= edt_ft5x06_attr_##name.limit_high)		\
++		edt_ft5x06_register_write(tsdata, reg, pdata->name)
++
++#define EDT_GET_PROP(name, reg) {				\
++	u32 val;						\
++	if (of_property_read_u32(np, #name, &val) == 0)		\
++		edt_ft5x06_register_write(tsdata, reg, val);	\
++}
++
++static void edt_ft5x06_ts_get_dt_defaults(struct device_node *np,
++					struct edt_ft5x06_ts_data *tsdata)
+ {
+ 	struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
+-	u32 val;
+-	int error;
+ 
+-	error = device_property_read_u32(dev, "threshold", &val);
+-	if (!error) {
+-		edt_ft5x06_register_write(tsdata, reg_addr->reg_threshold, val);
+-		tsdata->threshold = val;
+-	}
++	switch (tsdata->version) {
++	     case M12:
++	      EDT_GET_PROP(threshold_M12, reg_addr->reg_threshold);
++              EDT_GET_PROP(gain_M12, reg_addr->reg_gain);
++              EDT_GET_PROP(offset_M12, reg_addr->reg_offset);
++              break;
++
++	     case M09:
++	      EDT_GET_PROP(threshold_M09, reg_addr->reg_threshold);
++              EDT_GET_PROP(gain_M09, reg_addr->reg_gain);
++              EDT_GET_PROP(offset_M09, reg_addr->reg_offset);
++              break;
++
++	     case M06:
++	      EDT_GET_PROP(threshold_M06, reg_addr->reg_threshold);
++              EDT_GET_PROP(gain_M06, reg_addr->reg_gain);
++              EDT_GET_PROP(offset_M06, reg_addr->reg_offset);
++              break;
++             }
++}
+ 
+-	error = device_property_read_u32(dev, "gain", &val);
+-	if (!error) {
+-		edt_ft5x06_register_write(tsdata, reg_addr->reg_gain, val);
+-		tsdata->gain = val;
+-	}
++static void
++edt_ft5x06_ts_get_defaults(struct edt_ft5x06_ts_data *tsdata,
++			   const struct edt_ft5x06_platform_data *pdata)
++{
++	struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
+ 
+-	error = device_property_read_u32(dev, "offset", &val);
+-	if (!error) {
+-		edt_ft5x06_register_write(tsdata, reg_addr->reg_offset, val);
+-		tsdata->offset = val;
+-	}
++	if (!pdata->use_parameters)
++		return;
++
++	/* pick up defaults from the platform data */
++	EDT_ATTR_CHECKSET(threshold, reg_addr->reg_threshold);
++	EDT_ATTR_CHECKSET(gain, reg_addr->reg_gain);
++	EDT_ATTR_CHECKSET(offset, reg_addr->reg_offset);
++	if (reg_addr->reg_report_rate != NO_REGISTER)
++		EDT_ATTR_CHECKSET(report_rate, reg_addr->reg_report_rate);
+ }
+ 
+ static void
+@@ -855,6 +1000,12 @@ edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata)
+ 						reg_addr->reg_report_rate);
+ 	tsdata->num_x = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_x);
+ 	tsdata->num_y = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_y);
++
++	if(tsdata->max_x == 0)	
++		tsdata->max_x = tsdata->num_x * 64;
++	if(tsdata->max_y == 0)
++		tsdata->max_y = tsdata->num_y * 64;
++	
+ }
+ 
+ static void
+@@ -872,6 +1023,15 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
+ 		reg_addr->reg_num_y = WORK_REGISTER_NUM_Y;
+ 		break;
+ 
++        case M12:
++		reg_addr->reg_threshold = M12_REGISTER_THRESHOLD;
++		reg_addr->reg_report_rate = M12_REGISTER_REPORT_RATE;
++		reg_addr->reg_gain = M12_REGISTER_GAIN;
++		reg_addr->reg_offset = M12_REGISTER_OFFSET;
++		reg_addr->reg_num_x = M12_REGISTER_NUM_X;
++		reg_addr->reg_num_y = M12_REGISTER_NUM_Y;
++		break;
++
+ 	case M09:
+ 		reg_addr->reg_threshold = M09_REGISTER_THRESHOLD;
+ 		reg_addr->reg_gain = M09_REGISTER_GAIN;
+@@ -882,13 +1042,48 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
+ 	}
+ }
+ 
++#ifdef CONFIG_OF
++static int edt_ft5x06_i2c_ts_probe_dt(struct device *dev,
++				struct edt_ft5x06_ts_data *tsdata)
++{
++	struct device_node *np = dev->of_node;
++	/*
++	 * irq_pin is not needed for DT setup.
++	 * irq is associated via 'interrupts' property in DT
++	 */
++	tsdata->irq_pin = -EINVAL;
++	tsdata->reset_pin = of_get_named_gpio(np, "reset-gpios", 0);
++	tsdata->wake_pin = of_get_named_gpio(np, "wake-gpios", 0);
++	
++	tsdata->swap_xy = of_property_read_bool(np, "swap_xy")?1:0;
++	tsdata->invert_x = of_property_read_bool(np, "invert_x")?1:0;
++	tsdata->invert_y = of_property_read_bool(np, "invert_y")?1:0;
++
++	if(of_property_read_u32(np, "max_x", &tsdata->max_x))
++		tsdata->max_x = 0;
++	if(of_property_read_u32(np, "max_y", &tsdata->max_y))
++		tsdata->max_y = 0;
++
++	if(tsdata->swap_xy) {
++         printk(KERN_INFO "EDT-TC:: %s :: SWAP_XY\n", __func__);
++	 }
++	return 0;
++}
++#else
++static inline int edt_ft5x06_i2c_ts_probe_dt(struct device *dev,
++					struct edt_ft5x06_ts_data *tsdata)
++{
++	return -ENODEV;
++}
++#endif
++
+ static int edt_ft5x06_ts_probe(struct i2c_client *client,
+ 					 const struct i2c_device_id *id)
+ {
+-	const struct edt_i2c_chip_data *chip_data;
++	const struct edt_ft5x06_platform_data *pdata =
++						dev_get_platdata(&client->dev);
+ 	struct edt_ft5x06_ts_data *tsdata;
+ 	struct input_dev *input;
+-	unsigned long irq_flags;
+ 	int error;
+ 	char fw_version[EDT_NAME_LEN];
+ 
+@@ -900,43 +1095,32 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
+ 		return -ENOMEM;
+ 	}
+ 
+-	chip_data = of_device_get_match_data(&client->dev);
+-	if (!chip_data)
+-		chip_data = (const struct edt_i2c_chip_data *)id->driver_data;
+-	if (!chip_data || !chip_data->max_support_points) {
+-		dev_err(&client->dev, "invalid or missing chip data\n");
+-		return -EINVAL;
+-	}
+-
+-	tsdata->max_support_points = chip_data->max_support_points;
+-
+-	tsdata->reset_gpio = devm_gpiod_get_optional(&client->dev,
+-						     "reset", GPIOD_OUT_HIGH);
+-	if (IS_ERR(tsdata->reset_gpio)) {
+-		error = PTR_ERR(tsdata->reset_gpio);
+-		dev_err(&client->dev,
+-			"Failed to request GPIO reset pin, error %d\n", error);
+-		return error;
++	if (!pdata) {
++		error = edt_ft5x06_i2c_ts_probe_dt(&client->dev, tsdata);
++		if (error) {
++			dev_err(&client->dev,
++				"DT probe failed and no platform data present\n");
++			return error;
++		}
++	} else {
++		tsdata->reset_pin = pdata->reset_pin;
++		tsdata->irq_pin = pdata->irq_pin;
++		tsdata->wake_pin = -EINVAL;
+ 	}
+ 
+-	tsdata->wake_gpio = devm_gpiod_get_optional(&client->dev,
+-						    "wake", GPIOD_OUT_LOW);
+-	if (IS_ERR(tsdata->wake_gpio)) {
+-		error = PTR_ERR(tsdata->wake_gpio);
+-		dev_err(&client->dev,
+-			"Failed to request GPIO wake pin, error %d\n", error);
++	error = edt_ft5x06_ts_reset(client, tsdata);
++	if (error)
+ 		return error;
+-	}
+ 
+-	if (tsdata->wake_gpio) {
+-		usleep_range(5000, 6000);
+-		gpiod_set_value_cansleep(tsdata->wake_gpio, 1);
+-	}
+-
+-	if (tsdata->reset_gpio) {
+-		usleep_range(5000, 6000);
+-		gpiod_set_value_cansleep(tsdata->reset_gpio, 0);
+-		msleep(300);
++	if (gpio_is_valid(tsdata->irq_pin)) {
++		error = devm_gpio_request_one(&client->dev, tsdata->irq_pin,
++					GPIOF_IN, "edt-ft5x06 irq");
++		if (error) {
++			dev_err(&client->dev,
++				"Failed to request GPIO %d, error %d\n",
++				tsdata->irq_pin, error);
++			return error;
++		}
+ 	}
+ 
+ 	input = devm_input_allocate_device(&client->dev);
+@@ -957,7 +1141,12 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
+ 	}
+ 
+ 	edt_ft5x06_ts_set_regs(tsdata);
+-	edt_ft5x06_ts_get_defaults(&client->dev, tsdata);
++
++	if (!pdata)
++		edt_ft5x06_ts_get_dt_defaults(client->dev.of_node, tsdata);
++	else
++		edt_ft5x06_ts_get_defaults(tsdata, pdata);
++
+ 	edt_ft5x06_ts_get_parameters(tsdata);
+ 
+ 	dev_dbg(&client->dev,
+@@ -968,15 +1157,18 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
+ 	input->id.bustype = BUS_I2C;
+ 	input->dev.parent = &client->dev;
+ 
++	__set_bit(EV_SYN, input->evbit);
++	__set_bit(EV_KEY, input->evbit);
++	__set_bit(EV_ABS, input->evbit);
++	__set_bit(BTN_TOUCH, input->keybit);
++	
++ 	input_set_abs_params(input, ABS_X, 0, tsdata->max_x - 1, 0, 0);
++	input_set_abs_params(input, ABS_Y, 0, tsdata->max_y - 1, 0, 0);
+ 	input_set_abs_params(input, ABS_MT_POSITION_X,
+-			     0, tsdata->num_x * 64 - 1, 0, 0);
++			     0, tsdata->max_x - 1, 0, 0);
+ 	input_set_abs_params(input, ABS_MT_POSITION_Y,
+-			     0, tsdata->num_y * 64 - 1, 0, 0);
+-
+-	touchscreen_parse_properties(input, true, &tsdata->prop);
+-
+-	error = input_mt_init_slots(input, tsdata->max_support_points,
+-				INPUT_MT_DIRECT);
++			     0, tsdata->max_y - 1, 0, 0);
++	error = input_mt_init_slots(input, MAX_SUPPORT_POINTS, 0);
+ 	if (error) {
+ 		dev_err(&client->dev, "Unable to init MT slots.\n");
+ 		return error;
+@@ -985,13 +1177,9 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
+ 	input_set_drvdata(input, tsdata);
+ 	i2c_set_clientdata(client, tsdata);
+ 
+-	irq_flags = irq_get_trigger_type(client->irq);
+-	if (irq_flags == IRQF_TRIGGER_NONE)
+-		irq_flags = IRQF_TRIGGER_FALLING;
+-	irq_flags |= IRQF_ONESHOT;
+-
+-	error = devm_request_threaded_irq(&client->dev, client->irq,
+-					NULL, edt_ft5x06_ts_isr, irq_flags,
++	error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
++					edt_ft5x06_ts_isr,
++					IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ 					client->name, tsdata);
+ 	if (error) {
+ 		dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
+@@ -1011,9 +1199,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
+ 
+ 	dev_dbg(&client->dev,
+ 		"EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n",
+-		client->irq,
+-		tsdata->wake_gpio ? desc_to_gpio(tsdata->wake_gpio) : -1,
+-		tsdata->reset_gpio ? desc_to_gpio(tsdata->reset_gpio) : -1);
++		client->irq, tsdata->wake_pin, tsdata->reset_pin);
+ 
+ 	return 0;
+ 
+@@ -1032,7 +1218,8 @@ static int edt_ft5x06_ts_remove(struct i2c_client *client)
+ 	return 0;
+ }
+ 
+-static int __maybe_unused edt_ft5x06_ts_suspend(struct device *dev)
++#ifdef CONFIG_PM_SLEEP
++static int edt_ft5x06_ts_suspend(struct device *dev)
+ {
+ 	struct i2c_client *client = to_i2c_client(dev);
+ 
+@@ -1042,7 +1229,7 @@ static int __maybe_unused edt_ft5x06_ts_suspend(struct device *dev)
+ 	return 0;
+ }
+ 
+-static int __maybe_unused edt_ft5x06_ts_resume(struct device *dev)
++static int edt_ft5x06_ts_resume(struct device *dev)
+ {
+ 	struct i2c_client *client = to_i2c_client(dev);
+ 
+@@ -1051,31 +1238,22 @@ static int __maybe_unused edt_ft5x06_ts_resume(struct device *dev)
+ 
+ 	return 0;
+ }
++#endif
+ 
+ static SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops,
+ 			 edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume);
+ 
+-static const struct edt_i2c_chip_data edt_ft5x06_data = {
+-	.max_support_points = 5,
+-};
+-
+-static const struct edt_i2c_chip_data edt_ft5506_data = {
+-	.max_support_points = 10,
+-};
+-
+ static const struct i2c_device_id edt_ft5x06_ts_id[] = {
+-	{ .name = "edt-ft5x06", .driver_data = (long)&edt_ft5x06_data },
+-	{ .name = "edt-ft5506", .driver_data = (long)&edt_ft5506_data },
++	{ "edt-ft5x06", 0, },
+ 	{ /* sentinel */ }
+ };
+ MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id);
+ 
+ #ifdef CONFIG_OF
+ static const struct of_device_id edt_ft5x06_of_match[] = {
+-	{ .compatible = "edt,edt-ft5206", .data = &edt_ft5x06_data },
+-	{ .compatible = "edt,edt-ft5306", .data = &edt_ft5x06_data },
+-	{ .compatible = "edt,edt-ft5406", .data = &edt_ft5x06_data },
+-	{ .compatible = "edt,edt-ft5506", .data = &edt_ft5506_data },
++	{ .compatible = "edt,edt-ft5206", },
++	{ .compatible = "edt,edt-ft5306", },
++	{ .compatible = "edt,edt-ft5406", },
+ 	{ /* sentinel */ }
+ };
+ MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match);
+@@ -1083,6 +1261,7 @@ MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match);
+ 
+ static struct i2c_driver edt_ft5x06_ts_driver = {
+ 	.driver = {
++		.owner = THIS_MODULE,
+ 		.name = "edt_ft5x06",
+ 		.of_match_table = of_match_ptr(edt_ft5x06_of_match),
+ 		.pm = &edt_ft5x06_ts_pm_ops,
+diff --git a/include/linux/input/edt-ft5x06.h b/include/linux/input/edt-ft5x06.h
+new file mode 100644
+index 0000000..8a1e0d1
+--- /dev/null
++++ b/include/linux/input/edt-ft5x06.h
+@@ -0,0 +1,24 @@
++#ifndef _EDT_FT5X06_H
++#define _EDT_FT5X06_H
++
++/*
++ * Copyright (c) 2012 Simon Budig, <simon.budig@kernelconcepts.de>
++ *
++ * 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.
++ */
++
++struct edt_ft5x06_platform_data {
++	int irq_pin;
++	int reset_pin;
++
++	/* startup defaults for operational parameters */
++	bool use_parameters;
++	u8 gain;
++	u8 threshold;
++	u8 offset;
++	u8 report_rate;
++};
++
++#endif /* _EDT_FT5X06_H */