***************************************************************************************************************************
作者: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()动态创建。

  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. {
  12. I2C_BOARD_INFO("ft5x0x_ts", 0x3x),
  13. .irq = IRQ_EINT1,
  14. },
  15. #endif
  16. };

最后在内核初始化的部分调用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内核中,需要修改代码的]

  1. static int
  2. ft5x0x_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
  3. {
  4. struct ft5x0x_ts_data *ft5x0x_ts;
  5. struct input_dev *input_dev;
  6. int err = 0;
  7. unsigned char uc_reg_value;
  8. #if CFG_SUPPORT_TOUCH_KEY
  9. int i;
  10. #endif
  11. printk("[FTS] ft5x0x_ts_probe, driver version is %s.\n", CFG_FTS_CTP_DRIVER_VERSION);
  12. if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
  13. err = -ENODEV;
  14. goto exit_check_functionality_failed;
  15. }
  16. ft5x0x_ts = kzalloc(sizeof(struct ft5x0x_ts_data), GFP_KERNEL);
  17. //ft5x0x_ts = kmalloc(sizeof(struct ft5x0x_ts_data), GFP_KERNEL);
  18. if (!ft5x0x_ts) {
  19. err = -ENOMEM;
  20. goto exit_alloc_data_failed;
  21. }
  22. //memset(ft5x0x_ts, 0, sizeof(struct ft5x0x_ts_data));
  23. this_client = client;
  24. i2c_set_clientdata(client, ft5x0x_ts);
  25. mutex_init(&ft5x0x_ts->device_mode_mutex);
  26. INIT_WORK(&ft5x0x_ts->pen_event_work, ft5x0x_ts_pen_irq_work);
  27. ft5x0x_ts->ts_workqueue = create_singlethread_workqueue(dev_name(&client->dev));
  28. if (!ft5x0x_ts->ts_workqueue) {
  29. err = -ESRCH;
  30. goto exit_create_singlethread;
  31. }
  32. err = request_irq(IRQ_EINT(6), ft5x0x_ts_interrupt, IRQF_TRIGGER_FALLING, "ft5x0x_ts", ft5x0x_ts);
  33. if (err < 0) {
  34. dev_err(&client->dev, "ft5x0x_probe: request irq failed\n");
  35. goto exit_irq_request_failed;
  36. }
  37. disable_irq(IRQ_EINT(6));
  38. input_dev = input_allocate_device();
  39. if (!input_dev) {
  40. err = -ENOMEM;
  41. dev_err(&client->dev, "failed to allocate input device\n");
  42. goto exit_input_dev_alloc_failed;
  43. }
  44. ft5x0x_ts->input_dev = input_dev;
  45. set_bit(ABS_MT_TOUCH_MAJOR, input_dev->absbit);
  46. set_bit(ABS_MT_POSITION_X, input_dev->absbit);
  47. set_bit(ABS_MT_POSITION_Y, input_dev->absbit);
  48. set_bit(ABS_MT_WIDTH_MAJOR, input_dev->absbit);
  49. input_set_abs_params(input_dev,
  50. ABS_MT_POSITION_X, 0, SCREEN_MAX_X, 0, 0);
  51. input_set_abs_params(input_dev,
  52. ABS_MT_POSITION_Y, 0, SCREEN_MAX_Y, 0, 0);
  53. input_set_abs_params(input_dev,
  54. ABS_MT_TOUCH_MAJOR, 0, PRESS_MAX, 0, 0);
  55. input_set_abs_params(input_dev,
  56. ABS_MT_WIDTH_MAJOR, 0, 200, 0, 0);
  57. input_set_abs_params(input_dev,
  58. ABS_MT_TRACKING_ID, 0, 5, 0, 0);
  59. set_bit(EV_KEY, input_dev->evbit);
  60. set_bit(EV_ABS, input_dev->evbit);
  61. #if CFG_SUPPORT_TOUCH_KEY
  62. //setup key code area
  63. set_bit(EV_SYN, input_dev->evbit);
  64. set_bit(BTN_TOUCH, input_dev->keybit);
  65. input_dev->keycode = tsp_keycodes;
  66. for(i = 0; i < CFG_NUMOFKEYS; i++)
  67. {
  68. input_set_capability(input_dev, EV_KEY, ((int*)input_dev->keycode)[i]);
  69. tsp_keystatus[i] = KEY_RELEASE;
  70. }
  71. #endif
  72. input_dev->name      = FT5X0X_NAME;      //dev_name(&client->dev)
  73. err = input_register_device(input_dev);
  74. if (err) {
  75. dev_err(&client->dev,
  76. "ft5x0x_ts_probe: failed to register input device: %s\n",
  77. dev_name(&client->dev));
  78. goto exit_input_register_device_failed;
  79. }
  80. #ifdef CONFIG_HAS_EARLYSUSPEND
  81. printk("==register_early_suspend =\n");
  82. ft5x0x_ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
  83. ft5x0x_ts->early_suspend.suspend = ft5x0x_ts_suspend;
  84. ft5x0x_ts->early_suspend.resume  = ft5x0x_ts_resume;
  85. register_early_suspend(&ft5x0x_ts->early_suspend);
  86. #endif
  87. msleep(150);  //make sure CTP already finish startup process
  88. //get some register information
  89. uc_reg_value = ft5x0x_read_fw_ver();
  90. printk("[FTS] Firmware version = 0x%x\n", uc_reg_value);
  91. ft5x0x_read_reg(FT5X0X_REG_PERIODACTIVE, &uc_reg_value);
  92. printk("[FTS] report rate is %dHz.\n", uc_reg_value * 10);
  93. ft5x0x_read_reg(FT5X0X_REG_THGROUP, &uc_reg_value);
  94. printk("[FTS] touch threshold is %d.\n", uc_reg_value * 4);
  95. #if CFG_SUPPORT_AUTO_UPG
  96. fts_ctpm_auto_upg();
  97. #endif
  98. #if CFG_SUPPORT_UPDATE_PROJECT_SETTING
  99. fts_ctpm_update_project_setting();
  100. #endif
  101. enable_irq(IRQ_EINT(6));
  102. //create sysfs
  103. err = sysfs_create_group(&client->dev.kobj, &ft5x0x_attribute_group);
  104. if (0 != err)
  105. {
  106. dev_err(&client->dev, "%s() - ERROR: sysfs_create_group() failed: %d\n", __FUNCTION__, err);
  107. sysfs_remove_group(&client->dev.kobj, &ft5x0x_attribute_group);
  108. }
  109. else
  110. {
  111. printk("ft5x0x:%s() - sysfs_create_group() succeeded.\n", __FUNCTION__);
  112. }
  113. printk("[FTS] ==probe over =\n");
  114. return 0;
  115. exit_input_register_device_failed:
  116. input_free_device(input_dev);
  117. exit_input_dev_alloc_failed:
  118. //  free_irq(client->irq, ft5x0x_ts);
  119. free_irq(IRQ_EINT(6), ft5x0x_ts);
  120. exit_irq_request_failed:
  121. //exit_platform_data_null:
  122. cancel_work_sync(&ft5x0x_ts->pen_event_work);
  123. destroy_workqueue(ft5x0x_ts->ts_workqueue);
  124. exit_create_singlethread:
  125. printk("==singlethread error =\n");
  126. i2c_set_clientdata(client, NULL);
  127. kfree(ft5x0x_ts);
  128. exit_alloc_data_failed:
  129. exit_check_functionality_failed:
  130. return err;
  131. }
  132. static int __devexit ft5x0x_ts_remove(struct i2c_client *client)
  133. {
  134. struct ft5x0x_ts_data *ft5x0x_ts;
  135. printk("==ft5x0x_ts_remove=\n");
  136. ft5x0x_ts = i2c_get_clientdata(client);
  137. unregister_early_suspend(&ft5x0x_ts->early_suspend);
  138. //  free_irq(client->irq, ft5x0x_ts);
  139. mutex_destroy(&ft5x0x_ts->device_mode_mutex);
  140. free_irq(IRQ_EINT(6), ft5x0x_ts);
  141. input_unregister_device(ft5x0x_ts->input_dev);
  142. kfree(ft5x0x_ts);
  143. cancel_work_sync(&ft5x0x_ts->pen_event_work);
  144. destroy_workqueue(ft5x0x_ts->ts_workqueue);
  145. i2c_set_clientdata(client, NULL);
  146. del_timer(&test_timer);
  147. return 0;
  148. }
  149. static const struct i2c_device_id ft5x0x_ts_id[] = {
  150. { FT5X0X_NAME, 0x3x },{ }
  151. };
  152. MODULE_DEVICE_TABLE(i2c, ft5x0x_ts_id);
  153. static struct i2c_driver ft5x0x_ts_driver = {
  154. .probe      = ft5x0x_ts_probe,
  155. .remove     = __devexit_p(ft5x0x_ts_remove),
  156. .id_table   = ft5x0x_ts_id,
  157. .driver = {
  158. .name   = FT5X0X_NAME,
  159. .owner  = THIS_MODULE,
  160. },
  161. };
  162. static int __init ft5x0x_ts_init(void)
  163. {
  164. int ret;
  165. printk("==ft5x0x_ts_init==\n");
  166. ret = i2c_add_driver(&ft5x0x_ts_driver);
  167. printk("ret=%d\n",ret);
  168. return ret;
  169. }
  170. static void __exit ft5x0x_ts_exit(void)
  171. {
  172. printk("==ft5x0x_ts_exit==\n");
  173. i2c_del_driver(&ft5x0x_ts_driver);
  174. }
  175. module_init(ft5x0x_ts_init);
  176. module_exit(ft5x0x_ts_exit);
  177. MODULE_AUTHOR("<wenfs@Focaltech-systems.com>");
  178. MODULE_DESCRIPTION("FocalTech ft5x0x TouchScreen driver");
  179. MODULE_LICENSE("GPL");

移植到通用的Linux的内核中,就不写出来了,自己去研究吧。

基于FT5x06嵌入式Linux电容触摸屏驱动的更多相关文章

  1. 基于s5pv210嵌入式linux系统sqlite3数据库移植

    基于s5pv210嵌入式linux系统sqlite3数据库移植 1.下载源码 http://www.sqlite.org/download.html 最新源码为3080100 2.解压 tar xvf ...

  2. 调试exynos4412—ARM嵌入式Linux—LEDS/GPIO驱动之二

    /** ****************************************************************************** * @author    暴走的小 ...

  3. 调试exynos4412—ARM嵌入式Linux—LEDS/GPIO驱动之一

    /** ****************************************************************************** * @author    暴走的小 ...

  4. 调试exynos4412—ARM嵌入式Linux—LEDS/GPIO驱动之三

    /** ****************************************************************************** * @author    暴走的小 ...

  5. 基于335X平台Linux交换芯片驱动开发

    基于335X平台Linux交换芯片驱动开发   一.软硬件平台资料 1.开发板:创龙AM3359核心板,网口采用RMII形式. 2.Kernel版本:4.4.12,采用FDT 3.交换芯片MARVEL ...

  6. 基于设备树的TQ2440触摸屏驱动移植

    平台 开发板:tq2440 内核:Linux-4.9 u-boot:u-boot-2015.04   概述 之前移植了LCD驱动,下面继续移植触摸屏驱动,然后将tslib也移植上去. 正文 一.移植触 ...

  7. Linux学习: 触摸屏驱动

    一.Linux输入子系统的结构: 二.触摸屏驱动代码: s3c_ts.c #include <linux/errno.h> #include <linux/kernel.h> ...

  8. 转: 嵌入式linux下usb驱动开发方法--看完少走弯路【转】

    转自:http://blog.csdn.net/jimmy_1986/article/details/5838297 嵌入式linux下的usb属于所有驱动中相当复杂的一个子系统,要想将她彻底征服,至 ...

  9. 基于mini2440嵌入式Linux根文件系统制作(Initramfs和nfs两种跟文件系统)

    嵌入式系统由三部分构成: 1.bootoader---bootparameters---2.kernel 3.Root-filesysytem 一个内核可以挂载多个文件系统,但是有一个根文件系统所以叫 ...

随机推荐

  1. Go 语言指向指针的指针

    如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量. 当定义一个指向指针的指针变量时,第一个指针存放第二个指针的地址,第二个指针存放变量的地址: 指向指针的指针变量声 ...

  2. MongoDB Limit与Skip方法

    MongoDB Limit() 方法 如果你需要在MongoDB中读取指定数量的数据记录,可以使用MongoDB的Limit方法,limit()方法接受一个数字参数,该参数指定从MongoDB中读取的 ...

  3. Docker其它安全特性

    除了能力机制之外,还可以利用一些现有的安全机制来增强使用 Docker 的安全性,例如 TOMOYO, AppArmor, SELinux, GRSEC 等. Docker 当前默认只启用了能力机制. ...

  4. 实战 PureMVC

    最近看PureMVC,在IBM开发者社区发现此文,对PureMVC的讲解清晰简洁,看了可快速入门.另外,<腾讯桌球>游戏的开发者吴秦,也曾进一步剖析PureMVC,可结合看加深理解. 引言 ...

  5. Python 3 智能发音

    真是十分神奇.. import win32com.client import time s = win32com.client.Dispatch("SAPI.SpVoice") s ...

  6. nginx中configure脚本支持的常用选项,拍摄自《Nginx高性能Web服务器详解》

  7. [ExtJS5学习笔记]第二十八节 sencha ext js 5.1.0发布版本正式发布 extjs doc下载地址

    本文地址:http://blog.csdn.net/sushengmiyan/article/details/41911539 本文作者:sushengmiyan ------------------ ...

  8. ubuntu mysql表名大小写区分

    近期开发线上操作系统用的ubuntu,数据库用的mysql,突然发现mysql表名大写报错,找一下原因,看了下mysql的配置,果真可以设置,窃喜. 先找到你MySQL的my.cnf配置文件并修改,当 ...

  9. socket系列之服务器端socket——ServerSocket类

    一般地,Socket可分为TCP套接字和UDP套接字,再进一步,还可以被分为服务器端套接字跟客户端套接字.这节我们先关注TCP套接字的服务器端socket,Java中ServerSocket类与之相对 ...

  10. 关于activitygroup过时,用frament替换操作

    现在Fragment的应用真的是越来越广泛了,之前Android在3.0版本加入Fragment的时候,主要是为了解决Android Pad屏幕比较大,空间不能充分利用的问题,但现在即使只是在手机上, ...