触摸屏GT9xx移植

来源:互联网 发布:吉他收费软件 编辑:程序博客网 时间:2024/05/17 09:25

下载GT9xx的源码http://download.csdn.net/detail/u012724126/6506027

解压并编写Makefile文件,gt9xx.c的源码并不需要修改,gt9xx.h需根据平台和触摸屏进行一定的修改。

gt9xx.c的内容为

/* 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>#endifstatic 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    #endifstatic 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_EARLYSUSPENDstatic void goodix_ts_early_suspend(struct early_suspend *h);static void goodix_ts_late_resume(struct early_suspend *h);#endif #if GTP_CREATE_WR_NODEextern s32 init_wr_node(struct i2c_client*);extern void uninit_wr_node(void);#endif#if GTP_AUTO_UPDATEextern u8 gup_init_update_proc(struct goodix_ts_data *);#endif#if GTP_ESD_PROTECTstatic 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_WAKEUPtypedef 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);#endifstatic u8 chip_gt9xxs = 0;  // true if ic is gt9xxs, like gt915su8 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 countOutput:    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 countOutput:    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 resultsInput:    client:  i2c device    addr:    operate address    rxbuf:   read data to store, if compare successful    len:     bytes to readOutput:    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 functionInput:    ts: goodix i2c_client private dataOutput:    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 functionInput:    ts: goodix i2c_client private dataOutput:    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 pressureOutput:    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 eventInput:    ts: goodix i2c_client private dataOutput:    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 functionInput:    work: work struct of goodix_workqueueOutput:    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;        u8 report_num = 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);                report_num++;                pre_touch |= 0x01 << i;                                if(report_num < touch_num)                {                    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 pointerOutput:    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 pointerOutput:    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 millisecondOutput:    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 dataOutput:    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 dataOutput:    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;        }    }   <span style="color:#FF0000;"> GTP_DEBUG("Sensor_ID: %d", sensor_id);//根据该id发不同的配置</span>        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 versionOutput:    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 workInput:    client:  i2c device    on:      SWITCH_ON / SWITCH_OFFOutput:    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, >p_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(>p_esd_check_work);        }    }}/*******************************************************Function:    Initialize external watchdog for esd protectInput:    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/07Input:    work: delayed workOutput:    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, >p_esd_check_work, GTP_ESD_CHECK_CIRCLE);    }    else    {        GTP_INFO("Esd terminated!");        ts->esd_running = 0;    }    return;}#endifstatic 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(>p_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");

gt9xx.h的内容为

/* 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         //是否打开X,Y坐标交换,这个比较容易判断,在屏幕上滑动一下便可知道#define GTP_DRIVER_SEND_CFG   1#define GTP_HAVE_TOUCH_KEY    0#define GTP_POWER_CTRL_SLEEP  0#define GTP_ICS_SLOT_REPORT     0  //坐标点汇报方式,在rk3188上需定义为1#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_ */

编译Makefile文件

ifeq ($(KERNELRELEASE),)         KERNELDIR_OUT ?= /home/w/M8974AAAAANLYD4275/out/target/product/msm8974/obj/KERNEL_OBJDBG_CROSS_COMPILE ?= /home/w/M8974AAAAANLYD4275/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-    PWD := $(shell pwd)             modules:                         #编译为驱动模块        $(MAKE) -C $(KERNELDIR_OUT) M=$(PWD) ARCH=arm CROSS_COMPILE=$(DBG_CROSS_COMPILE) modules    modules_install:        $(MAKE) -C $(KERNELDIR_OUT) M=$(PWD) ARCH=arm CROSS_COMPILE=$(DBG_CROSS_COMPILE) modules  clean:        rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions modules.order Module.symvers        .PHONY: modules modules_install clean         else                                  GT9xx_CORE_OBJS  := gt9xx.o             #指定驱动模块的核心文件(有init 和 exit)    GT9xx_OTHER_OBJS := goodix_tool.o gt9xx_update.o #依赖文件    touchscreen-objs   := $(GT9xx_CORE_OBJS) $(GT9xx_OTHER_OBJS) #xxx-objs := 指定驱动模块的所有依赖文件    obj-m := touchscreen.o   #最终由xxx-objs链接生成touchscreen.o,再生成touchscreen.ko    endif

然后在板级文件中注册该路IIC的设备信息  

{        .type            =  "Goodix-TS",        .addr            =   0x14,        .flags            =   0,},

或者在设备树上参考其他i2c设备添加ii2信息。

当然,i2c设备信息也可直接写在gt9xx.c的驱动中,可参考

http://blog.csdn.net/mike8825/article/details/51335582

goodix_ts_probe函数跑起来了,说明设备和驱动已经匹配成功。

接下来,确定点击触摸屏有没有检测到中断(/proc/interrupts),如果没有中断,检查中断IO口有没有配置出错,以及通过硬件手段来确定有没有中断信号。

至此,GT9xx驱动移植成功。

参考资料

http://blog.csdn.net/wocao1226/article/details/42459673

1 1
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 我头发油头皮痒脱发怎么办 油性头发容易掉发怎么办 洗了头发很蓬松怎么办 小孩头皮黄掉头发怎么办 头发又油又掉发怎么办 英国的水掉头发怎么办 洗发为什么会掉头发怎么办 头发老掉怎么办吃什么 19岁掉头发严重怎么办 头发总是从根掉怎么办 18岁掉头发很厉害怎么办 20岁脱发严重该怎么办 22岁m型脱发严重怎么办 22掉头发很厉害怎么办 哺乳期头发掉的很厉害怎么办 失眠多梦掉头发怎么办 老婆生完孩子掉头发怎么办 16岁发际线高怎么办 生了小孩头发掉怎么办 16岁头发掉的厉害怎么办 经常脱发严重不长头发怎么办 产后3年一直脱发怎么办 生完宝宝头发掉怎么办 生完小孩掉好多头发怎么办 脱发头发掉的厉害怎么办 宝宝四个月妈妈掉头发怎么办 产后四个月掉头发怎么办 洗头时严重掉发怎么办 头发老是掉得到处都是怎么办 短发洗完头头发向外外怎么办 20岁掉头发厉害怎么办 20岁老掉头发怎么办 20岁有点掉头发怎么办 20岁开始掉头发怎么办 20岁掉头发严重怎么办 20岁脱发很严重怎么办 手的纹路很深怎么办 20岁白头发很多怎么办 一天掉40根头发怎么办 烫完头发掉头皮怎么办 接发遗留的胶水怎么办