summaryrefslogtreecommitdiff
path: root/drivers/input/touchscreen/icn83xx_ts/icn83xx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/touchscreen/icn83xx_ts/icn83xx.c')
-rwxr-xr-xdrivers/input/touchscreen/icn83xx_ts/icn83xx.c2034
1 files changed, 2034 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/icn83xx_ts/icn83xx.c b/drivers/input/touchscreen/icn83xx_ts/icn83xx.c
new file mode 100755
index 00000000..60e42e50
--- /dev/null
+++ b/drivers/input/touchscreen/icn83xx_ts/icn83xx.c
@@ -0,0 +1,2034 @@
+/*++
+
+ Copyright (c) 2012-2022 ChipOne Technology (Beijing) Co., Ltd. All Rights Reserved.
+ This PROPRIETARY SOFTWARE is the property of ChipOne Technology (Beijing) Co., Ltd.
+ and may contains trade secrets and/or other confidential information of ChipOne
+ Technology (Beijing) Co., Ltd. This file shall not be disclosed to any third party,
+ in whole or in part, without prior written consent of ChipOne.
+ THIS PROPRIETARY SOFTWARE & ANY RELATED DOCUMENTATION ARE PROVIDED AS IS,
+ WITH ALL FAULTS, & WITHOUT WARRANTY OF ANY KIND. CHIPONE DISCLAIMS ALL EXPRESS OR
+ IMPLIED WARRANTIES.
+
+ File Name: icn83xx.c
+Abstract:
+input driver.
+Author: Zhimin Tian
+Date : 01,17,2013
+Version: 1.0
+History :
+2012,10,30, V0.1 first version
+--*/
+
+#include "icn83xx.h"
+
+#if COMPILE_FW_WITH_DRIVER
+#include "icn83xx_fw.h"
+#endif
+
+static struct touch_param g_param;
+static struct i2c_client *this_client;
+short log_rawdata[28][16];// = {0,};
+short log_diffdata[28][16];// = {0,};
+static int l_suspend = 0; // 1:suspend, 0:normal state
+
+#if SUPPORT_ROCKCHIP
+//if file system not ready,you can use inner array
+//static char firmware[128] = "icn83xx_firmware";
+#endif
+static char firmware[128] = {"/system/etc/firmware/fw.bin"};
+
+//static void icn_delayedwork_fun(struct work_struct *work);
+extern int register_bl_notifier(struct notifier_block *nb);
+extern int unregister_bl_notifier(struct notifier_block *nb);
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+
+#define dbg(fmt, args...) do{if (g_param.dbg) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__ , ## args);}while(0)
+
+static ssize_t cat_dbg(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "echo 1 > dbg : print debug message.\necho 0 > dbg : Do not print debug message.\n");
+}
+static ssize_t echo_dbg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ g_param.dbg = simple_strtoul(buf, NULL, 10) ? 1 : 0;
+ return count;
+}
+static DEVICE_ATTR(dbg, S_IRUGO | S_IWUSR, cat_dbg, echo_dbg);
+
+#if SUPPORT_SYSFS
+static enum hrtimer_restart chipone_timer_func(struct hrtimer *timer);
+static ssize_t icn83xx_show_update(struct device* cd,struct device_attribute *attr, char* buf);
+static ssize_t icn83xx_store_update(struct device* cd, struct device_attribute *attr, const char* buf, size_t len);
+static ssize_t icn83xx_show_process(struct device* cd,struct device_attribute *attr, char* buf);
+static ssize_t icn83xx_store_process(struct device* cd, struct device_attribute *attr,const char* buf, size_t len);
+
+static DEVICE_ATTR(update, S_IRUGO | S_IWUSR, icn83xx_show_update, icn83xx_store_update);
+static DEVICE_ATTR(process, S_IRUGO | S_IWUSR, icn83xx_show_process, icn83xx_store_process);
+
+static ssize_t icn83xx_show_process(struct device* cd,struct device_attribute *attr, char* buf)
+{
+ ssize_t ret = 0;
+ sprintf(buf, "icn83xx process\n");
+ ret = strlen(buf) + 1;
+ return ret;
+}
+
+static ssize_t icn83xx_store_process(struct device* cd, struct device_attribute *attr,
+ const char* buf, size_t len)
+{
+ struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
+ unsigned long on_off = simple_strtoul(buf, NULL, 10);
+ if(on_off == 0)
+ {
+ icn83xx_ts->work_mode = on_off;
+ }
+ else if((on_off == 1) || (on_off == 2))
+ {
+ if((icn83xx_ts->work_mode == 0) && (icn83xx_ts->use_irq == 1))
+ {
+ hrtimer_init(&icn83xx_ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ icn83xx_ts->timer.function = chipone_timer_func;
+ hrtimer_start(&icn83xx_ts->timer, ktime_set(CTP_START_TIMER/1000, (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL);
+ }
+ icn83xx_ts->work_mode = on_off;
+ }
+ return len;
+}
+
+static ssize_t icn83xx_show_update(struct device* cd,
+ struct device_attribute *attr, char* buf)
+{
+ ssize_t ret = 0;
+ sprintf(buf, "icn83xx firmware\n");
+ ret = strlen(buf) + 1;
+ return ret;
+}
+
+static ssize_t icn83xx_store_update(struct device* cd, struct device_attribute *attr, const char* buf, size_t len)
+{
+ //int err=0;
+ //unsigned long on_off = simple_strtoul(buf, NULL, 10);
+ return len;
+}
+
+static int icn83xx_create_sysfs(struct i2c_client *client)
+{
+ int err;
+ struct device *dev = &(client->dev);
+ icn83xx_trace("%s: \n",__func__);
+ err = device_create_file(dev, &dev_attr_update);
+ err = device_create_file(dev, &dev_attr_process);
+ return err;
+}
+
+#endif
+
+#if SUPPORT_PROC_FS
+
+pack_head cmd_head;
+static struct proc_dir_entry *icn83xx_proc_entry;
+int DATA_LENGTH = 0;
+static int icn83xx_tool_write(struct file *filp, const char __user *buff, unsigned long len, void *data)
+{
+ int ret = 0;
+
+ struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
+ proc_info("%s \n",__func__);
+ if(down_interruptible(&icn83xx_ts->sem))
+ {
+ return -1;
+ }
+ ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH);
+ if(ret)
+ {
+ proc_error("copy_from_user failed.\n");
+ goto write_out;
+ }
+ else
+ {
+ ret = CMD_HEAD_LENGTH;
+ }
+
+ proc_info("wr :0x%02x.\n", cmd_head.wr);
+ proc_info("flag:0x%02x.\n", cmd_head.flag);
+ proc_info("circle :%d.\n", (int)cmd_head.circle);
+ proc_info("times :%d.\n", (int)cmd_head.times);
+ proc_info("retry :%d.\n", (int)cmd_head.retry);
+ proc_info("data len:%d.\n", (int)cmd_head.data_len);
+ proc_info("addr len:%d.\n", (int)cmd_head.addr_len);
+ proc_info("addr:0x%02x%02x.\n", cmd_head.addr[0], cmd_head.addr[1]);
+ proc_info("len:%d.\n", (int)len);
+ proc_info("data:0x%02x%02x.\n", buff[CMD_HEAD_LENGTH], buff[CMD_HEAD_LENGTH+1]);
+ if (1 == cmd_head.wr) // write iic
+ {
+ if(1 == cmd_head.addr_len)
+ {
+ ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
+ if(ret)
+ {
+ proc_error("copy_from_user failed.\n");
+ goto write_out;
+ }
+ ret = icn83xx_i2c_txdata(cmd_head.addr[0], &cmd_head.data[0], cmd_head.data_len);
+ if (ret < 0) {
+ proc_error("write iic failed! ret: %d\n", ret);
+ goto write_out;
+ }
+ ret = cmd_head.data_len + CMD_HEAD_LENGTH;
+ goto write_out;
+ }
+ }
+ else if(3 == cmd_head.wr)
+ {
+ ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
+ if(ret)
+ {
+ proc_error("copy_from_user failed.\n");
+ goto write_out;
+ }
+ ret = cmd_head.data_len + CMD_HEAD_LENGTH;
+ memset(firmware, 0, 128);
+ memcpy(firmware, &cmd_head.data[0], cmd_head.data_len);
+ proc_info("firmware : %s\n", firmware);
+ }
+ else if(5 == cmd_head.wr)
+ {
+ icn83xx_update_status(1);
+ ret = kernel_thread((int (*)(void *))icn83xx_fw_update,firmware,CLONE_KERNEL);
+ icn83xx_trace("the kernel_thread result is:%d\n", ret);
+ }
+ else if(7 == cmd_head.wr) //write reg
+ {
+ if(2 == cmd_head.addr_len)
+ {
+ ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
+ if(ret)
+ {
+ proc_error("copy_from_user failed.\n");
+ goto write_out;
+ }
+ ret = icn83xx_writeReg((cmd_head.addr[0]<<8)|cmd_head.addr[1], cmd_head.data[0]);
+ if (ret < 0) {
+ proc_error("write reg failed! ret: %d\n", ret);
+ goto write_out;
+ }
+ ret = cmd_head.data_len + CMD_HEAD_LENGTH;
+ goto write_out;
+
+ }
+ }
+
+write_out:
+ up(&icn83xx_ts->sem);
+ return len;
+
+}
+static int icn83xx_tool_read( char *page, char **start, off_t off, int count, int *eof, void *data )
+{
+ int i;
+ int ret = 0;
+ int data_len = 0;
+ int len = 0;
+ int loc = 0;
+ char retvalue;
+ struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
+ if(down_interruptible(&icn83xx_ts->sem))
+ {
+ return -1;
+ }
+ proc_info("%s: count:%d, off:%d, cmd_head.data_len: %d\n",__func__, count, (int)off, cmd_head.data_len);
+ if (cmd_head.wr % 2)
+ {
+ ret = 0;
+ goto read_out;
+ }
+ else if (0 == cmd_head.wr) //read iic
+ {
+ if(1 == cmd_head.addr_len)
+ {
+ data_len = cmd_head.data_len;
+ if(cmd_head.addr[0] == 0xff)
+ {
+ page[0] = 83;
+ proc_info("read ic type: %d\n", page[0]);
+ }
+ else
+ {
+ while(data_len>0)
+ {
+ if (data_len > DATA_LENGTH)
+ {
+ len = DATA_LENGTH;
+ }
+ else
+ {
+ len = data_len;
+ }
+ data_len -= len;
+ memset(&cmd_head.data[0], 0, len+1);
+ ret = icn83xx_i2c_rxdata(cmd_head.addr[0]+loc, &cmd_head.data[0], len);
+ //proc_info("cmd_head.data[0]: 0x%02x\n", cmd_head.data[0]);
+ //proc_info("cmd_head.data[1]: 0x%02x\n", cmd_head.data[1]);
+ if(ret < 0)
+ {
+ icn83xx_error("read iic failed: %d\n", ret);
+ goto read_out;
+ }
+ else
+ {
+ //proc_info("iic read out %d bytes, loc: %d\n", len, loc);
+ memcpy(&page[loc], &cmd_head.data[0], len);
+ }
+ loc += len;
+ }
+ proc_info("page[0]: 0x%02x\n", page[0]);
+ proc_info("page[1]: 0x%02x\n", page[1]);
+ }
+ }
+ }
+ else if(2 == cmd_head.wr) //read rawdata
+ {
+ //scan tp rawdata
+ icn83xx_write_reg(4, 0x20);
+ mdelay(cmd_head.times);
+ icn83xx_read_reg(2, &retvalue);
+ while(retvalue != 1)
+ {
+ mdelay(cmd_head.times);
+ icn83xx_read_reg(2, &retvalue);
+ }
+
+ if(2 == cmd_head.addr_len)
+ {
+ for(i=0; i<cmd_head.addr[1]; i++)
+ {
+ icn83xx_write_reg(3, i);
+ mdelay(cmd_head.times);
+ ret = icn83xx_i2c_rxdata(128, &cmd_head.data[0], cmd_head.addr[0]*2);
+ if (ret < 0)
+ {
+ icn83xx_error("read rawdata failed: %d\n", ret);
+ goto read_out;
+ }
+ else
+ {
+ //proc_info("read rawdata out %d bytes, loc: %d\n", cmd_head.addr[0]*2, loc);
+ memcpy(&page[loc], &cmd_head.data[0], cmd_head.addr[0]*2);
+ }
+ loc += cmd_head.addr[0]*2;
+ }
+ for(i=0; i<cmd_head.data_len; i=i+2)
+ {
+ swap_ab(page[i], page[i+1]);
+ }
+ //icn83xx_rawdatadump(&page[0], cmd_head.data_len/2, cmd_head.addr[0]);
+ }
+
+ //finish scan tp rawdata
+ icn83xx_write_reg(2, 0x0);
+
+ }
+ else if(4 == cmd_head.wr) //get update status
+ {
+ page[0] = icn83xx_get_status();
+ }
+ else if(6 == cmd_head.wr) //read reg
+ {
+ if(2 == cmd_head.addr_len)
+ {
+ ret = icn83xx_readReg((cmd_head.addr[0]<<8)|cmd_head.addr[1], &cmd_head.data[0]);
+ if (ret < 0) {
+ proc_error("reg reg failed! ret: %d\n", ret);
+ goto read_out;
+ }
+ page[0] = cmd_head.data[0];
+ goto read_out;
+ }
+ }
+read_out:
+ up(&icn83xx_ts->sem);
+ proc_info("%s out: %d, cmd_head.data_len: %d\n\n",__func__, count, cmd_head.data_len);
+ return cmd_head.data_len;
+}
+
+int init_proc_node(void)
+{
+ int i;
+ memset(&cmd_head, 0, sizeof(cmd_head));
+ cmd_head.data = NULL;
+
+ i = 5;
+ while ((!cmd_head.data) && i)
+ {
+ cmd_head.data = kzalloc(i * DATA_LENGTH_UINT, GFP_KERNEL);
+ if (NULL != cmd_head.data)
+ {
+ break;
+ }
+ i--;
+ }
+ if (i)
+ {
+ //DATA_LENGTH = i * DATA_LENGTH_UINT + GTP_ADDR_LENGTH;
+ DATA_LENGTH = i * DATA_LENGTH_UINT;
+ icn83xx_trace("alloc memory size:%d.\n", DATA_LENGTH);
+ }
+ else
+ {
+ proc_error("alloc for memory failed.\n");
+ return 0;
+ }
+
+ icn83xx_proc_entry = create_proc_entry(ICN83XX_ENTRY_NAME, 0666, NULL);
+ if (icn83xx_proc_entry == NULL)
+ {
+ proc_error("Couldn't create proc entry!\n");
+ return 0;
+ }
+ else
+ {
+ icn83xx_trace("Create proc entry success!\n");
+ icn83xx_proc_entry->write_proc = icn83xx_tool_write;
+ icn83xx_proc_entry->read_proc = icn83xx_tool_read;
+ }
+
+ return 1;
+}
+
+void uninit_proc_node(void)
+{
+ kfree(cmd_head.data);
+ cmd_head.data = NULL;
+ remove_proc_entry(ICN83XX_ENTRY_NAME, NULL);
+}
+
+#endif
+
+
+#if TOUCH_VIRTUAL_KEYS
+static ssize_t virtual_keys_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ return sprintf(buf,
+ __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":100:1030:50:60"
+ ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":280:1030:50:60"
+ ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":470:1030:50:60"
+ ":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":900:1030:50:60"
+ "\n");
+}
+
+static struct kobj_attribute virtual_keys_attr = {
+ .attr = {
+ .name = "virtualkeys.chipone-ts",
+ .mode = S_IRUGO,
+ },
+ .show = &virtual_keys_show,
+};
+
+static struct attribute *properties_attrs[] = {
+ &virtual_keys_attr.attr,
+ NULL
+};
+
+static struct attribute_group properties_attr_group = {
+ .attrs = properties_attrs,
+};
+
+static void icn83xx_ts_virtual_keys_init(void)
+{
+ int ret = 0;
+ struct kobject *properties_kobj;
+ properties_kobj = kobject_create_and_add("board_properties", NULL);
+ if (properties_kobj)
+ ret = sysfs_create_group(properties_kobj,
+ &properties_attr_group);
+ if (!properties_kobj || ret)
+ pr_err("failed to create board_properties\n");
+}
+#endif
+
+
+/* ---------------------------------------------------------------------
+ *
+ * Chipone panel related driver
+ *
+ *
+ ----------------------------------------------------------------------*/
+/***********************************************************************************************
+Name : icn83xx_ts_wakeup
+Input : void
+Output : ret
+function : this function is used to wakeup tp
+ ***********************************************************************************************/
+void icn83xx_ts_wakeup(void)
+{
+ //#if def TOUCH_RESET_PIN
+
+}
+
+/***********************************************************************************************
+Name : icn83xx_ts_reset
+Input : void
+Output : ret
+function : this function is used to reset tp, you should not delete it
+ ***********************************************************************************************/
+void icn83xx_ts_reset(void)
+{
+ int rst = g_param.rstgpio;
+ gpio_direction_output(rst, 0);
+ //mdelay(30);
+ msleep(50);
+ gpio_direction_output(rst, 1);
+ //mdelay(50);
+ msleep(50);
+
+}
+
+/***********************************************************************************************
+Name : icn83xx_irq_disable
+Input : void
+Output : ret
+function : this function is used to disable irq
+ ***********************************************************************************************/
+void icn83xx_irq_disable(void)
+{
+ unsigned long irqflags;
+ struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
+
+ spin_lock_irqsave(&icn83xx_ts->irq_lock, irqflags);
+ if (!icn83xx_ts->irq_is_disable)
+ {
+ icn83xx_ts->irq_is_disable = 1;
+ wmt_gpio_mask_irq(g_param.irqgpio);
+ //disable_irq_nosync(icn83xx_ts->irq);
+ //disable_irq(icn83xx_ts->irq);
+ }
+ spin_unlock_irqrestore(&icn83xx_ts->irq_lock, irqflags);
+}
+
+/***********************************************************************************************
+Name : icn83xx_irq_enable
+Input : void
+Output : ret
+function : this function is used to enable irq
+ ***********************************************************************************************/
+void icn83xx_irq_enable(void)
+{
+ unsigned long irqflags = 0;
+ struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
+
+ spin_lock_irqsave(&icn83xx_ts->irq_lock, irqflags);
+ if (icn83xx_ts->irq_is_disable)
+ {
+ wmt_gpio_unmask_irq(g_param.irqgpio);
+ //enable_irq(icn83xx_ts->irq);
+ icn83xx_ts->irq_is_disable = 0;
+ }
+ spin_unlock_irqrestore(&icn83xx_ts->irq_lock, irqflags);
+
+}
+
+/***********************************************************************************************
+Name : icn83xx_prog_i2c_rxdata
+Input : addr
+ *rxdata
+ length
+Output : ret
+function : read data from icn83xx, prog mode
+ ***********************************************************************************************/
+int icn83xx_prog_i2c_rxdata(unsigned short addr, char *rxdata, int length)
+{
+ int ret = -1;
+ int retries = 0;
+#if 0
+ struct i2c_msg msgs[] = {
+ {
+ .addr = ICN83XX_PROG_IIC_ADDR,//this_client->addr,
+ .flags = I2C_M_RD,
+ .len = length,
+ .buf = rxdata,
+#if SUPPORT_ROCKCHIP
+ .scl_rate = ICN83XX_I2C_SCL,
+#endif
+ },
+ };
+
+ icn83xx_prog_i2c_txdata(addr, NULL, 0);
+ while(retries < IIC_RETRY_NUM)
+ {
+ ret = i2c_transfer(this_client->adapter, msgs, 1);
+ if(ret == 1)break;
+ retries++;
+ }
+ if (retries >= IIC_RETRY_NUM)
+ {
+ icn83xx_error("%s i2c read error: %d\n", __func__, ret);
+ // icn83xx_ts_reset();
+ }
+#else
+ unsigned char tmp_buf[2];
+ struct i2c_msg msgs[] = {
+ {
+ .addr = ICN83XX_PROG_IIC_ADDR,//this_client->addr,
+ .flags = 0,
+ .len = 2,
+ .buf = tmp_buf,
+#if SUPPORT_ROCKCHIP
+ .scl_rate = ICN83XX_I2C_SCL,
+#endif
+ },
+ {
+ .addr = ICN83XX_PROG_IIC_ADDR,//this_client->addr,
+ .flags = I2C_M_RD,
+ .len = length,
+ .buf = rxdata,
+#if SUPPORT_ROCKCHIP
+ .scl_rate = ICN83XX_I2C_SCL,
+#endif
+ },
+ };
+ tmp_buf[0] = U16HIBYTE(addr);
+ tmp_buf[1] = U16LOBYTE(addr);
+
+ while(retries < IIC_RETRY_NUM)
+ {
+ ret = i2c_transfer(this_client->adapter, msgs, 2);
+ if(ret == 2)break;
+ retries++;
+ }
+
+ if (retries >= IIC_RETRY_NUM)
+ {
+ icn83xx_error("%s i2c read error: %d\n", __func__, ret);
+ // icn83xx_ts_reset();
+ }
+#endif
+ return ret;
+}
+/***********************************************************************************************
+Name : icn83xx_prog_i2c_txdata
+Input : addr
+ *rxdata
+ length
+Output : ret
+function : send data to icn83xx , prog mode
+ ***********************************************************************************************/
+int icn83xx_prog_i2c_txdata(unsigned short addr, char *txdata, int length)
+{
+ int ret = -1;
+ char tmp_buf[128];
+ int retries = 0;
+ struct i2c_msg msg[] = {
+ {
+ .addr = ICN83XX_PROG_IIC_ADDR,//this_client->addr,
+ .flags = 0,
+ .len = length + 2,
+ .buf = tmp_buf,
+#if SUPPORT_ROCKCHIP
+ .scl_rate = ICN83XX_I2C_SCL,
+#endif
+ },
+ };
+
+ if (length > 125)
+ {
+ icn83xx_error("%s too big datalen = %d!\n", __func__, length);
+ return -1;
+ }
+
+ tmp_buf[0] = U16HIBYTE(addr);
+ tmp_buf[1] = U16LOBYTE(addr);
+
+ if (length != 0 && txdata != NULL)
+ {
+ memcpy(&tmp_buf[2], txdata, length);
+ }
+
+ while(retries < IIC_RETRY_NUM)
+ {
+ ret = i2c_transfer(this_client->adapter, msg, 1);
+ if(ret == 1)break;
+ retries++;
+ }
+
+ if (retries >= IIC_RETRY_NUM)
+ {
+ icn83xx_error("%s i2c write error: %d\n", __func__, ret);
+ // icn83xx_ts_reset();
+ }
+ return ret;
+}
+/***********************************************************************************************
+Name : icn83xx_prog_write_reg
+Input : addr -- address
+para -- parameter
+Output :
+function : write register of icn83xx, prog mode
+ ***********************************************************************************************/
+int icn83xx_prog_write_reg(unsigned short addr, char para)
+{
+ char buf[3];
+ int ret = -1;
+
+ buf[0] = para;
+ ret = icn83xx_prog_i2c_txdata(addr, buf, 1);
+ if (ret < 0) {
+ icn83xx_error("write reg failed! %#x ret: %d\n", buf[0], ret);
+ return -1;
+ }
+
+ return ret;
+}
+
+
+/***********************************************************************************************
+Name : icn83xx_prog_read_reg
+Input : addr
+pdata
+Output :
+function : read register of icn83xx, prog mode
+ ***********************************************************************************************/
+int icn83xx_prog_read_reg(unsigned short addr, char *pdata)
+{
+ int ret = -1;
+ ret = icn83xx_prog_i2c_rxdata(addr, pdata, 1);
+ return ret;
+}
+
+/***********************************************************************************************
+Name : icn83xx_i2c_rxdata
+Input : addr
+ *rxdata
+ length
+Output : ret
+function : read data from icn83xx, normal mode
+ ***********************************************************************************************/
+int icn83xx_i2c_rxdata(unsigned char addr, char *rxdata, int length)
+{
+ int ret = -1;
+ int retries = 0;
+#if 0
+ struct i2c_msg msgs[] = {
+ {
+ .addr = this_client->addr,
+ .flags = I2C_M_RD,
+ .len = length,
+ .buf = rxdata,
+#if SUPPORT_ROCKCHIP
+ .scl_rate = ICN83XX_I2C_SCL,
+#endif
+ },
+ };
+
+ icn83xx_i2c_txdata(addr, NULL, 0);
+ while(retries < IIC_RETRY_NUM)
+ {
+
+ ret = i2c_transfer(this_client->adapter, msgs, 1);
+ if(ret == 1)break;
+ retries++;
+ }
+
+ if (retries >= IIC_RETRY_NUM)
+ {
+ icn83xx_error("%s i2c read error: %d\n", __func__, ret);
+ // icn83xx_ts_reset();
+ }
+
+#else
+ unsigned char tmp_buf[1];
+ struct i2c_msg msgs[] = {
+ {
+ .addr = this_client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = tmp_buf,
+#if SUPPORT_ROCKCHIP
+ .scl_rate = ICN83XX_I2C_SCL,
+#endif
+ },
+ {
+ .addr = this_client->addr,
+ .flags = I2C_M_RD,
+ .len = length,
+ .buf = rxdata,
+#if SUPPORT_ROCKCHIP
+ .scl_rate = ICN83XX_I2C_SCL,
+#endif
+ },
+ };
+ tmp_buf[0] = addr;
+
+ while(retries < IIC_RETRY_NUM)
+ {
+ ret = i2c_transfer(this_client->adapter, msgs, 2);
+ if(ret == 2)break;
+ retries++;
+ }
+
+ if (retries >= IIC_RETRY_NUM)
+ {
+ icn83xx_error("%s i2c read error: %d\n", __func__, ret);
+ icn83xx_ts_reset();
+ }
+#endif
+
+ return ret;
+}
+/***********************************************************************************************
+Name : icn83xx_i2c_txdata
+Input : addr
+ *rxdata
+ length
+Output : ret
+function : send data to icn83xx , normal mode
+ ***********************************************************************************************/
+int icn83xx_i2c_txdata(unsigned char addr, char *txdata, int length)
+{
+ int ret = -1;
+ unsigned char tmp_buf[128];
+ int retries = 0;
+
+ struct i2c_msg msg[] = {
+ {
+ .addr = this_client->addr,
+ .flags = 0,
+ .len = length + 1,
+ .buf = tmp_buf,
+#if SUPPORT_ROCKCHIP
+ .scl_rate = ICN83XX_I2C_SCL,
+#endif
+ },
+ };
+
+ if (length > 125)
+ {
+ icn83xx_error("%s too big datalen = %d!\n", __func__, length);
+ return -1;
+ }
+
+ tmp_buf[0] = addr;
+
+ if (length != 0 && txdata != NULL)
+ {
+ memcpy(&tmp_buf[1], txdata, length);
+ }
+
+ while(retries < IIC_RETRY_NUM)
+ {
+ ret = i2c_transfer(this_client->adapter, msg, 1);
+ if(ret == 1)break;
+ retries++;
+ }
+
+ if (retries >= IIC_RETRY_NUM)
+ {
+ icn83xx_error("%s i2c write error: %d\n", __func__, ret);
+ icn83xx_ts_reset();
+ }
+
+ return ret;
+}
+
+/***********************************************************************************************
+Name : icn83xx_write_reg
+Input : addr -- address
+para -- parameter
+Output :
+function : write register of icn83xx, normal mode
+ ***********************************************************************************************/
+int icn83xx_write_reg(unsigned char addr, char para)
+{
+ char buf[3];
+ int ret = -1;
+
+ buf[0] = para;
+ ret = icn83xx_i2c_txdata(addr, buf, 1);
+ if (ret < 0) {
+ icn83xx_error("write reg failed! %#x ret: %d\n", buf[0], ret);
+ return -1;
+ }
+
+ return ret;
+}
+
+
+/***********************************************************************************************
+Name : icn83xx_read_reg
+Input : addr
+pdata
+Output :
+function : read register of icn83xx, normal mode
+ ***********************************************************************************************/
+int icn83xx_read_reg(unsigned char addr, char *pdata)
+{
+ int ret = -1;
+ ret = icn83xx_i2c_rxdata(addr, pdata, 1);
+ return ret;
+}
+
+#if SUPPORT_FW_UPDATE
+/***********************************************************************************************
+Name : icn83xx_log
+Input : 0: rawdata, 1: diff data
+Output : err type
+function : calibrate param
+ ***********************************************************************************************/
+void icn83xx_log(char diff)
+{
+ char row = 0;
+ char column = 0;
+ int i, j;
+ icn83xx_read_reg(160, &row);
+ icn83xx_read_reg(161, &column);
+
+ if(diff == 1)
+ {
+ icn83xx_readTP(row, column, (char *)&log_diffdata[0][0]);
+
+ for(i=0; i<row; i++)
+ {
+ for(j=0; j<column; j++)
+ {
+ log_diffdata[i][j] = log_diffdata[i][j] - log_rawdata[i][j];
+ }
+ }
+ icn83xx_rawdatadump(&log_diffdata[0][0], row*16, 16);
+ }
+ else
+ {
+ icn83xx_readTP(row, column, (char *)&log_rawdata[0][0]);
+ icn83xx_rawdatadump(&log_rawdata[0][0], row*16, 16);
+ }
+}
+#endif
+
+/***********************************************************************************************
+Name : icn83xx_iic_test
+Input : void
+Output :
+function : 0 success,
+ ***********************************************************************************************/
+static int icn83xx_iic_test(void)
+{
+ int ret = -1;
+ char value = 0;
+ int retry = 0;
+ while(retry++ < 3)
+ {
+ ret = icn83xx_read_reg(0, &value);
+ if(ret > 0)
+ {
+ return ret;
+ }
+ icn83xx_error("iic test error! %d\n", retry);
+ msleep(3);
+ }
+ return ret;
+}
+
+/***********************************************************************************************
+Name : icn83xx_report_value_B
+Input : void
+Output :
+function : reprot touch ponit
+ ***********************************************************************************************/
+#if CTP_REPORT_PROTOCOL
+static int icn83xx_report_value_B(void)
+{
+ struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
+ char buf[POINT_NUM*POINT_SIZE+3]={0};
+ static unsigned char finger_last[POINT_NUM + 1]={0};
+ unsigned char finger_current[POINT_NUM + 1] = {0};
+ unsigned int position = 0;
+ int temp = 0;
+ int ret = -1;
+ int x,y;
+ icn83xx_info("==icn83xx_report_value_B ==\n");
+ // icn83xx_trace("==icn83xx_report_value_B ==\n");
+ ret = icn83xx_i2c_rxdata(16, buf, POINT_NUM*POINT_SIZE+2);
+ if (ret < 0) {
+ icn83xx_error("%s read_data i2c_rxdata failed: %d\n", __func__, ret);
+ return ret;
+ }
+
+ icn83xx_ts->point_num = buf[1];
+ if (icn83xx_ts->point_num > 5) {
+ printk("error point_num : %d\n",icn83xx_ts->point_num);
+ return -1;
+ }
+ if(icn83xx_ts->point_num > 0)
+ {
+ for(position = 0; position<icn83xx_ts->point_num; position++)
+ {
+ temp = buf[2 + POINT_SIZE*position] + 1;
+ finger_current[temp] = 1;
+ icn83xx_ts->point_info[temp].u8ID = buf[2 + POINT_SIZE*position];
+ icn83xx_ts->point_info[temp].u16PosX = (buf[3 + POINT_SIZE*position]<<8) + buf[4 + POINT_SIZE*position];
+ icn83xx_ts->point_info[temp].u16PosY = (buf[5 + POINT_SIZE*position]<<8) + buf[6 + POINT_SIZE*position];
+ icn83xx_ts->point_info[temp].u8Pressure = buf[7 + POINT_SIZE*position];
+ icn83xx_ts->point_info[temp].u8EventId = buf[8 + POINT_SIZE*position];
+
+ if(icn83xx_ts->point_info[temp].u8EventId == 4)
+ finger_current[temp] = 0;
+
+ if(1 == icn83xx_ts->revert_x_flag)
+ {
+ icn83xx_ts->point_info[temp].u16PosX = icn83xx_ts->screen_max_x- icn83xx_ts->point_info[temp].u16PosX;
+ }
+ if(1 == icn83xx_ts->revert_y_flag)
+ {
+ icn83xx_ts->point_info[temp].u16PosY = icn83xx_ts->screen_max_y- icn83xx_ts->point_info[temp].u16PosY;
+ }
+ icn83xx_info("temp %d\n", temp);
+ icn83xx_info("u8ID %d\n", icn83xx_ts->point_info[temp].u8ID);
+ icn83xx_info("u16PosX %d\n", icn83xx_ts->point_info[temp].u16PosX);
+ icn83xx_info("u16PosY %d\n", icn83xx_ts->point_info[temp].u16PosY);
+ icn83xx_info("u8Pressure %d\n", icn83xx_ts->point_info[temp].u8Pressure);
+ icn83xx_info("u8EventId %d\n", icn83xx_ts->point_info[temp].u8EventId);
+ //icn83xx_info("u8Pressure %d\n", icn83xx_ts->point_info[temp].u8Pressure*16);
+ }
+ }
+ else
+ {
+ for(position = 1; position < POINT_NUM+1; position++)
+ {
+ finger_current[position] = 0;
+ }
+ icn83xx_info("no touch\n");
+ }
+
+ for(position = 1; position < POINT_NUM + 1; position++)
+ {
+ if((finger_current[position] == 0) && (finger_last[position] != 0))
+ {
+ input_mt_slot(icn83xx_ts->input_dev, position-1);
+ input_mt_report_slot_state(icn83xx_ts->input_dev, MT_TOOL_FINGER, false);
+ icn83xx_point_info("one touch up: %d\n", position);
+ }
+ else if(finger_current[position])
+ {
+ if (g_param.xyswap == 0)
+ {
+ x = icn83xx_ts->point_info[position].u16PosX;
+ y = icn83xx_ts->point_info[position].u16PosY;
+ } else {
+ y = icn83xx_ts->point_info[position].u16PosX;
+ x = icn83xx_ts->point_info[position].u16PosY;
+ }
+ if (g_param.xdir == -1)
+ {
+ x = g_param.panelres_x - x;
+ }
+ if (g_param.ydir == -1)
+ {
+ y = g_param.panelres_y - y;
+ }
+
+ if (g_param.lcd_exchg) {
+ int tmp;
+ tmp = x;
+ x = y;
+ y = g_param.panelres_x - tmp;
+ }
+
+ input_mt_slot(icn83xx_ts->input_dev, position-1);
+ input_mt_report_slot_state(icn83xx_ts->input_dev, MT_TOOL_FINGER, true);
+ input_report_abs(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 1);
+ //input_report_abs(icn83xx_ts->input_dev, ABS_MT_PRESSURE, icn83xx_ts->point_info[position].u8Pressure);
+ input_report_abs(icn83xx_ts->input_dev, ABS_MT_PRESSURE, 200);
+ input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_X, x);
+ input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, y);
+ icn83xx_point_info("===position: %d, x = %d,y = %d, press = %d ====\n", position, icn83xx_ts->point_info[position].u16PosX,icn83xx_ts->point_info[position].u16PosY, icn83xx_ts->point_info[position].u8Pressure);
+ // icn83xx_trace("===position: %d, x = %d,y = %d, press = %d ====\n", position, icn83xx_ts->point_info[position].u16PosX,icn83xx_ts->point_info[position].u16PosY, icn83xx_ts->point_info[position].u8Pressure);
+ dbg("raw%d(%d,%d), rpt%d(%d,%d)\n", position, icn83xx_ts->point_info[position].u16PosX, icn83xx_ts->point_info[position].u16PosY, position, x, y);
+ }
+
+ }
+ input_sync(icn83xx_ts->input_dev);
+
+ for(position = 1; position < POINT_NUM + 1; position++)
+ {
+ finger_last[position] = finger_current[position];
+ }
+ return 0;
+}
+
+#else
+
+/***********************************************************************************************
+Name : icn83xx_ts_release
+Input : void
+Output :
+function : touch release
+ ***********************************************************************************************/
+static void icn83xx_ts_release(void)
+{
+ struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
+ icn83xx_info("==icn83xx_ts_release ==\n");
+ input_report_abs(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
+ input_sync(icn83xx_ts->input_dev);
+}
+
+/***********************************************************************************************
+Name : icn83xx_report_value_A
+Input : void
+Output :
+function : reprot touch ponit
+ ***********************************************************************************************/
+static int icn83xx_report_value_A(void)
+{
+ struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
+ char buf[POINT_NUM*POINT_SIZE+3]={0};
+ int ret = -1;
+ int i;
+#if TOUCH_VIRTUAL_KEYS
+ unsigned char button;
+ static unsigned char button_last;
+#endif
+ icn83xx_info("==icn83xx_report_value_A ==\n");
+
+ ret = icn83xx_i2c_rxdata(16, buf, POINT_NUM*POINT_SIZE+2);
+ if (ret < 0) {
+ icn83xx_error("%s read_data i2c_rxdata failed: %d\n", __func__, ret);
+ return ret;
+ }
+#if TOUCH_VIRTUAL_KEYS
+ button = buf[0];
+ icn83xx_info("%s: button=%d\n",__func__, button);
+
+ if((button_last != 0) && (button == 0))
+ {
+ icn83xx_ts_release();
+ button_last = button;
+ return 1;
+ }
+ if(button != 0)
+ {
+ switch(button)
+ {
+ case ICN_VIRTUAL_BUTTON_HOME:
+ icn83xx_info("ICN_VIRTUAL_BUTTON_HOME down\n");
+ input_report_abs(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 200);
+ input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_X, 280);
+ input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, 1030);
+ input_report_abs(icn83xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1);
+ input_mt_sync(icn83xx_ts->input_dev);
+ input_sync(icn83xx_ts->input_dev);
+ break;
+ case ICN_VIRTUAL_BUTTON_BACK:
+ icn83xx_info("ICN_VIRTUAL_BUTTON_BACK down\n");
+ input_report_abs(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 200);
+ input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_X, 470);
+ input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, 1030);
+ input_report_abs(icn83xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1);
+ input_mt_sync(icn83xx_ts->input_dev);
+ input_sync(icn83xx_ts->input_dev);
+ break;
+ case ICN_VIRTUAL_BUTTON_MENU:
+ icn83xx_info("ICN_VIRTUAL_BUTTON_MENU down\n");
+ input_report_abs(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 200);
+ input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_X, 100);
+ input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, 1030);
+ input_report_abs(icn83xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1);
+ input_mt_sync(icn83xx_ts->input_dev);
+ input_sync(icn83xx_ts->input_dev);
+ break;
+ default:
+ icn83xx_info("other gesture\n");
+ break;
+ }
+ button_last = button;
+ return 1;
+ }
+#endif
+
+ icn83xx_ts->point_num = buf[1];
+ if (icn83xx_ts->point_num == 0) {
+ icn83xx_ts_release();
+ return 1;
+ }
+ for(i=0;i<icn83xx_ts->point_num;i++){
+ if(buf[8 + POINT_SIZE*i] != 4) break ;
+ }
+
+ if(i == icn83xx_ts->point_num) {
+ icn83xx_ts_release();
+ return 1;
+ }
+
+ for(i=0; i<icn83xx_ts->point_num; i++)
+ {
+ icn83xx_ts->point_info[i].u8ID = buf[2 + POINT_SIZE*i];
+ icn83xx_ts->point_info[i].u16PosX = (buf[3 + POINT_SIZE*i]<<8) + buf[4 + POINT_SIZE*i];
+ icn83xx_ts->point_info[i].u16PosY = (buf[5 + POINT_SIZE*i]<<8) + buf[6 + POINT_SIZE*i];
+ icn83xx_ts->point_info[i].u8Pressure = 200;//buf[7 + POINT_SIZE*i];
+ icn83xx_ts->point_info[i].u8EventId = buf[8 + POINT_SIZE*i];
+
+ if(1 == icn83xx_ts->revert_x_flag)
+ {
+ icn83xx_ts->point_info[i].u16PosX = icn83xx_ts->screen_max_x- icn83xx_ts->point_info[i].u16PosX;
+ }
+ if(1 == icn83xx_ts->revert_y_flag)
+ {
+ icn83xx_ts->point_info[i].u16PosY = icn83xx_ts->screen_max_y- icn83xx_ts->point_info[i].u16PosY;
+ }
+
+ icn83xx_info("u8ID %d\n", icn83xx_ts->point_info[i].u8ID);
+ icn83xx_info("u16PosX %d\n", icn83xx_ts->point_info[i].u16PosX);
+ icn83xx_info("u16PosY %d\n", icn83xx_ts->point_info[i].u16PosY);
+ icn83xx_info("u8Pressure %d\n", icn83xx_ts->point_info[i].u8Pressure);
+ icn83xx_info("u8EventId %d\n", icn83xx_ts->point_info[i].u8EventId);
+
+
+ input_report_abs(icn83xx_ts->input_dev, ABS_MT_TRACKING_ID, icn83xx_ts->point_info[i].u8ID);
+ input_report_abs(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, icn83xx_ts->point_info[i].u8Pressure);
+ input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_X, icn83xx_ts->point_info[i].u16PosX);
+ input_report_abs(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, icn83xx_ts->point_info[i].u16PosY);
+ input_report_abs(icn83xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 1);
+ input_mt_sync(icn83xx_ts->input_dev);
+ icn83xx_point_info("point: %d ===x = %d,y = %d, press = %d ====\n",i, icn83xx_ts->point_info[i].u16PosX,icn83xx_ts->point_info[i].u16PosY, icn83xx_ts->point_info[i].u8Pressure);
+ }
+
+ input_sync(icn83xx_ts->input_dev);
+ return 0;
+}
+#endif
+
+/***********************************************************************************************
+Name : icn83xx_ts_pen_irq_work
+Input : void
+Output :
+function : work_struct
+ ***********************************************************************************************/
+static void icn83xx_ts_pen_irq_work(struct work_struct *work)
+{
+ struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
+#if SUPPORT_PROC_FS
+ if(down_interruptible(&icn83xx_ts->sem))
+ {
+ return;
+ }
+#endif
+
+ if(icn83xx_ts->work_mode == 0)
+ {
+#if CTP_REPORT_PROTOCOL
+ icn83xx_report_value_B();
+#else
+ icn83xx_report_value_A();
+#endif
+
+ }
+#if SUPPORT_FW_UPDATE
+ else if(icn83xx_ts->work_mode == 1)
+ {
+ printk("log raw data\n");
+ icn83xx_log(0); //raw data
+ }
+ else if(icn83xx_ts->work_mode == 2)
+ {
+ printk("log diff data\n");
+ icn83xx_log(1); //diff data
+ }
+#endif
+
+#if SUPPORT_PROC_FS
+ up(&icn83xx_ts->sem);
+#endif
+ wmt_gpio_unmask_irq(g_param.irqgpio);
+
+}
+/***********************************************************************************************
+Name : chipone_timer_func
+Input : void
+Output :
+function : Timer interrupt service routine.
+ ***********************************************************************************************/
+static enum hrtimer_restart chipone_timer_func(struct hrtimer *timer)
+{
+ struct icn83xx_ts_data *icn83xx_ts = container_of(timer, struct icn83xx_ts_data, timer);
+ queue_work(icn83xx_ts->ts_workqueue, &icn83xx_ts->pen_event_work);
+
+ if(icn83xx_ts->use_irq == 1)
+ {
+ if((icn83xx_ts->work_mode == 1) || (icn83xx_ts->work_mode == 2))
+ {
+ hrtimer_start(&icn83xx_ts->timer, ktime_set(CTP_POLL_TIMER/1000, (CTP_POLL_TIMER%1000)*1000000), HRTIMER_MODE_REL);
+ }
+ }
+ else
+ {
+ hrtimer_start(&icn83xx_ts->timer, ktime_set(CTP_POLL_TIMER/1000, (CTP_POLL_TIMER%1000)*1000000), HRTIMER_MODE_REL);
+ }
+ return HRTIMER_NORESTART;
+}
+/***********************************************************************************************
+Name : icn83xx_ts_interrupt
+Input : void
+Output :
+function : interrupt service routine
+ ***********************************************************************************************/
+static irqreturn_t icn83xx_ts_interrupt(int irq, void *dev_id)
+{
+ struct icn83xx_ts_data *icn83xx_ts = dev_id;
+ int irqindex = g_param.irqgpio;
+
+ icn83xx_info("==========------icn83xx_ts TS Interrupt-----============\n");
+ if (gpio_irqstatus(irqindex)) {
+ wmt_gpio_ack_irq(irqindex);
+ if (is_gpio_irqenable(irqindex) && l_suspend == 0) {
+ wmt_gpio_mask_irq(irqindex);
+ if(icn83xx_ts->work_mode != 0) {
+ wmt_gpio_unmask_irq(irqindex);
+ return IRQ_HANDLED;
+ }
+ //icn83xx_irq_disable();
+ if (!work_pending(&icn83xx_ts->pen_event_work)) {
+ //icn83xx_info("Enter work\n");
+ queue_work(icn83xx_ts->ts_workqueue, &icn83xx_ts->pen_event_work);
+ }
+ }
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
+}
+
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+/***********************************************************************************************
+Name : icn83xx_ts_suspend
+Input : void
+Output :
+function : tp enter sleep mode
+ ***********************************************************************************************/
+static void icn83xx_ts_early_suspend(struct early_suspend *handler)
+{
+ int retry = 0;
+ struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
+ icn83xx_trace("icn83xx_ts_suspend: write ICN83XX_REG_PMODE .\n");
+ if (icn83xx_ts->use_irq)
+ {
+ icn83xx_irq_disable();
+ icn83xx_trace("icn83xx_ts_suspend:disable irq .\n");
+ }
+ else
+ {
+ hrtimer_cancel(&icn83xx_ts->timer);
+ }
+ for(retry = 0;retry <3; retry++ )
+ {
+ icn83xx_write_reg(ICN83XX_REG_PMODE, PMODE_HIBERNATE);
+ }
+}
+
+/***********************************************************************************************
+Name : icn83xx_ts_resume
+Input : void
+Output :
+function : wakeup tp or reset tp
+ ***********************************************************************************************/
+static void icn83xx_ts_late_resume(struct early_suspend *handler)
+{
+ struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
+ int i;
+ printk("==icn83xx_ts_resume== \n");
+ // icn83xx_ts_reset();
+ //report touch release
+#if CTP_REPORT_PROTOCOL
+ for(i = 0; i < POINT_NUM; i++)
+ {
+ input_mt_slot(icn83xx_ts->input_dev, i);
+ input_mt_report_slot_state(icn83xx_ts->input_dev, MT_TOOL_FINGER, false);
+ }
+#else
+ icn83xx_ts_release();
+#endif
+ icn83xx_ts_wakeup();
+ icn83xx_ts_reset();
+ if (icn83xx_ts->use_irq)
+ {
+ printk("icn83xx_irq_enable\n");
+ icn83xx_irq_enable();
+ }
+ else
+ { printk("icn83xx_ts_resume hrtimer_start\n");
+ hrtimer_start(&icn83xx_ts->timer, ktime_set(CTP_START_TIMER/1000, (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL);
+ }
+
+}
+#endif
+
+#ifdef CONFIG_PM
+/***********************************************************************************************
+Name : icn83xx_ts_suspend
+Input : void
+Output :
+function : tp enter sleep mode
+ ***********************************************************************************************/
+static int icn83xx_ts_suspend(struct device *pdev)
+{
+ //int retry = 0;
+ struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
+ icn83xx_trace("icn83xx_ts_suspend: write ICN83XX_REG_PMODE .\n");
+ if (icn83xx_ts->use_irq)
+ {
+ icn83xx_irq_disable();
+ icn83xx_trace("icn83xx_ts_suspend:disable irq .\n");
+ }
+ else
+ {
+ hrtimer_cancel(&icn83xx_ts->timer);
+ }
+ /*for(retry = 0;retry <3; retry++ )
+ {
+ icn83xx_write_reg(ICN83XX_REG_PMODE, PMODE_HIBERNATE);
+ } */
+ l_suspend = 1;
+ return 0;
+}
+
+/***********************************************************************************************
+Name : icn83xx_ts_resume
+Input : void
+Output :
+function : wakeup tp or reset tp
+ ***********************************************************************************************/
+static int icn83xx_ts_resume(struct device *pdev)
+{
+ struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(this_client);
+ int i;
+ printk("==icn83xx_ts_resume== \n");
+ // icn83xx_ts_reset();
+ //report touch release
+#if CTP_REPORT_PROTOCOL
+ for(i = 0; i < POINT_NUM; i++)
+ {
+ input_mt_slot(icn83xx_ts->input_dev, i);
+ input_mt_report_slot_state(icn83xx_ts->input_dev, MT_TOOL_FINGER, false);
+ }
+#else
+ icn83xx_ts_release();
+#endif
+ //icn83xx_ts_wakeup();
+ icn83xx_ts_reset();
+ l_suspend = 0;
+ if (icn83xx_ts->use_irq)
+ {
+ printk("icn83xx_irq_enable\n");
+ icn83xx_irq_enable();
+ }
+ else
+ { printk("icn83xx_ts_resume hrtimer_start\n");
+ hrtimer_start(&icn83xx_ts->timer, ktime_set(CTP_START_TIMER/1000, (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL);
+ }
+ return 0;
+}
+#else
+#define icn83xx_ts_suspend NULL
+#define icn83xx_ts_resume NULL
+#endif
+
+/***********************************************************************************************
+Name : icn83xx_request_io_port
+Input : void
+Output :
+function : 0 success,
+ ***********************************************************************************************/
+static int icn83xx_request_io_port(struct icn83xx_ts_data *icn83xx_ts)
+{
+#if SUPPORT_ROCKCHIP
+ icn83xx_ts->screen_max_x = SCREEN_MAX_X;
+ icn83xx_ts->screen_max_y = SCREEN_MAX_Y;
+ icn83xx_ts->irq = CTP_IRQ_PORT;
+#endif
+ icn83xx_ts->irq = IRQ_GPIO;
+
+ if (gpio_request(g_param.rstgpio, "ts_rst") < 0) {
+ printk("gpio(%d) touchscreen reset request fail\n", g_param.rstgpio);
+ return -EIO;
+ }
+ gpio_direction_output(g_param.rstgpio, 1);
+
+ if (gpio_request(g_param.irqgpio, "ts_irq") < 0) {
+ printk("gpio(%d) touchscreen interrupt request fail\n", g_param.irqgpio);
+ gpio_free(g_param.rstgpio);
+ return -EIO;
+ }
+ wmt_gpio_setpull(g_param.irqgpio, WMT_GPIO_PULL_UP);
+ gpio_direction_input(g_param.irqgpio);
+
+ return 0;
+}
+
+/***********************************************************************************************
+Name : icn83xx_free_io_port
+Input : void
+Output :
+function : 0 success,
+ ***********************************************************************************************/
+static void icn83xx_free_io_port(void)
+{
+ gpio_free(g_param.rstgpio);
+ gpio_free(g_param.irqgpio);
+}
+
+/***********************************************************************************************
+Name : icn83xx_request_irq
+Input : void
+Output :
+function : 0 success,
+ ***********************************************************************************************/
+static int icn83xx_request_irq(struct icn83xx_ts_data *icn83xx_ts)
+{
+ int err = -1;
+
+ /*err = gpio_request(icn83xx_ts->irq, "TS_INT"); //Request IO
+ if (err < 0)
+ {
+ icn83xx_error("Failed to request GPIO:%d, ERRNO:%d\n", (int)icn83xx_ts->irq, err);
+ return err;
+ }
+ gpio_direction_input(icn83xx_ts->irq);*/
+
+ wmt_gpio_set_irq_type(g_param.irqgpio, IRQ_TYPE_EDGE_FALLING);
+ err = request_irq(icn83xx_ts->irq, icn83xx_ts_interrupt, IRQF_SHARED, "icn83xx_ts", icn83xx_ts);
+ if (err < 0)
+ {
+ icn83xx_error("icn83xx_ts_probe: request irq failed\n");
+ return err;
+ }
+ else
+ {
+ icn83xx_irq_disable();
+ icn83xx_ts->use_irq = 1;
+ }
+
+ return 0;
+}
+
+
+/***********************************************************************************************
+Name : icn83xx_free_irq
+Input : void
+Output :
+function : 0 success,
+ ***********************************************************************************************/
+static void icn83xx_free_irq(struct icn83xx_ts_data *icn83xx_ts)
+{
+ if (icn83xx_ts)
+ {
+ if (icn83xx_ts->use_irq)
+ {
+ free_irq(icn83xx_ts->irq, icn83xx_ts);
+ }
+ else
+ {
+ hrtimer_cancel(&icn83xx_ts->timer);
+ }
+ }
+}
+
+/***********************************************************************************************
+Name : icn83xx_request_input_dev
+Input : void
+Output :
+function : 0 success,
+ ***********************************************************************************************/
+static int icn83xx_request_input_dev(struct icn83xx_ts_data *icn83xx_ts)
+{
+ int ret = -1;
+ struct input_dev *input_dev;
+
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ icn83xx_error("failed to allocate input device\n");
+ return -ENOMEM;
+ }
+ icn83xx_ts->input_dev = input_dev;
+
+ icn83xx_ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ;
+#if CTP_REPORT_PROTOCOL
+ __set_bit(INPUT_PROP_DIRECT, icn83xx_ts->input_dev->propbit);
+ input_mt_init_slots(icn83xx_ts->input_dev, 255);
+#else
+ set_bit(ABS_MT_TOUCH_MAJOR, icn83xx_ts->input_dev->absbit);
+ set_bit(ABS_MT_POSITION_X, icn83xx_ts->input_dev->absbit);
+ set_bit(ABS_MT_POSITION_Y, icn83xx_ts->input_dev->absbit);
+ set_bit(ABS_MT_WIDTH_MAJOR, icn83xx_ts->input_dev->absbit);
+#endif
+ if (g_param.lcd_exchg) {
+ input_set_abs_params(icn83xx_ts->input_dev, ABS_MT_POSITION_X, 0, g_param.panelres_y, 0, 0);
+ input_set_abs_params(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, 0, g_param.panelres_x, 0, 0);
+ } else {
+ input_set_abs_params(icn83xx_ts->input_dev, ABS_MT_POSITION_X, 0, g_param.panelres_x, 0, 0);
+ input_set_abs_params(icn83xx_ts->input_dev, ABS_MT_POSITION_Y, 0, g_param.panelres_y, 0, 0);
+ }
+ input_set_abs_params(icn83xx_ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
+ input_set_abs_params(icn83xx_ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+ input_set_abs_params(icn83xx_ts->input_dev, ABS_MT_TRACKING_ID, 0, 255, 0, 0);
+
+ __set_bit(KEY_MENU, input_dev->keybit);
+ __set_bit(KEY_BACK, input_dev->keybit);
+ __set_bit(KEY_HOME, input_dev->keybit);
+ __set_bit(KEY_SEARCH, input_dev->keybit);
+
+ input_dev->name = CTP_NAME;
+ ret = input_register_device(input_dev);
+ if (ret) {
+ icn83xx_error("Register %s input device failed\n", input_dev->name);
+ input_free_device(input_dev);
+ return -ENODEV;
+ }
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ icn83xx_trace("==register_early_suspend =\n");
+ icn83xx_ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+ icn83xx_ts->early_suspend.suspend = icn83xx_ts_early_suspend;
+ icn83xx_ts->early_suspend.resume = icn83xx_ts_late_resume;
+ register_early_suspend(&icn83xx_ts->early_suspend);
+#endif
+
+ return 0;
+}
+
+#if SUPPORT_DELAYED_WORK
+static void icn_delayedwork_fun(struct work_struct *work)
+{
+ int retry;
+ short fwVersion = 0;
+ short curVersion = 0;
+ icn83xx_trace("====%s begin1111=====. \n", __func__);
+
+#if SUPPORT_FW_UPDATE
+ fwVersion = icn83xx_read_fw_Ver(firmware);
+ curVersion = icn83xx_readVersion();
+ icn83xx_trace("fwVersion : 0x%x\n", fwVersion);
+ icn83xx_trace("current version: 0x%x\n", curVersion);
+
+
+#if FORCE_UPDATA_FW
+ retry = 5;
+ while(retry > 0)
+ {
+ if(R_OK == icn83xx_fw_update(firmware))
+ {
+ break;
+ }
+ retry--;
+ icn83xx_error("icn83xx_fw_update failed.\n");
+ }
+#else
+ if(fwVersion > curVersion)
+ {
+ retry = 5;
+ while(retry > 0)
+ {
+ if(R_OK == icn83xx_fw_update(firmware))
+ {
+ break;
+ }
+ retry--;
+ icn83xx_error("icn83xx_fw_update failed.\n");
+ }
+ }
+#endif
+
+#endif
+
+
+ icn83xx_irq_enable();
+ icn83xx_trace("====%s over1111=====. \n", __func__);
+}
+#endif
+
+
+char FbCap[4][16]={
+ {0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14},
+ {0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12},
+ {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10},
+ {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08},
+};
+
+static int wmt_wakeup_bl_notify(struct notifier_block *nb, unsigned long event,
+ void *dummy)
+{
+ //printk("get notify\n");
+ switch (event) {
+ case BL_CLOSE:
+ l_suspend = 1;
+ //printk("\nclose backlight\n\n");
+ //printk("disable irq\n\n");
+ wmt_gpio_mask_irq(g_param.irqgpio);
+ break;
+ case BL_OPEN:
+ l_suspend = 0;
+ //printk("\nopen backlight\n\n");
+ //printk("enable irq\n\n");
+ wmt_gpio_unmask_irq(g_param.irqgpio);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block wmt_bl_notify = {
+ .notifier_call = wmt_wakeup_bl_notify,
+};
+
+static int icn83xx_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct icn83xx_ts_data *icn83xx_ts;
+ short fwVersion = 0;
+ short curVersion = 0;
+ //int average;
+ int err = 0;
+ //char value;
+ int retry;
+
+ icn83xx_trace("====%s begin=====. \n", __func__);
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ {
+ icn83xx_error("I2C check functionality failed.\n");
+ return -ENODEV;
+ }
+
+ icn83xx_ts = kzalloc(sizeof(*icn83xx_ts), GFP_KERNEL);
+ if (!icn83xx_ts)
+ {
+ icn83xx_error("Alloc icn83xx_ts memory failed.\n");
+ return -ENOMEM;
+ }
+
+ this_client = client;
+ i2c_set_clientdata(client, icn83xx_ts);
+
+ icn83xx_ts->work_mode = 0;
+ spin_lock_init(&icn83xx_ts->irq_lock);
+ // icn83xx_ts->irq_lock = SPIN_LOCK_UNLOCKED;
+
+ err = icn83xx_request_io_port(icn83xx_ts);
+ if (err != 0) {
+ icn83xx_error("icn83xx_request_io_port failed.\n");
+ goto fail1;
+ }
+
+ memset(firmware, 0, 128);
+ sprintf(firmware,"/system/etc/firmware/%s.bin",g_param.fw_name);
+
+ icn83xx_ts_reset();
+ err = icn83xx_iic_test();
+ if (err < 0)
+ {
+ icn83xx_error("icn83xx_iic_test failed.\n");
+#if SUPPORT_FW_UPDATE
+
+#if COMPILE_FW_WITH_DRIVER
+ icn83xx_set_fw(sizeof(icn83xx_fw), &icn83xx_fw[0]);
+#endif
+ if(icn83xx_check_progmod() == 0)
+ {
+
+ retry = 5;
+ icn83xx_trace("in prog mode\n");
+ while(retry > 0)
+ {
+ if(R_OK == icn83xx_fw_update(firmware))
+ {
+ break;
+ }
+ retry--;
+ icn83xx_error("icn83xx_fw_update failed.\n");
+ }
+ }
+ else //
+ {
+ icn83xx_error("I2C communication failed.\n");
+ err = -1;
+ goto fail2;
+ }
+
+#endif
+ }
+ else
+ {
+ icn83xx_trace("iic communication ok\n");
+ }
+
+#if SUPPORT_FW_UPDATE
+ fwVersion = icn83xx_read_fw_Ver(firmware);
+ curVersion = icn83xx_readVersion();
+ icn83xx_trace("fwVersion : 0x%x\n", fwVersion);
+ icn83xx_trace("current version: 0x%x\n", curVersion);
+
+ if (g_param.force_download) {
+ retry = 5;
+ while(retry > 0)
+ {
+ if(R_OK == icn83xx_fw_update(firmware))
+ {
+ break;
+ }
+ retry--;
+ icn83xx_error("icn83xx_fw_update failed.\n");
+ }
+ } else {
+ if(fwVersion > curVersion)
+ {
+ retry = 5;
+ while(retry > 0)
+ {
+ if(R_OK == icn83xx_fw_update(firmware))
+ {
+ break;
+ }
+ retry--;
+ icn83xx_error("icn83xx_fw_update failed.\n");
+ }
+ }
+ }
+
+#endif
+
+#if SUPPORT_FW_CALIB
+ err = icn83xx_read_reg(0, &value);
+ if(err > 0)
+ {
+ //auto calib fw
+ average = icn83xx_calib(0, NULL);
+ //fix FbCap
+ // average = icn83xx_calib(0, FbCap[1]);
+ icn83xx_trace("average : %d\n", average);
+ icn83xx_setPeakGroup(250, 150);
+ icn83xx_setDownUp(400, 300);
+ }
+#endif
+
+ INIT_WORK(&icn83xx_ts->pen_event_work, icn83xx_ts_pen_irq_work);
+ icn83xx_ts->ts_workqueue = create_singlethread_workqueue(dev_name(&client->dev));
+ if (!icn83xx_ts->ts_workqueue) {
+ icn83xx_error("create_singlethread_workqueue failed.\n");
+ err = -ESRCH;
+ goto fail3;
+ }
+
+ err= icn83xx_request_input_dev(icn83xx_ts);
+ if (err < 0)
+ {
+ icn83xx_error("request input dev failed\n");
+ goto fail4;
+ }
+
+#if TOUCH_VIRTUAL_KEYS
+ icn83xx_ts_virtual_keys_init();
+#endif
+ err = icn83xx_request_irq(icn83xx_ts);
+ if (err != 0)
+ {
+ printk("request irq error, use timer\n");
+ icn83xx_ts->use_irq = 0;
+ hrtimer_init(&icn83xx_ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ icn83xx_ts->timer.function = chipone_timer_func;
+ hrtimer_start(&icn83xx_ts->timer, ktime_set(CTP_START_TIMER/1000, (CTP_START_TIMER%1000)*1000000), HRTIMER_MODE_REL);
+ }
+#if SUPPORT_SYSFS
+ icn83xx_create_sysfs(client);
+#endif
+
+#if SUPPORT_PROC_FS
+ sema_init(&icn83xx_ts->sem, 1);
+ init_proc_node();
+#endif
+
+ err = device_create_file(&(client->dev), &dev_attr_dbg);
+ if (err) {
+ printk("Can't create attr file");
+ }
+ if (g_param.earlysus_en)
+ register_bl_notifier(&wmt_bl_notify);
+
+#if SUPPORT_DELAYED_WORK
+ INIT_DELAYED_WORK(&icn83xx_ts->icn_delayed_work, icn_delayedwork_fun);
+ schedule_delayed_work(&icn83xx_ts->icn_delayed_work, msecs_to_jiffies(8000));
+#else
+
+ icn83xx_irq_enable();
+#endif
+ icn83xx_trace("==%s over =\n", __func__);
+ return 0;
+
+fail4:
+ input_unregister_device(icn83xx_ts->input_dev);
+ input_free_device(icn83xx_ts->input_dev);
+fail3:
+ cancel_work_sync(&icn83xx_ts->pen_event_work);
+fail2:
+ icn83xx_free_io_port();
+fail1:
+ kfree(icn83xx_ts);
+ return err;
+}
+
+static int __devexit icn83xx_ts_remove(struct i2c_client *client)
+{
+ struct icn83xx_ts_data *icn83xx_ts = i2c_get_clientdata(client);
+ icn83xx_trace("==icn83xx_ts_remove=\n");
+ icn83xx_irq_disable();
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ unregister_early_suspend(&icn83xx_ts->early_suspend);
+#endif
+
+ if (g_param.earlysus_en)
+ unregister_bl_notifier(&wmt_bl_notify);
+
+#if SUPPORT_PROC_FS
+ uninit_proc_node();
+#endif
+
+ input_unregister_device(icn83xx_ts->input_dev);
+ input_free_device(icn83xx_ts->input_dev);
+ cancel_work_sync(&icn83xx_ts->pen_event_work);
+ destroy_workqueue(icn83xx_ts->ts_workqueue);
+ icn83xx_free_irq(icn83xx_ts);
+ icn83xx_free_io_port();
+ kfree(icn83xx_ts);
+ i2c_set_clientdata(client, NULL);
+ return 0;
+}
+
+static int wmt_check_touch_env(void)
+{
+ int ret = 0;
+ int len = 96;
+ char retval[200] = {0},*p=NULL,*s=NULL;
+ int Enable=0;
+
+ // Get u-boot parameter
+ /*ret = wmt_getsyspara("wmt.io.zettouch", retval, &len);
+ if(ret){
+ klog("Read wmt.io.zettouch Failed.\n");
+ } else
+ goto paste;*/
+ ret = wmt_getsyspara("wmt.io.touch", retval, &len);
+ if(ret){
+ printk("Read wmt.io.touch Failed.\n");
+ return -EIO;
+ }
+
+//paste:
+ p = retval;
+ Enable = (p[0] - '0' == 1) ? 1 : 0;
+ if(Enable == 0){
+ printk("Touch Screen Is Disabled.\n");
+ return -ENODEV;
+ }
+
+ p = strchr(p,':');p++;
+ s = strchr(p,':');
+ strncpy(g_param.fw_name,p, (s-p));
+ printk("ts_name=%s\n", g_param.fw_name);
+ if (strncmp(g_param.fw_name, "ICN83", 5)) {
+ printk("Wrong firmware name.\n");
+ return -ENODEV;
+ }
+
+ p = s+1;
+ ret = sscanf(p,"%d:%d:%d:%d:%d:%d:%d:%d",
+ &(g_param.irqgpio),&(g_param.panelres_x),&(g_param.panelres_y),&(g_param.rstgpio),
+ &(g_param.xyswap),&(g_param.xdir),&(g_param.ydir),&(g_param.force_download));
+
+ if (ret < 8) {
+ printk("Wrong format ts u-boot param(%d)!\nwmt.io.touch=%s\n",ret,retval);
+ return -ENODEV;
+ }
+
+ printk("p.x = %d, p.y = %d, irqgpio=%d, rstgpio=%d,xyswap=%d,xdir=%d,ydir=%d,force_download=%d\n",
+ g_param.panelres_x,g_param.panelres_y,g_param.irqgpio,g_param.rstgpio,
+ g_param.xyswap,g_param.xdir,g_param.ydir,g_param.force_download);
+
+ memset(retval,0,sizeof(retval));
+ ret = wmt_getsyspara("wmt.touch.earlysus", retval, &len);
+ if(!ret)
+ g_param.earlysus_en = (retval[0] - '0' == 1) ? 1 : 0;
+
+ memset(retval,0,sizeof(retval));
+ ret = wmt_getsyspara("wmt.display.fb0", retval, &len);
+ if (!ret) {
+ int tmp[6];
+ p = retval;
+ sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]);
+ if (tmp[4] > tmp[5])
+ g_param.lcd_exchg = 1;
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops icn83xx_pm_ops = {
+ .suspend = icn83xx_ts_suspend,
+ .resume = icn83xx_ts_resume,
+};
+
+static const struct i2c_device_id icn83xx_ts_id[] = {
+ { CTP_NAME, 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, icn83xx_ts_id);
+
+static struct i2c_driver icn83xx_ts_driver = {
+ .driver = {
+ .name = CTP_NAME,
+ .pm = &icn83xx_pm_ops,
+ },
+ .probe = icn83xx_ts_probe,
+ .remove = __devexit_p(icn83xx_ts_remove),
+ .id_table = icn83xx_ts_id,
+};
+
+static struct i2c_board_info i2c_board_info = {
+ I2C_BOARD_INFO(CTP_NAME, ICN83XX_IIC_ADDR),
+};
+
+static int __init icn83xx_ts_init(void)
+{
+ struct i2c_client *client;
+ struct i2c_adapter *adap;
+ //u8 ts_data[8];
+
+ icn83xx_trace("===========================%s=====================\n", __func__);
+ if(wmt_check_touch_env())
+ return -ENODEV;
+ {//register i2c device
+ adap = i2c_get_adapter(1); //i2c Bus 1
+ if (!adap)
+ return -ENODEV;
+ client = i2c_new_device(adap, &i2c_board_info);
+ i2c_put_adapter(adap);
+ if (!client) {
+ printk("i2c_new_device error\n");
+ return -ENODEV;
+ }
+ }
+ /*{ //check if IC exists
+ if (i2c_read_tsdata(client, ts_data, 8) <= 0) {
+ errlog("Can't find IC!\n");
+ i2c_unregister_device(client);
+ return -ENODEV;
+ }
+ }*/
+ return i2c_add_driver(&icn83xx_ts_driver);
+}
+
+static void __exit icn83xx_ts_exit(void)
+{
+ icn83xx_trace("==icn83xx_ts_exit==\n");
+ i2c_unregister_device(this_client);
+ return i2c_del_driver(&icn83xx_ts_driver);
+}
+
+late_initcall(icn83xx_ts_init);
+module_exit(icn83xx_ts_exit);
+
+MODULE_AUTHOR("<zmtian@chiponeic.com>");
+MODULE_DESCRIPTION("Chipone icn83xx TouchScreen driver");
+MODULE_LICENSE("GPL");