SmartAudio/lichee/linux-4.9/drivers/input/touchscreen/ftxxxx/ft5x.c

1988 lines
54 KiB
C
Raw Normal View History

2018-07-13 01:31:50 +00:00
/*
* drivers/input/touchscreen/ft5x0x_ts.c
*
* FocalTech ft5x TouchScreen driver.
*
* Copyright (c) 2010 Focal tech Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* note: only support mulititouch Wenfs 2010-10-01
* for this touchscreen to work, it's slave addr must be set to 0x7e | 0x70
*/
#include <linux/i2c.h>
#include <linux/input.h>
#include "ft5x_ts.h"
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/pm.h>
#include <linux/earlysuspend.h>
#endif
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/async.h>
#include <linux/hrtimer.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/gpio.h>
#include <asm/irq.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include "../../init-input.h"
#define CONFIG_SUPPORT_FTS_CTP_UPG
#define FOR_TSLIB_TEST
#ifdef TOUCH_KEY_SUPPORT
#define TOUCH_KEY_FOR_EVB13
#ifdef TOUCH_KEY_FOR_ANGDA
#define TOUCH_KEY_X_LIMIT (60000)
#define TOUCH_KEY_NUMBER (4)
#endif
#ifdef TOUCH_KEY_FOR_EVB13
#define TOUCH_KEY_LOWER_X_LIMIT (848)
#define TOUCH_KEY_HIGHER_X_LIMIT (852)
#define TOUCH_KEY_NUMBER (5)
#endif
#endif
/* FT5X02_CONFIG */
#define FT5X02_CONFIG_NAME "fttpconfig_5x02public.ini"
extern int ft5x02_Init_IC_Param(struct i2c_client *client);
extern int ft5x02_get_ic_param(struct i2c_client *client);
extern int ft5x02_Get_Param_From_Ini(char *config_name);
struct i2c_dev{
struct list_head list;
struct i2c_adapter *adap;
struct device *dev;
};
static struct class *i2c_dev_class;
static LIST_HEAD (i2c_dev_list);
static DEFINE_SPINLOCK(i2c_dev_list_lock);
struct Upgrade_Info {
u16 delay_aa; /*delay of write FT_UPGRADE_AA */
u16 delay_55; /*delay of write FT_UPGRADE_55 */
u8 upgrade_id_1; /*upgrade id 1 */
u8 upgrade_id_2; /*upgrade id 2 */
u16 delay_readid; /*delay of read id */
};
#define FT5X_NAME "ft5x_ts"
static struct i2c_client *this_client;
#ifdef TOUCH_KEY_SUPPORT
static int key_tp = 0;
static int key_val = 0;
#endif
/*********************************************************************************************/
#define CTP_IRQ_NUMBER (config_info.int_number)
#define CTP_IRQ_MODE (IRQF_TRIGGER_FALLING)
#define SCREEN_MAX_X (screen_max_x)
#define SCREEN_MAX_Y (screen_max_y)
#define CTP_NAME FT5X_NAME
#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 struct ctp_config_info config_info = {
.input_type = CTP_TYPE,
.name = NULL,
.int_number = 0,
};
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,
};
#define dprintk(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);
/*********************************************************************************************/
/*------------------------------------------------------------------------------------------*/
/* Addresses to scan */
static const unsigned short normal_i2c[2] = {0x38,I2C_CLIENT_END};
static const int chip_id_value[] = {0x55,0x06,0x08,0x02,0xa3};
static int chip_id = 0;
static void ft5x_resume_events(struct work_struct *work);
struct workqueue_struct *ft5x_resume_wq;
static DECLARE_WORK(ft5x_resume_work, ft5x_resume_events);
static void ft5x_init_events(struct work_struct *work);
struct workqueue_struct *ft5x_wq;
static DECLARE_WORK(ft5x_init_work, ft5x_init_events);
/*------------------------------------------------------------------------------------------*/
static int ctp_detect(struct i2c_client *client, struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
int ret = 0;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
if(twi_id == adapter->nr){
ret = i2c_smbus_read_byte_data(client,0xA3);
if(ret == -70) {
msleep(10);
ret = i2c_smbus_read_byte_data(client,0xA3);
}
dprintk(DEBUG_INIT,"addr:0x%x,chip_id_value:0x%x\n",client->addr,ret);
if(ret < 0){
printk("%s:I2C connection might be something wrong ! \n",__func__);
return -ENODEV;
} else {
strlcpy(info->type, CTP_NAME, I2C_NAME_SIZE);
chip_id = ret;
return 0;
}
}else{
return -ENODEV;
}
}
/**
* ctp_print_info - sysconfig print function
* return value:
*
*/
static void ctp_print_info(struct ctp_config_info info,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
*
*/
static 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);
return 0;
}
int fts_ctpm_fw_upgrade_with_i_file(void);
static struct i2c_dev *i2c_dev_get_by_minor(unsigned index)
{
struct i2c_dev *i2c_dev = NULL;
spin_lock(&i2c_dev_list_lock);
list_for_each_entry(i2c_dev,&i2c_dev_list,list){
dprintk(DEBUG_OTHERS_INFO,"--line = %d ,i2c_dev->adapt->nr = %d,index = %d.\n",\
__LINE__,i2c_dev->adap->nr,index);
if(i2c_dev->adap->nr == index){
goto found;
}
}
i2c_dev = NULL;
found:
spin_unlock(&i2c_dev_list_lock);
return i2c_dev ;
}
static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap)
{
struct i2c_dev *i2c_dev;
if (adap->nr >= I2C_MINORS){
dprintk(DEBUG_OTHERS_INFO,"i2c-dev:out of device minors (%d) \n",adap->nr);
return ERR_PTR (-ENODEV);
}
i2c_dev = kzalloc(sizeof(*i2c_dev), GFP_KERNEL);
if (!i2c_dev){
return ERR_PTR(-ENOMEM);
}
i2c_dev->adap = adap;
spin_lock(&i2c_dev_list_lock);
list_add_tail(&i2c_dev->list, &i2c_dev_list);
spin_unlock(&i2c_dev_list_lock);
return i2c_dev;
}
static int ft5x_i2c_rxdata(char *rxdata, int length);
struct ts_event {
u16 x1;
u16 y1;
u16 x2;
u16 y2;
u16 x3;
u16 y3;
u16 x4;
u16 y4;
u16 x5;
u16 y5;
u16 pressure;
s16 touch_ID1;
s16 touch_ID2;
s16 touch_ID3;
s16 touch_ID4;
s16 touch_ID5;
u8 touch_point;
};
struct ft5x_ts_data {
struct input_dev *input_dev;
struct ts_event event;
struct work_struct pen_event_work;
struct workqueue_struct *ts_workqueue;
#ifdef CONFIG_HAS_EARLYSUSPEND
struct early_suspend early_suspend;
#endif
bool is_suspended;
};
/* ---------------------------------------------------------------------
*
* Focal Touch panel upgrade related driver
*
*
----------------------------------------------------------------------*/
typedef enum
{
ERR_OK,
ERR_MODE,
ERR_READID,
ERR_ERASE,
ERR_STATUS,
ERR_ECC,
ERR_DL_ERASE_FAIL,
ERR_DL_PROGRAM_FAIL,
ERR_DL_VERIFY_FAIL
}E_UPGRADE_ERR_TYPE;
typedef unsigned char FTS_BYTE; //8 bit
typedef unsigned short FTS_WORD; //16 bit
typedef unsigned int FTS_DWRD; //16 bit
typedef unsigned char FTS_BOOL; //8 bit
#define FTS_NULL 0x0
#define FTS_TRUE 0x01
#define FTS_FALSE 0x0
#define I2C_CTPM_ADDRESS (0x70>>1)
static void delay_ms(FTS_WORD w_ms)
{
//platform related, please implement this function
msleep( w_ms );
}
void delay_qt_ms(unsigned long w_ms)
{
unsigned long i;
unsigned long j;
for (i = 0; i < w_ms; i++)
{
for (j = 0; j < 1000; j++)
{
udelay(1);
}
}
}
/*
[function]:
callback: read data from ctpm by i2c interface,implemented by special user;
[parameters]:
bt_ctpm_addr[in] :the address of the ctpm;
pbt_buf[out] :data buffer;
dw_lenth[in] :the length of the data buffer;
[return]:
FTS_TRUE :success;
FTS_FALSE :fail;
*/
int i2c_read_interface(u8 bt_ctpm_addr, u8* pbt_buf, u16 dw_lenth)
{
int ret;
ret = i2c_master_recv(this_client, pbt_buf, dw_lenth);
if(ret != dw_lenth){
printk("ret = %d. \n", ret);
printk("i2c_read_interface error\n");
return FTS_FALSE;
}
return FTS_TRUE;
}
/*
[function]:
callback: write data to ctpm by i2c interface,implemented by special user;
[parameters]:
bt_ctpm_addr[in] :the address of the ctpm;
pbt_buf[in] :data buffer;
dw_lenth[in] :the length of the data buffer;
[return]:
FTS_TRUE :success;
FTS_FALSE :fail;
*/
int i2c_write_interface(u8 bt_ctpm_addr, u8* pbt_buf, u16 dw_lenth)
{
int ret;
ret=i2c_master_send(this_client, pbt_buf, dw_lenth);
if(ret != dw_lenth){
printk("i2c_write_interface error\n");
return FTS_FALSE;
}
return FTS_TRUE;
}
/***************************************************************************************/
/*
[function]:
read out the register value.
[parameters]:
e_reg_name[in] :register name;
pbt_buf[out] :the returned register value;
bt_len[in] :length of pbt_buf, should be set to 2;
[return]:
FTS_TRUE :success;
FTS_FALSE :io fail;
*/
u8 fts_register_read(u8 e_reg_name, u8* pbt_buf, u8 bt_len)
{
u8 read_cmd[3]= {0};
u8 cmd_len = 0;
read_cmd[0] = e_reg_name;
cmd_len = 1;
/*call the write callback function*/
// if(!i2c_write_interface(I2C_CTPM_ADDRESS, &read_cmd, cmd_len))
// {
// return FTS_FALSE;
// }
if(!i2c_write_interface(I2C_CTPM_ADDRESS, read_cmd, cmd_len)) {//change by zhengdixu
return FTS_FALSE;
}
/*call the read callback function to get the register value*/
if(!i2c_read_interface(I2C_CTPM_ADDRESS, pbt_buf, bt_len)){
return FTS_FALSE;
}
return FTS_TRUE;
}
/*
[function]:
write a value to register.
[parameters]:
e_reg_name[in] :register name;
pbt_buf[in] :the returned register value;
[return]:
FTS_TRUE :success;
FTS_FALSE :io fail;
*/
int fts_register_write(u8 e_reg_name, u8 bt_value)
{
FTS_BYTE write_cmd[2] = {0};
write_cmd[0] = e_reg_name;
write_cmd[1] = bt_value;
/*call the write callback function*/
//return i2c_write_interface(I2C_CTPM_ADDRESS, &write_cmd, 2);
return i2c_write_interface(I2C_CTPM_ADDRESS, write_cmd, 2); //change by zhengdixu
}
/*
[function]:
send a command to ctpm.
[parameters]:
btcmd[in] :command code;
btPara1[in] :parameter 1;
btPara2[in] :parameter 2;
btPara3[in] :parameter 3;
num[in] :the valid input parameter numbers, if only command code needed and no parameters followed,then the num is 1;
[return]:
FTS_TRUE :success;
FTS_FALSE :io fail;
*/
int cmd_write(u8 btcmd,u8 btPara1,u8 btPara2,u8 btPara3,u8 num)
{
FTS_BYTE write_cmd[4] = {0};
write_cmd[0] = btcmd;
write_cmd[1] = btPara1;
write_cmd[2] = btPara2;
write_cmd[3] = btPara3;
//return i2c_write_interface(I2C_CTPM_ADDRESS, &write_cmd, num);
return i2c_write_interface(I2C_CTPM_ADDRESS, write_cmd, num);//change by zhengdixu
}
/*
[function]:
write data to ctpm , the destination address is 0.
[parameters]:
pbt_buf[in] :point to data buffer;
bt_len[in] :the data numbers;
[return]:
FTS_TRUE :success;
FTS_FALSE :io fail;
*/
int byte_write(u8* pbt_buf, u16 dw_len)
{
return i2c_write_interface(I2C_CTPM_ADDRESS, pbt_buf, dw_len);
}
/*
[function]:
read out data from ctpm,the destination address is 0.
[parameters]:
pbt_buf[out] :point to data buffer;
bt_len[in] :the data numbers;
[return]:
FTS_TRUE :success;
FTS_FALSE :io fail;
*/
int byte_read(u8* pbt_buf, u8 bt_len)
{
return i2c_read_interface(I2C_CTPM_ADDRESS, pbt_buf, bt_len);
//ft5x_i2c_rxdata
}
/*
[function]:
burn the FW to ctpm.
[parameters]:(ref. SPEC)
pbt_buf[in] :point to Head+FW ;
dw_lenth[in]:the length of the FW + 6(the Head length);
bt_ecc[in] :the ECC of the FW
[return]:
ERR_OK :no error;
ERR_MODE :fail to switch to UPDATE mode;
ERR_READID :read id fail;
ERR_ERASE :erase chip fail;
ERR_STATUS :status error;
ERR_ECC :ecc error.
*/
#define FTS_PACKET_LENGTH 128 //2//4//8//16//32//64//128//256
static unsigned char CTPM_FW[]=
{
#include "ft_app.i"
};
unsigned char fts_ctpm_get_i_file_ver(void)
{
unsigned int ui_sz;
ui_sz = sizeof(CTPM_FW);
if (ui_sz > 2){
return CTPM_FW[ui_sz - 2];
}else{
//TBD, error handling?
return 0xff; //default value
}
}
/*
*get upgrade information depend on the ic type
*/
static void fts_get_upgrade_info(struct Upgrade_Info *upgrade_info)
{
#ifdef WILLIAM_DEBUG
printk("####ft5x chip_id=%d####\n", chip_id);
#endif
switch (chip_id) {
case 0x55: //IC_FT5X06:
upgrade_info->delay_55 = FT5X06_UPGRADE_55_DELAY;
upgrade_info->delay_aa = FT5X06_UPGRADE_AA_DELAY;
upgrade_info->upgrade_id_1 = FT5X06_UPGRADE_ID_1;
upgrade_info->upgrade_id_2 = FT5X06_UPGRADE_ID_2;
upgrade_info->delay_readid = FT5X06_UPGRADE_READID_DELAY;
break;
case 0x08: //IC_FT5606<30><36><EFBFBD><EFBFBD>IC_FT5506
upgrade_info->delay_55 = FT5606_UPGRADE_55_DELAY;
upgrade_info->delay_aa = FT5606_UPGRADE_AA_DELAY;
upgrade_info->upgrade_id_1 = FT5606_UPGRADE_ID_1;
upgrade_info->upgrade_id_2 = FT5606_UPGRADE_ID_2;
upgrade_info->delay_readid = FT5606_UPGRADE_READID_DELAY;
break;
case 0x00: //IC FT5316
case 0x0a: //IC FT5316
upgrade_info->delay_55 = FT5316_UPGRADE_55_DELAY;
upgrade_info->delay_aa = FT5316_UPGRADE_AA_DELAY;
upgrade_info->upgrade_id_1 = FT5316_UPGRADE_ID_1;
upgrade_info->upgrade_id_2 = FT5316_UPGRADE_ID_2;
upgrade_info->delay_readid = FT5316_UPGRADE_READID_DELAY;
break;
default:
break;
}
}
E_UPGRADE_ERR_TYPE ft5x06_ctpm_fw_upgrade(u8* pbt_buf, u16 dw_lenth)
{
u8 reg_val[2] = {0};
FTS_BOOL i_ret = 0;
u16 i = 0;
u16 packet_number;
u16 j;
u16 temp;
u16 lenght;
u8 packet_buf[FTS_PACKET_LENGTH + 6];
//u8 auc_i2c_write_buf[10];
u8 bt_ecc;
struct Upgrade_Info upgradeinfo = {0, 0, 0, 0 , 0};
fts_get_upgrade_info(&upgradeinfo);
/*********Step 1:Reset CTPM *****/
/*write 0xaa to register 0xfc*/
//delay_ms(100);//<2F><><EFBFBD>µ<EFBFBD>Դ<EFBFBD><D4B4>ȥ<EFBFBD><C8A5><EFBFBD><EFBFBD>ʱ
fts_register_write(0xfc,0xaa);
delay_ms(upgradeinfo.delay_aa);
/*write 0x55 to register 0xfc*/
fts_register_write(0xfc,0x55);
printk("Step 1: Reset CTPM test\n");
delay_ms(upgradeinfo.delay_55);
/*********Step 2:Enter upgrade mode *****/
//auc_i2c_write_buf[0] = 0x55;
//auc_i2c_write_buf[1] = 0xaa;
i = 0;
do{
i++;
//i_ret = i2c_write_interface(I2C_CTPM_ADDRESS, auc_i2c_write_buf, 2);
cmd_write(0x55,0xaa,0x00,0x00,2);
printk("Step 2: Enter update mode. \n");
delay_ms(5);
}while((FTS_FALSE == i_ret) && i<5);
/*********Step 3:check READ-ID***********************/
/*send the opration head*/
msleep(upgradeinfo.delay_readid);
cmd_write(0x90,0x00,0x00,0x00,4);
byte_read(reg_val,2);
if (reg_val[0] == upgradeinfo.upgrade_id_1&& reg_val[1] == upgradeinfo.upgrade_id_2) {
printk("Step 3: CTPM ID,ID1 = 0x%x,ID2 = 0x%x\n",reg_val[0],reg_val[1]);
}
else {
printk("Step 3: CTPM ID,ID1 = 0x%x,ID2 = 0x%x\n",reg_val[0],reg_val[1]);
return ERR_READID;
}
cmd_write(0xcd,0x00,0x00,0x00,1);
byte_read(reg_val,1);
/*Step 4:erase app and panel paramenter area*/
cmd_write(0x61,0x00,0x00,0x00,1);
msleep(2000);
cmd_write(0x63,0x00,0x00,0x00,1);
msleep(100);
printk("Step 4: erase. \n");
/*********Step 5:write firmware(FW) to ctpm flash*********/
bt_ecc = 0;
printk("Step 5: start upgrade. \n");
dw_lenth = dw_lenth - 8;
packet_number = (dw_lenth) / FTS_PACKET_LENGTH;
packet_buf[0] = 0xbf;
packet_buf[1] = 0x00;
for (j=0;j<packet_number;j++){
temp = j * FTS_PACKET_LENGTH;
packet_buf[2] = (FTS_BYTE)(temp>>8);
packet_buf[3] = (FTS_BYTE)temp;
lenght = FTS_PACKET_LENGTH;
packet_buf[4] = (FTS_BYTE)(lenght>>8);
packet_buf[5] = (FTS_BYTE)lenght;
for (i=0;i<FTS_PACKET_LENGTH;i++){
packet_buf[6+i] = pbt_buf[j*FTS_PACKET_LENGTH + i];
bt_ecc ^= packet_buf[6+i];
}
byte_write(&packet_buf[0],FTS_PACKET_LENGTH + 6);
//delay_ms(FTS_PACKET_LENGTH/6 + 1);
msleep(FTS_PACKET_LENGTH/6 + 1);
if ((j * FTS_PACKET_LENGTH % 1024) == 0){
printk("upgrade the 0x%x th byte.\n", ((unsigned int)j) * FTS_PACKET_LENGTH);
}
}
if ((dw_lenth) % FTS_PACKET_LENGTH > 0){
temp = packet_number * FTS_PACKET_LENGTH;
packet_buf[2] = (FTS_BYTE)(temp>>8);
packet_buf[3] = (FTS_BYTE)temp;
temp = (dw_lenth) % FTS_PACKET_LENGTH;
packet_buf[4] = (FTS_BYTE)(temp>>8);
packet_buf[5] = (FTS_BYTE)temp;
for (i=0;i<temp;i++){
packet_buf[6+i] = pbt_buf[ packet_number*FTS_PACKET_LENGTH + i];
bt_ecc ^= packet_buf[6+i];
}
byte_write(&packet_buf[0],temp+6);
//delay_ms(20);
msleep(20);
}
//send the last six byte
for (i = 0; i<6; i++){
temp = 0x6ffa + i;
packet_buf[2] = (FTS_BYTE)(temp>>8);
packet_buf[3] = (FTS_BYTE)temp;
temp =1;
packet_buf[4] = (FTS_BYTE)(temp>>8);
packet_buf[5] = (FTS_BYTE)temp;
packet_buf[6] = pbt_buf[ dw_lenth + i];
bt_ecc ^= packet_buf[6];
byte_write(&packet_buf[0],7);
//delay_ms(20);
msleep(20);
}
/*********Step 6: read out checksum***********************/
/*send the opration head*/
//cmd_write(0xcc,0x00,0x00,0x00,1);//<2F><>0xcc<63><63><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><D6B7>ȥ<EFBFBD><C8A5><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>ֽ<EFBFBD>
// byte_read(reg_val,1);//change by zhengdixu
fts_register_read(0xcc, reg_val,1);
printk("Step 6: ecc read 0x%x, new firmware 0x%x. \n", reg_val[0], bt_ecc);
if(reg_val[0] != bt_ecc){
//cmd_write(0x07,0x00,0x00,0x00,1);
printk("ecc error! \n");
return ERR_ECC;
}
/*********Step 7: reset the new FW***********************/
cmd_write(0x07,0x00,0x00,0x00,1);
msleep(300);
return ERR_OK;
}
E_UPGRADE_ERR_TYPE ft5x02_ctpm_fw_upgrade(u8* pbt_buf, u32 dw_lenth)
{
u8 reg_val[2] = {0};
u32 i = 0;
u32 packet_number;
u32 j;
u32 temp;
u32 lenght;
u8 packet_buf[FTS_PACKET_LENGTH + 6];
//u8 auc_i2c_write_buf[10];
u8 bt_ecc;
//struct timeval begin_tv, end_tv;
//do_gettimeofday(&begin_tv);
for (i=0; i<16; i++) {
/*********Step 1:Reset CTPM *****/
/*write 0xaa to register 0xfc*/
fts_register_write(0xfc,0xaa);
msleep(30);
/*write 0x55 to register 0xfc*/
fts_register_write(0xfc,0x55);
//delay_qt_ms(18);
delay_qt_ms(25);
/*********Step 2:Enter upgrade mode *****/
#if 0
//auc_i2c_write_buf[0] = 0x55;
//auc_i2c_write_buf[1] = 0xaa;
do
{
i ++;
//i_ret = ft5x02_i2c_Write(client, auc_i2c_write_buf, 2);
//i_ret = i2c_write_interface(I2C_CTPM_ADDRESS, auc_i2c_write_buf, 2);
cmd_write(0x55,0xaa,0x00,0x00,2);
delay_qt_ms(5);
}while(i_ret <= 0 && i < 5 );
#else
//auc_i2c_write_buf[0] = 0x55;
//ft5x02_i2c_Write(client, auc_i2c_write_buf, 1);
cmd_write(0x55,0x00,0x00,0x00,1);
delay_qt_ms(1);
//auc_i2c_write_buf[0] = 0xaa;
//ft5x02_i2c_Write(client, auc_i2c_write_buf, 1);
cmd_write(0xaa,0x00,0x00,0x00,1);
#endif
/*********Step 3:check READ-ID***********************/
delay_qt_ms(1);
//ft5x02_upgrade_send_head(client);
cmd_write(0xFA,0xFA,0x00,0x00,2);//ft5x02_upgrade_send_head
//auc_i2c_write_buf[0] = 0x90;
//auc_i2c_write_buf[1] = auc_i2c_write_buf[2] = auc_i2c_write_buf[3] = 0x00;
//ft5x02_i2c_Read(client, auc_i2c_write_buf, 4, reg_val, 2);
cmd_write(0x90,0x00,0x00,0x00,4);
byte_read(reg_val,2);
if (reg_val[0] == 0x79
&& reg_val[1] == 0x02) {
//dev_dbg(&client->dev, "[FTS] Step 3: CTPM ID,ID1 = 0x%x,ID2 = 0x%x\n",reg_val[0],reg_val[1]);
printk("[FTS] Step 3: CTPM ID,ID1 = 0x%x,ID2 = 0x%x\n",reg_val[0],reg_val[1]);
break;
} else {
printk("[FTS] Step 3 ERROR: CTPM ID,ID1 = 0x%x,ID2 = 0x%x\n",reg_val[0],reg_val[1]);
//delay_qt_ms(1);
}
}
if (i >= 6)
return ERR_READID;
/********Step 4:enable write function*/
//ft5x02_upgrade_send_head(client);
cmd_write(0xFA,0xFA,0x00,0x00,2);//ft5x02_upgrade_send_head
//auc_i2c_write_buf[0] = 0x06;
//ft5x02_i2c_Write(client, auc_i2c_write_buf, 1);
cmd_write(0x06,0x00,0x00,0x00,1);
/*********Step 5:write firmware(FW) to ctpm flash*********/
bt_ecc = 0;
packet_number = (dw_lenth) / FTS_PACKET_LENGTH;
packet_buf[0] = 0xbf;
packet_buf[1] = 0x00;
for (j=0; j<packet_number; j++) {
temp = j * FTS_PACKET_LENGTH;
packet_buf[2] = (u8)(temp>>8);
packet_buf[3] = (u8)temp;
lenght = FTS_PACKET_LENGTH;
packet_buf[4] = (u8)(lenght>>8);
packet_buf[5] = (u8)lenght;
if(temp>=0x4c00 && temp <(0x4c00+512))
continue;
for (i=0; i<FTS_PACKET_LENGTH; i++) {
packet_buf[6+i] = pbt_buf[j*FTS_PACKET_LENGTH + i];
bt_ecc ^= packet_buf[6+i];
}
//ft5x02_upgrade_send_head(client);
cmd_write(0xFA,0xFA,0x00,0x00,2);//ft5x02_upgrade_send_head
//ft5x02_i2c_Write(client, packet_buf, FTS_PACKET_LENGTH+6);
byte_write(&packet_buf[0],FTS_PACKET_LENGTH + 6);
delay_qt_ms(2);
}
if ((dw_lenth) % FTS_PACKET_LENGTH > 0) {
temp = packet_number * FTS_PACKET_LENGTH;
packet_buf[2] = (u8)(temp>>8);
packet_buf[3] = (u8)temp;
temp = (dw_lenth) % FTS_PACKET_LENGTH;
packet_buf[4] = (u8)(temp>>8);
packet_buf[5] = (u8)temp;
for (i=0; i<temp; i++) {
packet_buf[6+i] = pbt_buf[ packet_number*FTS_PACKET_LENGTH + i];
bt_ecc ^= packet_buf[6+i];
}
//ft5x02_upgrade_send_head(client);
cmd_write(0xFA,0xFA,0x00,0x00,2);//ft5x02_upgrade_send_head
//ft5x02_i2c_Write(client, packet_buf, temp+6);
byte_write(&packet_buf[0],temp + 6);
delay_qt_ms(2);
}
/********Disable write function*/
//ft5x02_upgrade_send_head(client);
cmd_write(0xFA,0xFA,0x00,0x00,2);//ft5x02_upgrade_send_head
//auc_i2c_write_buf[0] = 0x04;
//ft5x02_i2c_Write(client, auc_i2c_write_buf, 1);
cmd_write(0x04,0x00,0x00,0x00,1);
delay_qt_ms(1);
/*********Step 6: read out checksum***********************/
//ft5x02_upgrade_send_head(client);
cmd_write(0xFA,0xFA,0x00,0x00,2);//ft5x02_upgrade_send_head
//auc_i2c_write_buf[0] = 0xcc;
//ft5x02_i2c_Read(client, auc_i2c_write_buf, 1, reg_val, 1);
cmd_write(0xcc,0x00,0x00,0x00,1);
byte_read(reg_val,1);
if (reg_val[0] != bt_ecc) {
printk("[FTS]--ecc error! FW=%02x bt_ecc=%02x\n", reg_val[0], bt_ecc);
//return -EIO;
return ERR_READID;
}
/*********Step 7: reset the new FW***********************/
//ft5x02_upgrade_send_head(client);
cmd_write(0xFA,0xFA,0x00,0x00,2);//ft5x02_upgrade_send_head
//auc_i2c_write_buf[0] = 0x07;
//ft5x02_i2c_Write(client, auc_i2c_write_buf, 1);
cmd_write(0x07,0x00,0x00,0x00,1);
msleep(200); /*make sure CTP startup normally*/
//DBG("-------upgrade successful-----\n");
//do_gettimeofday(&end_tv);
//DBG("cost time=%lu.%lu\n", end_tv.tv_sec-begin_tv.tv_sec,
// end_tv.tv_usec-begin_tv.tv_usec);
return ERR_OK;
}
int fts_ctpm_auto_clb(void)
{
unsigned char uc_temp;
unsigned char i ;
printk("[FTS] start auto CLB.\n");
msleep(200);
fts_register_write(0, 0x40);
//delay_ms(100); //make sure already enter factory mode
msleep(100);
fts_register_write(2, 0x4); //write command to start calibration
//delay_ms(300);
msleep(300);
for(i=0;i<100;i++){
fts_register_read(0,&uc_temp,1);
if (((uc_temp&0x70)>>4) == 0x0){ //return to normal mode, calibration finish
break;
}
//delay_ms(200);
msleep(200);
printk("[FTS] waiting calibration %d\n",i);
}
printk("[FTS] calibration OK.\n");
msleep(300);
fts_register_write(0, 0x40); //goto factory mode
delay_ms(100); //make sure already enter factory mode
fts_register_write(2, 0x5); //store CLB result
delay_ms(300);
fts_register_write(0, 0x0); //return to normal mode
msleep(300);
printk("[FTS] store CLB result OK.\n");
return 0;
}
void getVerNo(u8* buf, int len)
{
u8 start_reg=0x0;
int ret = -1;
//int status = 0;
int i = 0;
start_reg = 0xa6;
(void)i;
#if 0
printk("read 0xa6 one time. \n");
if(FTS_FALSE == fts_register_read(0xa6, buf, len)){
return ;
}
for (i=0; i< len; i++) {
printk("=========buf[%d] = 0x%x \n", i, buf[i]);
}
printk("read 0xa8. \n");
if(FTS_FALSE == fts_register_read(0xa8, buf, len)){
return ;
}
for (i=0; i< len; i++) {
printk("=========buf[%d] = 0x%x \n", i, buf[i]);
}
ft5x_i2c_rxdata(buf, len);
for (i=0; i< len; i++) {
printk("=========buf[%d] = 0x%x \n", i, buf[i]);
}
byte_read(buf, len);
for (i=0; i< len; i++) {
printk("=========buf[%d] = 0x%x \n", i, buf[i]);
}
#endif
ret =fts_register_read(0xa6, buf, len);
//et = ft5406_read_regs(ft5x0x_ts_data_test->client,start_reg, buf, 2);
if (ret < 0) {
printk("%s read_data i2c_rxdata failed: %d\n", __func__, ret);
return;
}
#if 0
for (i=0; i<2; i++) {
printk("=========buf[%d] = 0x%x \n", i, buf[i]);
}
return;
#endif
}
int fts_ctpm_fw_upgrade_with_i_file(void)
{
FTS_BYTE* pbt_buf = FTS_NULL;
int i_ret = 0;
unsigned char a;
unsigned char b;
#define BUFFER_LEN (2) //len == 2
unsigned char buf[BUFFER_LEN] = {0};
//=========FW upgrade========================*/
printk("%s. \n", __func__);
pbt_buf = CTPM_FW;
//msleep(200);
// cmd_write(0x07,0x00,0x00,0x00,1);
msleep(100);
getVerNo(buf, BUFFER_LEN);
a = buf[0];
b = fts_ctpm_get_i_file_ver();
/* printk("a == %hu, b== %hu \n",a, b);*/
/*
* when the firmware in touch panel maybe corrupted,
* or the firmware in host flash is new, need upgrade
*/
if ( 0xa6 == a || a != b ){
/*call the upgrade function*/
if(chip_id == 0x55 || chip_id == 0x08 || chip_id == 0x00 || chip_id == 0x0a){
i_ret = ft5x06_ctpm_fw_upgrade(&pbt_buf[0],sizeof(CTPM_FW));
if (i_ret != 0){
printk("[FTS] upgrade failed i_ret = %d.\n", i_ret);
}
else {
printk("[FTS] upgrade successfully.\n");
#ifdef AUTO_CLB
fts_ctpm_auto_clb(); //start auto CLB
#endif
}
}
}
return i_ret;
}
unsigned char fts_ctpm_get_upg_ver(void)
{
unsigned int ui_sz;
ui_sz = sizeof(CTPM_FW);
if (ui_sz > 2){
return CTPM_FW[0];
}
else{
return 0xff; //default value
}
}
static int ft5x_i2c_rxdata(char *rxdata, int length)
{
int ret;
struct i2c_msg msgs[] = {
{
.addr = this_client->addr,
.flags = 0,
.len = 1,
.buf = rxdata,
},
{
.addr = this_client->addr,
.flags = I2C_M_RD,
.len = length,
.buf = rxdata,
},
};
ret = i2c_transfer(this_client->adapter, msgs, 2);
if (ret < 0)
printk("msg %s i2c read error: %d\n", __func__, ret);
return ret;
}
static int ft5x_i2c_txdata(char *txdata, int length)
{
int ret;
struct i2c_msg msg[] = {
{
.addr = this_client->addr,
.flags = 0,
.len = length,
.buf = txdata,
},
};
//msleep(1);
ret = i2c_transfer(this_client->adapter, msg, 1);
if (ret < 0)
pr_err("%s i2c write error: %d\n", __func__, ret);
return ret;
}
static int ft5x_set_reg(u8 addr, u8 para)
{
u8 buf[3];
int ret = -1;
buf[0] = addr;
buf[1] = para;
ret = ft5x_i2c_txdata(buf, 2);
if (ret < 0) {
pr_err("write reg failed! %#x ret: %d", buf[0], ret);
return -1;
}
return 0;
}
static void ft5x_ts_release(void)
{
struct ft5x_ts_data *data = i2c_get_clientdata(this_client);
#ifdef CONFIG_FT5X0X_MULTITOUCH
#ifdef TOUCH_KEY_SUPPORT
if(1 == key_tp){
input_report_key(data->input_dev, key_val, 0);
dprintk(DEBUG_KEY_INFO,"Release Key = %d\n",key_val);
} else{
input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, 0);
}
#else
input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, 0);
input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 0);
#endif
input_report_key(data->input_dev, BTN_TOUCH, 0);
#else
input_report_abs(data->input_dev, ABS_PRESSURE, 0);
input_report_key(data->input_dev, BTN_TOUCH, 0);
#endif
input_sync(data->input_dev);
return;
}
static int ft5x_read_data(void)
{
struct ft5x_ts_data *data = i2c_get_clientdata(this_client);
struct ts_event *event = &data->event;
unsigned char buf[32]={0};
int ret = -1;
#ifdef CONFIG_FT5X0X_MULTITOUCH
ret = ft5x_i2c_rxdata(buf, 31);
#else
ret = ft5x_i2c_rxdata(buf, 31);
#endif
if (ret < 0) {
dprintk(DEBUG_X_Y_INFO,"%s read_data i2c_rxdata failed: %d\n", __func__, ret);
return ret;
}
memset(event, 0, sizeof(struct ts_event));
event->touch_point = buf[2] & 0x07;// 000 0111
dprintk(DEBUG_X_Y_INFO,"touch point = %d\n",event->touch_point);
if (event->touch_point == 0) {
ft5x_ts_release();
return 1;
}
switch (event->touch_point) {
case 5:
event->x5 = (s16)(buf[0x1b] & 0x0F)<<8 | (s16)buf[0x1c];
event->y5 = (s16)(buf[0x1d] & 0x0F)<<8 | (s16)buf[0x1e];
dprintk(DEBUG_X_Y_INFO,"source data:event->x5 = %d, event->y5 = %d. \n", event->x5, event->y5);
if(1 == exchange_x_y_flag){
swap(event->x5, event->y5);
}
if(1 == revert_x_flag){
event->x5 = SCREEN_MAX_X - event->x5;
}
if(1 == revert_y_flag){
event->y5 = SCREEN_MAX_Y - event->y5;
}
event->touch_ID5=(s16)(buf[0x1d] & 0xF0)>>4;
dprintk(DEBUG_X_Y_INFO,"touch id : %d. \n",event->touch_ID5);
case 4:
event->x4 = (s16)(buf[0x15] & 0x0F)<<8 | (s16)buf[0x16];
event->y4 = (s16)(buf[0x17] & 0x0F)<<8 | (s16)buf[0x18];
dprintk(DEBUG_X_Y_INFO,"source data:event->x4 = %d, event->y4 = %d. \n", event->x4, event->y4);
if(1 == exchange_x_y_flag){
swap(event->x4, event->y4);
}
if(1 == revert_x_flag){
event->x4 = SCREEN_MAX_X - event->x4;
}
if(1 == revert_y_flag){
event->y4 = SCREEN_MAX_Y - event->y4;
}
event->touch_ID4=(s16)(buf[0x17] & 0xF0)>>4;
dprintk(DEBUG_X_Y_INFO,"touch id : %d. \n",event->touch_ID4);
case 3:
event->x3 = (s16)(buf[0x0f] & 0x0F)<<8 | (s16)buf[0x10];
event->y3 = (s16)(buf[0x11] & 0x0F)<<8 | (s16)buf[0x12];
dprintk(DEBUG_X_Y_INFO,"source data:event->x3 = %d, event->y3 = %d. \n", event->x3, event->y3);
if(1 == exchange_x_y_flag){
swap(event->x3, event->y3);
}
if(1 == revert_x_flag){
event->x3 = SCREEN_MAX_X - event->x3;
}
if(1 == revert_y_flag){
event->y3 = SCREEN_MAX_Y - event->y3;
}
event->touch_ID3=(s16)(buf[0x11] & 0xF0)>>4;
dprintk(DEBUG_X_Y_INFO,"touch id : %d. \n",event->touch_ID3);
case 2:
event->x2 = (s16)(buf[9] & 0x0F)<<8 | (s16)buf[10];
event->y2 = (s16)(buf[11] & 0x0F)<<8 | (s16)buf[12];
dprintk(DEBUG_X_Y_INFO,"source data:event->x2 = %d, event->y2 = %d. \n", event->x2, event->y2);
if(1 == exchange_x_y_flag){
swap(event->x2, event->y2);
}
if(1 == revert_x_flag){
event->x2 = SCREEN_MAX_X - event->x2;
}
if(1 == revert_y_flag){
event->y2 = SCREEN_MAX_Y - event->y2;
}
event->touch_ID2=(s16)(buf[0x0b] & 0xF0)>>4;
dprintk(DEBUG_X_Y_INFO,"touch id : %d. \n",event->touch_ID2);
case 1:
event->x1 = (s16)(buf[3] & 0x0F)<<8 | (s16)buf[4];
event->y1 = (s16)(buf[5] & 0x0F)<<8 | (s16)buf[6];
dprintk(DEBUG_X_Y_INFO,"source data:event->x1 = %d, event->y1 = %d. \n", event->x1, event->y1);
if(1 == exchange_x_y_flag){
swap(event->x1, event->y1);
}
if(1 == revert_x_flag){
event->x1 = SCREEN_MAX_X - event->x1;
}
if(1 == revert_y_flag){
event->y1 = SCREEN_MAX_Y - event->y1;
}
event->touch_ID1=(s16)(buf[0x05] & 0xF0)>>4;
dprintk(DEBUG_X_Y_INFO,"touch id : %d. \n",event->touch_ID1);
break;
default:
return -1;
}
event->pressure = 20;
return 0;
}
#ifdef TOUCH_KEY_LIGHT_SUPPORT
static void ft5x_lighting(void)
{
ctp_key_light(1,15);
return;
}
#endif
static void ft5x_report_multitouch(void)
{
struct ft5x_ts_data *data = i2c_get_clientdata(this_client);
struct ts_event *event = &data->event;
#ifdef WILLIAM_DEBUG
printk("####%s####\n", __func__);
#endif
#ifdef TOUCH_KEY_SUPPORT
if(1 == key_tp){
return;
}
#endif
switch(event->touch_point) {
case 5:
input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, event->touch_ID5);
input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x5);
input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y5);
input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 30);
input_mt_sync(data->input_dev);
dprintk(DEBUG_X_Y_INFO,"report data:===x5 = %d,y5 = %d ====\n",event->x5,event->y5);
case 4:
input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, event->touch_ID4);
input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x4);
input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y4);
input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 30);
input_mt_sync(data->input_dev);
dprintk(DEBUG_X_Y_INFO,"report data:===x4 = %d,y4 = %d ====\n",event->x4,event->y4);
case 3:
input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, event->touch_ID3);
input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x3);
input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y3);
input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 30);
input_mt_sync(data->input_dev);
dprintk(DEBUG_X_Y_INFO,"report data:===x3 = %d,y3 = %d ====\n",event->x3,event->y3);
case 2:
input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, event->touch_ID2);
input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x2);
input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y2);
input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 30);
input_mt_sync(data->input_dev);
dprintk(DEBUG_X_Y_INFO,"report data:===x2 = %d,y2 = %d ====\n",event->x2,event->y2);
case 1:
input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, event->touch_ID1);
input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x1);
input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y1);
input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 30);
input_mt_sync(data->input_dev);
dprintk(DEBUG_X_Y_INFO,"report data:===x1 = %d,y1 = %d ====\n",event->x1,event->y1);
break;
default:
dprintk(DEBUG_X_Y_INFO,"report data:==touch_point default =\n");
break;
}
if(event->touch_point)
input_report_key(data->input_dev, BTN_TOUCH, 1);
else
input_report_key(data->input_dev, BTN_TOUCH, 0);
input_sync(data->input_dev);
return;
}
#ifndef CONFIG_FT5X0X_MULTITOUCH
static void ft5x_report_singletouch(void)
{
struct ft5x_ts_data *data = i2c_get_clientdata(this_client);
struct ts_event *event = &data->event;
if (event->touch_point == 1) {
input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x1);
input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y1);
input_report_abs(data->input_dev, ABS_PRESSURE, event->pressure);
}
dprintk(DEBUG_X_Y_INFO,"report:===x1 = %d,y1 = %d ====\n",event->x1,event->y1);
input_report_key(data->input_dev, BTN_TOUCH, 1);
input_sync(data->input_dev);
return;
}
#endif
#ifdef TOUCH_KEY_SUPPORT
static void ft5x_report_touchkey(void)
{
struct ft5x_ts_data *data = i2c_get_clientdata(this_client);
struct ts_event *event = &data->event;
#ifdef TOUCH_KEY_FOR_ANGDA
if((1==event->touch_point)&&(event->x1 > TOUCH_KEY_X_LIMIT)){
key_tp = 1;
if(event->y1 < 40){
key_val = 1;
input_report_key(data->input_dev, key_val, 1);
input_sync(data->input_dev);
dprintk(DEBUG_KEY_INFO,"===KEY 1====\n");
}else if(event->y1 < 90){
key_val = 2;
input_report_key(data->input_dev, key_val, 1);
input_sync(data->input_dev);
dprintk(DEBUG_KEY_INFO,"===KEY 2 ====\n");
}else{
key_val = 3;
input_report_key(data->input_dev, key_val, 1);
input_sync(data->input_dev);
dprintk(DEBUG_KEY_INFO,"===KEY 3====\n");
}
} else{
key_tp = 0;
}
#endif
#ifdef TOUCH_KEY_FOR_EVB13
if((1==event->touch_point)&&((event->x1 > TOUCH_KEY_LOWER_X_LIMIT)&&(event->x1<TOUCH_KEY_HIGHER_X_LIMIT))){
key_tp = 1;
if(event->y1 < 5){
key_val = 1;
input_report_key(data->input_dev, key_val, 1);
input_sync(data->input_dev);
dprintk(DEBUG_KEY_INFO,"===KEY 1====\n");
}else if((event->y1 < 45)&&(event->y1>35)){
key_val = 2;
input_report_key(data->input_dev, key_val, 1);
input_sync(data->input_dev);
dprintk(DEBUG_KEY_INFO,"===KEY 2 ====\n");
}else if((event->y1 < 75)&&(event->y1>65)){
key_val = 3;
input_report_key(data->input_dev, key_val, 1);
input_sync(data->input_dev);
dprintk(DEBUG_KEY_INFO,"===KEY 3====\n");
}else if ((event->y1 < 105)&&(event->y1>95)) {
key_val = 4;
input_report_key(data->input_dev, key_val, 1);
input_sync(data->input_dev);
dprintk(DEBUG_KEY_INFO,"===KEY 4====\n");
}
}else{
key_tp = 0;
}
#endif
#ifdef TOUCH_KEY_LIGHT_SUPPORT
ft5x_lighting();
#endif
return;
}
#endif
static void ft5x_report_value(void)
{
#ifdef TOUCH_KEY_SUPPORT
ft5x_report_touchkey();
#endif
#ifdef CONFIG_FT5X0X_MULTITOUCH
ft5x_report_multitouch();
#else /* CONFIG_FT5X0X_MULTITOUCH*/
ft5x_report_singletouch();
#endif /* CONFIG_FT5X0X_MULTITOUCH*/
return;
}
static void ft5x_ts_pen_irq_work(struct work_struct *work)
{
int ret = -1;
ret = ft5x_read_data();
if (ret == 0) {
ft5x_report_value();
}
dprintk(DEBUG_INT_INFO,"%s:ret:%d\n",__func__,ret);
}
irqreturn_t ft5x_ts_interrupt(int irq, void *dev_id)
{
struct ft5x_ts_data *ft5x_ts = (struct ft5x_ts_data *)dev_id;
dprintk(DEBUG_INT_INFO,"==========ft5x_ts TS Interrupt============\n");
queue_work(ft5x_ts->ts_workqueue, &ft5x_ts->pen_event_work);
return IRQ_HANDLED;
}
static void ft5x_resume_events (struct work_struct *work)
{
int i = 0;
int ret = 0;
ctp_wakeup(0, 20);
#ifdef CONFIG_HAS_EARLYSUSPEND
if(STANDBY_WITH_POWER_OFF != standby_level){
goto standby_with_power_on;
}
#endif
if(chip_id == 0x02 ){
#ifdef FT5X02_CONFIG_INI
if (ft5x02_Get_Param_From_Ini(FT5X02_CONFIG_NAME) >= 0)
ft5x02_Init_IC_Param(this_client);
else
printk("Get ft5x02 param from INI file failed\n");
#else
msleep(200); /*wait...*/
while(i<5){
dprintk(DEBUG_INIT,"-----------------------------------------Init ic param\r\n");
if (ft5x02_Init_IC_Param(this_client) >=0 ){
dprintk(DEBUG_INIT,"---------------------------------------get ic param\r\n");
if(ft5x02_get_ic_param(this_client) >=0)
break;
}
i++;
}
#endif
}
#ifdef CONFIG_HAS_EARLYSUSPEND
standby_with_power_on:
#endif
ret = input_set_int_enable(&(config_info.input_type), 1);
if (ret < 0)
dprintk(DEBUG_SUSPEND,"%s irq disable failed\n", __func__);
}
static int ft5x_ts_suspend(struct device *dev, pm_message_t mesg)
{
struct i2c_client *client = to_i2c_client(dev);
struct ft5x_ts_data *data = i2c_get_clientdata(client);
int ret = 0;
dprintk(DEBUG_SUSPEND,"==ft5x_ts_suspend=\n");
dprintk(DEBUG_SUSPEND,"CONFIG_PM: write FT5X0X_REG_PMODE .\n");
#ifndef CONFIG_HAS_EARLYSUSPEND
data->is_suspended = true;
#endif
if (data->is_suspended == true) {
//ft5x_ts_release();
flush_workqueue(ft5x_resume_wq);
ret = input_set_int_enable(&(config_info.input_type), 0);
if (ret < 0)
dprintk(DEBUG_SUSPEND,"%s irq disable failed\n", __func__);
cancel_work_sync(&data->pen_event_work);
flush_workqueue(data->ts_workqueue);
ft5x_set_reg(FT5X0X_REG_PMODE, PMODE_HIBERNATE);
msleep(5);
input_set_power_enable(&(config_info.input_type), 0);
}
return 0;
}
static int ft5x_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ft5x_ts_data *data = i2c_get_clientdata(client);
dprintk(DEBUG_SUSPEND,"==CONFIG_PM:ft5x_ts_resume== \n");
data->is_suspended = true;
input_set_power_enable(&(config_info.input_type), 1);
msleep(5);
queue_work(ft5x_resume_wq, &ft5x_resume_work);
return 0;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
static void ft5x_ts_early_suspend(struct early_suspend *handler)
{
int ret = 0;
struct ft5x_ts_data *data = i2c_get_clientdata(this_client);
dprintk(DEBUG_SUSPEND,"==ft5x_ts_suspend=\n");
dprintk(DEBUG_SUSPEND,"CONFIG_HAS_EARLYSUSPEND: write FT5X0X_REG_PMODE .\n");
ft5x_ts_release();
data->is_suspended = false;
flush_workqueue(ft5x_resume_wq);
ret = input_set_int_enable(&(config_info.input_type), 0);
if (ret < 0)
dprintk(DEBUG_SUSPEND,"%s irq disable failed\n", __func__);
cancel_work_sync(&data->pen_event_work);
flush_workqueue(data->ts_workqueue);
ft5x_set_reg(FT5X0X_REG_PMODE, PMODE_HIBERNATE);
msleep(5);
input_set_power_enable(&(config_info.input_type), 0);
}
static void ft5x_ts_late_resume(struct early_suspend *handler)
{
struct ft5x_ts_data *data = container_of(handler, struct ft5x_ts_data, early_suspend);
dprintk(DEBUG_SUSPEND,"==CONFIG_HAS_EARLYSUSPEND:ft5x_ts_resume== \n");
if (data->is_suspended == false) {
input_set_power_enable(&(config_info.input_type), 1);
msleep(5);
queue_work(ft5x_resume_wq, &ft5x_resume_work);
}
printk("ts->is_suspended:%d\n",data->is_suspended);
}
#endif
static void ft5x_init_events (struct work_struct *work)
{
int i = 0;
int ret;
dprintk(DEBUG_INIT,"====%s begin=====. \n", __func__);
while((chip_id == 0x00) || (chip_id == 0xa3)){
delay_ms(5);
ret = i2c_smbus_read_byte_data(this_client,0xA3);
dprintk(DEBUG_INIT,"addr:0x%x,chip_id_value:0x%x\n",this_client->addr,ret);
if((ret != 0x00) && (ret != 0xa3)) {
chip_id = ret;
break;
}
if((i++)>10) {
break;
}
}
dprintk(DEBUG_INIT,"read chip_id timers,timers=%d\n",i);
i = 0;
#ifdef CONFIG_SUPPORT_FTS_CTP_UPG
fts_ctpm_fw_upgrade_with_i_file();
#endif
if(chip_id == 0x02 ){
#ifdef FT5X02_CONFIG_INI
if (ft5x02_Get_Param_From_Ini(FT5X02_CONFIG_NAME) >= 0)
ft5x02_Init_IC_Param(this_client);
else
printk("Get ft5x02 param from INI file failed\n");
#else
msleep(1000); /*wait...*/
while(i<5){
dprintk(DEBUG_INIT,"-----------------------------------------Init ic param\r\n");
if (ft5x02_Init_IC_Param(this_client) >=0 ){
dprintk(DEBUG_INIT,"---------------------------------------get ic param\r\n");
if(ft5x02_get_ic_param(this_client) >=0)
break;
}
i++;
}
#endif
}
}
static int ft5x_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct ft5x_ts_data *ft5x_ts;
struct input_dev *input_dev;
struct device *dev;
struct i2c_dev *i2c_dev;
int err = 0;
#ifdef TOUCH_KEY_SUPPORT
int i = 0;
#endif
dprintk(DEBUG_INIT,"====%s begin=====. \n", __func__);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
err = -ENODEV;
printk("check_functionality_failed\n");
goto exit_check_functionality_failed;
}
ft5x_ts = kzalloc(sizeof(*ft5x_ts), GFP_KERNEL);
if (!ft5x_ts) {
err = -ENOMEM;
printk("alloc_data_failed\n");
goto exit_alloc_data_failed;
}
this_client = client;
i2c_set_clientdata(client, ft5x_ts);
ft5x_wq = create_singlethread_workqueue("ft5x_init");
if (ft5x_wq == NULL) {
printk("create ft5x_wq fail!\n");
return -ENOMEM;
}
queue_work(ft5x_wq, &ft5x_init_work);
INIT_WORK(&ft5x_ts->pen_event_work, ft5x_ts_pen_irq_work);
ft5x_ts->ts_workqueue = create_singlethread_workqueue(dev_name(&client->dev));
if (!ft5x_ts->ts_workqueue) {
err = -ESRCH;
printk("ts_workqueue fail!\n");
goto exit_create_singlethread;
}
input_dev = input_allocate_device();
if (!input_dev) {
err = -ENOMEM;
dev_err(&client->dev, "failed to allocate input device\n");
goto exit_input_dev_alloc_failed;
}
ft5x_ts->input_dev = input_dev;
#ifdef CONFIG_FT5X0X_MULTITOUCH
set_bit(ABS_MT_TOUCH_MAJOR, input_dev->absbit);
set_bit(ABS_MT_POSITION_X, input_dev->absbit);
set_bit(ABS_MT_POSITION_Y, input_dev->absbit);
set_bit(ABS_MT_WIDTH_MAJOR, input_dev->absbit);
#ifdef FOR_TSLIB_TEST
set_bit(BTN_TOUCH, input_dev->keybit);
#endif
input_set_abs_params(input_dev,
ABS_MT_POSITION_X, 0, SCREEN_MAX_X, 0, 0);
input_set_abs_params(input_dev,
ABS_MT_POSITION_Y, 0, SCREEN_MAX_Y, 0, 0);
input_set_abs_params(input_dev,
ABS_MT_TOUCH_MAJOR, 0, PRESS_MAX, 0, 0);
input_set_abs_params(input_dev,
ABS_MT_WIDTH_MAJOR, 0, 200, 0, 0);
input_set_abs_params(input_dev,
ABS_MT_TRACKING_ID, 0, 4, 0, 0);
#ifdef TOUCH_KEY_SUPPORT
key_tp = 0;
input_dev->evbit[0] = BIT_MASK(EV_KEY);
for (i = 1; i < TOUCH_KEY_NUMBER; i++)
set_bit(i, input_dev->keybit);
#endif
#else
set_bit(ABS_MT_POSITION_X, input_dev->absbit);
set_bit(ABS_MT_POSITION_Y, input_dev->absbit);
set_bit(ABS_PRESSURE, input_dev->absbit);
set_bit(BTN_TOUCH, input_dev->keybit);
input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, SCREEN_MAX_X, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, SCREEN_MAX_Y, 0, 0);
input_set_abs_params(input_dev,
ABS_PRESSURE, 0, PRESS_MAX, 0 , 0);
#endif
set_bit(EV_ABS, input_dev->evbit);
set_bit(EV_KEY, input_dev->evbit);
2018-12-13 10:48:25 +00:00
set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
2018-07-13 01:31:50 +00:00
input_dev->name = CTP_NAME; //dev_name(&client->dev)
err = input_register_device(input_dev);
if (err) {
dev_err(&client->dev,"ft5x_ts_probe: failed to register input device: %s\n",
dev_name(&client->dev));
goto exit_input_register_device_failed;
}
ft5x_ts->is_suspended = false;
ft5x_resume_wq = create_singlethread_workqueue("ft5x_resume");
if (ft5x_resume_wq == NULL) {
printk("create ft5x_resume_wq fail!\n");
return -ENOMEM;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
printk("==register_early_suspend =\n");
ft5x_ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
ft5x_ts->early_suspend.suspend = ft5x_ts_early_suspend;
ft5x_ts->early_suspend.resume = ft5x_ts_late_resume;
register_early_suspend(&ft5x_ts->early_suspend);
#endif
#ifdef CONFIG_FT5X0X_MULTITOUCH
dprintk(DEBUG_INIT,"CONFIG_FT5X0X_MULTITOUCH is defined. \n");
#endif
config_info.dev = &(ft5x_ts->input_dev->dev);
err = input_request_int(&(config_info.input_type), ft5x_ts_interrupt,
CTP_IRQ_MODE, ft5x_ts);
if (err) {
pr_info( "goodix_probe: request irq failed\n");
goto exit_irq_request_failed;
}
i2c_dev = get_free_i2c_dev(client->adapter);
if (IS_ERR(i2c_dev)){
err = PTR_ERR(i2c_dev);
printk("i2c_dev fail!");
return err;
}
dev = device_create(i2c_dev_class, &client->adapter->dev, MKDEV(I2C_MAJOR,client->adapter->nr),
NULL, "aw_i2c_ts%d", client->adapter->nr);
if (IS_ERR(dev)) {
err = PTR_ERR(dev);
printk("dev fail!\n");
return err;
}
device_enable_async_suspend(&client->dev);
dprintk(DEBUG_INIT,"==%s over =\n", __func__);
return 0;
exit_irq_request_failed:
cancel_work_sync(&ft5x_resume_work);
destroy_workqueue(ft5x_resume_wq);
exit_input_register_device_failed:
input_free_device(input_dev);
exit_input_dev_alloc_failed:
input_free_int(&(config_info.input_type), ft5x_ts);
i2c_set_clientdata(client, NULL);
cancel_work_sync(&ft5x_ts->pen_event_work);
destroy_workqueue(ft5x_ts->ts_workqueue);
exit_create_singlethread:
kfree(ft5x_ts);
exit_alloc_data_failed:
exit_check_functionality_failed:
cancel_work_sync(&ft5x_init_work);
destroy_workqueue(ft5x_wq);
return err;
}
static int ft5x_ts_remove(struct i2c_client *client)
{
struct ft5x_ts_data *ft5x_ts = i2c_get_clientdata(client);
ft5x_set_reg(FT5X0X_REG_PMODE, PMODE_HIBERNATE);
printk("==ft5x_ts_remove=\n");
device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR,client->adapter->nr));
input_free_int(&(config_info.input_type), ft5x_ts);
#ifdef CONFIG_HAS_EARLYSUSPEND
unregister_early_suspend(&ft5x_ts->early_suspend);
#endif
cancel_work_sync(&ft5x_resume_work);
destroy_workqueue(ft5x_resume_wq);
input_unregister_device(ft5x_ts->input_dev);
input_free_device(ft5x_ts->input_dev);
cancel_work_sync(&ft5x_ts->pen_event_work);
destroy_workqueue(ft5x_ts->ts_workqueue);
input_set_power_enable(&(config_info.input_type), 0);
kfree(ft5x_ts);
i2c_set_clientdata(this_client, NULL);
return 0;
}
static const struct i2c_device_id ft5x_ts_id[] = {
{ CTP_NAME, 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, ft5x_ts_id);
static struct i2c_driver ft5x_ts_driver = {
.class = I2C_CLASS_HWMON,
.probe = ft5x_ts_probe,
.remove = ft5x_ts_remove,
.id_table = ft5x_ts_id,
.driver = {
.name = CTP_NAME,
.owner = THIS_MODULE,
.suspend = ft5x_ts_suspend,
.resume = ft5x_ts_resume,
},
.address_list = normal_i2c,
};
static int aw_open(struct inode *inode, struct file *file)
{
int subminor;
struct i2c_client *client;
struct i2c_adapter *adapter;
struct i2c_dev *i2c_dev;
printk("====%s======.\n", __func__);
dprintk(DEBUG_OTHERS_INFO,"enter aw_open function\n");
subminor = iminor(inode);
dprintk(DEBUG_OTHERS_INFO,"subminor=%d\n",subminor);
i2c_dev = i2c_dev_get_by_minor(2);
if (!i2c_dev) {
printk("error i2c_dev\n");
return -ENODEV;
}
adapter = i2c_get_adapter(i2c_dev->adap->nr);
if (!adapter) {
return -ENODEV;
}
client = kzalloc(sizeof(*client), GFP_KERNEL);
if (!client) {
i2c_put_adapter(adapter);
return -ENOMEM;
}
snprintf(client->name, I2C_NAME_SIZE, "pctp_i2c_ts%d", adapter->nr);
//client->driver = &ft5x_ts_driver;
client->adapter = adapter;
file->private_data = client;
return 0;
}
static long aw_ioctl(struct file *file, unsigned int cmd,unsigned long arg )
{
dprintk(DEBUG_OTHERS_INFO,"====%s====\n",__func__);
dprintk(DEBUG_OTHERS_INFO,"line :%d,cmd = %d,arg = %ld.\n",__LINE__,cmd,arg);
switch (cmd) {
case UPGRADE:
dprintk(DEBUG_OTHERS_INFO,"==UPGRADE_WORK=\n");
fts_ctpm_fw_upgrade_with_i_file();
// calibrate();
break;
default:
break;
}
return 0;
}
static int aw_release (struct inode *inode, struct file *file)
{
struct i2c_client *client = file->private_data;
dprintk(DEBUG_OTHERS_INFO,"enter aw_release function.\n");
i2c_put_adapter(client->adapter);
kfree(client);
file->private_data = NULL;
return 0;
}
static const struct file_operations aw_i2c_ts_fops ={
.owner = THIS_MODULE,
.open = aw_open,
.unlocked_ioctl = aw_ioctl,
.release = aw_release,
};
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 config error!\n",__func__);
return 0;
}
return 1;
}
static int __init ft5x_ts_init(void)
{
int ret = -1;
dprintk(DEBUG_INIT,"***************************init begin*************************************\n");
#ifdef WILLIAM_DEBUG
printk("####%s start####\n", __func__);
#endif
if (input_sensor_startup(&(config_info.input_type))) {
printk("%s: ctp_fetch_sysconfig_para err.\n", __func__);
return 0;
} else {
ret = input_sensor_init(&(config_info.input_type));
if (0 != ret) {
printk("%s:ctp_ops.init_platform_resource err. \n", __func__);
}
}
if(config_info.ctp_used == 0){
printk("*** ctp_used set to 0 !\n");
printk("*** if use ctp,please put the sys_config.fex ctp_used set to 1. \n");
return 0;
}
if(!ctp_get_system_config()){
printk("%s:read config fail!\n",__func__);
return ret;
}
input_set_power_enable(&(config_info.input_type), 1);
msleep(10);
ctp_wakeup(0, 10);
ft5x_ts_driver.detect = ctp_detect;
ret= register_chrdev(I2C_MAJOR,"aw_i2c_ts",&aw_i2c_ts_fops );
if(ret) {
printk("%s:register chrdev failed\n",__FILE__);
return ret;
}
i2c_dev_class = class_create(THIS_MODULE,"aw_i2c_dev");
if (IS_ERR(i2c_dev_class)) {
ret = PTR_ERR(i2c_dev_class);
class_destroy(i2c_dev_class);
}
ret = i2c_add_driver(&ft5x_ts_driver);
dprintk(DEBUG_INIT,"****************************init end************************************\n");
#ifdef WILLIAM_DEBUG
printk("####%s end####\n", __func__);
#endif
return ret;
}
static void __exit ft5x_ts_exit(void)
{
printk("==ft5x_ts_exit==\n");
i2c_del_driver(&ft5x_ts_driver);
class_destroy(i2c_dev_class);
unregister_chrdev(I2C_MAJOR, "aw_i2c_ts");
input_sensor_free(&(config_info.input_type));
}
late_initcall(ft5x_ts_init);
module_exit(ft5x_ts_exit);
MODULE_AUTHOR("<wenfs@Focaltech-systems.com>");
MODULE_DESCRIPTION("FocalTech ft5x TouchScreen driver");
MODULE_LICENSE("GPL");