IMX6Q移植ft5x06_ts觸控式螢幕驅動
一、附上原理圖
第一張圖是開發板的觸控式螢幕原理圖,第二張是顯示屏觸控式螢幕介面原理圖。對應起來只用到了六個腳,開發板7、8腳不用管。
從開發板觸控式螢幕介面可以看到用到了i2c2_scl、i2c2_sda,RST、INT四個主要的引腳,這裡要檢視觸控式螢幕介面的GPIO_14/15對應的是RST和INT的哪個腳,具體看核心板原理圖。
首先對i2c進行分析。由於核心自帶i2c,基本不需要做修改,我們需要在板級檔案中註冊觸控式螢幕ft5x06的i2c資訊,與ft5x06.c驅動檔案匹配。程式碼如下:
static struct i2c_board_info mxc_i2c1_board_info[] __initdata = {
{
I2C_BOARD_INFO("ft5x0x_ts", 0x38),//touch screen i2c2
},
};
然後新增標頭檔案中的引腳資訊:
MX6Q_PAD_CSI0_DAT12__GPIO_5_30,//lcd touch screen INT
MX6Q_PAD_CSI0_DAT13__GPIO_5_31,//lcd touch screen rest
在板級檔案中的程式碼就寫好了,主要是配置一下兩個引腳,使之正常工作。
在ft5x06.c驅動檔案中做如下修改:
新增:
#define GPIO_TO_PIN(bank, gpio) (32 * (bank-1) + (gpio)) #define GPIO5_30 GPIO_TO_PIN(5, 30) #define GPIO5_31 GPIO_TO_PIN(5, 31) #define GPIO_INT GPIO5_30 #define GPIO_RESET GPIO5_31 #define ATTB GPIO_INT #define get_attb_value gpio_get_value #define RESETPIN_SET0 gpio_direction_output(GPIO_RESET,0) #define RESETPIN_SET1 gpio_direction_output(GPIO_RESET,1) #define RESETPIN_REQUEST gpio_request(GPIO_RESET, "GPIO_RESET") #define RESETPIN_FREE gpio_free(GPIO_RESET)
在下面用到了復位和中斷引腳,在這裡需要配置一下,也可以在板級檔案中定義,然後在驅動i程式碼中引用一下。
ft5x06.c實現程式碼如下:
/*
* drivers/input/touchscreen/ft5x06_ts.c
*
* FocalTech ft5x06 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
* 1.0 2010-01-05 WenFS
*
* note: only support mulititouch Wenfs 2010-10-01
*/
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include "ft5x06_ts.h"
#include <linux/earlysuspend.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
//#include <asm/jzsoc.h>
#include <mach/gpio.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#define GPIO_TO_PIN(bank, gpio) (32 * (bank-1) + (gpio))
#define GPIO5_30 GPIO_TO_PIN(5, 30)
#define GPIO5_31 GPIO_TO_PIN(5, 31)
#define GPIO_INT GPIO5_30
#define GPIO_RESET GPIO5_31
#define ATTB GPIO_INT
#define get_attb_value gpio_get_value
#define RESETPIN_SET0 gpio_direction_output(GPIO_RESET,0)
#define RESETPIN_SET1 gpio_direction_output(GPIO_RESET,1)
#define RESETPIN_REQUEST gpio_request(GPIO_RESET, "GPIO_RESET")
#define RESETPIN_FREE gpio_free(GPIO_RESET)
static struct i2c_client *this_client;
static struct ft5x06_ts_platform_data *pdata;
//#define CONFIG_FT5X06_MULTITOUCH 1
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;
u8 touch_point;
};
struct ft5x06_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;
};
/***********************************************************************************************
Name : ft5x06_i2c_rxdata
Input : *rxdata
*length
Output : ret
function :
***********************************************************************************************/
static int ft5x06_i2c_rxdata(char *rxdata, int length)
{
int ret;
printk("========ft5x06_i2c_rxdata========\n");
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,
},
};
//msleep(1);
ret = i2c_transfer(this_client->adapter, msgs, 2);
if (ret < 0)
pr_err("msg %s i2c read error: %d\n", __func__, ret);
return ret;
}
/***********************************************************************************************
Name :
Input :
Output :
function :
***********************************************************************************************/
static int ft5x06_i2c_txdata(char *txdata, int length)
{
//printk("Step 2\n");
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;
}
/***********************************************************************************************
Name : ft5x06_write_reg
Input : addr -- address
para -- parameter
Output :
function : write register of ft5x06
***********************************************************************************************/
static int ft5x06_write_reg(u8 addr, u8 para)
{
//printk("Step 3\n");
u8 buf[3];
int ret = -1;
buf[0] = addr;
buf[1] = para;
ret = ft5x06_i2c_txdata(buf, 2);
if (ret < 0) {
pr_err("write reg failed! %#x ret: %d", buf[0], ret);
return -1;
}
return 0;
}
/***********************************************************************************************
Name : ft5x06_read_reg
Input : addr
pdata
Output :
function : read register of ft5x06
***********************************************************************************************/
static int ft5x06_read_reg(u8 addr, u8 *pdata)
{
//printk("Step 4\n");
int ret;
u8 buf[2] = {0};
buf[0] = addr;
struct i2c_msg msgs[] = {
{
.addr = this_client->addr,
.flags = 0,
.len = 1,
.buf = buf,
},
{
.addr = this_client->addr,
.flags = I2C_M_RD,
.len = 1,
.buf = buf,
},
};
//msleep(1);
ret = i2c_transfer(this_client->adapter, msgs, 2);
if (ret < 0)
pr_err("msg %s i2c read error: %d\n", __func__, ret);
*pdata = buf[0];
return ret;
}
/***********************************************************************************************
Name : ft5x06_read_fw_ver
Input : void
Output : firmware version
function : read TP firmware version
***********************************************************************************************/
static unsigned char ft5x06_read_fw_ver(void)
{
//printk("Step 5\n");
unsigned char ver;
ft5x06_read_reg(FT5X0X_REG_FIRMID, &ver);
return(ver);
}
#define CONFIG_SUPPORT_FTS_CTP_UPG
#ifdef CONFIG_SUPPORT_FTS_CTP_UPG
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
void delay_qt_ms(unsigned long w_ms)
{
//printk("Step 6\n");
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("[TSP]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("[TSP]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[]=
{
#define FT_UPDATE_FIRMWARE_FILENAME "ft070101_app_1118.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*/
ft5x06_write_reg(0xfc,0xaa);
delay_qt_ms(50);
/*write 0x55 to register 0xfc*/
ft5x06_write_reg(0xfc,0x55);
//printk("[TSP] 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 = ft5x06_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("[TSP] 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;
}
/*********Step 4:erase app*******************************/
cmd_write(0x61,0x00,0x00,0x00,1);
delay_qt_ms(1500);
//printk("[TSP] Step 4: erase. \n");
/*********Step 5:write firmware(FW) to ctpm flash*********/
bt_ecc = 0;
//printk("[TSP] 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)
{
//printk("[TSP] 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);
//printk("[TSP] 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);
return ERR_OK;
}
int fts_ctpm_fw_upgrade_with_i_file(void)
{
//printk("Step 7\n");
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)
{
//error handling ...
//TBD
}
return i_ret;
}
unsigned char fts_ctpm_get_upg_ver(void)
{
//printk("Step 8\n");
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
}
}
#endif
/***********************************************************************************************
Name :
Input :
Output :
function :
***********************************************************************************************/
static void ft5x06_ts_release(void)
{
//printk("Step 9\n");
struct ft5x06_ts_data *data = i2c_get_clientdata(this_client);
#ifdef CONFIG_FT5X06_MULTITOUCH
input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, 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);
}
static int ft5x06_read_data(void)
{
//printk("Step 10\n");
struct ft5x06_ts_data *data = i2c_get_clientdata(this_client);
struct ts_event *event = &data->event;
// u8 buf[14] = {0};
u8 buf[32] = {0};
int ret = -1;
printk("===========ft5x0x start read data============\n");
#ifdef CONFIG_FT5X06_MULTITOUCH
// ret = ft5x06_i2c_rxdata(buf, 13);
ret = ft5x06_i2c_rxdata(buf, 31);
#else
ret = ft5x06_i2c_rxdata(buf, 7);
#endif
if (ret < 0) {
printk("%s read_data i2c_rxdata failed: %d\n", __func__, ret);
return ret;
}
memset(event, 0, sizeof(struct ts_event));
// event->touch_point = buf[2] & 0x03;// 0000 0011
event->touch_point = buf[2] & 0x07;// 000 0111
if (event->touch_point == 0) {
ft5x06_ts_release();
return 1;
}
#ifdef CONFIG_FT5X06_MULTITOUCH
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];
case 4:
event->x4 = (s16)(buf[0x15] & 0x0F)<<8 | (s16)buf[0x16];
event->y4 = (s16)(buf[0x17] & 0x0F)<<8 | (s16)buf[0x18];
case 3:
event->x3 = (s16)(buf[0x0f] & 0x0F)<<8 | (s16)buf[0x10];
event->y3 = (s16)(buf[0x11] & 0x0F)<<8 | (s16)buf[0x12];
case 2:
event->x2 = (s16)(buf[9] & 0x0F)<<8 | (s16)buf[10];
event->y2 = (s16)(buf[11] & 0x0F)<<8 | (s16)buf[12];
case 1:
event->x1 = (s16)(buf[3] & 0x0F)<<8 | (s16)buf[4];
event->y1 = (s16)(buf[5] & 0x0F)<<8 | (s16)buf[6];
break;
default:
return -1;
}
#else
if (event->touch_point == 1) {
event->x1 = (s16)(buf[3] & 0x0F)<<8 | (s16)buf[4];
event->y1 = (s16)(buf[5] & 0x0F)<<8 | (s16)buf[6];
}
#endif
event->pressure = 200;
dev_dbg(&this_client->dev, "%s: 1:%d %d 2:%d %d \n", __func__,
event->x1, event->y1, event->x2, event->y2);
////printk("%d (%d, %d), (%d, %d)\n", event->touch_point, event->x1, event->y1, event->x2, event->y2);
printk("===========ft5x0x read datav over!!============\n");
return 0;
}
/***********************************************************************************************
Name :
Input :
Output :
function :
***********************************************************************************************/
static void ft5x06_report_value(void)
{
struct ft5x06_ts_data *data = i2c_get_clientdata(this_client);
struct ts_event *event = &data->event;
u8 uVersion;
// printk("==ft5x06_report_value =\n");
#ifdef CONFIG_FT5X06_MULTITOUCH
switch(event->touch_point) {
case 5:
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, 1);
input_mt_sync(data->input_dev);
printk("===x5 = %d,y5 = %d ====\n",event->x5,event->y5);
case 4:
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, 1);
input_mt_sync(data->input_dev);
printk("===x4 = %d,y4 = %d ====\n",event->x4,event->y4);
case 3:
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, 1);
input_mt_sync(data->input_dev);
printk("===x3 = %d,y3 = %d ====\n",event->x3,event->y3);
case 2:
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, 1);
input_mt_sync(data->input_dev);
printk("===x2 = %d,y2 = %d ====\n",event->x2,event->y2);
case 1:
input_report_abs(data->input_dev, ABS_MT_SLOT, 0);
input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, 45);
//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, 1);
//input_mt_sync(data->input_dev);
input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, -1);
input_sync(data->input_dev);
//input_syn_report(data->input_dev);
printk("===x1 = %d,y1 = %d ====\n",event->x1,event->y1);
default:
printk("==touch_point default =\n");
break;
}
#else /* CONFIG_FT5X06_MULTITOUCH*/
if (event->touch_point == 1) {
// printk("===x1 = %d,y1 = %d ====\n",event->x1,event->y1);
input_report_abs(data->input_dev, ABS_X, event->x1);
input_report_abs(data->input_dev, ABS_Y, 600-event->y1);
input_report_abs(data->input_dev, ABS_PRESSURE, event->pressure);
}
input_report_key(data->input_dev, BTN_TOUCH, 1);
#endif /* CONFIG_FT5X06_MULTITOUCH*/
input_sync(data->input_dev);
dev_dbg(&this_client->dev, "%s: 1:%d %d 2:%d %d \n", __func__,
event->x1, event->y1, event->x2, event->y2);
} /*end ft5x06_report_value*/
/***********************************************************************************************
Name :
Input :
Output :
function :
***********************************************************************************************/
static void ft5x06_ts_pen_irq_work(struct work_struct *work)
{
//printk("Step 12\n");
int ret = -1;
//printk("==work 1=\n");
ret = ft5x06_read_data();
if (ret == 0) {
ft5x06_report_value();
}
else //printk("data package read error\n");
//printk("==work 2=\n");
msleep(1);
// enable_irq(this_client->irq);
// enable_irq(this_client->irq);
}
/***********************************************************************************************
Name :
Input :
Output :
function :
***********************************************************************************************/
static irqreturn_t ft5x06_ts_interrupt(int irq, void *dev_id)
{
struct ft5x06_ts_data *ft5x06_ts = dev_id;
//disable_irq_nosync_lockdep
//disable_irq_lockdep
//disable_irq_nosync_lockdep(this_client->irq);
//disable_irq(ft5x06_ts->this_client->irq);
//printk("Step 13.b\n");
////printk("Disable IRQ 2\n");
//disable_irq(190);
//disable_irq_lockdep(this_client->irq);
// //printk("==int=\n");
//printk("Step 13.c\n");
if (!work_pending(&ft5x06_ts->pen_event_work)) {
//printk("Step 13.d\n");
queue_work(ft5x06_ts->ts_workqueue, &ft5x06_ts->pen_event_work);
//printk("Step 13.e\n");
}
//printk("Step 13.f\n");
return IRQ_HANDLED;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
/***********************************************************************************************
Name :
Input :
Output :
function :
***********************************************************************************************/
static void ft5x06_ts_suspend(struct early_suspend *handler)
{
//printk("Step 14\n");
// struct ft5x06_ts_data *ts;
// ts = container_of(handler, struct ft5x06_ts_data, early_suspend);
//printk("==ft5x06_ts_suspend=\n");
// disable_irq(this_client->irq);
// disable_irq(this_client->irq);
// cancel_work_sync(&ts->pen_event_work);
// flush_workqueue(ts->ts_workqueue);
// ==set mode ==,
// ft5x06_set_reg(FT5X06_REG_PMODE, PMODE_HIBERNATE);
}
/***********************************************************************************************
Name :
Input :
Output :
function :
***********************************************************************************************/
static void ft5x06_ts_resume(struct early_suspend *handler)
{
//printk("Step 15\n");
//printk("==ft5x06_ts_resume=\n");
// wake the mode
// __gpio_as_output(GPIO_FT5X06_WAKE);
// __gpio_clear_pin(GPIO_FT5X06_WAKE); //set wake = 0,base on system
// msleep(100);
// __gpio_set_pin(GPIO_FT5X06_WAKE); //set wake = 1,base on system
// msleep(100);
// enable_irq(this_client->irq);
// enable_irq(this_client->irq);
}
#endif //CONFIG_HAS_EARLYSUSPEND
/***********************************************************************************************
Name :
Input :
Output :
function :
***********************************************************************************************/
static int
ft5x06_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
//printk("Step 16\n");
struct ft5x06_ts_data *ft5x06_ts;
struct input_dev *input_dev;
int err = 0;
unsigned char uc_reg_value;
//printk("==ft5x06_ts_probe=\n");
RESETPIN_REQUEST;
RESETPIN_SET1;
//mdelay(1000);
gpio_set_value(GPIO_RESET,0);
// printk("GPIO1_14 is %d \n ", gpio_get_value(GPIO1_14));
mdelay(50);
gpio_set_value(GPIO_RESET,1);
mdelay(100);
// printk("GPIO1_14 is %d \n ", gpio_get_value(GPIO1_14));
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
err = -ENODEV;
goto exit_check_functionality_failed;
}
//printk("==kzalloc=\n");
ft5x06_ts = kzalloc(sizeof(*ft5x06_ts), GFP_KERNEL);
if (!ft5x06_ts) {
err = -ENOMEM;
goto exit_alloc_data_failed;
}
this_client = client;
i2c_set_clientdata(client, ft5x06_ts);
INIT_WORK(&ft5x06_ts->pen_event_work, ft5x06_ts_pen_irq_work);
ft5x06_ts->ts_workqueue = create_singlethread_workqueue(dev_name(&client->dev));
if (!ft5x06_ts->ts_workqueue) {
err = -ESRCH;
goto exit_create_singlethread;
}
// pdata = client->dev.platform_data;
// if (pdata == NULL) {
// dev_err(&client->dev, "%s: platform data is null\n", __func__);
// goto exit_platform_data_null;
// }
// //printk("==request_irq=\n");
// err = request_irq(client->irq, ft5x06_ts_interrupt, IRQF_DISABLED, "ft5x06_ts", ft5x06_ts);
this_client->irq = gpio_to_irq(GPIO_INT);
if (this_client->irq < 0)
{
printk("Unable to get irq number for GPIO_NUM\n");
goto exit_irq_request_failed;
}
err = request_irq(this_client->irq, ft5x06_ts_interrupt, IRQF_TRIGGER_FALLING, "ft5x06_ts", ft5x06_ts);
if (err < 0) {
dev_err(&client->dev, "ft5x06_probe: request irq failed\n");
goto exit_irq_request_failed;
}
printk(">>>>>>>>>>>>>request_irq\n");
// __gpio_as_irq_fall_edge(pdata->intr); //
// disable_irq(this_client->irq);
//printk("Disable IRQ 1\n");
disable_irq(this_client->irq);
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;
}
// printk("==input_allocate_device=\n");
ft5x06_ts->input_dev = input_dev;
#ifdef CONFIG_FT5X06_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_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);
// printk("==> ABS_MT_POSITION_X = %x\n",ABS_MT_POSITION_X);
// printk("==> ABS_MT_POSITION_Y = %x\n",ABS_MT_POSITION_Y);
// printk("==> ABS_MT_TOUCH_MAJOR = %x\n",ABS_MT_TOUCH_MAJOR);
// printk("==> ABS_MT_WIDTH_MAJOR = %x\n",ABS_MT_WIDTH_MAJOR);
#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);
input_dev->name = FT5X0X_NAME; //dev_name(&client->dev)
err = input_register_device(input_dev);
if (err) {
dev_err(&client->dev,
"ft5x06_ts_probe: failed to register input device: %s\n",
dev_name(&client->dev));
goto exit_input_register_device_failed;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
//printk("==register_early_suspend =\n");
ft5x06_ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
ft5x06_ts->early_suspend.suspend = ft5x06_ts_suspend;
ft5x06_ts->early_suspend.resume = ft5x06_ts_resume;
register_early_suspend(&ft5x06_ts->early_suspend);
#endif
msleep(50);
//get some register information
uc_reg_value = ft5x06_read_fw_ver();
printk("[FST] Firmware version = 0x%x\n", uc_reg_value);
// fts_ctpm_fw_upgrade_with_i_file();
//wake the CTPM
// __gpio_as_output(GPIO_FT5X06_WAKE);
// __gpio_clear_pin(GPIO_FT5X06_WAKE); //set wake = 0,base on system
// msleep(100);
// __gpio_set_pin(GPIO_FT5X06_WAKE); //set wake = 1,base on system
// msleep(100);
// ft5x06_set_reg(0x88, 0x05); //5, 6,7,8
// ft5x06_set_reg(0x80, 30);
// msleep(50);
// enable_irq(this_client->irq);
enable_irq(this_client->irq);
printk("==probe over =\n");
return 0;
exit_input_register_device_failed:
input_free_device(input_dev);
exit_input_dev_alloc_failed:
// free_irq(client->irq, ft5x06_ts);
free_irq(this_client->irq, ft5x06_ts);
exit_irq_request_failed:
exit_platform_data_null:
cancel_work_sync(&ft5x06_ts->pen_event_work);
destroy_workqueue(ft5x06_ts->ts_workqueue);
exit_create_singlethread:
//printk("==singlethread error =\n");
i2c_set_clientdata(client, NULL);
kfree(ft5x06_ts);
exit_alloc_data_failed:
exit_check_functionality_failed:
return err;
}
/***********************************************************************************************
Name :
Input :
Output :
function :
***********************************************************************************************/
static int __devexit ft5x06_ts_remove(struct i2c_client *client)
{
//printk("Step 17\n");
//printk("==ft5x06_ts_remove=\n");
struct ft5x06_ts_data *ft5x06_ts = i2c_get_clientdata(client);
unregister_early_suspend(&ft5x06_ts->early_suspend);
// free_irq(client->irq, ft5x06_ts);
free_irq(this_client->irq, ft5x06_ts);
gpio_free(GPIO_RESET);
input_unregister_device(ft5x06_ts->input_dev);
kfree(ft5x06_ts);
cancel_work_sync(&ft5x06_ts->pen_event_work);
destroy_workqueue(ft5x06_ts->ts_workqueue);
i2c_set_clientdata(client, NULL);
return 0;
}
static const struct i2c_device_id ft5x06_ts_id[] = {
{ FT5X0X_NAME, 0 },{ }
};
MODULE_DEVICE_TABLE(i2c, ft5x06_ts_id);
static struct i2c_driver ft5x06_ts_driver = {
.probe = ft5x06_ts_probe,
.remove = __devexit_p(ft5x06_ts_remove),
.id_table = ft5x06_ts_id,
.driver = {
.name = FT5X0X_NAME,
.owner = THIS_MODULE,
},
};
/***********************************************************************************************
Name :
Input :
Output :
function :
***********************************************************************************************/
static int __init ft5x06_ts_init(void)
{
//printk("Step 18\n");
int ret;
printk("==ft5x06_ts_init==\n");
ret = i2c_add_driver(&ft5x06_ts_driver);
//printk("ret=%d\n",ret);
return ret;
// return i2c_add_driver(&ft5x06_ts_driver);
}
/***********************************************************************************************
Name :
Input :
Output :
function :
***********************************************************************************************/
static void __exit ft5x06_ts_exit(void)
{
//printk("Step 19\n");
//printk("==ft5x06_ts_exit==\n");
i2c_del_driver(&ft5x06_ts_driver);
}
module_init(ft5x06_ts_init);
module_exit(ft5x06_ts_exit);
MODULE_AUTHOR("< [email protected]>");
MODULE_DESCRIPTION("FocalTech ft5x06 TouchScreen driver");
MODULE_LICENSE("GPL");
如何移植驅動和測試網上都有例程,自行百度。
相關推薦
IMX6Q移植ft5x06_ts觸控式螢幕驅動
一、附上原理圖 第一張圖是開發板的觸控式螢幕原理圖,第二張是顯示屏觸控式螢幕介面原理圖。對應起來只用到了六個腳,開發板7、8腳不用管。 從開發板觸控式螢幕介面可以看到用到了i2c2_scl、i2c2_sda,RST、INT四個主要的引腳,這裡要檢視觸控式螢
Android gt911觸控式螢幕驅動移植記錄
基本上參考“GT9XX驅動移植說明書_for_Android”來做就好的,有幾點注意的地方提一下: 1、替換配置資訊表的時候,如果你的屏驅動晶片gt9xx有設定sensor ID的話,配置資訊應該配置到對應的陣列中(CTP_CFG_GROUP) 2、我的弄完後發現屏的
【TINY4412】LINUX移植筆記:(23)裝置樹LCD觸控式螢幕驅動
【TINY4412】LINUX移植筆記:(23)裝置樹 LCD觸控式螢幕驅動 宿主機 : 虛擬機器 Ubuntu 16.04 LTS / X64 目標板[底板]: Tiny4412SDK - 1506 目標板[核心板]
Qualcomm 平臺觸控式螢幕驅動移植 筆記
TP觸控式螢幕,應該是驅動開發中比較簡單並且適合新手入手的模組。不過雖然簡單,但涉及到的內容還是比較多的,其中Linux相關主要的機制: 1. input 機制 2. 中斷、定時器 3. I2C 1
基於imx6的gt911觸控式螢幕驅動移植
參考:https://blog.csdn.net/zhuyuming/article/details/52652525?locationNum=3 實驗平臺:TQ_iMX6Q 其實在Linux核心官網(https://www.kernel.org/)上下載適合自己
I.MX6Q(TQIMX6Q/TQE9)學習筆記——新版BSP之觸控式螢幕驅動移植
之所以說是驅動移植是因為之前已經在TQ210、AM335x兩個平臺上移植過了,因此,僅需要少量修改就可以將驅動移植到imx6q。下面開始觸控驅動移植。 DTS編寫 參考其它DTS的i2c裝置寫法,我們可以新增如下內容: &i2c1 { clock-frequen
IMX6Q下tlv320aic3x音訊驅動移植
原理圖: tlv320aic3x音訊晶片 功率放大器 移植分為三步: 1.codec 驅動 sound/soc/codecs/tlv320aic3x.c 2.平臺驅動 sound/soc/imx/imx-tlv320aic3x.c 3.新增板檔案 arch/a
CC2640R2F&TI-RTOS 拿到 TI CC2640R2F 開發板 第一件事就是移植串口驅動,重定向 printf
ade 默認值 hand drivers exp bin 初始化 strong simple /* * board_uart.c * * Created on: 2018年7月3日 * Author: admin */ #include "boa
Llinux-觸控式螢幕驅動(詳解)
https://www.cnblogs.com/lifexy/p/7628889.html https://forum.qt.io/topic/57756/solved-proper-configuration-of-capacitive-touchscreen-with-qt5-and-egl
linux 輸入子系統之電阻式觸控式螢幕驅動
一、輸入子系統情景回憶ING...... 在Linux中,輸入子系統是由輸入子系統裝置驅動層、輸入子系統核心層(Input Core)和輸入子系統事件處理層(Event Handler)組成。其中裝置驅動層提供對硬體各暫存器的讀寫訪問和將底層硬體對使用者輸入訪問的響應轉換為標準的輸入事件,再
十三、Linux驅動之觸控式螢幕驅動
1. 基本概念 常用的觸控式螢幕型別有兩種:阻性觸控式螢幕和容性觸控式螢幕。阻性觸控式螢幕是一種感測器,它將矩形區域中觸控點(X, Y)的物理位置轉換為代表X座標和Y座標的電壓。觸控式螢幕包含上下疊合的兩個透明層阻性材料,中間由一種彈性材料隔開。當觸控式螢幕
MT3561平臺 GT928觸控式螢幕驅動客製化觸控的開關
MT3561 開光觸控式螢幕GT928邏輯 1 . MT3561 觸控式螢幕的驅動檔案路徑: kernel-3.18/drivers/input/touchscreen/mediatek/GT928/gt9xx_driver.c 2. 需求: 提供介面控制觸
MSM8909的觸控式螢幕驅動導致的熄屏後重新亮屏速度慢的原因!
使用的匯頂的觸控驅動的時候會重新亮屏速度慢3秒,而在使用另外一個敦泰觸控驅動的時候沒有發現問題。比較程式碼後發現,fb_notifier_callback的影響是關鍵. 有問題的程式碼是: static int fb_notifier_callback(struct
電容螢幕觸控式螢幕驅動——ft5406 晶片
/*產生一個 SYN_MT_REPORT event來標記一個點的結束,告訴接收方接收當前手指的資訊並準備接收其它手指的觸控資訊*/ input_mt_sync(i2c.input_dev); #ifdef DEBUG_MSG printk(KERN_INFO "input
focaltech(敦泰)觸控式螢幕驅動Ft5306.c學習記錄
最近正在做安卓系統的驅動開發工作,學習了focaltech(敦泰)觸控式螢幕驅動Ft5306.c,簡單總結如下(未完,待續)。因為剛接觸驅動開發,許多知識沒有徹底理解,如有錯誤請指正。 1 概述 linux觸控式螢幕驅動基於linux input 子系統,層次上位於input系統的第三層,主要是完成具
修改LCD和觸控式螢幕驅動的一些經驗
硬體平臺:遠峰開發板 + 3.5寸三星液晶屏軟體平臺:winCE PB5.0 + SMDK BSP====LCD部分====解析度修改1、s2410.h (D:/WINCE500/PLATFORM/SMDK2410/INC/)#define LCD_XSIZE_TFT (64
Linux下的觸控式螢幕驅動
一.觸控式螢幕理論概述 對於觸控式螢幕驅動,我們主要需要掌握觸控式螢幕驅動程式碼和應用層測試程式碼。下面講的是基於Mini2440的觸控式螢幕驅動,現在的驅動我們都將裝置和驅動分離,掛在平臺裝置總線上,讓裝置和驅動去匹配。而我們在linu2.6.32.2核心版本中的觸控
觸控式螢幕驅動之編寫驅動程式
我們開啟我們的核心板原理圖可以看到這四根引腳分別接在xadcAIN2,3,4,5上面 搜尋發現不需要配置什麼暫存器 我們看一看晶片手冊上的觸控式螢幕那一章,我們的工作就是閱讀那一章然後弄清楚那裡面的東西就可以了 先來看一看核心自帶的觸控式螢幕驅動做了什麼事情 ts.clo
Linux晶片級移植與底層驅動(基於3.7.4核心)
1. SoC Linux底層驅動的組成和現狀 為了讓Linux在一個全新的ARM SoC上執行,需要提供大量的底層支撐,如定時器節拍、中斷控制器、SMP啟動、CPU hotplug以及底層的GPIO、clock、pinctrl和DMA硬體的封裝等。定時器
Linux晶片級移植與底層驅動(基於3.7.4核心)(GPIO&&pinctrl&&clk)
6. GPIO驅動 在drivers/gpio下實現了通用的基於gpiolib的GPIO驅動,其中定義了一個通用的用於描述底層GPIO控制器的gpio_chip結構體,並要求具體的SoC實現gpio_chip結構體的成員函式,最後透過gpiochip_add