触摸按键Android的驱动解析

 

/*---------------------------------------------------------------------------------------------------------
 * driver/input/touchscreen/goodix_touch.c
 *
 * Copyright(c) 2010 Goodix Technology Corp.    
 * Author: Eltonny
 * Date: 2010.11.11                                   
 *                                                                                                        
 *---------------------------------------------------------------------------------------------------------*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/time.h>
#include <linux/delay.h>
#define DEBUG 1
#include <linux/device.h>
#include <linux/earlysuspend.h>
#include <linux/platform_device.h>
#include <linux/hrtimer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <mach/gpio.h>
#include <plat/gpio-cfg.h>
#include <linux/gpio.h>
#include <linux/ioc4.h>
#include <linux/io.h>
#include <mach/ut210_gpio_reg.h>
#include "goodix_touch.h"
#include "goodix_queue.h"

#ifndef GUITAR_GT80X
#error The code does not match the hardware version.
#endif

#define GOODIX_DEBUG_F
#ifdef GOODIX_DEBUG_F
#define GOODIXTS_DEBUG(fmt,args...)  printk(  "[goodix_ts]: " fmt, ## args) //printk( KERN_DEBUG "[egalax_i2c]: " fmt, ## args)
#define DBG() printk("[%s]:%d => \n",__FUNCTION__,__LINE__)
#else
#define GOODIXTS_DEBUG(fmt,args...)  do{ }while(0)
#define DBG() do{ }while(0)
#endif

#ifdef utv210
static volatile  VIC_REG *VICREG;                

static volatile UT210_GPIO_REG *UT210_GPIOREG;    //denis_wei add 2010-12-08
#define TIMER     //采用的是定时器扫描的方式

#ifdef  EINT29     //如果是定义EINT29表示采用的是中断的方式    是对中断的定义 
#define EINT_KEY      (IRQ_RTC_TIC)//按键中断
#define KEY_EINT_EN  do { VICREG->VICINTENABLE  |= (0x1<<29); \
 VICREG->VICINTENCLEAR &= (~(0x1<<29));}while(0)
#define KEY_EINT_DIS  do {VICREG->VICINTENABLE  &= (~(0x1<<29));\
 VICREG->VICINTENCLEAR |= (0x1<<29); } while(0) 
static void goodix_key_callback(struct work_struct *work);
static DECLARE_WORK(key_work, goodix_key_callback);
static struct input_dev * s_input_dev = NULL;
#endif

/***wangyulu******/
#define MAX_BUTTON_CNT 3
static int goodix_scancode[MAX_BUTTON_CNT] = {0x1A,0x1B,0x1C};
static int goodix_keycode[MAX_BUTTON_CNT] = {KEY_BACK, KEY_HOME,KEY_MENU};
static int goodix_scancode_history[MAX_BUTTON_CNT] = {0,0,0,0};

///wangyulu lock_key time
#ifdef TIMER    //对定时器的定义
#define KEY_DETECT_INTERVAL      (msecs_to_jiffies(60))//定时60ms
static struct timer_list key_timer;
static void lockkey_timer_callback(struct work_struct *work);
static DECLARE_WORK(lock_work, lockkey_timer_callback);
static struct input_dev * s_input_dev = NULL;
static void goodix_key_timer_handler(unsigned long data);
#endif
#endif
#define MID706_SP  
static struct point_queue  finger_list; //record the fingers list
/*************************************************/
static struct i2c_client * i2c_connect_client = NULL;
#ifdef CONFIG_HAS_EARLYSUSPEND
static void goodix_ts_early_suspend(struct early_suspend *h);
static void goodix_ts_late_resume(struct early_suspend *h);
#endif
#define GOODIX_KEY_I2C (0xC4>>1)//触摸按键芯片的设备地址
/*Function as i2c_master_send */
static int i2c_write_key(struct i2c_client *client,uint8_t *data,int len)
{
 struct i2c_msg msg;
 int ret=-1;
 //发送设备地址
 msg.flags=!I2C_M_RD;//写消息
 msg.addr=GOODIX_KEY_I2C;
 msg.len=len;
 msg.buf=data;  
 ret=i2c_transfer(i2c_get_adapter(1),&msg,1);
 return ret;
}
//************ urbetter+ ******************
static int goodix_i2c_rxdata(char *rxdata, int length)
{
 int ret;
 struct i2c_msg msgs[] = {
  {
   .addr = GOODIX_KEY_I2C,
   .flags = 0,
   .len = 1,
   .buf = rxdata,
  },
  {
   .addr = GOODIX_KEY_I2C,
   .flags = I2C_M_RD,
   .len = length,
   .buf = rxdata,
  },
 };
 ret = i2c_transfer(i2c_get_adapter(1), msgs, 2);//i2c_get_adapter(1)选着iic 1
 if (ret < 0)
  pr_err("msg %s i2c read error: %d\n", __func__, ret);
 
 return ret;
}
#ifdef TIMER
////轮询处理函数wangyulu
static void goodix_key_timer_handler(unsigned long data)
{
 //ceshi
 schedule_work(&lock_work);
 mod_timer(&key_timer,jiffies + KEY_DETECT_INTERVAL);
}
/////lock_key的处理函数 key_703 wangyulu
static void lockkey_timer_callback(struct work_struct *work)
{
     int i;
 int boy_flag = 0;
 unsigned char buf[2];
 buf[0] = 0xc5;
 goodix_i2c_rxdata(buf, 1);
 //printk("key_TIMER=0x%02X\n", buf[0]); //没有按下是0xff  boy
 for(i = 0; i < MAX_BUTTON_CNT; i++)
 {  
      if((buf[0] == goodix_scancode_history[i]) || (buf[0] == goodix_scancode[i]))
      {
            printk("key_TIMER=0x%02X\n", buf[0]); //没有按下是0xff  boy
            goodix_scancode_history[i]= buf[0];
        input_report_key(s_input_dev, goodix_keycode[i], 1);
     }
      if(buf[0] == 0xFF)
      {
        input_report_key(s_input_dev, goodix_keycode[i], 0);
      }
 }
}

#endif
static int goodix_key_input_init(struct goodix_ts_data *ts)
{
 int i;
 s_input_dev = ts->input_dev;
 set_bit(EV_KEY, ts->input_dev->evbit);
 for(i = 0; i < MAX_BUTTON_CNT; i++)
  set_bit(goodix_keycode[i], ts->input_dev->keybit);
         /******wangyulu********添加time*****/
#ifdef TIMER
          init_timer(&key_timer);
      key_timer.function = goodix_key_timer_handler;
      key_timer.expires = jiffies + KEY_DETECT_INTERVAL;
      add_timer(&key_timer);
#endif
}
static int goodix_init_key(struct goodix_ts_data *ts)
{
 int ret=-1;
#ifdef EINT29
 //KEY_EINT_NUM INT11 wangyulu
 gpio_request(S5PV210_GPH3(5), "goodix_key_int");
 s3c_gpio_cfgpin(S5PV210_GPH3(5), 0xf<<20);
 s3c_gpio_setpull(S5PV210_GPH3(5), S3C_GPIO_PULL_DOWN);
 set_irq_type(EINT_KEY, IRQ_TYPE_EDGE_RISING);
 gpio_free(S5PV210_GPH3(5));
 KEY_EINT_EN;
#else
 if(ts->use_irq)
  enable_irq(ts->client->irq);
#endif
 uint8_t config_info[]={
          0x88,0x08,0x90,0x90,0x90,0x90,0x50,0x58,0x55,0x56,
       0x0e,0x00,0x00,0x00,0x09,0x04,0x00,0x00,0x00,
       0x00,0x05,0x06,0x07,0x00,0xc8};
#endif

 ret=i2c_write_key(ts->client,config_info,sizeof(config_info));

 if(ret > 0)
  ret = 0;
     goodix_key_input_init(ts); //urbetter+ boy
 return ret;
}
#ifdef EINT29
///add wangyulu 按键中断处理函数
static irqreturn_t goodix_key_irq_handler(int irq, void *dev_id)
{
 struct goodix_ts_data *ts = dev_id;
     printk("goodix_key_irq_handler\n"); //没有按下是0xff  boy
 KEY_EINT_DIS;
 schedule_work(&key_work);
 return IRQ_HANDLED;
}
static void goodix_key_callback(struct work_struct *work)/////adb wangyulu interrupter
{

     int i;
 int boy_flag = 0;
 unsigned char buf[2];
 buf[0] = 0xc5;
 goodix_i2c_rxdata(buf, 1);
 printk("key_EINT29=0x%02X\n", buf[0]); //没有按下是0xff  boy
 for(i = 0; i < MAX_BUTTON_CNT; i++)
 {  
      if((buf[0] == goodix_scancode_history[i]) || (buf[0] == goodix_scancode[i]))
      {
           goodix_scancode_history[i]= buf[0];
          input_report_key(s_input_dev, goodix_keycode[i], 1);
     }
      if(buf[0] == 0xFF)
      {
         input_report_key(s_input_dev, goodix_keycode[i], 0);
      }
 }
     KEY_EINT_EN;
}
#endif

static void utv210_gpio_init(void)
{
     int ret = 0;
     VICREG = ioremap(0xf2000000, sizeof(VIC_REG));                   
     UT210_GPIOREG  = ioremap(0xe0200000, sizeof(UT210_GPIO_REG)); 
     //wangyulu key
#ifdef EINT29
 set_irq_type(EINT_KEY, IRQ_TYPE_EDGE_RISING);
     ret = gpio_request(S5PV210_GPH3(5), "goodix_key_int");
 if (ret < 0) {
    gpio_free(S5PV210_GPH3(5));  // now bug; TODO
 }
 ret = gpio_request(S5PV210_GPH3(5), "goodix_key_int");
 s3c_gpio_setpull(S5PV210_GPH3(5), S3C_GPIO_PULL_DOWN);
     gpio_free(S5PV210_GPH3(5));
     //denis_wei add 2010-12-10 for touch interrupt detect
     UT210_GPIOREG->GPH1.GP_CON &= ~((0xf<<20) );//gph13 as input port
 UT210_GPIOREG->GPH1.GP_CON |= ((0xf<<20));//gph13 interrupt port
     UT210_GPIOREG->GPH1.GP_DAT &= ~((0x1<<20) );//gph13. output 1 
 UT210_GPIOREG->GPH1.GP_PUD &= ~((0x3<<20) );//gph13 pull disable
 UT210_GPIOREG->GPH1.GP_PUD |= ((0x2<<20));//gph13 pull-up enable
#endif
#ifdef TIMER
     s3c_gpio_cfgpin(S5PV210_GPH3(5), 0x0<<20);
 gpio_direction_output(S5PV210_GPH3(5), 1);
 s3c_gpio_setpull(S5PV210_GPH3(5), S3C_GPIO_PULL_DOWN);
#endif   
}
/******************************************************* 
功能:
 触摸屏探测函数
 在注册驱动时调用(要求存在对应的client);
 用于IO,中断等资源申请;设备注册;触摸屏初始化等工作
参数:
 client:待驱动的设备结构体
 id:设备ID
return:
 执行结果码,0表示正常执行
********************************************************/
static int goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
 struct goodix_ts_data *ts;
 int ret = 0;
 int retry=0;
 int count=0;

 u8 testbuf[6] = {0, 0, 0, 0, 0};
 struct goodix_i2c_rmi_platform_data *pdata;
 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
 {
  dev_err(&client->dev, "System need I2C function.\n");
  ret = -ENODEV;
  goto err_check_functionality_failed;
 }
 ts = kzalloc(sizeof(*ts), GFP_KERNEL);
 if (ts == NULL) {
  ret = -ENOMEM;
  goto err_alloc_data_failed;
 }
 //utv210_gpio_init(); 
 /***wangyulu****/
 ts->client = client;
 i2c_set_clientdata(client, ts);
 pdata = client->dev.platform_data; 
 ts->input_dev = input_allocate_device();
 if (ts->input_dev == NULL) {
  ret = -ENOMEM;
  dev_dbg(&client->dev,"Failed to allocate input device\n");
  goto err_input_dev_alloc_failed;
 }
 ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);

     ret = input_register_device(ts->input_dev);
 if (ret) {
  dev_err(&client->dev,"Probe: Unable to register %s input device\n", ts->input_dev->name);
   goto  err_input_register_device_failed;
 }
 utv210_gpio_init(); 
 goodix_init_key(ts);
#ifdef EINT29
///wangyulu 按键中断申请
 ret = request_irq(EINT_KEY, goodix_key_irq_handler,   IRQ_TYPE_EDGE_RISING, client->name, ts);
 if( ret )
 {
  printk("Can't allocate touchscreen's interrupt\n");
  dev_err(&client->dev,"Can't allocate touchscreen's interrupt!ERRNO:%d\n", ret);
  goto Fail_utv210_int;
 }
 ts->use_irq = 1;
 KEY_EINT_DIS;
#endif
 printk("#############line =%d\n", __LINE__);
err_input_register_device_failed:
 input_free_device(ts->input_dev);
err_input_dev_alloc_failed:
  i2c_set_clientdata(client, NULL);
Fail_utv210_int:
err_alloc_data_failed:
err_check_functionality_failed:
 return ret;
}
/******************************************************* 
功能:
 驱动资源释放
参数:
 client:设备结构体
return:
 执行结果码,0表示正常执行
********************************************************/
static int goodix_ts_remove(struct i2c_client *client)
{
 struct goodix_ts_data *ts = i2c_get_clientdata(client);
 unregister_early_suspend(&ts->early_suspend);
 dev_notice(&client->dev,"The driver is removing...\n");
 i2c_set_clientdata(client, NULL);
 input_unregister_device(ts->input_dev);
#ifdef EINT29 
  free_irq(EINT_KEY, ts);
#endif
 if(ts->input_dev)
  kfree(ts->input_dev);
 kfree(ts);
 return 0;
}
//停用设备
static int goodix_ts_suspend(struct i2c_client *client, pm_message_t mesg)
{
 int ret;
 struct goodix_ts_data *ts = i2c_get_clientdata(client);

 if(ts->bad_data)
     return 0;
 }
static int goodix_ts_resume(struct i2c_client *client)
{
 int ret;
 struct goodix_ts_data *ts = i2c_get_clientdata(client);

 if(ts->bad_data)
  return 0;
#ifdef EINT29
     KEY_EINT_EN;
#else
 if (ts->use_irq) {
  enable_irq(client->irq);
 }
#endif
  return 0;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
static void goodix_ts_early_suspend(struct early_suspend *h)
{
   
 struct goodix_ts_data *ts;
 ts = container_of(h, struct goodix_ts_data, early_suspend);
 goodix_ts_suspend(ts->client, PMSG_SUSPEND);
}

static void goodix_ts_late_resume(struct early_suspend *h)
{
 struct goodix_ts_data *ts;
 ts = container_of(h, struct goodix_ts_data, early_suspend);
 goodix_ts_resume(ts->client);
 
}
#endif
#undef GOODIX_I2C_NAME
#define GOODIX_I2C_NAME "Goodix-key-703" //boy
static const struct i2c_device_id goodix_ts_id[] = {
 { GOODIX_I2C_NAME, 0 },
 { }
};
//设备驱动结构体
struct i2c_driver goodix_ts_driver = {
 .probe  = goodix_ts_probe,
 .remove  = goodix_ts_remove,
#ifndef CONFIG_HAS_EARLYSUSPEND
 .suspend = goodix_ts_suspend,
 .resume  = goodix_ts_resume,
#endif
 .id_table = goodix_ts_id,
 .driver = {
  .name = GOODIX_I2C_NAME,
  .owner = THIS_MODULE,
 },
};
/******************************************************* 
功能:
 驱动加载函数
return:
 执行结果码,0表示正常执行
********************************************************/
 static int __devinit goodix_ts_init(void)
 {
  int ret;
   ret=i2c_add_driver(&goodix_ts_driver);
  return ret;
 }
/******************************************************* 
功能:
 驱动卸载函数
参数:
 client:设备结构体
********************************************************/
 static void __exit goodix_ts_exit(void)
 {
   i2c_del_driver(&goodix_ts_driver);
 }

late_initcall(goodix_ts_init);
module_exit(goodix_ts_exit);

MODULE_DESCRIPTION("Goodix Touchscreen Driver");
MODULE_LICENSE("GPL");
希望能够和大家分享,如有疑问可以给我留言,谢谢

你可能感兴趣的:(触摸按键Android的驱动解析)