基于FT5x06嵌入式Linux电容触摸屏驱动

2019-07-13 00:45发布

***************************************************************************************************************************
作者:EasyWave                                                                                 时间:2013.02.06
类别:Linux 内核驱动源码分析                                                      声明:转载,请保留链接 注意:如有错误,欢迎指正。这些是我学习的日志文章...... *************************************************************************************************************************** 一:FT5X06电容触摸IC简介      FT5x06系列ICs是单芯片电容式触摸屏控制器IC,带有一个内置的8位微控制器单元(MCU)。采用互电容的方法,在配合的相互的电容式触摸面板,它支持真正的多点触摸功能。FT5x06具有用户友好的输入的功能,这可以应用在许多便携式设备,例如蜂窝式电话,移动互联网设备,上网本和笔记本个人电脑。FT5x06系列IC包括FT5206/FT5306/FT5406。具体的功能如下图所示: 二:硬件接口设计 从FT5X06的datasheet中,我们可以看到,FT5X06既可以工作的SPI的接口方式,也可以工作在I2C的接口方式,不管工作在SPI,还是工作在I2C,从硬件的接口设计上来说,这下面的几个控制口,都是需要要接的。如下图所示: 1):INT引脚,这个脚是一个中端信号,它用来通知HOST端FT5X06已经准备好,可以进行读操作了。 2):WAKE引脚:这个功能主要的作用是将FT5X06从睡眠状态转换到工作状态。 3):/RST引脚:FT5X06的芯片复位信号。 如何来设计硬件接口呢,这个我们可以从FT5X06的datasheet看出来,首先我们来看下FT5X06的上电时序,如下图所示: FT5X06的上电时序 FT5X06的RESET时序 FT5X06的wakeup时序 各自的最小的时间限制如下所所示: 因此,从上面的图片和表格中,我们可以看出,在poweron中,必须确保在上电后,wakeup的电平为高电平,至于INT信号,只要确保无INT信号时,这个INT为高即可,这个可以从poweron的时序可以看出,它是一个低电平的动作,这个是驱动中来做的事情了。 接下来就是确定I2C的从地址,如下图所示:[以下引用自网络] 从地址高位必须为:3,低位必须根据i2ccon设定的值来确定。 根据FT5406数据手册上的指令,我们先了解下驱动如何实现电容屏的多点触摸,其实很简单,主要需要触摸屏IC FT5406 能够捕获多点数据,这点电容屏基本多能支持到捕获2点以上,而FT5406 可以捕获5个触摸点,编写驱动时,只要去获取这几个点的数据,然后上报就可以了。如下图所示:[以下引用自网络] 02H :捕获的触摸点个数              03H- 1EH :对应每个点的x,y坐标数值。 三:Linux驱动源码         I2C的驱动需要根据具体的ARM芯片,一般来说,IC原厂,一般会将在linux的bsp中都会有I2C的驱动,这个部分不需要我们去写的,我们只需要将FT5X06和BSP包中的I2C驱动匹配起来就好了。而整个FT5X06也是这样做的。在linu内核中关于i2c的一般会有这个函数:i2c_board_info()i2c_board_info用于构建信息表来列出存在的I2C设备。这一信息用于增长新型I2C驱动的驱动模型树。对于主板,它使用i2c_register_board_info()来静态创建。对于子板,利用已知的适配器使用i2c_new_device()动态创建。     [cpp] view plaincopyprint?
  1. struct i2c_board_info { 
  2.     char type[I2C_NAME_SIZE];   
  3.     unsigned short flags;   
  4.     unsigned short addr;   
  5.     void *platform_data;   
  6.     struct dev_archdata *archdata;   
  7.     int irq;   
  8. }; 
  9. static struct i2c_board_info i2c_devs0[] __initdata = { 
  10. #ifdef CONFIG_TOUCHSCREEN_CDTLCD 
  11. I2C_BOARD_INFO("ft5x0x_ts", 0x3x), 
  12. .irq = IRQ_EINT1, 
  13. }, 
  14. #endif  
  15. }; 
struct i2c_board_info { char type[I2C_NAME_SIZE]; unsigned short flags; unsigned short addr; void *platform_data; struct dev_archdata *archdata; int irq; }; static struct i2c_board_info i2c_devs0[] __initdata = { #ifdef CONFIG_TOUCHSCREEN_CDTLCD { I2C_BOARD_INFO("ft5x0x_ts", 0x3x), .irq = IRQ_EINT1, }, #endif };
最后在内核初始化的部分调用int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len);函数即可。如下详细的解释:
@busnum: 指定这些设备属于哪个总线
@info: I2C设备描述符向量
@len: 向量中描述符的数量;为了预留特定的总线号,可以是0。
i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));
下面贴出部分代码:[下面的代码是Android下的Linux驱动,如果要修改到通用的Linux内核中,需要修改代码的] [cpp] view plaincopyprint?
  1. static int  
  2. ft5x0x_ts_probe(struct i2c_client *client,conststruct i2c_device_id *id) 
  3.     struct ft5x0x_ts_data *ft5x0x_ts; 
  4.     struct input_dev *input_dev; 
  5.     int err = 0; 
  6.     unsigned char uc_reg_value;  
  7. #if CFG_SUPPORT_TOUCH_KEY 
  8.     int i; 
  9. #endif 
  10.      
  11.     printk("[FTS] ft5x0x_ts_probe, driver version is %s. ", CFG_FTS_CTP_DRIVER_VERSION); 
  12.      
  13.     if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 
  14.         err = -ENODEV; 
  15.         goto exit_check_functionality_failed; 
  16.     } 
  17.  
  18.     ft5x0x_ts = kzalloc(sizeof(struct ft5x0x_ts_data), GFP_KERNEL); 
  19.     //ft5x0x_ts = kmalloc(sizeof(struct ft5x0x_ts_data), GFP_KERNEL); 
  20.     if (!ft5x0x_ts) { 
  21.         err = -ENOMEM; 
  22.         goto exit_alloc_data_failed; 
  23.     } 
  24.     //memset(ft5x0x_ts, 0, sizeof(struct ft5x0x_ts_data)); 
  25.  
  26.     this_client = client; 
  27.     i2c_set_clientdata(client, ft5x0x_ts); 
  28.  
  29.     mutex_init(&ft5x0x_ts->device_mode_mutex); 
  30.     INIT_WORK(&ft5x0x_ts->pen_event_work, ft5x0x_ts_pen_irq_work); 
  31.  
  32.     ft5x0x_ts->ts_workqueue = create_singlethread_workqueue(dev_name(&client->dev)); 
  33.     if (!ft5x0x_ts->ts_workqueue) { 
  34.         err = -ESRCH; 
  35.         goto exit_create_singlethread; 
  36.     } 
  37.  
  38.  
  39.     err = request_irq(IRQ_EINT(6), ft5x0x_ts_interrupt, IRQF_TRIGGER_FALLING,"ft5x0x_ts", ft5x0x_ts); 
  40.     if (err < 0) { 
  41.         dev_err(&client->dev, "ft5x0x_probe: request irq failed "); 
  42.         goto exit_irq_request_failed; 
  43.     } 
  44.  
  45.  
  46.     disable_irq(IRQ_EINT(6)); 
  47.  
  48.     input_dev = input_allocate_device(); 
  49.     if (!input_dev) { 
  50.         err = -ENOMEM; 
  51.         dev_err(&client->dev, "failed to allocate input device "); 
  52.         goto exit_input_dev_alloc_failed; 
  53.     } 
  54.      
  55.     ft5x0x_ts->input_dev = input_dev; 
  56.  
  57.     set_bit(ABS_MT_TOUCH_MAJOR, input_dev->absbit); 
  58.     set_bit(ABS_MT_POSITION_X, input_dev->absbit); 
  59.     set_bit(ABS_MT_POSITION_Y, input_dev->absbit); 
  60.     set_bit(ABS_MT_WIDTH_MAJOR, input_dev->absbit); 
  61.  
  62.     input_set_abs_params(input_dev, 
  63.                  ABS_MT_POSITION_X, 0, SCREEN_MAX_X, 0, 0); 
  64.     input_set_abs_params(input_dev, 
  65.                  ABS_MT_POSITION_Y, 0, SCREEN_MAX_Y, 0, 0); 
  66.     input_set_abs_params(input_dev, 
  67.                  ABS_MT_TOUCH_MAJOR, 0, PRESS_MAX, 0, 0); 
  68.     input_set_abs_params(input_dev, 
  69.                  ABS_MT_WIDTH_MAJOR, 0, 200, 0, 0); 
  70.     input_set_abs_params(input_dev, 
  71.                  ABS_MT_TRACKING_ID, 0, 5, 0, 0); 
  72.  
  73.  
  74.     set_bit(EV_KEY, input_dev->evbit); 
  75.     set_bit(EV_ABS, input_dev->evbit); 
  76.  
  77. #if CFG_SUPPORT_TOUCH_KEY 
  78.     //setup key code area 
  79.     set_bit(EV_SYN, input_dev->evbit); 
  80.     set_bit(BTN_TOUCH, input_dev->keybit); 
  81.     input_dev->keycode = tsp_keycodes; 
  82.     for(i = 0; i < CFG_NUMOFKEYS; i++) 
  83.     { 
  84.         input_set_capability(input_dev, EV_KEY, ((int*)input_dev->keycode)[i]); 
  85.         tsp_keystatus[i] = KEY_RELEASE; 
  86.     } 
  87. #endif 
  88.  
  89.     input_dev->name      = FT5X0X_NAME;      //dev_name(&client->dev) 
  90.     err = input_register_device(input_dev); 
  91.     if (err) { 
  92.         dev_err(&client->dev, 
  93.         "ft5x0x_ts_probe: failed to register input device: %s "
  94.         dev_name(&client->dev)); 
  95.         goto exit_input_register_device_failed; 
  96.     } 
  97.  
  98. #ifdef CONFIG_HAS_EARLYSUSPEND 
  99.     printk("==register_early_suspend = "); 
  100.     ft5x0x_ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; 
  101.     ft5x0x_ts->early_suspend.suspend = ft5x0x_ts_suspend; 
  102.     ft5x0x_ts->early_suspend.resume  = ft5x0x_ts_resume; 
  103.     register_early_suspend(&ft5x0x_ts->early_suspend); 
  104. #endif 
  105.  
  106.     msleep(150);  //make sure CTP already finish startup process 
  107.      
  108.     //get some register information 
  109.     uc_reg_value = ft5x0x_read_fw_ver(); 
  110.     printk("[FTS] Firmware version = 0x%x ", uc_reg_value); 
  111.     ft5x0x_read_reg(FT5X0X_REG_PERIODACTIVE, &uc_reg_value); 
  112.     printk("[FTS] report rate is %dHz. ", uc_reg_value * 10); 
  113.     ft5x0x_read_reg(FT5X0X_REG_THGROUP, &uc_reg_value); 
  114.     printk("[FTS] touch threshold is %d. ", uc_reg_value * 4); 
  115.  
  116. #if CFG_SUPPORT_AUTO_UPG 
  117.     fts_ctpm_auto_upg(); 
  118. #endif     
  119.  
  120. #if CFG_SUPPORT_UPDATE_PROJECT_SETTING 
  121.     fts_ctpm_update_project_setting(); 
  122. #endif 
  123.  
  124.     enable_irq(IRQ_EINT(6)); 
  125.    //create sysfs 
  126.    err = sysfs_create_group(&client->dev.kobj, &ft5x0x_attribute_group); 
  127.    if (0 != err) 
  128.   { 
  129.     dev_err(&client->dev, "%s() - ERROR: sysfs_create_group() failed: %d ", __FUNCTION__, err); 
  130.     sysfs_remove_group(&client->dev.kobj, &ft5x0x_attribute_group); 
  131.   } 
  132.    else 
  133.     { 
  134.         printk("ft5x0x:%s() - sysfs_create_group() succeeded. ", __FUNCTION__); 
  135.     } 
  136.  
  137.     printk("[FTS] ==probe over = "); 
  138.     return 0; 
  139.  
  140. exit_input_register_device_failed: 
  141.     input_free_device(input_dev); 
  142. exit_input_dev_alloc_failed: 
  143. //  free_irq(client->irq, ft5x0x_ts); 
  144.     free_irq(IRQ_EINT(6), ft5x0x_ts); 
  145. exit_irq_request_failed: 
  146. //exit_platform_data_null: 
  147.     cancel_work_sync(&ft5x0x_ts->pen_event_work); 
  148.     destroy_workqueue(ft5x0x_ts->ts_workqueue); 
  149. exit_create_singlethread: 
  150.     printk("==singlethread error = "); 
  151.     i2c_set_clientdata(client, NULL); 
  152.     kfree(ft5x0x_ts); 
  153. exit_alloc_data_failed: 
  154. exit_check_functionality_failed: 
  155.     return err; 
  156. static int __devexit ft5x0x_ts_remove(struct i2c_client *client) 
  157.     struct ft5x0x_ts_data *ft5x0x_ts; 
  158.     printk("==ft5x0x_ts_remove= "); 
  159.     ft5x0x_ts = i2c_get_clientdata(client); 
  160.     unregister_early_suspend(&ft5x0x_ts->early_suspend); 
  161. //  free_irq(client->irq, ft5x0x_ts); 
  162.     mutex_destroy(&ft5x0x_ts->device_mode_mutex); 
  163.     free_irq(IRQ_EINT(6), ft5x0x_ts); 
  164.     input_unregister_device(ft5x0x_ts->input_dev); 
  165.     kfree(ft5x0x_ts); 
  166.     cancel_work_sync(&ft5x0x_ts->pen_event_work); 
  167.     destroy_workqueue(ft5x0x_ts->ts_workqueue); 
  168.     i2c_set_clientdata(client, NULL);  
  169.     del_timer(&test_timer); 
  170.     return 0; 
  171.  
  172. static conststruct i2c_device_id ft5x0x_ts_id[] = { 
  173.     { FT5X0X_NAME, 0x3x },{ } 
  174. }; 
  175.  
  176.  
  177. MODULE_DEVICE_TABLE(i2c, ft5x0x_ts_id); 
  178.  
  179. static struct i2c_driver ft5x0x_ts_driver = { 
  180.     .probe      = ft5x0x_ts_probe, 
  181.     .remove     = __devexit_p(ft5x0x_ts_remove), 
  182.     .id_table   = ft5x0x_ts_id, 
  183.     .driver = { 
  184.         .name   = FT5X0X_NAME, 
  185.         .owner  = THIS_MODULE, 
  186.     }, 
  187. }; 
  188.  
  189. static int __init ft5x0x_ts_init(void
  190.     int ret; 
  191.     printk("==ft5x0x_ts_init== "); 
  192.     ret = i2c_add_driver(&ft5x0x_ts_driver); 
  193.     printk("ret=%d ",ret); 
  194.     return ret; 
  195.  
  196. static void __exit ft5x0x_ts_exit(void
  197.     printk("==ft5x0x_ts_exit== "); 
  198.     i2c_del_driver(&ft5x0x_ts_driver); 
  199.  
  200. module_init(ft5x0x_ts_init); 
  201. module_exit(ft5x0x_ts_exit); 
  202.  
  203. MODULE_AUTHOR(""); 
  204. MODULE_DESCRIPTION("FocalTech ft5x0x TouchScreen driver"); 
  205. MODULE_LICENSE("GPL");
原文地址:http://blog.csdn.net/wavemcu/article/details/8573362