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