下面是源文件
/*
* drivers/input/touchscreen/ft5x0x_ts.c
*
* FocalTech ft5x0x 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.
*
* VERSION DATE AUTHOR Note
* 1.0 2010-01-05 WenFS only support mulititouch Wenfs 2010-10-01
* 2.0 2011-09-05 Duxx Add touch key, and project setting update, auto CLB command
* 3.0 2013-03-11 EasyWave Porting to linux2.6.17.14 version
*
*/
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <asm/uaccess.h>
#include <linux/version.h> // new v1.3
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/input/mt.h>
#include <linux/input/edt-ft5x06.h>
#include <mach/mfp.h>
#include "ft5x06_ts.h"
#ifdef CONFIG_TOUCH_VKBD
#include <linux/netfilter_ipv4.h>
#endif
#define DEBUG 1
#define DEBUG_0 1
#ifdef DEBUG_0
#define TS_DEBUG(fmt,args...) printk(fmt, ##args )
#else
#define TS_DEBUG(fmt,args...)
#endif
#ifdef DEBUG
#define TS_DEBUG1(fmt,args...) printk(fmt, ##args )
#else
#define TS_DEBUG1(fmt,args...)
#endif
/*
*****************************************************************************
*
* I2C Driver Interface
*
*****************************************************************************
*/
static struct i2c_client *this_client;
//static struct mutex touchlock;
struct ts_event {
u16 au16_x[CFG_MAX_TOUCH_POINTS]; //x coordinate
u16 au16_y[CFG_MAX_TOUCH_POINTS]; //y coordinate
u8 au8_touch_event[CFG_MAX_TOUCH_POINTS]; //touch event: 0 -- down; 1-- contact; 2 -- contact
u8 au8_finger_id[CFG_MAX_TOUCH_POINTS]; //touch ID
u16 pressure;
u8 touch_point;
};
struct ft5x0x_ts_data {
struct input_dev *input_dev;
struct ts_event event;
struct work_struct pen_event_work;
struct workqueue_struct *ts_workqueue;
//struct early_suspend early_suspend;
};
#ifdef CONFIG_TOUCH_VKBD
static int ts_keycode[CFG_NUMOFKEYS]=
{
/*{ "Esc",*/KEY_ESC,
/*{ "`",*/KEY_GRAVE /*}*/,
/*{ "1", */KEY_1 /*}*/,
/*{ "2",*/KEY_2 /*}*/,
/*{ "3",*/KEY_3 /*}*/,
/*{ "4", */KEY_4 /*}*/,
/*{ "5", */KEY_5 /*}*/,
/*{ "6", */KEY_6 /*}*/,
/*{ "7", */KEY_7 /*}*/,
/*{ "8", */KEY_8 /*}*/,
/*{ "9", */KEY_9 /*}*/,
/*{ "0", */KEY_0 /*}*/,
/*{ "-", */KEY_MINUS /*}*/,
/*{ "=", */KEY_EQUAL /*}*/,
/*{ "[", */KEY_LEFTBRACE /*}*/,
/*{ "]", */KEY_RIGHTBRACE /*}*/,
/*{ "\\",*/KEY_BACKSLASH /*}*/,
/*{ ";", */KEY_SEMICOLON /*}*/,
/*{ "'", */KEY_APOSTROPHE /*}*/,
/*{ ",", */KEY_COMMA /*}*/,
/*{ ".", */KEY_DOT /*}*/,
/*{ "/", */KEY_SLASH /*}*/,
/*{ "Space",*/KEY_SPACE /*}*/,
/*{ "Tab", */KEY_TAB /*}*/,
/*{ "Ins", */KEY_INSERT /*}*/,
/*{ "Bs", */KEY_BACKSPACE /* }*/,
/*{ "Enter", */KEY_ENTER /*}*/,
/*{ "Next", */KEY_UNKNOWN/*}*/
};
struct Keyboard keyboard= {0,0, {
{ "Esc",},
{ "`",},
{ "1",},
{ "2",},
{ "3",},
{ "4",},
{ "5",},
{ "6",},
{ "7",},
{ "8",},
{ "9",},
{ "0",},
{ "-",},
{ "=",},
{ "[",},
{ "]",},
{ "\\",},
{ ";",},
{ "'",},
{ ",",},
{ ".",},
{ "/",},
{ "Space",},
{ "Tab",},
{ "Ins",},
{ "Bs",},
{ "Enter",},
{ "Next",}}
};
#endif
/***********************************************************************************************
Name : ft5x0x_i2c_rxdata
Input : *rxdata
*length
Output : ret
function :
***********************************************************************************************/
static int ft5x0x_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("%s i2c read error: %d\n", __func__, ret);
return ret;
}
/***********************************************************************************************
Name : ft5x0x_read_reg
Input : addr
pdata
Output :
function : read register of ft5x0x
***********************************************************************************************/
static int ft5x0x_read_reg(u8 addr, u8 *pdata) {
int ret;
u8 buf[2];
struct i2c_msg msgs[2];
buf[0] = addr; //register address
msgs[0].addr = this_client->addr;
msgs[0].flags = 0;
msgs[0].len = 1;
msgs[0].buf = buf;
msgs[1].addr = this_client->addr;
msgs[1].flags = I2C_M_RD;
msgs[1].len = 1;
msgs[1].buf = buf;
ret = i2c_transfer(this_client->adapter, msgs, 2);
if (ret < 0)
printk("msg %s i2c read error: %d\n", __func__, ret);
else
*pdata = buf[0];
return ret;
}
/***********************************************************************************************
Name : ft5x0x_read_fw_ver
Input : void
Output : firmware version
function : read TP firmware version
***********************************************************************************************/
static unsigned char ft5x0x_read_fw_ver(void) {
unsigned char ver = 0;
ft5x0x_read_reg(FT5X0X_REG_FIRMID, &ver);
return (ver);
}
#if CFG_SUPPORT_AUTO_UPG //upgrade related
/***********************************************************************************************
Name :
Input :
Output :
function :
***********************************************************************************************/
static int ft5x0x_i2c_txdata(char *txdata, int length)
{
int ret;
struct i2c_msg msg[] = {
{
.addr = this_client->addr,
.flags = 0,
.len = length,
.buf = txdata,
},
};
ret = i2c_transfer(this_client->adapter, msg, 1);
if (ret < 0)
printk("%s i2c write error: %d\n", __func__, ret);
return ret;
}
/***********************************************************************************************
Name : ft5x0x_write_reg
Input : addr -- address
para -- parameter
Output :
function : write register of ft5x0x
***********************************************************************************************/
static int ft5x0x_write_reg(u8 addr, u8 para)
{
u8 buf[3];
int ret = -1;
buf[0] = addr;
buf[1] = para;
ret = ft5x0x_i2c_txdata(buf, 2);
if (ret < 0) {
printk("write reg failed! %#x ret: %d", buf[0], ret);
return -1;
}
return 0;
}
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
typedef struct _FTS_CTP_PROJECT_SETTING_T
{
unsigned char uc_i2C_addr; //I2C slave address (8 bit address)
unsigned char uc_io_voltage;//IO Voltage 0---3.3v; 1----1.8v
unsigned char uc_panel_factory_id;//TP panel factory ID
}FTS_CTP_PROJECT_SETTING_T;
#define FTS_NULL 0x00
#define FTS_TRUE 0x01
#define FTS_FALSE 0x00
#define I2C_CTPM_ADDRESS 0x70
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;
*/
FTS_BOOL i2c_read_interface(FTS_BYTE bt_ctpm_addr, FTS_BYTE* pbt_buf, FTS_DWRD dw_lenth)
{
int ret;
ret = i2c_master_recv(this_client, pbt_buf, dw_lenth);
if(ret<=0) {
printk("[FTS]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;
*/
FTS_BOOL i2c_write_interface(FTS_BYTE bt_ctpm_addr, FTS_BYTE* pbt_buf, FTS_DWRD dw_lenth)
{
int ret;
ret = i2c_master_send(this_client, pbt_buf, dw_lenth);
if(ret<=0) {
printk("[FTS]i2c_write_interface error line = %d, ret = %d\n", __LINE__, ret);
return FTS_FALSE;
}
return FTS_TRUE;
}
/*
[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;
*/
FTS_BOOL cmd_write(FTS_BYTE btcmd,FTS_BYTE btPara1,FTS_BYTE btPara2,FTS_BYTE btPara3,FTS_BYTE 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);
}
/*
[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;
*/
FTS_BOOL byte_write(FTS_BYTE* pbt_buf, FTS_DWRD 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;
*/
FTS_BOOL byte_read(FTS_BYTE* pbt_buf, FTS_BYTE bt_len)
{
return i2c_read_interface(I2C_CTPM_ADDRESS, pbt_buf, bt_len);
}
/*
[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
static unsigned char CTPM_FW[]= {
#include "ft_app.i"
};
E_UPGRADE_ERR_TYPE fts_ctpm_fw_upgrade(FTS_BYTE* pbt_buf, FTS_DWRD dw_lenth)
{
FTS_BYTE reg_val[2] = {0};
FTS_DWRD i = 0;
FTS_DWRD packet_number;
FTS_DWRD j;
FTS_DWRD temp;
FTS_DWRD lenght;
FTS_BYTE packet_buf[FTS_PACKET_LENGTH + 6];
FTS_BYTE auc_i2c_write_buf[10];
FTS_BYTE bt_ecc;
int i_ret;
/*********Step 1:Reset CTPM *****/
/*write 0xaa to register 0xfc*/
ft5x0x_write_reg(0xfc,0xaa);
delay_qt_ms(50);
/*write 0x55 to register 0xfc*/
ft5x0x_write_reg(0xfc,0x55);
TS_DEBUG("[FTS] Step 1: Reset CTPM test\n");
delay_qt_ms(30);
/*********Step 2:Enter upgrade mode *****/
auc_i2c_write_buf[0] = 0x55;
auc_i2c_write_buf[1] = 0xaa;
do {
i ++;
i_ret = ft5x0x_i2c_txdata(auc_i2c_write_buf, 2);
delay_qt_ms(5);
}while(i_ret <= 0 && i < 5 );
/*********Step 3:check READ-ID***********************/
cmd_write(0x90,0x00,0x00,0x00,4);
byte_read(reg_val,2);
if (reg_val[0] == 0x79 && reg_val[1] == 0x3) {
printk("[FTS] Step 3: CTPM ID,ID1 = 0x%x,ID2 = 0x%x\n",reg_val[0],reg_val[1]);
} else {
return ERR_READID;
//i_is_new_protocol = 1;
}
cmd_write(0xcd,0x0,0x00,0x00,1);
byte_read(reg_val,1);
TS_DEBUG("[FTS] bootloader version = 0x%x\n", reg_val[0]);
/*********Step 4:erase app and panel paramenter area ********************/
cmd_write(0x61,0x00,0x00,0x00,1); //erase app area
delay_qt_ms(1500);
cmd_write(0x63,0x00,0x00,0x00,1);//erase panel parameter area
delay_qt_ms(100);
TS_DEBUG("[FTS] Step 4: erase. \n");
/*********Step 5:write firmware(FW) to ctpm flash*********/
bt_ecc = 0;
TS_DEBUG("[FTS] 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_qt_ms(FTS_PACKET_LENGTH/6 + 1);
if ((j * FTS_PACKET_LENGTH % 1024) == 0) {
TS_DEBUG("[FTS] 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_qt_ms(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_qt_ms(20);
}
/*********Step 6: read out checksum***********************/
/*send the opration head*/
cmd_write(0xcc,0x00,0x00,0x00,1);
byte_read(reg_val,1);
TS_DEBUG("[FTS] Step 6: ecc read 0x%x, new firmware 0x%x. \n", reg_val[0], bt_ecc);
if(reg_val[0] != bt_ecc) {
return ERR_ECC;
}
/*********Step 7: reset the new FW***********************/
cmd_write(0x07,0x00,0x00,0x00,1);
msleep(300); //make sure CTP startup normally
return ERR_OK;
}
int fts_ctpm_auto_clb(void)
{
unsigned char uc_temp;
unsigned char i;
TS_DEBUG("[FTS] start auto CLB.\n");
msleep(200);
ft5x0x_write_reg(0, 0x40);
delay_qt_ms(100); //make sure already enter factory mode
ft5x0x_write_reg(2, 0x4);//write command to start calibration
delay_qt_ms(300);
for(i=0;i<100;i++) {
ft5x0x_read_reg(0,&uc_temp);
if ( ((uc_temp&0x70)>>4) == 0x0) { //return to normal mode, calibration finish
break;
}
delay_qt_ms(200);
printk("[FTS] waiting calibration %d\n",i);
}
TS_DEBUG("[FTS] calibration OK.\n");
msleep(300);
ft5x0x_write_reg(0, 0x40); //goto factory mode
delay_qt_ms(100);//make sure already enter factory mode
ft5x0x_write_reg(2, 0x5);//store CLB result
delay_qt_ms(300);
ft5x0x_write_reg(0, 0x0);//return to normal mode
msleep(300);
TS_DEBUG("[FTS] store CLB result OK.\n");
return 0;
}
int fts_ctpm_fw_upgrade_with_i_file(void)
{
FTS_BYTE* pbt_buf = FTS_NULL;
int i_ret;
//=========FW upgrade========================*/
pbt_buf = CTPM_FW;
/*call the upgrade function*/
i_ret = fts_ctpm_fw_upgrade(pbt_buf,sizeof(CTPM_FW));
if (i_ret != 0) {
TS_DEBUG("[FTS] upgrade failed i_ret = %d.\n", i_ret);
//error handling ...
//TBD
} else {
TS_DEBUG("[FTS] upgrade successfully.\n");
fts_ctpm_auto_clb(); //start auto CLB
fts_ctpm_auto_clb();//start auto CLB
}
return i_ret;
}
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
}
}
#define FTS_SETTING_BUF_LEN 128
//update project setting
//only update these settings for COB project, or for some special case
int fts_ctpm_update_project_setting(void)
{
unsigned char uc_i2c_addr; //I2C slave address (8 bit address)
unsigned char uc_io_voltage;//IO Voltage 0---3.3v; 1----1.8v
unsigned char uc_panel_factory_id;//TP panel factory ID
unsigned char buf[FTS_SETTING_BUF_LEN];
FTS_BYTE reg_val[2] = {0};
FTS_BYTE auc_i2c_write_buf[10];
FTS_BYTE packet_buf[FTS_SETTING_BUF_LEN + 6];
FTS_DWRD i = 0;
int i_ret;
uc_i2c_addr = 0x70;
uc_io_voltage = 0x0;
uc_panel_factory_id = 0x5a;
/*********Step 1:Reset CTPM *****/
/*write 0xaa to register 0xfc*/
ft5x0x_write_reg(0xfc,0xaa);
delay_qt_ms(50);
/*write 0x55 to register 0xfc*/
ft5x0x_write_reg(0xfc,0x55);
printk("[FTS] Step 1: Reset CTPM test\n");
delay_qt_ms(30);
/*********Step 2:Enter upgrade mode *****/
auc_i2c_write_buf[0] = 0x55;
auc_i2c_write_buf[1] = 0xaa;
do {
i ++;
i_ret = ft5x0x_i2c_txdata(auc_i2c_write_buf, 2);
delay_qt_ms(5);
}while(i_ret <= 0 && i < 5 );
/*********Step 3:check READ-ID***********************/
cmd_write(0x90,0x00,0x00,0x00,4);
byte_read(reg_val,2);
if (reg_val[0] == 0x79 && reg_val[1] == 0x3) {
TS_DEBUG("[FTS] Step 3: CTPM ID,ID1 = 0x%x,ID2 = 0x%x\n",reg_val[0],reg_val[1]);
} else {
return ERR_READID;
}
cmd_write(0xcd,0x0,0x00,0x00,1);
byte_read(reg_val,1);
TS_DEBUG("bootloader version = 0x%x\n", reg_val[0]);
/* --------- read current project setting ---------- */
//set read start address
buf[0] = 0x3;
buf[1] = 0x0;
buf[2] = 0x78;
buf[3] = 0x0;
byte_write(buf, 4);
byte_read(buf, FTS_SETTING_BUF_LEN);
TS_DEBUG("[FTS] old setting: uc_i2c_addr = 0x%x, uc_io_voltage = %d, uc_panel_factory_id = 0x%x\n",
buf[0], buf[2], buf[4]);
for (i = 0; i < FTS_SETTING_BUF_LEN; i++)
{
if (i % 16 == 0) printk("\n");
printk("0x%x, ", buf[i]);
}
printk("\n");
/*--------- Step 4:erase project setting --------------*/
cmd_write(0x62,0x00,0x00,0x00,1);
delay_qt_ms(100);
/*---------- Set new settings ------------------------*/
buf[0] = uc_i2c_addr;
buf[1] = ~uc_i2c_addr;
buf[2] = uc_io_voltage;
buf[3] = ~uc_io_voltage;
buf[4] = uc_panel_factory_id;
buf[5] = ~uc_panel_factory_id;
packet_buf[0] = 0xbf;
packet_buf[1] = 0x00;
packet_buf[2] = 0x78;
packet_buf[3] = 0x0;
packet_buf[4] = 0;
packet_buf[5] = FTS_SETTING_BUF_LEN;
for (i = 0; i < FTS_SETTING_BUF_LEN; i++)
{
packet_buf[6 + i] = buf[i];
if (i % 16 == 0) TS_DEBUG("\n");
TS_DEBUG("0x%x, ", buf[i]);
}
TS_DEBUG("\n");
byte_write(&packet_buf[0],FTS_SETTING_BUF_LEN + 6);
delay_qt_ms(100);
/********* reset the new FW**************************/
cmd_write(0x07,0x00,0x00,0x00,1);
msleep(200);
return 0;
}
int fts_ctpm_auto_upg(void)
{
unsigned char uc_host_fm_ver;
unsigned char uc_tp_fm_ver;
int i_ret;
uc_tp_fm_ver = ft5x0x_read_fw_ver();
uc_host_fm_ver = fts_ctpm_get_i_file_ver();
if ( uc_tp_fm_ver == 0xa6 || //the firmware in touch panel maybe corrupted
uc_tp_fm_ver < uc_host_fm_ver//the firmware in host flash is new, need upgrade
) {
msleep(100);
TS_DEBUG("[FTS] uc_tp_fm_ver = 0x%x, uc_host_fm_ver = 0x%x\n", uc_tp_fm_ver, uc_host_fm_ver);
i_ret = fts_ctpm_fw_upgrade_with_i_file();
if (i_ret == 0) {
msleep(300);
uc_host_fm_ver = fts_ctpm_get_i_file_ver();
TS_DEBUG("[FTS] upgrade to new version 0x%x\n", uc_host_fm_ver);
} else {
TS_DEBUG("[FTS] upgrade failed ret=%d.\n", i_ret);
}
}
return 0;
}
#endif
/***********************************************************************************************
Name :
Input :
Output :
function :
***********************************************************************************************/
static void ft5x0x_ts_release(void) {
struct ft5x0x_ts_data *data = i2c_get_clientdata(this_client);
#ifdef CONFIG_FT5X0X_MULTITOUCH
input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, 0);
#else
input_report_abs(data->input_dev, ABS_PRESSURE, 0);
#endif
input_sync(data->input_dev);
}
//read touch point information
static int ft5x0x_read_data(void) {
struct ft5x0x_ts_data *data = i2c_get_clientdata(this_client);
struct ts_event *event = &data->event;
u8 buf[CFG_POINT_READ_BUF] = { 0 };
int ret = -1;
int i;
ret = ft5x0x_i2c_rxdata(buf, CFG_POINT_READ_BUF);
if (ret < 0) {
TS_DEBUG("%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;
if (event->touch_point == 0) {
ft5x0x_ts_release();
return -1;
}
if (event->touch_point > CFG_MAX_TOUCH_POINTS) {
event->touch_point = CFG_MAX_TOUCH_POINTS;
}
for (i = 0; i < event->touch_point; i++) {
event->au8_touch_event[i] = buf[3 + 6 * i] >> 6;
event->au16_x[i] = (s16) (buf[3 + 6 * i] & 0x0F) << 8
| (s16) buf[4 + 6 * i];
event->au8_finger_id[i] = (buf[5 + 6 * i]) >> 4;
event->au16_y[i] = (s16) (buf[5 + 6 * i] & 0x0F) << 8
| (s16) buf[6 + 6 * i];
event->au16_y[i] = SCREEN_MAX_Y - event->au16_y[i]; // switch y
TS_DEBUG("event:%d,x:%d,y:%d,finger id:%d\n", event->au8_touch_event[i],
event->au16_x[i], event->au16_y[i], event->au8_finger_id[i]);
}
event->pressure = 200;
return 0;
}
#ifdef CONFIG_TOUCH_VKBD
#define STARTY 240
void ft5x0x_touch_init_key_postion(void)
{
int i;
for (i=0;i<CFG_NUMOFKEYS;i++)
{
keyboard.keys[i].lx=i*(480/14);
keyboard.keys[i].ly=STARTY+(i%28)*16;
keyboard.keys[i].rx=(i+1)*(480/14);
keyboard.keys[i].ry=STARTY+(i%28)*16+16;
}
}
int ft5x0x_touch_report_key(struct input_dev *dev,int x,int y,int touch_event)
{
int i;
for (i=0;i<CFG_NUMOFKEYS;i++)
{
if (keyboard.keys[i].key_status==KEY_PRESS)
{
input_report_key(dev,((int*)dev->keycode)[i],0);
keyboard.keys[i].key_status=KEY_RELEASE;
TS_DEBUG("report key %s released:%d \n",keyboard.keys[i].key_name,((int*)dev->keycode)[i]);
}
if ((x>=keyboard.keys[i].lx)&&(x<=keyboard.keys[i].rx)&&
(y>=keyboard.keys[i].ly)&&(y<=keyboard.keys[i].ry))
{
if (touch_event==0)
{
input_report_key(dev,((int*)dev->keycode)[i],1);
keyboard.keys[i].key_status=KEY_PRESS;
TS_DEBUG("report key %s pressed:%d \n",keyboard.keys[i].key_name,((int*)dev->keycode)[i]);
}
}
}
return 0;
}
#endif
/***********************************************************************************************
Name :
Input :
Output :
function :
***********************************************************************************************/
static void ft5x0x_report_value(void) {
struct ft5x0x_ts_data *data = i2c_get_clientdata(this_client);
struct ts_event *event = &data->event;
int i, uppoint, MaxY;
uppoint = 0;
#ifdef CONFIG_TOUCH_VKBD
if ( keyboard.active)
MaxY=SCREEN_Y;
else
MaxY=SCREEN_MAX_Y;
#endif
for (i = 0; i < event->touch_point; i++) {
if ((event->au16_x[i] < SCREEN_MAX_X) && (event->au16_y[i] < MaxY)) {
// LCD view area
//TS_DEBUG("event->au16_x[i]=%d,event->au16_y[i]=%d\n",event->au16_x[i],event->au16_y[i]);
#ifdef CONFIG_FT5X0X_MULTITOUCH
input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
input_report_abs(data->input_dev, ABS_MT_PRESSURE, event->pressure);
input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->au16_x[i]);
input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->au16_y[i]);
input_report_abs(data->input_dev, ABS_MT_TRACKING_ID,event->au8_finger_id[i]);
#else
input_report_abs(data->input_dev, ABS_X, event->au16_x[i]);
input_report_abs(data->input_dev, ABS_Y, event->au16_y[i]);
input_report_abs(data->input_dev, ABS_PRESSURE, event->pressure);
#endif
input_report_key(data->input_dev, BTN_TOUCH, 1); //所有手指都抬起了 发送BTN_TOUCH 抬起事件
}
#ifdef CONFIG_TOUCH_VKBD
else {
TS_DEBUG("report key:x=%d,y=%d\n",event->au16_x[i],event->au16_y[i]);
ft5x0x_touch_report_key(data->input_dev,event->au16_x[i],event->au16_y[i],event->au8_touch_event[i]);
input_report_key(data->input_dev, BTN_TOUCH, 1); //所有手指都抬起了 发送BTN_TOUCH 抬起事件
}
#endif
}
// if (event->touch_point == uppoint) {
// input_report_key(data->input_dev, BTN_TOUCH, 0); //所有手指都抬起了 发送BTN_TOUCH 抬起事件
// } else {
// input_report_key(data->input_dev, BTN_TOUCH, event->touch_point > 0); //还有手指没抬起,发送BTN_TOUCH 按下的事件
// }
input_sync(data->input_dev);
}
/***********************************************************************************************
Name :
Input :
Output :
function :
***********************************************************************************************/
static void ft5x0x_ts_pen_irq_work(struct work_struct *work) {
int ret = -1;
ret = ft5x0x_read_data();
if (ret == 0) {
ft5x0x_report_value();
}
}
/***********************************************************************************************
Name :
Input :
Output :
function :
***********************************************************************************************/
static irqreturn_t ft5x0x_ts_interrupt(int irq, void *dev_id) {
struct ft5x0x_ts_data *ft5x0x_ts = (struct ft5x0x_ts_data*) dev_id;
if (!work_pending(&ft5x0x_ts->pen_event_work)) {
queue_work(ft5x0x_ts->ts_workqueue, &ft5x0x_ts->pen_event_work);
}
return IRQ_HANDLED;
}
static int ft5x06_ts_reset(struct i2c_client *client, int reset_pin) {
int error;
if (gpio_is_valid(reset_pin)) {
/* this pulls reset down, enabling the low active reset */
error = gpio_request_one(reset_pin, GPIOF_OUT_INIT_HIGH,
"edt-ft5x06 reset");
if (error) {
dev_err(&client->dev,
"Failed to request GPIO %d as reset pin, error %d\n",
reset_pin, error);
return error;
}
gpio_set_value(reset_pin, 1);
mdelay(100);
gpio_set_value(reset_pin, 0);
mdelay(200);
gpio_set_value(reset_pin, 1);
}
return 0;
}
#ifdef CONFIG_TOUCH_VKBD
static int data_to_kernel(struct sock *sk, int cmd, void *user,
unsigned int len)
{
switch(cmd)
{
case IMP1_SET:
{
char umsg[4];
memset(umsg, 0, sizeof(char)*1);
copy_from_user(umsg, user, sizeof(char)*1);
switch(umsg[0])
{
case 0:
keyboard.active=0;
break;
case 1:
keyboard.active=1;
break;
case 3:
keyboard.currentpage=0;
break;
case 4:
keyboard.currentpage=1;
break;
}
break;
}
return 0;
}
static int data_from_kernel(struct sock *sk, int cmd, void *user, int *len)
{
switch(cmd)
{
case IMP1_GET:
{
copy_to_user(user, (char*)&keyboard, 2); //retrun active status and current page
}
break;
}
return 0;
}
static struct nf_sockopt_ops imp1_sockops =
{
.pf = PF_INET,
.set_optmin = IMP1_SET,
.set_optmax = IMP1_MAX,
.set = data_to_kernel,
.get_optmin = IMP1_GET,
.get_optmax = IMP1_MAX,
.get = data_from_kernel,
};
static int init_sockopt(void)
{
return nf_register_sockopt(&imp1_sockops);
}
static void exit_sockopt(void)
{
nf_unregister_sockopt(&imp1_sockops);
}
#endif
/***********************************************************************************************
Name :
Input :
Output :
function :
***********************************************************************************************/
static int ft5x0x_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id) {
const struct edt_ft5x06_platform_data *pdata = client->dev.platform_data;
struct ft5x0x_ts_data *ft5x0x_ts;
struct input_dev *input_dev;
int err = 0;
unsigned char i, uc_reg_value;
dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n");
if (!pdata) {
dev_err(&client->dev, "no platform data?\n");
return -EINVAL;
}
err = ft5x06_ts_reset(client, pdata->reset_pin);
if (err)
return err;
if (gpio_is_valid(pdata->irq_pin)) {
//#if 0 //GPIO interrupt
err = gpio_request_one(pdata->irq_pin,
GPIOF_IN, "edt-ft5x06 irq");
if (err) {
dev_err(&client->dev, "Failed to request GPIO %d, error %d\n",
pdata->irq_pin, err);
return err;
}
// #else
// nuc970_mfp_set_port_i(1, 0xF); //INT6
// nuc970_mfp_set_port_i(2, 0xF); //INT7
// #endif
client->irq = gpio_to_irq(pdata->irq_pin);
}
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
err = -ENODEV;
goto exit_check_functionality_failed;
}
//TS_DEBUG("==kzalloc=\n");
ft5x0x_ts = kzalloc(sizeof(struct ft5x0x_ts_data), GFP_KERNEL);
if (!ft5x0x_ts) {
err = -ENOMEM;
goto exit_alloc_data_failed;
}
INIT_WORK(&ft5x0x_ts->pen_event_work, ft5x0x_ts_pen_irq_work);
ft5x0x_ts->ts_workqueue = create_singlethread_workqueue(
dev_name(&client->dev));
if (!ft5x0x_ts->ts_workqueue) {
err = -ESRCH;
goto exit_create_singlethread;
}
err = request_irq(client->irq, ft5x0x_ts_interrupt,
IRQF_ONESHOT | IRQF_TRIGGER_FALLING, "ft5x0x_ts", ft5x0x_ts);
if (err < 0) {
dev_err(&client->dev, "client->irq: %d", client->irq);
dev_err(&client->dev, "ft5x0x_probe: request irq failed\n");
goto exit_irq_request_failed;
}
disable_irq(client->irq);
//TS_DEBUG("==input_allocate_device=\n");
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;
}
input_dev->name = "FT5x16 TouchScreen";
input_dev->id.bustype = BUS_I2C;
input_dev->phys = "input/event0";
ft5x0x_ts->input_dev = input_dev;
input_dev->name = FT5X0X_NAME;
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->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);
input_set_abs_params(input_dev, ABS_MT_PRESSURE, 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, 5, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, SCREEN_MAX_X-1, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, SCREEN_MAX_Y-1, 0, 0);
set_bit(BTN_TOUCH, input_dev->keybit);
#else
set_bit(ABS_X, input_dev->absbit);
set_bit(ABS_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_X, 0, SCREEN_MAX_X, 0, 0);
input_set_abs_params(input_dev, ABS_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);
#ifdef CONFIG_TOUCH_VKBD
dev_info(&client->dev,"Virtual keyboard initialized.\n");
ft5x0x_touch_init_key_postion();
set_bit(EV_SYN, input_dev->evbit);
input_dev->keycode=ts_keycode;
for (i=0;i<CFG_NUMOFKEYS;i++)
{
input_set_capability(input_dev,EV_KEY,((int*)input_dev->keycode)[i]);
}
#endif
err = input_register_device(input_dev);
if (err) {
dev_err(&client->dev,
"ft5x0x_ts_probe: failed to register input device: %s\n",
dev_name(&client->dev));
goto exit_input_register_device_failed;
}
msleep(150);
//TS_DEBUG("==i2c_set_clientdata=\n");
this_client = client;
i2c_set_clientdata(client, ft5x0x_ts);
//get some register information
uc_reg_value = ft5x0x_read_fw_ver();
TS_DEBUG("[FTS] Firmware version = 0x%x\n", uc_reg_value);
ft5x0x_read_reg(FT5X0X_REG_PERIODACTIVE, &uc_reg_value);
TS_DEBUG("[FTS] report rate is %dHz.\n", uc_reg_value * 10);
ft5x0x_read_reg(FT5X0X_REG_THGROUP, &uc_reg_value);
TS_DEBUG("[FTS] touch threshold is %d.\n", uc_reg_value * 4);
enable_irq(client->irq);
#ifdef CONFIG_TOUCH_VKBD
init_sockopt();
#endif
dev_info(&client->dev,
"Screen size: %dX%d initialized: IRQ pin %d ==> %d, Reset pin %d.\n",
SCREEN_MAX_X, SCREEN_MAX_Y, pdata->irq_pin, client->irq,
pdata->reset_pin);
return 0;
exit_input_register_device_failed: input_free_device(input_dev);
exit_input_dev_alloc_failed: free_irq(client->irq, ft5x0x_ts);
exit_irq_request_failed: cancel_work_sync(&ft5x0x_ts->pen_event_work);
destroy_workqueue(ft5x0x_ts->ts_workqueue);
exit_create_singlethread: i2c_set_clientdata(client, NULL);
kfree(ft5x0x_ts);
exit_alloc_data_failed: exit_check_functionality_failed: if (gpio_is_valid(
pdata->irq_pin))
gpio_free(pdata->irq_pin);
return err;
}
/***********************************************************************************************
Name :
Input :
Output :
function :
***********************************************************************************************/
static int ft5x0x_ts_remove(struct i2c_client *client) {
const struct edt_ft5x06_platform_data *pdata = dev_get_platdata(
&client->dev);
struct ft5x0x_ts_data *ft5x0x_ts = i2c_get_clientdata(client);
input_unregister_device(ft5x0x_ts->input_dev);
destroy_workqueue(ft5x0x_ts->ts_workqueue);
free_irq(client->irq, ft5x0x_ts);
i2c_set_clientdata(client, NULL);
i2c_set_clientdata(this_client, NULL); //Add by EasyWave 20130402
if (gpio_is_valid(pdata->irq_pin))
gpio_free(pdata->irq_pin);
if (gpio_is_valid(pdata->reset_pin))
gpio_free(pdata->reset_pin);
kfree(ft5x0x_ts);
#ifdef CONFIG_TOUCH_VKBD
exit_sockopt();
#endif
return 0;
}
static const struct i2c_device_id ft5x0x_ts_id[] =
{ { FT5X0X_NAME, 0x38 }, { } };
MODULE_DEVICE_TABLE(i2c, ft5x0x_ts_id);
static struct i2c_driver ft5x0x_ts_driver = { .probe = ft5x0x_ts_probe,
.remove = ft5x0x_ts_remove, .id_table = ft5x0x_ts_id, .driver = {
.name = FT5X0X_NAME, .owner = THIS_MODULE, }, };
module_i2c_driver( ft5x0x_ts_driver);
下面是h文件
#ifndef __LINUX_FT5X0X_TS_H__
#define __LINUX_FT5X0X_TS_H__
#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,17)
#define WORK_STRUCT_PENDING 0 /* if work item pending execution */
#define work_data_bits(work) ((unsigned long *)(&(work)->pending))
/**
* work_pending - Find out whether a work item is currently pending
* @work: The work item in question
*/
#define work_pending(work) \
test_bit(WORK_STRUCT_PENDING, work_data_bits(work))
#endif
/* -- dirver configure -- */
#define CFG_SUPPORT_AUTO_UPG 0
#define CFG_SUPPORT_UPDATE_PROJECT_SETTING 0
//#define CFG_SUPPORT_TOUCH_KEY 1 //touch key, HOME, SEARCH, RETURN etc
#ifdef CONFIG_FT5X0X_MULTITOUCH
#define CFG_MAX_TOUCH_POINTS 5 //2
#else
#define CFG_MAX_TOUCH_POINTS 1 //2
#endif
#define CFG_FTS_CTP_DRIVER_VERSION "2.0"
#define SCREEN_MAX_X 480
#ifdef CONFIG_TOUCH_VKBD
#define SCREEN_Y (272-32)
#endif
#define SCREEN_MAX_Y 272
#define PRESS_MAX 255
#define CFG_POINT_READ_BUF (3 + 6 * (CFG_MAX_TOUCH_POINTS))
#define FT5X0X_NAME "ft5x0x_ts"
#define KEY_PRESS 1
#define KEY_RELEASE 0
enum ft5x0x_ts_regs {
FT5X0X_REG_THGROUP = 0x80, /* touch threshold, related to sensitivity */
FT5X0X_REG_THPEAK = 0x81,
FT5X0X_REG_THCAL = 0x82,
FT5X0X_REG_THWATER = 0x83,
FT5X0X_REG_THTEMP = 0x84,
FT5X0X_REG_THDIFF = 0x85,
FT5X0X_REG_CTRL = 0x86,
FT5X0X_REG_TIMEENTERMONITOR = 0x87,
FT5X0X_REG_PERIODACTIVE = 0x88, /* report rate */
FT5X0X_REG_PERIODMONITOR = 0x89,
FT5X0X_REG_HEIGHT_B = 0x8a,
FT5X0X_REG_MAX_FRAME = 0x8b,
FT5X0X_REG_DIST_MOVE = 0x8c,
FT5X0X_REG_DIST_POINT = 0x8d,
FT5X0X_REG_FEG_FRAME = 0x8e,
FT5X0X_REG_SINGLE_CLICK_OFFSET = 0x8f,
FT5X0X_REG_DOUBLE_CLICK_TIME_MIN = 0x90,
FT5X0X_REG_SINGLE_CLICK_TIME = 0x91,
FT5X0X_REG_LEFT_RIGHT_OFFSET = 0x92,
FT5X0X_REG_UP_DOWN_OFFSET = 0x93,
FT5X0X_REG_DISTANCE_LEFT_RIGHT = 0x94,
FT5X0X_REG_DISTANCE_UP_DOWN = 0x95,
FT5X0X_REG_ZOOM_DIS_SQR = 0x96,
FT5X0X_REG_RADIAN_VALUE = 0x97,
FT5X0X_REG_MAX_X_HIGH = 0x98,
FT5X0X_REG_MAX_X_LOW = 0x99,
FT5X0X_REG_MAX_Y_HIGH = 0x9a,
FT5X0X_REG_MAX_Y_LOW = 0x9b,
FT5X0X_REG_K_X_HIGH = 0x9c,
FT5X0X_REG_K_X_LOW = 0x9d,
FT5X0X_REG_K_Y_HIGH = 0x9e,
FT5X0X_REG_K_Y_LOW = 0x9f,
FT5X0X_REG_AUTO_CLB_MODE = 0xa0,
FT5X0X_REG_LIB_VERSION_H = 0xa1,
FT5X0X_REG_LIB_VERSION_L = 0xa2,
FT5X0X_REG_CIPHER = 0xa3,
FT5X0X_REG_MODE = 0xa4,
FT5X0X_REG_PMODE = 0xa5, /* Power Consume Mode */
FT5X0X_REG_FIRMID = 0xa6, /* Firmware version */
FT5X0X_REG_STATE = 0xa7,
FT5X0X_REG_FT5201ID = 0xa8,
FT5X0X_REG_ERR = 0xa9,
FT5X0X_REG_CLB = 0xaa,
};
//FT5X0X_REG_PMODE
#define PMODE_ACTIVE 0x00
#define PMODE_MONITOR 0x01
#define PMODE_STANDBY 0x02
#define PMODE_HIBERNATE 0x03
#ifndef ABS_MT_TOUCH_MAJOR
#define ABS_MT_TOUCH_MAJOR 0x30 /* touching ellipse */
#define ABS_MT_TOUCH_MINOR 0x31 /* (omit if circular) */
#define ABS_MT_WIDTH_MAJOR 0x32 /* approaching ellipse */
#define ABS_MT_WIDTH_MINOR 0x33 /* (omit if circular) */
#define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */
#define ABS_MT_POSITION_X 0x35 /* Center X ellipse position */
#define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */
#define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */
#define ABS_MT_BLOB_ID 0x38 /* Group set of pkts as blob */
#endif /* ABS_MT_TOUCH_MAJOR */
#ifndef ABS_MT_TRACKING_ID
#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */
#endif
#ifdef CONFIG_TOUCH_VKBD
#define IMP1_OPS_BASIC 128
#define IMP1_SET IMP1_OPS_BASIC
#define IMP1_GET IMP1_OPS_BASIC
#define IMP1_MAX IMP1_OPS_BASIC+1
#define CFG_NUMOFKEYS 28
#define KEY_RELEASE 0
#define KEY_PRESS 1
struct Keys
{
char key_name[20];
int key_status;
int lx,ly,rx,ry;
};
struct Keyboard
{
unsigned char active;
unsigned char currentpage;
struct Keys keys[CFG_NUMOFKEYS];
};
#endif
#endif