From 5f5bd605abef552c798a6d94f04d71a0ee858c8a Mon Sep 17 00:00:00 2001
From: luowei <lw@rock-chips.com>
Date: Tue, 9 Oct 2012 20:10:19 +0800
Subject: [PATCH] rk30_phonepad:add auto touchscreen support

---
 drivers/input/Kconfig           |   2 +
 drivers/input/Makefile          |   1 +
 drivers/input/ts/Kconfig        |  15 +
 drivers/input/ts/Makefile       |   6 +
 drivers/input/ts/chips/Kconfig  |  11 +
 drivers/input/ts/chips/Makefile |   3 +
 drivers/input/ts/chips/ft5306.c | 259 ++++++++++++++++
 drivers/input/ts/chips/gt8110.c | 330 +++++++++++++++++++++
 drivers/input/ts/ts-auto.c      | 511 ++++++++++++++++++++++++++++++++
 drivers/input/ts/ts-i2c.c       | 233 +++++++++++++++
 include/linux/ts-auto.h         | 117 ++++++++
 11 files changed, 1488 insertions(+)
 create mode 100755 drivers/input/ts/Kconfig
 create mode 100755 drivers/input/ts/Makefile
 create mode 100755 drivers/input/ts/chips/Kconfig
 create mode 100755 drivers/input/ts/chips/Makefile
 create mode 100644 drivers/input/ts/chips/ft5306.c
 create mode 100644 drivers/input/ts/chips/gt8110.c
 create mode 100644 drivers/input/ts/ts-auto.c
 create mode 100755 drivers/input/ts/ts-i2c.c
 create mode 100644 include/linux/ts-auto.h

diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 972b67ffaffd..1682dbae1bda 100755
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -182,6 +182,8 @@ source "drivers/input/tablet/Kconfig"
 
 source "drivers/input/touchscreen/Kconfig"
 
+source "drivers/input/ts/Kconfig"
+
 source "drivers/input/misc/Kconfig"
 
 source "drivers/input/magnetometer/Kconfig"
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index d9f2e938540e..89a28d2b8623 100755
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_LIGHT_SENSOR_DEVICE) += lightsensor/
 obj-$(CONFIG_MAG_SENSORS)	+= magnetometer/
 
 obj-$(CONFIG_SENSOR_DEVICE)	+= sensors/
+obj-$(CONFIG_TS_AUTO)	+= ts/
 
 obj-$(CONFIG_INPUT_APMPOWER)	+= apm-power.o
 obj-$(CONFIG_INPUT_KEYRESET)	+= keyreset.o
diff --git a/drivers/input/ts/Kconfig b/drivers/input/ts/Kconfig
new file mode 100755
index 000000000000..e205cb125737
--- /dev/null
+++ b/drivers/input/ts/Kconfig
@@ -0,0 +1,15 @@
+#
+# all auto touch screen drivers configuration
+#
+
+menuconfig TS_AUTO
+	bool "auto touch screen driver support"
+	default n	
+
+if TS_AUTO
+
+source "drivers/input/ts/chips/Kconfig"
+
+endif
+
+
diff --git a/drivers/input/ts/Makefile b/drivers/input/ts/Makefile
new file mode 100755
index 000000000000..a92c9b671b1d
--- /dev/null
+++ b/drivers/input/ts/Makefile
@@ -0,0 +1,6 @@
+# auto touch screen drivers
+obj-$(CONFIG_TS_AUTO)			+= chips/
+
+obj-$(CONFIG_TS_AUTO)			+= ts-i2c.o
+obj-$(CONFIG_TS_AUTO)			+= ts-auto.o
+
diff --git a/drivers/input/ts/chips/Kconfig b/drivers/input/ts/chips/Kconfig
new file mode 100755
index 000000000000..7dc4b2ab2f48
--- /dev/null
+++ b/drivers/input/ts/chips/Kconfig
@@ -0,0 +1,11 @@
+config TS_FT5306
+  bool "touch screen ft5306"
+	default n
+ 
+config TS_CT360
+  bool "touch screen ct360"
+	default n
+
+config TS_GT8110
+  bool "touch screen gt8110"
+	default n	  
\ No newline at end of file
diff --git a/drivers/input/ts/chips/Makefile b/drivers/input/ts/chips/Makefile
new file mode 100755
index 000000000000..aec7f1c31b27
--- /dev/null
+++ b/drivers/input/ts/chips/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_TS_FT5306)			+= ft5306.o
+obj-$(CONFIG_TS_CT360)			+= ct360.o
+obj-$(CONFIG_TS_GT8110)			+= gt8110.o
\ No newline at end of file
diff --git a/drivers/input/ts/chips/ft5306.c b/drivers/input/ts/chips/ft5306.c
new file mode 100644
index 000000000000..4c045f15be9f
--- /dev/null
+++ b/drivers/input/ts/chips/ft5306.c
@@ -0,0 +1,259 @@
+/* drivers/input/ts/chips/ts_ft5306.c
+ *
+ * Copyright (C) 2012-2015 ROCKCHIP.
+ * Author: luowei <lw@rock-chips.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/miscdevice.h>
+#include <linux/gpio.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/freezer.h>
+#include <linux/input/mt.h>
+#include <mach/gpio.h>
+#include <mach/board.h> 
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif	 
+#include <linux/ts-auto.h>
+	 
+	 
+#if 0
+#define DBG(x...)  printk(x)
+#else
+#define DBG(x...)
+#endif
+
+
+#define FT5306_ID_REG		0x00
+#define FT5306_DEVID		0x00
+#define FT5306_DATA_REG		0x00
+
+
+/****************operate according to ts chip:start************/
+
+static int ts_active(struct i2c_client *client, int enable)
+{
+	struct ts_private_data *ts =
+	    (struct ts_private_data *) i2c_get_clientdata(client);	
+	int result = 0;
+
+	if(enable)
+	{
+		gpio_direction_output(ts->pdata->reset_pin, GPIO_LOW);
+		mdelay(10);
+		gpio_direction_output(ts->pdata->reset_pin, GPIO_HIGH);
+		msleep(100);
+	}
+	else
+	{
+		gpio_direction_output(ts->pdata->reset_pin, GPIO_LOW);	
+	}
+		
+	
+	return result;
+}
+
+static int ts_init(struct i2c_client *client)
+{
+	struct ts_private_data *ts =
+	    (struct ts_private_data *) i2c_get_clientdata(client);
+	int irq_pin = irq_to_gpio(ts->pdata->irq);
+	int result = 0;
+	
+	gpio_direction_output(ts->pdata->reset_pin, GPIO_LOW);
+	mdelay(10);
+	gpio_direction_output(ts->pdata->reset_pin, GPIO_HIGH);
+	msleep(100);
+
+	//init some register
+	//to do
+	
+	return result;
+}
+
+
+static int ts_report_value(struct i2c_client *client)
+{
+	struct ts_private_data *ts =
+		(struct ts_private_data *) i2c_get_clientdata(client);	
+	struct ts_platform_data *pdata = ts->pdata;
+	struct ts_event *event = &ts->event;
+	unsigned char buf[32] = {0};
+	int result = 0 , i = 0, off = 0, id = 0;
+
+	buf[0] = ts->ops->read_reg;
+	result = ts_rx_data(client, buf, ts->ops->read_len);
+	if(result < 0)
+	{
+		printk("%s:fail to init ts\n",__func__);
+		return result;
+	}
+
+	//for(i=0; i<ts->ops->read_len; i++)
+	//DBG("buf[%d]=0x%x\n",i,buf[i]);
+	
+	event->touch_point = buf[2] & 0x07;// 0000 1111
+
+	if(event->touch_point == 0)
+	{	
+		for(i=0; i<ts->ops->max_point; i++)
+		{
+			if(event->point[i].status != 0)
+			{
+				event->point[i].status = 0;				
+				input_mt_slot(ts->input_dev, event->point[i].id);				
+				input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1);
+				input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, false);
+				DBG("%s:%s press up,id=%d\n",__func__,ts->ops->name, event->point[i].id);
+			}
+		}
+		
+		input_sync(ts->input_dev);
+		memset(event, 0x00, sizeof(struct ts_event));
+				
+		return 0;
+	}
+	
+	for(i = 0; i<event->touch_point; i++)
+	{
+		off = i*6+3;
+		id = (buf[off+2] & 0xf0) >> 4;				
+		event->point[id].id = id;
+		event->point[id].status = (buf[off+0] & 0xc0) >> 6;
+		event->point[id].x = ((buf[off+0] & 0x0f)<<8) | buf[off+1];
+		event->point[id].y = ((buf[off+2] & 0x0f)<<8) | buf[off+3];
+		
+		if(ts->ops->xy_swap)
+		{
+			swap(event->point[id].x, event->point[id].y);
+		}
+
+		if(ts->ops->x_revert)
+		{
+			event->point[id].x = ts->ops->pixel.max_x - event->point[id].x;	
+		}
+
+		if(ts->ops->y_revert)
+		{
+			event->point[id].y = ts->ops->pixel.max_y - event->point[id].y;
+		}
+
+		if(event->point[id].status != 0)
+		{		
+			input_mt_slot(ts->input_dev, event->point[id].id);
+			input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, event->point[id].id);
+			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 1);
+			input_report_abs(ts->input_dev, ABS_MT_POSITION_X, event->point[id].x);
+			input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, event->point[id].y);
+			input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 1);
+	   		DBG("%s:%s press down,id=%d,x=%d,y=%d\n",__func__,ts->ops->name, event->point[id].id, event->point[id].x,event->point[id].y);
+		}
+		
+		
+	}
+	
+	input_sync(ts->input_dev);
+
+	return 0;
+}
+
+static int ts_suspend(struct i2c_client *client)
+{
+	struct ts_private_data *ts =
+		(struct ts_private_data *) i2c_get_clientdata(client);	
+	struct ts_platform_data *pdata = ts->pdata;
+	
+	if(ts->pdata->irq_enable)	
+		disable_irq_nosync(client->irq);
+
+	if(ts->ops->active)
+		ts->ops->active(client, 0);
+	
+	return 0;
+}
+
+
+static int ts_resume(struct i2c_client *client)
+{
+	struct ts_private_data *ts =
+		(struct ts_private_data *) i2c_get_clientdata(client);	
+	struct ts_platform_data *pdata = ts->pdata;
+	
+	if(ts->pdata->irq_enable)	
+		enable_irq(client->irq);
+
+	if(ts->ops->active)
+		ts->ops->active(client, 1);
+	return 0;
+}
+
+
+
+struct ts_operate ts_ft5306_ops = {
+	.name				= "ft5306",
+	.slave_addr			= 0x3e,
+	.id_i2c				= TS_ID_FT5306,			//i2c id number
+	.pixel				= {1024,768},
+	.id_reg				= FT5306_ID_REG,
+	.id_data			= TS_UNKNOW_DATA,	
+	.read_reg			= FT5306_DATA_REG,		//read data
+	.read_len			= 32,				//data length
+	.trig				= IRQF_TRIGGER_FALLING,		
+	.max_point			= 5,
+	.xy_swap 			= 1,
+	.x_revert 			= 1,
+	.y_revert			= 0,
+	.range				= {1024,768},
+	.active				= ts_active,	
+	.init				= ts_init,
+	.report 			= ts_report_value,
+	.firmware			= NULL,
+	.suspend			= ts_suspend,
+	.resume				= ts_resume,
+};
+
+/****************operate according to ts chip:end************/
+
+//function name should not be changed
+static struct ts_operate *ts_get_ops(void)
+{
+	return &ts_ft5306_ops;
+}
+
+
+static int __init ts_ft5306_init(void)
+{
+	struct ts_operate *ops = ts_get_ops();
+	int result = 0;
+	result = ts_register_slave(NULL, NULL, ts_get_ops);	
+	DBG("%s\n",__func__);
+	return result;
+}
+
+static void __exit ts_ft5306_exit(void)
+{
+	struct ts_operate *ops = ts_get_ops();
+	ts_unregister_slave(NULL, NULL, ts_get_ops);
+}
+
+
+subsys_initcall(ts_ft5306_init);
+module_exit(ts_ft5306_exit);
+
diff --git a/drivers/input/ts/chips/gt8110.c b/drivers/input/ts/chips/gt8110.c
new file mode 100644
index 000000000000..99c8097c33d8
--- /dev/null
+++ b/drivers/input/ts/chips/gt8110.c
@@ -0,0 +1,330 @@
+/* drivers/input/ts/chips/gt8110.c
+ *
+ * Copyright (C) 2012-2015 ROCKCHIP.
+ * Author: luowei <lw@rock-chips.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/miscdevice.h>
+#include <linux/gpio.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/freezer.h>
+#include <linux/input/mt.h>
+#include <mach/gpio.h>
+#include <mach/board.h> 
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif	 
+#include <linux/ts-auto.h>
+	 
+	 
+#if 0
+#define DBG(x...)  printk(x)
+#else
+#define DBG(x...)
+#endif
+
+
+#define GT8110_ID_REG		0x00
+#define GT8110_DATA_REG		0x00
+
+
+/****************operate according to ts chip:start************/
+
+static int ts_active(struct i2c_client *client, int enable)
+{
+	struct ts_private_data *ts =
+	    (struct ts_private_data *) i2c_get_clientdata(client);
+	unsigned char buf_suspend[2] = {0x38, 0x56};		//suspend cmd
+	int result = 0;
+
+	if(enable)
+	{
+		gpio_direction_output(ts->pdata->reset_pin, GPIO_LOW);
+		mdelay(200);
+		gpio_direction_output(ts->pdata->reset_pin, GPIO_HIGH);
+		msleep(200);
+	}
+	else
+	{
+		result = ts_tx_data(client, buf_suspend, 2);
+		if(result < 0)
+		{
+			printk("%s:fail to init ts\n",__func__);
+			return result;
+		}
+		
+		gpio_direction_output(ts->pdata->reset_pin, GPIO_LOW);	
+	}
+		
+	
+	return result;
+}
+
+static int ts_init(struct i2c_client *client)
+{
+	struct ts_private_data *ts =
+	    (struct ts_private_data *) i2c_get_clientdata(client);
+	int irq_pin = irq_to_gpio(ts->pdata->irq);
+	char version_data[18] = {240};
+	char init_data[95] = {
+	0x65,0x02,0x00,0x10,0x00,0x10,0x0A,0x6E,0x0A,0x00,
+	0x0F,0x1E,0x02,0x08,0x10,0x00,0x00,0x27,0x00,0x00,
+	0x50,0x10,0x10,0x11,0x37,0x00,0x00,0x00,0x01,0x02,
+	0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0xFF,
+	0xFF,0xFF,0xFF,0x00,0x01,0x02,0x03,0x04,0x05,0x06,
+	0x07,0x08,0x09,0x0A,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,
+	0x00,0x50,0x64,0x50,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+	0x00,0x00,0x00,0x00,0x20
+        };
+	int result = 0, i = 0;
+
+	//read version
+	result = ts_rx_data(client, version_data, 17);
+	if(result < 0)
+	{
+		printk("%s:fail to init ts\n",__func__);
+		return result;
+	}
+	version_data[17]='\0';
+
+	printk("%s:%s version is %s\n",__func__,ts->ops->name, version_data);
+#if 1
+	//init some register
+	result = ts_tx_data(client, init_data, 95);
+	if(result < 0)
+	{
+		printk("%s:fail to init ts\n",__func__);
+		return result;
+	}
+#endif
+	result = ts_rx_data(client, init_data, 95);
+	if(result < 0)
+	{
+		printk("%s:fail to init ts\n",__func__);
+		return result;
+	}
+
+	
+	printk("%s:rx:",__func__);
+	for(i=0; i<95; i++)
+	printk("0x%x,",init_data[i]);
+
+	printk("\n");
+	
+	return result;
+}
+
+
+static int ts_report_value(struct i2c_client *client)
+{
+	struct ts_private_data *ts =
+		(struct ts_private_data *) i2c_get_clientdata(client);	
+	struct ts_platform_data *pdata = ts->pdata;
+	struct ts_event *event = &ts->event;
+	unsigned char buf[54] = {0};
+	int result = 0 , i = 0, j = 0, off = 0, id = 0;
+	int temp = 0, num = 0;
+
+	buf[0] = ts->ops->read_reg;
+	result = ts_rx_data(client, buf, ts->ops->read_len);
+	if(result < 0)
+	{
+		printk("%s:fail to init ts\n",__func__);
+		return result;
+	}
+
+	//for(i=0; i<ts->ops->read_len; i++)
+	//DBG("buf[%d]=0x%x\n",i,buf[i]);
+
+	//temp =  (buf[2]<<8) + buf[1];
+
+	temp = ((buf[2]&0x03) << 8) | buf[1];
+	for(i=0; i<ts->ops->max_point; i++)
+	{
+		if(temp & (1 << i)) 
+			num++;
+	}
+
+	event->touch_point = num;
+#if 0
+	if(event->touch_point == 0)
+	{	
+		for(i=0; i<ts->ops->max_point; i++)
+		{
+			if(event->point[i].status != 0)
+			{
+				event->point[i].status = 0;				
+				input_mt_slot(ts->input_dev, event->point[i].id);				
+				input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1);
+				input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, false);
+				DBG("%s:%s press up,id=%d\n",__func__,ts->ops->name, event->point[i].id);
+			}
+		}
+		
+		input_sync(ts->input_dev);
+		memset(event, 0x00, sizeof(struct ts_event));
+				
+		return 0;
+	}
+#endif	
+	for(i = 0; i<ts->ops->max_point; i++)
+	{
+		off = 3 + i*4;
+		
+		id = i;				
+		event->point[id].id = id;
+		event->point[id].status = temp & (1 << (ts->ops->max_point - i -1));
+		event->point[id].x = (unsigned int)(buf[off+0]<<8) + (unsigned int)buf[off+1];
+		event->point[id].y = (unsigned int)(buf[off+2]<<8) + (unsigned int)buf[off+3];
+		//event->point[id].press = buf[off+4];
+
+		//for(j=0; j<(3 + (i+1)*4); j++)
+		//DBG("buf[%d]=0x%x\n",j,buf[j]);
+		
+		if(ts->ops->xy_swap)
+		{
+			swap(event->point[id].x, event->point[id].y);
+		}
+
+		if(ts->ops->x_revert)
+		{
+			event->point[id].x = ts->ops->pixel.max_x - event->point[id].x;	
+		}
+
+		if(ts->ops->y_revert)
+		{
+			event->point[id].y = ts->ops->pixel.max_y - event->point[id].y;
+		}
+
+		DBG("%s:point[%d].status=%d,point[%d].last_status=%d\n",__func__,i,event->point[i].status,i,event->point[i].last_status);
+
+		if(event->point[id].status != 0)
+		{		
+			input_mt_slot(ts->input_dev, event->point[id].id);
+			input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, event->point[id].id);
+			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 1);
+			input_report_abs(ts->input_dev, ABS_MT_POSITION_X, event->point[id].x);
+			input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, event->point[id].y);
+			input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 1);	
+	   		DBG("%s:%s press down,id=%d,x=%d,y=%d\n\n",__func__,ts->ops->name, event->point[id].id, event->point[id].x,event->point[id].y);
+		}
+		else if((event->point[id].status == 0) && (event->point[id].last_status != 0))
+		{
+			event->point[i].status = 0;				
+			input_mt_slot(ts->input_dev, event->point[i].id);				
+			input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1);
+			input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, false);
+			DBG("%s:%s press up,id=%d\n\n",__func__,ts->ops->name, event->point[i].id);
+
+		}
+		
+		event->point[id].last_status = event->point[id].status;
+	}
+	
+	input_sync(ts->input_dev);
+
+	return 0;
+}
+
+static int ts_suspend(struct i2c_client *client)
+{
+	struct ts_private_data *ts =
+		(struct ts_private_data *) i2c_get_clientdata(client);	
+	struct ts_platform_data *pdata = ts->pdata;
+	
+	if(ts->pdata->irq_enable)	
+		disable_irq_nosync(client->irq);
+
+	if(ts->ops->active)
+		ts->ops->active(client, 0);
+	
+	return 0;
+}
+
+
+static int ts_resume(struct i2c_client *client)
+{
+	struct ts_private_data *ts =
+		(struct ts_private_data *) i2c_get_clientdata(client);	
+	struct ts_platform_data *pdata = ts->pdata;
+	
+	if(ts->pdata->irq_enable)	
+		enable_irq(client->irq);
+
+	if(ts->ops->active)
+		ts->ops->active(client, 1);
+	return 0;
+}
+
+
+
+struct ts_operate ts_gt8110_ops = {
+	.name				= "gt8110",
+	.slave_addr			= 0x5c,
+	.id_i2c				= TS_ID_GT8110,			//i2c id number
+	.pixel				= {1280,800},
+	.id_reg				= GT8110_ID_REG,
+	.id_data			= TS_UNKNOW_DATA,	
+	.read_reg			= GT8110_DATA_REG,		//read data
+	.read_len			= 5*10+3+1,			//data length
+	.trig				= IRQ_TYPE_LEVEL_LOW | IRQF_ONESHOT,		
+	.max_point			= 10,
+	.xy_swap 			= 0,
+	.x_revert 			= 0,
+	.y_revert			= 0,
+	.range				= {4096,4096},
+	.active				= ts_active,	
+	.init				= ts_init,
+	.report 			= ts_report_value,
+	.firmware			= NULL,
+	.suspend			= ts_suspend,
+	.resume				= ts_resume,
+};
+
+/****************operate according to ts chip:end************/
+
+//function name should not be changed
+static struct ts_operate *ts_get_ops(void)
+{
+	return &ts_gt8110_ops;
+}
+
+
+static int __init ts_gt8110_init(void)
+{
+	struct ts_operate *ops = ts_get_ops();
+	int result = 0;
+	result = ts_register_slave(NULL, NULL, ts_get_ops);	
+	DBG("%s\n",__func__);
+	return result;
+}
+
+static void __exit ts_gt8110_exit(void)
+{
+	struct ts_operate *ops = ts_get_ops();
+	ts_unregister_slave(NULL, NULL, ts_get_ops);
+}
+
+
+subsys_initcall(ts_gt8110_init);
+module_exit(ts_gt8110_exit);
+
diff --git a/drivers/input/ts/ts-auto.c b/drivers/input/ts/ts-auto.c
new file mode 100644
index 000000000000..ca141fb66b29
--- /dev/null
+++ b/drivers/input/ts/ts-auto.c
@@ -0,0 +1,511 @@
+/* drivers/input/ts/ts-auto.c - handle all touchscreen in this file
+ *
+ * Copyright (C) 2012-2015 ROCKCHIP.
+ * Author: luowei <lw@rock-chips.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/miscdevice.h>
+#include <linux/gpio.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/freezer.h>
+#include <linux/input/mt.h>
+#include <mach/gpio.h>
+#include <mach/board.h> 
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
+#include <linux/ts-auto.h>
+
+
+#if 0
+#define DBG(x...)  printk(x)
+#else
+#define DBG(x...)
+#endif
+
+struct ts_private_data *g_ts;
+static struct class *g_ts_class;
+static struct ts_operate *g_ts_ops[TS_NUM_ID]; 
+
+static int ts_get_id(struct ts_operate *ops, struct i2c_client *client, int *value)
+{
+	struct ts_private_data *ts =
+	    (struct ts_private_data *) i2c_get_clientdata(client);	
+	int result = 0;
+	char temp = ops->id_reg;
+	int i = 0;
+	
+	DBG("%s:start\n",__func__);
+	if(ops->id_reg >= 0)
+	{
+		for(i=0; i<1; i++)
+		{
+			result = ts_rx_data(client, &temp, 1);
+			*value = temp;
+			if(!result)
+			break;
+		}
+
+		if(result)
+			return result;
+		
+		if((ops->id_data != TS_UNKNOW_DATA)&&(ops->id_data != *value)) 
+		{
+			printk("%s:id=0x%x is not 0x%x\n",__func__,*value, ops->id_data);
+			result = -1;
+		}
+			
+		DBG("%s:devid=0x%x\n",__func__,*value);
+	}
+
+	return result;
+}
+
+
+static int ts_chip_init(struct i2c_client *client)
+{
+	struct ts_private_data *ts =
+	    (struct ts_private_data *) i2c_get_clientdata(client);	
+	struct ts_operate *ops = NULL;
+	int result = 0;
+	int i = 0;
+	
+	if(ts->pdata->init_platform_hw)
+		ts->pdata->init_platform_hw();
+	
+	for(i=TS_ID_INVALID+1; i<TS_NUM_ID; i++)
+	{
+		ops = g_ts_ops[i];
+		if(!ops)
+		{
+			printk("%s:error:%p\n",__func__,ops);
+			result = -1;	
+			continue;
+		}
+		
+		if(!ops->init || !ops->report)
+		{
+			printk("%s:error:%p,%p\n",__func__,ops->init,ops->report);
+			result = -1;
+			continue;
+		}
+
+		client->addr = ops->slave_addr;	//use slave_addr of ops
+		
+		if(ops->active)
+		{
+			result = ops->active(client, TS_ENABLE);
+			if(result < 0)
+			{
+				printk("%s:fail to init ts\n",__func__);
+				continue;
+			}
+		}
+
+		result = ts_get_id(ops, client, &ts->devid);//get id
+		if(result < 0)
+		{	
+			printk("%s:fail to read %s devid:0x%x\n",__func__, ops->name, ts->devid);	
+			continue;
+		}
+	
+		ts->ops = ops;	//save ops
+
+		result = ops->init(client);
+		if(result < 0)
+		{
+			printk("%s:fail to init ts\n",__func__);	
+			continue;
+		}
+
+		if(ops->firmware)
+		{
+			result = ops->firmware(client);
+			if(result < 0)
+			{
+				printk("%s:fail to updata firmware ts\n",__func__);
+				return result;
+			}
+		}
+	
+		printk("%s:%s devid:0x%x\n",__func__, ts->ops->name, ts->devid);
+
+		break;
+					
+	}
+
+	
+	return result;
+
+}
+
+
+static int ts_get_data(struct i2c_client *client)
+{
+	struct ts_private_data *ts =
+	    (struct ts_private_data *) i2c_get_clientdata(client);	
+	int result = 0;
+	
+	result = ts->ops->report(client);
+	if(result)
+		goto error;
+	
+error:		
+	return result;
+}
+
+
+static void  ts_delaywork_func(struct work_struct *work)
+{
+	struct delayed_work *delaywork = container_of(work, struct delayed_work, work);
+	struct ts_private_data *ts = container_of(delaywork, struct ts_private_data, delaywork);
+	struct i2c_client *client = ts->client;
+
+	mutex_lock(&ts->ts_mutex);	
+	if (ts_get_data(client) < 0) 
+		DBG(KERN_ERR "%s: Get data failed\n",__func__);
+	
+	if(!ts->pdata->irq_enable)//restart work while polling
+	schedule_delayed_work(&ts->delaywork, msecs_to_jiffies(ts->pdata->poll_delay_ms));
+	//else
+	//{
+		//if((ts->ops->trig == IRQF_TRIGGER_LOW) || (ts->ops->trig == IRQF_TRIGGER_HIGH))
+		//enable_irq(ts->client->irq);
+	//}
+	mutex_unlock(&ts->ts_mutex);
+	
+	DBG("%s:%s\n",__func__,ts->i2c_id->name);
+}
+
+/*
+ * This is a threaded IRQ handler so can access I2C/SPI.  Since all
+ * interrupts are clear on read the IRQ line will be reasserted and
+ * the physical IRQ will be handled again if another interrupt is
+ * asserted while we run - in the normal course of events this is a
+ * rare occurrence so we save I2C/SPI reads.  We're also assuming that
+ * it's rare to get lots of interrupts firing simultaneously so try to
+ * minimise I/O.
+ */
+static irqreturn_t ts_interrupt(int irq, void *dev_id)
+{
+	struct ts_private_data *ts = (struct ts_private_data *)dev_id;
+
+	//use threaded IRQ
+	if (ts_get_data(ts->client) < 0) 
+		DBG(KERN_ERR "%s: Get data failed\n",__func__);
+	msleep(ts->pdata->poll_delay_ms);
+
+	
+	//if((ts->ops->trig == IRQF_TRIGGER_LOW) || (ts->ops->trig == IRQF_TRIGGER_HIGH))
+	//disable_irq_nosync(irq);
+	//schedule_delayed_work(&ts->delaywork, msecs_to_jiffies(ts->pdata->poll_delay_ms));
+	DBG("%s:irq=%d\n",__func__,irq);
+	return IRQ_HANDLED;
+}
+
+
+static int ts_irq_init(struct i2c_client *client)
+{
+	struct ts_private_data *ts =
+	    (struct ts_private_data *) i2c_get_clientdata(client);	
+	int result = 0;
+	int irq;
+	if((ts->pdata->irq_enable)&&(ts->ops->trig != TS_UNKNOW_DATA))
+	{
+		//INIT_DELAYED_WORK(&ts->delaywork, ts_delaywork_func);
+		if(ts->pdata->poll_delay_ms < 0)
+			ts->pdata->poll_delay_ms = 30;
+		
+		result = gpio_request(client->irq, ts->i2c_id->name);
+		if (result)
+		{
+			printk("%s:fail to request gpio :%d\n",__func__,client->irq);
+		}
+	
+		gpio_pull_updown(client->irq, PullEnable);
+		irq = gpio_to_irq(client->irq);
+		//result = request_irq(irq, ts_interrupt, ts->ops->trig, ts->ops->name, ts);
+		result = request_threaded_irq(irq, NULL, ts_interrupt, ts->ops->trig, ts->ops->name, ts);
+		if (result) {
+			printk(KERN_ERR "%s:fail to request irq = %d, ret = 0x%x\n",__func__, irq, result);	       
+			goto error;	       
+		}
+		client->irq = irq;
+		printk("%s:use irq=%d\n",__func__,irq);
+	}
+	else if(!ts->pdata->irq_enable)
+	{		
+		INIT_DELAYED_WORK(&ts->delaywork, ts_delaywork_func);
+		if(ts->pdata->poll_delay_ms < 0)
+			ts->pdata->poll_delay_ms = 30;
+		
+		printk("%s:use polling,delay=%d ms\n",__func__,ts->pdata->poll_delay_ms);
+	}
+
+error:	
+	return result;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void ts_suspend(struct early_suspend *h)
+{
+	struct ts_private_data *ts = 
+			container_of(h, struct ts_private_data, early_suspend);
+	
+	if(ts->ops->suspend)
+		ts->ops->suspend(ts->client);
+
+}
+
+static void ts_resume(struct early_suspend *h)
+{
+	struct ts_private_data *ts = 
+			container_of(h, struct ts_private_data, early_suspend);
+
+	if(ts->ops->resume)
+		ts->ops->resume(ts->client);
+}
+#endif
+
+
+
+int ts_register_slave(struct i2c_client *client,
+			struct ts_platform_data *slave_pdata,
+			struct ts_operate *(*get_ts_ops)(void))
+{
+	int result = 0;
+	struct ts_operate *ops = get_ts_ops();
+	if((ops->id_i2c >= TS_NUM_ID) || (ops->id_i2c <= TS_ID_INVALID))
+	{	
+		printk("%s:%s id is error %d\n", __func__, ops->name, ops->id_i2c);
+		return -1;	
+	}
+	g_ts_ops[ops->id_i2c] = ops;
+	printk("%s:%s,id=%d\n",__func__,g_ts_ops[ops->id_i2c]->name, ops->id_i2c);
+	return result;
+}
+
+
+int ts_unregister_slave(struct i2c_client *client,
+			struct ts_platform_data *slave_pdata,
+			struct ts_operate *(*get_ts_ops)(void))
+{
+	int result = 0;
+	struct ts_operate *ops = get_ts_ops();
+	if((ops->id_i2c >= TS_NUM_ID) || (ops->id_i2c <= TS_ID_INVALID))
+	{	
+		printk("%s:%s id is error %d\n", __func__, ops->name, ops->id_i2c);
+		return -1;	
+	}
+	printk("%s:%s,id=%d\n",__func__,g_ts_ops[ops->id_i2c]->name, ops->id_i2c);
+	g_ts_ops[ops->id_i2c] = NULL;	
+	return result;
+}
+
+
+int ts_probe(struct i2c_client *client, const struct i2c_device_id *devid)
+{
+	struct ts_private_data *ts =
+	    (struct ts_private_data *) i2c_get_clientdata(client);
+	struct ts_platform_data *pdata;
+	int result = 0;
+	dev_info(&client->adapter->dev, "%s: %s,0x%x\n", __func__, devid->name,(unsigned int)client);
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		result = -ENODEV;
+		goto out_no_free;
+	}
+
+	pdata = client->dev.platform_data;
+	if (!pdata) {
+		dev_err(&client->adapter->dev,
+			"Missing platform data for slave %s\n", devid->name);
+		result = -EFAULT;
+		goto out_no_free;
+	}
+
+	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+	if (!ts) {
+		result = -ENOMEM;
+		goto out_no_free;
+	}
+	
+	i2c_set_clientdata(client, ts);
+	ts->client = client;	
+	ts->pdata = pdata;	
+	ts->i2c_id = (struct i2c_device_id *)devid;
+
+	mutex_init(&ts->data_mutex);	
+	mutex_init(&ts->ts_mutex);
+	mutex_init(&ts->i2c_mutex);
+	
+	result = ts_chip_init(ts->client);
+	if(result < 0)
+		goto out_free_memory;
+	
+	ts->client->addr = ts->ops->slave_addr;		
+	
+	ts->input_dev = input_allocate_device();
+	if (!ts->input_dev) {
+		result = -ENOMEM;
+		dev_err(&client->dev,
+			"Failed to allocate input device %s\n", ts->input_dev->name);
+		goto out_free_memory;
+	}	
+
+	ts->input_dev->dev.parent = &client->dev;
+	ts->input_dev->name = ts->ops->name;
+	
+	result = input_register_device(ts->input_dev);
+	if (result) {
+		dev_err(&client->dev,
+			"Unable to register input device %s\n", ts->input_dev->name);
+		goto out_input_register_device_failed;
+	}
+	
+	result = ts_irq_init(ts->client);
+	if (result) {
+		dev_err(&client->dev,
+			"fail to init ts irq,ret=%d\n",result);
+		goto out_input_register_device_failed;
+	}
+	
+	__set_bit(EV_ABS, ts->input_dev->evbit);
+	__set_bit(EV_KEY, ts->input_dev->evbit);
+	__set_bit(EV_REP,  ts->input_dev->evbit);
+	__set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+	set_bit(ABS_MT_POSITION_X, ts->input_dev->absbit);
+	set_bit(ABS_MT_POSITION_Y, ts->input_dev->absbit);
+	set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit);
+	set_bit(ABS_MT_WIDTH_MAJOR, ts->input_dev->absbit);
+
+	if(ts->ops->max_point <= 0)
+		ts->ops->max_point = 1;
+	
+	input_mt_init_slots(ts->input_dev, ts->ops->max_point);
+
+	if((ts->ops->pixel.max_x <= 0) || (ts->ops->pixel.max_y <= 0))
+	{
+		ts->ops->pixel.max_x = 1024;
+		ts->ops->pixel.max_y = 600;
+	}
+	
+	input_set_abs_params(ts->input_dev,ABS_MT_POSITION_X, 0, ts->ops->range[0], 0, 0);
+	input_set_abs_params(ts->input_dev,ABS_MT_POSITION_Y, 0, ts->ops->range[1], 0, 0);
+	input_set_abs_params(ts->input_dev,ABS_MT_TOUCH_MAJOR, 0, 10, 0, 0);
+	input_set_abs_params(ts->input_dev,ABS_MT_WIDTH_MAJOR, 0, 10, 0, 0);
+	
+	g_ts = ts;
+	
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	if((ts->ops->suspend) && (ts->ops->resume))
+	{
+		ts->early_suspend.suspend = ts_suspend;
+		ts->early_suspend.resume = ts_resume;
+		ts->early_suspend.level = 0x02;
+		register_early_suspend(&ts->early_suspend);
+	}
+#endif
+
+	printk("%s:initialized ok,ts name:%s,devid=%d\n\n",__func__,ts->ops->name,ts->devid);
+
+	return result;
+	
+out_misc_device_register_device_failed:
+	input_unregister_device(ts->input_dev);	
+out_input_register_device_failed:
+	input_free_device(ts->input_dev);	
+out_free_memory:	
+	kfree(ts);
+out_no_free:
+	dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result);
+	return result;
+
+}
+
+static void ts_shut_down(struct i2c_client *client)
+{
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct ts_private_data *ts =
+	    (struct ts_private_data *) i2c_get_clientdata(client);
+	if((ts->ops->suspend) && (ts->ops->resume))		
+		unregister_early_suspend(&ts->early_suspend);
+	DBG("%s:%s\n",__func__,ts->i2c_id->name);
+#endif
+}
+
+static int ts_remove(struct i2c_client *client)
+{
+	struct ts_private_data *ts =
+	    (struct ts_private_data *) i2c_get_clientdata(client);
+	int result = 0;
+	
+	cancel_delayed_work_sync(&ts->delaywork);
+	input_unregister_device(ts->input_dev);	
+	input_free_device(ts->input_dev);	
+	kfree(ts);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	if((ts->ops->suspend) && (ts->ops->resume))
+		unregister_early_suspend(&ts->early_suspend);
+#endif  
+	return result;
+}
+
+static const struct i2c_device_id ts_id_table[] = {
+	{"auto_ts", 0},
+	{},
+};
+
+
+static struct i2c_driver ts_driver = {
+	.probe = ts_probe,
+	.remove = ts_remove,
+	.shutdown = ts_shut_down,
+	.id_table = ts_id_table,
+	.driver = {
+		   .owner = THIS_MODULE,
+		   .name = "auto_ts",
+		   },
+};
+
+static int __init ts_init(void)
+{
+	int res = i2c_add_driver(&ts_driver);
+	pr_info("%s: Probe name %s\n", __func__, ts_driver.driver.name);
+	if (res)
+		pr_err("%s failed\n", __func__);
+	return res;
+}
+
+static void __exit ts_exit(void)
+{
+	pr_info("%s\n", __func__);
+	i2c_del_driver(&ts_driver);
+}
+
+subsys_initcall_sync(ts_init);
+module_exit(ts_exit);
+
+MODULE_AUTHOR("ROCKCHIP Corporation:lw@rock-chips.com");
+MODULE_DESCRIPTION("User space character device interface for tss");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/input/ts/ts-i2c.c b/drivers/input/ts/ts-i2c.c
new file mode 100755
index 000000000000..8c00ff7d7ea3
--- /dev/null
+++ b/drivers/input/ts/ts-i2c.c
@@ -0,0 +1,233 @@
+/* drivers/input/ts/ts-i2c.c - touchscreen i2c handle
+ *
+ * Copyright (C) 2012-2015 ROCKCHIP.
+ * Author: luowei <lw@rock-chips.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/miscdevice.h>
+#include <linux/gpio.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/freezer.h>
+#include <mach/gpio.h>
+#include <mach/board.h> 
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+#include <linux/ts-auto.h>
+
+#define TS_I2C_RATE 200*1000
+
+#if 0
+#define TS_DEBUG_ENABLE
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+static int ts_i2c_write(struct i2c_adapter *i2c_adap,
+			    unsigned char address,
+			    unsigned int len, unsigned char const *data)
+{
+	struct i2c_msg msgs[1];
+	int res;
+
+	if (!data || !i2c_adap) {
+		printk("%s:line=%d,error\n",__func__,__LINE__);
+		return -EINVAL;
+	}
+
+	msgs[0].addr = address;
+	msgs[0].flags = 0;	/* write */
+	msgs[0].buf = (unsigned char *)data;
+	msgs[0].len = len;
+	msgs[0].scl_rate = TS_I2C_RATE;
+
+	res = i2c_transfer(i2c_adap, msgs, 1);
+	if (res == 1)
+		return 0;
+	else if(res == 0)
+		return -EBUSY;
+	else
+		return res;
+
+}
+
+static int senosr_i2c_read(struct i2c_adapter *i2c_adap,
+			   unsigned char address, unsigned char reg,
+			   unsigned int len, unsigned char *data)
+{
+	struct i2c_msg msgs[2];
+	int res;
+
+	if (!data || !i2c_adap) {
+		printk("%s:line=%d,error\n",__func__,__LINE__);
+		return -EINVAL;
+	}
+
+	msgs[0].addr = address;
+	msgs[0].flags = 0;	/* write */
+	msgs[0].buf = &reg;
+	msgs[0].len = 1;
+	msgs[0].scl_rate = TS_I2C_RATE;
+	
+	msgs[1].addr = address;
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].buf = data;
+	msgs[1].len = len;
+	msgs[1].scl_rate = TS_I2C_RATE;	
+
+	res = i2c_transfer(i2c_adap, msgs, 2);
+	if (res == 2)
+		return 0;
+	else if(res == 0)
+		return -EBUSY;
+	else
+		return res;
+
+}
+
+
+int ts_rx_data(struct i2c_client *client, char *rxData, int length)
+{
+#ifdef TS_DEBUG_ENABLE
+	struct ts_private_data* ts = 
+		(struct ts_private_data *)i2c_get_clientdata(client);
+	int i = 0;
+#endif
+	int ret = 0;
+	char reg = rxData[0];
+	ret = senosr_i2c_read(client->adapter, client->addr, reg, length, rxData);
+	
+#ifdef TS_DEBUG_ENABLE
+	DBG("addr=0x%x,len=%d,rxdata:",reg,length);
+	for(i=0; i<length; i++)
+		DBG("0x%x,",rxData[i]);
+	DBG("\n");
+#endif	
+	return ret;
+}
+EXPORT_SYMBOL(ts_rx_data);
+
+int ts_tx_data(struct i2c_client *client, char *txData, int length)
+{
+#ifdef TS_DEBUG_ENABLE	
+	struct ts_private_data* ts = 
+		(struct ts_private_data *)i2c_get_clientdata(client);
+	int i = 0;
+#endif
+	int ret = 0;
+#ifdef TS_DEBUG_ENABLE	
+	DBG("addr=0x%x,len=%d,txdata:",txData[0],length);
+	for(i=1; i<length; i++)
+		DBG("0x%x,",txData[i]);
+	DBG("\n");
+#endif
+	ret = ts_i2c_write(client->adapter, client->addr, length, txData);
+	return ret;
+
+}
+EXPORT_SYMBOL(ts_tx_data);
+
+int ts_write_reg(struct i2c_client *client, int addr, int value)
+{
+	char buffer[2];
+	int ret = 0;
+	struct ts_private_data* ts = 
+		(struct ts_private_data *)i2c_get_clientdata(client);
+	
+	mutex_lock(&ts->i2c_mutex);	
+	buffer[0] = addr;
+	buffer[1] = value;
+	ret = ts_tx_data(client, &buffer[0], 2);	
+	mutex_unlock(&ts->i2c_mutex);	
+	return ret;
+}
+EXPORT_SYMBOL(ts_write_reg);
+
+int ts_read_reg(struct i2c_client *client, int addr)
+{
+	char tmp[1] = {0};
+	int ret = 0;	
+	struct ts_private_data* ts = 
+		(struct ts_private_data *)i2c_get_clientdata(client);
+	
+	mutex_lock(&ts->i2c_mutex);	
+	tmp[0] = addr;
+	ret = ts_rx_data(client, tmp, 1);
+	mutex_unlock(&ts->i2c_mutex);
+	
+	return tmp[0];
+}
+
+EXPORT_SYMBOL(ts_read_reg);
+
+
+int ts_tx_data_normal(struct i2c_client *client, char *buf, int num)
+{
+	int ret = 0;
+	ret = i2c_master_normal_send(client, buf, num, TS_I2C_RATE);
+	
+	return (ret == num) ? 0 : ret;
+}
+EXPORT_SYMBOL(ts_tx_data_normal);
+
+
+int ts_rx_data_normal(struct i2c_client *client, char *buf, int num)
+{
+	int ret = 0;
+	ret = i2c_master_normal_recv(client, buf, num, TS_I2C_RATE);
+	
+	return (ret == num) ? 0 : ret;
+}
+
+EXPORT_SYMBOL(ts_rx_data_normal);
+
+
+int ts_write_reg_normal(struct i2c_client *client, char value)
+{
+	char buffer[2];
+	int ret = 0;
+	struct ts_private_data* ts = 
+		(struct ts_private_data *)i2c_get_clientdata(client);
+	
+	mutex_lock(&ts->i2c_mutex);	
+	buffer[0] = value;
+	ret = ts_tx_data_normal(client, &buffer[0], 1);	
+	mutex_unlock(&ts->i2c_mutex);	
+	return ret;
+}
+EXPORT_SYMBOL(ts_write_reg_normal);
+
+int ts_read_reg_normal(struct i2c_client *client)
+{
+	char tmp[1] = {0};
+	int ret = 0;	
+	struct ts_private_data* ts = 
+		(struct ts_private_data *)i2c_get_clientdata(client);
+	
+	mutex_lock(&ts->i2c_mutex);	
+	ret = ts_rx_data_normal(client, tmp, 1);
+	mutex_unlock(&ts->i2c_mutex);
+	
+	return tmp[0];
+}
+
+EXPORT_SYMBOL(ts_read_reg_normal);
+
diff --git a/include/linux/ts-auto.h b/include/linux/ts-auto.h
new file mode 100644
index 000000000000..0db065805be7
--- /dev/null
+++ b/include/linux/ts-auto.h
@@ -0,0 +1,117 @@
+#ifndef __TS_AUTO_H
+#define __TS_AUTO_H
+#include <linux/miscdevice.h>
+
+#define TS_ENABLE	1
+#define	TS_DISABLE	0
+#define TS_UNKNOW_DATA	-1
+#define	TS_MAX_POINT	20
+
+enum ts_id {
+	TS_ID_INVALID = 0,
+		
+	TS_ID_FT5306,
+	TS_ID_CT360,
+	TS_ID_GT8110,
+	
+	TS_NUM_ID,
+};
+
+struct point_data {
+	int status;
+	int id;
+	int x;
+	int y;
+	int press;
+	int last_status;
+};
+
+struct ts_event {
+  int  touch_point;
+  struct point_data point[TS_MAX_POINT];
+};
+
+
+/* Platform data for the auto touchscreen */
+struct ts_platform_data {
+	unsigned char  slave_addr;
+	int irq;
+	int power_pin;
+	int reset_pin;
+	int irq_enable;         //if irq_enable=1 then use irq else use polling  
+	int poll_delay_ms;      //polling
+	int (*init_platform_hw)(void);	
+};
+
+struct ts_max_pixel{
+	int max_x;
+	int max_y;
+};
+
+struct ts_operate {
+	char *name;
+	char slave_addr;
+	int id_i2c;
+	struct ts_max_pixel pixel;	
+	int id_reg;
+	int id_data;
+	int read_reg;
+	int read_len;
+	int trig;	//intterupt trigger
+	int max_point;
+	int xy_swap;
+	int x_revert;
+	int y_revert;
+	int range[2];
+	int (*active)(struct i2c_client *client, int enable);	
+	int (*init)(struct i2c_client *client);	
+	int (*report)(struct i2c_client *client);
+	int (*firmware)(struct i2c_client *client);
+	int (*suspend)(struct i2c_client *client);
+	int (*resume)(struct i2c_client *client);	
+	struct miscdevice *misc_dev;
+
+};
+
+
+struct ts_private_data {
+	struct i2c_client *client;	
+	struct input_dev *input_dev;
+	struct ts_event	event;
+	struct work_struct work;
+	struct delayed_work delaywork;	/*report second event*/	
+	char ts_data[40];		//max support40 bytes data
+	struct mutex data_mutex;
+	struct mutex ts_mutex;
+	struct mutex i2c_mutex;
+	int devid;
+	struct i2c_device_id *i2c_id;
+	struct ts_platform_data *pdata;
+	struct ts_operate *ops; 
+	struct file_operations fops;
+	struct miscdevice miscdev;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct 	early_suspend early_suspend;
+#endif
+};
+
+
+extern int ts_register_slave(struct i2c_client *client,
+			struct ts_platform_data *slave_pdata,
+			struct ts_operate *(*get_ts_ops)(void));
+
+
+extern int ts_unregister_slave(struct i2c_client *client,
+			struct ts_platform_data *slave_pdata,
+			struct ts_operate *(*get_ts_ops)(void));
+
+extern int ts_rx_data(struct i2c_client *client, char *rxData, int length);
+extern int ts_tx_data(struct i2c_client *client, char *txData, int length);
+extern int ts_write_reg(struct i2c_client *client, int addr, int value);
+extern int ts_read_reg(struct i2c_client *client, int addr);
+extern int ts_tx_data_normal(struct i2c_client *client, char *buf, int num);
+extern int ts_rx_data_normal(struct i2c_client *client, char *buf, int num);
+extern int ts_write_reg_normal(struct i2c_client *client, char value);
+extern int ts_read_reg_normal(struct i2c_client *client);
+
+#endif
-- 
2.34.1