OSDN Git Service

input: touchpanel: Add GT9xx touchpanel driver for skuf
authorAndrew Huang <andrew@goodix.com>
Thu, 27 Jun 2013 10:06:56 +0000 (10:06 +0000)
committerAbinaya P <abinayap@codeaurora.org>
Fri, 22 Jul 2016 08:06:09 +0000 (13:36 +0530)
This is the reference driver source code V1.8 for the GT9XX series.For
this first commit just copy binary, the second commit decompress the
binary and the third commit upgrade the version. We just need the newest
version, so Squashed the following commits:

commit 31915760747230826fa474fbb5b06a70b103c7e7
Author: Andrew Huang <andrew@goodix.com>
Date:   Thu Jun 27 10:06:56 2013 +0000

    This is the official reference driver source code V1.8 for the GT9XX series CTP controller,release for CIENET.

Signed-off-by: Andrew Huang <andrew@goodix.com>
    git-svn-id: http://gtp-drivers-for-android.googlecode.com/svn//drivers@15 4d552555-e8e2-8f43-36d7-85641c3b7a2e

commit 82f70eaf58b0996e9f488b170f81a107642d4df8
Author: unknowtree@gmail.com <unknowtree@gmail.com>
Date:   Thu Jun 6 02:58:58 2013 +0000

    git-svn-id: http://gtp-drivers-for-android.googlecode.com/svn//drivers@7 4d552555-e8e2-8f43-36d7-85641c3b7a2e

commit 5c42b80f40a9731ac45d4e04a7a7528367f713e7
Author: unknowtree@gmail.com <unknowtree@gmail.com>
Date:   Tue Jun 4 08:53:01 2013 +0000

    git-svn-id: http://gtp-drivers-for-android.googlecode.com/svn//drivers@5 4d552555-e8e2-8f43-36d7-85641c3b7a2e

Change-Id: I30420fc51fe1bb153c36342e607539e5cd74de61
Signed-off-by: Pan Fang <fangpan@codeaurora.org>
(cherry picked from commit ab45aab306d8b8d16619bc02f35465fb8d6ff066)
Signed-off-by: Abinaya P <abinayap@codeaurora.org>
input/touchscreen/gt9xx/goodix_tool.c [new file with mode: 0644]
input/touchscreen/gt9xx/gt9xx.c [new file with mode: 0644]
input/touchscreen/gt9xx/gt9xx.h [new file with mode: 0644]
input/touchscreen/gt9xx/gt9xx_firmware.h [new file with mode: 0644]
input/touchscreen/gt9xx/gt9xx_update.c [new file with mode: 0644]

diff --git a/input/touchscreen/gt9xx/goodix_tool.c b/input/touchscreen/gt9xx/goodix_tool.c
new file mode 100644 (file)
index 0000000..3dfe4e1
--- /dev/null
@@ -0,0 +1,615 @@
+/* drivers/input/touchscreen/goodix_tool.c\r
+ * \r
+ * 2010 - 2012 Goodix Technology.\r
+ * \r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ * \r
+ * This program is distributed in the hope that it will be a reference \r
+ * to you, when you are integrating the GOODiX's CTP IC into your system, \r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of \r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU \r
+ * General Public License for more details.\r
+ * \r
+ * Version:1.6\r
+ *        V1.0:2012/05/01,create file.\r
+ *        V1.2:2012/06/08,modify some warning.\r
+ *        V1.4:2012/08/28,modified to support GT9XX\r
+ *        V1.6:new proc name\r
+ */\r
+\r
+#include "gt9xx.h"\r
+\r
+#define DATA_LENGTH_UINT    512\r
+#define CMD_HEAD_LENGTH     (sizeof(st_cmd_head) - sizeof(u8*))\r
+static char procname[20] = {0};\r
+\r
+#define UPDATE_FUNCTIONS\r
+\r
+#ifdef UPDATE_FUNCTIONS\r
+extern s32 gup_enter_update_mode(struct i2c_client *client);\r
+extern void gup_leave_update_mode(void);\r
+extern s32 gup_update_proc(void *dir);\r
+#endif\r
+\r
+extern void gtp_irq_disable(struct goodix_ts_data *);\r
+extern void gtp_irq_enable(struct goodix_ts_data *);\r
+\r
+#pragma pack(1)\r
+typedef struct{\r
+    u8  wr;         //write read flag£¬0:R  1:W  2:PID 3:\r
+    u8  flag;       //0:no need flag/int 1: need flag  2:need int\r
+    u8 flag_addr[2];  //flag address\r
+    u8  flag_val;   //flag val\r
+    u8  flag_relation;  //flag_val:flag 0:not equal 1:equal 2:> 3:<\r
+    u16 circle;     //polling cycle \r
+    u8  times;      //plling times\r
+    u8  retry;      //I2C retry times\r
+    u16 delay;      //delay befor read or after write\r
+    u16 data_len;   //data length\r
+    u8  addr_len;   //address length\r
+    u8  addr[2];    //address\r
+    u8  res[3];     //reserved\r
+    u8* data;       //data pointer\r
+}st_cmd_head;\r
+#pragma pack()\r
+st_cmd_head cmd_head;\r
+\r
+static struct i2c_client *gt_client = NULL;\r
+\r
+static struct proc_dir_entry *goodix_proc_entry;\r
+\r
+static s32 goodix_tool_write(struct file *filp, const char __user *buff, unsigned long len, void *data);\r
+static s32 goodix_tool_read( char *page, char **start, off_t off, int count, int *eof, void *data );\r
+static s32 (*tool_i2c_read)(u8 *, u16);\r
+static s32 (*tool_i2c_write)(u8 *, u16);\r
+\r
+#if GTP_ESD_PROTECT\r
+extern void gtp_esd_switch(struct i2c_client *, s32);\r
+#endif\r
+s32 DATA_LENGTH = 0;\r
+s8 IC_TYPE[16] = {0};\r
+\r
+static void tool_set_proc_name(char * procname)\r
+{\r
+    char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", \r
+        "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};\r
+    char date[20] = {0};\r
+    char month[4] = {0};\r
+    int i = 0, n_month = 1, n_day = 0, n_year = 0;\r
+    \r
+    sprintf(date, "%s", __DATE__);\r
+    \r
+    //GTP_DEBUG("compile date: %s", date);\r
+    \r
+    sscanf(date, "%s %d %d", month, &n_day, &n_year);\r
+    \r
+    for (i = 0; i < 12; ++i)\r
+    {\r
+        if (!memcmp(months[i], month, 3))\r
+        {\r
+            n_month = i+1;\r
+            break;\r
+        }\r
+    }\r
+    \r
+    sprintf(procname, "gmnode%04d%02d%02d", n_year, n_month, n_day);    \r
+    \r
+    //GTP_DEBUG("procname = %s", procname);\r
+}\r
+\r
+\r
+static s32 tool_i2c_read_no_extra(u8* buf, u16 len)\r
+{\r
+    s32 ret = -1;\r
+    s32 i = 0;\r
+    struct i2c_msg msgs[2];\r
+    \r
+    msgs[0].flags = !I2C_M_RD;\r
+    msgs[0].addr  = gt_client->addr;\r
+    msgs[0].len   = cmd_head.addr_len;\r
+    msgs[0].buf   = &buf[0];\r
+    \r
+    msgs[1].flags = I2C_M_RD;\r
+    msgs[1].addr  = gt_client->addr;\r
+    msgs[1].len   = len;\r
+    msgs[1].buf   = &buf[GTP_ADDR_LENGTH];\r
+\r
+    for (i = 0; i < cmd_head.retry; i++)\r
+    {\r
+        ret=i2c_transfer(gt_client->adapter, msgs, 2);\r
+        if (ret > 0)\r
+        {\r
+            break;\r
+        }\r
+    }\r
+    return ret;\r
+}\r
+\r
+static s32 tool_i2c_write_no_extra(u8* buf, u16 len)\r
+{\r
+    s32 ret = -1;\r
+    s32 i = 0;\r
+    struct i2c_msg msg;\r
+\r
+    msg.flags = !I2C_M_RD;\r
+    msg.addr  = gt_client->addr;\r
+    msg.len   = len;\r
+    msg.buf   = buf;\r
+\r
+    for (i = 0; i < cmd_head.retry; i++)\r
+    {\r
+        ret=i2c_transfer(gt_client->adapter, &msg, 1);\r
+        if (ret > 0)\r
+        {\r
+            break;\r
+        }\r
+    }\r
+    return ret;\r
+}\r
+\r
+static s32 tool_i2c_read_with_extra(u8* buf, u16 len)\r
+{\r
+    s32 ret = -1;\r
+    u8 pre[2] = {0x0f, 0xff};\r
+    u8 end[2] = {0x80, 0x00};\r
+\r
+    tool_i2c_write_no_extra(pre, 2);\r
+    ret = tool_i2c_read_no_extra(buf, len);\r
+    tool_i2c_write_no_extra(end, 2);\r
+\r
+    return ret;\r
+}\r
+\r
+static s32 tool_i2c_write_with_extra(u8* buf, u16 len)\r
+{\r
+    s32 ret = -1;\r
+    u8 pre[2] = {0x0f, 0xff};\r
+    u8 end[2] = {0x80, 0x00};\r
+\r
+    tool_i2c_write_no_extra(pre, 2);\r
+    ret = tool_i2c_write_no_extra(buf, len);\r
+    tool_i2c_write_no_extra(end, 2);\r
+\r
+    return ret;\r
+}\r
+\r
+static void register_i2c_func(void)\r
+{\r
+//    if (!strncmp(IC_TYPE, "GT818", 5) || !strncmp(IC_TYPE, "GT816", 5) \r
+//        || !strncmp(IC_TYPE, "GT811", 5) || !strncmp(IC_TYPE, "GT818F", 6) \r
+//        || !strncmp(IC_TYPE, "GT827", 5) || !strncmp(IC_TYPE,"GT828", 5)\r
+//        || !strncmp(IC_TYPE, "GT813", 5))\r
+    if (strncmp(IC_TYPE, "GT8110", 6) && strncmp(IC_TYPE, "GT8105", 6)\r
+        && strncmp(IC_TYPE, "GT801", 5) && strncmp(IC_TYPE, "GT800", 5)\r
+        && strncmp(IC_TYPE, "GT801PLUS", 9) && strncmp(IC_TYPE, "GT811", 5)\r
+        && strncmp(IC_TYPE, "GTxxx", 5))\r
+    {\r
+        tool_i2c_read = tool_i2c_read_with_extra;\r
+        tool_i2c_write = tool_i2c_write_with_extra;\r
+        GTP_DEBUG("I2C function: with pre and end cmd!");\r
+    }\r
+    else\r
+    {\r
+        tool_i2c_read = tool_i2c_read_no_extra;\r
+        tool_i2c_write = tool_i2c_write_no_extra;\r
+        GTP_INFO("I2C function: without pre and end cmd!");\r
+    }\r
+}\r
+\r
+static void unregister_i2c_func(void)\r
+{\r
+    tool_i2c_read = NULL;\r
+    tool_i2c_write = NULL;\r
+    GTP_INFO("I2C function: unregister i2c transfer function!");\r
+}\r
+\r
+\r
+s32 init_wr_node(struct i2c_client *client)\r
+{\r
+    s32 i;\r
+\r
+    gt_client = client;\r
+    memset(&cmd_head, 0, sizeof(cmd_head));\r
+    cmd_head.data = NULL;\r
+\r
+    i = 5;\r
+    while ((!cmd_head.data) && i)\r
+    {\r
+        cmd_head.data = kzalloc(i * DATA_LENGTH_UINT, GFP_KERNEL);\r
+        if (NULL != cmd_head.data)\r
+        {\r
+            break;\r
+        }\r
+        i--;\r
+    }\r
+    if (i)\r
+    {\r
+        DATA_LENGTH = i * DATA_LENGTH_UINT + GTP_ADDR_LENGTH;\r
+        GTP_INFO("Applied memory size:%d.", DATA_LENGTH);\r
+    }\r
+    else\r
+    {\r
+        GTP_ERROR("Apply for memory failed.");\r
+        return FAIL;\r
+    }\r
+\r
+    cmd_head.addr_len = 2;\r
+    cmd_head.retry = 5;\r
+\r
+    register_i2c_func();\r
+\r
+    tool_set_proc_name(procname);\r
+    goodix_proc_entry = create_proc_entry(procname, 0666, NULL);\r
+    if (goodix_proc_entry == NULL)\r
+    {\r
+        GTP_ERROR("Couldn't create proc entry!");\r
+        return FAIL;\r
+    }\r
+    else\r
+    {\r
+        GTP_INFO("Create proc entry success!");\r
+        goodix_proc_entry->write_proc = goodix_tool_write;\r
+        goodix_proc_entry->read_proc = goodix_tool_read;\r
+    }\r
+\r
+    return SUCCESS;\r
+}\r
+\r
+void uninit_wr_node(void)\r
+{\r
+    kfree(cmd_head.data);\r
+    cmd_head.data = NULL;\r
+    unregister_i2c_func();\r
+    remove_proc_entry(procname, NULL);\r
+}\r
+\r
+static u8 relation(u8 src, u8 dst, u8 rlt)\r
+{\r
+    u8 ret = 0;\r
+    \r
+    switch (rlt)\r
+    {\r
+    case 0:\r
+        ret = (src != dst) ? true : false;\r
+        break;\r
+\r
+    case 1:\r
+        ret = (src == dst) ? true : false;\r
+        GTP_DEBUG("equal:src:0x%02x   dst:0x%02x   ret:%d.", src, dst, (s32)ret);\r
+        break;\r
+\r
+    case 2:\r
+        ret = (src > dst) ? true : false;\r
+        break;\r
+\r
+    case 3:\r
+        ret = (src < dst) ? true : false;\r
+        break;\r
+\r
+    case 4:\r
+        ret = (src & dst) ? true : false;\r
+        break;\r
+\r
+    case 5:\r
+        ret = (!(src | dst)) ? true : false;\r
+        break;\r
+\r
+    default:\r
+        ret = false;\r
+        break;    \r
+    }\r
+\r
+    return ret;\r
+}\r
+\r
+/*******************************************************    \r
+Function:\r
+    Comfirm function.\r
+Input:\r
+  None.\r
+Output:\r
+    Return write length.\r
+********************************************************/\r
+static u8 comfirm(void)\r
+{\r
+    s32 i = 0;\r
+    u8 buf[32];\r
+    \r
+//    memcpy(&buf[GTP_ADDR_LENGTH - cmd_head.addr_len], &cmd_head.flag_addr, cmd_head.addr_len);\r
+//    memcpy(buf, &cmd_head.flag_addr, cmd_head.addr_len);//Modified by Scott, 2012-02-17\r
+    memcpy(buf, cmd_head.flag_addr, cmd_head.addr_len);\r
+   \r
+    for (i = 0; i < cmd_head.times; i++)\r
+    {\r
+        if (tool_i2c_read(buf, 1) <= 0)\r
+        {\r
+            GTP_ERROR("Read flag data failed!");\r
+            return FAIL;\r
+        }\r
+        if (true == relation(buf[GTP_ADDR_LENGTH], cmd_head.flag_val, cmd_head.flag_relation))\r
+        {\r
+            GTP_DEBUG("value at flag addr:0x%02x.", buf[GTP_ADDR_LENGTH]);\r
+            GTP_DEBUG("flag value:0x%02x.", cmd_head.flag_val);\r
+            break;\r
+        }\r
+\r
+        msleep(cmd_head.circle);\r
+    }\r
+\r
+    if (i >= cmd_head.times)\r
+    {\r
+        GTP_ERROR("Didn't get the flag to continue!");\r
+        return FAIL;\r
+    }\r
+\r
+    return SUCCESS;\r
+}\r
+\r
+/*******************************************************    \r
+Function:\r
+    Goodix tool write function.\r
+Input:\r
+  standard proc write function param.\r
+Output:\r
+    Return write length.\r
+********************************************************/\r
+static s32 goodix_tool_write(struct file *filp, const char __user *buff, unsigned long len, void *data)\r
+{\r
+    s32 ret = 0;\r
+    GTP_DEBUG_FUNC();\r
+    GTP_DEBUG_ARRAY((u8*)buff, len);\r
+    \r
+    ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH);\r
+    if(ret)\r
+    {\r
+        GTP_ERROR("copy_from_user failed.");\r
+    }\r
+\r
+    GTP_DEBUG("wr  :0x%02x.", cmd_head.wr);\r
+    GTP_DEBUG("flag:0x%02x.", cmd_head.flag);\r
+    GTP_DEBUG("flag addr:0x%02x%02x.", cmd_head.flag_addr[0], cmd_head.flag_addr[1]);\r
+    GTP_DEBUG("flag val:0x%02x.", cmd_head.flag_val);\r
+    GTP_DEBUG("flag rel:0x%02x.", cmd_head.flag_relation);\r
+    GTP_DEBUG("circle  :%d.", (s32)cmd_head.circle);\r
+    GTP_DEBUG("times   :%d.", (s32)cmd_head.times);\r
+    GTP_DEBUG("retry   :%d.", (s32)cmd_head.retry);\r
+    GTP_DEBUG("delay   :%d.", (s32)cmd_head.delay);\r
+    GTP_DEBUG("data len:%d.", (s32)cmd_head.data_len);\r
+    GTP_DEBUG("addr len:%d.", (s32)cmd_head.addr_len);\r
+    GTP_DEBUG("addr:0x%02x%02x.", cmd_head.addr[0], cmd_head.addr[1]);\r
+    GTP_DEBUG("len:%d.", (s32)len);\r
+    GTP_DEBUG("buf[20]:0x%02x.", buff[CMD_HEAD_LENGTH]);\r
+    \r
+    if (1 == cmd_head.wr)\r
+    {\r
+      //  copy_from_user(&cmd_head.data[cmd_head.addr_len], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);\r
+        ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);\r
+        if(ret)\r
+        {\r
+            GTP_ERROR("copy_from_user failed.");\r
+        }\r
+        memcpy(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len], cmd_head.addr, cmd_head.addr_len);\r
+\r
+        GTP_DEBUG_ARRAY(cmd_head.data, cmd_head.data_len + cmd_head.addr_len);\r
+        GTP_DEBUG_ARRAY((u8*)&buff[CMD_HEAD_LENGTH], cmd_head.data_len);\r
+\r
+        if (1 == cmd_head.flag)\r
+        {\r
+            if (FAIL == comfirm())\r
+            {\r
+                GTP_ERROR("[WRITE]Comfirm fail!");\r
+                return FAIL;\r
+            }\r
+        }\r
+        else if (2 == cmd_head.flag)\r
+        {\r
+            //Need interrupt!\r
+        }\r
+        if (tool_i2c_write(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],\r
+            cmd_head.data_len + cmd_head.addr_len) <= 0)\r
+        {\r
+            GTP_ERROR("[WRITE]Write data failed!");\r
+            return FAIL;\r
+        }\r
+\r
+        GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],cmd_head.data_len + cmd_head.addr_len);\r
+        if (cmd_head.delay)\r
+        {\r
+            msleep(cmd_head.delay);\r
+        }\r
+\r
+        return cmd_head.data_len + CMD_HEAD_LENGTH;\r
+    }\r
+    else if (3 == cmd_head.wr)  //Write ic type\r
+    {\r
+    ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);\r
+        if(ret)\r
+        {\r
+            GTP_ERROR("copy_from_user failed.");\r
+        }\r
+        memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);\r
+\r
+        register_i2c_func();\r
+\r
+        return cmd_head.data_len + CMD_HEAD_LENGTH;\r
+    }\r
+    else if (5 == cmd_head.wr)\r
+    {\r
+        //memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);\r
+\r
+        return cmd_head.data_len + CMD_HEAD_LENGTH;\r
+    }\r
+    else if (7 == cmd_head.wr)//disable irq!\r
+    {\r
+        gtp_irq_disable(i2c_get_clientdata(gt_client));\r
+        \r
+    #if GTP_ESD_PROTECT\r
+        gtp_esd_switch(gt_client, SWITCH_OFF);\r
+    #endif\r
+        return CMD_HEAD_LENGTH;\r
+    }\r
+    else if (9 == cmd_head.wr) //enable irq!\r
+    {\r
+        gtp_irq_enable(i2c_get_clientdata(gt_client));\r
+\r
+    #if GTP_ESD_PROTECT\r
+        gtp_esd_switch(gt_client, SWITCH_ON);\r
+    #endif\r
+        return CMD_HEAD_LENGTH;\r
+    }\r
+    else if(17 == cmd_head.wr)\r
+    {\r
+        struct goodix_ts_data *ts = i2c_get_clientdata(gt_client);\r
+        ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);\r
+        if(ret)\r
+        {\r
+            GTP_DEBUG("copy_from_user failed.");\r
+        }\r
+        if(cmd_head.data[GTP_ADDR_LENGTH])\r
+        {\r
+            GTP_DEBUG("gtp enter rawdiff.");\r
+            ts->gtp_rawdiff_mode = true;\r
+        }\r
+        else\r
+        {\r
+            ts->gtp_rawdiff_mode = false;\r
+            GTP_DEBUG("gtp leave rawdiff.");\r
+        }\r
+        return CMD_HEAD_LENGTH;\r
+    }\r
+#ifdef UPDATE_FUNCTIONS\r
+    else if (11 == cmd_head.wr)//Enter update mode!\r
+    {\r
+        if (FAIL == gup_enter_update_mode(gt_client))\r
+        {\r
+            return FAIL;\r
+        }\r
+    }\r
+    else if (13 == cmd_head.wr)//Leave update mode!\r
+    {\r
+        gup_leave_update_mode();\r
+    }\r
+    else if (15 == cmd_head.wr) //Update firmware!\r
+    {\r
+        show_len = 0;\r
+        total_len = 0;\r
+        memset(cmd_head.data, 0, cmd_head.data_len + 1);\r
+        memcpy(cmd_head.data, &buff[CMD_HEAD_LENGTH], cmd_head.data_len);\r
+\r
+        if (FAIL == gup_update_proc((void*)cmd_head.data))\r
+        {\r
+            return FAIL;\r
+        }\r
+    }\r
+#endif\r
+\r
+    return CMD_HEAD_LENGTH;\r
+}\r
+\r
+/*******************************************************    \r
+Function:\r
+    Goodix tool read function.\r
+Input:\r
+  standard proc read function param.\r
+Output:\r
+    Return read length.\r
+********************************************************/\r
+static s32 goodix_tool_read( char *page, char **start, off_t off, int count, int *eof, void *data )\r
+{\r
+    GTP_DEBUG_FUNC();\r
+    \r
+    if (cmd_head.wr % 2)\r
+    {\r
+        return FAIL;\r
+    }\r
+    else if (!cmd_head.wr)\r
+    {\r
+        u16 len = 0;\r
+        s16 data_len = 0;\r
+        u16 loc = 0;\r
+        \r
+        if (1 == cmd_head.flag)\r
+        {\r
+            if (FAIL == comfirm())\r
+            {\r
+                GTP_ERROR("[READ]Comfirm fail!");\r
+                return FAIL;\r
+            }\r
+        }\r
+        else if (2 == cmd_head.flag)\r
+        {\r
+            //Need interrupt!\r
+        }\r
+\r
+        memcpy(cmd_head.data, cmd_head.addr, cmd_head.addr_len);\r
+\r
+        GTP_DEBUG("[CMD HEAD DATA] ADDR:0x%02x%02x.", cmd_head.data[0], cmd_head.data[1]);\r
+        GTP_DEBUG("[CMD HEAD ADDR] ADDR:0x%02x%02x.", cmd_head.addr[0], cmd_head.addr[1]);\r
+        \r
+        if (cmd_head.delay)\r
+        {\r
+            msleep(cmd_head.delay);\r
+        }\r
+        \r
+        data_len = cmd_head.data_len;\r
+        while(data_len > 0)\r
+        {\r
+            if (data_len > DATA_LENGTH)\r
+            {\r
+                len = DATA_LENGTH;\r
+            }\r
+            else\r
+            {\r
+                len = data_len;\r
+            }\r
+            data_len -= DATA_LENGTH;\r
+\r
+            if (tool_i2c_read(cmd_head.data, len) <= 0)\r
+            {\r
+                GTP_ERROR("[READ]Read data failed!");\r
+                return FAIL;\r
+            }\r
+            memcpy(&page[loc], &cmd_head.data[GTP_ADDR_LENGTH], len);\r
+            loc += len;\r
+\r
+            GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH], len);\r
+            GTP_DEBUG_ARRAY(page, len);\r
+        }\r
+    }\r
+    else if (2 == cmd_head.wr)\r
+    {\r
+    //    memcpy(page, "gt8", cmd_head.data_len);\r
+       // memcpy(page, "GT818", 5);\r
+      //  page[5] = 0;\r
+\r
+        GTP_DEBUG("Return ic type:%s len:%d.", page, (s32)cmd_head.data_len);\r
+        return cmd_head.data_len;\r
+        //return sizeof(IC_TYPE_NAME);\r
+    }\r
+    else if (4 == cmd_head.wr)\r
+    {\r
+        page[0] = show_len >> 8;\r
+        page[1] = show_len & 0xff;\r
+        page[2] = total_len >> 8;\r
+        page[3] = total_len & 0xff;\r
+\r
+        return cmd_head.data_len;\r
+    }\r
+    else if (6 == cmd_head.wr)\r
+    {\r
+        //Read error code!\r
+    }\r
+    else if (8 == cmd_head.wr)  //Read driver version\r
+    {\r
+       // memcpy(page, GTP_DRIVER_VERSION, strlen(GTP_DRIVER_VERSION));\r
+       s32 tmp_len;\r
+       tmp_len = strlen(GTP_DRIVER_VERSION);\r
+       memcpy(page, GTP_DRIVER_VERSION, tmp_len);\r
+       page[tmp_len] = 0;\r
+    }\r
+\r
+    return cmd_head.data_len;\r
+}\r
diff --git a/input/touchscreen/gt9xx/gt9xx.c b/input/touchscreen/gt9xx/gt9xx.c
new file mode 100644 (file)
index 0000000..b1dc08b
--- /dev/null
@@ -0,0 +1,1810 @@
+/* drivers/input/touchscreen/gt9xx.c
+ * 
+ * 2010 - 2013 Goodix Technology.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be a reference 
+ * to you, when you are integrating the GOODiX's CTP IC into your system, 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
+ * General Public License for more details.
+ * 
+ * Version: 1.8
+ * Authors: andrew@goodix.com, meta@goodix.com
+ * Release Date: 2013/04/25
+ * Revision record:
+ *      V1.0:   
+ *          first Release. By Andrew, 2012/08/31 
+ *      V1.2:
+ *          modify gtp_reset_guitar,slot report,tracking_id & 0x0F. By Andrew, 2012/10/15
+ *      V1.4:
+ *          modify gt9xx_update.c. By Andrew, 2012/12/12
+ *      V1.6: 
+ *          1. new heartbeat/esd_protect mechanism(add external watchdog)
+ *          2. doze mode, sliding wakeup 
+ *          3. 3 more cfg_group(GT9 Sensor_ID: 0~5) 
+ *          3. config length verification
+ *          4. names & comments
+ *                  By Meta, 2013/03/11
+ *      V1.8:
+ *          1. pen/stylus identification 
+ *          2. read double check & fixed config support
+ *          2. new esd & slide wakeup optimization
+ *                  By Meta, 2013/06/08
+ */
+
+#include <linux/irq.h>
+#include "gt9xx.h"
+
+#if GTP_ICS_SLOT_REPORT
+    #include <linux/input/mt.h>
+#endif
+
+static const char *goodix_ts_name = "Goodix Capacitive TouchScreen";
+static struct workqueue_struct *goodix_wq;
+struct i2c_client * i2c_connect_client = NULL; 
+u8 config[GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH]
+                = {GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff};
+
+#if GTP_HAVE_TOUCH_KEY
+    static const u16 touch_key_array[] = GTP_KEY_TAB;
+    #define GTP_MAX_KEY_NUM  (sizeof(touch_key_array)/sizeof(touch_key_array[0]))
+    
+#if GTP_DEBUG_ON
+    static const int  key_codes[] = {KEY_HOME, KEY_BACK, KEY_MENU, KEY_SEARCH};
+    static const char *key_names[] = {"Key_Home", "Key_Back", "Key_Menu", "Key_Search"};
+#endif
+    
+#endif
+
+static s8 gtp_i2c_test(struct i2c_client *client);
+void gtp_reset_guitar(struct i2c_client *client, s32 ms);
+void gtp_int_sync(s32 ms);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void goodix_ts_early_suspend(struct early_suspend *h);
+static void goodix_ts_late_resume(struct early_suspend *h);
+#endif
+#if GTP_CREATE_WR_NODE
+extern s32 init_wr_node(struct i2c_client*);
+extern void uninit_wr_node(void);
+#endif
+
+#if GTP_AUTO_UPDATE
+extern u8 gup_init_update_proc(struct goodix_ts_data *);
+#endif
+
+#if GTP_ESD_PROTECT
+static struct delayed_work gtp_esd_check_work;
+static struct workqueue_struct * gtp_esd_check_workqueue = NULL;
+static void gtp_esd_check_func(struct work_struct *);
+static s32 gtp_init_ext_watchdog(struct i2c_client *client);
+void gtp_esd_switch(struct i2c_client *, s32);
+#endif
+
+
+#if GTP_SLIDE_WAKEUP
+typedef enum
+{
+    DOZE_DISABLED = 0,
+    DOZE_ENABLED = 1,
+    DOZE_WAKEUP = 2,
+}DOZE_T;
+static DOZE_T doze_status = DOZE_DISABLED;
+static s8 gtp_enter_doze(struct goodix_ts_data *ts);
+#endif
+
+static u8 chip_gt9xxs = 0;  // true if ic is gt9xxs, like gt915s
+u8 grp_cfg_version = 0;
+
+/*******************************************************
+Function:
+    Read data from the i2c slave device.
+Input:
+    client:     i2c device.
+    buf[0~1]:   read start address.
+    buf[2~len-1]:   read data buffer.
+    len:    GTP_ADDR_LENGTH + read bytes count
+Output:
+    numbers of i2c_msgs to transfer: 
+      2: succeed, otherwise: failed
+*********************************************************/
+s32 gtp_i2c_read(struct i2c_client *client, u8 *buf, s32 len)
+{
+    struct i2c_msg msgs[2];
+    s32 ret=-1;
+    s32 retries = 0;
+
+    GTP_DEBUG_FUNC();
+
+    msgs[0].flags = !I2C_M_RD;
+    msgs[0].addr  = client->addr;
+    msgs[0].len   = GTP_ADDR_LENGTH;
+    msgs[0].buf   = &buf[0];
+    //msgs[0].scl_rate = 300 * 1000;    // for Rockchip
+    
+    msgs[1].flags = I2C_M_RD;
+    msgs[1].addr  = client->addr;
+    msgs[1].len   = len - GTP_ADDR_LENGTH;
+    msgs[1].buf   = &buf[GTP_ADDR_LENGTH];
+    //msgs[1].scl_rate = 300 * 1000;
+
+    while(retries < 5)
+    {
+        ret = i2c_transfer(client->adapter, msgs, 2);
+        if(ret == 2)break;
+        retries++;
+    }
+    if((retries >= 5))
+    {
+    #if GTP_SLIDE_WAKEUP
+        // reset chip would quit doze mode
+        if (DOZE_ENABLED == doze_status)
+        {
+            return ret;
+        }
+    #endif
+        GTP_DEBUG("I2C communication timeout, resetting chip...");
+        gtp_reset_guitar(client, 10);
+    }
+    return ret;
+}
+
+/*******************************************************
+Function:
+    Write data to the i2c slave device.
+Input:
+    client:     i2c device.
+    buf[0~1]:   write start address.
+    buf[2~len-1]:   data buffer
+    len:    GTP_ADDR_LENGTH + write bytes count
+Output:
+    numbers of i2c_msgs to transfer: 
+        1: succeed, otherwise: failed
+*********************************************************/
+s32 gtp_i2c_write(struct i2c_client *client,u8 *buf,s32 len)
+{
+    struct i2c_msg msg;
+    s32 ret = -1;
+    s32 retries = 0;
+
+    GTP_DEBUG_FUNC();
+
+    msg.flags = !I2C_M_RD;
+    msg.addr  = client->addr;
+    msg.len   = len;
+    msg.buf   = buf;
+    //msg.scl_rate = 300 * 1000;    // for Rockchip
+
+    while(retries < 5)
+    {
+        ret = i2c_transfer(client->adapter, &msg, 1);
+        if (ret == 1)break;
+        retries++;
+    }
+    if((retries >= 5))
+    {
+    #if GTP_SLIDE_WAKEUP
+        if (DOZE_ENABLED == doze_status)
+        {
+            return ret;
+        }
+    #endif
+        GTP_DEBUG("I2C communication timeout, resetting chip...");
+        gtp_reset_guitar(client, 10);
+    }
+    return ret;
+}
+/*******************************************************
+Function:
+    i2c read twice, compare the results
+Input:
+    client:  i2c device
+    addr:    operate address
+    rxbuf:   read data to store, if compare successful
+    len:     bytes to read
+Output:
+    FAIL:    read failed
+    SUCCESS: read successful
+*********************************************************/
+s32 gtp_i2c_read_dbl_check(struct i2c_client *client, u16 addr, u8 *rxbuf, int len)
+{
+    u8 buf[16] = {0};
+    u8 confirm_buf[16] = {0};
+    u8 retry = 0;
+    
+    while (retry++ < 3)
+    {
+        memset(buf, 0xAA, 16);
+        buf[0] = (u8)(addr >> 8);
+        buf[1] = (u8)(addr & 0xFF);
+        gtp_i2c_read(client, buf, len + 2);
+        
+        memset(confirm_buf, 0xAB, 16);
+        confirm_buf[0] = (u8)(addr >> 8);
+        confirm_buf[1] = (u8)(addr & 0xFF);
+        gtp_i2c_read(client, confirm_buf, len + 2);
+        
+        if (!memcmp(buf, confirm_buf, len+2))
+        {
+            break;
+        }
+    }    
+    if (retry < 3)
+    {
+        memcpy(rxbuf, confirm_buf+2, len);
+        return SUCCESS;
+    }
+    else
+    {
+        GTP_ERROR("i2c read 0x%04X, %d bytes, double check failed!", addr, len);
+        return FAIL;
+    }
+}
+
+/*******************************************************
+Function:
+    Send config.
+Input:
+    client: i2c device.
+Output:
+    result of i2c write operation. 
+        1: succeed, otherwise: failed
+*********************************************************/
+s32 gtp_send_cfg(struct i2c_client *client)
+{
+    s32 ret = 2;
+    
+#if GTP_DRIVER_SEND_CFG
+    s32 retry = 0;
+    struct goodix_ts_data *ts = i2c_get_clientdata(client);
+    
+    if (ts->fixed_cfg)
+    {
+        GTP_INFO("Ic fixed config, no config sent!");
+        return 2;
+    }
+    GTP_INFO("driver send config");
+    for (retry = 0; retry < 5; retry++)
+    {
+        ret = gtp_i2c_write(client, config , GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH);
+        if (ret > 0)
+        {
+            break;
+        }
+    }
+#endif
+
+    return ret;
+}
+
+/*******************************************************
+Function:
+    Disable irq function
+Input:
+    ts: goodix i2c_client private data
+Output:
+    None.
+*********************************************************/
+void gtp_irq_disable(struct goodix_ts_data *ts)
+{
+    unsigned long irqflags;
+
+    GTP_DEBUG_FUNC();
+
+    spin_lock_irqsave(&ts->irq_lock, irqflags);
+    if (!ts->irq_is_disable)
+    {
+        ts->irq_is_disable = 1; 
+        disable_irq_nosync(ts->client->irq);
+    }
+    spin_unlock_irqrestore(&ts->irq_lock, irqflags);
+}
+
+/*******************************************************
+Function:
+    Enable irq function
+Input:
+    ts: goodix i2c_client private data
+Output:
+    None.
+*********************************************************/
+void gtp_irq_enable(struct goodix_ts_data *ts)
+{
+    unsigned long irqflags = 0;
+
+    GTP_DEBUG_FUNC();
+    
+    spin_lock_irqsave(&ts->irq_lock, irqflags);
+    if (ts->irq_is_disable) 
+    {
+        enable_irq(ts->client->irq);
+        ts->irq_is_disable = 0; 
+    }
+    spin_unlock_irqrestore(&ts->irq_lock, irqflags);
+}
+
+
+/*******************************************************
+Function:
+    Report touch point event 
+Input:
+    ts: goodix i2c_client private data
+    id: trackId
+    x:  input x coordinate
+    y:  input y coordinate
+    w:  input pressure
+Output:
+    None.
+*********************************************************/
+static void gtp_touch_down(struct goodix_ts_data* ts,s32 id,s32 x,s32 y,s32 w)
+{
+#if GTP_CHANGE_X2Y
+    GTP_SWAP(x, y);
+#endif
+
+#if GTP_ICS_SLOT_REPORT
+    input_mt_slot(ts->input_dev, id);
+    input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, id);
+    input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x);
+    input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);
+    input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w);
+    input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w);
+#else
+    input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x);
+    input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);
+    input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w);
+    input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w);
+    input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, id);
+    input_mt_sync(ts->input_dev);
+#endif
+
+    GTP_DEBUG("ID:%d, X:%d, Y:%d, W:%d", id, x, y, w);
+}
+
+/*******************************************************
+Function:
+    Report touch release event
+Input:
+    ts: goodix i2c_client private data
+Output:
+    None.
+*********************************************************/
+static void gtp_touch_up(struct goodix_ts_data* ts, s32 id)
+{
+#if GTP_ICS_SLOT_REPORT
+    input_mt_slot(ts->input_dev, id);
+    input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1);
+    GTP_DEBUG("Touch id[%2d] release!", id);
+#else
+    input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
+    input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0);
+    input_mt_sync(ts->input_dev);
+#endif
+}
+
+
+/*******************************************************
+Function:
+    Goodix touchscreen work function
+Input:
+    work: work struct of goodix_workqueue
+Output:
+    None.
+*********************************************************/
+static void goodix_ts_work_func(struct work_struct *work)
+{
+    u8  end_cmd[3] = {GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF, 0};
+    u8  point_data[2 + 1 + 8 * GTP_MAX_TOUCH + 1]={GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF};
+    u8  touch_num = 0;
+    u8  finger = 0;
+    static u16 pre_touch = 0;
+    static u8 pre_key = 0;
+#if GTP_WITH_PEN
+    static u8 pre_pen = 0;
+#endif
+    u8  key_value = 0;
+    u8* coor_data = NULL;
+    s32 input_x = 0;
+    s32 input_y = 0;
+    s32 input_w = 0;
+    s32 id = 0;
+    s32 i  = 0;
+    s32 ret = -1;
+    struct goodix_ts_data *ts = NULL;
+
+#if GTP_SLIDE_WAKEUP
+    u8 doze_buf[3] = {0x81, 0x4B};
+#endif
+
+    GTP_DEBUG_FUNC();
+    ts = container_of(work, struct goodix_ts_data, work);
+    if (ts->enter_update)
+    {
+        return;
+    }
+#if GTP_SLIDE_WAKEUP
+    if (DOZE_ENABLED == doze_status)
+    {               
+        ret = gtp_i2c_read(i2c_connect_client, doze_buf, 3);
+        GTP_DEBUG("0x814B = 0x%02X", doze_buf[2]);
+        if (ret > 0)
+        {               
+            if (doze_buf[2] == 0xAA)
+            {
+                GTP_INFO("Slide(0xAA) To Light up the screen!");
+                doze_status = DOZE_WAKEUP;
+                input_report_key(ts->input_dev, KEY_POWER, 1);
+                input_sync(ts->input_dev);
+                input_report_key(ts->input_dev, KEY_POWER, 0);
+                input_sync(ts->input_dev);
+                // clear 0x814B
+                doze_buf[2] = 0x00;
+                gtp_i2c_write(i2c_connect_client, doze_buf, 3);
+            }
+            else if (doze_buf[2] == 0xBB)
+            {
+                GTP_INFO("Slide(0xBB) To Light up the screen!");
+                doze_status = DOZE_WAKEUP;
+                input_report_key(ts->input_dev, KEY_POWER, 1);
+                input_sync(ts->input_dev);
+                input_report_key(ts->input_dev, KEY_POWER, 0);
+                input_sync(ts->input_dev);
+                // clear 0x814B
+                doze_buf[2] = 0x00;
+                gtp_i2c_write(i2c_connect_client, doze_buf, 3);
+            }
+            else if (0xC0 == (doze_buf[2] & 0xC0))
+            {
+                GTP_INFO("double click to light up the screen!");
+                doze_status = DOZE_WAKEUP;
+                input_report_key(ts->input_dev, KEY_POWER, 1);
+                input_sync(ts->input_dev);
+                input_report_key(ts->input_dev, KEY_POWER, 0);
+                input_sync(ts->input_dev);
+                // clear 0x814B
+                doze_buf[2] = 0x00;
+                gtp_i2c_write(i2c_connect_client, doze_buf, 3);
+            }
+            else
+            {
+                gtp_enter_doze(ts);
+            }
+        }
+        if (ts->use_irq)
+        {
+            gtp_irq_enable(ts);
+        }
+        return;
+    }
+#endif
+
+    ret = gtp_i2c_read(ts->client, point_data, 12);
+    if (ret < 0)
+    {
+        GTP_ERROR("I2C transfer error. errno:%d\n ", ret);
+        goto exit_work_func;
+    }
+
+    finger = point_data[GTP_ADDR_LENGTH];    
+    if((finger & 0x80) == 0)
+    {
+        goto exit_work_func;
+    }
+
+    touch_num = finger & 0x0f;
+    if (touch_num > GTP_MAX_TOUCH)
+    {
+        goto exit_work_func;
+    }
+
+    if (touch_num > 1)
+    {
+        u8 buf[8 * GTP_MAX_TOUCH] = {(GTP_READ_COOR_ADDR + 10) >> 8, (GTP_READ_COOR_ADDR + 10) & 0xff};
+
+        ret = gtp_i2c_read(ts->client, buf, 2 + 8 * (touch_num - 1)); 
+        memcpy(&point_data[12], &buf[2], 8 * (touch_num - 1));
+    }
+
+#if GTP_HAVE_TOUCH_KEY
+    key_value = point_data[3 + 8 * touch_num];
+    
+    if(key_value || pre_key)
+    {
+        for (i = 0; i < GTP_MAX_KEY_NUM; i++)
+        {
+        #if GTP_DEBUG_ON
+            for (ret = 0; ret < 4; ++ret)
+            {
+                if (key_codes[ret] == touch_key_array[i])
+                {
+                    GTP_DEBUG("Key: %s %s", key_names[ret], (key_value & (0x01 << i)) ? "Down" : "Up");
+                    break;
+                }
+            }
+        #endif
+            input_report_key(ts->input_dev, touch_key_array[i], key_value & (0x01<<i));   
+        }
+        touch_num = 0;
+        pre_touch = 0;
+    }
+#endif
+    pre_key = key_value;
+
+    GTP_DEBUG("pre_touch:%02x, finger:%02x.", pre_touch, finger);
+
+#if GTP_ICS_SLOT_REPORT
+
+#if GTP_WITH_PEN
+    if (pre_pen && (touch_num == 0))
+    {
+        GTP_DEBUG("Pen touch UP(Slot)!");
+        input_report_key(ts->input_dev, BTN_TOOL_PEN, 0);
+        input_mt_slot(ts->input_dev, 5);
+        input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1);
+        pre_pen = 0;
+    }
+#endif
+    if (pre_touch || touch_num)
+    {
+        s32 pos = 0;
+        u16 touch_index = 0;
+
+        coor_data = &point_data[3];
+        
+        if(touch_num)
+        {
+            id = coor_data[pos] & 0x0F;
+        
+        #if GTP_WITH_PEN
+            id = coor_data[pos];
+            if ((id == 128))  
+            {
+                GTP_DEBUG("Pen touch DOWN(Slot)!");
+                input_x  = coor_data[pos + 1] | (coor_data[pos + 2] << 8);
+                input_y  = coor_data[pos + 3] | (coor_data[pos + 4] << 8);
+                input_w  = coor_data[pos + 5] | (coor_data[pos + 6] << 8);
+                
+                input_report_key(ts->input_dev, BTN_TOOL_PEN, 1);
+                input_mt_slot(ts->input_dev, 5);
+                input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 5);
+                input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x);
+                input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y);
+                input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w);
+                GTP_DEBUG("Pen/Stylus: (%d, %d)[%d]", input_x, input_y, input_w);
+                pre_pen = 1;
+                pre_touch = 0;
+            }    
+        #endif
+        
+            touch_index |= (0x01<<id);
+        }
+        
+        GTP_DEBUG("id = %d,touch_index = 0x%x, pre_touch = 0x%x\n",id, touch_index,pre_touch);
+        for (i = 0; i < GTP_MAX_TOUCH; i++)
+        {
+        #if GTP_WITH_PEN
+            if (pre_pen == 1)
+            {
+                break;
+            }
+        #endif
+        
+            if (touch_index & (0x01<<i))
+            {
+                input_x  = coor_data[pos + 1] | (coor_data[pos + 2] << 8);
+                input_y  = coor_data[pos + 3] | (coor_data[pos + 4] << 8);
+                input_w  = coor_data[pos + 5] | (coor_data[pos + 6] << 8);
+
+                gtp_touch_down(ts, id, input_x, input_y, input_w);
+                pre_touch |= 0x01 << i;
+                
+                pos += 8;
+                id = coor_data[pos] & 0x0F;
+                touch_index |= (0x01<<id);
+            }
+            else
+            {
+                gtp_touch_up(ts, i);
+                pre_touch &= ~(0x01 << i);
+            }
+        }
+    }
+#else
+    input_report_key(ts->input_dev, BTN_TOUCH, (touch_num || key_value));
+    if (touch_num)
+    {
+        for (i = 0; i < touch_num; i++)
+        {
+            coor_data = &point_data[i * 8 + 3];
+
+            id = coor_data[0];      //  & 0x0F;
+            input_x  = coor_data[1] | (coor_data[2] << 8);
+            input_y  = coor_data[3] | (coor_data[4] << 8);
+            input_w  = coor_data[5] | (coor_data[6] << 8);
+        
+        #if GTP_WITH_PEN
+            if (id == 128)
+            {
+                GTP_DEBUG("Pen touch DOWN!");
+                input_report_key(ts->input_dev, BTN_TOOL_PEN, 1);
+                pre_pen = 1;
+                id = 0;   
+            }
+        #endif
+        
+            gtp_touch_down(ts, id, input_x, input_y, input_w);
+        }
+    }
+    else if (pre_touch)
+    {
+    
+    #if GTP_WITH_PEN
+        if (pre_pen == 1)
+        {
+            GTP_DEBUG("Pen touch UP!");
+            input_report_key(ts->input_dev, BTN_TOOL_PEN, 0);
+            pre_pen = 0;
+        }
+    #endif
+    
+        GTP_DEBUG("Touch Release!");
+        gtp_touch_up(ts, 0);
+    }
+
+    pre_touch = touch_num;
+#endif
+
+    input_sync(ts->input_dev);
+
+exit_work_func:
+    if(!ts->gtp_rawdiff_mode)
+    {
+        ret = gtp_i2c_write(ts->client, end_cmd, 3);
+        if (ret < 0)
+        {
+            GTP_INFO("I2C write end_cmd error!");
+        }
+    }
+    if (ts->use_irq)
+    {
+        gtp_irq_enable(ts);
+    }
+}
+
+/*******************************************************
+Function:
+    Timer interrupt service routine for polling mode.
+Input:
+    timer: timer struct pointer
+Output:
+    Timer work mode. 
+        HRTIMER_NORESTART: no restart mode
+*********************************************************/
+static enum hrtimer_restart goodix_ts_timer_handler(struct hrtimer *timer)
+{
+    struct goodix_ts_data *ts = container_of(timer, struct goodix_ts_data, timer);
+
+    GTP_DEBUG_FUNC();
+
+    queue_work(goodix_wq, &ts->work);
+    hrtimer_start(&ts->timer, ktime_set(0, (GTP_POLL_TIME+6)*1000000), HRTIMER_MODE_REL);
+    return HRTIMER_NORESTART;
+}
+
+/*******************************************************
+Function:
+    External interrupt service routine for interrupt mode.
+Input:
+    irq:  interrupt number.
+    dev_id: private data pointer
+Output:
+    Handle Result.
+        IRQ_HANDLED: interrupt handled successfully
+*********************************************************/
+static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id)
+{
+    struct goodix_ts_data *ts = dev_id;
+
+    GTP_DEBUG_FUNC();
+    gtp_irq_disable(ts);
+
+    queue_work(goodix_wq, &ts->work);
+    
+    return IRQ_HANDLED;
+}
+/*******************************************************
+Function:
+    Synchronization.
+Input:
+    ms: synchronization time in millisecond.
+Output:
+    None.
+*******************************************************/
+void gtp_int_sync(s32 ms)
+{
+    GTP_GPIO_OUTPUT(GTP_INT_PORT, 0);
+    msleep(ms);
+    GTP_GPIO_AS_INT(GTP_INT_PORT);
+}
+
+/*******************************************************
+Function:
+    Reset chip.
+Input:
+    ms: reset time in millisecond
+Output:
+    None.
+*******************************************************/
+void gtp_reset_guitar(struct i2c_client *client, s32 ms)
+{
+    GTP_DEBUG_FUNC();
+
+    GTP_GPIO_OUTPUT(GTP_RST_PORT, 0);   // begin select I2C slave addr
+    msleep(ms);                         // T2: > 10ms
+    // HIGH: 0x28/0x29, LOW: 0xBA/0xBB
+    GTP_GPIO_OUTPUT(GTP_INT_PORT, client->addr == 0x14);
+
+    msleep(2);                          // T3: > 100us
+    GTP_GPIO_OUTPUT(GTP_RST_PORT, 1);
+    
+    msleep(6);                          // T4: > 5ms
+
+    GTP_GPIO_AS_INPUT(GTP_RST_PORT);    // end select I2C slave addr
+
+    gtp_int_sync(50);                  
+    
+#if GTP_ESD_PROTECT
+    gtp_init_ext_watchdog(client);
+#endif
+}
+
+#if GTP_SLIDE_WAKEUP
+/*******************************************************
+Function:
+    Enter doze mode for sliding wakeup.
+Input:
+    ts: goodix tp private data
+Output:
+    1: succeed, otherwise failed
+*******************************************************/
+static s8 gtp_enter_doze(struct goodix_ts_data *ts)
+{
+    s8 ret = -1;
+    s8 retry = 0;
+    u8 i2c_control_buf[3] = {(u8)(GTP_REG_SLEEP >> 8), (u8)GTP_REG_SLEEP, 8};
+
+    GTP_DEBUG_FUNC();
+
+#if GTP_DBL_CLK_WAKEUP
+    i2c_control_buf[2] = 0x09;
+#endif
+
+    gtp_irq_disable(ts);
+    
+    GTP_DEBUG("entering doze mode...");
+    while(retry++ < 5)
+    {
+        i2c_control_buf[0] = 0x80;
+        i2c_control_buf[1] = 0x46;
+        ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
+        if (ret < 0)
+        {
+            GTP_DEBUG("failed to set doze flag into 0x8046, %d", retry);
+            continue;
+        }
+        i2c_control_buf[0] = 0x80;
+        i2c_control_buf[1] = 0x40;
+        ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
+        if (ret > 0)
+        {
+            doze_status = DOZE_ENABLED;
+            GTP_INFO("GTP has been working in doze mode!");
+            gtp_irq_enable(ts);
+            return ret;
+        }
+        msleep(10);
+    }
+    GTP_ERROR("GTP send doze cmd failed.");
+    gtp_irq_enable(ts);
+    return ret;
+}
+#else 
+/*******************************************************
+Function:
+    Enter sleep mode.
+Input:
+    ts: private data.
+Output:
+    Executive outcomes.
+       1: succeed, otherwise failed.
+*******************************************************/
+static s8 gtp_enter_sleep(struct goodix_ts_data * ts)
+{
+    s8 ret = -1;
+    s8 retry = 0;
+    u8 i2c_control_buf[3] = {(u8)(GTP_REG_SLEEP >> 8), (u8)GTP_REG_SLEEP, 5};
+
+    GTP_DEBUG_FUNC();
+    
+    GTP_GPIO_OUTPUT(GTP_INT_PORT, 0);
+    msleep(5);
+    
+    while(retry++ < 5)
+    {
+        ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
+        if (ret > 0)
+        {
+            GTP_INFO("GTP enter sleep!");
+            
+            return ret;
+        }
+        msleep(10);
+    }
+    GTP_ERROR("GTP send sleep cmd failed.");
+    return ret;
+}
+#endif 
+/*******************************************************
+Function:
+    Wakeup from sleep.
+Input:
+    ts: private data.
+Output:
+    Executive outcomes.
+        >0: succeed, otherwise: failed.
+*******************************************************/
+static s8 gtp_wakeup_sleep(struct goodix_ts_data * ts)
+{
+    u8 retry = 0;
+    s8 ret = -1;
+    
+    GTP_DEBUG_FUNC();
+    
+#if GTP_POWER_CTRL_SLEEP
+    while(retry++ < 5)
+    {
+        gtp_reset_guitar(ts->client, 20);
+        
+        ret = gtp_send_cfg(ts->client);
+        if (ret < 0)
+        {
+            GTP_INFO("Wakeup sleep send config failed!");
+            continue;
+        }
+        GTP_INFO("GTP wakeup sleep");
+        return 1;
+    }
+#else
+    while(retry++ < 10)
+    {
+    #if GTP_SLIDE_WAKEUP
+        if (DOZE_WAKEUP != doze_status)       // wakeup not by slide 
+        {
+            gtp_reset_guitar(ts->client, 10);
+        }
+        else              // wakeup by slide 
+        {
+            doze_status = DOZE_DISABLED;
+        }
+    #else
+        if (chip_gt9xxs == 1)
+        {
+           gtp_reset_guitar(ts->client, 10);
+        }
+        else
+        {
+            GTP_GPIO_OUTPUT(GTP_INT_PORT, 1);
+            msleep(5);
+        }
+    #endif
+        ret = gtp_i2c_test(ts->client);
+        if (ret > 0)
+        {
+            GTP_INFO("GTP wakeup sleep.");
+            
+        #if (!GTP_SLIDE_WAKEUP)
+            if (chip_gt9xxs == 0)
+            {
+                gtp_int_sync(25);
+                msleep(20);
+            #if GTP_ESD_PROTECT
+                gtp_init_ext_watchdog(ts->client);
+            #endif
+            }
+        #endif
+            return ret;
+        }
+        gtp_reset_guitar(ts->client, 20);
+    }
+#endif
+
+    GTP_ERROR("GTP wakeup sleep failed.");
+    return ret;
+}
+
+/*******************************************************
+Function:
+    Initialize gtp.
+Input:
+    ts: goodix private data
+Output:
+    Executive outcomes.
+        0: succeed, otherwise: failed
+*******************************************************/
+static s32 gtp_init_panel(struct goodix_ts_data *ts)
+{
+    s32 ret = -1;
+
+#if GTP_DRIVER_SEND_CFG
+    s32 i;
+    u8 check_sum = 0;
+    u8 opr_buf[16];
+    u8 sensor_id = 0;
+
+    u8 cfg_info_group1[] = CTP_CFG_GROUP1;
+    u8 cfg_info_group2[] = CTP_CFG_GROUP2;
+    u8 cfg_info_group3[] = CTP_CFG_GROUP3;
+    u8 cfg_info_group4[] = CTP_CFG_GROUP4;
+    u8 cfg_info_group5[] = CTP_CFG_GROUP5;
+    u8 cfg_info_group6[] = CTP_CFG_GROUP6;
+    u8 *send_cfg_buf[] = {cfg_info_group1, cfg_info_group2, cfg_info_group3,
+                        cfg_info_group4, cfg_info_group5, cfg_info_group6};
+    u8 cfg_info_len[] = { CFG_GROUP_LEN(cfg_info_group1),
+                          CFG_GROUP_LEN(cfg_info_group2),
+                          CFG_GROUP_LEN(cfg_info_group3),
+                          CFG_GROUP_LEN(cfg_info_group4),
+                          CFG_GROUP_LEN(cfg_info_group5),
+                          CFG_GROUP_LEN(cfg_info_group6)};
+
+    GTP_DEBUG("Config Groups\' Lengths: %d, %d, %d, %d, %d, %d", 
+        cfg_info_len[0], cfg_info_len[1], cfg_info_len[2], cfg_info_len[3],
+        cfg_info_len[4], cfg_info_len[5]);
+
+    ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1);
+    if (SUCCESS == ret) 
+    {
+        if (opr_buf[0] != 0xBE)
+        {
+            ts->fw_error = 1;
+            GTP_ERROR("Firmware error, no config sent!");
+            return -1;
+        }
+    }
+
+    if ((!cfg_info_len[1]) && (!cfg_info_len[2]) && 
+        (!cfg_info_len[3]) && (!cfg_info_len[4]) && 
+        (!cfg_info_len[5]))
+    {
+        sensor_id = 0; 
+    }
+    else
+    {
+        ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID, &sensor_id, 1);
+        if (SUCCESS == ret)
+        {
+            if (sensor_id >= 0x06)
+            {
+                GTP_ERROR("Invalid sensor_id(0x%02X), No Config Sent!", sensor_id);
+                return -1;
+            }
+        }
+        else
+        {
+            GTP_ERROR("Failed to get sensor_id, No config sent!");
+            return -1;
+        }
+    }
+    GTP_DEBUG("Sensor_ID: %d", sensor_id);
+    
+    ts->gtp_cfg_len = cfg_info_len[sensor_id];
+    
+    if (ts->gtp_cfg_len < GTP_CONFIG_MIN_LENGTH)
+    {
+        GTP_ERROR("Sensor_ID(%d) matches with NULL or INVALID CONFIG GROUP! NO Config Sent! You need to check you header file CFG_GROUP section!", sensor_id);
+        return -1;
+    }
+    
+    ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA, &opr_buf[0], 1);
+    
+    if (ret == SUCCESS)
+    {
+        GTP_DEBUG("CFG_GROUP%d Config Version: %d, 0x%02X; IC Config Version: %d, 0x%02X", sensor_id+1, 
+                    send_cfg_buf[sensor_id][0], send_cfg_buf[sensor_id][0], opr_buf[0], opr_buf[0]);
+        
+        if (opr_buf[0] < 90)    
+        {
+            grp_cfg_version = send_cfg_buf[sensor_id][0];       // backup group config version
+            send_cfg_buf[sensor_id][0] = 0x00;
+            ts->fixed_cfg = 0;
+        }
+        else        // treated as fixed config, not send config
+        {
+            GTP_INFO("Ic fixed config with config version(%d, 0x%02X)", opr_buf[0], opr_buf[0]);
+            ts->fixed_cfg = 1;
+        }
+    }
+    else
+    {
+        GTP_ERROR("Failed to get ic config version!No config sent!");
+        return -1;
+    }
+    
+    memset(&config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
+    memcpy(&config[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id], ts->gtp_cfg_len);
+
+#if GTP_CUSTOM_CFG
+    config[RESOLUTION_LOC]     = (u8)GTP_MAX_WIDTH;
+    config[RESOLUTION_LOC + 1] = (u8)(GTP_MAX_WIDTH>>8);
+    config[RESOLUTION_LOC + 2] = (u8)GTP_MAX_HEIGHT;
+    config[RESOLUTION_LOC + 3] = (u8)(GTP_MAX_HEIGHT>>8);
+    
+    if (GTP_INT_TRIGGER == 0)  //RISING
+    {
+        config[TRIGGER_LOC] &= 0xfe; 
+    }
+    else if (GTP_INT_TRIGGER == 1)  //FALLING
+    {
+        config[TRIGGER_LOC] |= 0x01;
+    }
+#endif  // GTP_CUSTOM_CFG
+    
+    check_sum = 0;
+    for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++)
+    {
+        check_sum += config[i];
+    }
+    config[ts->gtp_cfg_len] = (~check_sum) + 1;
+    
+#else // DRIVER NOT SEND CONFIG
+    ts->gtp_cfg_len = GTP_CONFIG_MAX_LENGTH;
+    ret = gtp_i2c_read(ts->client, config, ts->gtp_cfg_len + GTP_ADDR_LENGTH);
+    if (ret < 0)
+    {
+        GTP_ERROR("Read Config Failed, Using Default Resolution & INT Trigger!");
+        ts->abs_x_max = GTP_MAX_WIDTH;
+        ts->abs_y_max = GTP_MAX_HEIGHT;
+        ts->int_trigger_type = GTP_INT_TRIGGER;
+    }
+#endif // GTP_DRIVER_SEND_CFG
+
+    GTP_DEBUG_FUNC();
+    if ((ts->abs_x_max == 0) && (ts->abs_y_max == 0))
+    {
+        ts->abs_x_max = (config[RESOLUTION_LOC + 1] << 8) + config[RESOLUTION_LOC];
+        ts->abs_y_max = (config[RESOLUTION_LOC + 3] << 8) + config[RESOLUTION_LOC + 2];
+        ts->int_trigger_type = (config[TRIGGER_LOC]) & 0x03; 
+    }
+    ret = gtp_send_cfg(ts->client);
+    if (ret < 0)
+    {
+        GTP_ERROR("Send config error.");
+    }
+    GTP_DEBUG("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x",
+        ts->abs_x_max,ts->abs_y_max,ts->int_trigger_type);
+
+    msleep(10);
+    return 0;
+}
+
+/*******************************************************
+Function:
+    Read chip version.
+Input:
+    client:  i2c device
+    version: buffer to keep ic firmware version
+Output:
+    read operation return.
+        2: succeed, otherwise: failed
+*******************************************************/
+s32 gtp_read_version(struct i2c_client *client, u16* version)
+{
+    s32 ret = -1;
+    u8 buf[8] = {GTP_REG_VERSION >> 8, GTP_REG_VERSION & 0xff};
+
+    GTP_DEBUG_FUNC();
+
+    ret = gtp_i2c_read(client, buf, sizeof(buf));
+    if (ret < 0)
+    {
+        GTP_ERROR("GTP read version failed");
+        return ret;
+    }
+
+    if (version)
+    {
+        *version = (buf[7] << 8) | buf[6];
+    }
+    
+    if (buf[5] == 0x00)
+    {
+        GTP_INFO("IC Version: %c%c%c_%02x%02x", buf[2], buf[3], buf[4], buf[7], buf[6]);
+    }
+    else
+    {
+        if (buf[5] == 'S' || buf[5] == 's')
+        {
+            chip_gt9xxs = 1;
+        }
+        GTP_INFO("IC Version: %c%c%c%c_%02x%02x", buf[2], buf[3], buf[4], buf[5], buf[7], buf[6]);
+    }
+    return ret;
+}
+
+/*******************************************************
+Function:
+    I2c test Function.
+Input:
+    client:i2c client.
+Output:
+    Executive outcomes.
+        2: succeed, otherwise failed.
+*******************************************************/
+static s8 gtp_i2c_test(struct i2c_client *client)
+{
+    u8 test[3] = {GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff};
+    u8 retry = 0;
+    s8 ret = -1;
+  
+    GTP_DEBUG_FUNC();
+  
+    while(retry++ < 5)
+    {
+        ret = gtp_i2c_read(client, test, 3);
+        if (ret > 0)
+        {
+            return ret;
+        }
+        GTP_ERROR("GTP i2c test failed time %d.",retry);
+        msleep(10);
+    }
+    return ret;
+}
+
+/*******************************************************
+Function:
+    Request gpio(INT & RST) ports.
+Input:
+    ts: private data.
+Output:
+    Executive outcomes.
+        >= 0: succeed, < 0: failed
+*******************************************************/
+static s8 gtp_request_io_port(struct goodix_ts_data *ts)
+{
+    s32 ret = 0;
+
+    ret = GTP_GPIO_REQUEST(GTP_INT_PORT, "GTP_INT_IRQ");
+    if (ret < 0) 
+    {
+        GTP_ERROR("Failed to request GPIO:%d, ERRNO:%d", (s32)GTP_INT_PORT, ret);
+        ret = -ENODEV;
+    }
+    else
+    {
+        GTP_GPIO_AS_INT(GTP_INT_PORT);  
+        ts->client->irq = GTP_INT_IRQ;
+    }
+
+    ret = GTP_GPIO_REQUEST(GTP_RST_PORT, "GTP_RST_PORT");
+    if (ret < 0) 
+    {
+        GTP_ERROR("Failed to request GPIO:%d, ERRNO:%d",(s32)GTP_RST_PORT,ret);
+        ret = -ENODEV;
+    }
+
+    GTP_GPIO_AS_INPUT(GTP_RST_PORT);
+    gtp_reset_guitar(ts->client, 20);
+
+    
+    if(ret < 0)
+    {
+        GTP_GPIO_FREE(GTP_RST_PORT);
+        GTP_GPIO_FREE(GTP_INT_PORT);
+    }
+
+    return ret;
+}
+
+/*******************************************************
+Function:
+    Request interrupt.
+Input:
+    ts: private data.
+Output:
+    Executive outcomes.
+        0: succeed, -1: failed.
+*******************************************************/
+static s8 gtp_request_irq(struct goodix_ts_data *ts)
+{
+    s32 ret = -1;
+    const u8 irq_table[] = GTP_IRQ_TAB;
+
+    GTP_DEBUG("INT trigger type:%x", ts->int_trigger_type);
+
+    ret  = request_irq(ts->client->irq, 
+                       goodix_ts_irq_handler,
+                       irq_table[ts->int_trigger_type],
+                       ts->client->name,
+                       ts);
+    if (ret)
+    {
+        GTP_ERROR("Request IRQ failed!ERRNO:%d.", ret);
+        GTP_GPIO_AS_INPUT(GTP_INT_PORT);
+        GTP_GPIO_FREE(GTP_INT_PORT);
+
+        hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+        ts->timer.function = goodix_ts_timer_handler;
+        hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+        return -1;
+    }
+    else 
+    {
+        gtp_irq_disable(ts);
+        ts->use_irq = 1;
+        return 0;
+    }
+}
+
+/*******************************************************
+Function:
+    Request input device Function.
+Input:
+    ts:private data.
+Output:
+    Executive outcomes.
+        0: succeed, otherwise: failed.
+*******************************************************/
+static s8 gtp_request_input_dev(struct goodix_ts_data *ts)
+{
+    s8 ret = -1;
+    s8 phys[32];
+#if GTP_HAVE_TOUCH_KEY
+    u8 index = 0;
+#endif
+  
+    GTP_DEBUG_FUNC();
+  
+    ts->input_dev = input_allocate_device();
+    if (ts->input_dev == NULL)
+    {
+        GTP_ERROR("Failed to allocate input device.");
+        return -ENOMEM;
+    }
+
+    ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ;
+#if GTP_ICS_SLOT_REPORT
+    __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+    input_mt_init_slots(ts->input_dev, 10);     // in case of "out of memory"
+#else
+    ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+#endif
+
+#if GTP_HAVE_TOUCH_KEY
+    for (index = 0; index < GTP_MAX_KEY_NUM; index++)
+    {
+        input_set_capability(ts->input_dev, EV_KEY, touch_key_array[index]);  
+    }
+#endif
+
+#if GTP_SLIDE_WAKEUP
+    input_set_capability(ts->input_dev, EV_KEY, KEY_POWER);
+#endif 
+
+#if GTP_WITH_PEN
+    // pen support
+    __set_bit(BTN_TOOL_PEN, ts->input_dev->keybit);
+    __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+    __set_bit(INPUT_PROP_POINTER, ts->input_dev->propbit);
+#endif
+
+#if GTP_CHANGE_X2Y
+    GTP_SWAP(ts->abs_x_max, ts->abs_y_max);
+#endif
+
+    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, ts->abs_x_max, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, ts->abs_y_max, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, 255, 0, 0);
+
+    sprintf(phys, "input/ts");
+    ts->input_dev->name = goodix_ts_name;
+    ts->input_dev->phys = phys;
+    ts->input_dev->id.bustype = BUS_I2C;
+    ts->input_dev->id.vendor = 0xDEAD;
+    ts->input_dev->id.product = 0xBEEF;
+    ts->input_dev->id.version = 10427;
+    
+    ret = input_register_device(ts->input_dev);
+    if (ret)
+    {
+        GTP_ERROR("Register %s input device failed", ts->input_dev->name);
+        return -ENODEV;
+    }
+    
+#ifdef CONFIG_HAS_EARLYSUSPEND
+    ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+    ts->early_suspend.suspend = goodix_ts_early_suspend;
+    ts->early_suspend.resume = goodix_ts_late_resume;
+    register_early_suspend(&ts->early_suspend);
+#endif
+
+    return 0;
+}
+
+/*******************************************************
+Function:
+    I2c probe.
+Input:
+    client: i2c device struct.
+    id: device id.
+Output:
+    Executive outcomes. 
+        0: succeed.
+*******************************************************/
+static int goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+    s32 ret = -1;
+    struct goodix_ts_data *ts;
+    u16 version_info;
+
+    GTP_DEBUG_FUNC();
+    
+    //do NOT remove these logs
+    GTP_INFO("GTP Driver Version: %s", GTP_DRIVER_VERSION);
+    GTP_INFO("GTP Driver Built@%s, %s", __TIME__, __DATE__);
+    GTP_INFO("GTP I2C Address: 0x%02x", client->addr);
+
+    i2c_connect_client = client;
+    
+    if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) 
+    {
+        GTP_ERROR("I2C check functionality failed.");
+        return -ENODEV;
+    }
+    ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+    if (ts == NULL)
+    {
+        GTP_ERROR("Alloc GFP_KERNEL memory failed.");
+        return -ENOMEM;
+    }
+   
+    memset(ts, 0, sizeof(*ts));
+    INIT_WORK(&ts->work, goodix_ts_work_func);
+    ts->client = client;
+    spin_lock_init(&ts->irq_lock);          // 2.6.39 later
+    // ts->irq_lock = SPIN_LOCK_UNLOCKED;   // 2.6.39 & before
+    i2c_set_clientdata(client, ts);
+    
+    ts->gtp_rawdiff_mode = 0;
+
+    ret = gtp_request_io_port(ts);
+    if (ret < 0)
+    {
+        GTP_ERROR("GTP request IO port failed.");
+        kfree(ts);
+        return ret;
+    }
+
+    ret = gtp_i2c_test(client);
+    if (ret < 0)
+    {
+        GTP_ERROR("I2C communication ERROR!");
+    }
+
+#if GTP_AUTO_UPDATE
+    ret = gup_init_update_proc(ts);
+    if (ret < 0)
+    {
+        GTP_ERROR("Create update thread error.");
+    }
+#endif
+    
+    ret = gtp_init_panel(ts);
+    if (ret < 0)
+    {
+        GTP_ERROR("GTP init panel failed.");
+        ts->abs_x_max = GTP_MAX_WIDTH;
+        ts->abs_y_max = GTP_MAX_HEIGHT;
+        ts->int_trigger_type = GTP_INT_TRIGGER;
+    }
+
+    ret = gtp_request_input_dev(ts);
+    if (ret < 0)
+    {
+        GTP_ERROR("GTP request input dev failed");
+    }
+    
+    ret = gtp_request_irq(ts); 
+    if (ret < 0)
+    {
+        GTP_INFO("GTP works in polling mode.");
+    }
+    else
+    {
+        GTP_INFO("GTP works in interrupt mode.");
+    }
+
+    ret = gtp_read_version(client, &version_info);
+    if (ret < 0)
+    {
+        GTP_ERROR("Read version failed.");
+    }
+    if (ts->use_irq)
+    {
+        gtp_irq_enable(ts);
+    }
+    
+#if GTP_CREATE_WR_NODE
+    init_wr_node(client);
+#endif
+    
+#if GTP_ESD_PROTECT
+    gtp_esd_switch(client, SWITCH_ON);
+#endif
+    return 0;
+}
+
+
+/*******************************************************
+Function:
+    Goodix touchscreen driver release function.
+Input:
+    client: i2c device struct.
+Output:
+    Executive outcomes. 0---succeed.
+*******************************************************/
+static int goodix_ts_remove(struct i2c_client *client)
+{
+    struct goodix_ts_data *ts = i2c_get_clientdata(client);
+    
+    GTP_DEBUG_FUNC();
+    
+#ifdef CONFIG_HAS_EARLYSUSPEND
+    unregister_early_suspend(&ts->early_suspend);
+#endif
+
+#if GTP_CREATE_WR_NODE
+    uninit_wr_node();
+#endif
+
+#if GTP_ESD_PROTECT
+    destroy_workqueue(gtp_esd_check_workqueue);
+#endif
+
+    if (ts) 
+    {
+        if (ts->use_irq)
+        {
+            GTP_GPIO_AS_INPUT(GTP_INT_PORT);
+            GTP_GPIO_FREE(GTP_INT_PORT);
+            free_irq(client->irq, ts);
+        }
+        else
+        {
+            hrtimer_cancel(&ts->timer);
+        }
+    }   
+    
+    GTP_INFO("GTP driver removing...");
+    i2c_set_clientdata(client, NULL);
+    input_unregister_device(ts->input_dev);
+    kfree(ts);
+
+    return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+/*******************************************************
+Function:
+    Early suspend function.
+Input:
+    h: early_suspend struct.
+Output:
+    None.
+*******************************************************/
+static void goodix_ts_early_suspend(struct early_suspend *h)
+{
+    struct goodix_ts_data *ts;
+    s8 ret = -1;    
+    ts = container_of(h, struct goodix_ts_data, early_suspend);
+    
+    GTP_DEBUG_FUNC();
+
+#if GTP_ESD_PROTECT
+    ts->gtp_is_suspend = 1;
+    gtp_esd_switch(ts->client, SWITCH_OFF);
+#endif
+
+#if GTP_SLIDE_WAKEUP
+    ret = gtp_enter_doze(ts);
+#else
+    if (ts->use_irq)
+    {
+        gtp_irq_disable(ts);
+    }
+    else
+    {
+        hrtimer_cancel(&ts->timer);
+    }
+    ret = gtp_enter_sleep(ts);
+#endif 
+    if (ret < 0)
+    {
+        GTP_ERROR("GTP early suspend failed.");
+    }
+    // to avoid waking up while not sleeping
+    //  delay 48 + 10ms to ensure reliability    
+    msleep(58);   
+}
+
+/*******************************************************
+Function:
+    Late resume function.
+Input:
+    h: early_suspend struct.
+Output:
+    None.
+*******************************************************/
+static void goodix_ts_late_resume(struct early_suspend *h)
+{
+    struct goodix_ts_data *ts;
+    s8 ret = -1;
+    ts = container_of(h, struct goodix_ts_data, early_suspend);
+    
+    GTP_DEBUG_FUNC();
+    
+    ret = gtp_wakeup_sleep(ts);
+
+#if GTP_SLIDE_WAKEUP
+    doze_status = DOZE_DISABLED;
+#endif
+
+    if (ret < 0)
+    {
+        GTP_ERROR("GTP later resume failed.");
+    }
+
+    if (ts->use_irq)
+    {
+        gtp_irq_enable(ts);
+    }
+    else
+    {
+        hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+    }
+
+#if GTP_ESD_PROTECT
+    ts->gtp_is_suspend = 0;
+    gtp_esd_switch(ts->client, SWITCH_ON);
+#endif
+}
+#endif
+
+#if GTP_ESD_PROTECT
+/*******************************************************
+Function:
+    switch on & off esd delayed work
+Input:
+    client:  i2c device
+    on:      SWITCH_ON / SWITCH_OFF
+Output:
+    void
+*********************************************************/
+void gtp_esd_switch(struct i2c_client *client, s32 on)
+{
+    struct goodix_ts_data *ts;
+    
+    ts = i2c_get_clientdata(client);
+    if (SWITCH_ON == on)     // switch on esd 
+    {
+        if (!ts->esd_running)
+        {
+            ts->esd_running = 1;
+            GTP_INFO("Esd started");
+            queue_delayed_work(gtp_esd_check_workqueue, &gtp_esd_check_work, GTP_ESD_CHECK_CIRCLE);
+        }
+    }
+    else    // switch off esd
+    {
+        if (ts->esd_running)
+        {
+            ts->esd_running = 0;
+            GTP_INFO("Esd cancelled");
+            cancel_delayed_work_sync(&gtp_esd_check_work);
+        }
+    }
+}
+
+/*******************************************************
+Function:
+    Initialize external watchdog for esd protect
+Input:
+    client:  i2c device.
+Output:
+    result of i2c write operation. 
+        1: succeed, otherwise: failed
+*********************************************************/
+static s32 gtp_init_ext_watchdog(struct i2c_client *client)
+{
+    u8 opr_buffer[4] = {0x80, 0x40, 0xAA, 0xAA};
+    
+    struct i2c_msg msg;         // in case of recursively reset by calling gtp_i2c_write
+    s32 ret = -1;
+    s32 retries = 0;
+
+    GTP_DEBUG("Init external watchdog...");
+    GTP_DEBUG_FUNC();
+
+    msg.flags = !I2C_M_RD;
+    msg.addr  = client->addr;
+    msg.len   = 4;
+    msg.buf   = opr_buffer;
+
+    while(retries < 5)
+    {
+        ret = i2c_transfer(client->adapter, &msg, 1);
+        if (ret == 1)
+        {
+            return 1;
+        }
+        retries++;
+    }
+    if (retries >= 5)
+    {
+        GTP_ERROR("init external watchdog failed!");
+    }
+    return 0;
+}
+
+/*******************************************************
+Function:
+    Esd protect function.
+    Added external watchdog by meta, 2013/03/07
+Input:
+    work: delayed work
+Output:
+    None.
+*******************************************************/
+static void gtp_esd_check_func(struct work_struct *work)
+{
+    s32 i;
+    s32 ret = -1;
+    struct goodix_ts_data *ts = NULL;
+    u8 test[4] = {0x80, 0x40};
+    
+    GTP_DEBUG_FUNC();
+   
+    ts = i2c_get_clientdata(i2c_connect_client);
+
+    if (ts->gtp_is_suspend)
+    {
+        ts->esd_running = 0;
+        GTP_INFO("Esd terminated!");
+        return;
+    }
+    
+    for (i = 0; i < 3; i++)
+    {
+        ret = gtp_i2c_read(ts->client, test, 4);
+        
+        GTP_DEBUG("0x8040 = 0x%02X, 0x8041 = 0x%02X", test[2], test[3]);
+        if ((ret < 0))
+        {
+            // IIC communication problem
+            continue;
+        }
+        else
+        { 
+            if ((test[2] == 0xAA) || (test[3] != 0xAA))
+            {
+                // IC works abnormally..
+                i = 3;
+                break;  
+            }
+            else 
+            {
+                // IC works normally, Write 0x8040 0xAA, feed the dog
+                test[2] = 0xAA; 
+                gtp_i2c_write(ts->client, test, 3);
+                break;
+            }
+        }
+    }
+    if (i >= 3)
+    {
+        GTP_ERROR("IC Working ABNORMALLY, Resetting Guitar...");
+        gtp_reset_guitar(ts->client, 50);
+    }
+
+    if(!ts->gtp_is_suspend)
+    {
+        queue_delayed_work(gtp_esd_check_workqueue, &gtp_esd_check_work, GTP_ESD_CHECK_CIRCLE);
+    }
+    else
+    {
+        GTP_INFO("Esd terminated!");
+        ts->esd_running = 0;
+    }
+    return;
+}
+#endif
+
+static const struct i2c_device_id goodix_ts_id[] = {
+    { GTP_I2C_NAME, 0 },
+    { }
+};
+
+static struct i2c_driver goodix_ts_driver = {
+    .probe      = goodix_ts_probe,
+    .remove     = goodix_ts_remove,
+#ifndef CONFIG_HAS_EARLYSUSPEND
+    .suspend    = goodix_ts_early_suspend,
+    .resume     = goodix_ts_late_resume,
+#endif
+    .id_table   = goodix_ts_id,
+    .driver = {
+        .name     = GTP_I2C_NAME,
+        .owner    = THIS_MODULE,
+    },
+};
+
+/*******************************************************    
+Function:
+    Driver Install function.
+Input:
+    None.
+Output:
+    Executive Outcomes. 0---succeed.
+********************************************************/
+static int __devinit goodix_ts_init(void)
+{
+    s32 ret;
+
+    GTP_DEBUG_FUNC();   
+    GTP_INFO("GTP driver installing...");
+    goodix_wq = create_singlethread_workqueue("goodix_wq");
+    if (!goodix_wq)
+    {
+        GTP_ERROR("Creat workqueue failed.");
+        return -ENOMEM;
+    }
+#if GTP_ESD_PROTECT
+    INIT_DELAYED_WORK(&gtp_esd_check_work, gtp_esd_check_func);
+    gtp_esd_check_workqueue = create_workqueue("gtp_esd_check");
+#endif
+    ret = i2c_add_driver(&goodix_ts_driver);
+    return ret; 
+}
+
+/*******************************************************    
+Function:
+    Driver uninstall function.
+Input:
+    None.
+Output:
+    Executive Outcomes. 0---succeed.
+********************************************************/
+static void __exit goodix_ts_exit(void)
+{
+    GTP_DEBUG_FUNC();
+    GTP_INFO("GTP driver exited.");
+    i2c_del_driver(&goodix_ts_driver);
+    if (goodix_wq)
+    {
+        destroy_workqueue(goodix_wq);
+    }
+}
+
+late_initcall(goodix_ts_init);
+module_exit(goodix_ts_exit);
+
+MODULE_DESCRIPTION("GTP Series Driver");
+MODULE_LICENSE("GPL");
diff --git a/input/touchscreen/gt9xx/gt9xx.h b/input/touchscreen/gt9xx/gt9xx.h
new file mode 100644 (file)
index 0000000..e375af5
--- /dev/null
@@ -0,0 +1,241 @@
+/* drivers/input/touchscreen/gt9xx.h
+ * 
+ * 2010 - 2013 Goodix Technology.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be a reference 
+ * to you, when you are integrating the GOODiX's CTP IC into your system, 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
+ * General Public License for more details.
+ * 
+ */
+
+#ifndef _GOODIX_GT9XX_H_
+#define _GOODIX_GT9XX_H_
+
+#include <linux/kernel.h>
+#include <linux/hrtimer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <asm/uaccess.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <mach/gpio.h>
+#include <linux/earlysuspend.h>
+
+struct goodix_ts_data {
+    spinlock_t irq_lock;
+    struct i2c_client *client;
+    struct input_dev  *input_dev;
+    struct hrtimer timer;
+    struct work_struct  work;
+    struct early_suspend early_suspend;
+    s32 irq_is_disable;
+    s32 use_irq;
+    u16 abs_x_max;
+    u16 abs_y_max;
+    u8  max_touch_num;
+    u8  int_trigger_type;
+    u8  green_wake_mode;
+    u8  chip_type;
+    u8  enter_update;
+    u8  gtp_is_suspend;
+    u8  gtp_rawdiff_mode;
+    u8  gtp_cfg_len;
+    u8  fixed_cfg;
+    u8  esd_running;
+    u8  fw_error;
+};
+
+extern u16 show_len;
+extern u16 total_len;
+
+//***************************PART1:ON/OFF define*******************************
+#define GTP_CUSTOM_CFG        0
+#define GTP_CHANGE_X2Y        0
+#define GTP_DRIVER_SEND_CFG   1
+#define GTP_HAVE_TOUCH_KEY    0
+#define GTP_POWER_CTRL_SLEEP  0
+#define GTP_ICS_SLOT_REPORT   0
+
+#define GTP_AUTO_UPDATE       1     // auto updated by .bin file as default
+#define GTP_HEADER_FW_UPDATE  0     // auto updated by head_fw_array in gt9xx_firmware.h, function together with GTP_AUTO_UPDATE
+                               
+#define GTP_CREATE_WR_NODE    1
+#define GTP_ESD_PROTECT       0
+#define GTP_WITH_PEN          0
+
+#define GTP_SLIDE_WAKEUP      0
+#define GTP_DBL_CLK_WAKEUP    0     // double-click wakeup, function together with GTP_SLIDE_WAKEUP
+
+#define GTP_DEBUG_ON          1
+#define GTP_DEBUG_ARRAY_ON    0
+#define GTP_DEBUG_FUNC_ON     0
+
+//*************************** PART2:TODO define **********************************
+// STEP_1(REQUIRED): Define Configuration Information Group(s)
+// Sensor_ID Map:
+/* sensor_opt1 sensor_opt2 Sensor_ID
+    GND         GND         0 
+    VDDIO       GND         1 
+    NC          GND         2 
+    GND         NC/300K     3 
+    VDDIO       NC/300K     4 
+    NC          NC/300K     5 
+*/
+// TODO: define your own default or for Sensor_ID == 0 config here. 
+// The predefined one is just a sample config, which is not suitable for your tp in most cases.
+#define CTP_CFG_GROUP1 {\
+    0x41,0x1C,0x02,0xC0,0x03,0x0A,0x05,0x01,0x01,0x0F,\
+    0x23,0x0F,0x5F,0x41,0x03,0x05,0x00,0x00,0x00,0x00,\
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x91,0x00,0x0A,\
+    0x28,0x00,0xB8,0x0B,0x00,0x00,0x00,0x9A,0x03,0x25,\
+    0x00,0x00,0x00,0x00,0x00,0x03,0x64,0x32,0x00,0x00,\
+    0x00,0x32,0x8C,0x94,0x05,0x01,0x05,0x00,0x00,0x96,\
+    0x0C,0x22,0xD8,0x0E,0x23,0x56,0x11,0x25,0xFF,0x13,\
+    0x28,0xA7,0x15,0x2E,0x00,0x00,0x10,0x30,0x48,0x00,\
+    0x56,0x4A,0x3A,0xFF,0xFF,0x16,0x00,0x00,0x00,0x00,\
+    0x00,0x01,0x1B,0x14,0x0D,0x19,0x00,0x00,0x01,0x00,\
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+    0x00,0x00,0x1A,0x18,0x16,0x14,0x12,0x10,0x0E,0x0C,\
+    0x0A,0x08,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\
+    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\
+    0xFF,0xFF,0x1D,0x1E,0x1F,0x20,0x22,0x24,0x28,0x29,\
+    0x0C,0x0A,0x08,0x00,0x02,0x04,0x05,0x06,0x0E,0xFF,\
+    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\
+    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\
+    0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,\
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+    0x00,0x00,0x00,0x00,0x00,0x00,0x91,0x01\
+    }
+    
+// TODO: define your config for Sensor_ID == 1 here, if needed
+#define CTP_CFG_GROUP2 {\
+    }
+// TODO: define your config for Sensor_ID == 2 here, if needed
+#define CTP_CFG_GROUP3 {\
+    }
+
+// TODO: define your config for Sensor_ID == 3 here, if needed
+#define CTP_CFG_GROUP4 {\
+    }
+
+// TODO: define your config for Sensor_ID == 4 here, if needed
+#define CTP_CFG_GROUP5 {\
+    }
+
+// TODO: define your config for Sensor_ID == 5 here, if needed
+#define CTP_CFG_GROUP6 {\
+    }
+
+// STEP_2(REQUIRED): Customize your I/O ports & I/O operations
+#define GTP_RST_PORT    S5PV210_GPJ3(6)
+#define GTP_INT_PORT    S5PV210_GPH1(3)
+#define GTP_INT_IRQ     gpio_to_irq(GTP_INT_PORT)
+#define GTP_INT_CFG     S3C_GPIO_SFN(0xF)
+
+#define GTP_GPIO_AS_INPUT(pin)          do{\
+                                            gpio_direction_input(pin);\
+                                            s3c_gpio_setpull(pin, S3C_GPIO_PULL_NONE);\
+                                        }while(0)
+#define GTP_GPIO_AS_INT(pin)            do{\
+                                            GTP_GPIO_AS_INPUT(pin);\
+                                            s3c_gpio_cfgpin(pin, GTP_INT_CFG);\
+                                        }while(0)
+#define GTP_GPIO_GET_VALUE(pin)         gpio_get_value(pin)
+#define GTP_GPIO_OUTPUT(pin,level)      gpio_direction_output(pin,level)
+#define GTP_GPIO_REQUEST(pin, label)    gpio_request(pin, label)
+#define GTP_GPIO_FREE(pin)              gpio_free(pin)
+#define GTP_IRQ_TAB                     {IRQ_TYPE_EDGE_RISING, IRQ_TYPE_EDGE_FALLING, IRQ_TYPE_LEVEL_LOW, IRQ_TYPE_LEVEL_HIGH}
+
+// STEP_3(optional): Specify your special config info if needed
+#if GTP_CUSTOM_CFG
+  #define GTP_MAX_HEIGHT   800
+  #define GTP_MAX_WIDTH    480
+  #define GTP_INT_TRIGGER  0            // 0: Rising 1: Falling
+#else
+  #define GTP_MAX_HEIGHT   4096
+  #define GTP_MAX_WIDTH    4096
+  #define GTP_INT_TRIGGER  1
+#endif
+#define GTP_MAX_TOUCH         5
+#define GTP_ESD_CHECK_CIRCLE  2000      // jiffy: ms
+
+// STEP_4(optional): If keys are available and reported as keys, config your key info here                             
+#if GTP_HAVE_TOUCH_KEY
+    #define GTP_KEY_TAB  {KEY_MENU, KEY_HOME, KEY_BACK}
+#endif
+
+//***************************PART3:OTHER define*********************************
+#define GTP_DRIVER_VERSION    "V1.8<2013/06/08>"
+#define GTP_I2C_NAME          "Goodix-TS"
+#define GTP_POLL_TIME         10     // jiffy: ms
+#define GTP_ADDR_LENGTH       2
+#define GTP_CONFIG_MIN_LENGTH 186
+#define GTP_CONFIG_MAX_LENGTH 240
+#define FAIL                  0
+#define SUCCESS               1
+#define SWITCH_OFF            0
+#define SWITCH_ON             1
+
+// Registers define
+#define GTP_READ_COOR_ADDR    0x814E
+#define GTP_REG_SLEEP         0x8040
+#define GTP_REG_SENSOR_ID     0x814A
+#define GTP_REG_CONFIG_DATA   0x8047
+#define GTP_REG_VERSION       0x8140
+
+#define RESOLUTION_LOC        3
+#define TRIGGER_LOC           8
+
+#define CFG_GROUP_LEN(p_cfg_grp)  (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0]))
+// Log define
+#define GTP_INFO(fmt,arg...)           printk("<<-GTP-INFO->> "fmt"\n",##arg)
+#define GTP_ERROR(fmt,arg...)          printk("<<-GTP-ERROR->> "fmt"\n",##arg)
+#define GTP_DEBUG(fmt,arg...)          do{\
+                                         if(GTP_DEBUG_ON)\
+                                         printk("<<-GTP-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\
+                                       }while(0)
+#define GTP_DEBUG_ARRAY(array, num)    do{\
+                                         s32 i;\
+                                         u8* a = array;\
+                                         if(GTP_DEBUG_ARRAY_ON)\
+                                         {\
+                                            printk("<<-GTP-DEBUG-ARRAY->>\n");\
+                                            for (i = 0; i < (num); i++)\
+                                            {\
+                                                printk("%02x   ", (a)[i]);\
+                                                if ((i + 1 ) %10 == 0)\
+                                                {\
+                                                    printk("\n");\
+                                                }\
+                                            }\
+                                            printk("\n");\
+                                        }\
+                                       }while(0)
+#define GTP_DEBUG_FUNC()               do{\
+                                         if(GTP_DEBUG_FUNC_ON)\
+                                         printk("<<-GTP-FUNC->> Func:%s@Line:%d\n",__func__,__LINE__);\
+                                       }while(0)
+#define GTP_SWAP(x, y)                 do{\
+                                         typeof(x) z = x;\
+                                         x = y;\
+                                         y = z;\
+                                       }while (0)
+
+//*****************************End of Part III********************************
+
+#endif /* _GOODIX_GT9XX_H_ */
diff --git a/input/touchscreen/gt9xx/gt9xx_firmware.h b/input/touchscreen/gt9xx/gt9xx_firmware.h
new file mode 100644 (file)
index 0000000..3998bf0
--- /dev/null
@@ -0,0 +1,6 @@
+// make sense only when GTP_HEADER_FW_UPDATE & GTP_AUTO_UPDATE are enabled\r
+// define your own firmware array here\r
+const unsigned char header_fw_array[] = \r
+{\r
+    \r
+};
\ No newline at end of file
diff --git a/input/touchscreen/gt9xx/gt9xx_update.c b/input/touchscreen/gt9xx/gt9xx_update.c
new file mode 100644 (file)
index 0000000..f564a6b
--- /dev/null
@@ -0,0 +1,1930 @@
+/* drivers/input/touchscreen/gt9xx_update.c
+ * 
+ * 2010 - 2012 Goodix Technology.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be a reference 
+ * to you, when you are integrating the GOODiX's CTP IC into your system, 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
+ * General Public License for more details.
+ * 
+ * Latest Version:1.6
+ * Author: andrew@goodix.com
+ * Revision Record: 
+ *      V1.0:
+ *          first release. By Andrew, 2012/08/31
+ *      V1.2:
+ *          add force update,GT9110P pid map. By Andrew, 2012/10/15
+ *      V1.4:
+ *          1. add config auto update function;
+ *          2. modify enter_update_mode;
+ *          3. add update file cal checksum.
+ *                          By Andrew, 2012/12/12
+ *      V1.6: 
+ *          1. replace guitar_client with i2c_connect_client;
+ *          2. support firmware header array update.
+ *                          By Meta, 2013/03/11
+ */
+#include <linux/kthread.h>
+#include "gt9xx.h"
+
+#if GTP_HEADER_FW_UPDATE
+#include <linux/namei.h>
+#include <linux/mount.h>
+#include "gt9xx_firmware.h"
+#endif
+
+#define GUP_REG_HW_INFO             0x4220
+#define GUP_REG_FW_MSG              0x41E4
+#define GUP_REG_PID_VID             0x8140
+
+#define GUP_SEARCH_FILE_TIMES       50
+#define UPDATE_FILE_PATH_2          "/data/_goodix_update_.bin"
+#define UPDATE_FILE_PATH_1          "/sdcard/_goodix_update_.bin"
+
+#define CONFIG_FILE_PATH_1          "/data/_goodix_config_.cfg"     
+#define CONFIG_FILE_PATH_2          "/sdcard/_goodix_config_.cfg"   
+
+#define FW_HEAD_LENGTH               14
+#define FW_SECTION_LENGTH            0x2000
+#define FW_DSP_ISP_LENGTH            0x1000
+#define FW_DSP_LENGTH                0x1000
+#define FW_BOOT_LENGTH               0x800
+
+#define PACK_SIZE                    256
+#define MAX_FRAME_CHECK_TIME         5
+
+#define _bRW_MISCTL__SRAM_BANK       0x4048
+#define _bRW_MISCTL__MEM_CD_EN       0x4049
+#define _bRW_MISCTL__CACHE_EN        0x404B
+#define _bRW_MISCTL__TMR0_EN         0x40B0
+#define _rRW_MISCTL__SWRST_B0_       0x4180
+#define _bWO_MISCTL__CPU_SWRST_PULSE 0x4184
+#define _rRW_MISCTL__BOOTCTL_B0_     0x4190
+#define _rRW_MISCTL__BOOT_OPT_B0_    0x4218
+#define _rRW_MISCTL__BOOT_CTL_       0x5094
+
+#define FAIL    0
+#define SUCCESS 1
+
+#pragma pack(1)
+typedef struct 
+{
+    u8  hw_info[4];          //hardware info//
+    u8  pid[8];              //product id   //
+    u16 vid;                 //version id   //
+}st_fw_head;
+#pragma pack()
+
+typedef struct
+{
+    u8 force_update;
+    u8 fw_flag;
+    struct file *file; 
+    struct file *cfg_file;
+    st_fw_head  ic_fw_msg;
+    mm_segment_t old_fs;
+}st_update_msg;
+
+st_update_msg update_msg;
+u16 show_len;
+u16 total_len;
+u8 got_file_flag = 0;
+u8 searching_file = 0;
+extern u8 config[GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH];
+extern void gtp_reset_guitar(struct i2c_client *client, s32 ms);
+extern s32  gtp_send_cfg(struct i2c_client *client);
+extern struct i2c_client * i2c_connect_client;
+extern void gtp_irq_enable(struct goodix_ts_data *ts);
+extern void gtp_irq_disable(struct goodix_ts_data *ts);
+extern s32 gtp_i2c_read_dbl_check(struct i2c_client *, u16, u8 *, int);
+#if GTP_ESD_PROTECT
+extern void gtp_esd_switch(struct i2c_client *, s32);
+#endif
+/*******************************************************
+Function:
+    Read data from the i2c slave device.
+Input:
+    client:     i2c device.
+    buf[0~1]:   read start address.
+    buf[2~len-1]:   read data buffer.
+    len:    GTP_ADDR_LENGTH + read bytes count
+Output:
+    numbers of i2c_msgs to transfer: 
+      2: succeed, otherwise: failed
+*********************************************************/
+s32 gup_i2c_read(struct i2c_client *client, u8 *buf, s32 len)
+{
+    struct i2c_msg msgs[2];
+    s32 ret=-1;
+    s32 retries = 0;
+
+    GTP_DEBUG_FUNC();
+
+    msgs[0].flags = !I2C_M_RD;
+    msgs[0].addr  = client->addr;
+    msgs[0].len   = GTP_ADDR_LENGTH;
+    msgs[0].buf   = &buf[0];
+    //msgs[0].scl_rate = 300 * 1000;    // for Rockchip
+
+    msgs[1].flags = I2C_M_RD;
+    msgs[1].addr  = client->addr;
+    msgs[1].len   = len - GTP_ADDR_LENGTH;
+    msgs[1].buf   = &buf[GTP_ADDR_LENGTH];
+    //msgs[1].scl_rate = 300 * 1000;    
+
+    while(retries < 5)
+    {
+        ret = i2c_transfer(client->adapter, msgs, 2);
+        if(ret == 2)break;
+        retries++;
+    }
+
+    return ret;
+}
+
+/*******************************************************
+Function:
+    Write data to the i2c slave device.
+Input:
+    client:     i2c device.
+    buf[0~1]:   write start address.
+    buf[2~len-1]:   data buffer
+    len:    GTP_ADDR_LENGTH + write bytes count
+Output:
+    numbers of i2c_msgs to transfer: 
+        1: succeed, otherwise: failed
+*********************************************************/
+s32 gup_i2c_write(struct i2c_client *client,u8 *buf,s32 len)
+{
+    struct i2c_msg msg;
+    s32 ret=-1;
+    s32 retries = 0;
+
+    GTP_DEBUG_FUNC();
+
+    msg.flags = !I2C_M_RD;
+    msg.addr  = client->addr;
+    msg.len   = len;
+    msg.buf   = buf;
+    //msg.scl_rate = 300 * 1000;    // for Rockchip
+
+    while(retries < 5)
+    {
+        ret = i2c_transfer(client->adapter, &msg, 1);
+        if (ret == 1)break;
+        retries++;
+    }
+
+    return ret;
+}
+
+static s32 gup_init_panel(struct goodix_ts_data *ts)
+{
+    s32 ret = 0;
+    s32 i = 0;
+    u8 check_sum = 0;
+    u8 opr_buf[16];
+    u8 sensor_id = 0;
+
+    u8 cfg_info_group1[] = CTP_CFG_GROUP1;
+    u8 cfg_info_group2[] = CTP_CFG_GROUP2;
+    u8 cfg_info_group3[] = CTP_CFG_GROUP3;
+    u8 cfg_info_group4[] = CTP_CFG_GROUP4;
+    u8 cfg_info_group5[] = CTP_CFG_GROUP5;
+    u8 cfg_info_group6[] = CTP_CFG_GROUP6;
+    u8 *send_cfg_buf[] = {cfg_info_group1, cfg_info_group2, cfg_info_group3,
+                        cfg_info_group4, cfg_info_group5, cfg_info_group6};
+    u8 cfg_info_len[] = { CFG_GROUP_LEN(cfg_info_group1),
+                          CFG_GROUP_LEN(cfg_info_group2),
+                          CFG_GROUP_LEN(cfg_info_group3),
+                          CFG_GROUP_LEN(cfg_info_group4),
+                          CFG_GROUP_LEN(cfg_info_group5),
+                          CFG_GROUP_LEN(cfg_info_group6)};
+                          
+    if ((!cfg_info_len[1]) && (!cfg_info_len[2]) && 
+        (!cfg_info_len[3]) && (!cfg_info_len[4]) && 
+        (!cfg_info_len[5]))
+    {
+        sensor_id = 0; 
+    }
+    else
+    {
+        ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID, &sensor_id, 1);
+        if (SUCCESS == ret)
+        {
+            if (sensor_id >= 0x06)
+            {
+                GTP_ERROR("Invalid sensor_id(0x%02X), No Config Sent!", sensor_id);
+                return -1;
+            }
+        }
+        else
+        {
+            GTP_ERROR("Failed to get sensor_id, No config sent!");
+            return -1;
+        }
+    }
+    
+    GTP_DEBUG("Sensor_ID: %d", sensor_id);
+    
+    ts->gtp_cfg_len = cfg_info_len[sensor_id];
+    
+    if (ts->gtp_cfg_len < GTP_CONFIG_MIN_LENGTH)
+    {
+        GTP_ERROR("Sensor_ID(%d) matches with NULL or INVALID CONFIG GROUP! NO Config Sent! You need to check you header file CFG_GROUP section!", sensor_id);
+        return -1;
+    }
+    
+    ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA, &opr_buf[0], 1);
+    
+    if (ret == SUCCESS)
+    {
+        GTP_DEBUG("CFG_GROUP%d Config Version: %d, IC Config Version: %d", sensor_id+1, 
+                    send_cfg_buf[sensor_id][0], opr_buf[0]);
+        
+        send_cfg_buf[sensor_id][0] = opr_buf[0];
+        ts->fixed_cfg = 0;
+        /*
+        if (opr_buf[0] < 90)    
+        {
+            grp_cfg_version = send_cfg_buf[sensor_id][0];       // backup group config version
+            send_cfg_buf[sensor_id][0] = 0x00;
+            ts->fixed_cfg = 0;
+        }
+        else        // treated as fixed config, not send config
+        {
+            GTP_INFO("Ic fixed config with config version(%d)", opr_buf[0]);
+            ts->fixed_cfg = 1;
+        }*/
+    }
+    else
+    {
+        GTP_ERROR("Failed to get ic config version!No config sent!");
+        return -1;
+    }
+    
+    memset(&config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
+    memcpy(&config[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id], ts->gtp_cfg_len);
+
+    GTP_DEBUG("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x",
+        ts->abs_x_max, ts->abs_y_max, ts->int_trigger_type);
+
+    config[RESOLUTION_LOC]     = (u8)GTP_MAX_WIDTH;
+    config[RESOLUTION_LOC + 1] = (u8)(GTP_MAX_WIDTH>>8);
+    config[RESOLUTION_LOC + 2] = (u8)GTP_MAX_HEIGHT;
+    config[RESOLUTION_LOC + 3] = (u8)(GTP_MAX_HEIGHT>>8);
+    
+    if (GTP_INT_TRIGGER == 0)  //RISING
+    {
+        config[TRIGGER_LOC] &= 0xfe; 
+    }
+    else if (GTP_INT_TRIGGER == 1)  //FALLING
+    {
+        config[TRIGGER_LOC] |= 0x01;
+    }
+    
+    check_sum = 0;
+    for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++)
+    {
+        check_sum += config[i];
+    }
+    config[ts->gtp_cfg_len] = (~check_sum) + 1;
+
+    GTP_DEBUG_FUNC();
+    ret = gtp_send_cfg(ts->client);
+    if (ret < 0)
+    {
+        GTP_ERROR("Send config error.");
+    }
+
+    msleep(10);
+    return 0;
+}
+
+
+static u8 gup_get_ic_msg(struct i2c_client *client, u16 addr, u8* msg, s32 len)
+{
+    s32 i = 0;
+
+    msg[0] = (addr >> 8) & 0xff;
+    msg[1] = addr & 0xff;
+
+    for (i = 0; i < 5; i++)
+    {
+        if (gup_i2c_read(client, msg, GTP_ADDR_LENGTH + len) > 0)
+        {
+            break;
+        }
+    }
+
+    if (i >= 5)
+    {
+        GTP_ERROR("Read data from 0x%02x%02x failed!", msg[0], msg[1]);
+        return FAIL;
+    }
+
+    return SUCCESS;
+}
+
+static u8 gup_set_ic_msg(struct i2c_client *client, u16 addr, u8 val)
+{
+    s32 i = 0;
+    u8 msg[3];
+
+    msg[0] = (addr >> 8) & 0xff;
+    msg[1] = addr & 0xff;
+    msg[2] = val;
+
+    for (i = 0; i < 5; i++)
+    {
+        if (gup_i2c_write(client, msg, GTP_ADDR_LENGTH + 1) > 0)
+        {
+            break;
+        }
+    }
+
+    if (i >= 5)
+    {
+        GTP_ERROR("Set data to 0x%02x%02x failed!", msg[0], msg[1]);
+        return FAIL;
+    }
+
+    return SUCCESS;
+}
+
+static u8 gup_get_ic_fw_msg(struct i2c_client *client)
+{
+    s32 ret = -1;
+    u8  retry = 0;
+    u8  buf[16];
+    u8  i;
+    
+    // step1:get hardware info
+    ret = gtp_i2c_read_dbl_check(client, GUP_REG_HW_INFO, &buf[GTP_ADDR_LENGTH], 4);
+    if (FAIL == ret)
+    {
+        GTP_ERROR("[get_ic_fw_msg]get hw_info failed,exit");
+        return FAIL;
+    }
+     
+    // buf[2~5]: 00 06 90 00
+    // hw_info: 00 90 06 00
+    for(i=0; i<4; i++)
+    {
+        update_msg.ic_fw_msg.hw_info[i] = buf[GTP_ADDR_LENGTH + 3 - i];
+    } 
+    GTP_DEBUG("IC Hardware info:%02x%02x%02x%02x", update_msg.ic_fw_msg.hw_info[0], update_msg.ic_fw_msg.hw_info[1],
+                                                   update_msg.ic_fw_msg.hw_info[2], update_msg.ic_fw_msg.hw_info[3]);
+    // step2:get firmware message
+    for(retry=0; retry<2; retry++)
+    {
+        ret = gup_get_ic_msg(client, GUP_REG_FW_MSG, buf, 1);
+        if(FAIL == ret)
+        {
+            GTP_ERROR("Read firmware message fail.");
+            return ret;
+        }
+        
+        update_msg.force_update = buf[GTP_ADDR_LENGTH];
+        if((0xBE != update_msg.force_update)&&(!retry))
+        {
+            GTP_INFO("The check sum in ic is error.");
+            GTP_INFO("The IC will be updated by force.");
+            continue;
+        }
+        break;
+    }
+    GTP_DEBUG("IC force update flag:0x%x", update_msg.force_update);
+    
+    // step3:get pid & vid
+    ret = gtp_i2c_read_dbl_check(client, GUP_REG_PID_VID, &buf[GTP_ADDR_LENGTH], 6);
+    if (FAIL == ret)
+    {
+        GTP_ERROR("[get_ic_fw_msg]get pid & vid failed,exit");
+        return FAIL;
+    }
+    
+    memset(update_msg.ic_fw_msg.pid, 0, sizeof(update_msg.ic_fw_msg.pid));
+    memcpy(update_msg.ic_fw_msg.pid, &buf[GTP_ADDR_LENGTH], 4);
+    GTP_DEBUG("IC Product id:%s", update_msg.ic_fw_msg.pid);
+    
+    //GT9XX PID MAPPING
+    /*|-----FLASH-----RAM-----|
+      |------918------918-----|
+      |------968------968-----|
+      |------913------913-----|
+      |------913P-----913P----|
+      |------927------927-----|
+      |------927P-----927P----|
+      |------9110-----9110----|
+      |------9110P----9111----|*/
+    if(update_msg.ic_fw_msg.pid[0] != 0)
+    {
+        if(!memcmp(update_msg.ic_fw_msg.pid, "9111", 4))
+        {
+            GTP_DEBUG("IC Mapping Product id:%s", update_msg.ic_fw_msg.pid);
+            memcpy(update_msg.ic_fw_msg.pid, "9110P", 5);
+        }
+    }
+    
+    update_msg.ic_fw_msg.vid = buf[GTP_ADDR_LENGTH+4] + (buf[GTP_ADDR_LENGTH+5]<<8);
+    GTP_DEBUG("IC version id:%04x", update_msg.ic_fw_msg.vid);
+    
+    return SUCCESS;
+}
+
+s32 gup_enter_update_mode(struct i2c_client *client)
+{
+    s32 ret = -1;
+    s32 retry = 0;
+    u8 rd_buf[3];
+    
+    //step1:RST output low last at least 2ms
+    GTP_GPIO_OUTPUT(GTP_RST_PORT, 0);
+    msleep(2);
+    
+    //step2:select I2C slave addr,INT:0--0xBA;1--0x28.
+    GTP_GPIO_OUTPUT(GTP_INT_PORT, (client->addr == 0x14));
+    msleep(2);
+    
+    //step3:RST output high reset guitar
+    GTP_GPIO_OUTPUT(GTP_RST_PORT, 1);
+    
+    //20121211 modify start
+    msleep(5);
+    while(retry++ < 200)
+    {
+        //step4:Hold ss51 & dsp
+        ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+        if(ret <= 0)
+        {
+            GTP_DEBUG("Hold ss51 & dsp I2C error,retry:%d", retry);
+            continue;
+        }
+        
+        //step5:Confirm hold
+        ret = gup_get_ic_msg(client, _rRW_MISCTL__SWRST_B0_, rd_buf, 1);
+        if(ret <= 0)
+        {
+            GTP_DEBUG("Hold ss51 & dsp I2C error,retry:%d", retry);
+            continue;
+        }
+        if(0x0C == rd_buf[GTP_ADDR_LENGTH])
+        {
+            GTP_DEBUG("Hold ss51 & dsp confirm SUCCESS");
+            break;
+        }
+        GTP_DEBUG("Hold ss51 & dsp confirm 0x4180 failed,value:%d", rd_buf[GTP_ADDR_LENGTH]);
+    }
+    if(retry >= 200)
+    {
+        GTP_ERROR("Enter update Hold ss51 failed.");
+        return FAIL;
+    }
+    
+    //step6:DSP_CK and DSP_ALU_CK PowerOn
+    ret = gup_set_ic_msg(client, 0x4010, 0x00);
+    
+    //20121211 modify end
+    return ret;
+}
+
+void gup_leave_update_mode(void)
+{
+    GTP_GPIO_AS_INT(GTP_INT_PORT);
+    
+    GTP_DEBUG("[leave_update_mode]reset chip.");
+    gtp_reset_guitar(i2c_connect_client, 20);
+}
+
+// Get the correct nvram data
+// The correct conditions: 
+//  1. the hardware info is the same
+//  2. the product id is the same
+//  3. the firmware version in update file is greater than the firmware version in ic 
+//      or the check sum in ic is wrong
+/* Update Conditions: 
+    1. Same hardware info
+    2. Same PID
+    3. File PID > IC PID
+   Force Update Conditions:
+    1. Wrong ic firmware checksum
+    2. INVALID IC PID or VID
+    3. IC PID == 91XX || File PID == 91XX
+*/
+
+static u8 gup_enter_update_judge(st_fw_head *fw_head)
+{
+    u16 u16_tmp;
+    s32 i = 0;
+    
+    u16_tmp = fw_head->vid;
+    fw_head->vid = (u16)(u16_tmp>>8) + (u16)(u16_tmp<<8);
+
+    GTP_DEBUG("FILE HARDWARE INFO:%02x%02x%02x%02x", fw_head->hw_info[0], fw_head->hw_info[1], fw_head->hw_info[2], fw_head->hw_info[3]);
+    GTP_DEBUG("FILE PID:%s", fw_head->pid);
+    GTP_DEBUG("FILE VID:%04x", fw_head->vid);
+
+    GTP_DEBUG("IC HARDWARE INFO:%02x%02x%02x%02x", update_msg.ic_fw_msg.hw_info[0], update_msg.ic_fw_msg.hw_info[1],
+                                                   update_msg.ic_fw_msg.hw_info[2], update_msg.ic_fw_msg.hw_info[3]);
+    GTP_DEBUG("IC PID:%s", update_msg.ic_fw_msg.pid);
+    GTP_DEBUG("IC VID:%04x", update_msg.ic_fw_msg.vid);
+
+    //First two conditions
+    if ( !memcmp(fw_head->hw_info, update_msg.ic_fw_msg.hw_info, sizeof(update_msg.ic_fw_msg.hw_info)))
+    {
+        GTP_DEBUG("Get the same hardware info.");
+        if( update_msg.force_update != 0xBE )
+        {
+            GTP_INFO("FW chksum error,need enter update.");
+            return SUCCESS;
+        }
+        
+        // 20130523 start
+        if (strlen(update_msg.ic_fw_msg.pid) < 3)
+        {
+            GTP_INFO("Illegal IC pid, need enter update");
+            return SUCCESS;
+        }
+        else
+        {
+            for (i = 0; i < 3; i++)
+            {
+                if ((update_msg.ic_fw_msg.pid[i] < 0x30) || (update_msg.ic_fw_msg.pid[i] > 0x39))
+                {
+                    GTP_INFO("Illegal IC pid, out of bound, need enter update");
+                    return SUCCESS;
+                }
+            }
+        }
+        // 20130523 end
+        
+        
+        if (( !memcmp(fw_head->pid, update_msg.ic_fw_msg.pid, (strlen(fw_head->pid)<3?3:strlen(fw_head->pid))))||
+            (!memcmp(update_msg.ic_fw_msg.pid, "91XX", 4))||
+            (!memcmp(fw_head->pid, "91XX", 4)))
+        {
+            if(!memcmp(fw_head->pid, "91XX", 4))
+            {
+                GTP_DEBUG("Force none same pid update mode.");
+            }
+            else
+            {
+                GTP_DEBUG("Get the same pid.");
+            }
+            //The third condition
+            if (fw_head->vid > update_msg.ic_fw_msg.vid)
+            {
+
+                GTP_INFO("Need enter update.");
+                return SUCCESS;
+            }
+            GTP_ERROR("Don't meet the third condition.");
+            GTP_ERROR("File VID <= Ic VID, update aborted!");
+        }
+        else
+        {
+            GTP_ERROR("File PID != Ic PID, update aborted!");
+        }
+    }
+    else
+    {
+        GTP_ERROR("Different Hardware, update aborted!");
+    }
+    return FAIL;
+}
+
+static u8 ascii2hex(u8 a)
+{
+    s8 value = 0;
+
+    if(a >= '0' && a <= '9')
+    {
+        value = a - '0';
+    }
+    else if(a >= 'A' && a <= 'F')
+    {
+        value = a - 'A' + 0x0A;
+    }
+    else if(a >= 'a' && a <= 'f')
+    {
+        value = a - 'a' + 0x0A;
+    }
+    else
+    {
+        value = 0xff;
+    }
+    
+    return value;
+}
+
+static s8 gup_update_config(struct i2c_client *client)
+{
+    s32 file_len = 0;
+    s32 ret = 0;
+    s32 i = 0;
+    s32 file_cfg_len = 0;
+    s32 chip_cfg_len = 0;
+    s32 count = 0;
+    u8 *buf;
+    u8 *pre_buf;
+    u8 *file_config;
+    //u8 checksum = 0;
+    u8 pid[8];
+    
+    if(NULL == update_msg.cfg_file)
+    {
+        GTP_ERROR("[update_cfg]No need to upgrade config!");
+        return FAIL;
+    }
+    file_len = update_msg.cfg_file->f_op->llseek(update_msg.cfg_file, 0, SEEK_END);
+    
+    ret = gup_get_ic_msg(client, GUP_REG_PID_VID, pid, 6);
+    if(FAIL == ret)
+    {
+        GTP_ERROR("[update_cfg]Read product id & version id fail.");
+        return FAIL;
+    }
+    pid[5] = '\0';
+    GTP_DEBUG("update cfg get pid:%s", &pid[GTP_ADDR_LENGTH]);
+    
+    chip_cfg_len = 186;
+    if(!memcmp(&pid[GTP_ADDR_LENGTH], "968", 3) || 
+       !memcmp(&pid[GTP_ADDR_LENGTH], "910", 3) ||
+       !memcmp(&pid[GTP_ADDR_LENGTH], "960", 3))
+    {
+        chip_cfg_len = 228;
+    }
+    GTP_DEBUG("[update_cfg]config file len:%d", file_len);
+    GTP_DEBUG("[update_cfg]need config len:%d",chip_cfg_len);
+    if((file_len+5) < chip_cfg_len*5)
+    {
+        GTP_ERROR("Config length error");
+        return -1;
+    }
+    
+    buf = (u8*)kzalloc(file_len, GFP_KERNEL);
+    pre_buf = (u8*)kzalloc(file_len, GFP_KERNEL);
+    file_config = (u8*)kzalloc(chip_cfg_len + GTP_ADDR_LENGTH, GFP_KERNEL);
+    update_msg.cfg_file->f_op->llseek(update_msg.cfg_file, 0, SEEK_SET);
+    
+    GTP_DEBUG("[update_cfg]Read config from file.");
+    ret = update_msg.cfg_file->f_op->read(update_msg.cfg_file, (char*)pre_buf, file_len, &update_msg.cfg_file->f_pos);
+    if(ret<0)
+    {
+        GTP_ERROR("[update_cfg]Read config file failed.");
+        goto update_cfg_file_failed;
+    }
+    
+    GTP_DEBUG("[update_cfg]Delete illgal charactor.");
+    for(i=0,count=0; i<file_len; i++)
+    {
+        if (pre_buf[i] == ' ' || pre_buf[i] == '\r' || pre_buf[i] == '\n')
+        {
+            continue;
+        }
+        buf[count++] = pre_buf[i];
+    }
+    
+    GTP_DEBUG("[update_cfg]Ascii to hex.");
+    file_config[0] = GTP_REG_CONFIG_DATA >> 8;
+    file_config[1] = GTP_REG_CONFIG_DATA & 0xff;
+    for(i=0,file_cfg_len=GTP_ADDR_LENGTH; i<count; i+=5)
+    {
+        if((buf[i]=='0') && ((buf[i+1]=='x') || (buf[i+1]=='X')))
+        {
+            u8 high,low;
+            high = ascii2hex(buf[i+2]);
+            low = ascii2hex(buf[i+3]);
+            
+            if((high == 0xFF) || (low == 0xFF))
+            {
+                ret = 0;
+                GTP_ERROR("[update_cfg]Illegal config file.");
+                goto update_cfg_file_failed;
+            }
+            file_config[file_cfg_len++] = (high<<4) + low;
+        }
+        else
+        {
+            ret = 0;
+            GTP_ERROR("[update_cfg]Illegal config file.");
+            goto update_cfg_file_failed;
+        }
+    }
+    
+//    //cal checksum
+//    for(i=GTP_ADDR_LENGTH; i<chip_cfg_len; i++)
+//    {
+//        checksum += file_config[i];
+//    }
+//    file_config[chip_cfg_len] = (~checksum) + 1;
+//    file_config[chip_cfg_len+1] = 0x01;
+    
+    GTP_DEBUG("config:");
+    GTP_DEBUG_ARRAY(file_config+2, file_cfg_len);
+    
+    i = 0;
+    while(i++ < 5)
+    {
+        ret = gup_i2c_write(client, file_config, file_cfg_len);
+        if(ret > 0)
+        {
+            GTP_INFO("[update_cfg]Send config SUCCESS.");
+            break;
+        }
+        GTP_ERROR("[update_cfg]Send config i2c error.");
+    }
+    
+update_cfg_file_failed:
+    kfree(pre_buf);
+    kfree(buf);
+    kfree(file_config);
+    return ret;
+}
+
+#if GTP_HEADER_FW_UPDATE
+static u8 gup_check_fs_mounted(char *path_name)
+{
+    struct path root_path;
+    struct path path;
+    int err;
+    err = kern_path("/", LOOKUP_FOLLOW, &root_path);
+
+    if (err)
+    {
+        GTP_DEBUG("\"/\" NOT Mounted: %d", err);
+        return FAIL;
+    }
+    err = kern_path(path_name, LOOKUP_FOLLOW, &path);
+
+    if (err)
+    {
+        GTP_DEBUG("/data/ NOT Mounted: %d", err);
+        return FAIL;
+    }
+
+    return SUCCESS;
+    
+    /*
+    if (path.mnt->mnt_sb == root_path.mnt->mnt_sb)
+    {
+        //-- not mounted
+        return FAIL;
+    }
+    else
+    {
+        return SUCCESS;
+    }*/
+
+}
+#endif
+static u8 gup_check_update_file(struct i2c_client *client, st_fw_head* fw_head, u8* path)
+{
+    s32 ret = 0;
+    s32 i = 0;
+    s32 fw_checksum = 0;
+    u8 buf[FW_HEAD_LENGTH];
+    
+    if (path)
+    {
+        GTP_DEBUG("Update File path:%s, %d", path, strlen(path));
+        update_msg.file = filp_open(path, O_RDONLY, 0);
+
+        if (IS_ERR(update_msg.file))
+        {
+            GTP_ERROR("Open update file(%s) error!", path);
+            return FAIL;
+        }
+    }
+    else
+    {
+#if GTP_HEADER_FW_UPDATE
+        for (i = 0; i < (GUP_SEARCH_FILE_TIMES); i++)
+        {
+            GTP_DEBUG("Waiting for /data mounted [%d]", i);
+
+            if (gup_check_fs_mounted("/data") == SUCCESS)
+            {
+                GTP_DEBUG("/data Mounted!");
+                break;
+            }
+            msleep(3000);
+        }
+        if (i >= (GUP_SEARCH_FILE_TIMES))
+        {
+            GTP_ERROR("Wait for /data mounted timeout!");
+            return FAIL;
+        }
+        
+        // update config
+        update_msg.cfg_file = filp_open(CONFIG_FILE_PATH_1, O_RDONLY, 0);
+        if (IS_ERR(update_msg.cfg_file))
+        {
+            GTP_DEBUG("%s is unavailable", CONFIG_FILE_PATH_1);
+        }
+        else
+        {
+            GTP_INFO("Update Config File: %s", CONFIG_FILE_PATH_1);
+            ret = gup_update_config(client);
+            if(ret <= 0)
+            {
+                GTP_ERROR("Update config failed.");
+            }
+            filp_close(update_msg.cfg_file, NULL);
+        }
+        
+        if (sizeof(header_fw_array) < (FW_HEAD_LENGTH+FW_SECTION_LENGTH*4+FW_DSP_ISP_LENGTH+FW_DSP_LENGTH+FW_BOOT_LENGTH))
+        {
+            GTP_ERROR("INVALID header_fw_array, check your gt9xx_firmware.h file!");
+            return FAIL;           
+        }
+        update_msg.file = filp_open(UPDATE_FILE_PATH_2, O_CREAT | O_RDWR, 0666);
+        if ((IS_ERR(update_msg.file)))
+        {
+            GTP_ERROR("Failed to Create file: %s for fw_header!", UPDATE_FILE_PATH_2);
+            return FAIL;
+        }
+        update_msg.file->f_op->llseek(update_msg.file, 0, SEEK_SET);
+        update_msg.file->f_op->write(update_msg.file, (char *)header_fw_array, sizeof(header_fw_array), &update_msg.file->f_pos);
+        filp_close(update_msg.file, NULL);
+        update_msg.file = filp_open(UPDATE_FILE_PATH_2, O_RDONLY, 0);
+#else
+        u8 fp_len = max(sizeof(UPDATE_FILE_PATH_1), sizeof(UPDATE_FILE_PATH_2));
+        u8 cfp_len = max(sizeof(CONFIG_FILE_PATH_1), sizeof(CONFIG_FILE_PATH_2));
+        u8 *search_update_path = (u8*)kzalloc(fp_len, GFP_KERNEL);
+        u8 *search_cfg_path = (u8*)kzalloc(cfp_len, GFP_KERNEL);
+        //Begin to search update file,the config file & firmware file must be in the same path,single or double.
+        searching_file = 1;
+        for (i = 0; i < GUP_SEARCH_FILE_TIMES; i++)
+        {
+            if (searching_file == 0)
+            {
+                kfree(search_update_path);
+                kfree(search_cfg_path);
+                GTP_INFO(".bin/.cfg update file search forcely terminated!");
+                return FAIL;
+            }
+            if(i%2)
+            {
+                memcpy(search_update_path, UPDATE_FILE_PATH_1, sizeof(UPDATE_FILE_PATH_1));
+                memcpy(search_cfg_path, CONFIG_FILE_PATH_1, sizeof(CONFIG_FILE_PATH_1));
+            }
+            else
+            {
+                memcpy(search_update_path, UPDATE_FILE_PATH_2, sizeof(UPDATE_FILE_PATH_2));
+                memcpy(search_cfg_path, CONFIG_FILE_PATH_2, sizeof(CONFIG_FILE_PATH_2));
+            }
+            
+            if(!(got_file_flag&0x0F))
+            {
+                update_msg.file = filp_open(search_update_path, O_RDONLY, 0);
+                if(!IS_ERR(update_msg.file))
+                {
+                    GTP_DEBUG("Find the bin file");
+                    got_file_flag |= 0x0F;
+                }
+            }
+            if(!(got_file_flag&0xF0))
+            {
+                update_msg.cfg_file = filp_open(search_cfg_path, O_RDONLY, 0);
+                if(!IS_ERR(update_msg.cfg_file))
+                {
+                    GTP_DEBUG("Find the cfg file");
+                    got_file_flag |= 0xF0;
+                }
+            }
+            
+            if(got_file_flag)
+            {
+                if(got_file_flag == 0xFF)
+                {
+                    break;
+                }
+                else
+                {
+                    i += 4;
+                }
+            }
+            GTP_DEBUG("%3d:Searching %s %s file...", i, (got_file_flag&0x0F)?"":"bin", (got_file_flag&0xF0)?"":"cfg");
+            msleep(3000);
+        }
+        searching_file = 0;
+        kfree(search_update_path);
+        kfree(search_cfg_path);
+        
+        if(!got_file_flag)
+        {
+            GTP_ERROR("Can't find update file.");
+            goto load_failed;
+        }
+        
+        if(got_file_flag&0xF0)
+        {
+            GTP_DEBUG("Got the update config file.");
+            ret = gup_update_config(client);
+            if(ret <= 0)
+            {
+                GTP_ERROR("Update config failed.");
+            }
+            filp_close(update_msg.cfg_file, NULL);
+            msleep(500);                //waiting config to be stored in FLASH.
+        }
+        if(got_file_flag&0x0F)
+        {
+            GTP_DEBUG("Got the update firmware file.");
+        }
+        else
+        {
+            GTP_ERROR("No need to upgrade firmware.");
+            goto load_failed;
+        }
+#endif
+    }
+    
+    update_msg.old_fs = get_fs();
+    set_fs(KERNEL_DS);
+
+    update_msg.file->f_op->llseek(update_msg.file, 0, SEEK_SET);
+    //update_msg.file->f_pos = 0;
+
+    ret = update_msg.file->f_op->read(update_msg.file, (char*)buf, FW_HEAD_LENGTH, &update_msg.file->f_pos);
+    if (ret < 0)
+    {
+        GTP_ERROR("Read firmware head in update file error.");
+        goto load_failed;
+    }
+    memcpy(fw_head, buf, FW_HEAD_LENGTH);
+    
+    //check firmware legality
+    fw_checksum = 0;
+    for(i=0; i<FW_SECTION_LENGTH*4+FW_DSP_ISP_LENGTH+FW_DSP_LENGTH+FW_BOOT_LENGTH; i+=2)
+    {
+        u16 temp;
+        ret = update_msg.file->f_op->read(update_msg.file, (char*)buf, 2, &update_msg.file->f_pos);
+        if (ret < 0)
+        {
+            GTP_ERROR("Read firmware file error.");
+            goto load_failed;
+        }
+        //GTP_DEBUG("BUF[0]:%x", buf[0]);
+        temp = (buf[0]<<8) + buf[1];
+        fw_checksum += temp;
+    }
+    
+    GTP_DEBUG("firmware checksum:%x", fw_checksum&0xFFFF);
+    if(fw_checksum&0xFFFF)
+    {
+        GTP_ERROR("Illegal firmware file.");
+        goto load_failed;    
+    }
+    
+    return SUCCESS;
+
+load_failed:
+    set_fs(update_msg.old_fs);
+    return FAIL;
+}
+
+#if 0
+static u8 gup_check_update_header(struct i2c_client *client, st_fw_head* fw_head)
+{
+    const u8* pos;
+    int i = 0;
+    u8 mask_num = 0;
+    s32 ret = 0;
+
+    pos = HEADER_UPDATE_DATA;
+      
+    memcpy(fw_head, pos, FW_HEAD_LENGTH);
+    pos += FW_HEAD_LENGTH;
+
+    ret = gup_enter_update_judge(fw_head);
+    if(SUCCESS == ret)
+    {
+        return SUCCESS;
+    }
+    return FAIL;
+}
+#endif
+
+static u8 gup_burn_proc(struct i2c_client *client, u8 *burn_buf, u16 start_addr, u16 total_length)
+{
+    s32 ret = 0;
+    u16 burn_addr = start_addr;
+    u16 frame_length = 0;
+    u16 burn_length = 0;
+    u8  wr_buf[PACK_SIZE + GTP_ADDR_LENGTH];
+    u8  rd_buf[PACK_SIZE + GTP_ADDR_LENGTH];
+    u8  retry = 0;
+    
+    GTP_DEBUG("Begin burn %dk data to addr 0x%x", (total_length/1024), start_addr);
+    while(burn_length < total_length)
+    {
+        GTP_DEBUG("B/T:%04d/%04d", burn_length, total_length);
+        frame_length = ((total_length - burn_length) > PACK_SIZE) ? PACK_SIZE : (total_length - burn_length);
+        wr_buf[0] = (u8)(burn_addr>>8);
+        rd_buf[0] = wr_buf[0];
+        wr_buf[1] = (u8)burn_addr;
+        rd_buf[1] = wr_buf[1];
+        memcpy(&wr_buf[GTP_ADDR_LENGTH], &burn_buf[burn_length], frame_length);
+        
+        for(retry = 0; retry < MAX_FRAME_CHECK_TIME; retry++)
+        {
+            ret = gup_i2c_write(client, wr_buf, GTP_ADDR_LENGTH + frame_length);
+            if(ret <= 0)
+            {
+                GTP_ERROR("Write frame data i2c error.");
+                continue;
+            }
+            ret = gup_i2c_read(client, rd_buf, GTP_ADDR_LENGTH + frame_length);
+            if(ret <= 0)
+            {
+                GTP_ERROR("Read back frame data i2c error.");
+                continue;
+            }
+            
+            if(memcmp(&wr_buf[GTP_ADDR_LENGTH], &rd_buf[GTP_ADDR_LENGTH], frame_length))
+            {
+                GTP_ERROR("Check frame data fail,not equal.");
+                GTP_DEBUG("write array:");
+                GTP_DEBUG_ARRAY(&wr_buf[GTP_ADDR_LENGTH], frame_length);
+                GTP_DEBUG("read array:");
+                GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], frame_length);
+                continue;
+            }
+            else
+            {
+                //GTP_DEBUG("Check frame data success.");
+                break;
+            }
+        }
+        if(retry >= MAX_FRAME_CHECK_TIME)
+        {
+            GTP_ERROR("Burn frame data time out,exit.");
+            return FAIL;
+        }
+        burn_length += frame_length;
+        burn_addr += frame_length;
+    }
+    return SUCCESS;
+}
+
+static u8 gup_load_section_file(u8* buf, u16 offset, u16 length)
+{
+    s32 ret = 0;
+    
+    if(update_msg.file == NULL)
+    {
+        GTP_ERROR("cannot find update file,load section file fail.");
+        return FAIL;
+    }
+    update_msg.file->f_pos = FW_HEAD_LENGTH + offset;
+    
+    ret = update_msg.file->f_op->read(update_msg.file, (char*)buf, length, &update_msg.file->f_pos);
+    if(ret < 0)
+    {
+        GTP_ERROR("Read update file fail.");
+        return FAIL;
+    }
+    
+    return SUCCESS;
+}
+
+static u8 gup_recall_check(struct i2c_client *client, u8* chk_src, u16 start_rd_addr, u16 chk_length)
+{
+    u8  rd_buf[PACK_SIZE + GTP_ADDR_LENGTH];
+    s32 ret = 0;
+    u16 recall_addr = start_rd_addr;
+    u16 recall_length = 0;
+    u16 frame_length = 0;
+
+    while(recall_length < chk_length)
+    {
+        frame_length = ((chk_length - recall_length) > PACK_SIZE) ? PACK_SIZE : (chk_length - recall_length);
+        ret = gup_get_ic_msg(client, recall_addr, rd_buf, frame_length);
+        if(ret <= 0)
+        {
+            GTP_ERROR("recall i2c error,exit");
+            return FAIL;
+        }
+        
+        if(memcmp(&rd_buf[GTP_ADDR_LENGTH], &chk_src[recall_length], frame_length))
+        {
+            GTP_ERROR("Recall frame data fail,not equal.");
+            GTP_DEBUG("chk_src array:");
+            GTP_DEBUG_ARRAY(&chk_src[recall_length], frame_length);
+            GTP_DEBUG("recall array:");
+            GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], frame_length);
+            return FAIL;
+        }
+        
+        recall_length += frame_length;
+        recall_addr += frame_length;
+    }
+    GTP_DEBUG("Recall check %dk firmware success.", (chk_length/1024));
+    
+    return SUCCESS;
+}
+
+static u8 gup_burn_fw_section(struct i2c_client *client, u8 *fw_section, u16 start_addr, u8 bank_cmd )
+{
+    s32 ret = 0;
+    u8  rd_buf[5];
+  
+    //step1:hold ss51 & dsp
+    ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_fw_section]hold ss51 & dsp fail.");
+        return FAIL;
+    }
+    
+    //step2:set scramble
+    ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_fw_section]set scramble fail.");
+        return FAIL;
+    }
+    
+    //step3:select bank
+    ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, (bank_cmd >> 4)&0x0F);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_fw_section]select bank %d fail.", (bank_cmd >> 4)&0x0F);
+        return FAIL;
+    }
+    
+    //step4:enable accessing code
+    ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_fw_section]enable accessing code fail.");
+        return FAIL;
+    }
+    
+    //step5:burn 8k fw section
+    ret = gup_burn_proc(client, fw_section, start_addr, FW_SECTION_LENGTH);
+    if(FAIL == ret)
+    {
+        GTP_ERROR("[burn_fw_section]burn fw_section fail.");
+        return FAIL;
+    }
+    
+    //step6:hold ss51 & release dsp
+    ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_fw_section]hold ss51 & release dsp fail.");
+        return FAIL;
+    }
+    //must delay
+    msleep(1);
+    
+    //step7:send burn cmd to move data to flash from sram
+    ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, bank_cmd&0x0f);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_fw_section]send burn cmd fail.");
+        return FAIL;
+    }
+    GTP_DEBUG("[burn_fw_section]Wait for the burn is complete......");
+    do{
+        ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+        if(ret <= 0)
+        {
+            GTP_ERROR("[burn_fw_section]Get burn state fail");
+            return FAIL;
+        }
+        msleep(10);
+        //GTP_DEBUG("[burn_fw_section]Get burn state:%d.", rd_buf[GTP_ADDR_LENGTH]);
+    }while(rd_buf[GTP_ADDR_LENGTH]);
+
+    //step8:select bank
+    ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, (bank_cmd >> 4)&0x0F);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_fw_section]select bank %d fail.", (bank_cmd >> 4)&0x0F);
+        return FAIL;
+    }
+    
+    //step9:enable accessing code
+    ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_fw_section]enable accessing code fail.");
+        return FAIL;
+    }
+    
+    //step10:recall 8k fw section
+    ret = gup_recall_check(client, fw_section, start_addr, FW_SECTION_LENGTH);
+    if(FAIL == ret)
+    {
+        GTP_ERROR("[burn_fw_section]recall check 8k firmware fail.");
+        return FAIL;
+    }
+    
+    //step11:disable accessing code
+    ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x00);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_fw_section]disable accessing code fail.");
+        return FAIL;
+    }
+    
+    return SUCCESS;
+}
+
+static u8 gup_burn_dsp_isp(struct i2c_client *client)
+{
+    s32 ret = 0;
+    u8* fw_dsp_isp = NULL;
+    u8  retry = 0;
+    
+    GTP_DEBUG("[burn_dsp_isp]Begin burn dsp isp---->>");
+    
+    //step1:alloc memory
+    GTP_DEBUG("[burn_dsp_isp]step1:alloc memory");
+    while(retry++ < 5)
+    {
+        fw_dsp_isp = (u8*)kzalloc(FW_DSP_ISP_LENGTH, GFP_KERNEL);
+        if(fw_dsp_isp == NULL)
+        {
+            continue;
+        }
+        else
+        {
+            GTP_INFO("[burn_dsp_isp]Alloc %dk byte memory success.", (FW_DSP_ISP_LENGTH/1024));
+            break;
+        }
+    }
+    if(retry >= 5)
+    {
+        GTP_ERROR("[burn_dsp_isp]Alloc memory fail,exit.");
+        return FAIL;
+    }
+    
+    //step2:load dsp isp file data
+    GTP_DEBUG("[burn_dsp_isp]step2:load dsp isp file data");
+    ret = gup_load_section_file(fw_dsp_isp, (4*FW_SECTION_LENGTH+FW_DSP_LENGTH+FW_BOOT_LENGTH), FW_DSP_ISP_LENGTH);
+    if(FAIL == ret)
+    {
+        GTP_ERROR("[burn_dsp_isp]load firmware dsp_isp fail.");
+        goto exit_burn_dsp_isp;
+    }
+    
+    //step3:disable wdt,clear cache enable
+    GTP_DEBUG("[burn_dsp_isp]step3:disable wdt,clear cache enable");
+    ret = gup_set_ic_msg(client, _bRW_MISCTL__TMR0_EN, 0x00);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_dsp_isp]disable wdt fail.");
+        ret = FAIL;
+        goto exit_burn_dsp_isp;
+    }
+    ret = gup_set_ic_msg(client, _bRW_MISCTL__CACHE_EN, 0x00);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_dsp_isp]clear cache enable fail.");
+        ret = FAIL;
+        goto exit_burn_dsp_isp;
+    }
+    
+    //step4:hold ss51 & dsp
+    GTP_DEBUG("[burn_dsp_isp]step4:hold ss51 & dsp");
+    ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_dsp_isp]hold ss51 & dsp fail.");
+        ret = FAIL;
+        goto exit_burn_dsp_isp;
+    }
+    
+    //step5:set boot from sram
+    GTP_DEBUG("[burn_dsp_isp]step5:set boot from sram");
+    ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOTCTL_B0_, 0x02);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_dsp_isp]set boot from sram fail.");
+        ret = FAIL;
+        goto exit_burn_dsp_isp;
+    }
+    
+    //step6:software reboot
+    GTP_DEBUG("[burn_dsp_isp]step6:software reboot");
+    ret = gup_set_ic_msg(client, _bWO_MISCTL__CPU_SWRST_PULSE, 0x01);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_dsp_isp]software reboot fail.");
+        ret = FAIL;
+        goto exit_burn_dsp_isp;
+    }
+    
+    //step7:select bank2
+    GTP_DEBUG("[burn_dsp_isp]step7:select bank2");
+    ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x02);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_dsp_isp]select bank2 fail.");
+        ret = FAIL;
+        goto exit_burn_dsp_isp;
+    }
+    
+    //step8:enable accessing code
+    GTP_DEBUG("[burn_dsp_isp]step8:enable accessing code");
+    ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_dsp_isp]enable accessing code fail.");
+        ret = FAIL;
+        goto exit_burn_dsp_isp;
+    }
+    
+    //step9:burn 4k dsp_isp
+    GTP_DEBUG("[burn_dsp_isp]step9:burn 4k dsp_isp");
+    ret = gup_burn_proc(client, fw_dsp_isp, 0xC000, FW_DSP_ISP_LENGTH);
+    if(FAIL == ret)
+    {
+        GTP_ERROR("[burn_dsp_isp]burn dsp_isp fail.");
+        goto exit_burn_dsp_isp;
+    }
+    
+    //step10:set scramble
+    GTP_DEBUG("[burn_dsp_isp]step10:set scramble");
+    ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_dsp_isp]set scramble fail.");
+        ret = FAIL;
+        goto exit_burn_dsp_isp;
+    }
+    ret = SUCCESS;
+
+exit_burn_dsp_isp:
+    kfree(fw_dsp_isp);
+    return ret;
+}
+
+static u8 gup_burn_fw_ss51(struct i2c_client *client)
+{
+    u8* fw_ss51 = NULL;
+    u8  retry = 0;
+    s32 ret = 0;
+    
+    GTP_DEBUG("[burn_fw_ss51]Begin burn ss51 firmware---->>");
+    
+    //step1:alloc memory
+    GTP_DEBUG("[burn_fw_ss51]step1:alloc memory");
+    while(retry++ < 5)
+    {
+        fw_ss51 = (u8*)kzalloc(FW_SECTION_LENGTH, GFP_KERNEL);
+        if(fw_ss51 == NULL)
+        {
+            continue;
+        }
+        else
+        {
+            GTP_INFO("[burn_fw_ss51]Alloc %dk byte memory success.", (FW_SECTION_LENGTH/1024));
+            break;
+        }
+    }
+    if(retry >= 5)
+    {
+        GTP_ERROR("[burn_fw_ss51]Alloc memory fail,exit.");
+        return FAIL;
+    }
+    
+    //step2:load ss51 firmware section 1 file data
+    GTP_DEBUG("[burn_fw_ss51]step2:load ss51 firmware section 1 file data");
+    ret = gup_load_section_file(fw_ss51, 0, FW_SECTION_LENGTH);
+    if(FAIL == ret)
+    {
+        GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 1 fail.");
+        goto exit_burn_fw_ss51;
+    }
+    
+    //step3:clear control flag
+    GTP_DEBUG("[burn_fw_ss51]step3:clear control flag");
+    ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_fw_ss51]clear control flag fail.");
+        ret = FAIL;
+        goto exit_burn_fw_ss51;
+    }
+    
+    //step4:burn ss51 firmware section 1
+    GTP_DEBUG("[burn_fw_ss51]step4:burn ss51 firmware section 1");
+    ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x01);
+    if(FAIL == ret)
+    {
+        GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 1 fail.");
+        goto exit_burn_fw_ss51;
+    }
+    
+    //step5:load ss51 firmware section 2 file data
+    GTP_DEBUG("[burn_fw_ss51]step5:load ss51 firmware section 2 file data");
+    ret = gup_load_section_file(fw_ss51, FW_SECTION_LENGTH, FW_SECTION_LENGTH);
+    if(FAIL == ret)
+    {
+        GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 2 fail.");
+        goto exit_burn_fw_ss51;
+    }
+    
+    //step6:burn ss51 firmware section 2
+    GTP_DEBUG("[burn_fw_ss51]step6:burn ss51 firmware section 2");
+    ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x02);
+    if(FAIL == ret)
+    {
+        GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 2 fail.");
+        goto exit_burn_fw_ss51;
+    }
+    
+    //step7:load ss51 firmware section 3 file data
+    GTP_DEBUG("[burn_fw_ss51]step7:load ss51 firmware section 3 file data");
+    ret = gup_load_section_file(fw_ss51, 2*FW_SECTION_LENGTH, FW_SECTION_LENGTH);
+    if(FAIL == ret)
+    {
+        GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 3 fail.");
+        goto exit_burn_fw_ss51;
+    }
+    
+    //step8:burn ss51 firmware section 3
+    GTP_DEBUG("[burn_fw_ss51]step8:burn ss51 firmware section 3");
+    ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x13);
+    if(FAIL == ret)
+    {
+        GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 3 fail.");
+        goto exit_burn_fw_ss51;
+    }
+    
+    //step9:load ss51 firmware section 4 file data
+    GTP_DEBUG("[burn_fw_ss51]step9:load ss51 firmware section 4 file data");
+    ret = gup_load_section_file(fw_ss51, 3*FW_SECTION_LENGTH, FW_SECTION_LENGTH);
+    if(FAIL == ret)
+    {
+        GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 4 fail.");
+        goto exit_burn_fw_ss51;
+    }
+    
+    //step10:burn ss51 firmware section 4
+    GTP_DEBUG("[burn_fw_ss51]step10:burn ss51 firmware section 4");
+    ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x14);
+    if(FAIL == ret)
+    {
+        GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 4 fail.");
+        goto exit_burn_fw_ss51;
+    }
+    
+    ret = SUCCESS;
+    
+exit_burn_fw_ss51:
+    kfree(fw_ss51);
+    return ret;
+}
+
+static u8 gup_burn_fw_dsp(struct i2c_client *client)
+{
+    s32 ret = 0;
+    u8* fw_dsp = NULL;
+    u8  retry = 0;
+    u8  rd_buf[5];
+    
+    GTP_DEBUG("[burn_fw_dsp]Begin burn dsp firmware---->>");
+    //step1:alloc memory
+    GTP_DEBUG("[burn_fw_dsp]step1:alloc memory");
+    while(retry++ < 5)
+    {
+        fw_dsp = (u8*)kzalloc(FW_DSP_LENGTH, GFP_KERNEL);
+        if(fw_dsp == NULL)
+        {
+            continue;
+        }
+        else
+        {
+            GTP_INFO("[burn_fw_dsp]Alloc %dk byte memory success.", (FW_SECTION_LENGTH/1024));
+            break;
+        }
+    }
+    if(retry >= 5)
+    {
+        GTP_ERROR("[burn_fw_dsp]Alloc memory fail,exit.");
+        return FAIL;
+    }
+    
+    //step2:load firmware dsp
+    GTP_DEBUG("[burn_fw_dsp]step2:load firmware dsp");
+    ret = gup_load_section_file(fw_dsp, 4*FW_SECTION_LENGTH, FW_DSP_LENGTH);
+    if(FAIL == ret)
+    {
+        GTP_ERROR("[burn_fw_dsp]load firmware dsp fail.");
+        goto exit_burn_fw_dsp;
+    }
+    
+    //step3:select bank3
+    GTP_DEBUG("[burn_fw_dsp]step3:select bank3");
+    ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_fw_dsp]select bank3 fail.");
+        ret = FAIL;
+        goto exit_burn_fw_dsp;
+    }
+    
+    //step4:hold ss51 & dsp
+    GTP_DEBUG("[burn_fw_dsp]step4:hold ss51 & dsp");
+    ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_fw_dsp]hold ss51 & dsp fail.");
+        ret = FAIL;
+        goto exit_burn_fw_dsp;
+    }
+    
+    //step5:set scramble
+    GTP_DEBUG("[burn_fw_dsp]step5:set scramble");
+    ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_fw_dsp]set scramble fail.");
+        ret = FAIL;
+        goto exit_burn_fw_dsp;
+    }
+    
+    //step6:release ss51 & dsp
+    GTP_DEBUG("[burn_fw_dsp]step6:release ss51 & dsp");
+    ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);                 //20121211
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_fw_dsp]release ss51 & dsp fail.");
+        ret = FAIL;
+        goto exit_burn_fw_dsp;
+    }
+    //must delay
+    msleep(1);
+    
+    //step7:burn 4k dsp firmware
+    GTP_DEBUG("[burn_fw_dsp]step7:burn 4k dsp firmware");
+    ret = gup_burn_proc(client, fw_dsp, 0x9000, FW_DSP_LENGTH);
+    if(FAIL == ret)
+    {
+        GTP_ERROR("[burn_fw_dsp]burn fw_section fail.");
+        goto exit_burn_fw_dsp;
+    }
+    
+    //step8:send burn cmd to move data to flash from sram
+    GTP_DEBUG("[burn_fw_dsp]step8:send burn cmd to move data to flash from sram");
+    ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x05);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_fw_dsp]send burn cmd fail.");
+        goto exit_burn_fw_dsp;
+    }
+    GTP_DEBUG("[burn_fw_dsp]Wait for the burn is complete......");
+    do{
+        ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+        if(ret <= 0)
+        {
+            GTP_ERROR("[burn_fw_dsp]Get burn state fail");
+            goto exit_burn_fw_dsp;
+        }
+        msleep(10);
+        //GTP_DEBUG("[burn_fw_dsp]Get burn state:%d.", rd_buf[GTP_ADDR_LENGTH]);
+    }while(rd_buf[GTP_ADDR_LENGTH]);
+    
+    //step9:recall check 4k dsp firmware
+    GTP_DEBUG("[burn_fw_dsp]step9:recall check 4k dsp firmware");
+    ret = gup_recall_check(client, fw_dsp, 0x9000, FW_DSP_LENGTH);
+    if(FAIL == ret)
+    {
+        GTP_ERROR("[burn_fw_dsp]recall check 4k dsp firmware fail.");
+        goto exit_burn_fw_dsp;
+    }
+    
+    ret = SUCCESS;
+    
+exit_burn_fw_dsp:
+    kfree(fw_dsp);
+    return ret;
+}
+
+static u8 gup_burn_fw_boot(struct i2c_client *client)
+{
+    s32 ret = 0;
+    u8* fw_boot = NULL;
+    u8  retry = 0;
+    u8  rd_buf[5];
+    
+    GTP_DEBUG("[burn_fw_boot]Begin burn bootloader firmware---->>");
+    
+    //step1:Alloc memory
+    GTP_DEBUG("[burn_fw_boot]step1:Alloc memory");
+    while(retry++ < 5)
+    {
+        fw_boot = (u8*)kzalloc(FW_BOOT_LENGTH, GFP_KERNEL);
+        if(fw_boot == NULL)
+        {
+            continue;
+        }
+        else
+        {
+            GTP_INFO("[burn_fw_boot]Alloc %dk byte memory success.", (FW_BOOT_LENGTH/1024));
+            break;
+        }
+    }
+    if(retry >= 5)
+    {
+        GTP_ERROR("[burn_fw_boot]Alloc memory fail,exit.");
+        return FAIL;
+    }
+    
+    //step2:load firmware bootloader
+    GTP_DEBUG("[burn_fw_boot]step2:load firmware bootloader");
+    ret = gup_load_section_file(fw_boot, (4*FW_SECTION_LENGTH+FW_DSP_LENGTH), FW_BOOT_LENGTH);
+    if(FAIL == ret)
+    {
+        GTP_ERROR("[burn_fw_boot]load firmware dsp fail.");
+        goto exit_burn_fw_boot;
+    }
+    
+    //step3:hold ss51 & dsp
+    GTP_DEBUG("[burn_fw_boot]step3:hold ss51 & dsp");
+    ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_fw_boot]hold ss51 & dsp fail.");
+        ret = FAIL;
+        goto exit_burn_fw_boot;
+    }
+    
+    //step4:set scramble
+    GTP_DEBUG("[burn_fw_boot]step4:set scramble");
+    ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_fw_boot]set scramble fail.");
+        ret = FAIL;
+        goto exit_burn_fw_boot;
+    }
+    
+    //step5:release ss51 & dsp
+    GTP_DEBUG("[burn_fw_boot]step5:release ss51 & dsp");
+    ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);                 //20121211
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_fw_boot]release ss51 & dsp fail.");
+        ret = FAIL;
+        goto exit_burn_fw_boot;
+    }
+    //must delay
+    msleep(1);
+    
+    //step6:select bank3
+    GTP_DEBUG("[burn_fw_boot]step6:select bank3");
+    ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_fw_boot]select bank3 fail.");
+        ret = FAIL;
+        goto exit_burn_fw_boot;
+    }
+    
+    //step7:burn 2k bootloader firmware
+    GTP_DEBUG("[burn_fw_boot]step7:burn 2k bootloader firmware");
+    ret = gup_burn_proc(client, fw_boot, 0x9000, FW_BOOT_LENGTH);
+    if(FAIL == ret)
+    {
+        GTP_ERROR("[burn_fw_boot]burn fw_section fail.");
+        goto exit_burn_fw_boot;
+    }
+    
+    //step7:send burn cmd to move data to flash from sram
+    GTP_DEBUG("[burn_fw_boot]step7:send burn cmd to move data to flash from sram");
+    ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x06);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_fw_boot]send burn cmd fail.");
+        goto exit_burn_fw_boot;
+    }
+    GTP_DEBUG("[burn_fw_boot]Wait for the burn is complete......");
+    do{
+        ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+        if(ret <= 0)
+        {
+            GTP_ERROR("[burn_fw_boot]Get burn state fail");
+            goto exit_burn_fw_boot;
+        }
+        msleep(10);
+        //GTP_DEBUG("[burn_fw_boot]Get burn state:%d.", rd_buf[GTP_ADDR_LENGTH]);
+    }while(rd_buf[GTP_ADDR_LENGTH]);
+    
+    //step8:recall check 2k bootloader firmware
+    GTP_DEBUG("[burn_fw_boot]step8:recall check 2k bootloader firmware");
+    ret = gup_recall_check(client, fw_boot, 0x9000, FW_BOOT_LENGTH);
+    if(FAIL == ret)
+    {
+        GTP_ERROR("[burn_fw_boot]recall check 4k dsp firmware fail.");
+        goto exit_burn_fw_boot;
+    }
+    
+    //step9:enable download DSP code 
+    GTP_DEBUG("[burn_fw_boot]step9:enable download DSP code ");
+    ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x99);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_fw_boot]enable download DSP code fail.");
+        ret = FAIL;
+        goto exit_burn_fw_boot;
+    }
+    
+    //step10:release ss51 & hold dsp
+    GTP_DEBUG("[burn_fw_boot]step10:release ss51 & hold dsp");
+    ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x08);
+    if(ret <= 0)
+    {
+        GTP_ERROR("[burn_fw_boot]release ss51 & hold dsp fail.");
+        ret = FAIL;
+        goto exit_burn_fw_boot;
+    }
+    
+    ret = SUCCESS;
+    
+exit_burn_fw_boot:
+    kfree(fw_boot);
+    return ret;
+}
+
+s32 gup_update_proc(void *dir)
+{
+    s32 ret = 0;
+    u8  retry = 0;
+    st_fw_head fw_head;
+    struct goodix_ts_data *ts = NULL;
+    
+    GTP_DEBUG("[update_proc]Begin update ......");
+    
+    show_len = 1;
+    total_len = 100;
+    if(dir == NULL)
+    {
+        msleep(3000);                               //wait main thread to be completed
+    }
+    
+    ts = i2c_get_clientdata(i2c_connect_client);
+    
+    if (searching_file)
+    {
+        searching_file = 0;     // exit .bin update file searching 
+        GTP_INFO("Exiting searching .bin update file...");
+        while ((show_len != 200) && (show_len != 100))     // wait for auto update quitted completely
+        {
+            msleep(100);
+        }
+    }
+    
+    update_msg.file = NULL;
+    ret = gup_check_update_file(i2c_connect_client, &fw_head, (u8*)dir);     //20121211
+    if(FAIL == ret)
+    {
+        GTP_ERROR("[update_proc]check update file fail.");
+        goto file_fail;
+    }
+    
+    //gtp_reset_guitar(i2c_connect_client, 20);
+    ret = gup_get_ic_fw_msg(i2c_connect_client);
+    if(FAIL == ret)
+    {
+        GTP_ERROR("[update_proc]get ic message fail.");
+        goto file_fail;
+    }    
+    
+    ret = gup_enter_update_judge(&fw_head);
+    if(FAIL == ret)
+    {
+        GTP_ERROR("[update_proc]Check *.bin file fail.");
+        goto file_fail;
+    }
+    
+    ts->enter_update = 1;        
+    gtp_irq_disable(ts);
+#if GTP_ESD_PROTECT
+    gtp_esd_switch(ts->client, SWITCH_OFF);
+#endif
+    ret = gup_enter_update_mode(i2c_connect_client);
+    if(FAIL == ret)
+    {
+         GTP_ERROR("[update_proc]enter update mode fail.");
+         goto update_fail;
+    }
+    
+    while(retry++ < 5)
+    {
+        show_len = 10;
+        total_len = 100;
+        ret = gup_burn_dsp_isp(i2c_connect_client);
+        if(FAIL == ret)
+        {
+            GTP_ERROR("[update_proc]burn dsp isp fail.");
+            continue;
+        }
+        
+        show_len += 10;
+        ret = gup_burn_fw_ss51(i2c_connect_client);
+        if(FAIL == ret)
+        {
+            GTP_ERROR("[update_proc]burn ss51 firmware fail.");
+            continue;
+        }
+        
+        show_len += 40;
+        ret = gup_burn_fw_dsp(i2c_connect_client);
+        if(FAIL == ret)
+        {
+            GTP_ERROR("[update_proc]burn dsp firmware fail.");
+            continue;
+        }
+        
+        show_len += 20;
+        ret = gup_burn_fw_boot(i2c_connect_client);
+        if(FAIL == ret)
+        {
+            GTP_ERROR("[update_proc]burn bootloader firmware fail.");
+            continue;
+        }
+        show_len += 10;
+        GTP_INFO("[update_proc]UPDATE SUCCESS.");
+        break;
+    }
+    if(retry >= 5)
+    {
+        GTP_ERROR("[update_proc]retry timeout,UPDATE FAIL.");
+        goto update_fail;
+    }
+    
+    GTP_DEBUG("[update_proc]leave update mode.");
+    gup_leave_update_mode();
+    
+    msleep(100);
+//    GTP_DEBUG("[update_proc]send config.");
+//    ret = gtp_send_cfg(i2c_connect_client);
+//    if(ret < 0)
+//    {
+//        GTP_ERROR("[update_proc]send config fail.");
+//    }
+    if (ts->fw_error)
+    {
+        GTP_INFO("firmware error auto update, resent config!");
+        gup_init_panel(ts);
+    }
+    show_len = 100;
+    total_len = 100;
+    ts->enter_update = 0;
+    gtp_irq_enable(ts);
+    
+#if GTP_ESD_PROTECT
+    gtp_esd_switch(ts->client, SWITCH_ON);
+#endif
+    filp_close(update_msg.file, NULL);
+    return SUCCESS;
+    
+update_fail:
+    ts->enter_update = 0;
+    gtp_irq_enable(ts);
+    
+#if GTP_ESD_PROTECT
+    gtp_esd_switch(ts->client, SWITCH_ON);
+#endif
+
+file_fail:
+    if(update_msg.file && !IS_ERR(update_msg.file))
+    {
+        filp_close(update_msg.file, NULL);
+    }
+    show_len = 200;
+    total_len = 100;
+    return FAIL;
+}
+
+#if GTP_AUTO_UPDATE
+u8 gup_init_update_proc(struct goodix_ts_data *ts)
+{
+    struct task_struct *thread = NULL;
+
+    GTP_INFO("Ready to run update thread.");
+    thread = kthread_run(gup_update_proc, (void*)NULL, "guitar_update");
+    if (IS_ERR(thread))
+    {
+        GTP_ERROR("Failed to create update thread.\n");
+        return -1;
+    }
+
+    return 0;
+}
+#endif
\ No newline at end of file