N32926移植电容触摸屏GT911驱动到内核
此驱动在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文件本来已修改好。
开发板运行后的/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:%[email protected]:%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 [email protected]%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 = >p_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