imx6q 單點觸摸ft5x06驅動

/* 
 * 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>
#include <linux/of_device.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)
#define PRINTK_DBG(...)     //printk(__VA_ARGS__) 

static struct i2c_client *this_client;
static struct ft5x06_ts_platform_data *pdata;
 
//#define CONFIG_FT5X06_MULTITOUCH 1
#define FT5X0X_NAME      "ft5x06"
#define PRESS_MAX      255u
#define SCREEN_MAX_X     800u
#define SCREEN_MAX_Y     480u

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_DBG("========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_DBG("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_DBG("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_DBG("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_DBG("Step 5\n");
    return(0x09);
}
 
 
#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_DBG("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_DBG("[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_DBG("[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_DBG("[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_DBG("[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_DBG("[TSP] Step 4: erase. \n");
 
    /*********Step 5:write firmware(FW) to ctpm flash*********/
    bt_ecc = 0;
    //PRINTK_DBG("[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_DBG("[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_DBG("[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_DBG("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_DBG("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_DBG("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_DBG("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_DBG("===========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_DBG("%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_DBG("%d (%d, %d), (%d, %d)\n", event->touch_point, event->x1, event->y1, event->x2, event->y2);
    PRINTK_DBG("===========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_DBG("==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_DBG("===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_DBG("===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_DBG("===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_DBG("===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_DBG("===x1 = %d,y1 = %d ====\n",event->x1,event->y1);
 
        default:
            PRINTK_DBG("==touch_point default =\n");
            break;
    }
#else    /* CONFIG_FT5X06_MULTITOUCH*/
    if (event->touch_point == 1) {
//        PRINTK_DBG("===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_DBG("Step 12\n");
    int ret = -1;
    //PRINTK_DBG("==work 1=\n");
    ret = ft5x06_read_data();    
    if (ret == 0) {    
        ft5x06_report_value();
    }
    else //PRINTK_DBG("data package read error\n");
    //PRINTK_DBG("==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_DBG("Step 13.b\n");    
        ////PRINTK_DBG("Disable IRQ 2\n");
    //disable_irq(190);
    //disable_irq_lockdep(this_client->irq);
        //    //PRINTK_DBG("==int=\n");
        //PRINTK_DBG("Step 13.c\n");
    if (!work_pending(&ft5x06_ts->pen_event_work)) {
            //PRINTK_DBG("Step 13.d\n");
        queue_work(ft5x06_ts->ts_workqueue, &ft5x06_ts->pen_event_work);
        //PRINTK_DBG("Step 13.e\n");
    }
        //PRINTK_DBG("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_DBG("Step 14\n");
//    struct ft5x06_ts_data *ts;
//    ts =  container_of(handler, struct ft5x06_ts_data, early_suspend);
 
    //PRINTK_DBG("==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_DBG("Step 15\n");
    //PRINTK_DBG("==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    :    
***********************************************************************************************/
#define EDT_NAME_LEN            23

enum edt_ver {
    M06,
    M09,
};

struct edt_reg_addr {
    int reg_threshold;
    int reg_report_rate;
    int reg_gain;
    int reg_offset;
    int reg_num_x;
    int reg_num_y;
};

struct edt_ft5x06_ts_data {
    struct i2c_client *client;
    struct input_dev *input;
    //struct touchscreen_properties prop;
    u16 num_x;
    u16 num_y;
    struct gpio_desc *reset_gpio;
    struct gpio_desc *wake_gpio;

#if defined(CONFIG_DEBUG_FS)
    struct dentry *debug_dir;
    u8 *raw_buffer;
    size_t raw_bufsize;
#endif

    struct mutex mutex;
    bool factory_mode;
    int threshold;
    int gain;
    int offset;
    int report_rate;
    int max_support_points;

    char name[EDT_NAME_LEN];

    struct edt_reg_addr reg_addr;
    enum edt_ver version;
};

static int 
ft5x06_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
//PRINTK_DBG("Step 16\n");
    struct ft5x06_ts_data *ft5x06_ts;
    const struct edt_i2c_chip_data *chip_data;
    struct edt_ft5x06_ts_data *tsdata;
    struct input_dev *input_dev;
    int err = 0;
    unsigned char uc_reg_value; 
    
    PRINTK_DBG("==ft5x06_ts_probe=\n");

    tsdata = devm_kzalloc(&client->dev, sizeof(*tsdata), GFP_KERNEL);
    if (!tsdata) {
        dev_err(&client->dev, "failed to allocate driver data.\n");
        return -ENOMEM;
    }

    //chip_data = of_device_get_match_data(&client->dev);
    //if (!chip_data)
    //    chip_data = (const struct edt_i2c_chip_data *)id->driver_data;
    //if (!chip_data || !chip_data->max_support_points) {
    //    dev_err(&client->dev, "invalid or missing chip data\n");
    //    return -EINVAL;
    //}

    tsdata->max_support_points = 1;//chip_data->max_support_points;

    tsdata->reset_gpio = devm_gpiod_get_optional(&client->dev,
         "reset", GPIOD_OUT_HIGH);
    if (IS_ERR(tsdata->reset_gpio)) {
        err = PTR_ERR(tsdata->reset_gpio);
        dev_err(&client->dev,
        "Failed to request GPIO reset pin, error %d\n", err);
        return err;
    }
    tsdata->wake_gpio = devm_gpiod_get_optional(&client->dev,
        "wake", GPIOD_OUT_LOW);
    if (IS_ERR(tsdata->wake_gpio)) {
        err = PTR_ERR(tsdata->wake_gpio);
        dev_err(&client->dev,
        "Failed to request GPIO wake pin, error %d\n", err);
        return err;
    }

    if (tsdata->wake_gpio) {
        usleep_range(5000, 6000);
        gpiod_set_value_cansleep(tsdata->wake_gpio, 1);
    }

    if (tsdata->reset_gpio) {
        usleep_range(5000, 6000);
        gpiod_set_value_cansleep(tsdata->reset_gpio, 0);
        msleep(300);
    }


    //RESETPIN_REQUEST;
    //RESETPIN_SET1;
    //mdelay(1000);
    //gpio_set_value(GPIO_RESET,0);
//    PRINTK_DBG("GPIO1_14 is %d \n ", gpio_get_value(GPIO1_14));
    //mdelay(50);
    //gpio_set_value(GPIO_RESET,1);
    //mdelay(100);
 //   PRINTK_DBG("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_DBG("==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_DBG("==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_DBG("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_DBG(">>>>>>>>>>>>>request_irq\n");
//    __gpio_as_irq_fall_edge(pdata->intr);        //
//    disable_irq(this_client->irq);
        //PRINTK_DBG("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_DBG("==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_DBG("==> ABS_MT_POSITION_X = %x\n",ABS_MT_POSITION_X);
//        PRINTK_DBG("==> ABS_MT_POSITION_Y = %x\n",ABS_MT_POSITION_Y);
//        PRINTK_DBG("==> ABS_MT_TOUCH_MAJOR = %x\n",ABS_MT_TOUCH_MAJOR);
//        PRINTK_DBG("==> 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_DBG("==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_DBG("[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_DBG("==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_DBG("==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 ft5x06_ts_remove(struct i2c_client *client)
{
//PRINTK_DBG("Step 17\n");
    //PRINTK_DBG("==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 },{ }
};


struct edt_i2c_chip_data {
                    int  max_support_points;
};

static const struct edt_i2c_chip_data edt_ft5x06_data = {
            .max_support_points = 1,
};

static const struct i2c_device_id edt_ft5x06_ts_id[] = {
{ .name = "edt-ft5x06", .driver_data = (long)&edt_ft5x06_data },
/* Note no edt- prefix for compatibility with the ft6236.c driver */
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id);
 
#ifdef CONFIG_OF
static const struct of_device_id edt_ft5x06_of_match[] = {
{ .compatible = "edt,edt-ft5206", .data = &edt_ft5x06_data },
{ .compatible = "edt,edt-ft5306", .data = &edt_ft5x06_data },
{ .compatible = "edt,edt-ft5406", .data = &edt_ft5x06_data },
/* Note focaltech vendor prefix for compatibility with ft6236.c */
{ /* sentinel */ }
};


MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match);
#endif

static struct i2c_driver ft5x06_ts_driver = {
    .probe        = ft5x06_ts_probe,
    .remove        = ft5x06_ts_remove,
    .id_table    = edt_ft5x06_ts_id,
    .driver    = {
        .name    = FT5X0X_NAME,
        .owner    = THIS_MODULE,
        .of_match_table = of_match_ptr(edt_ft5x06_of_match),
    },
};
 
/***********************************************************************************************
Name    :     
Input    :    
                     
Output    :    
function    :    
***********************************************************************************************/
static int __init ft5x06_ts_init(void)
{
//PRINTK_DBG("Step 18\n");
    int ret;
    PRINTK_DBG("==ft5x06_ts_init==\n");
    ret = i2c_add_driver(&ft5x06_ts_driver);
    //PRINTK_DBG("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_DBG("Step 19\n");
    //PRINTK_DBG("==ft5x06_ts_exit==\n");
    i2c_del_driver(&ft5x06_ts_driver);
}
 
//module_init(ft5x06_ts_init);
//module_exit(ft5x06_ts_exit);
module_i2c_driver(ft5x06_ts_driver);

MODULE_AUTHOR("<[email protected]>");
MODULE_DESCRIPTION("FocalTech ft5x06 TouchScreen driver");
MODULE_LICENSE("GPL");
 
/**********************************************************************************

#作爲模塊編譯時的Makefile部分

export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
KERN_DIR = /home/lonnox/work/imx6/freescale/linux-imx-4.9.88/linux-imx

all:
        make -C $(KERN_DIR) M=`pwd` modules

clean:
        make -C $(KERN_DIR) M=`pwd` modules clean
        rm -rf modules.order

obj-m   += ft5x06.o
**********************************************************************************/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章