大家好,又见面了,我是你们的朋友全栈君。
全志A33之添加电容触摸GT911驱动
基于锐尔威视的A33开发板及提供的开发包,仅供参考。
开发板说是支持GT911,其实是不支持的,得修改驱动及配置,启动文件。
一. 修改配置文件
/home/yygyickl/A33/dragonboard/tools/pack/chips/sun8iw5p1/configs/vstar/sys_config.fex 这是我的目录。
触摸部分修改为下面的样子。
[ctp_para]
ctp_used = 1
ctp_name = “gt9xx_ts”
ctp_twi_id = 0
ctp_twi_addr = 0x5d
ctp_screen_max_x = 1024
ctp_screen_max_y = 600
ctp_revert_x_flag = 0
ctp_revert_y_flag = 0
ctp_exchange_x_y_flag= 0
ctp_int_port =port:PB05<4><default><default><default>
ctp_wakeup =port:PH01<1><default><default><1>
;ctp_power_ldo = “axp22_eldo1”
;ctp_power_ldo_vol = 3000
;ctp_power_io =
;——————————————————————————–
; CTP automaticdetection configuration
;ctp_detect_used — Whether startup automatic inspectionfunction. 1:used,0:unused
;Module namepostposition 1 said detection, 0 means no detection.
;——————————————————————————–
[ctp_list_para]
ctp_det_used = 0
ft5x_ts = 0
gt82x = 0
gslX680 = 0
gslX680new = 0
gt9xx_ts = 1
gt9xxf_ts = 0
tu_ts = 0
gt818_ts = 0
zet622x = 0
aw5306_ts = 0
icn83xx_ts = 0
仅支持GT911。
二. 修改启动文件
/home/yygyickl/A33/dragonboard/buildroot/target/dragonboard/extra/autorun.sh 这是我的目录。
将触摸部分的insmod”$tp_module_path” 修改为
insmod /system/vendor/modules/gt9xx_ts.ko
下面这部分中的ft5x_ts全部替换为gt9xx_ts
#tslib config
export TSLIB_CALIBFILE=/etc/pointercal
TS_INFO_FILE1=/sys/class/input/event3/device/name
TS_INFO_FILE2=/sys/class/input/event4/device/name
if grep -q ft5x_ts $TS_INFO_FILE1; then
export TSLIB_TSDEVICE=/dev/input/event3
export QWS_MOUSE_PROTO=”Tslib:/dev/input/event3MouseMan:/dev/input/mouse0″
if [ ! -s “$TSLIB_CALIBFILE” ];then
rm -f $TSLIB_CALIBFILE
fi
elif grep -q ft5x_ts $TS_INFO_FILE2; then
export TSLIB_TSDEVICE=/dev/input/event4
export QWS_MOUSE_PROTO=”Tslib:/dev/input/event4MouseMan:/dev/input/mouse0″
if [ ! -s “$TSLIB_CALIBFILE” ]; then
rm -f $TSLIB_CALIBFILE
fi
else
export QWS_MOUSE_PROTO=MouseMan:/dev/input/mouse0 > $TSLIB_CALIBFILE
fi
unset TS_INFO_FILE1
unset TS_INFO_FILE2
三. 修改驱动
/home/yygyickl/A33/dragonboard/Linux-3.4/Drivers/Input/Touchscreen/Gt9xx/ 进入目录
修改Gt9xx_ts.h为:
#ifndef _LINUX_GOODIX_TOUCH_H
#define _LINUX_GOODIX_TOUCH_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>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
#include <linux/async.h>
#include <linux/ioport.h>
#include <asm/irq.h>
#include <asm/delay.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <mach/irqs.h>
#include <mach/hardware.h>
#include <mach/sys_config.h>
#include <linux/init-input.h>
#include <linux/pinctrl/consumer.h>
#include<linux/pinctrl/pinconf-sunxi.h>
struct gt9xx_event {
inttouch_point;
u16x[5];
u16y[5];
u16w[5];
};
struct goodix_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;
#ifdef CONFIG_HAS_EARLYSUSPEND
struct early_suspend early_suspend;
#endif
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;
#elif defined(CONFIG_HAS_EARLYSUSPEND)
structearly_suspend early_suspend;
#endif
};
extern u16 show_len;
extern u16 total_len;
extern struct ctp_config_info config_info;
//***************************PART1:ON/OFFdefine*******************************
#define GTP_CUSTOM_CFG 1
#define GTP_CHANGE_X2Y 0 //swap x y
#define GTP_DRIVER_SEND_CFG 1 //driver send config 此开关根据需要选择
#define GTP_CONFIG_MODE 0 //触摸屏本来是好的,没有厂家数据表的情况下:0=从GT911中读原来的配置参数,修改后再配置
//有厂家数据表的情况 1:修改数据表后配置
#define GTP_HAVE_TOUCH_KEY 0
#define GTP_POWER_CTRL_SLEEP 0 //power off when suspend
#define GTP_ICS_SLOT_REPORT 0 // slot protocol
#define GTP_AUTO_UPDATE 0 // auto update fw by .bin file as default
#define GTP_HEADER_FW_UPDATE 0 //auto update fw by gtp_default_FW in gt9xx_firmware.h, function together withGTP_AUTO_UPDATE
#define GTP_AUTO_UPDATE_CFG 0 // auto update config by .cfg file, function together withGTP_AUTO_UPDATE
#define GTP_COMPATIBLE_MODE 0 // compatible with GT9XXF
#define GTP_CREATE_WR_NODE 0
#define GTP_ESD_PROTECT 0 // esd protection with a cycle of 2 seconds
#define GTP_WITH_PEN 0
#define GTP_PEN_HAVE_BUTTON 0 // active pen has buttons, function together with GTP_WITH_PEN
#define GTP_GESTURE_WAKEUP 0 // gesture wakeup
#define GTP_DEBUG_ON 1
#define GTP_DEBUG_ARRAY_ON 0
#define GTP_DEBUG_FUNC_ON 0
//***************************PART2:TODOdefine**********************************
//STEP_1(REQUIRED):Change config table.
/*TODO: puts the config info correspondedto your TP here, the following is just
a sample config, send this config shouldcause the chip cannot work normally*/
//default or float
// sochip,ma805d5 ,768*1024,gt911,COB
#define CTP_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}
//#define GTP_RST_PORT S5PV210_GPJ3(6)
//#define GTP_INT_PORT S5PV210_GPH1(3)
//#define GTP_INT_IRQ SW_INT_IRQNO_PIO
//#define GTP_INT_CFG S3C_GPIO_SFN(0xF)
//#ifdef CONFIG_ARCH_SUN4I
//#define CTP_IRQ_NO (IRQ_EINT21)
//#elif defined CONFIG_ARCH_SUN5I
//#define CTP_IRQ_NO (IRQ_EINT9)
//#endif
//#define CTP_IRQ_MODE (TRIG_EDGE_NEGATIVE)
#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):Custom set some configby themself,if need.
#if GTP_CUSTOM_CFG
#define GTP_MAX_HEIGHT 600
#define GTP_MAX_WIDTH 1024
#define GTP_INT_TRIGGER 1 //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
//STEP_4(optional):If this project havetouch key,Set touch key config.
#if GTP_HAVE_TOUCH_KEY
#define GTP_KEY_TAB {KEY_MENU,KEY_HOME, KEY_BACK, KEY_SEND}
#endif
//***************************PART3:OTHERdefine*********************************
#define GTP_DRIVER_VERSION “V2.4<2014/11/28>”
#define GTP_I2C_NAME “gt9xx_ts”
#define GTP_POLL_TIME 10
#define GTP_ADDR_LENGTH 2
#define GTP_CONFIG_MIN_LENGTH 186
#define GTP_CONFIG_MAX_LENGTH 240
#define FAIL 0
#define SUCCESS 1
//Register 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 GTP_REG_COMMAND 0x8040
#define GTP_COMMAND_READSTATUS 0
#define GTP_COMMAND_DIFFERENCE 1
#define GTP_COMMAND_SOFTRESET 2
#define GTP_COMMAND_UPDATE 3
#define GTP_COMMAND_CALCULATE 4
#define GTP_COMMAND_TURNOFF 5
#define RESOLUTION_LOC 3
#define TRIGGER_LOC 8
//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{\
s32i;\
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)
//****************************PART4:UPDATEdefine*******************************
//Error no
#define ERROR_NO_FILE 2 //ENOENT
#define ERROR_FILE_READ 23 //ENFILE
#define ERROR_FILE_TYPE 21 //EISDIR
#define ERROR_GPIO_REQUEST 4 //EINTR
#define ERROR_I2C_TRANSFER 5 //EIO
#define ERROR_NO_RESPONSE 16 //EBUSY
#define ERROR_TIMEOUT 110 //ETIMEDOUT
//*****************************End of PartIII********************************
#endif /* _LINUX_GOODIX_TOUCH_H */
修改gt9xx.c为:
#include <linux/irq.h>
#include “gt9xx_ts.h”
#include <linux/pm.h>
#if GTP_ICS_SLOT_REPORT
#include <linux/input/mt.h>
#endif
static const char *goodix_ts_name =”gt9xx”;
static struct workqueue_struct *goodix_wq;
struct i2c_client * i2c_connect_client =NULL;
static u8 config[GTP_CONFIG_MAX_LENGTH +GTP_ADDR_LENGTH]
= {GTP_REG_CONFIG_DATA >>8, GTP_REG_CONFIG_DATA & 0xff};
#if GTP_HAVE_TOUCH_KEY
staticconst u16 touch_key_array[] = GTP_KEY_TAB;
#defineGTP_MAX_KEY_NUM (sizeof(touch_key_array)/sizeof(touch_key_array[0]))
#endif
static s8 gtp_i2c_test(struct i2c_client*client);
void gtp_reset_guitar(struct i2c_client*client, s32 ms);
void gtp_int_sync(s32 ms);
#ifdef CONFIG_HAS_EARLYSUSPEND
static void goodix_ts_early_suspend(structearly_suspend *h);
static void goodix_ts_late_resume(structearly_suspend *h);
#endif
#if GTP_CREATE_WR_NODE
extern s32 init_wr_node(structi2c_client*);
extern void uninit_wr_node(void);
#endif
#if GTP_AUTO_UPDATE
extern u8 gup_init_update_proc(structgoodix_ts_data *);
#endif
#if GTP_ESD_PROTECT
static struct delayed_workgtp_esd_check_work;
static struct workqueue_struct *gtp_esd_check_workqueue = NULL;
static void gtp_esd_check_func(structwork_struct *);
s32 gtp_init_ext_watchdog(structi2c_client *client);
#endif
///
//specific tp related macro: need beconfigured for specific tp
#define CTP_IRQ_NUMBER (config_info.int_number)
#define CTP_IRQ_MODE (IRQF_TRIGGER_FALLING)
#define CTP_NAME (“gt9xx_ts”)
#define SCREEN_MAX_X (screen_max_x)
#define SCREEN_MAX_Y (screen_max_y)
#define PRESS_MAX (255)
static int screen_max_x = 0;
static int screen_max_y = 0;
static int revert_x_flag = 0;
static int revert_y_flag = 0;
static int exchange_x_y_flag = 0;
static __u32 twi_id = 0;
static char irq_pin_name[8];
static u32 debug_mask = 0;
enum{
DEBUG_INIT= 1U << 0,
DEBUG_SUSPEND= 1U << 1,
DEBUG_INT_INFO= 1U << 2,
DEBUG_X_Y_INFO= 1U << 3,
DEBUG_KEY_INFO= 1U << 4,
DEBUG_WAKEUP_INFO= 1U << 5,
DEBUG_OTHERS_INFO= 1U << 6,
};
#definedprintk(level_mask,fmt,arg…) if(unlikely(debug_mask & level_mask)) \
printk(“***CTP***”fmt, ## arg)
module_param_named(debug_mask,debug_mask,int,S_IRUGO| S_IWUSR | S_IWGRP);
static const unsigned short normal_i2c[2]= {0x5d, I2C_CLIENT_END};
//static const int chip_id_value[3] ={57};
//static uint8_t read_chip_value[3] ={GTP_REG_VERSION >> 8, GTP_REG_VERSION & 0xff,0};
struct ctp_config_info config_info = {
.input_type= CTP_TYPE,
.name= NULL,
.int_number= 0,
};
//static void goodix_init_events(structwork_struct *work);
static void goodix_resume_events(structwork_struct *work);
static struct workqueue_struct *goodix_wq;
//static struct workqueue_struct*goodix_init_wq;
static struct workqueue_struct*goodix_resume_wq;
//static DECLARE_WORK(goodix_init_work,goodix_init_events);
static DECLARE_WORK(goodix_resume_work,goodix_resume_events);
/**
*ctp_detect – Device detection callback for automatic device creation
*return value:
* = 0; success;
* < 0; err
*/
static int ctp_detect(struct i2c_client*client, struct i2c_board_info *info)
{
structi2c_adapter *adapter = client->adapter;
int ret = -1;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)){
printk(“======return=====\n”);
return -ENODEV;
}
if(twi_id == adapter->nr){
dprintk(DEBUG_INIT,”%s: addr = %x\n”, __func__,client->addr);
ret = gtp_i2c_test(client);
printk(“detectret %d\n”,ret);
if(!ret){
printk(“%s:I2Cconnection might be something wrong \n”, __func__);
return -ENODEV;
}else{
strlcpy(info->type, CTP_NAME,I2C_NAME_SIZE);
printk(“======detectok !=====\n”);
return0;
}
}else{
return -ENODEV;
}
}
/**
*ctp_print_info – sysconfig print function
*return value:
*
*/
void ctp_print_info(struct ctp_config_infoinfo,int debug_level)
{
if(debug_level== DEBUG_INIT)
{
dprintk(DEBUG_INIT,”info.ctp_used:%d\n”,info.ctp_used);
dprintk(DEBUG_INIT,”info.twi_id:%d\n”,info.twi_id);
dprintk(DEBUG_INIT,”info.screen_max_x:%d\n”,info.screen_max_x);
dprintk(DEBUG_INIT,”info.screen_max_y:%d\n”,info.screen_max_y);
dprintk(DEBUG_INIT,”info.revert_x_flag:%d\n”,info.revert_x_flag);
dprintk(DEBUG_INIT,”info.revert_y_flag:%d\n”,info.revert_y_flag);
dprintk(DEBUG_INIT,”info.exchange_x_y_flag:%d\n”,info.exchange_x_y_flag);
dprintk(DEBUG_INIT,”info.irq_gpio_number:%d\n”,info.irq_gpio.gpio);
dprintk(DEBUG_INIT,”info.wakeup_gpio_number:%d\n”,info.wakeup_gpio.gpio);
}
}
/**
*ctp_wakeup – function
*
*/
int ctp_wakeup(int status,int ms)
{
dprintk(DEBUG_INIT,”***CTP***%s:status:%d,ms = %d\n”,__func__,status,ms);
if(status == 0) {
if(ms== 0) {
__gpio_set_value(config_info.wakeup_gpio.gpio,0);
}else{
__gpio_set_value(config_info.wakeup_gpio.gpio,0);
msleep(ms);
__gpio_set_value(config_info.wakeup_gpio.gpio,1);
}
}
if(status == 1) {
if(ms== 0) {
__gpio_set_value(config_info.wakeup_gpio.gpio,1);
}else{
__gpio_set_value(config_info.wakeup_gpio.gpio,1);
msleep(ms);
__gpio_set_value(config_info.wakeup_gpio.gpio,0);
}
}
msleep(5);
return0;
}
void gtp_set_int_value(int status)
{
long unsigned int config;
config= SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC,0xFFFF);
pin_config_get(SUNXI_PINCTRL,irq_pin_name,&config);
if(1 != SUNXI_PINCFG_UNPACK_VALUE(config)){
config =SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC,1);
pin_config_set(SUNXI_PINCTRL,irq_pin_name,config);;
}
__gpio_set_value(CTP_IRQ_NUMBER, status);
}
void gtp_set_io_int(void)
{
long unsigned int config;
config= SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC,0xFFFF);
pin_config_get(SUNXI_PINCTRL,irq_pin_name,&config);
if(4 != SUNXI_PINCFG_UNPACK_VALUE(config)){
config =SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC,4);
pin_config_set(SUNXI_PINCTRL,irq_pin_name,config);
}
}
/*******************************************************
Function:
Synchronization.
Input:
ms: synchronization time in millisecond.
Output:
None.
*******************************************************/
void gtp_int_sync(s32 ms)
{
gtp_set_int_value(0);
msleep(ms);
gtp_set_io_int();
}
/*******************************************************
Function:
Reset chip.
Input:
ms: reset time in millisecond
Output:
None.
*******************************************************/
void gtp_reset_guitar(struct i2c_client*client, s32 ms)
{
#if GTP_COMPATIBLE_MODE
struct goodix_ts_data *ts = i2c_get_clientdata(client);
#endif
GTP_DEBUG_FUNC();
GTP_INFO(“Guitar reset”);
ctp_wakeup(0, 0); // beginselect I2C slave addr
msleep(ms); // T2: > 10ms
// HIGH: 0x28/0x29, LOW: 0xBA/0xBB
gtp_set_int_value(0);
msleep(2); // T3: > 100us
ctp_wakeup(1, 0);
msleep(6); // T4: > 5ms
// GTP_GPIO_AS_INPUT(gtp_rst_gpio); // end select I2C slave addr
#if GTP_COMPATIBLE_MODE
if (CHIP_TYPE_GT9F == ts->chip_type)
{
return;
}
#endif
gtp_int_sync(50);
#if GTP_ESD_PROTECT
gtp_init_ext_watchdog(client);
#endif
}
void gtp_io_init(int ms)
{
ctp_wakeup(0, 0);
msleep(ms);
gtp_set_int_value(0);
msleep(2);
ctp_wakeup(1, 0);
msleep(6);
gtp_int_sync(50);
#if GTP_ESD_PROTECT
// gtp_init_ext_watchdog(client);
#endif
}
/*******************************************************
Function:
Readdata from the i2c slave device.
Input:
client: i2c device.
buf[0]:operateaddress.
buf[1]~buf[len]:readdata buffer.
len:operatelength.
Output:
numbersof i2c_msgs to transfer
*********************************************************/
s32 gtp_i2c_read(struct i2c_client*client, u8 *buf, s32 len)
{
struct i2c_msg msgs[2];
s32 ret = -1;
s32 retries = 0;
msgs[0].flags = !I2C_M_RD;
msgs[0].addr = client->addr;
msgs[0].len = GTP_ADDR_LENGTH;
msgs[0].buf = &buf[0];
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];
while(retries < 5) {
ret =i2c_transfer(client->adapter, msgs, 2);
if(ret == 2)
break;
retries++;
}
if(retries >= 5) {
printk(“%s:I2C retrytimeout, reset chip.”, __func__);
gtp_reset_guitar(client,10);
}
return ret;
}
/*******************************************************
Function:
writedata to the i2c slave device.
Input:
client: i2c device.
buf[0]:operateaddress.
buf[1]~buf[len]:writedata buffer.
len:operatelength.
Output:
numbersof i2c_msgs to transfer.
*********************************************************/
s32 gtp_i2c_write(struct i2c_client*client,u8 *buf,s32 len)
{
struct i2c_msg msg;
s32 ret = -1;
s32 retries = 0;
msg.flags = !I2C_M_RD;
msg.addr = client->addr;
msg.len = len;
msg.buf = buf;
while(retries < 5) {
ret =i2c_transfer(client->adapter, &msg, 1);
if (ret == 1)
break;
retries++;
}
if(retries >= 5) {
printk(“%s:I2C retry timeout,reset chip.”, __func__);
gtp_reset_guitar(client,10);
}
return ret;
}
/*******************************************************
Function:
i2c read twice, compare the results
Input:
client: i2c device
addr: operate address
rxbuf: read data to store, ifcompare successful
len: bytes to read
Output:
FAIL: read failed
SUCCESS: read successful
*********************************************************/
s32 gtp_i2c_read_dbl_check(structi2c_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
*********************************************************/
void gtp_i2c_read_cfg_check(structi2c_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:
Sendconfig Function.
Input:
client: i2c client.
Output:
Executiveoutcomes.0–success,non-0–fail.
*******************************************************/
s32 gtp_send_cfg(struct i2c_client*client)
{
s32 ret = 0;
#if GTP_DRIVER_SEND_CFG
s32 retry = 0;
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:
DisableIRQ Function.
Input:
ts: i2c client private struct.
Output:
None.
*******************************************************/
void gtp_irq_disable(struct goodix_ts_data*ts)
{
unsigned long irqflags;
intret;
dprintk(DEBUG_INT_INFO, “%s —start!—\n”, __func__);
spin_lock_irqsave(&ts->irq_lock, irqflags);
if (!ts->irq_is_disable) {
ts->irq_is_disable = 1;
ret =input_set_int_enable(&(config_info.input_type), 0);
if (ret < 0)
dprintk(DEBUG_OTHERS_INFO,”%s irqdisable failed\n”, goodix_ts_name);
}
spin_unlock_irqrestore(&ts->irq_lock, irqflags);
}
/*******************************************************
Function:
DisableIRQ Function.
Input:
ts: i2c client private struct.
Output:
None.
*******************************************************/
void gtp_irq_enable(struct goodix_ts_data*ts)
{
unsigned long irqflags = 0;
intret;
dprintk(DEBUG_INT_INFO, “%s —start!—\n”, __func__);
spin_lock_irqsave(&ts->irq_lock, irqflags);
if (ts->irq_is_disable) {
ts->irq_is_disable = 0;
ret =input_set_int_enable(&(config_info.input_type), 1);
if(ret < 0)
dprintk(DEBUG_OTHERS_INFO,”%sirq enable failed\n”, goodix_ts_name);
}
spin_unlock_irqrestore(&ts->irq_lock, irqflags);
}
/*******************************************************
Function:
Touchdown report function.
Input:
ts:privatedata.
id:trackingid.
x:inputx.
y:inputy.
w:inputweight.
Output:
None.
*******************************************************/
static void gtp_touch_down(structgoodix_ts_data* ts,s32 id,s32 x,s32 y,s32 w)
{
dprintk(DEBUG_X_Y_INFO, “source data:ID:%d, X:%d, Y:%d,W:%d\n”, id, x, y, w);
if(1 == exchange_x_y_flag){
swap(x, y);
}
if(1 == revert_x_flag){
x = SCREEN_MAX_X – x;
}
if(1 == revert_y_flag){
y = SCREEN_MAX_Y – y;
}
dprintk(DEBUG_X_Y_INFO,”report data:ID:%d, X:%d, Y:%d,W:%d\n”, id, x, y, w);
#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
}
/*******************************************************
Function:
Touchup report function.
Input:
ts:privatedata.
Output:
None.
*******************************************************/
static void gtp_touch_up(structgoodix_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);
dprintk(DEBUG_X_Y_INFO, “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:
Goodixtouchscreen work function.
Input:
work: work_struct of goodix_wq.
Output:
None.
*******************************************************/
static void goodix_ts_work_func(structwork_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;
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;
dprintk(DEBUG_X_Y_INFO,”===enter %s===\n”,__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){
printk(“I2C transfererror. 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++) {
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;
dprintk(DEBUG_X_Y_INFO, “pre_touch:%02x, finger:%02x.”,pre_touch, finger);
#if GTP_ICS_SLOT_REPORT
if (pre_touch || touch_num) {
s32 pos = 0;
u16 touch_index = 0;
coor_data = &point_data[3];
if(touch_num) {
id = coor_data[pos]& 0x0F;
touch_index |=(0x01<<id);
}
dprintk(DEBUG_X_Y_INFO,
“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 (touch_index &(0x01<<i)) {
input_x = coor_data[pos + 1] | coor_data[pos + 2]<< 8;
input_y = coor_data[pos + 3] | coor_data[pos + 4]<< 8;
input_w = coor_data[pos + 5] | coor_data[pos + 6]<< 8;
gtp_touch_down(ts, id, input_x, input_y, input_w);
pre_touch |=0x01 << i;
pos += 8;
id =coor_data[pos] & 0x0F;
touch_index |=(0x01<<id);
}else {// if (pre_touch& (0x01 << i))
gtp_touch_up(ts, i);
pre_touch&= ~(0x01 << i);
}
}
}
#else
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;
gtp_touch_down(ts, id,input_x, input_y, input_w);
}
}else if(pre_touch){
dprintk(DEBUG_X_Y_INFO,”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) {
printk(“I2C writeend_cmd error!”);
}
}
return ;
}
/*******************************************************
Function:
Externalinterrupt service routine.
Input:
irq: interrupt number.
dev_id:private data pointer.
Output:
irqexecute status.
*******************************************************/
irqreturn_t goodix_ts_irq_handler(int irq,void *dev_id)
{
struct goodix_ts_data *ts = (struct goodix_ts_data *)dev_id;
dprintk(DEBUG_INT_INFO,”==========——TS Interrupt—–============\n”);
queue_work(goodix_wq, &ts->work);
return 0;
}
/*******************************************************
Function:
Etersleep function.
Input:
ts:privatedata.
Output:
Executiveoutcomes.0–success,non-0–fail.
*******************************************************/
static s8 gtp_enter_sleep(structgoodix_ts_data * ts)
{
s8 ret = -1;
s8 retry = 0;
u8 i2c_control_buf[3] = {(u8)(GTP_REG_SLEEP >> 8),(u8)GTP_REG_SLEEP, 5};
dprintk(DEBUG_SUSPEND, “%s start!\n”, __func__);
gtp_set_int_value(0);
msleep(5);
while(retry++ < 5) {
ret =gtp_i2c_write(ts->client, i2c_control_buf, 3);
if (ret > 0) {
dprintk(DEBUG_SUSPEND,”GTP enter sleep!”);
return ret;
}
msleep(10);
}
dprintk(DEBUG_SUSPEND, “GTP send sleep cmd failed.”);
return ret;
}
/*******************************************************
Function:
Wakeupfrom sleep mode Function.
Input:
ts: private data.
Output:
Executiveoutcomes.0–success,non-0–fail.
*******************************************************/
static s8 gtp_wakeup_sleep(structgoodix_ts_data * ts)
{
u8 retry = 0;
s8 ret = -1;
gtp_io_init(20);
gtp_set_io_int();
#if GTP_POWER_CTRL_SLEEP
while(retry++ < 5)
{
gtp_reset_guitar(ts->client, 20);
GTP_INFO(“GTP wakeup sleep.”);
return 1;
}
#else
while(retry++ < 10)
{
#if GTP_GESTURE_WAKEUP
if (DOZE_WAKEUP != doze_status)
{
GTP_INFO(“Powerkey wakeup.”);
}
else
{
GTP_INFO(“Gesture wakeup.”);
}
doze_status = DOZE_DISABLED;
gtp_irq_disable(ts);
gtp_reset_guitar(ts->client, 10);
gtp_irq_enable(ts);
#else
gtp_set_int_value(1);
msleep(5);
#endif
ret = gtp_i2c_test(ts->client);
if (ret > 0)
{
GTP_INFO(“GTP wakeupsleep.”);
#if (!GTP_GESTURE_WAKEUP)
{
gtp_int_sync(25);
#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:
GTP initializefunction.
Input:
ts: i2c client private struct.
Output:
Executiveoutcomes.0—succeed.
*******************************************************/
static s32 gtp_init_panel(structgoodix_ts_data *ts)
{
s32 ret = -1;
s32i = 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); //读出原配置信息,以利恢复_记得将打印出来的配置信息保存
#if GTP_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;
}
}
#if GTP_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
#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);
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;
#if GTP_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;
}
/*******************************************************
Function:
Readgoodix touchscreen version function.
Input:
client: i2c client struct.
version:addressto store version info
Output:
Executiveoutcomes.0—succeed.
*******************************************************/
s32 gtp_read_version(struct i2c_client*client, u16* version)
{
s32 ret = -1;
u8 buf[8] = {GTP_REG_VERSION >> 8, GTP_REG_VERSION & 0xff};
dprintk(DEBUG_INIT, “%s —start!.—\n”, __func__);
ret = gtp_i2c_read(client, buf, sizeof(buf));
if (ret < 0) {
printk(“GTP read versionfailed”);
return ret;
}
if (version) {
*version = (buf[7] << 8)| buf[6];
}
if (buf[5] == 0x00) {
printk(“IC Version:%c%c%c_%02x%02x”, buf[2], buf[3], buf[4], buf[7], buf[6]);
}
else {
printk(“IC Version:%c%c%c%c_%02x%02x”, buf[2], buf[3], buf[4], buf[5], buf[7], buf[6]);
}
return ret;
}
/*******************************************************
Function:
I2ctest Function.
Input:
client:i2cclient.
Output:
Executiveoutcomes.0–success,non-0–fail.
*******************************************************/
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;
while(retry++ < 2) {
ret = gtp_i2c_read(client,test, 3);
if (ret > 0) {
return ret;
}
printk(“GTP i2c testfailed time %d.”,retry);
msleep(10);
}
return ret;
}
/*******************************************************
Function:
Requestinput device Function.
Input:
ts:privatedata.
Output:
Executiveoutcomes.0–success,non-0–fail.
*******************************************************/
static s8 gtp_request_input_dev(structgoodix_ts_data *ts)
{
s8 ret = -1;
#if GTP_HAVE_TOUCH_KEY
u8 index = 0;
#endif
ts->input_dev = input_allocate_device();
if (ts->input_dev == NULL) {
GTP_ERROR(“Failed toallocate 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, 255);
#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_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,SCREEN_MAX_X, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0,SCREEN_MAX_Y, 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);
set_bit(INPUT_PROP_DIRECT,ts->input_dev->propbit);
ts->input_dev->name = CTP_NAME;
ts->input_dev->phys = “input/goodix-ts”;
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) {
printk(“Register %s inputdevice 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:
Goodixtouchscreen probe function.
Input:
client: i2c device struct.
id:deviceid.
Output:
Executiveoutcomes. 0—succeed.
*******************************************************/
static int goodix_ts_probe(structi2c_client *client, const struct i2c_device_id *id)
{
s32 ret = -1;
struct goodix_ts_data *ts;
u16 version_info;
dprintk(DEBUG_INIT, “GTP DriverVersion:%s\n”,GTP_DRIVER_VERSION);
dprintk(DEBUG_INIT, “GTP Driver build@%s,%s\n”,__TIME__,__DATE__);
printk(“GTP I2C Address:0x%02x\n”, client->addr);
i2c_connect_client = client;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
printk(“I2C checkfunctionality failed.\n”);
return -ENODEV;
}
ts = kzalloc(sizeof(*ts), GFP_KERNEL);
if (ts == NULL) {
printk(“Alloc GFP_KERNELmemory failed.\n”);
return -ENOMEM;
}
memset(ts, 0, sizeof(*ts));
INIT_WORK(&ts->work, goodix_ts_work_func);
ts->client = client;
i2c_set_clientdata(client, ts);
//ts->irq_lock = SPIN_LOCK_UNLOCKED;
ts->gtp_rawdiff_mode = 0;
ret = gtp_i2c_test(client);
if (ret < 0){
printk(“I2C communicationERROR!\n”);
goto exit_device_detect;
}
goodix_resume_wq = create_singlethread_workqueue(“goodix_resume”);
if (goodix_resume_wq == NULL) {
printk(“create goodix_resume_wqfail!\n”);
return -ENOMEM;
}
goodix_wq =create_singlethread_workqueue(“goodix_wq”);
if (!goodix_wq) {
printk(KERN_ALERT “Creat goodix_wqworkqueue failed.\n”);
return-ENOMEM;
}
#if GTP_AUTO_UPDATE
ret = gup_init_update_proc(ts);
if (ret < 0) {
printk(“Create updatethread error.”);
}
#endif
ret = gtp_init_panel(ts);
if (ret < 0) {
printk(“GTP init panelfailed.\n”);
}
ret = gtp_request_input_dev(ts);
if (ret < 0) {
printk(“GTP request inputdev failed\n”);
gotoexit_device_detect;
}
ret= gtp_read_version(client, &version_info);
if(ret < 0) {
printk(“Readversion failed.”);
}
config_info.dev= &(ts->input_dev->dev);
ret = input_request_int(&(config_info.input_type), goodix_ts_irq_handler,CTP_IRQ_MODE,ts);
if (ret) {
printk(“Request irqfail!.\n”);
}
spin_lock_init(&ts->irq_lock);
#if GTP_CREATE_WR_NODE
init_wr_node(client);
#endif
#if GTP_ESD_PROTECT
INIT_DELAYED_WORK(>p_esd_check_work, gtp_esd_check_func);
gtp_esd_check_workqueue = create_workqueue(“gtp_esd_check”);
queue_delayed_work(gtp_esd_check_workqueue, >p_esd_check_work,GTP_ESD_CHECK_CIRCLE);
#endif
dprintk(DEBUG_INIT,”gt9xx probe success!\n”);
return 0;
exit_device_detect:
i2c_set_clientdata(client,NULL);
kfree(ts);
returnret;
}
/*******************************************************
Function:
Goodixtouchscreen driver release function.
Input:
client: i2c device struct.
Output:
Executiveoutcomes. 0—succeed.
*******************************************************/
static int goodix_ts_remove(structi2c_client *client)
{
struct goodix_ts_data *ts = i2c_get_clientdata(client);
dprintk(DEBUG_INIT,”%sstart!\n”, __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
flush_workqueue(gtp_esd_check_workqueue);
if(gtp_esd_check_workqueue)
destroy_workqueue(gtp_esd_check_workqueue);
#endif
input_free_int(&(config_info.input_type), ts);
flush_workqueue(goodix_wq);
//cancel_work_sync(&goodix_init_work);
cancel_work_sync(&goodix_resume_work);
if(goodix_wq)
destroy_workqueue(goodix_wq);
//destroy_workqueue(goodix_init_wq);
if(goodix_resume_wq)
destroy_workqueue(goodix_resume_wq);
i2c_set_clientdata(ts->client, NULL);
input_unregister_device(ts->input_dev);
kfree(ts);
return 0;
}
static void goodix_resume_events (structwork_struct *work)
{
intret;
struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client);
ret= gtp_wakeup_sleep(ts);
if(ret < 0)
printk(“resumepower on failed\n”);
gtp_irq_enable(ts);
}
/*******************************************************
Function:
Earlysuspend function.
Input:
h:early_suspendstruct.
Output:
None.
*******************************************************/
#ifdef CONFIG_HAS_EARLYSUSPEND
static void goodix_ts_early_suspend(structearly_suspend *h)
{
struct goodix_ts_data *ts;
s8 ret = -1;
ts = container_of(h, struct goodix_ts_data, early_suspend);
#if GTP_ESD_PROTECT
ts->gtp_is_suspend = 1;
cancel_delayed_work_sync(>p_esd_check_work);
#endif
gtp_irq_disable(ts);
cancel_work_sync(&goodix_resume_work);
flush_workqueue(goodix_resume_wq);
ret = cancel_work_sync(&ts->work);
flush_workqueue(goodix_wq);
ret = gtp_enter_sleep(ts);
if (ret < 0) {
printk(“GTP early suspendfailed.”);
}
}
/*******************************************************
Function:
Lateresume function.
Input:
h:early_suspendstruct.
Output:
None.
*******************************************************/
static void goodix_ts_late_resume(structearly_suspend *h)
{
struct goodix_ts_data *ts;
ts = container_of(h, struct goodix_ts_data, early_suspend);
queue_work(goodix_resume_wq, &goodix_resume_work);//gandy
#if GTP_ESD_PROTECT
ts->gtp_is_suspend = 0;
queue_delayed_work(gtp_esd_check_workqueue, >p_esd_check_work,GTP_ESD_CHECK_CIRCLE);
#endif
}
#else
#ifdef CONFIG_PM
static void goodix_ts_suspend(structi2c_client *client, pm_message_t mesg)
{
struct goodix_ts_data *ts;
s8 ret = -1;
ts = i2c_get_clientdata(client);
printk(“%s goodix_ts_suspend\n”, goodix_ts_name);
#if GTP_ESD_PROTECT
ts->gtp_is_suspend = 1;
cancel_delayed_work_sync(>p_esd_check_work);
#endif
ret = input_set_int_enable(&(config_info.input_type), 0);
if (ret < 0)
dprintk(DEBUG_SUSPEND,”%sirq disable failed\n”, goodix_ts_name);
cancel_work_sync(&goodix_resume_work);
flush_workqueue(goodix_resume_wq);
ret = cancel_work_sync(&ts->work);
flush_workqueue(goodix_wq);
ret = gtp_enter_sleep(ts);
if (ret < 0) {
printk(“GTP suspendfailed.”);
}
}
static void goodix_ts_resume(structi2c_client *client)
{
struct goodix_ts_data *ts;
ts = i2c_get_clientdata(client);
printk(“%s goodix_ts_resume\n”,goodix_ts_name);
queue_work(goodix_resume_wq, &goodix_resume_work);//gandy
#if GTP_ESD_PROTECT
ts->gtp_is_suspend = 0;
queue_delayed_work(gtp_esd_check_workqueue, >p_esd_check_work,GTP_ESD_CHECK_CIRCLE);
#endif
}
#endif
#endif
#if GTP_ESD_PROTECT
/*******************************************************
Function:
Initialize external watchdog for esd protect
Input:
client: i2c device.
Output:
result of i2c write operation.
1: succeed, otherwise: failed
*********************************************************/
s32 gtp_init_ext_watchdog(structi2c_client *client)
{
u8 opr_buffer[4] = {0x80, 0x40, 0xAA, 0xAA};
dprintk(DEBUG_INIT, “Init external watchdog…”);
return gtp_i2c_write(client, opr_buffer, 4);
}
/*******************************************************
Function:
Esd protect function.
Added external watchdog by meta, 2013/03/07
Input:
work: delayed work
Output:
None.
*******************************************************/
static void gtp_esd_check_func(structwork_struct *work)
{
s32 i;
s32 ret = -1;
struct goodix_ts_data *ts = NULL;
u8 test[4] = {0x80, 0x40};
dprintk(DEBUG_INIT, “enter %s work!\n”, __func__);
ts = i2c_get_clientdata(i2c_connect_client);
if (ts->gtp_is_suspend || ts->enter_update) {
return;
}
for (i = 0; i < 3; i++) {
ret =gtp_i2c_read(ts->client, test, 4);
dprintk(DEBUG_INIT,”0x8040 = 0x%02X, 0x8041 = 0x%02X”, test[2], test[3]);
if ((ret < 0)) {
// IC worksabnormally..
continue;
}else {
if ((test[2] == 0xAA)|| (test[3] != 0xAA)) {
// IC works abnormally..
i = 3;
break;
}else {
// IC worksnormally, Write 0x8040 0xAA
test[2] = 0xAA;
gtp_i2c_write(ts->client, test, 3);
break;
}
}
}
if (i >= 3) {
GTP_DEBUG(“IC WorkingABNORMALLY, 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);
}
return;
}
#endif
static const struct i2c_device_idgoodix_ts_id[] = {
{ CTP_NAME, 0 },
{ }
};
static struct i2c_driver goodix_ts_driver= {
.class = I2C_CLASS_HWMON,
.probe = goodix_ts_probe,
.remove = goodix_ts_remove,
#ifndef CONFIG_HAS_EARLYSUSPEND
#ifdef CONFIG_PM
.suspend =goodix_ts_suspend,
.resume =goodix_ts_resume,
#endif
#endif
.id_table = goodix_ts_id,
.driver = {
.name = CTP_NAME,
.owner = THIS_MODULE,
},
.address_list = normal_i2c,
};
static int ctp_get_system_config(void)
{
ctp_print_info(config_info,DEBUG_INIT);
twi_id = config_info.twi_id;
screen_max_x = config_info.screen_max_x;
screen_max_y = config_info.screen_max_y;
revert_x_flag = config_info.revert_x_flag;
revert_y_flag = config_info.revert_y_flag;
exchange_x_y_flag = config_info.exchange_x_y_flag;
if((screen_max_x == 0) || (screen_max_y == 0)){
printk(“%s:read configerror!\n”,__func__);
return 0;
}
return 1;
}
/*******************************************************
Function:
DriverInstall function.
Input:
None.
Output:
ExecutiveOutcomes. 0—succeed.
********************************************************/
static int __devinit goodix_ts_init(void)
{
s32 ret = -1;
dprintk(DEBUG_INIT,”****************************************************************\n”);
struct regulator *ldo = regulator_get(NULL, “axp22_ldoio1”);
if (input_fetch_sysconfig_para(&(config_info.input_type))) {
printk(“%s:ctp_fetch_sysconfig_para err.\n”, __func__);
return0;
} else {
printk(“%s:gt9xx ctp_fetch_sysconfig_para ok.\n”, __func__);
ret= input_init_platform_resource(&(config_info.input_type));
if(0 != ret) {
printk(“%s:ctp_ops.init_platform_resourceerr. \n”, __func__);
}
}
if(config_info.ctp_used == 0){
printk(“*** ctp_used set to 0!\n”);
printk(“*** if use ctp,please putthe sys_config.fex ctp_used set to 1. \n”);
return 0;
}
//关于电压部分是关键
if(IS_ERR(ldo)) {
printk(“glsX680get regulator error!! \n”);
return-1;
}else {
regulator_set_voltage(ldo,3300000, 3300000);
if(!regulator_is_enabled(ldo)){
regulator_enable(ldo);
}
regulator_put(ldo);
}
if(!ctp_get_system_config()){
printk(“%s:read configfail!\n”,__func__);
return ret;
}
input_set_power_enable(&(config_info.input_type),1);
msleep(10);
sunxi_gpio_to_name(CTP_IRQ_NUMBER,irq_pin_name);
gtp_io_init(20);
goodix_ts_driver.detect= ctp_detect;
ret = i2c_add_driver(&goodix_ts_driver);
printk(“%s: gt9xx init over!.\n”, __func__);
dprintk(DEBUG_INIT,”****************************************************************\n”);
return ret;
}
/*******************************************************
Function:
Driveruninstall function.
Input:
None.
Output:
ExecutiveOutcomes. 0—succeed.
********************************************************/
static void __exit goodix_ts_exit(void)
{
printk(“GTP driver exited.\n”);
i2c_del_driver(&goodix_ts_driver);
input_free_platform_resource(&(config_info.input_type));
}
late_initcall(goodix_ts_init);
module_exit(goodix_ts_exit);
MODULE_DESCRIPTION(“GTP SeriesDriver”);
MODULE_LICENSE(“GPL”);
四. 编译打包
回到目录:/home/yygyickl/A33/dragonboard
./build.sh 重新编译
./build.sh pack_debug 打包debug 固件
五. 烧到开发板,进入 校准程序后,触摸正常。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/148830.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...