/*--------------------------------------------------------------------------------------------------------- * 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");
转载自:http://blog.csdn.net/Baiduluckyboy/article/details/6616533