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

1987 lines
54 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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);
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");