This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM335x Starter Kit Capacitive Touch Screen

Other Parts Discussed in Thread: DA8XX

Hi,

I am trying to integrate a capacitive touch screen display - NHD-5.0-800480TF-ATXI#-CTP with the starter kit under linux.

I have successfully modified the boardconfig file to get the LCD display right. Unfortunately I am having trouble with the capacitive touch screen.

The touch controller is FT5X06 and I have found some driver files, that I hope can be adapted here.

It would be great if anyone could give me pointers in integrating this, and this could serve as a solution to others trying the same.

I have adapted  the driver file and managed to compile a new kernel image. But during the driver probe, it is unable to read anything from the touch controller.(Error -121 I2C Read Reg)

I have tried to manually detect this chip at address 0x38 using i2cdetect -r 1. With the driver not added in kernel, Nothing is detected at this address. When the driver is added, a "UU" is shown at this address.

A device is registered successfully as /devices/virtual/input/input2

I am attaching the driver files and the board config file.

Thanks a lot.

Ram

7750.ft5x06_ts.c
/* 
 * 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
 *    1.0		  2010-01-05			WenFS
 *
 * note: only support multitouch	Wenfs 2010-10-01
 */



#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/ft5x06_ts.h>

#ifdef CONFIG_HAS_EARLYSUSPEND
	#include <linux/earlysuspend.h>
#endif

#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/module.h>
//#include <asm/jzsoc.h>

static struct i2c_client *this_client;
static struct ft5x0x_ts_platform_data *pdata;

#define CONFIG_FT5X0X_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 ft5x0x_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  //CONFIG_HAS_EARLYSUSPEND
};

/***********************************************************************************************
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,
		},
	};

    //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 ft5x0x_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;
}
/***********************************************************************************************
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) {
        pr_err("write reg failed! %#x ret: %d", buf[0], ret);
        return -1;
    }
    
    return 0;
}


/***********************************************************************************************
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] = {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	:	 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;
	ft5x0x_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)
{
    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[]=
{
#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);
    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 = 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("[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)
{
   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)
{
    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 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);
	input_report_key(data->input_dev, BTN_TOUCH, 0);
#endif
	input_sync(data->input_dev);
}

static int ft5x0x_read_data(void)
{
	struct ft5x0x_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;

#ifdef CONFIG_FT5X0X_MULTITOUCH
//	ret = ft5x0x_i2c_rxdata(buf, 13);
	ret = ft5x0x_i2c_rxdata(buf, 31);
#else
    ret = ft5x0x_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) {
        ft5x0x_ts_release();
        return 1; 
    }

#ifdef CONFIG_FT5X0X_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);

    return 0;
}
/***********************************************************************************************
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;
	u8 uVersion;

//		printk("==ft5x0x_report_value =\n");
#ifdef CONFIG_FT5X0X_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("===x2 = %d,y2 = %d ====\n",event->x2,event->y2);
		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("===x2 = %d,y2 = %d ====\n",event->x2,event->y2);
		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("===x2 = %d,y2 = %d ====\n",event->x2,event->y2);
		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_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);
			printk("===x1 = %d,y1 = %d ====\n",event->x1,event->y1);

		default:
//			printk("==touch_point default =\n");
			break;
	}
#else	/* CONFIG_FT5X0X_MULTITOUCH*/
	if (event->touch_point == 1) {
		input_report_abs(data->input_dev, ABS_X, event->x1);
		input_report_abs(data->input_dev, ABS_Y, event->y1);
		input_report_abs(data->input_dev, ABS_PRESSURE, event->pressure);
	}
	input_report_key(data->input_dev, BTN_TOUCH, 1);
#endif	/* CONFIG_FT5X0X_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 ft5x0x_report_value*/
/***********************************************************************************************
Name	:	 

Input	:	
                     

Output	:	

function	:	

***********************************************************************************************/
static void ft5x0x_ts_pen_irq_work(struct work_struct *work)
{
	int ret = -1;
//	printk("==work 1=\n");
	ret = ft5x0x_read_data();	
	if (ret == 0) {	
		ft5x0x_report_value();
	}
//	else printk("data package read error\n");
//	printk("==work 2=\n");
//    	msleep(1);
    enable_irq(this_client->irq);
//	enable_irq(IRQ_EINT(6));
}
/***********************************************************************************************
Name	:	 

Input	:	
                     

Output	:	

function	:	

***********************************************************************************************/
static irqreturn_t ft5x0x_ts_interrupt(int irq, void *dev_id)
{
	struct ft5x0x_ts_data *ft5x0x_ts = dev_id;
    	disable_irq(this_client->irq);		
//	disable_irq(IRQ_EINT(6));
//	printk("==int=\n");
	if (!work_pending(&ft5x0x_ts->pen_event_work)) {
		queue_work(ft5x0x_ts->ts_workqueue, &ft5x0x_ts->pen_event_work);
	}

	return IRQ_HANDLED;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
/***********************************************************************************************
Name	:	 

Input	:	
                     

Output	:	

function	:	

***********************************************************************************************/
static void ft5x0x_ts_suspend(struct early_suspend *handler)
{
//	struct ft5x0x_ts_data *ts;
//	ts =  container_of(handler, struct ft5x0x_ts_data, early_suspend);

	printk("==ft5x0x_ts_suspend=\n");
//	disable_irq(this_client->irq);
//	disable_irq(IRQ_EINT(6));
//	cancel_work_sync(&ts->pen_event_work);
//	flush_workqueue(ts->ts_workqueue);
	// ==set mode ==, 
//    	ft5x0x_set_reg(FT5X0X_REG_PMODE, PMODE_HIBERNATE);
}
/***********************************************************************************************
Name	:	 

Input	:	
                     

Output	:	

function	:	

***********************************************************************************************/
static void ft5x0x_ts_resume(struct early_suspend *handler)
{
	printk("==ft5x0x_ts_resume=\n");
	// wake the mode
//	__gpio_as_output(GPIO_FT5X0X_WAKE);		
//	__gpio_clear_pin(GPIO_FT5X0X_WAKE);		//set wake = 0,base on system
//	 msleep(100);
//	__gpio_set_pin(GPIO_FT5X0X_WAKE);			//set wake = 1,base on system
//	msleep(100);
//	enable_irq(this_client->irq);
//	enable_irq(IRQ_EINT(6));
}
#endif  //CONFIG_HAS_EARLYSUSPEND
/***********************************************************************************************
Name	:	 

Input	:	
                     

Output	:	

function	:	

***********************************************************************************************/
static int 
ft5x0x_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	struct ft5x0x_ts_data *ft5x0x_ts;
	struct input_dev *input_dev;
	int err = 0;
	unsigned char ver = 0;
	unsigned char uc_reg_value; 
	
	printk("==ft5x0x_ts_probe=\n");
	
	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
		err = -ENODEV;
		goto exit_check_functionality_failed;
	}

	printk("==kzalloc=\n");
	ft5x0x_ts = kzalloc(sizeof(*ft5x0x_ts), GFP_KERNEL);
	if (!ft5x0x_ts)	{
		err = -ENOMEM;
		goto exit_alloc_data_failed;
	}


	this_client = client;
	i2c_set_clientdata(client, ft5x0x_ts);


	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;
	}

//	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, ft5x0x_ts_interrupt, IRQF_DISABLED, "ft5x0x_ts", ft5x0x_ts);
//	err = request_irq(IRQ_EINT(6), ft5x0x_ts_interrupt, IRQF_TRIGGER_FALLING, "ft5x0x_ts", ft5x0x_ts);
	if (err < 0) {
		dev_err(&client->dev, "ft5x0x_probe: request irq failed\n");
		goto exit_irq_request_failed;
	}

//	__gpio_as_irq_fall_edge(pdata->intr);		//
	disable_irq(this_client->irq);
//	disable_irq(IRQ_EINT(6));

//	printk("==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;
	}
	
	ft5x0x_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);

	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);
#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,
		"ft5x0x_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");
	ft5x0x_ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
	ft5x0x_ts->early_suspend.suspend = ft5x0x_ts_suspend;
	ft5x0x_ts->early_suspend.resume	= ft5x0x_ts_resume;
	register_early_suspend(&ft5x0x_ts->early_suspend);
#endif

    msleep(50);
    //get some register information
    uc_reg_value = ft5x0x_read_fw_ver();
    printk("[FST] FT55x0x Firmware version = 0x%x\n", uc_reg_value);
    uc_reg_value = ft5x0x_read_reg(FT5X0X_REG_FT5201ID, &ver);
    printk("[FST] FT55x0x FiT5201ID = 0x%x\n", uc_reg_value);
    uc_reg_value = ft5x0x_read_reg(FT5X0X_REG_ERR, &ver);
    printk("[FST] FT55x0x ERR = 0x%x\n", uc_reg_value);


//    fts_ctpm_fw_upgrade_with_i_file();


    
//wake the CTPM
//	__gpio_as_output(GPIO_FT5X0X_WAKE);		
//	__gpio_clear_pin(GPIO_FT5X0X_WAKE);		//set wake = 0,base on system
//	 msleep(100);
//	__gpio_set_pin(GPIO_FT5X0X_WAKE);			//set wake = 1,base on system
//	msleep(100);
//	ft5x0x_set_reg(0x88, 0x05); //5, 6,7,8
//	ft5x0x_set_reg(0x80, 30);
//	msleep(50);
    	enable_irq(this_client->irq);
//    enable_irq(IRQ_EINT(6));

	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, ft5x0x_ts);
//	free_irq(IRQ_EINT(6), ft5x0x_ts);
exit_irq_request_failed:
exit_platform_data_null:
	cancel_work_sync(&ft5x0x_ts->pen_event_work);
	destroy_workqueue(ft5x0x_ts->ts_workqueue);
exit_create_singlethread:
	printk("==singlethread error =\n");
	i2c_set_clientdata(client, NULL);
	kfree(ft5x0x_ts);
exit_alloc_data_failed:
exit_check_functionality_failed:
	return err;
}
/***********************************************************************************************
Name	:	 

Input	:	
                     

Output	:	

function	:	

***********************************************************************************************/
static int __devexit ft5x0x_ts_remove(struct i2c_client *client)
{
	printk("==ft5x0x_ts_remove=\n");
	struct ft5x0x_ts_data *ft5x0x_ts = i2c_get_clientdata(client);
#ifdef CONFIG_HAS_EARLYSUSPEND
	unregister_early_suspend(&ft5x0x_ts->early_suspend);
#endif
	free_irq(client->irq, ft5x0x_ts);
//	free_irq(IRQ_EINT(6), ft5x0x_ts);
	input_unregister_device(ft5x0x_ts->input_dev);
	kfree(ft5x0x_ts);
	cancel_work_sync(&ft5x0x_ts->pen_event_work);
	destroy_workqueue(ft5x0x_ts->ts_workqueue);
	i2c_set_clientdata(client, NULL);
	return 0;
}

static const struct i2c_device_id ft5x0x_ts_id[] = {
	{ FT5X0X_NAME, 0 },{ }
};


MODULE_DEVICE_TABLE(i2c, ft5x0x_ts_id);

static struct i2c_driver ft5x0x_ts_driver = {
	.probe		= ft5x0x_ts_probe,
	.remove		= __devexit_p(ft5x0x_ts_remove),
	.id_table	= ft5x0x_ts_id,
	.driver	= {
		.name	= FT5X0X_NAME,
		.owner	= THIS_MODULE,
	},
};

/***********************************************************************************************
Name	:	 

Input	:	
                     

Output	:	

function	:	

***********************************************************************************************/
static int __init ft5x0x_ts_init(void)
{
	int ret;
	printk("==ft5x0x_ts_init==\n");
	ret = i2c_add_driver(&ft5x0x_ts_driver);
	printk("ret=%d\n",ret);
	return ret;
//	return i2c_add_driver(&ft5x0x_ts_driver);
}

/***********************************************************************************************
Name	:	 

Input	:	
                     

Output	:	

function	:	

***********************************************************************************************/
static void __exit ft5x0x_ts_exit(void)
{
	printk("==ft5x0x_ts_exit==\n");
	i2c_del_driver(&ft5x0x_ts_driver);
}

module_init(ft5x0x_ts_init);
module_exit(ft5x0x_ts_exit);

MODULE_AUTHOR("<wenfs@Focaltech-systems.com>");
MODULE_DESCRIPTION("FocalTech ft5x0x TouchScreen driver");
MODULE_LICENSE("GPL");

8231.board-am335xevm.c

7357.ft5x06_ts.h

  • I am using the newhaven 5" display as well. I found the source fles for the driver posted here very helpful in probing the device to the point where I get some reaction to touches on the display.

    I still have some problems though and are not sure what to expect from the driver/device.

    I have it configured as multitouch.

    In the /dev/input directory I find the devices input0 and touchscreen (also mice and mouse0)

    Using the ts_test program, i get the following output (I added some more debug prints in the code):

    [ 19.644622] ==int=
    [ 19.646881] ==work 1=
    [ 19.660186] ==int=
    [ 19.677856] ==int=
    [ 19.694641] ==int=
    [ 20.644683] omap_i2c omap_i2c.3: controller timed out
    [ 21.660308] omap_i2c omap_i2c.3: timeout waiting for bus ready
    [ 21.666656] msg ft5x0x_i2c_rxdata i2c read error: -110
    [ 21.672180] ft5x0x_read_data read_data i2c_rxdata failed: -110
    [ 21.678436] data package read error
    [ 21.682128] ==work 2=
    [ 21.684570] ==work 1=
    [ 22.699401] omap_i2c omap_i2c.3: timeout waiting for bus ready
    [ 23.714996] omap_i2c omap_i2c.3: controller timed out
    [ 24.730621] omap_i2c omap_i2c.3: timeout waiting for bus ready
    [ 24.736938] msg ft5x0x_i2c_rxdata i2c read error: -110
    [ 24.742431] ft5x0x_read_data read_data i2c_rxdata failed: -110
    [ 24.748657] data package read error
    [ 24.752380] ==work 2=
    [ 38.632720] ==int=
    [ 38.634948] ==work 1=
    [ 38.648773] ==int=
    [ 38.665557] ==int=
    [ 39.652496] omap_i2c omap_i2c.3: timeout waiting for bus ready
    [ 39.669372] data package read error
    [ 39.673126] ==work 2=
    [ 39.673126] ==work 1=
    [ 39.673400] omap_i2c omap_i2c.3: Arbitration lost
    [ 39.673645] msg ft5x0x_i2c_rxdata i2c read error: -5
    [ 39.673645] ft5x0x_read_data read_data i2c_rxdata failed: -5
    [ 39.673675] data package read error
    [ 39.673675] ==work 2=
    tslib: Unable to grab selected input device
    [ 48.767974] ==int=

    after a while, it stops responding to touch event.

    1. Do I need to recompile tslib? 

    2. How can I determine the version of compile tslib

    3. Why this line "tslib: Unable to grab selected input device"

  • As promised, here is what I did to get this work with android.

    First off, many credits to shriram for the help and guidance.



    I can confirm this works on android WITH multi-touch and without any hardware hack!

    1) Setup your Android development environment. I did mine in VirtualBox under Ubuntu as instructed on the am335x android development guide.

    2) Add the new Capacitive screen to the PINMUX file called: "board-arm335xevm.c". It is located at: "/kernel/arch/arm/mach-omap2/"

    The best way to do so is to copy what shriram has in his file. Just add what is not currently there. The file is posted as the solution in this page.

    http://e2e.ti.com/support/arm/sitara_arm/f/791/t/255787.aspx?pi239031349=2

    My solution is attached to this message.

    3) Modify the code so it does NOT look for the 4.3 inch screen in the file in 2) by replacing following line:

    lcdc_pdata = &NHD_480272MF_ATXI_pdata;

    with

    lcdc_pdata = &TFC_S9700RTWV35TR_01B_pdata;

    This is located in the lcdc_init function in the file in 2). See the ref file for more detail. This will change the resolution to the 5.0 inch resolution as well as get the parallel pins timing correct for this graphic chip.

    4) Add the following to your Kconfig file located in "/kernel/drivers/input/touchscreen"

    config TOUCHSCREEN_FT5X06
        tristate "FocalTech ft5x06 touchscreen"
        depends on I2C
        help
          Say Y here if you want to support FT5X06 in NewHaven 5inch display
          touchscreen controller.
     
          If unsure, say N.
     
          To compile this driver as a module, choose M here: the
          module will be called ft5x06_ts.
     
    endif

    This will enable the touchscreen on your kernel xconfig menu. You will need to enable this to enable the kernel to build it.

    5) Add the following to the make file in the same folder as 4)

    obj-$(CONFIG_TOUCHSCREEN_FT5X06)    += ft5x06_ts.o

    6) Reconfigure the kernel build to with kernel. Use the following command to get to the configuration GUI:

    make ARCH=arm CROSS-COMPILE=arm-arago-linux-gnueabi- xconfig

    7) Add the solution files from shriram on page 2 "ft5x06_ts.c" to the following folder: "kernel/drivers/input/touchscreen"

    8) Insert the following to the file you added in 7) in the function ft5x0x_ts_probe. Add it after creating the workqueue but before reading the chip. See the attached file for more reference.

    err = gpio_request(GPIO_TO_PIN(2,1),FT5X0X_NAME);
        gpio_direction_output(GPIO_TO_PIN(2,1),1);
        gpio_export(GPIO_TO_PIN(2,1),true);
     
        err = gpio_request(GPIO_TO_PIN(2,0),FT5X0X_NAME);
        gpio_direction_input(GPIO_TO_PIN(2,0));
        gpio_export(GPIO_TO_PIN(2,0),true);
        ct_irq_num = gpio_to_irq(GPIO_TO_PIN(2,0));

    This will allow for the proper interrupt to occur I think...

    9) Create fake firmware file using the following command:

    touch ~/rowboat-android/kernel/drivers/input/touchscreen/ft_app.i

    Keep in mind, my upper directory is ~/rowboat-android/

    10) rebuild the kernel. follow instruction on TI's android development user's guide on how to do this for the am335x

    11) rebuild the android OS on a microSD and boot up.

    It should work and I have verified it does up to 5 points multi-touch when using the multi-touch test program.

    0458.board-am335xevm.c

    3247.ft5x06_ts.c
    /* 
     * 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
     *    1.0		  2010-01-05			WenFS
     *
     * note: only support multitouch	Wenfs 2010-10-01
     */
    
    
    
    #include <linux/i2c.h>
    #include <linux/input.h>
    
    #ifdef CONFIG_HAS_EARLYSUSPEND
    	#include <linux/earlysuspend.h>
    #endif
    
    #include <linux/interrupt.h>
    #include <linux/delay.h>
    #include <linux/slab.h>
    #include <linux/module.h>
    #include <linux/gpio.h>
    #include <linux/input/mt.h>
    #include <linux/input/ft5x06_ts.h>
    //#include <asm/jzsoc.h>
    
    static struct i2c_client *this_client;
    static struct ft5x0x_ts_platform_data *pdata;
    
    #define CONFIG_FT5X0X_MULTITOUCH 1
    
    /* Convert GPIO signal to GPIO pin number */
    #define GPIO_TO_PIN(bank, gpio) (32 * (bank) + (gpio))
    
    static int ct_irq_num;
    
    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 ft5x0x_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  //CONFIG_HAS_EARLYSUSPEND
    };
    
    /***********************************************************************************************
    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,
    		},
    	};
    
        //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 ft5x0x_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;
    }
    /***********************************************************************************************
    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) {
            pr_err("write reg failed! %#x ret: %d", buf[0], ret);
            return -1;
        }
        
        return 0;
    }
    
    
    /***********************************************************************************************
    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] = {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]; 
    
    	//Modification to add delay between two operations for clock stretching issue. --Shriram
    	/*ret = i2c_transfer(this_client->adapter, &msgs[0], 1);
    	if (ret < 0)
    		pr_err("msg %s i2c read error - write addr error: %d\n", __func__, ret);
    	ret = i2c_transfer(this_client->adapter, &msgs[1], 1);
    	if (ret < 0)
    		pr_err("msg %s i2c read error - write suc, read reg error: %d\n", __func__, ret);
    	*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;
    	ft5x0x_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)
    {
        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[]=
    {
    #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);
        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 = 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("[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)
    {
       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)
    {
        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 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);
    	input_mt_sync(data->input_dev);
    #else
    	input_report_abs(data->input_dev, ABS_PRESSURE, 0);
    #endif
    	input_report_key(data->input_dev, BTN_TOUCH, 0);
    	input_sync(data->input_dev);
    }
    
    static int ft5x0x_read_data(void)
    {
    	struct ft5x0x_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;
    
    #ifdef CONFIG_FT5X0X_MULTITOUCH
    //	ret = ft5x0x_i2c_rxdata(buf, 13);
    	ret = ft5x0x_i2c_rxdata(buf, 31);
    #else
        ret = ft5x0x_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) {
            ft5x0x_ts_release();
            return 1; 
        }
    
    #ifdef CONFIG_FT5X0X_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);
    
        return 0;
    }
    /***********************************************************************************************
    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;
    	u8 uVersion;
    
    		//printk("==ft5x0x_report_value =\n");
    #ifdef CONFIG_FT5X0X_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->x2,event->y2);
    		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->x2,event->y2);
    		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->x2,event->y2);
    		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_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);
    			//printk("===x1 = %d,y1 = %d ====\n",event->x1,event->y1);
    
    		default:
    			//printk("==touch_point default =\n");
    			break;
    	}
    #else	/* CONFIG_FT5X0X_MULTITOUCH*/
    	if (event->touch_point == 1) {
    		input_report_abs(data->input_dev, ABS_X, event->x1);
    		input_report_abs(data->input_dev, ABS_Y, event->y1);
    		input_report_abs(data->input_dev, ABS_PRESSURE, event->pressure);
    	}
    #endif	/* CONFIG_FT5X0X_MULTITOUCH*/
    	input_report_key(data->input_dev, BTN_TOUCH, 1);
    	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 ft5x0x_report_value*/
    /***********************************************************************************************
    Name	:	 
    
    Input	:	
                         
    
    Output	:	
    
    function	:	
    
    ***********************************************************************************************/
    static void ft5x0x_ts_pen_irq_work(struct work_struct *work)
    {
    	int ret = -1;
    	//printk("==work 1=\n");
    	ret = ft5x0x_read_data();	
    	if (ret == 0) {	
    		ft5x0x_report_value();
    	}
    	//else printk("data package read error\n");
    	//printk("==work 2=\n");
        	msleep(1);
    //    enable_irq(this_client->irq);
    //	enable_irq(IRQ_EINT(6));
    }
    /***********************************************************************************************
    Name	:	 
    
    Input	:	
                         
    
    Output	:	
    
    function	:	
    
    ***********************************************************************************************/
    static irqreturn_t ft5x0x_ts_interrupt(int irq, void *dev_id)
    {
    	struct ft5x0x_ts_data *ft5x0x_ts = dev_id;
    //    	disable_irq(this_client->irq);		
    //	disable_irq(IRQ_EINT(6));
    	//printk("==int=");
    	if (!work_pending(&ft5x0x_ts->pen_event_work)) {
    		queue_work(ft5x0x_ts->ts_workqueue, &ft5x0x_ts->pen_event_work);
    	}
    
    	return IRQ_HANDLED;
    }
    #ifdef CONFIG_HAS_EARLYSUSPEND
    /***********************************************************************************************
    Name	:	 
    
    Input	:	
                         
    
    Output	:	
    
    function	:	
    
    ***********************************************************************************************/
    static void ft5x0x_ts_suspend(struct early_suspend *handler)
    {
    //	struct ft5x0x_ts_data *ts;
    //	ts =  container_of(handler, struct ft5x0x_ts_data, early_suspend);
    
    	printk("==ft5x0x_ts_suspend=\n");
    //	disable_irq(this_client->irq);
    //	disable_irq(IRQ_EINT(6));
    //	cancel_work_sync(&ts->pen_event_work);
    //	flush_workqueue(ts->ts_workqueue);
    	// ==set mode ==, 
    //    	ft5x0x_set_reg(FT5X0X_REG_PMODE, PMODE_HIBERNATE);
    }
    /***********************************************************************************************
    Name	:	 
    
    Input	:	
                         
    
    Output	:	
    
    function	:	
    
    ***********************************************************************************************/
    static void ft5x0x_ts_resume(struct early_suspend *handler)
    {
    	printk("==ft5x0x_ts_resume=\n");
    	// wake the mode
    //	__gpio_as_output(GPIO_FT5X0X_WAKE);		
    //	__gpio_clear_pin(GPIO_FT5X0X_WAKE);		//set wake = 0,base on system
    //	 msleep(100);
    //	__gpio_set_pin(GPIO_FT5X0X_WAKE);			//set wake = 1,base on system
    //	msleep(100);
    //	enable_irq(this_client->irq);
    //	enable_irq(IRQ_EINT(6));
    }
    #endif  //CONFIG_HAS_EARLYSUSPEND
    /***********************************************************************************************
    Name	:	 
    
    Input	:	
                         
    
    Output	:	
    
    function	:	
    
    ***********************************************************************************************/
    static int 
    ft5x0x_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
    {
    	struct ft5x0x_ts_data *ft5x0x_ts;
    	struct input_dev *input_dev;
    	int err = 0;
    	unsigned char ver = 0;
    	unsigned char uc_reg_value;
    	ct_irq_num=0;
    	
    	printk("==ft5x0x_ts_probe=\n");
    	
    	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
    		err = -ENODEV;
    		goto exit_check_functionality_failed;
    	}
    
    	printk("==kzalloc=\n");
    	ft5x0x_ts = kzalloc(sizeof(*ft5x0x_ts), GFP_KERNEL);
    	if (!ft5x0x_ts)	{
    		err = -ENOMEM;
    		goto exit_alloc_data_failed;
    	}
    
    
    	this_client = client;
    	i2c_set_clientdata(client, ft5x0x_ts);
    
    
    	INIT_WORK(&ft5x0x_ts->pen_event_work, ft5x0x_ts_pen_irq_work);
    
    	ft5x0x_ts->ts_workqueue = create_singlethread_workqueue(dev_name(&client->dev));//dev_name(&client->dev));
    	if (!ft5x0x_ts->ts_workqueue) {
    		err = -ESRCH;
    		goto exit_create_singlethread;
    	}
    
    	err = gpio_request(GPIO_TO_PIN(2,1),FT5X0X_NAME);
        	gpio_direction_output(GPIO_TO_PIN(2,1),1);
        	gpio_export(GPIO_TO_PIN(2,1),true);
    
    	err = gpio_request(GPIO_TO_PIN(2,0),FT5X0X_NAME);
    	gpio_direction_input(GPIO_TO_PIN(2,0));
    	gpio_export(GPIO_TO_PIN(2,0),true);
    	ct_irq_num = gpio_to_irq(GPIO_TO_PIN(2,0));
    
    //	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");64 irq line
    //	err = request_irq(client->irq, ft5x0x_ts_interrupt, IRQF_DISABLED, FT5X0X_NAME, ft5x0x_ts);//"ft5x0x_ts" instead of FT5.._NAME before --shriram
    	err = request_irq(ct_irq_num, ft5x0x_ts_interrupt, IRQF_TRIGGER_FALLING, FT5X0X_NAME, ft5x0x_ts);//IRQ_EINT(6)
    	if (err < 0) {
    		dev_err(&client->dev, "ft5x0x_probe: request irq failed\n");
    		printk("==request_irq failed=\n");//64 irq line should be
    		goto exit_irq_request_failed;
    	}
    
    //	__gpio_as_irq_fall_edge(pdata->intr);		//
    	disable_irq(ct_irq_num);
    //	disable_irq(IRQ_EINT(6));
    
    //	printk("==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;
    	}
    	
    	ft5x0x_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);
    
    	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);
    #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
    
    	//Define ABS_X&Y for tslib as it expects that
    	set_bit(ABS_X, input_dev->absbit);
    	set_bit(ABS_Y, input_dev->absbit);
    	set_bit(BTN_TOUCH, input_dev->keybit);
    
    	set_bit(EV_SYN, input_dev->evbit);
    	set_bit(EV_ABS, input_dev->evbit);
    	set_bit(EV_KEY, input_dev->evbit);
    
    //	 err = input_mt_init_slots(input_dev, 4);//4 is max support points
    //	 if (err) {
    //			 dev_err(&client->dev, "Unable to init MT slots.\n");
    //			 printk("Unable to init MT Slots.\n");
    //			 //goto err_free_mem;
    //	 }
    
    	input_dev->name		= FT5X0X_NAME;		//dev_name(&client->dev)
    	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;
    	}
    
    #ifdef CONFIG_HAS_EARLYSUSPEND
    	printk("==register_early_suspend =\n");
    	ft5x0x_ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
    	ft5x0x_ts->early_suspend.suspend = ft5x0x_ts_suspend;
    	ft5x0x_ts->early_suspend.resume	= ft5x0x_ts_resume;
    	register_early_suspend(&ft5x0x_ts->early_suspend);
    #endif
    
        msleep(50);
        //get some register information
        uc_reg_value = ft5x0x_read_fw_ver();
        printk("[FST] FT55x0x Firmware version = 0x%x\n", uc_reg_value);
        /*uc_reg_value = ft5x0x_read_reg(FT5X0X_REG_FT5201ID, &ver);
        printk("[FST] FT55x0x FiT5201ID = 0x%x\n", uc_reg_value);
        uc_reg_value = ft5x0x_read_reg(FT5X0X_REG_ERR, &ver);
        printk("[FST] FT55x0x ERR = 0x%x\n", uc_reg_value);*/
    
    
    //    fts_ctpm_fw_upgrade_with_i_file();
    
    //wake the CTPM
    //	__gpio_as_output(GPIO_FT5X0X_WAKE);		
    //	__gpio_clear_pin(GPIO_FT5X0X_WAKE);		//set wake = 0,base on system
    //	 msleep(100);
    //	__gpio_set_pin(GPIO_FT5X0X_WAKE);			//set wake = 1,base on system
    //	msleep(100);
    //	ft5x0x_set_reg(0x88, 0x05); //5, 6,7,8
    //	ft5x0x_set_reg(0x80, 30);
    //	msleep(50);
        	enable_irq(ct_irq_num);
    //    enable_irq(IRQ_EINT(6));
    
    	printk("==probe over =\n");
        return 0;
    
    exit_input_register_device_failed:
    	input_free_device(input_dev);
    exit_input_dev_alloc_failed:
    	free_irq(ct_irq_num, ft5x0x_ts);
    //	free_irq(IRQ_EINT(6), ft5x0x_ts);
    exit_irq_request_failed:
    exit_platform_data_null:
    	cancel_work_sync(&ft5x0x_ts->pen_event_work);
    	destroy_workqueue(ft5x0x_ts->ts_workqueue);
    exit_create_singlethread:
    	printk("==singlethread error =\n");
    	i2c_set_clientdata(client, NULL);
    	kfree(ft5x0x_ts);
    exit_alloc_data_failed:
    exit_check_functionality_failed:
    	return err;
    }
    /***********************************************************************************************
    Name	:	 
    
    Input	:	
                         
    
    Output	:	
    
    function	:	
    
    ***********************************************************************************************/
    static int __devexit ft5x0x_ts_remove(struct i2c_client *client)
    {
    	printk("==ft5x0x_ts_remove=\n");
    	struct ft5x0x_ts_data *ft5x0x_ts = i2c_get_clientdata(client);
    #ifdef CONFIG_HAS_EARLYSUSPEND
    	unregister_early_suspend(&ft5x0x_ts->early_suspend);
    #endif
    	free_irq(ct_irq_num, ft5x0x_ts);
    	gpio_free(GPIO_TO_PIN(2,0));
    //	free_irq(IRQ_EINT(6), ft5x0x_ts);
    	input_unregister_device(ft5x0x_ts->input_dev);
    	kfree(ft5x0x_ts);
    	cancel_work_sync(&ft5x0x_ts->pen_event_work);
    	destroy_workqueue(ft5x0x_ts->ts_workqueue);
    	i2c_set_clientdata(client, NULL);
    	return 0;
    }
    
    static const struct i2c_device_id ft5x0x_ts_id[] = {
    	{ FT5X0X_NAME, 0 },{ }
    };
    
    
    MODULE_DEVICE_TABLE(i2c, ft5x0x_ts_id);
    
    static struct i2c_driver ft5x0x_ts_driver = {
    	.probe		= ft5x0x_ts_probe,
    	.remove		= __devexit_p(ft5x0x_ts_remove),
    	.id_table	= ft5x0x_ts_id,
    	.driver	= {
    		.name	= FT5X0X_NAME,
    		.owner	= THIS_MODULE,
    	},
    };
    
    /***********************************************************************************************
    Name	:	 
    
    Input	:	
                         
    
    Output	:	
    
    function	:	
    
    ***********************************************************************************************/
    static int __init ft5x0x_ts_init(void)
    {
    	int ret;
    	printk("==ft5x0x_ts_init==\n");
    	ret = i2c_add_driver(&ft5x0x_ts_driver);
    	printk("ret=%d\n",ret);
    	return ret;
    //	return i2c_add_driver(&ft5x0x_ts_driver);
    }
    
    /***********************************************************************************************
    Name	:	 
    
    Input	:	
                         
    
    Output	:	
    
    function	:	
    
    ***********************************************************************************************/
    static void __exit ft5x0x_ts_exit(void)
    {
    	printk("==ft5x0x_ts_exit==\n");
    	i2c_del_driver(&ft5x0x_ts_driver);
    }
    
    module_init(ft5x0x_ts_init);
    module_exit(ft5x0x_ts_exit);
    
    MODULE_AUTHOR("<wenfs@Focaltech-systems.com>");
    MODULE_DESCRIPTION("FocalTech ft5x0x TouchScreen driver");
    MODULE_LICENSE("GPL");
    



  • Hi all,

    I am trying to integrate capacitive touch panel with ft5306 on am335x custom board using android. but i am not getting any events on touching the screen.

    The wake pin is connected to reset pin on the board, this pin has low signal at power on time and gets high after power on. The touch panel  interrupt is connected to a gpio, this pin has high value signal at power on and remains on low after boot up.

    The touchscreen driver and gpio interrupt seems registered.

    root@android:/ # getevent
    add device 1: /dev/input/event0
      name:     "ft5x06_ts"
    could not get driver version for /dev/input/mice, Not a typewriter
    add device 2: /dev/input/event1
      name:     "gpio-keys"


    ^C
    130|root@android:/ # cat /proc/bus/input/devices
    I: Bus=0000 Vendor=0000 Product=0000 Version=0000
    N: Name="ft5x06_ts"
    P: Phys=
    S: Sysfs=/devices/virtual/input/input0
    U: Uniq=
    H: Handlers=event0
    B: PROP=0
    B: EV=b
    B: KEY=0
    B: ABS=650000 0

    I: Bus=0019 Vendor=0001 Product=0001 Version=0100
    N: Name="gpio-keys"
    P: Phys=gpio-keys/input0
    S: Sysfs=/devices/platform/gpio-keys/input/input1
    U: Uniq=
    H: Handlers=kbd event1
    B: PROP=0
    B: EV=3
    B: KEY=100000 0 0 0


    root@android:/ # cat /proc/interrupts
               CPU0
     12:       5512      INTC  edma
     14:          0      INTC  edma_error
     18:          1      INTC  musb-hdrc.0
     19:          0      INTC  musb-hdrc.1
     36:       9337      INTC  da8xx_lcdc
     37:       4700      INTC  SGX ISR
     59:          0      INTC  ehrpwm_evt
     64:      20947      INTC  mmc0
     68:       6192      INTC  gp timer
     70:         18      INTC  omap_i2c
     71:          0      INTC  omap_i2c
     72:       1317      INTC  OMAP UART0
     75:          0      INTC  rtc0
     76:          0      INTC  rtc0
     77:          0      INTC  wkup_m3
     78:          1      INTC  wkup_m3_txev
     87:          0      INTC  ehrpwmTZ
    166:          0      GPIO  ft5x0x_ts
    211:          0      GPIO  power
    Err:          0
    root@android:/ #

    But i am not getting any interrupts from the touch screen.

    On the board_am335xevm.c file i made the following changes-

    #define CAP_TSC_INT        GPIO_TO_PIN(0,6)

    static void cap_tsc_init(int evm_id,int profile)
    {
        setup_pin_mux(cap_tsc_pin_mux);
           return;
    }

    static struct pinmux_config cap_tsc_pin_mux[] = {
        {"spi0_cs1.gpio0_6",        OMAP_MUX_MODE7 | AM33XX_PIN_INPUT},
        {NULL,0},     

    };

    static struct i2c_board_info am335x_i2c_boardinfo1[] = {
        {
            I2C_BOARD_INFO("ft5x06_ts",0x38),
            .irq = OMAP_GPIO_IRQ(CAP_TSC_INT),
        },
    };

    static void i2c1_init(int evm_id, int profile)
    {
        setup_pin_mux(i2c1_pin_mux);
        omap_register_i2c_bus(2, 100, am335x_i2c_boardinfo1,
                ARRAY_SIZE(am335x_i2c_boardinfo1));
        return;
    }

    Could anyone please provide some points to proceed further.

    Regards,

    Ebin

  • I am not sure if you tried exactly what I did, but I would start there. Also keep in mind, you cannot wake the device using the touch screen like the resistive touch screen. If this mean what interrupt is. I have not tried my device, but it works for me.

  • Hi,

    I tried with the driver posted on this question thread, but i am getting i2c read error.

    <4>[    1.354125] ==ft5x0x_ts_init==
    <4>[    1.357421] ==ft5x0x_ts_probe=
    <4>[    1.360626] ==kzalloc=
    <6>[    1.363922] input: ft5x0x_ts as /devices/virtual/input/input0
    <4>[    1.370330] ==register_early_suspend =
    <3>[    1.431396] msg ft5x0x_read_reg i2c read error: -121
    <4>[    1.436614] [FST] FT55x0x Firmware version = 0xa6
    <4>[    1.441589] ==probe over =
    <4>[    1.444519] ret=0
    <6>[    1.447631] using rtc device, omap_rtc, for alarms

    The gpio interrupt is configured as below and the wake pin is connected to system reset pin in hardware.

        err = gpio_request(GPIO_TO_PIN(0,6),FT5X0X_NAME);            
        gpio_direction_input(GPIO_TO_PIN(0,6));
        gpio_export(GPIO_TO_PIN(0,6),true);
        ct_irq_num = gpio_to_irq(GPIO_TO_PIN(0,6));

        err = request_irq(ct_irq_num, ft5x0x_ts_interrupt, IRQF_TRIGGER_FALLING, FT5X0X_NAME, ft5x0x_ts);

    I am using i2c1 for capacitive touch panel, could anyone please help me to debug this issue?

    Regards,

    Ebin

  • Did you make the corresponding changes in the board-am335xevm.c file? I think there something you need to change there also.

    Other than that, if your driver registered correctly, I don't know what else it could be.

    The other possibility is the GPIO you selected is not interrupt compatible? Keep me posted if you do get it working.

  • My Ft5x06 driver loads, the irqs trigger, I get data on event0, gui responds to touch events... BUT

    the data coming back is all zero. Running ts_calibrate produces the following output after touching each of the different points on the screen as prompted:

    ts_calibrate
    xres = 800, yres = 480
    Took 11 samples...
    Top left : X =    0 Y =    0
    Took 29 samples...
    Top right : X =    0 Y =    0
    Took 31 samples...
    Bot right : X =    0 Y =    0
    Took 25 samples...
    Bot left : X =    0 Y =    0
    Took 29 samples...
    Center : X =    0 Y =    0
    ts_calibrate: determinant is too small -- 0.000000
    Calibration failed.

    Any ideas why I am receiving zeros?

  • Hi Ivor,

    You have to recompile tslib with changes as described here

    http://www.ptrackapp.com/apclassys-notes/embedded-linux-multitouch/

    to solve this issue. Key is replacing any occurence of ABS_X / Y with ABS_MT_POSITION_X / Y in input_raw.c.

    Then copy and replace the new lib and executables in target system.

    This should solve your issue.

    Ram

  • Ram, thanks again for your quick response. I have tried to recompile the tslib with the changes for the event type reporting. I say "tried" because I am not sure if it worked because the results are still the same. Getting zeros for all touch event.

    I am working on an OMAP4430 board, but in principle the touch screen is the same. I use the Pengutronix dist as provided by Phytec. I entered the source directory and edited the tslib file input-raw.c file with the changes you suggested.

    Is there a way to get the version of the tslib from the target device os?


    Also, note that I am not particularly interested in multitouch as such, single touch would also be ok.

    I have add prints in your driver to display the received touch info, and touch point one indicates correct values when touching the screen, so hardware and driver/irq installation is fine.

    Thanks for your help.

  • If you have replaced the new tslib (libs+programs) and you still get zeroes, there is still something wrong with the communication between tslib and driver. find out how the driver reports the touch coordinates (with or without MT) and make sure that is how tslib gets its coordinates. I cannot think of anyother reason you are getting zeroes with tslib programs.

    I assume here that your driver reads the proper coordinates from ft5x controller. You can verify if it is porperly transfered by vieweing /dev/input/eventX with hexdump.

  • Hello Ram, I am having trouble to integrate the same display. I don't get any picture. Can you sent me your modifications or the image.

    Please sent this to email@friesenundminuth.de

    Thank you

  • Hi Thomas,

    I have posted all code pertaining to display in this thread already.

    If it is the same display, find the da8xxfb.c file posted by me here and the boardconfig file from me and replicate the same at your side.

    If I remember correct, you have to choose the TFC_S9700RTWV35TR_01B config in da8xx-fb.c in boardconfig

    Hope this helps,

    Ram

  • Hi all,

    The ft5306 capacitive touch panel worked on my am335x custom board with the driver posted here.

    I had to modify the hardware, connected the wake pin to a gpio and enabled it in ft5x06 driver and board file. Earlier it was connected to the reset pin.

    Thanks all for the help and for posting the work.

    Regards,

    Ebin

  • Hi Ram, I don't get this display up and running. I ve used your definitions and it is compiling without errors. But the display doesn't work. I ve seen in the board file from you that you don't use the LCD data 16 tip 23. Do you use the display in 16bit mode? It is possible to send me the kernel? Only to check the display. Perhps it is defect.

    Thanks 

    Thomas

  • Hi Thomas,

    My kernel is for a custom board and will not even boot in yours. Do not use my board config file as it is. Just change the display in your board config file to the one specified in da8xxfb.c file. NHD display works without any extra addition to SDK code.

    I have connected a 24 bit display to a 16 bit ouput from processor by shorting some LSB lines. RGB(565). 

    Check if you switch on the display properly (display enable) and blank display is not enabled.

    Ram

  • Hi Ram, my display must be dameged. I took your Board config file and changed according to your advice only the display to TFC_S9700RTWV35TR_01B. I made the changes according the data sheet, but still nothing. Can you tell me wether you have made changes to theda8xx-fb file?

     

    Thanks 

     

    Thomas

  • Hi, I have the same problem as you. Can you sent me your modification in the da8xx-fb.c file?

     

    Thanks

     

    Thomas

  • Hello ram,

    after some frustrating tests I changed the display and connected the 4.3 NHD again. I found out that the timing was exactly the same for the NHD 4.3 (I got an picture without changing the kernel) but the resolution changed (icon size, etc) to 800x480, the size for the NHD 5 inch display. I am using version 6.00.00. With version are you using?

    Thanks 

    Thomas

  • Hello,,

    can you tell me what version of the Android SDK you use?

    Thanks

    Thomas

  • Hello All, I ve got a new Display from my distributor and it works now as described under Linux. 

    Thanks all for the support.

    Thomas

  • Hello,

    I try to add FT5316 support in Linux 2.6.36 but not sure how to change mach-file.

    When probing on this line in driver:

    ft5x0x_ts->pdata = pdata

    I get:

    Unable to handle kernel NULL pointer dereference at virtual address 00000000
    pgd = c0004000
    [00000000] *pgd=00000000
    Internal error: Oops: 5 [#1] PREEMPT
    last sysfs file:
    Modules linked in:
    CPU: 0 Not tainted (2.6.38-FriendlyARM #38)
    PC is at ft5x0x_ts_probe+0xc0/0x3fc

    May be resourses not set ?

     

  • I have some doubts regarding the above topic.

    1) For Kernel  3.8.13  version when I build Android 4.2 JB I donot get the file board-arm335xevm.c in the "/kernel/arch/arm/mach-omap2/ folder.

    2) For the touchscreen driver (ft5x06) to work do we need to change/modify the board-arm335xevm.c file? I donot have it So, how do I proceed. Can any one helpme with this. I have followed edt-ft5x06.c driver file.My LCD is 

    https://www.google.co.in/webhp?sourceid=chrome-instant&rlz=1C1TGIB_enIN565IN565&ion=1&espv=2&ie=UTF-8#q=SH480272T-006-I13Q

    I know its old post but some help and light will guide me.

     

    Thanks

    Polash Misra

  • Hi Ebin,

    I'm also facing the same issue which u have told here, same types of prints I'm also getting and also not getting any interrupt when I touch the display.
    But in my case wakeup pin is not connected to any reset pin and wakeup pin is default high only(in hardware).
    could you please explain any other changes which you made to get this worked.

    Thanks in advance
    Regards,
    Yashavantha
  • hi,

    could you please attach the driver and board file which you have used to get it work,

    Thanks and Regards,
    Yashavantha
  • can you share your h/w and kernel details ?
  • I'm hoping for support on this topic.
    I have a 3.5" NHD display/touchscreen.
    I've incorporated the ft5x06 drivers into my kernel build and have successfully gotten the device LCD portion correct.
    It also appears that the touch behavior is active.
    Under /dev/input I can see event0, mouse0, mice, and by_path.
    I can successfully run ts_calibrate and ts_print utilities with reasonable responses.

    However, I don't get a touchscreen0 input device.
    I'm have the matrix_gui code running with these variable settings:
    export TSLIB_TSDEVICE=/dev/input/event0
    export QWS_MOUSE_PROTO=/dev/input/event0

    The Qt 4.8 code does not seem to recognize the touch events.

    Can someone guide me as to the steps I need to take to receive the touchscreen data and have Qt apply it to my GUI app?

    Thanks,

    David
  • HI,

    i am using the ft5x0x_ts same CTP in am335x. I am able to build the driver and added and created the interface as event2.

    root@am335x-evm:~# cat /proc/bus/input/devices

    I: Bus=0000 Vendor=0000 Product=0000 Version=0000

    N: Name="ft5x0x_ts"

    P: Phys=

    S: Sysfs=/devices/virtual/input/input3

    U: Uniq=

    H: Handlers=mouse1 event3

    B: PROP=0

    B: EV=b

    B: KEY=400 0 0 0 0 0 0 0 0 0 0

    B: ABS=650000 3

    root@am335x-evm:~#

    But i am not getting any event output on my terminal. How to make it working. I ma using WAKEUP connected to pullup, and INT is doing as same attached code

    could you send me the working code. 

    Regards,

    Anil.

  • Hi Ram

    I am using the same LCD with ft5x06 CTP controller and used your drivers it is working in driver level i have printed some logs when interrupt occurs.

    cat /dev/input/event2 on interface some garbage data is coming, that mean my driver and CTP is working.

    But i am unable to operate my desktop using Qt 4.8 with my finger touch . TSLIB are not proper it seems.  how to make my touch on in Qt application

    from your link i downloaded the tslib and cross compiled and loaded in my rootfs. I am getting the error while run the ts_calibrate

    root@am335x-evm:/home# ts_calibrate
    No raw modules loaded.
    ts_config: No such file or directory

    Regards,

    Anil 

     

  • e2e.ti.com/.../152517

    Also, is your QT build with tslib support ?
  • Hi Ankur,

    We configured my Qt with tslib at the beginning. 

    my cursor is not moving in my Qt application while i have integrated with CTP. when i use the resistive touch it is working my application with touch.

    I have called the below configuration on script and trying to capture the ts_calibrate it is working, But my Qt application cursor is not moving the with the same tslib.

    Is there any modifications required under the tslib source for Capacitive touch. find the attached ts_calibrate script is working in my platform.

    Regards,

    Anil

    ts_calibrate-script.txt
    #! /bin/sh
    
    ### BEGIN INIT INFO
    # Provides:          ts_calibrate
    # Short-Description: daemon that enables touchscreen for kodi media player
    # Required-Start:    $remote_fs $local_fs $syslog
    # Required-Stop:     $remote_fs $local_fs $syslog
    # Default-Start:     2 3 4 5
    # Default-Stop:      0 1 6
    ### END INIT INFO
    
    case "$1" in
      start)
            echo -n "Starting ts_calibrate:"
            export LD_LIBRARY_PATH=/usr/lib
            export TSLIB_CONSOLEDEVICE=none
            export TSLIB_FBDEVICE=/dev/fb0
            export TSLIB_TSDEVICE=/dev/input/event3
            export TSLIB_CALIBFILE=/etc/pointercal
            export TSLIB_CONFFILE=/etc/ts.conf
            export TSLIB_PLUGINDIR=/usr/lib/ts
            ts_calibrate -d
            
            echo "OK"
            ;;
      stop)
            echo -n "Stopping ts_calibrate:"
            killall ts_calibrate
            echo "OK"
            ;;
      restart|reload)
            ;;
      *)
            echo "Usage: $0 {start|stop|restart}"
            exit 1
    esac
    
    exit $?