A33_TP驱动调试

做linux 嵌入式驱动,离不开调试i2c 外设,这里对i2c做一下3点总结:

1.先要知道i2c的4个信号;

a) 起始信号:当 SCL 线是高电平时 SDA 线从高电平向低电平切换。 

b) 停止信号:当 SCL 线是高电平时 SDA 线由低电平向高电平切换。

c)   ACk信号: 当scl线由低变高时候,SDA线保持低电平;

d)  NACK信号:当scl线由低变高时候,SDA线保持高电平;

2、通信接口
i2c发送或者接收一次数据都以数据包 struct i2c_msg 封装
[cpp] 
struct i2c_msg { 
    __u16 addr;     // 从机地址 
    __u16 flags;    // 标志 
#define I2C_M_TEN   0x0010  // 十位地址标志 
#define I2C_M_RD    0x0001  // 接收数据标志 
    __u16 len;      // 数据长度 
    __u8 *buf;      // 数据指针 
}; 
其中addr为从机地址;flags则是这次通信的标志,发送数据为0,接收数据则为 I2C_M_RD;len为此次通信的数据字节数;buf 为发送或接收数据的指针。在设备驱动中我们通常调用 i2c-core 定义的接口 i2c_master_send 和 i2c_master_recv 来发送或接收一次数据。
[cpp]
int i2c_master_send(struct i2c_client *client,const char *buf ,int count) 

    int ret; 
    struct i2c_adapter *adap=client->adapter;  // 获取adapter信息 
    struct i2c_msg msg;                        // 定义一个临时的数据包 
 
    msg.addr = client->addr;                   // 将从机地址写入数据包 
    msg.flags = client->flags & I2C_M_TEN;     // 将从机标志并入数据包 
    msg.len = count;                           // 将此次发送的数据字节数写入数据包 
    msg.buf = (char *)buf;                     // 将发送数据指针写入数据包 
 
    ret = i2c_transfer(adap, &msg, 1);         // 调用平台接口发送数据 
 
     
    return (ret == 1) ? count : ret;           // 如果发送成功就返回字节数 

EXPORT_SYMBOL(i2c_master_send); 
i2c_master_send 接口的三个参数:client 为此次与主机通信的从机,buf 为发送的数据指针,count 为发送数据的字节数。
[cpp] 
int i2c_master_recv(struct i2c_client *client, char *buf ,int count) 

    struct i2c_adapter *adap=client->adapter;  // 获取adapter信息 
    struct i2c_msg msg;                        // 定义一个临时的数据包 
    int ret; 
 
    msg.addr = client->addr;                   // 将从机地址写入数据包 
    msg.flags = client->flags & I2C_M_TEN;     // 将从机标志并入数据包 
    msg.flags |= I2C_M_RD;                     // 将此次通信的标志并入数据包 
    msg.len = count;                           // 将此次接收的数据字节数写入数据包 
    msg.buf = buf; 
 
    ret = i2c_transfer(adap, &msg, 1);         // 调用平台接口接收数据 
 
     
    return (ret == 1) ? count : ret;           // 如果接收成功就返回字节数 

EXPORT_SYMBOL(i2c_master_recv); 
i2c_master_recv 接口的三个参数:client 为此次与主机通信的从机,buf 为接收的数据指针,count 为接收数据的字节数。我们看一下 i2c_transfer 接口的参数说明:
[cpp
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num); 

其中 adap 为此次主机与从机通信的适配器;msgs 为通信的数据包,这里可以是单个或多个数据包;num 用于指定数据包的个数,如果大于1则表明将进行不止一次的通信。通信一次就需要寻址一次,如果需要多次通信就需要多次寻址,前面2个接口都是进行一次通 信,所以 num 为1;有的情况下我们要读一个寄存器的值,就需要先向从机发送一个寄存器地址然后再接收数据,这样如果想自己封装一个接口就需要将 num 设置为2。接口的返回值如果失败则为负数,如果成功则返回传输的数据包个数。

首先我们先来看一下写数据的时序图:进行了1次寻址操作 

结合I2C总线协议的知识,我们可以知道OZ9350的I2C写数据由一下10个步骤组成。 
  第一步,发送一个起始信号。 
  第二步,发送7bit从机地址,即OZ9350的地址。此处需要注意,发送数据时,无法发送7bit数据,此处发送了7bit地址+1bit读写选择位,即发送7bit+r/w。最低位为1表示读,为0表示写。 
  第三步,产生一个ACK应答信号,此应答信号为从机器件产生的应答。 
  第四步,发送寄存器地址,8bit数据。 
  第五步,产生一个ACK应答信号,此应答信号为从机器件产生的应答。 
  第六步,发送一个数据,8bit数据。 
  第七步,产生一个ACK应答信号,此应答信号为从机器件产生的应答信号。 
  第八步,发送一个CRC校验码,此CRC校验值为2、4、6步数据产生的校验码。 
  第九步,既可以发送一个应答信号,也可以发送一个无应答信号,均有从机器件产生。 

  第十步,发送一个停止信号。

读数据的时序图如下图所示:进行了2次寻址操作

 

通过分解后的时序图,可以看到OZ9350的读数据由以下13个步骤组成。 
  第一步,发送一个起始信号。 
  第二步,发送7bit从机地址,即OZ9350的地址。此处需要注意,发送数据时,无法发送7bit数据,此处发送了7bit地址+1bit读写选择位,即发送7bit+r/w。最低位为1表示读,为0表示写。 
  第三步,产生一个ACK应答信号,此应答信号为从机器件产生的应答。 
  第四步,发送寄存器地址。 
  第五步,产生一个ACK应答信号,此应答信号为从机器件产生的应答。 
  第六步,再次发送一个骑士信号。 
  第七步,发送7bit从机地址,即OZ9350的地址。此处需要注意,发送数据时,无法发送7bit数据,此处发送了7bit地址+1bit读写选择位,即发送7bit+r/w。最低位为1表示读,为0表示写。 
  第八步,产生一个ACK应答信号,此应答信号为从机器件产生的应答。 
  第九步,读取一个字节(8bit)的数据。 
  第十步,产生一个ACK应答信号,此应答信号为CPU产生。 
  第十一步,读取一个CRC校验码。 
  第十二步,产生一个NACK信号。此无应答信号由CPU产生。 

  第十三步,产生一个停止信号。

/*这三点I2C总结,非常好,感谢该博主https://blog.csdn.net/c_L_j_/article/details/80845083的总结*/

言归正传,回到代码

/*
 * drivers/input/touchscreen/gslX680.c
 */
 


#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/jiffies.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/pm_runtime.h>

 

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

 

#include <linux/input/mt.h>

 

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

 

#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/async.h>
#include <linux/hrtimer.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/device.h>
#include <mach/irqs.h>
#include <mach/hardware.h>
#include <mach/sys_config.h>
#include <linux/gpio.h>

 

#include <linux/init-input.h>

 

#include "gslX680.h"
#include "gslX680_inetd71.h"
#include "gsl1680e_p2.h"
#include "gslX680_m86hd.h"
#include "gslX680_m102.h"
#include "gslX680_m102gg.h"
#include "main_1680E_m320.h"
#include "gslX680_m100.h"
#include "gslX680_mq88.h"
#include "gslX680_m71.h"
#include "gslX680_m7300.h"
#include "gslX680_jinghong.h"
#include "gsl1680e_d7.h"
struct gslX680_fw_array {
 const char* name;
 unsigned int size;
 const struct fw_data *fw;
} gslx680_fw_grp[] = {
 {"gslX680_inetd71"  ,  ARRAY_SIZE(GSLX680_FW_INETD71),GSLX680_FW_INETD71},
 {"gsl1680e_p2"  ,  ARRAY_SIZE(GSL1680E_FW_P2),GSL1680E_FW_P2},
 {"gsl_m86_hd"  ,  ARRAY_SIZE(GSLX680_FW_M86HD),GSLX680_FW_M86HD},
 {"gsl_m102"  ,  ARRAY_SIZE(GSLX680_FW_M102),GSLX680_FW_M102},
 {"gsl_m102gg"  ,  ARRAY_SIZE(GSLX680_FW_M102GG),GSLX680_FW_M102GG},
 {"gsl_m320"  ,  ARRAY_SIZE(GSLX680_FW_M320),GSLX680_FW_M320},
 {"gsl_m100"  ,  ARRAY_SIZE(GSLX680_FW_M100),GSLX680_FW_M100},
 {"gsl_mq88"  ,  ARRAY_SIZE(GSLX680_FW_MQ88),GSLX680_FW_MQ88},
 {"gsl_m71"  ,  ARRAY_SIZE(GSLX680_FW_M71),GSLX680_FW_M71},
 {"gsl_m7300"  ,  ARRAY_SIZE(GSLX680_FW_M7300),GSLX680_FW_M7300},
 {"gsl_jinghong"  ,  ARRAY_SIZE(GSLX680_FW_JINGHONG),GSLX680_FW_JINGHONG},
 {"gsl1680_d7" , ARRAY_SIZE(GSLX680_FW_D7),GSLX680_FW_D7},
};

 

unsigned int *gslX680_config_data[16] = {
    gsl_config_data_id_K71_OGS_1024600,    
    gsl_config_data_id_P2,
    gsl_config_data_id_m86_1024600,
    gsl_config_data_id_m102,
    gsl_config_data_id_m102gg,
    gsl_config_data_id_m320,
    gsl_config_data_id_m100,
    gsl_config_data_id_mq88,
    gsl_config_data_id_m71,
    gsl_config_data_id_m7300,
    gsl_config_data_id_jinghong,
 gsl_config_data_id_d7,
};

 

#define FOR_TSLIB_TEST

 

#define GSL_MONITOR

 

//#define HAVE_TOUCH_KEY
#ifdef TPD_PROC_DEBUG
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
static struct proc_dir_entry *gsl_config_proc = NULL;
#define GSL_CONFIG_PROC_FILE "gsl_config"
#define CONFIG_LEN 31
static char gsl_read[CONFIG_LEN];
static u8 gsl_data_proc[8] = {0};
static u8 gsl_proc_flag = 0;
#endif

 

 

 

#define GSL_DATA_REG  0x80
#define GSL_STATUS_REG  0xe0
#define GSL_PAGE_REG  0xf0

 

#define PRESS_MAX       255
#define MAX_FINGERS   5//5 //最大手指个数
#define MAX_CONTACTS   10
#define DMA_TRANS_LEN  0x20

 

#define PHO_CFG2_OFFSET (0X104)
#define PHO_DAT_OFFSET  (0X10C)
#define PHO_PULL1_OFFSET (0X11C)
#define GPIOF_CON   0x7f0080a0
#define GPIOF_DAT   0x7f0080a4
#define GPIOF_PUD   0x7f0080a8

 

#define GSL_NOID_VERSION

 

#ifdef GSL_MONITOR
static struct delayed_work gsl_monitor_work;
static struct workqueue_struct *gsl_monitor_workqueue = NULL;
static char int_1st[4] = {0};
static char int_2nd[4] = {0};
#endif

 


#ifdef HAVE_TOUCH_KEY      
static u16 key = 0;
static int key_state_flag = 0;
struct key_data {
 u16 key;
 u16 x_min;
 u16 x_max;
 u16 y_min;
 u16 y_max; 
};

 

const u16 key_array[]={
      KEY_BACK,
      KEY_HOME,
      KEY_MENU,
      KEY_SEARCH,
};
#define MAX_KEY_NUM     (sizeof(key_array)/sizeof(key_array[0]))

 

struct key_data gsl_key_data[MAX_KEY_NUM] = {
 {KEY_BACK,  816, 836,115, 125},
 {KEY_HOME,  816, 836,259 ,269}, 
 {KEY_MENU,  816, 836,398, 410},
 {KEY_SEARCH, 2048, 2048, 2048, 2048},
};
#endif

 

struct gsl_ts_data {
 u8 x_index;
 u8 y_index;
 u8 z_index;
 u8 id_index;
 u8 touch_index;
 u8 data_reg;
 u8 status_reg;
 u8 data_size;
 u8 touch_bytes;
 u8 update_data;
 u8 touch_meta_data;
 u8 finger_size;
};

 

static struct gsl_ts_data devices[] = {
 {
  .x_index = 6,
  .y_index = 4,
  .z_index = 5,
  .id_index = 7,
  .data_reg = GSL_DATA_REG,
  .status_reg = GSL_STATUS_REG,
  .update_data = 0x4,
  .touch_bytes = 4,
  .touch_meta_data = 4,
  .finger_size = 70,
 },
};

 

struct gsl_ts {
 struct i2c_client *client;
 struct input_dev *input;
 struct work_struct work;
 struct workqueue_struct *wq;
 struct gsl_ts_data *dd;
 u8 *touch_data;
 u8 device_id;
 u8 prev_touches;
 bool is_suspended;
 bool int_pending;
 struct mutex sus_lock;
 int irq;
#if defined(CONFIG_HAS_EARLYSUSPEND)
 struct early_suspend early_suspend;
#endif
#ifdef GSL_TIMER
 struct timer_list gsl_timer;
#endif

 

};

 

 

 

static u32 id_sign[MAX_CONTACTS+1] = {0};
static u8 id_state_flag[MAX_CONTACTS+1] = {0};
static u8 id_state_old_flag[MAX_CONTACTS+1] = {0};
static u16 x_old[MAX_CONTACTS+1] = {0};
static u16 y_old[MAX_CONTACTS+1] = {0};
static u16 x_new = 0;
static u16 y_new = 0;

 


///
//specific tp related macro: need be configured for specific tp

 

#define GSLX680_I2C_NAME          "gslX680"

 

#define CTP_IRQ_NUMBER              (config_info.int_number)
#define CTP_IRQ_MODE       (IRQF_TRIGGER_FALLING)
#define CTP_NAME           GSLX680_I2C_NAME
#define SCREEN_MAX_X          (screen_max_x)
#define SCREEN_MAX_Y          (screen_max_y)

 

static char* fwname;
static int fw_index = -1;

 


#define GSLX680_I2C_ADDR 0x40
      
#define GSLX680_USED     "\n \
              \n+++++++++++++++++++++++++++++++++ \
              \n++++++ GSLX680 new used +++++++++ \
              \n+++++++++++++++++++++++++++++++++ \
              \n"
             
#define GSLX680_IC_INFO  "\n============================================================== \
              \nIC  :GSLX680 \
              \nAUTHOR :mbgalex@163.com \
              \nVERSION:2013-07-20_10:41\n"
             
static int screen_max_x = 0;
static int screen_max_y = 0;
static int revert_x_flag = 0;
static int revert_y_flag = 0;
static int exchange_x_y_flag = 0;

 


struct ctp_config_info config_info = {
 .input_type = CTP_TYPE,
 .name = NULL,
 .int_number = 0,
};

 


static __u32 twi_id = 0;

 

static u32 debug_mask = 0;
enum{
 DEBUG_INIT = 1U << 0,
 DEBUG_SUSPEND = 1U << 1,
 DEBUG_INT_INFO = 1U << 2,
 DEBUG_X_Y_INFO = 1U << 3,
 DEBUG_KEY_INFO = 1U << 4,
 DEBUG_WAKEUP_INFO = 1U << 5,
 DEBUG_OTHERS_INFO = 1U << 6,
};

 

#define dprintk(level_mask,fmt,arg...)    if(unlikely(debug_mask & level_mask)) \
        printk("***CTP***"fmt, ## arg)

 


/* Addresses to scan */
static const unsigned short normal_i2c[2] = {GSLX680_I2C_ADDR, I2C_CLIENT_END};

 

static void glsX680_init_events(struct work_struct *work);
static void glsX680_resume_events(struct work_struct *work);
struct workqueue_struct *gslX680_wq;
struct workqueue_struct *gslX680_resume_wq;
static DECLARE_WORK(glsX680_init_work, glsX680_init_events);
static DECLARE_WORK(glsX680_resume_work, glsX680_resume_events);
struct i2c_client *glsX680_i2c;
struct gsl_ts *ts_init;

 


int ctp_i2c_write_bytes(struct i2c_client *client, uint8_t *data, uint16_t len)
{
 struct i2c_msg msg;
 int ret=-1;
 
 msg.flags = !I2C_M_RD;
 msg.addr = client->addr;
 msg.len = len;
 msg.buf = data;  
 
 ret=i2c_transfer(client->adapter, &msg,1);
 return ret;
}

 

bool ctp_i2c_test(struct i2c_client * client)
{
 int ret,retry;
 uint8_t test_data[1] = { 0 }; //only write a data address.

 

 for(retry=0; retry < 2; retry++)
 {
  ret =ctp_i2c_write_bytes(client, test_data, 1); //Test i2c.
  if (ret == 1)
   break;
  msleep(50);
 }

 

 return ret==1 ? true : false;
}

 

static int ctp_detect(struct i2c_client *client, struct i2c_board_info *info)
{
 struct i2c_adapter *adapter = client->adapter;
 int ret;

 

    if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -ENODEV;
   
 if(twi_id == adapter->nr){ //判断I2C通道数,是否和sysconfig.fex中一致
     pr_info("%s: addr= %x\n",__func__,client->addr);
        ret = ctp_i2c_test(client);
        if(!ret){
         pr_info("%s:I2C connection might be something wrong \n",__func__);
         return -ENODEV;
        }else{     
            pr_info("I2C connection sucess!\n");
            strlcpy(info->type, CTP_NAME, I2C_NAME_SIZE);
   pr_info("%s", GSLX680_USED);
      return 0; 
     }

 

 }else{
  return -ENODEV;
 }
}

 

/**
 * ctp_print_info - sysconfig print function
 * return value:
 *
 */
void ctp_print_info(struct ctp_config_info info,int debug_level)
{
 if(debug_level == DEBUG_INIT)
 {
  dprintk(DEBUG_INIT,"info.ctp_used:%d\n",info.ctp_used);
  dprintk(DEBUG_INIT,"info.ctp_name:%s\n",info.name);
  dprintk(DEBUG_INIT,"info.twi_id:%d\n",info.twi_id);
  dprintk(DEBUG_INIT,"info.screen_max_x:%d\n",info.screen_max_x);
  dprintk(DEBUG_INIT,"info.screen_max_y:%d\n",info.screen_max_y);
  dprintk(DEBUG_INIT,"info.revert_x_flag:%d\n",info.revert_x_flag);
  dprintk(DEBUG_INIT,"info.revert_y_flag:%d\n",info.revert_y_flag);
  dprintk(DEBUG_INIT,"info.exchange_x_y_flag:%d\n",info.exchange_x_y_flag);
  dprintk(DEBUG_INIT,"info.irq_gpio_number:%d\n",info.irq_gpio.gpio);
  dprintk(DEBUG_INIT,"info.wakeup_gpio_number:%d\n",info.wakeup_gpio.gpio);
 }
}

 

/**
 * ctp_wakeup - function
 *
 */
int ctp_wakeup(int status,int ms)
{
 dprintk(DEBUG_INIT,"***CTP*** %s:status:%d,ms = %d\n",__func__,status,ms);

 

 if (status == 0) {

 

  if(ms == 0) {
   __gpio_set_value(config_info.wakeup_gpio.gpio, 0);
  }else {
   __gpio_set_value(config_info.wakeup_gpio.gpio, 0);
   msleep(ms);
   __gpio_set_value(config_info.wakeup_gpio.gpio, 1);
  }
 }
 if (status == 1) {
  if(ms == 0) {
   __gpio_set_value(config_info.wakeup_gpio.gpio, 1);
  }else {
   __gpio_set_value(config_info.wakeup_gpio.gpio, 1);
   msleep(ms);
   __gpio_set_value(config_info.wakeup_gpio.gpio, 0);
  }
 }
 msleep(5);

 

 return 0;
}

 

static int gslX680_chip_init(void)

         ctp_wakeup(1,0);
         msleep(20);
         return 0;  
}

 

static int gslX680_shutdown_low(void)
{
        ctp_wakeup(0,0);
 return 0;
}

 

static int gslX680_shutdown_high(void)
{
        ctp_wakeup(1,0);
 return 0;
}

 

static inline u16 join_bytes(u8 a, u8 b)
{
 u16 ab = 0;
 ab = ab | a;
 ab = ab << 8 | b;
 return ab;
}

 

#if 0
static u32 gsl_read_interface(struct i2c_client *client, u8 reg, u8 *buf, u32 num)
{
 struct i2c_msg xfer_msg[2];

 

 xfer_msg[0].addr = client->addr;
 xfer_msg[0].len = 1;
 xfer_msg[0].flags = client->flags & I2C_M_TEN;
 xfer_msg[0].buf = &reg;

 

 xfer_msg[1].addr = client->addr;
 xfer_msg[1].len = num;
 xfer_msg[1].flags |= I2C_M_RD;
 xfer_msg[1].buf = buf;

 

 if (reg < 0x80) {
  i2c_transfer(client->adapter, xfer_msg, ARRAY_SIZE(xfer_msg));
  msleep(5);
 }

 

 return i2c_transfer(client->adapter, xfer_msg, ARRAY_SIZE(xfer_msg)) == ARRAY_SIZE(xfer_msg) ? 0 : -EFAULT;
}
#endif

 

static u32 gsl_write_interface(struct i2c_client *client, const u8 reg, u8 *buf, u32 num)
{
 struct i2c_msg xfer_msg[1];

 

 buf[0] = reg;

 

 xfer_msg[0].addr = client->addr;
 xfer_msg[0].len = num + 1;
 xfer_msg[0].flags = client->flags & I2C_M_TEN;
 xfer_msg[0].buf = buf;

 

 return i2c_transfer(client->adapter, xfer_msg, 1) == 1 ? 0 : -EFAULT;
}

 

static int gsl_ts_write(struct i2c_client *client, u8 addr, u8 *pdata, int datalen)
{
 int ret = 0;
 u8 tmp_buf[128];
 unsigned int bytelen = 0;
 if (datalen > 125){
  printk("%s too big datalen = %d!\n", __func__, datalen);
  return -1;
 }
 
 tmp_buf[0] = addr;
 bytelen++;
 
 if (datalen != 0 && pdata != NULL){
  memcpy(&tmp_buf[bytelen], pdata, datalen);
  bytelen += datalen;
 }
 
 ret = i2c_master_send(client, tmp_buf, bytelen);//发送成功,则返回字节数,bytelen
 return ret;
}

 

static int gsl_ts_read(struct i2c_client *client, u8 addr, u8 *pdata, unsigned int datalen)
{
 int ret = 0;

 

 if (datalen > 126){
  printk("%s too big datalen = %d!\n", __func__, datalen);
  return -1;
 }

 

 ret = gsl_ts_write(client, addr, NULL, 0); //client是从机
 if (ret < 0){
  printk("%s set data address fail!\n", __func__);
  return ret;
 }
/*
i2c_master_send 接口的三个参数:client 为此次与主机通信的从机,
buf 为发送的数据指针,count 为发送数据的字节数

 

i2c_master_recv 接口的三个参数:client 为此次与主机通信的从机,
buf 为接收的数据指针,count 为接收数据的字节数

 

//i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)//
adap 为此次主机与从机通信的适配器;msgs 为通信的数据包,
这里可以是单个或多个数据包;num 用于指定数据包的个数,
如果大于1则表明将进行不止一次的通信。通信一次就需要寻址一次,
如果需要多次通信就需要多次寻址,前面2个接口都是进行一次通信,
所以 num 为1;有的情况下我们要读一个寄存器的值,
就需要先向从机发送一个寄存器地址然后再接收数据,
这样如果想自己封装一个接口就需要将 num 设置为2
成功则返回传输的数据包个数
*/
 return i2c_master_recv(client, pdata, datalen);
}

 

static ssize_t gslX680_reg_show(
 struct device *dev,
 struct device_attribute *attr,
 char *buf)
{
         u8 mem_buf[4]  = {0};
         u8 int_buf[4]  = {0};
 u8 power_buf[4]  = {0};
         u8 point_buf = 0;

 

         gsl_ts_read(ts_init->client,0xb0, mem_buf, sizeof(mem_buf));
         printk("check mem read 0xb0  = %x %x %x %x \n",
                   mem_buf[3], mem_buf[2], mem_buf[1], mem_buf[0]);
         gsl_ts_read(ts_init->client,0xb4, int_buf, sizeof(int_buf));
         printk("int  num  read  0xb4  = %d \n",
                           (int_buf[3]<<24) |( int_buf[2]<<16 ) |(int_buf[1]<<8) |int_buf[0]);
         gsl_ts_read(ts_init->client,0xbc, power_buf, sizeof(power_buf));
         printk("power check read 0xbc = %4x \n",
                           (power_buf[3]<<24) |( power_buf[2]<<16 ) |(power_buf[1]<<8) |power_buf[0]);
         gsl_ts_read(ts_init->client,0x80, &point_buf, 1);
         printk("point count read  0x80 = %d \n",point_buf);

 

         return sprintf(buf, "[check mem read = 0x%4x ]  [int num read = %d ]  [power check read = 0x%4x ]  [point count read = %d ] \n",
  (mem_buf[3]<<24) |( mem_buf[2]<<16 ) |(mem_buf[1]<<8) |mem_buf[0] ,
  (int_buf[3]<<24) |( int_buf[2]<<16 ) |(int_buf[1]<<8) |int_buf[0],
  (power_buf[3]<<24) |( power_buf[2]<<16 ) |(power_buf[1]<<8) |power_buf[0],point_buf);
}

 

static DEVICE_ATTR(debug_reg, 0664, gslX680_reg_show, NULL);

 

static __inline__ void fw2buf(u8 *buf, const u32 *fw)
{
 u32 *u32_buf = (int *)buf;
 *u32_buf = *fw;
}

 

static int gsl_find_fw_idx(const char* name)
{
 int i = 0;

 

 if (NULL != name) {
  for (i=0; i<ARRAY_SIZE(gslx680_fw_grp); i++) {
   if (!strcmp(name, gslx680_fw_grp[i].name))
    return i;
  }
 }
 return -1;
}

 


static void gsl_load_fw(struct i2c_client *client)

 u8 buf[DMA_TRANS_LEN*4 + 1] = {0};
 u8 send_flag = 1;
 u8 *cur = buf + 1;
 u32 source_line = 0;
 u32 source_len;
 const struct fw_data *ptr_fw;
  
 printk("=============gsl_load_fw start==============\n");
 
 ptr_fw = gslx680_fw_grp[fw_index].fw;
 source_len = gslx680_fw_grp[fw_index].size;   
 
 for (source_line = 0; source_line < source_len; source_line++)
 {
  /* init page trans, set the page val */
  if (GSL_PAGE_REG == ptr_fw[source_line].offset)
  {
   fw2buf(cur, &ptr_fw[source_line].val);
   gsl_write_interface(client, GSL_PAGE_REG, buf, 4);
   send_flag = 1;
  }
  else
  {
   if (1 == send_flag % (DMA_TRANS_LEN < 0x20 ? DMA_TRANS_LEN : 0x20))
        buf[0] = (u8)ptr_fw[source_line].offset;

 

   fw2buf(cur, &ptr_fw[source_line].val);
   cur += 4;

 

   if (0 == send_flag % (DMA_TRANS_LEN < 0x20 ? DMA_TRANS_LEN : 0x20))
   {
        gsl_write_interface(client, buf[0], buf, cur - buf - 1);
        cur = buf + 1;
   }

 

   send_flag++;
  }
 }

 

 printk("=============gsl_load_fw end==============\n");

 

}

 

static void startup_chip(struct i2c_client *client)
{
 u8 tmp = 0x00;

 

#ifdef GSL_NOID_VERSION
 gsl_DataInit(gslX680_config_data[fw_index]);
#endif
 gsl_ts_write(client, 0xe0, &tmp, 1);
 msleep(10);
}

 

static void reset_chip(struct i2c_client *client)
{
 u8 tmp = 0x88;
 u8 buf[4] = {0x00};
 
 gsl_ts_write(client, 0xe0, &tmp, sizeof(tmp));
 msleep(10);

 

 tmp = 0x04;
 gsl_ts_write(client, 0xe4, &tmp, sizeof(tmp));
 msleep(10);
 gsl_ts_write(client, 0xbc, buf, sizeof(buf));
 msleep(10);
}

 

static void clr_reg(struct i2c_client *client)
{
 u8 write_buf[4] = {0};

 

 write_buf[0] = 0x88;
 gsl_ts_write(client, 0xe0, &write_buf[0], 1);  
 msleep(20);
 write_buf[0] = 0x03;
 gsl_ts_write(client, 0x80, &write_buf[0], 1);  
 msleep(5);
 write_buf[0] = 0x04;
 gsl_ts_write(client, 0xe4, &write_buf[0], 1);  
 msleep(5);
 write_buf[0] = 0x00;
 gsl_ts_write(client, 0xe0, &write_buf[0], 1);  
 msleep(20);
}

 

static void init_chip(struct i2c_client *client)
{
 gslX680_shutdown_low(); 
 msleep(50);  
 gslX680_shutdown_high(); 
 msleep(30);   
 clr_reg(client);
 reset_chip(client);
 gsl_load_fw(client);   
 startup_chip(client);
 reset_chip(client);
 startup_chip(client); 
}

 

static void check_mem_data(struct i2c_client *client)
{
 u8 read_buf[4]  = {0};

 

 //if(gsl_chipType_new == 1) 
 {
          if(ts_init->is_suspended != false)
                         msleep(30);
  gsl_ts_read(client,0xb0, read_buf, sizeof(read_buf));
  printk("#########check mem read 0xb0 = %x %x %x %x #########\n", read_buf[3], read_buf[2], read_buf[1], read_buf[0]);
 
  if (read_buf[3] != 0x5a || read_buf[2] != 0x5a || read_buf[1] != 0x5a || read_buf[0] != 0x5a)
  {
   init_chip(client);
  }
 }
}
#ifdef STRETCH_FRAME
static void stretch_frame(u16 *x, u16 *y)
{
 u16 temp_x = *x;
 u16 temp_y = *y;
 u16 temp_0, temp_1, temp_2;

 

 if(temp_x < X_STRETCH_MAX + X_STRETCH_CUST)
 {
  temp_0 = temp_1 = temp_2 = 0;
  temp_0 = X_STRETCH_MAX + X_STRETCH_CUST - temp_x;
  temp_0 = temp_0 > X_STRETCH_CUST ? X_STRETCH_CUST : temp_0;
  temp_0 = temp_0*(100 + X_RATIO_CUST)/100;
  if(temp_x < X_STRETCH_MAX)
  {
   temp_1 = X_STRETCH_MAX - temp_x;
   temp_1 = temp_1 > X_STRETCH_MAX/4 ? X_STRETCH_MAX/4 : temp_1;
   temp_1 = temp_1*(100 + 2*XL_RATIO_1)/100;
  } 
  if(temp_x < 3*X_STRETCH_MAX/4)
  {
   temp_2 = 3*X_STRETCH_MAX/4 - temp_x;
   temp_2 = temp_2*(100 + 2*XL_RATIO_2)/100;
  }
  *x = (temp_0 + temp_1 +temp_2) < (X_STRETCH_MAX + X_STRETCH_CUST) ? ((X_STRETCH_MAX + X_STRETCH_CUST) - (temp_0 + temp_1 +temp_2)) : 1;
 }
 else if(temp_x > (CTP_MAX_X -X_STRETCH_MAX - X_STRETCH_CUST))
 {
  temp_0 = temp_1 = temp_2 = 0;
  temp_0 = temp_x - (CTP_MAX_X -X_STRETCH_MAX - X_STRETCH_CUST);
  temp_0 = temp_0 > X_STRETCH_CUST ? X_STRETCH_CUST : temp_0;
  temp_0 = temp_0*(100 + X_RATIO_CUST)/100;
  if(temp_x > (CTP_MAX_X -X_STRETCH_MAX))
  {
   temp_1 = temp_x - (CTP_MAX_X -X_STRETCH_MAX);
   temp_1 = temp_1 > X_STRETCH_MAX/4 ? X_STRETCH_MAX/4 : temp_1;
   temp_1 = temp_1*(100 + 2*XR_RATIO_1)/100;
  } 
  if(temp_x > (CTP_MAX_X -3*X_STRETCH_MAX/4))
  {
   temp_2 = temp_x - (CTP_MAX_X -3*X_STRETCH_MAX/4);
   temp_2 = temp_2*(100 + 2*XR_RATIO_2)/100;
  }
  *x = (temp_0 + temp_1 +temp_2) < (X_STRETCH_MAX + X_STRETCH_CUST) ? ((CTP_MAX_X -X_STRETCH_MAX - X_STRETCH_CUST) + (temp_0 + temp_1 +temp_2)) : (CTP_MAX_X - 1);
 }
  
 if(temp_y < Y_STRETCH_MAX + Y_STRETCH_CUST)
 {
  temp_0 = temp_1 = temp_2 = 0;
  temp_0 = Y_STRETCH_MAX + Y_STRETCH_CUST - temp_y;
  temp_0 = temp_0 > Y_STRETCH_CUST ? Y_STRETCH_CUST : temp_0;
  temp_0 = temp_0*(100 + Y_RATIO_CUST)/100;
  if(temp_y < Y_STRETCH_MAX)
  {
   temp_1 = Y_STRETCH_MAX - temp_y;
   temp_1 = temp_1 > Y_STRETCH_MAX/4 ? Y_STRETCH_MAX/4 : temp_1;
   temp_1 = temp_1*(100 + 2*YL_RATIO_1)/100;
  } 
  if(temp_y < 3*Y_STRETCH_MAX/4)
  {
   temp_2 = 3*Y_STRETCH_MAX/4 - temp_y;
   temp_2 = temp_2*(100 + 2*YL_RATIO_2)/100;
  }
  *y = (temp_0 + temp_1 +temp_2) < (Y_STRETCH_MAX + Y_STRETCH_CUST) ? ((Y_STRETCH_MAX + Y_STRETCH_CUST) - (temp_0 + temp_1 +temp_2)) : 1;
 }
 else if(temp_y > (CTP_MAX_Y -Y_STRETCH_MAX - Y_STRETCH_CUST))
 {
  temp_0 = temp_1 = temp_2 = 0; 
  temp_0 = temp_y - (CTP_MAX_Y -Y_STRETCH_MAX - Y_STRETCH_CUST);
  temp_0 = temp_0 > Y_STRETCH_CUST ? Y_STRETCH_CUST : temp_0;
  temp_0 = temp_0*(100 + Y_RATIO_CUST)/100;
  if(temp_y > (CTP_MAX_Y -Y_STRETCH_MAX))
  {
   temp_1 = temp_y - (CTP_MAX_Y -Y_STRETCH_MAX);
   temp_1 = temp_1 > Y_STRETCH_MAX/4 ? Y_STRETCH_MAX/4 : temp_1;
   temp_1 = temp_1*(100 + 2*YR_RATIO_1)/100;
  } 
  if(temp_y > (CTP_MAX_Y -3*Y_STRETCH_MAX/4))
  {
   temp_2 = temp_y - (CTP_MAX_Y -3*Y_STRETCH_MAX/4);
   temp_2 = temp_2*(100 + 2*YR_RATIO_2)/100;
  }
  *y = (temp_0 + temp_1 +temp_2) < (Y_STRETCH_MAX + Y_STRETCH_CUST) ? ((CTP_MAX_Y -Y_STRETCH_MAX - Y_STRETCH_CUST) + (temp_0 + temp_1 +temp_2)) : (CTP_MAX_Y - 1);
 }
}
#endif

 

#ifdef FILTER_POINT
static void filter_point(u16 x, u16 y , u8 id)
{
 u16 x_err =0;
 u16 y_err =0;
 u16 filter_step_x = 0, filter_step_y = 0;
 
 id_sign[id] = id_sign[id] + 1;
 if(id_sign[id] == 1)
 {
  x_old[id] = x;
  y_old[id] = y;
 }
 
 x_err = x > x_old[id] ? (x -x_old[id]) : (x_old[id] - x);
 y_err = y > y_old[id] ? (y -y_old[id]) : (y_old[id] - y);

 

 if( (x_err > FILTER_MAX && y_err > FILTER_MAX/3) || (x_err > FILTER_MAX/3 && y_err > FILTER_MAX) )
 {
  filter_step_x = x_err;
  filter_step_y = y_err;
 }
 else
 {
  if(x_err > FILTER_MAX)
   filter_step_x = x_err;
  if(y_err> FILTER_MAX)
   filter_step_y = y_err;
 }

 

 if(x_err <= 2*FILTER_MAX && y_err <= 2*FILTER_MAX)
 {
  filter_step_x >>= 2;
  filter_step_y >>= 2;
 }
 else if(x_err <= 3*FILTER_MAX && y_err <= 3*FILTER_MAX)
 {
  filter_step_x >>= 1;
  filter_step_y >>= 1;
 } 
 else if(x_err <= 4*FILTER_MAX && y_err <= 4*FILTER_MAX)
 {
  filter_step_x = filter_step_x*3/4;
  filter_step_y = filter_step_y*3/4;
 } 
 
 x_new = x > x_old[id] ? (x_old[id] + filter_step_x) : (x_old[id] - filter_step_x);
 y_new = y > y_old[id] ? (y_old[id] + filter_step_y) : (y_old[id] - filter_step_y);

 

 x_old[id] = x_new;
 y_old[id] = y_new;
}
#else

 

static void record_point(u16 x, u16 y , u8 id)
{
 u16 x_err =0;
 u16 y_err =0;

 

 id_sign[id]=id_sign[id]+1;
 
 if(id_sign[id]==1){
  x_old[id]=x;
  y_old[id]=y;
 }

 

 x = (x_old[id] + x)/2;
 y = (y_old[id] + y)/2;
  
 if(x>x_old[id]){
  x_err=x -x_old[id];
 }
 else{
  x_err=x_old[id]-x;
 }

 

 if(y>y_old[id]){
  y_err=y -y_old[id];
 }
 else{
  y_err=y_old[id]-y;
 }

 

 if( (x_err > 3 && y_err > 1) || (x_err > 1 && y_err > 3) ){
  x_new = x;     x_old[id] = x;
  y_new = y;     y_old[id] = y;
 }
 else{
  if(x_err > 3){
   x_new = x;     x_old[id] = x;
  }
  else
   x_new = x_old[id];
  if(y_err> 3){
   y_new = y;     y_old[id] = y;
  }
  else
   y_new = y_old[id];
 }

 

 if(id_sign[id]==1){
  x_new= x_old[id];
  y_new= y_old[id];
 }
 
}
#endif
#ifdef TPD_PROC_DEBUG
static int char_to_int(char ch)
{
 if(ch>='0' && ch<='9')
  return (ch-'0');
 else
  return (ch-'a'+10);
}

 

static int gsl_config_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
{
 char *ptr = page;
 char temp_data[5] = {0};
 unsigned int tmp=0;
 if('v'==gsl_read[0]&&'s'==gsl_read[1])
 {
#ifdef GSL_NOID_VERSION
  tmp=gsl_version_id();
#else
  tmp=0x20121215;
#endif
  ptr += sprintf(ptr,"version:%x\n",tmp);
 }
 else if('r'==gsl_read[0]&&'e'==gsl_read[1])
 {
  if('i'==gsl_read[3])
  {
#ifdef GSL_NOID_VERSION
   tmp=(gsl_data_proc[5]<<8) | gsl_data_proc[4];
   ptr +=sprintf(ptr,"gsl_config_data_id[%u] = ",tmp);
   if(tmp>=0&&tmp<256)
    ptr +=sprintf(ptr,"%d\n",gsl_config_data_id_d7[tmp]);
#endif
  }
  else
  {
   gsl_ts_write(glsX680_i2c,0xf0,&gsl_data_proc[4],4);
   gsl_ts_read(glsX680_i2c,gsl_data_proc[0],temp_data,4);
   gsl_ts_read(glsX680_i2c,gsl_data_proc[0],temp_data,4);
   ptr +=sprintf(ptr,"offset : {0x%02x,0x",gsl_data_proc[0]);
   ptr +=sprintf(ptr,"%02x",temp_data[3]);
   ptr +=sprintf(ptr,"%02x",temp_data[2]);
   ptr +=sprintf(ptr,"%02x",temp_data[1]);
   ptr +=sprintf(ptr,"%02x};\n",temp_data[0]);
  }
 }
 *eof = 1;
 return (ptr - page);
}
static int gsl_config_write_proc(struct file *file, const char *buffer, unsigned long count, void *data)
{
 u8 buf[8] = {0};
 int tmp = 0;
 int tmp1 = 0;

 

 
 if(count > CONFIG_LEN)
 {
  printk("size not match [%d:%ld]\n", CONFIG_LEN, count);
        return -EFAULT;
 }
 
 if(copy_from_user(gsl_read, buffer, (count<CONFIG_LEN?count:CONFIG_LEN)))
 {
  printk("copy from user fail\n");
        return -EFAULT;
 }
 dprintk(DEBUG_OTHERS_INFO,"[tp-gsl][%s][%s]\n",__func__,gsl_read);

 

 buf[3]=char_to_int(gsl_read[14])<<4 | char_to_int(gsl_read[15]); 
 buf[2]=char_to_int(gsl_read[16])<<4 | char_to_int(gsl_read[17]);
 buf[1]=char_to_int(gsl_read[18])<<4 | char_to_int(gsl_read[19]);
 buf[0]=char_to_int(gsl_read[20])<<4 | char_to_int(gsl_read[21]);
 
 buf[7]=char_to_int(gsl_read[5])<<4 | char_to_int(gsl_read[6]);
 buf[6]=char_to_int(gsl_read[7])<<4 | char_to_int(gsl_read[8]);
 buf[5]=char_to_int(gsl_read[9])<<4 | char_to_int(gsl_read[10]);
 buf[4]=char_to_int(gsl_read[11])<<4 | char_to_int(gsl_read[12]);
 if('v'==gsl_read[0]&& 's'==gsl_read[1])//version //vs
 {
  printk("gsl version\n");
 }
 else if('s'==gsl_read[0]&& 't'==gsl_read[1])//start //st
 {
  gsl_proc_flag = 1;
  reset_chip(glsX680_i2c);
 }
 else if('e'==gsl_read[0]&&'n'==gsl_read[1])//end //en
 {
  msleep(20);
  reset_chip(glsX680_i2c);
  startup_chip(glsX680_i2c);
  
#ifdef GSL_NOID_VERSION
  gsl_DataInit(gslX680_config_data[fw_index]);  
#endif
  gsl_proc_flag = 0;
 }
 else if('r'==gsl_read[0]&&'e'==gsl_read[1])//read buf //
 {
  memcpy(gsl_data_proc,buf,8);
 }
 else if('w'==gsl_read[0]&&'r'==gsl_read[1])//write buf
 {
  gsl_ts_write(glsX680_i2c,buf[4],buf,4);
 }
 
#ifdef GSL_NOID_VERSION
 else if('i'==gsl_read[0]&&'d'==gsl_read[1])//write id config //
 {
  tmp1=(buf[7]<<24)|(buf[6]<<16)|(buf[5]<<8)|buf[4];
  tmp=(buf[3]<<24)|(buf[2]<<16)|(buf[1]<<8)|buf[0];
  if(tmp1>=0 && tmp1<256)
  {
   gslX680_config_data[fw_index][tmp1] = tmp;
  }
 }
#endif
 return count;
}
#endif
#ifdef HAVE_TOUCH_KEY
static void report_key(struct gsl_ts *ts, u16 x, u16 y)
{
 u16 i = 0;
 for(i = 0; i < MAX_KEY_NUM; i++) {
  if((gsl_key_data[i].x_min < x) && (x < gsl_key_data[i].x_max)&&(gsl_key_data[i].y_min < y) &&\
    (y < gsl_key_data[i].y_max)){
   key = gsl_key_data[i].key; 
   dprintk(DEBUG_KEY_INFO,"key=%d\n",key);
   input_report_key(ts->input, key, 1);
   input_sync(ts->input);   
   key_state_flag = 1;
   break;
  }
 }
}
#endif

 

static void report_data(struct gsl_ts *ts, u16 x, u16 y, u8 pressure, u8 id)
{
 dprintk(DEBUG_X_Y_INFO,"source data:ID:%d, X:%d, Y:%d, W:%d\n", id, x, y,pressure);
 if(1 == exchange_x_y_flag){
  swap(x, y);
 }
 if(1 == revert_x_flag){
  x = SCREEN_MAX_X - x;
 }
 if(1 == revert_y_flag){
  y = SCREEN_MAX_Y - y;
 }
 dprintk(DEBUG_X_Y_INFO,"report data:ID:%d, X:%d, Y:%d, W:%d\n", id, x, y, pressure);
   
 if(x>SCREEN_MAX_X||y>SCREEN_MAX_Y)
 {
 #ifdef HAVE_TOUCH_KEY
  
  report_key(ts,x,y);

 

 #endif
  return;
 }
 
#ifdef REPORT_DATA_ANDROID_4_0
 input_mt_slot(ts->input, id);  
 input_report_abs(ts->input, ABS_MT_TRACKING_ID, id);
 input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, pressure);
 input_report_abs(ts->input, ABS_MT_POSITION_X, x);
 input_report_abs(ts->input, ABS_MT_POSITION_Y, y); 
 input_report_abs(ts->input, ABS_MT_WIDTH_MAJOR, 1);
#else
 input_report_abs(ts->input, ABS_MT_TRACKING_ID, id);
 input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, pressure); //相当于单点屏的ABX_PRESSURE
 input_report_abs(ts->input, ABS_MT_POSITION_X,x);
 input_report_abs(ts->input, ABS_MT_POSITION_Y, y);
 input_report_abs(ts->input, ABS_MT_WIDTH_MAJOR, 1);  //相当于单点屏的ABS_TOOL_WIDTH
 input_mt_sync(ts->input);
 /*
 由于多点触摸技术需要采集到多个点,然后再一起处理这些点,
 所以在软件实现中需要保证每一波点的准确性和完整性。因此,
 Linux内核提供了input_mt_sync(struct input_dev * input)函数。
 在每波的每个点上报后需要紧跟一句input_mt_sync(), 当这波所有点上报后再使用input_sync()进行同步
 */
#endif
}

 


static void process_gslX680_data(struct gsl_ts *ts)
{
 u8 id, touches;
 u16 x, y;
 int i = 0;
 int tmp1 = 0;
 u8 buf[4]={0};
#ifdef GSL_NOID_VERSION
    struct gsl_touch_info cinfo;
#endif
 touches = ts->touch_data[ts->dd->touch_index];
#ifdef GSL_NOID_VERSION
 cinfo.finger_num = touches;
 dprintk(DEBUG_OTHERS_INFO,"tp-gsl  finger_num = %d\n",cinfo.finger_num);
 for(i = 0; i < (touches < MAX_CONTACTS ? touches : MAX_CONTACTS); i ++)
 {
  cinfo.x[i] = join_bytes( ( ts->touch_data[ts->dd->x_index  + 4 * i + 1] & 0xf),
    ts->touch_data[ts->dd->x_index + 4 * i]);
  cinfo.y[i] = join_bytes(ts->touch_data[ts->dd->y_index + 4 * i + 1],
    ts->touch_data[ts->dd->y_index + 4 * i ]);
 }
 cinfo.finger_num = ts->touch_data[0] | (ts->touch_data[1]<<8)|(ts->touch_data[2]<<16)|
  (ts->touch_data[3]<<24);
 gsl_alg_id_main(&cinfo);
 dprintk(DEBUG_OTHERS_INFO,"tp-gsl  finger_num = %d\n",cinfo.finger_num);
 tmp1=gsl_mask_tiaoping();
 if(tmp1>0&&tmp1<0xffffffff)
 {
  buf[0]=0xa;
  buf[1]=0;
  buf[2]=0;
  buf[3]=0;
  gsl_ts_write(ts->client,0xf0,buf,4);
  buf[0]=(u8)(tmp1 & 0xff);
  buf[1]=(u8)((tmp1>>8) & 0xff);
  buf[2]=(u8)((tmp1>>16) & 0xff);
  buf[3]=(u8)((tmp1>>24) & 0xff);
  printk("tmp1=%08x,buf[0]=%02x,buf[1]=%02x,buf[2]=%02x,buf[3]=%02x\n",
   tmp1,buf[0],buf[1],buf[2],buf[3]);
  gsl_ts_write(ts->client,0x8,buf,4);
 }
 touches = cinfo.finger_num;

 

#endif
 for(i=1;i<=MAX_CONTACTS;i++){
  if(touches == 0)
   id_sign[i] = 0; 
  id_state_flag[i] = 0;
 }
 for(i= 0;i < (touches > MAX_FINGERS ? MAX_FINGERS : touches);i++)
 {
 #ifdef GSL_NOID_VERSION
  id = cinfo.id[i];
  x =  cinfo.x[i];
  y =  cinfo.y[i]; 
 #else
  x = join_bytes( ( ts->touch_data[ts->dd->x_index  + 4 * i + 1] & 0xf),
    ts->touch_data[ts->dd->x_index + 4 * i]);
  y = join_bytes(ts->touch_data[ts->dd->y_index + 4 * i + 1],
    ts->touch_data[ts->dd->y_index + 4 * i ]);
  id = ts->touch_data[ts->dd->id_index + 4 * i] >> 4;
    #endif
  if(1 <=id && id <= MAX_CONTACTS)
  {

 

  #ifdef STRETCH_FRAME
   stretch_frame(&x, &y);
  
  #endif
  #ifdef FILTER_POINT
   filter_point(x, y ,id);
  #else
   record_point(x, y , id);
  #endif
   report_data(ts, x_new, y_new, 10, id);  
   id_state_flag[id] = 1;
  }
 }
 
 
 for(i = 1;i <= MAX_CONTACTS ; i++)
 {
  if( (0 == touches) || ((0 != id_state_old_flag[i]) && (0 == id_state_flag[i])) ){
  #ifdef REPORT_DATA_ANDROID_4_0
   input_mt_slot(ts->input, i);
   input_report_abs(ts->input, ABS_MT_TRACKING_ID, -1);
   input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, false);
  #endif
   id_sign[i]=0;
  }
  id_state_old_flag[i] = id_state_flag[i];
 }
#ifndef REPORT_DATA_ANDROID_4_0
 if(0 == touches){ 
  input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, 0);
         input_report_abs(ts->input, ABS_MT_WIDTH_MAJOR, 0);
  input_mt_sync(ts->input);
 #ifdef HAVE_TOUCH_KEY
 if(key_state_flag){
        input_report_key(ts->input, key, 0);
  input_sync(ts->input);
  key_state_flag = 0;
 }
 #endif   
 }
#endif
 input_sync(ts->input);
 ts->prev_touches = touches;
}

 


static void gsl_ts_xy_worker(struct work_struct *work)
{
 int rc;
 u8 read_buf[4] = {0};
 struct gsl_ts *ts = container_of(work, struct gsl_ts,work);
 /*
 container_of(ptr,type,member)已知结构体type的成员member的地址ptr,求解结构体type的地址
 */
#ifndef GSL_TIMER
 int ret;
 input_set_int_enable(&(config_info.input_type), 0);
#endif
 dprintk(DEBUG_X_Y_INFO,"---gsl_ts_xy_worker---\n");    
#ifdef TPD_PROC_DEBUG
 if(gsl_proc_flag == 1){
  goto schedule;
 }
#endif
 /* read data from DATA_REG */
 rc = gsl_ts_read(ts->client, 0x80, ts->touch_data, ts->dd->data_size);
 dprintk(DEBUG_X_Y_INFO,"---touches: %d ---\n",ts->touch_data[0]);   
 if (rc < 0) {
  dev_err(&ts->client->dev, "read failed\n");
  goto schedule;
 }

 

 if (ts->touch_data[ts->dd->touch_index] == 0xff) {
  goto schedule;
 }

 

 rc = gsl_ts_read( ts->client, 0xbc, read_buf, sizeof(read_buf));
 if (rc < 0) {
  dev_err(&ts->client->dev, "read 0xbc failed\n");
  goto schedule;
 }
 dprintk(DEBUG_X_Y_INFO,"reg %x : %x %x %x %x\n",0xbc, read_buf[3], read_buf[2], read_buf[1], read_buf[0]);  
 if (read_buf[3] == 0 && read_buf[2] == 0 && read_buf[1] == 0 && read_buf[0] == 0){
  process_gslX680_data(ts); //process_gslX680_data(ts)这函数里实现循环上报
 }
 else
 {
  reset_chip(ts->client);
  startup_chip(ts->client);
 }
 
schedule:
#ifndef GSL_TIMER
    ret = input_set_int_enable(&(config_info.input_type), 1);
 if (ret < 0)
  dprintk(DEBUG_SUSPEND,"%s irq enable failed\n", __func__);
#endif
}

 


#ifdef GSL_MONITOR
static void gsl_monitor_worker(struct work_struct *work)
{
 char read_buf[4]  = {0};
 
 dprintk(DEBUG_OTHERS_INFO,"---------------gsl_monitor_worker-----------------\n");

 

 gsl_ts_read(glsX680_i2c, 0xb4, read_buf, 4);
 int_2nd[3] = int_1st[3];
 int_2nd[2] = int_1st[2];
 int_2nd[1] = int_1st[1];
 int_2nd[0] = int_1st[0];
 int_1st[3] = read_buf[3];
 int_1st[2] = read_buf[2];
 int_1st[1] = read_buf[1];
 int_1st[0] = read_buf[0];

 

 if (int_1st[3] == int_2nd[3] && int_1st[2] == int_2nd[2] &&int_1st[1] == int_2nd[1] && int_1st[0] == int_2nd[0])
 {
  printk("======int_1st: %x %x %x %x , int_2nd: %x %x %x %x ======\n",int_1st[3], int_1st[2], int_1st[1], int_1st[0], int_2nd[3], int_2nd[2],int_2nd[1],int_2nd[0]);
  init_chip(glsX680_i2c);
 }
 queue_delayed_work(gsl_monitor_workqueue, &gsl_monitor_work, 300);
}
#endif

 


irqreturn_t gsl_ts_irq(int irq, void *dev_id)
{
 struct gsl_ts *ts = (struct gsl_ts *)dev_id;
 dprintk(DEBUG_INT_INFO,"==========GSLX680 Interrupt============\n");
 queue_work(ts->wq, &ts->work);
#ifdef GSL_TIMER
 mod_timer(&ts->gsl_timer, jiffies + msecs_to_jiffies(30));
#endif
 return IRQ_HANDLED;
}

 


#ifdef GSL_TIMER
static void gsl_timer_handle(unsigned long data)
{
 struct gsl_ts *ts = (struct gsl_ts *)data;

 

#ifdef GSL_DEBUG 
 printk("----------------gsl_timer_handle-----------------\n"); 
#endif
    ret = input_set_int_enable(&(config_info.input_type), 1);
 if (ret < 0)
  dprintk(DEBUG_SUSPEND,"%s irq disable failed\n", __func__);
 check_mem_data(ts->client);
 ts->gsl_timer.expires = jiffies + 3 * HZ;
 add_timer(&ts->gsl_timer);
 //enable_irq(ts->irq);
 
}
#endif

 

static int gsl_ts_init_ts(struct i2c_client *client, struct gsl_ts *ts)
{
 struct input_dev *input_device;
 int  rc = 0;
#ifdef HAVE_TOUCH_KEY
 int i= 0;
#endif
 printk("[GSLX680] Enter %s\n", __func__);
 ts->dd = &devices[ts->device_id];

 

 if (ts->device_id == 0) {
  ts->dd->data_size = MAX_FINGERS * ts->dd->touch_bytes + ts->dd->touch_meta_data;
  ts->dd->touch_index = 0;
 }

 

 ts->touch_data = kzalloc(ts->dd->data_size, GFP_KERNEL);
 if (!ts->touch_data) {
  pr_err("%s: Unable to allocate memory\n", __func__);
  return -ENOMEM;
 }

 

 ts->prev_touches = 0;

 

 input_device = input_allocate_device();
 if (!input_device) {
  rc = -ENOMEM;
  goto error_alloc_dev;
 }

 

 ts->input = input_device;
 input_device->name = GSLX680_I2C_NAME;
 input_device->id.bustype = BUS_I2C;
 input_device->dev.parent = &client->dev;
 input_set_drvdata(input_device, ts);

 

#ifdef REPORT_DATA_ANDROID_4_0
 __set_bit(EV_ABS, input_device->evbit);
 __set_bit(EV_KEY, input_device->evbit);
 __set_bit(EV_REP, input_device->evbit);
 __set_bit(INPUT_PROP_DIRECT, input_device->propbit);
 input_mt_init_slots(input_device, (MAX_CONTACTS+1));
#else
 input_set_abs_params(input_device,ABS_MT_TRACKING_ID, 0, (MAX_CONTACTS+1), 0, 0);
 set_bit(EV_ABS, input_device->evbit);
 set_bit(EV_KEY, input_device->evbit);
 __set_bit(INPUT_PROP_DIRECT, input_device->propbit);
 input_device->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
 /*
/*__set_bit(int nr, volatile unsigned long *addr)将一个指针指向的数据的第nr位置

 

input_set_abs_params给设备的input_dev结构体初始化,
 这些input_dev的参数会在Android的EventHub.cpp中被读取
 input_set_abs_params(ts->dev, ABS_X, 0, 480, 0, 0);
    input_set_abs_params(ts->dev, ABS_Y, 0, 272, 0, 0);

 

大家在移植别人的触摸屏驱动时一定要注意上面范围的设置。必须要匹配你的屏分辨率 
 

 

 
unsigned long evbit[NBITS(EV_MAX)];   // 表示能产生哪类事件 
unsigned long keybit[NBITS(KEY_MAX)]; // 表示能产生哪些按键 
unsigned long relbit[NBITS(REL_MAX)]; // 表示能产生哪些相对位移事件, x,y,滚轮 
unsigned long absbit[NBITS(ABS_MAX)]; // 表示能产生哪些绝对位移事件, x,y
/* 2.1 设置按键能产生哪类事件
set_bit(EV_KEY,buttons_dev->evbit);  //按键类事件
set_bit(EV_REP,buttons_dev->evbit);  //重复类事件,比如按下按键L能重复打印L;按下后,
能重复帮你上报事件(重复,说明肯定用到定时器)
  
/* 2.2 设置能产生这类操作的哪些事件 
set_bit(KEY_L,buttons_dev->keybit);
 
*/
#endif
#ifdef HAVE_TOUCH_KEY
  //input_device->evbit[0] = BIT_MASK(EV_KEY);
 for (i = 0; i < MAX_KEY_NUM; i++)
  set_bit(key_array[i] & KEY_MAX, input_device->keybit);

 

#endif

 

 set_bit(ABS_MT_POSITION_X, input_device->absbit);
 set_bit(ABS_MT_POSITION_Y, input_device->absbit);
 set_bit(ABS_MT_TOUCH_MAJOR, input_device->absbit);
 set_bit(ABS_MT_WIDTH_MAJOR, input_device->absbit);

 

 input_set_abs_params(input_device,ABS_MT_POSITION_X, 0, SCREEN_MAX_X, 0, 0);
 input_set_abs_params(input_device,ABS_MT_POSITION_Y, 0, SCREEN_MAX_Y, 0, 0);
 input_set_abs_params(input_device,ABS_MT_TOUCH_MAJOR, 0, PRESS_MAX, 0, 0);
 input_set_abs_params(input_device,ABS_MT_WIDTH_MAJOR, 0, 200, 0, 0);

 

 ts->wq = create_singlethread_workqueue("kworkqueue_ts");
 if (!ts->wq) {
  dev_err(&client->dev, "Could not create workqueue\n");
  goto error_wq_create;
 }
 flush_workqueue(ts->wq); 

 

 INIT_WORK(&ts->work, gsl_ts_xy_worker);

 

 rc = input_register_device(input_device);
 if (rc)
  goto error_unreg_device;

 

 return 0;

 

error_unreg_device:
 destroy_workqueue(ts->wq);
error_wq_create:
 input_free_device(input_device);
error_alloc_dev:
 kfree(ts->touch_data);
 return rc;
}

 

static void glsX680_resume_events (struct work_struct *work)
{
#ifndef GSL_TIMER
 int ret;
#endif
 gslX680_shutdown_high();
 msleep(10);
 reset_chip(glsX680_i2c);
 startup_chip(glsX680_i2c);
 check_mem_data(glsX680_i2c);
#ifndef GSL_TIMER
 ret = input_set_int_enable(&(config_info.input_type), 1);
 if (ret < 0)
  dprintk(DEBUG_SUSPEND,"%s irq disable failed\n", __func__);
#endif
}

 

#ifdef CONFIG_PM
static int gsl_ts_suspend(struct i2c_client *client, pm_message_t mesg)
{
#ifndef GSL_TIMER
 int ret;
#endif
        struct gsl_ts *ts = i2c_get_clientdata(client);
        dprintk(DEBUG_SUSPEND,"%s,start\n",__func__);
        cancel_work_sync(&glsX680_resume_work);
        flush_workqueue(gslX680_resume_wq);
   
#ifndef CONFIG_HAS_EARLYSUSPEND
        ts->is_suspended = true;
#endif

 

#ifdef GSL_TIMER
 dprintk(DEBUG_SUSPEND,"gsl_ts_suspend () : delete gsl_timer\n");
 del_timer(&ts->gsl_timer);
#endif
        if(ts->is_suspended == true ){
#ifndef GSL_TIMER
                ret = input_set_int_enable(&(config_info.input_type), 0);
                if (ret < 0)
                       dprintk(DEBUG_SUSPEND,"%s irq disable failed\n", __func__);
#endif
                flush_workqueue(gslX680_resume_wq);
                cancel_work_sync(&ts->work);
                flush_workqueue(ts->wq);
                gslX680_shutdown_low();
        }
  input_set_power_enable(&(config_info.input_type), 0);
       
        return 0;
 
}

 

static int gsl_ts_resume(struct i2c_client *client)
{
 
 struct gsl_ts *ts = i2c_get_clientdata(client);
 input_set_power_enable(&(config_info.input_type), 1);
 
 ts->is_suspended = true;
   dprintk(DEBUG_SUSPEND,"I'am in gsl_ts_resume() start\n");
   cancel_work_sync(&ts->work);
 flush_workqueue(ts->wq);
 queue_work(gslX680_resume_wq, &glsX680_resume_work);
 
#ifdef GSL_TIMER
 dprintk(DEBUG_SUSPEND, "gsl_ts_resume () : add gsl_timer\n");
 init_timer(&ts->gsl_timer);
 ts->gsl_timer.expires = jiffies + 3 * HZ;
 ts->gsl_timer.function = &gsl_timer_handle;
 ts->gsl_timer.data = (unsigned long)ts;
 add_timer(&ts->gsl_timer);
#endif
 return 0;
}
#endif

 

#ifdef CONFIG_HAS_EARLYSUSPEND
static void gsl_ts_early_suspend(struct early_suspend *h)
{
 struct gsl_ts *ts = container_of(h, struct gsl_ts, early_suspend);
#ifndef GSL_TIMER
 int ret = 0;
#endif
 dprintk(DEBUG_SUSPEND,"[GSL1680] Enter %s\n", __func__);
#ifdef TPD_PROC_DEBUG
  if(gsl_proc_flag == 1){
   return;
  }
#endif
#ifdef GSL_MONITOR
 cancel_delayed_work_sync(&gsl_monitor_work);
 flush_workqueue(gsl_monitor_workqueue);
#endif
 cancel_work_sync(&glsX680_resume_work);
 flush_workqueue(gslX680_resume_wq);
        ts->is_suspended = false;
#ifndef GSL_TIMER
    ret = input_set_int_enable(&(config_info.input_type), 0);
 if (ret < 0)
  dprintk(DEBUG_SUSPEND,"%s irq disable failed\n", __func__);
#endif

 

 cancel_work_sync(&ts->work);
 flush_workqueue(ts->wq);
 gslX680_shutdown_low();
 
#ifdef SLEEP_CLEAR_POINT
  msleep(10);   
 #ifdef REPORT_DATA_ANDROID_4_0
  for(i = 1; i <= MAX_CONTACTS ;i ++)
  { 
   input_mt_slot(ts->input, i);
   input_report_abs(ts->input, ABS_MT_TRACKING_ID, -1);
   input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, false);
  }
 #else 
  input_mt_sync(ts->input);
 #endif
  input_sync(ts->input);
  msleep(10);  
  report_data(ts, 1, 1, 10, 1);  
  input_sync(ts->input); 
#endif 

 

}

 

static void gsl_ts_late_resume(struct early_suspend *h)
{
 struct gsl_ts *ts = container_of(h, struct gsl_ts, early_suspend);
#ifndef GSL_TIMER
  int ret = 0;
#endif
        dprintk(DEBUG_SUSPEND,"[GSL1680] Enter %s\n", __func__);
#ifdef TPD_PROC_DEBUG
  if(gsl_proc_flag == 1){
   return;
  }
#endif
 cancel_work_sync(&ts->work);
 flush_workqueue(ts->wq);
 
#ifndef CONFIG_PM
        gsl_ts_resume(ts->client);
#else
        if(ts->is_suspended == false){
                 gslX680_shutdown_high();
         msleep(10);
         reset_chip(glsX680_i2c);
         startup_chip(glsX680_i2c);
#ifndef GSL_TIMER
         ret = input_set_int_enable(&(config_info.input_type), 1);
         if (ret < 0)
   dprintk(DEBUG_SUSPEND,"%s irq disable failed\n", __func__);
#endif
        }
#endif
#ifdef GSL_MONITOR
 printk( "gsl_ts_resume () : queue gsl_monitor_work\n");
 queue_delayed_work(gsl_monitor_workqueue, &gsl_monitor_work, 300);
#endif 

 

}
#endif

 

static void glsX680_init_events (struct work_struct *work)
{
 int ret = 0;

 

 gslX680_chip_init();
 init_chip(glsX680_i2c);
 check_mem_data(glsX680_i2c);

 

#ifndef GSL_TIMER
 config_info.dev = &(ts_init->input->dev);
 ret = input_request_int(&(config_info.input_type), gsl_ts_irq,
    CTP_IRQ_MODE, ts_init);
 if (ret) {
  printk( "glsX680_init_events: request irq failed\n");
 }
#else
 printk( "add gsl_timer\n");
 init_timer(&ts_init->gsl_timer);
 ts_init->gsl_timer.expires = jiffies + msecs_to_jiffies(500);
 ts_init->gsl_timer.function = &gsl_ts_irq;
 ts_init->gsl_timer.data = (unsigned long)ts_init;
 add_timer(&ts_init->gsl_timer);
#endif

 

 return;
}

 

static int __devinit gsl_ts_probe(struct i2c_client *client,
   const struct i2c_device_id *id)
{
 struct gsl_ts *ts;
 int rc = 0;

 

 input_set_power_enable(&(config_info.input_type), 1); //上电
 printk("GSLX680 Enter %s\n", __func__);
 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { //检查I2C功能
  dev_err(&client->dev, "I2C functionality not supported\n");
  return -ENODEV;
 }
 
 ts = kzalloc(sizeof(*ts), GFP_KERNEL);
 if (!ts){
         printk("allocate data fail!\n");
  return -ENOMEM;
 }

 

 /*
 1.INIT_WORK(struct work_struct *work, void (*function)(void *), void *data)
 上面一句只是定义了work和work对应的操作.在实际使用的时候还是需要你去在适当的条件下激活这个work。
只有激活了这个work,  这个work才有运行的机会。这个激活操作接口是shudule_work(&work)或是
queue_work(workqueue_struct:指定的workqueue指针 ,  work_struct:具体任务对象指针)。 
这两个接口之后只是说这个work有了运行的机会,但是具体到什么时候运行,那要看你用哪个接口激活的。 
如果是shudule_work的话,系统中有个events内核线程,这个线程会处理你用shudule_work接口激活  的所有work.
如果是queue_work的话,一般这种情况都是自己创建了一个单独的处理线程,这样将你激活的work和这个线程联系起来。
至于什么时候运行,那就是events或是你定义的特定线程运行的时候。

 

2.至于你提到的为什么要用到work。这个的话,我个人的理解是:一般用在对耗时处理上。比如当中断发生的时候,
你可以在中断上下文中完成激活操作,让那些耗时的操作在work中完成。
*/
    gslX680_wq = create_singlethread_workqueue("gslX680_init");
 if (gslX680_wq == NULL) {
  printk("create gslX680_wq fail!\n");
  return -ENOMEM;
 }
 
 gslX680_resume_wq = create_singlethread_workqueue("gslX680_resume");
 if (gslX680_resume_wq == NULL) {
  printk("create gslX680_resume_wq fail!\n");
  return -ENOMEM;
 }
 
    glsX680_i2c = client;
 ts->client = client;
 i2c_set_clientdata(client, ts);
 ts->device_id = id->driver_data;

 

 ts->is_suspended = false;
 ts->int_pending = false;
 mutex_init(&ts->sus_lock);
 
 rc = gsl_ts_init_ts(client, ts);
/*
gsl_ts_init_ts
 ->input_allocate_device
 ->input_set_abs_params(初始化input_device)
 ->create_singlethread_workqueue("kworkqueue_ts")
 ->INIT_WORK(&ts->work, gsl_ts_xy_worker)
 ->input_register_device(input_device)
*/
 if (rc < 0) {
  dev_err(&client->dev, "GSLX680 init failed\n");
  goto error_mutex_destroy;
 }
 ts_init = ts;
 queue_work(gslX680_wq, &glsX680_init_work);
 /*
 glsX680_init_work
  DECLARE_WORK(glsX680_init_work, glsX680_init_events)
   glsX680_init_events
    input_request_int
     gsl_ts_irq(中断处理)
      queue_work(ts->wq, &ts->work);
       INIT_WORK(&ts->work, gsl_ts_xy_worker)
        gsl_ts_xy_worker
         gsl_ts_read //read data from DATA_REG
          gsl_ts_write(client, addr, NULL, 0)
           i2c_master_send(client, tmp_buf, bytelen)
          return i2c_master_recv(client, pdata, datalen)
         process_gslX680_data(ts)实现循环上报
 */
 
        device_create_file(&ts->input->dev, &dev_attr_debug_reg);
 device_enable_async_suspend(&client->dev);

 

#ifdef TPD_PROC_DEBUG
 gsl_config_proc = create_proc_entry(GSL_CONFIG_PROC_FILE, 0666, NULL);
 if (gsl_config_proc == NULL)
 {
  printk("create_proc_entry %s failed\n", GSL_CONFIG_PROC_FILE);
 }
 else
 {
  gsl_config_proc->read_proc = gsl_config_read_proc;
  gsl_config_proc->write_proc = gsl_config_write_proc;
 }
 gsl_proc_flag = 0;
#endif

 


#ifdef CONFIG_HAS_EARLYSUSPEND
 ts->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1;
 ts->early_suspend.suspend = gsl_ts_early_suspend;
 ts->early_suspend.resume = gsl_ts_late_resume;
 register_early_suspend(&ts->early_suspend);
#endif

 

#ifdef GSL_MONITOR
 printk( "gsl_ts_probe () : queue gsl_monitor_workqueue\n");

 

 INIT_DELAYED_WORK(&gsl_monitor_work, gsl_monitor_worker);
 gsl_monitor_workqueue = create_singlethread_workqueue("gsl_monitor_workqueue");
 queue_delayed_work(gsl_monitor_workqueue, &gsl_monitor_work, 1000);
#endif

 


 input_set_power_enable(&(config_info.input_type), 1); //上电
 
 dprintk(DEBUG_INIT,"[GSLX680] End %s\n", __func__);
 return 0;
   
error_mutex_destroy:
 mutex_destroy(&ts->sus_lock);
 input_free_device(ts->input);
 kfree(ts);
 return rc;
}

 

static int __devexit gsl_ts_remove(struct i2c_client *client)
{
 struct gsl_ts *ts = i2c_get_clientdata(client);
 printk("==gsl_ts_remove=\n");

 

#ifdef CONFIG_HAS_EARLYSUSPEND
 unregister_early_suspend(&ts->early_suspend);
#endif
 device_remove_file(&ts->input->dev, &dev_attr_debug_reg);
#ifdef GSL_MONITOR
 cancel_delayed_work_sync(&gsl_monitor_work);
 destroy_workqueue(gsl_monitor_workqueue);
#endif

 

 device_init_wakeup(&client->dev, 0);
 cancel_work_sync(&ts->work);
 cancel_work_sync(&glsX680_init_work);
 cancel_work_sync(&glsX680_resume_work);

 

#ifndef GSL_TIMER
  input_free_int(&(config_info.input_type), ts);
#else
  del_timer(&ts->gsl_timer);
#endif
 destroy_workqueue(ts->wq);
 destroy_workqueue(gslX680_wq);
 destroy_workqueue(gslX680_resume_wq);
 input_unregister_device(ts->input);
 mutex_destroy(&ts->sus_lock);
 kfree(ts->touch_data);
 kfree(ts);

 

 return 0;
}

 

static const struct i2c_device_id gsl_ts_id[] = {
 {GSLX680_I2C_NAME, 0},
 {}
};
MODULE_DEVICE_TABLE(i2c, gsl_ts_id);

 

static struct i2c_driver gsl_ts_driver = {
 .class = I2C_CLASS_HWMON,
 .driver = {
  .name = GSLX680_I2C_NAME,
  .owner = THIS_MODULE,
 },
 .probe  = gsl_ts_probe,
 .remove  = __devexit_p(gsl_ts_remove),
 .id_table  = gsl_ts_id,
 .address_list = normal_i2c,
 .detect   = ctp_detect,
#ifdef CONFIG_PM
 .suspend = gsl_ts_suspend,
 .resume = gsl_ts_resume,
#endif
};
static int ctp_get_system_config(void)
{     
    ctp_print_info(config_info,DEBUG_INIT);

 

 fwname = config_info.name;
 dprintk(DEBUG_INIT,"%s:fwname:%s\n",__func__,fwname);
 fw_index = gsl_find_fw_idx(fwname); //与sysconfig.fex中的CTP下的ctp_name进行比较匹配,\
 //匹配成功返回gslx680_fw_grp【】中的 i,用于后面加载gslx680_fw_grp【i】中的 GSLX680_FW_D7 TP的硬件寄存器数据
 if (fw_index == -1) {
  printk("gslx680: no matched TP firmware(%s)!\n", fwname);
  return 0;
 }

 

 dprintk(DEBUG_INIT,"fw_index = %d\n",fw_index);
    twi_id = config_info.twi_id;
    screen_max_x = config_info.screen_max_x; //LCD_X 1024
    screen_max_y = config_info.screen_max_y; //LCD_Y 600
    revert_x_flag = config_info.revert_x_flag;
    revert_y_flag = config_info.revert_y_flag;
    exchange_x_y_flag = config_info.exchange_x_y_flag;
 if((screen_max_x == 0) || (screen_max_y == 0)){
           printk("%s:read config error!\n",__func__);
           return 0;
    }
    return 1;
}
static int __init gsl_ts_init(void)
{

 

 int ret = -1;
       
 input_set_power_enable(&(config_info.input_type), 1); //上电
 dprintk(DEBUG_INIT,"****************************************************************\n");
 if (input_fetch_sysconfig_para(&(config_info.input_type))) {
  printk("%s: ctp_fetch_sysconfig_para err.\n", __func__);
  return 0;
 } else {
  ret = input_init_platform_resource(&(config_info.input_type));
  if (0 != ret) {
   printk("%s:ctp_ops.init_platform_resource err. \n", __func__);   
  }
 }
 if (config_info.ctp_used == 0) {
  printk("*** ctp_used set to 0 !\n");
  printk("*** if use ctp,please put the sys_config.fex ctp_used set to 1. \n");
  return 0;
 }
 if (!ctp_get_system_config()) { //获取sysconfig.fex中CTP的初始数据到本地
  printk("%s:read config fail!\n",__func__);
  return ret;
 }
 input_set_power_enable(&(config_info.input_type), 1); //上电
    msleep(20);
 ctp_wakeup(1,0);

 

 ret = i2c_add_driver(&gsl_ts_driver); //添加 I2C驱动gsl_ts_driver
 printk("****************************************************************\n");
 return ret;
}

 

static void __exit gsl_ts_exit(void)
{
 printk("==gsl_ts_exit==\n");
 i2c_del_driver(&gsl_ts_driver);
 input_free_platform_resource(&(config_info.input_type));
 return;
}

 

module_init(gsl_ts_init);
module_exit(gsl_ts_exit);
module_param_named(debug_mask,debug_mask,int,S_IRUGO | S_IWUSR | S_IWGRP);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("GSLX680 touchscreen controller driver");
MODULE_ALIAS("platform:gsl_ts");

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zeropoint127

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值