N32926移植电容触摸屏GT911驱动到内核

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/YYGY731793898/article/details/73329837

此驱动在N32926上亲测可用,烧程序前请看第三条,少走弯路。

一.打开新唐N32926 BSP 进入rootfs-2.6.35文件夹,打开/etc/profile文件可以看到,有关触摸屏的环境变量声明都在这:

exportPATH=$PATH:/mnt/nand1-2/bin

exportLD_LIBRARY_PATH=./

exportQWS_MOUSE_PROTO="Tslib:/dev/input/event0"

exportTSLIB_CONFFILE=/etc/ts.conf

exportTSLIB_PLUGINDIR=/usr/gui/tslib/lib/ts

exportTSLIB_TSDEVICE=/dev/input/event0

 exportTSLIB_CALIBFILE=/mnt/nand1-1/pointercal

在文件系统中,触摸屏的库tslib1.0,及测试程序都有了。校准程序在rootfs-2.6.35/usr/bin。

/etc/ts.conf文件本来已修改好

扫描二维码关注公众号,回复: 6436563 查看本文章

开发板运行后的/mnt/nand1-1/boot_script文件内容如下,请看情况设置。

export LD_LIBRARY_PATH=/lib:/mnt/nand1-1/qt/lib/:$LD_LIBRARY_PATH

export QT_QWS_FONTDIR=/mnt/nand1-1/qt/lib/fonts/                

export QWS_SIZE=1024x600                       

export QWS_DISPLAY="LinuxFb:mmWidth218:mmHeight208:0"

export QT_PLUGIN_PATH=/mnt/nand1-1/qt/lib/plugins/  

export QWS_KEYBOARD="TTY:/dev/tty5"              

#export QWS_MOUSE_PROTO="IntelliMouse:/dev/input/mouse0"

export PATH=/bin:$PATH                                 

                      

if [-f /mnt/nand1-1/pointercal ]; then

       echo "havepointercal file!"

else                               

       #/mnt/nand1-1/qt/bin/ts_calibrate

       /usr/bin/ts_calibrate

fi                          

cp/mnt/nand1-1/pointercal   /etc

//最后一句,QT程序会到/etc目录下找pointercal校准文件。这里拷贝过去。

二.     开始移植

1.    修改Makefile:在drivers/input/touchscreen目录下,打开Makefile,增加条目obj-$(CONFIG_TOUCHSCREEN_GT9XX) +=gt9xx.o

2.   修改Kconfig:在drivers/input/touchscreen目录下,打开Kconfig,在最后增加:

configTOUCHSCREEN_GT9XX

    tristate"GT9XX based touchscreens"

    dependson I2C

   help

        Say Y here if you have a GT9XX basedtouchscreen

       controller.

       If unsure, say N.

        To compile this driver as a module,choose M here: the

      module will be called gt9xx_ts.

3.   添加设备:在arch/arm/mach-w55fa92/mach-w55fa92.c中,向

staticstruct i2c_board_info __initdataw55fa92_i2c_clients[] = { 数组中添加 

{

                 I2C_BOARD_INFO("Goodix-TS",0x5d),

        },

//"Goodix-TS"为I2C设备驱动名, 必须与后面的gt9xx.h中的宏定义

#defineGTP_I2C_NAME               "Goodix-TS" 一致

0X5D为GT911设置地址

4.makemenuconfig 在Device Drivers ->Input devicesupport->Event interface选上,Touchscreens也选上,并进入,选上GT9XX选项。

5.   添加驱动文件,在drivers/input/touchscreen目录下添加gt9xx.c gt9xx.h文件。

文件内容如下:

gt9xx.h

#ifndef_GOODIX_GT9XX_H_
#define_GOODIX_GT9XX_H_


#include<mach/w55fa92_reg.h>
#include<asm/io.h>
#include<mach/w55fa92_gpio.h>
#include<mach/irqs.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<linux/gpio.h>
#ifdefCONFIG_OF
#include<linux/of_gpio.h>
#include<linux/regulator/consumer.h>
#endif
#ifdefCONFIG_FB
#include<linux/notifier.h>
#include<linux/fb.h>
#endif
#ifdefCONFIG_HAS_EARLYSUSPEND
#include<linux/earlysuspend.h>
#endif


//***************************PART1:ON/OFFdefine*******************************
#defineGTP_CUSTOM_CFG        1   
#defineGTP_CHANGE_X2Y        0   //swap x y
#defineGTP_DRIVER_SEND_CFG   1   //driver send config 此开关根据需要选择
#defineGTP_CONFIG_MODE  0//触摸屏本来是好的,没有厂家数据表的情况下:0=从GT911中读原来的配置参数,修改后再配置
//有厂家数据表的情况  1:修改数据表后配置
#defineGTP_HAVE_TOUCH_KEY    0
#defineGTP_POWER_CTRL_SLEEP  0    //power off when suspend
#defineGTP_ICS_SLOT_REPORT   0    // slot protocol 


#defineGTP_AUTO_UPDATE       0    // auto update fw by .binfile as default
#defineGTP_HEADER_FW_UPDATE  0    // auto update fw by gtp_default_FWin gt9xx_firmware.h, function together with GTP_AUTO_UPDATE
#defineGTP_AUTO_UPDATE_CFG   0    // auto update config by .cfg file,function together with GTP_AUTO_UPDATE


#defineGTP_COMPATIBLE_MODE   0    // compatible with GT9XXF


#defineGTP_CREATE_WR_NODE    0
#defineGTP_ESD_PROTECT       0    // esd protection with acycle of 2 seconds


#defineGTP_WITH_PEN          0
#defineGTP_PEN_HAVE_BUTTON   0    // active pen has buttons, functiontogether with GTP_WITH_PEN


#defineGTP_GESTURE_WAKEUP    0    // gesture wakeup 


#defineGTP_DEBUG_ON          1
#defineGTP_DEBUG_ARRAY_ON    1
#defineGTP_DEBUG_FUNC_ON     0




structgt9xx_event {
inttouch_point;


u16x[5];
u16y[5];
u16w[5];
};


structgoodix_ts_data {
   spinlock_t irq_lock;
   struct i2c_client *client;
   struct input_dev  *input_dev;
structgt9xx_event event;
   struct hrtimer timer;
   struct work_struct  work;
   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  enter_update;
   u8  gtp_is_suspend;
   u8  gtp_rawdiff_mode;
   int  gtp_cfg_len;
   u8  fw_error;
   u8  pnl_init_error;


#if  defined(CONFIG_FB)
structnotifier_block notifier;
#elifdefined(CONFIG_HAS_EARLYSUSPEND)
structearly_suspend early_suspend;
#endif
 
};




externint gtp_rst_gpio;
externint gtp_int_gpio;


//***************************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. 
// Thepredefined one is just a sample config, which is not suitable for your tp inmost cases.
//------此配置表由触摸屏厂家提供,如何没有,千万不要配置,得先读出原来的配置参数,否则触摸屏配置后可能不能使用。---//
#defineCTP_CFG_GROUP0 {\
0x42,0x00,0x04,0x58,0x02,0x05,0x3D,0x00,0x01,0x08,\
0x28,0x08,0x50,0x3C,0x03,0x05,0x00,0x00,0x00,0x00,\
0x00,0x00,0x00,0x18,0x1A,0x1E,0x14,0x89,0x2A,0x0B,\
0x40,0x42,0xB5,0x06,0x00,0x00,0x00,0x02,0x02,0x1D,\
0x00,0x01,0x00,0x00,0x00,0x03,0x64,0x00,0x00,0x00,\
0x00,0x32,0x5A,0x94,0xC5,0x02,0x08,0x00,0x00,0x00,\
0x98,0x35,0x00,0x8A,0x3B,0x00,0x7A,0x43,0x00,0x6E,\
0x4B,0x00,0x62,0x55,0x00,0x62,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,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0E,0x10,\
0x12,0x14,0x16,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,\
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
0x00,0x00,0x00,0x02,0x04,0x06,0x08,0x0A,0x0F,0x10,\
0x12,0x16,0x18,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,\
0x24,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,\
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
0x00,0x00,0x00,0x00,0x60,0x01} 
  
//STEP_2(REQUIRED): Customize your I/O ports & I/O operations
//---此部分根据芯片设置,以下为N32926的设置---//
#defineGTP_RST_PORT    0x6d//GPD13
#defineGTP_INT_PORT    0x6e//GPD14
#defineGTP_INT_IRQ_NUM             W55FA92_IRQ(4) // nIRQ2
#defineCLEAR_EXT_INTERRUPT_FLAG() writel(readl(REG_IRQTGSRC1) &(1<<(GTP_INT_PORT%0X20)), REG_IRQTGSRC1)//清INT中断标志GPD14 
#defineREAD_EXT_INTERRUPT_FLAG() readl(REG_IRQTGSRC1)& 0xffff0000//读INT中断标志GPD


//外部中断2  
#defineGPIO_SET_SRCGRP() do{\
writel(readl(REG_IRQSRCGPD)& ~((3 << (GTP_INT_PORT%0X20)*2)), REG_IRQSRCGPD);\
writel(readl(REG_IRQSRCGPD)|((2 << (GTP_INT_PORT%0X20)*2)), REG_IRQSRCGPD);\
}while(0)


//设置GPE1中断类型为下降沿
#defineGPIO_SET_INTMODE() do{\
writel((readl(REG_IRQENGPD)&~((1<<((GTP_INT_PORT%0X20)+16)) | (1<<(GTP_INT_PORT%0X20)))),REG_IRQENGPD);\
writel((readl(REG_IRQENGPD)| (1<<((GTP_INT_PORT%0X20)+16))), REG_IRQENGPD);\
}while(0)
#defineEXT_SET_MODE() writel((readl(REG_AIC_SCR1)& ~(0x07000000)) | 0x07000000,REG_AIC_SCR1)//外部中断2,下降沿,级别7
       
#defineGTP_CONFIG_PIN(pin) w55fa92_gpio_configure(pin/0x20,pin%0x20)  

#defineGTP_GPIO_AS_INPUT(pin)          do{\
                                         gpio_direction_input(pin);\
                                      }while(0)
#defineGTP_GPIO_GET_VALUE(pin)         gpio_get_value(pin)
#defineGTP_GPIO_OUTPUT(pin,level)      gpio_direction_output(pin,level)

#defineGTP_GPIO_AS_INT(pin)            do{\
                                         GTP_GPIO_AS_INPUT(pin);\
\
                                      }while(0)


#defineGTP_GPIO_REQUEST(pin, label)    gpio_request(pin, label)
#defineGTP_GPIO_FREE(pin)             gpio_free(pin)
#defineGTP_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
#ifGTP_CUSTOM_CFG
 #define GTP_MAX_HEIGHT   600
 #define GTP_MAX_WIDTH    1024
 #define GTP_INT_TRIGGER  1           // 0: Rising1: Falling
#else
 #define GTP_MAX_HEIGHT   4096
 #define GTP_MAX_WIDTH    4096
 #define GTP_INT_TRIGGER  1
#endif
#defineGTP_MAX_TOUCH         1


//STEP_4(optional): If keys are available and reported as keys, config your keyinfo here                            
#ifGTP_HAVE_TOUCH_KEY
   #define GTP_KEY_TAB  {KEY_MENU, KEY_HOME, KEY_BACK}
#endif


//***************************PART3:OTHERdefine*********************************
#defineGTP_DRIVER_VERSION         "V2.4<2014/11/28>"
#defineGTP_I2C_NAME               "Goodix-TS"
#defineGT91XX_CONFIG_PROC_FILE     "gt9xx_config"
#defineGTP_POLL_TIME         10    
#defineGTP_ADDR_LENGTH       2
#defineGTP_CONFIG_MIN_LENGTH 186
#defineGTP_CONFIG_MAX_LENGTH 240
#defineFAIL                  0
#defineSUCCESS               1
#defineSWITCH_OFF            0
#defineSWITCH_ON             1


//********************For GT9XXF Start **********************//
#defineGTP_REG_BAK_REF                 0x99D0
#defineGTP_REG_MAIN_CLK                0x8020
#defineGTP_REG_CHIP_TYPE               0x8000
#defineGTP_REG_HAVE_KEY                0x804E
#defineGTP_REG_MATRIX_DRVNUM           0x8069    
#defineGTP_REG_MATRIX_SENNUM           0x806A


#defineGTP_FL_FW_BURN              0x00
#defineGTP_FL_ESD_RECOVERY         0x01
#defineGTP_FL_READ_REPAIR          0x02


#defineGTP_BAK_REF_SEND                0
#defineGTP_BAK_REF_STORE               1
#defineCFG_LOC_DRVA_NUM                29
#defineCFG_LOC_DRVB_NUM                30
#defineCFG_LOC_SENS_NUM                31


#defineGTP_CHK_FW_MAX                  40
#defineGTP_CHK_FS_MNT_MAX              300
#defineGTP_BAK_REF_PATH               "/data/gtp_ref.bin"
#defineGTP_MAIN_CLK_PATH              "/data/gtp_clk.bin"
#defineGTP_RQST_CONFIG                 0x01
#defineGTP_RQST_BAK_REF                0x02
#defineGTP_RQST_RESET                 0x03
#defineGTP_RQST_MAIN_CLOCK             0x04
#defineGTP_RQST_RESPONDED              0x00
#defineGTP_RQST_IDLE                  0xFF


//********************For GT9XXF End **********************//
//Registers define
#defineGTP_READ_COOR_ADDR    0x814E
#defineGTP_REG_SLEEP         0x8040
#defineGTP_REG_SENSOR_ID     0x814A
#defineGTP_REG_CONFIG_DATA   0x8047
#defineGTP_REG_VERSION       0x8140
#defineGTP_REG_COMMAND  0x8040


#defineGTP_COMMAND_READSTATUS        0
#defineGTP_COMMAND_DIFFERENCE        1
#defineGTP_COMMAND_SOFTRESET        2
#defineGTP_COMMAND_UPDATE       3
#defineGTP_COMMAND_CALCULATE          4
#defineGTP_COMMAND_TURNOFF         5


#defineRESOLUTION_LOC        3
#defineTRIGGER_LOC           8


#defineCFG_GROUP_LEN(p_cfg_grp)  (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0]))
// Logdefine
#defineGTP_INFO(fmt,arg...)          printk("<<-GTP-INFO->> "fmt"\n",##arg)
#defineGTP_ERROR(fmt,arg...)         printk("<<-GTP-ERROR->> "fmt"\n",##arg)
#defineGTP_DEBUG(fmt,arg...)          do{\
                                       if(GTP_DEBUG_ON)\
                                      printk("<<-GTP-DEBUG->>[%d]"fmt"\n",__LINE__, ##arg);\
                                     }while(0)
#defineGTP_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("0x%02x,", (a)[i]);\
                                             if ((i + 1 ) %10 == 0)\
                                             {\
                                                 printk("\\\n");\
                                             }\
                                          }\
                                         printk("\n");\
                                      }\
                                     }while(0)
#defineGTP_DEBUG_FUNC()               do{\
                                       if(GTP_DEBUG_FUNC_ON)\
                                      printk("<<-GTP-FUNC->>Func:%s@Line:%d\n",__func__,__LINE__);\
                                     }while(0)
#defineGTP_SWAP(x, y)                 do{\
                                       typeof(x) z = x;\
                                       x = y;\
                                       y = z;\
                                     }while (0)


//*****************************Endof Part III********************************
#ifdefCONFIG_OF
intgtp_parse_dt_cfg(struct device *dev, u8 *cfg, int *cfg_len, u8 sid);
#endif
#endif/* _GOODIX_GT9XX_H_ */

gt9xx.c

//N32926yygyickl 20170615 ok
#include<linux/irq.h>
#include"gt9xx.h"


staticconst char *goodix_ts_name = "goodix-ts";
staticconst char *goodix_input_phys = "input/ts";
staticstruct workqueue_struct *goodix_wq;
structi2c_client * i2c_connect_client = NULL; 
intgtp_rst_gpio;
intgtp_int_gpio;
u8config[GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH]
               = {GTP_REG_CONFIG_DATA>> 8, GTP_REG_CONFIG_DATA & 0xff};


statics8 gtp_i2c_test(struct i2c_client *client);
voidgtp_reset_guitar(struct i2c_client *client, s32 ms);
s32gtp_send_cfg(struct i2c_client *client);
voidgtp_int_sync(s32 ms);


staticssize_t gt91xx_config_read_proc(struct file *, char __user *, size_t, loff_t*);
staticssize_t gt91xx_config_write_proc(struct file *, const char __user *, size_t,loff_t *);


staticstruct proc_dir_entry *gt91xx_config_proc = NULL;
staticconst struct file_operations config_proc_ops = {
   .owner = THIS_MODULE,
   .read = gt91xx_config_read_proc,
   .write = gt91xx_config_write_proc,
};
staticint gtp_register_powermanger(struct goodix_ts_data *ts);
staticint gtp_unregister_powermanger(struct goodix_ts_data *ts);






/*******************************************************
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
*********************************************************/
s32gtp_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, etc.
   
   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))
   {   
       GTP_ERROR("I2C Read: 0x%04X, %d bytes failed,errcode: %d! Process reset.", (((u16)(buf[0] << 8)) | buf[1]),len-2, ret);
       {
           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
*********************************************************/
s32gtp_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, etc


   while(retries < 5)
   {
       ret = i2c_transfer(client->adapter, &msg, 1);
       if (ret == 1)break;
       retries++;
   }
   if((retries >= 5))
   {
       GTP_ERROR("I2C Write: 0x%04X, %d bytes failed,errcode: %d! Process reset.", (((u16)(buf[0] << 8)) | buf[1]),len-2, ret);
       {
           gtp_reset_guitar(client, 10);  
       }
   }
   return ret;
}


/*******************************************************
Function:
   i2c Send_Command
Input:
   client:  i2c device
   command:   command
Output:
   ret:    >0 ok
=0failed
*********************************************************/
s8GTP_Send_Command(u8 command,struct i2c_client *client)
{
   s8 ret = -1;
   s8 retry = 0;
structgoodix_ts_data *ts = i2c_get_clientdata(client);
   u8 command_buf[3] = {(u8)(GTP_REG_COMMAND >> 8),(u8)GTP_REG_COMMAND&0xFF, 1};
command_buf[2]= command;


   GTP_DEBUG_FUNC();


   while(retry++ < 5)
   {
ret =gtp_i2c_write(client, command_buf , 1 + GTP_ADDR_LENGTH);
       if (ret > 0)
       {
           GTP_INFO("send command success!");


           return ret;
       }


   }
   GTP_ERROR("send command fail!");
   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
*********************************************************/
s32gtp_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))
       {
           memcpy(rxbuf, confirm_buf+2, len);
           return SUCCESS;
       }
   }    
   GTP_ERROR("I2C read 0x%04X, %d bytes, double check failed!",addr, len);
   return FAIL;
}


/*******************************************************
Function:
   i2c read config data check it
Input:
   client:  i2c device
Output:
   FAIL:    read failed
   SUCCESS: read successful
*********************************************************/
voidgtp_i2c_read_cfg_check(struct i2c_client *client)
{
structgoodix_ts_data *ts = i2c_get_clientdata(client);
u8buf[GTP_CONFIG_MIN_LENGTH + GTP_ADDR_LENGTH];


u8retry = 0;

memset(buf,0, ts->gtp_cfg_len + GTP_ADDR_LENGTH);
buf[0]= config[0];
buf[1]= config[1];
gtp_i2c_read(client,buf, ts->gtp_cfg_len + GTP_ADDR_LENGTH);
GTP_DEBUG_ARRAY(buf+GTP_ADDR_LENGTH,ts->gtp_cfg_len);
if(memcmp(buf+GTP_ADDR_LENGTH,config+GTP_ADDR_LENGTH, ts->gtp_cfg_len-1) == 0)
{
GTP_INFO("cfgcheck ok!\r\n");
returnSUCCESS;
}
else
{
GTP_INFO("cfgcheck failed!\r\n");
returnFAIL;
}

}




/*******************************************************
Function:
   Send config.
Input:
   client: i2c device.
Output:
   result of i2c write operation. 
       1: succeed, otherwise: failed
*********************************************************/


s32gtp_send_cfg(struct i2c_client *client)
{
   s32 ret = 2;


#ifGTP_DRIVER_SEND_CFG
   s32 retry = 0;
   struct goodix_ts_data *ts = i2c_get_clientdata(client);


   if (ts->pnl_init_error)
   {
       GTP_INFO("Error occured in init_panel, no configsent");
       return 0;
   }
   
   GTP_INFO("Driver send config.");
GTP_DEBUG_ARRAY(config+GTP_ADDR_LENGTH,ts->gtp_cfg_len);
   for (retry = 0; retry < 5; retry++)
   {
       ret = gtp_i2c_write(client, config , ts->gtp_cfg_len +GTP_ADDR_LENGTH);
       if (ret > 0)
       {
           break;
       }
   }

msleep(100);
gtp_i2c_read_cfg_check(client);
#endif
   return ret;
}
/*******************************************************
Function:
   Disable irq function
Input:
   ts: goodix i2c_client private data
Output:
   None.
*********************************************************/
voidgtp_irq_disable(struct goodix_ts_data *ts)
{


unsignedlong 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.
*********************************************************/
voidgtp_irq_enable(struct goodix_ts_data *ts)
{

unsignedlong 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.
*********************************************************/
staticvoid gtp_touch_down(struct goodix_ts_data* ts,s32 id,s32 x,s32 y,s32 w)
{
#ifGTP_CHANGE_X2Y
   GTP_SWAP(x, y);
#endif
input_report_abs(ts->input_dev,ABS_X, x);
input_report_abs(ts->input_dev,ABS_Y, y);
input_report_abs(ts->input_dev,ABS_PRESSURE, w);
input_report_key(ts->input_dev,BTN_TOUCH, 1);
input_sync(ts->input_dev);
   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.
*********************************************************/
staticvoid gtp_touch_up(struct goodix_ts_data* ts, s32 id)
{
input_report_abs(ts->input_dev,ABS_PRESSURE, 0);
input_report_key(ts->input_dev,BTN_TOUCH, 0);
input_sync(ts->input_dev);
GTP_DEBUG("touchrelease\r\n");
}


/*******************************************************
Function:
   Goodix touchscreen work function
Input:
   work: work struct of goodix_workqueue
Output:
   None.
*********************************************************/
staticvoid 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;
staticu8  pre_touch=0;
u8 test_data[12]={GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA &0xff};
   
  
   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;


   GTP_DEBUG_FUNC();
   ts = container_of(work, struct goodix_ts_data, work);
   if (ts->enter_update)
   {
       return;
   }


   ret = gtp_i2c_read(ts->client, point_data, 12);
   if (ret < 0)
   {
       GTP_ERROR("I2C transfer error. errno:%d\n ",ret);
       if (ts->use_irq)
       {
           gtp_irq_enable(ts);
       }
       return;
   }
   finger = point_data[GTP_ADDR_LENGTH];
   if (finger == 0x00)
   {
       if (ts->use_irq)
       {
           gtp_irq_enable(ts);
       }
       return;
   }


   if((finger & 0x80) == 0)
   {
GTP_DEBUG("I2Cfinger:%X, status err return.\r\n",finger);
gotoexit_work_func;//坐标未就绪,数据无效
   }


   touch_num = finger & 0x0f;


   if (touch_num > GTP_MAX_TOUCH)
   {
       GTP_DEBUG("touch_num:%X, toomuch\r\n",touch_num);
gotoexit_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 (touch_num)
{
for (i= 0; i < touch_num; i++)
       {
coor_data= &point_data[i * 8 + 3];
id =coor_data[0] & 0x0F;
ts->event.x[i]= input_x  = coor_data[1] | (coor_data[2] << 8);
ts->event.y[i]= input_y  = coor_data[3] | (coor_data[4] << 8);
ts->event.w[i]= input_w  = coor_data[5] | (coor_data[6] << 8);

gtp_touch_down(ts,id, input_x, input_y, input_w);
//gtp_touch_down(ts,id);
}

   }
elseif(pre_touch)
   {
gtp_touch_up(ts,id);
}
pre_touch= touch_num;

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_cmderror!");
       }
   }
   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
*********************************************************/
staticenum 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
*********************************************************/
staticirqreturn_t goodix_ts_irq_handler(int irq, void *dev_id)
{
   struct goodix_ts_data *ts = dev_id;

CLEAR_EXT_INTERRUPT_FLAG();//清INT端口中断标志GPE1 
gtp_irq_disable(ts);
queue_work(goodix_wq,&ts->work);
   return IRQ_HANDLED;
}
/*******************************************************
Function:
   Synchronization.
Input:
   ms: synchronization time in millisecond.
Output:
   None.
*******************************************************/
voidgtp_int_sync(s32 ms)
{
   GTP_GPIO_OUTPUT(gtp_int_gpio, 0);
   msleep(ms);
   GTP_GPIO_AS_INT(gtp_int_gpio);
}




/*******************************************************
Function:
   Reset chip.
Input:
   ms: reset time in millisecond
Output:
   None.
*******************************************************/
voidgtp_reset_guitar(struct i2c_client *client, s32 ms)
{
   GTP_DEBUG_FUNC();
   GTP_INFO("Guitar reset");
   GTP_GPIO_OUTPUT(gtp_rst_gpio, 0);   // begin select I2C slave addr
   msleep(ms);                        // T2: > 10ms
   // HIGH: 0x28/0x29, LOW: 0xBA/0xBB
   GTP_GPIO_OUTPUT(gtp_int_gpio, client->addr == 0x14);
   msleep(2);                         // T3: > 100us
   GTP_GPIO_OUTPUT(gtp_rst_gpio, 1); 
   msleep(10);                         // T4: > 5ms
   GTP_GPIO_AS_INPUT(gtp_rst_gpio);    // end select I2C slaveaddr
   gtp_int_sync(50);  
}




/*******************************************************
Function:
   Enter sleep mode.
Input:
   ts: private data.
Output:
   Executive outcomes.
      1: succeed, otherwise failed.
*******************************************************/
statics8 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_gpio, 0); //先拉低INT脚,再发送关屏命令5
   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;
}


/*******************************************************
Function:
   Wakeup from sleep.
Input:
   ts: private data.
Output:
   Executive outcomes.
       >0: succeed, otherwise: failed.
*******************************************************/
statics8 gtp_wakeup_sleep(struct goodix_ts_data * ts)
{
   u8 retry = 0;
   s8 ret = -1;
   
   GTP_DEBUG_FUNC();
   while(retry++ < 10)
   { 
       GTP_GPIO_OUTPUT(gtp_int_gpio, 1); //先拉高INT脚,再复位唤醒
       msleep(5);
       ret = gtp_i2c_test(ts->client);
       if (ret > 0)
       {
           GTP_INFO("GTP wakeup sleep.");
           
       #if (!GTP_GESTURE_WAKEUP)
           {
               gtp_int_sync(25);        
           }
       #endif
           
           return ret;
       }
       gtp_reset_guitar(ts->client, 20);
   }
   GTP_ERROR("GTP wakeup sleep failed.");
   return ret;
}


/*******************************************************
Function:
   Initialize gtp.
Input:
   ts: goodix private data
Output:
   Executive outcomes.
       0: succeed, otherwise: failed
*******************************************************/
statics32 gtp_init_panel(struct goodix_ts_data *ts)
{
   s32 ret = -1;
s32 i= 0;
   u8 check_sum = 0;
   u8 opr_buf[16] = {0};
   u8 sensor_id = 0;
u8drv_cfg_version;
u8flash_cfg_version;


   u8 send_cfg_buf[] = CTP_CFG_GROUP0;
   u8 cfg_info_len = GTP_CONFIG_MIN_LENGTH;
ts->gtp_cfg_len= cfg_info_len;

gtp_int_sync(20);//先同步一下INT脚才能读到正确的配置信息
memset(config+GTP_ADDR_LENGTH,0, GTP_CONFIG_MAX_LENGTH);
if(gtp_i2c_read(ts->client,config, GTP_CONFIG_MIN_LENGTH+GTP_ADDR_LENGTH) < 0)
{
GTP_DEBUG("readgt9xx config data failed! return.\r\n");
return-1;
}
GTP_DEBUG("readconfig data ok!,as follows:\r\n");
GTP_DEBUG_ARRAY(config+GTP_ADDR_LENGTH,GTP_CONFIG_MIN_LENGTH);//读出原配置信息,以利恢复, 记得将打印出来的配置信息保存

#ifGTP_DRIVER_SEND_CFG
   
/*check firmware */
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("Firmwareerror, no config sent!");
return-1;
}
}

#ifGTP_CONFIG_MODE //根据厂家数据表配置
memcpy(config+GTP_ADDR_LENGTH,send_cfg_buf, ts->gtp_cfg_len);


ret =gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA, &opr_buf[0],1);//读版本号
if(ret == SUCCESS) 
{
GTP_DEBUG("ConfigVersion: 0x%02X; IC Config Version: 0x%02X", \
config[GTP_ADDR_LENGTH],opr_buf[0]);


flash_cfg_version= opr_buf[0];
drv_cfg_version= config[GTP_ADDR_LENGTH];

if(flash_cfg_version < 90 && flash_cfg_version >drv_cfg_version) 
{
config[GTP_ADDR_LENGTH]= 0x00;//版本写入0,强制更新版本为0X41 A版本
}

else 
{
GTP_ERROR("Failedto get ic config version!No config sent!");
return-1;
}
#endif//GTP_CONFIG_MODE

#ifGTP_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);
config[RESOLUTION_LOC+ 4] = (u8)GTP_MAX_TOUCH;
   config[TRIGGER_LOC] &= 0xfc;
config[TRIGGER_LOC]|= GTP_INT_TRIGGER;
#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;
config[ts->gtp_cfg_len+1]= 1;

ret =gtp_send_cfg(ts->client);
if(ret < 0)
{
GTP_ERROR("Sendconfig error.");
}

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; 

#ifGTP_CONFIG_MODE //根据厂家数据表配置
if(flash_cfg_version < 90 && flash_cfg_version >drv_cfg_version) 
{
config[GTP_ADDR_LENGTH]= 0x41;//版本写入0x41 ,唤醒时不会强制更新版本
}
#endif//GTP_CONFIG_MODE

#else// driver not send config
  
   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_INFO("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;


}


staticssize_t gt91xx_config_read_proc(struct file *file, char __user *page, size_tsize, loff_t *ppos)
{
   char *ptr = page;
   char temp_data[GTP_CONFIG_MAX_LENGTH + 2] = {0x80, 0x47};
   int i;
   
   if (*ppos)
   {
       return 0;
   }
   ptr += sprintf(ptr, "==== GT9XX config init value====\n");


   for (i = 0 ; i < GTP_CONFIG_MAX_LENGTH ; i++)
   {
       ptr += sprintf(ptr, "0x%02X ", config[i + 2]);


       if (i % 8 == 7)
           ptr += sprintf(ptr, "\n");
   }


   ptr += sprintf(ptr, "\n");


   ptr += sprintf(ptr, "==== GT9XX config real value====\n");
   gtp_i2c_read(i2c_connect_client, temp_data, GTP_CONFIG_MAX_LENGTH + 2);
   for (i = 0 ; i < GTP_CONFIG_MAX_LENGTH ; i++)
   {
       ptr += sprintf(ptr, "0x%02X ", temp_data[i+2]);


       if (i % 8 == 7)
           ptr += sprintf(ptr, "\n");
   }
   *ppos += ptr - page;
   return (ptr - page);
}


staticssize_t gt91xx_config_write_proc(struct file *filp, const char __user *buffer,size_t count, loff_t *off)
{
   s32 ret = 0;


   GTP_DEBUG("write count %d\n", count);


   if (count > GTP_CONFIG_MAX_LENGTH)
   {
       GTP_ERROR("size not match [%d:%d]\n",GTP_CONFIG_MAX_LENGTH, count);
       return -EFAULT;
   }


   if (copy_from_user(&config[2], buffer, count))
   {
       GTP_ERROR("copy from user fail\n");
       return -EFAULT;
   }


   ret = gtp_send_cfg(i2c_connect_client);


   if (ret < 0)
   {
       GTP_ERROR("send config failed.");
   }


   return count;
}
/*******************************************************
Function:
   Read chip version.
Input:
   client:  i2c device
   version: buffer to keep ic firmware version
Output:
   read operation return.
       2: succeed, otherwise: failed
*******************************************************/
s32gtp_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
   {
       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.
*******************************************************/
statics8 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
*******************************************************/
statics8 gtp_request_io_port(struct goodix_ts_data *ts)
{
   s32 ret = 0;


   GTP_DEBUG_FUNC();
   ret = GTP_GPIO_REQUEST(gtp_int_gpio, "GTP INT IRQ");
   if (ret < 0) 
   {
       GTP_ERROR("Failed to request GPIO:%d, ERRNO:%d",(s32)gtp_int_gpio, ret);
       return -ENODEV;
   }
   
GTP_CONFIG_PIN(GTP_INT_PORT); 
GTP_GPIO_OUTPUT(GTP_INT_PORT,0);//为初始化作准备,设置GT911 I2C 从机地址
ts->client->irq= GTP_INT_IRQ_NUM;
   
   ret = GTP_GPIO_REQUEST(gtp_rst_gpio, "GTP RST PORT");
   if (ret < 0) 
   {
       GTP_ERROR("Failed to request GPIO:%d,ERRNO:%d",(s32)gtp_rst_gpio,ret);
GTP_GPIO_FREE(gtp_int_gpio);
       return -ENODEV;
   }
GTP_CONFIG_PIN(GTP_RST_PORT); 
GTP_GPIO_OUTPUT(GTP_RST_PORT,0);//为初始化作准备,设置GT911 I2C 从机地址

   gtp_reset_guitar(ts->client, 20); // 初始化
   return ret;
}


/*******************************************************
Function:
   Request interrupt.
Input:
   ts: private data.
Output:
   Executive outcomes.
       0: succeed, -1: failed.
*******************************************************/
statics8 gtp_request_irq(struct goodix_ts_data *ts)
{
   s32 ret = -1;
   const u8 irq_table[] = GTP_IRQ_TAB;
   GTP_DEBUG_FUNC();
   GTP_DEBUG("INT NOMBER:0x%x, INT trigger type:%x",ts->client->irq, 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_gpio);
       GTP_GPIO_FREE(gtp_int_gpio);


       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.
*******************************************************/
statics8 gtp_request_input_dev(struct goodix_ts_data *ts)
{
   s8 ret = -1;
   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) ;
   ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
#ifGTP_CHANGE_X2Y
   GTP_SWAP(ts->abs_x_max, ts->abs_y_max);
#endif
set_bit(ABS_X,ts->input_dev->absbit);
set_bit(ABS_Y,ts->input_dev->absbit);
set_bit(ABS_PRESSURE,ts->input_dev->absbit);
set_bit(BTN_TOUCH,ts->input_dev->keybit);


input_set_abs_params(ts->input_dev,ABS_X, 0, ts->abs_x_max, 0, 0);
input_set_abs_params(ts->input_dev,ABS_Y, 0, ts->abs_y_max, 0, 0);
input_set_abs_params(ts->input_dev,ABS_PRESSURE, 0, 255, 0 , 0);

   ts->input_dev->name = goodix_ts_name;
   ts->input_dev->phys = goodix_input_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;
   }


   return 0;
}




/*******************************************************
Function:
   I2c probe.
Input:
   client: i2c device struct.
   id: device id.
Output:
   Executive outcomes. 
       0: succeed.
*******************************************************/
staticint 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;
   }


/* usegpio defined in gt9xx.h */
gtp_rst_gpio= GTP_RST_PORT;
gtp_int_gpio= GTP_INT_PORT;


   INIT_WORK(&ts->work, goodix_ts_work_func);
   ts->client = client;
   spin_lock_init(&ts->irq_lock);         // 2.6.39 later 


   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!");
   }


  ret = gtp_read_version(client, &version_info);
   if (ret < 0)
   {
       GTP_ERROR("Read version failed.");
   }
   
   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;
   }
  
   // Create proc file system
   gt91xx_config_proc = proc_create(GT91XX_CONFIG_PROC_FILE, 0666, NULL,&config_proc_ops);
   if (gt91xx_config_proc == NULL)
   {
       GTP_ERROR("create_proc_entry %s failed\n",GT91XX_CONFIG_PROC_FILE);
   }
   else
   {
       GTP_INFO("create proc entry %s success",GT91XX_CONFIG_PROC_FILE);
   }


   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.");
   }


GPIO_SET_SRCGRP();
GPIO_SET_INTMODE();
EXT_SET_MODE();


CLEAR_EXT_INTERRUPT_FLAG();//清INT中断标志GPE1 
// gtp_int_sync(20);
   if (ts->use_irq)
   {
       gtp_irq_enable(ts);


   }

/*register suspend and resume fucntion*/
gtp_register_powermanger(ts);
   
   return 0;
}




/*******************************************************
Function:
   Goodix touchscreen driver release function.
Input:
   client: i2c device struct.
Output:
   Executive outcomes. 0---succeed.
*******************************************************/
staticint goodix_ts_remove(struct i2c_client *client)
{
   struct goodix_ts_data *ts = i2c_get_clientdata(client);
   
   GTP_DEBUG_FUNC();


gtp_unregister_powermanger(ts);


   if (ts) 
   {
       if (ts->use_irq)
       {
           GTP_GPIO_AS_INPUT(gtp_int_gpio);
           GTP_GPIO_FREE(gtp_int_gpio);
           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;
}




/*******************************************************
Function:
   Early suspend function.
Input:
   h: early_suspend struct.
Output:
   None.
*******************************************************/
staticvoid goodix_ts_suspend(struct goodix_ts_data *ts)
{
   s8 ret = -1;    
   
   GTP_DEBUG_FUNC();
   if (ts->enter_update) {
   return;
   }
   GTP_INFO("System suspend.");


   ts->gtp_is_suspend = 1;


   if (ts->use_irq)
   {
       gtp_irq_disable(ts);
   }
   else
   {
       hrtimer_cancel(&ts->timer);
   }
   ret = gtp_enter_sleep(ts);


   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.
*******************************************************/
staticvoid goodix_ts_resume(struct goodix_ts_data *ts)
{
   s8 ret = -1; 
   GTP_DEBUG_FUNC();
   if (ts->enter_update) {
   return;
   }
   GTP_INFO("System resume.");
   
   ret = gtp_wakeup_sleep(ts);


   if (ret < 0)
   {
       GTP_ERROR("GTP later resume failed.");
   }


    gtp_send_cfg(ts->client);
   


   if (ts->use_irq)
   {
       gtp_irq_enable(ts);
   }
   else
   {
       hrtimer_start(&ts->timer, ktime_set(1, 0),HRTIMER_MODE_REL);
   }


   ts->gtp_is_suspend = 0;


}




#if  defined(CONFIG_FB)
/*frame buffer notifier block control the suspend/resume procedure */
staticint gtp_fb_notifier_callback(struct notifier_block *noti, unsigned long event,void *data)
{
structfb_event *ev_data = data;
structgoodix_ts_data *ts = container_of(noti, struct goodix_ts_data, notifier);
int*blank;

if(ev_data && ev_data->data && event == FB_EVENT_BLANK&& ts) {
blank= ev_data->data;
if(*blank == FB_BLANK_UNBLANK) {
GTP_DEBUG("Resumeby fb notifier.");
goodix_ts_resume(ts);

}
elseif (*blank == FB_BLANK_POWERDOWN) {
GTP_DEBUG("Suspendby fb notifier.");
goodix_ts_suspend(ts);
}
}


return0;
}
#elifdefined(CONFIG_PM)
/* buscontrol the suspend/resume procedure */
staticint gtp_pm_suspend(struct device *dev)
{
structi2c_client *client = to_i2c_client(dev);
structgoodix_ts_data *ts = i2c_get_clientdata(client);


if(ts) {
GTP_DEBUG("Suspendby i2c pm.");
goodix_ts_suspend(ts);
}


return0;
}
staticint gtp_pm_resume(struct device *dev)
{
structi2c_client *client = to_i2c_client(dev);
structgoodix_ts_data *ts = i2c_get_clientdata(client);


if(ts) {
GTP_DEBUG("Resumeby i2c pm.");
goodix_ts_resume(ts);
}


return0;
}


staticstruct dev_pm_ops gtp_pm_ops = {
.suspend= gtp_pm_suspend,
.resume = gtp_pm_resume,
};


#elifdefined(CONFIG_HAS_EARLYSUSPEND)
/*earlysuspend module the suspend/resume procedure */
staticvoid gtp_early_suspend(struct early_suspend *h)
{
structgoodix_ts_data *ts = container_of(h, struct goodix_ts_data, early_suspend);


if(ts) {
GTP_DEBUG("Suspendby earlysuspend module.");
goodix_ts_suspend(ts);
}
}
staticvoid gtp_early_resume(struct early_suspend *h)
{
structgoodix_ts_data *ts = container_of(h, struct goodix_ts_data, early_suspend);


if(ts) {
GTP_DEBUG("Resumeby earlysuspend module.");
goodix_ts_resume(ts);
}
}
#endif


staticint gtp_register_powermanger(struct goodix_ts_data *ts)
{
#if  defined(CONFIG_FB)
ts->notifier.notifier_call= gtp_fb_notifier_callback;
fb_register_client(&ts->notifier);

#elifdefined(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


return0;
}


staticint gtp_unregister_powermanger(struct goodix_ts_data *ts)
{
#if  defined(CONFIG_FB)
fb_unregister_client(&ts->notifier);

#elifdefined(CONFIG_HAS_EARLYSUSPEND)
unregister_early_suspend(&ts->early_suspend);
#endif
return0;
}


/* end*/




staticconst struct i2c_device_id goodix_ts_id[] = {
   { GTP_I2C_NAME, 0 },
   { }
};


staticstruct i2c_driver goodix_ts_driver = {
   .probe      = goodix_ts_probe,
   .remove     = goodix_ts_remove,
   .id_table   = goodix_ts_id,
   .driver = {
       .name     = GTP_I2C_NAME,
       .owner    = THIS_MODULE,


#if!defined(CONFIG_FB) && defined(CONFIG_PM)
.pm = &gtp_pm_ops,
#endif
   },
};


/*******************************************************   
Function:
   Driver Install function.
Input:
   None.
Output:
   Executive Outcomes. 0---succeed.
********************************************************/
staticint __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;
   }

   ret = i2c_add_driver(&goodix_ts_driver);
   return ret; 
}


/*******************************************************   
Function:
   Driver uninstall function.
Input:
   None.
Output:
   Executive Outcomes. 0---succeed.
********************************************************/
staticvoid __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);
   }
}


module_init(goodix_ts_init);
module_exit(goodix_ts_exit);


MODULE_DESCRIPTION("GTPSeries Driver");
MODULE_LICENSE("GPL");

三.     如何没有厂家提供的配置表,也就是CTP_CFG_GROUP0数组,请注意宏定义开关,#defineGTP_CUSTOM_CFG       1

#define GTP_DRIVER_SEND_CFG  1 

#defineGTP_CONFIG_MODE          0 //这样不会破坏屏原来的关键配置参数。如果打开为1,则是根据CTP_CFG_GROUP0数组内容来配置,一旦配置进去,屏可能无法使用。

四.      编译烧录,运行校准,正常。

下图为运行ts_test

猜你喜欢

转载自blog.csdn.net/YYGY731793898/article/details/73329837