Chinaunix首页 | 论坛 | 博客
  • 博客访问: 796793
  • 博文数量: 478
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 4831
  • 用 户 组: 普通用户
  • 注册时间: 2014-06-28 11:12
文章分类

全部博文(478)

文章存档

2019年(1)

2018年(27)

2017年(21)

2016年(171)

2015年(258)

我的朋友

分类: 嵌入式

2018-03-05 17:05:39

原文地址:TP驱动分析(上) 作者:jerry20000

 

--分析Ft0x5x.c

一、硬件电路概述

1,电容触摸屏的工作及坐标定位算法这里不做介绍,网上有很多相关的资料可以查看。一般按TP的触摸IC是否在主板上,可以分为:COBchip on board)和COFchip on film)。前者是把触摸IC贴在主板上,后者是把触摸IC帖在FPC上。但是他们的工作原理是一样的,不同的是TP connectorpin数不一样罢了。

2TP的工作原理

从规格书上可以知道,在CTPHOST之间有三种通信:

1Transfer the data via I2C(通过I2C或者其它接口传输数据给主机)

2Send interrupt when there is a valid touch(当有触摸时发送中断给主机)

3Host send Wakeup signal to CTPM(主机唤醒TP)


TP检测到有效的触摸以后,计算出具体坐标等数据存放在寄存器中,然后发中断给主控,主控收到中断后让TP通过I2C发送数据过来,接着主控再对这些数据进行处理,以响应对应的操作。如果TP进入休眠模式,则主机可以通过WAKE信号线唤醒TP,使之正常工作。

二,软件代码分析

linux系统中,TP驱动流程如下:

先进行I2C等初始化,然后TP等待被触摸。如果有触摸事件发生,TP会把这些数据存储在寄存器里;同时产生一个中断给主控,主控接收到中断后调用中断处理函数,中断处理函数向工作队列提交一个任务,最后执行中断服务函数,通过i2c_transferTP的寄存器里获取刚才得到的触摸事件的记录;主控接收到数据以后,对从I2C得到的数据进行判断:是按下,弹起,还是move;然后把这些分好类的数据再上报给input子系统;input子系统再对这些数据进行分析,以决定调用哪个事件。

下面从头开始分析代码:一切驱动的入口module_init(),在驱动的最后位置找了下,没看到module_init()函数,倒是看到这个late_initcall(ft5x0x_mod_init)module_exit(ft5x0x_mod_init)相对应,原来late_initcall就是这个驱动的入口。有关late_initcall()module_init()函数的区别可以参考此文章:

http://blog.csdn.net/cstk502/article/details/6579231

1,我们接着看ft5x0x_mod_init()内部的主要内容:

1)首先定义了一个i2c_board_info结构体,以及i2c_adapteri2c_client指针。

紧接着就是对i2c_board_info结构体和i2c_adapter指针进行填充,这两个结构体的主要功能是为了收集资源。填充了i2c_board_info这个结构体中的addrirqtype,接着调用i2c_get_adapter2)函数,初始化了adapter结构体。

2client = i2c_new_device(adapter, &info); 这个函数利用i2c_board_info结构体和i2c_adapter指针生成了一个新的i2c_client,并且将这个i2c_client注册到了i2c_device链表中。

3i2c_add_driver(&ft5x0x_driver); 这个函数的作用就是将&ft5x0x_driver注册到i2c_driver链表中,在每次注册完i2c_device或者i2c_driver后,都会有一个匹配过程,主要是通过名字匹配,如果匹配成功,则会调用i2c_driverprobe函数。

2ft5x0x_probe()函数:

接下来我们去看看ft5x0x_driver,这里有几个回调函数,但最重要的是probe函数。我们来看probe都实现了哪些功能。

ft5x0x_probe函数开头有两个非常重要的参数定义:

1struct ft5x0x_data *ft5x0x_ts;主要是为了接受i2c_clinti2c_board_info传来的资源,这个是为了综合整个TP驱动中使用的所有资源,包括中断,输入子系统,工作队列等,应该说,整个驱动最难的地方在于如何设计这个结构体。

2)主要的工作如下:

i2c_set_clientdata(client, ft5x0x_ts); //tsi2c_client进行绑定

err = ft5x0x_chip_init(client);

上面这个函数又调用了i2c_get_clientdata(client);进一步跟踪进去会发现其实是把client->p->driver_data给取出来,放到ft5x0x_ts里,以便进行i2c_set_clientdata(client, ft5x0x_ts);

ft5x0x_ts->input_dev = input_allocate_device();//source insight 点进去看原形可知,这个函数其实就是分配内存。有关input_device的原理,可以参见这篇文章:http://blog.csdn.net/wealoong/article/details/7580916

err = input_register_device(ft5x0x_ts->input_dev);// 上一个函数是分配空间,分配完之后就是注册了

3,接下来要分析函数:

INIT_WORK(&ft5x0x_ts->pen_event_work, ft5x0x_work_func);

//设置ts中的任务,即让ft5x0x_ts->pen_event_work指向我们自己定义的函数ft5x0x_work_func

ft5x0x_ts->ts_workqueue=create_singlethread_workqueue(dev_name(&client->dev));

//创建一个工作队列

err = request_irq(_sui_irq_num, fts_ts_irq, 0, "qt602240_ts", ft5x0x_ts);//请求一个中断

1)在分析它们之前,先简要说明一下INIT_WORK()这个宏。

内核里对这个函数是这样定义的 #define INIT_WORK(_work, _func),可以理解为INIT_WORK会在你定义的_work工作队列里面增加一个工作任务,该任务就是_func。看许多驱动模块的时候会发觉work就是一个工作队列,一般是结构体work_struct,主要的目的就是用来处理中断的。比如在中断里面要做很多事,但是比较耗时,这时就可以把耗时的工作放到工作队列。说白了就是系统延时调度的一个自定义函数。

我们深入到fts_work_func这个函数里。

fts_work_func调用了fts_read_data函数,在fts_work_func函数里实现了收集触摸信息,计算x,y坐标,并把这些信息上报给input系统的功能。

2)分析中断请求函数:

err = request_irq(_sui_irq_num, fts_ts_irq, 0, "qt602240_ts", ft5x0x_ts);

此函数的原型是:

request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,

          const char *name, void *dev);

在发生对应于第 1个参数 irq 的中断时,则调用第 2 个参数 handler 指定的中断服务函数(也就是把 handler() 中断服务函数注册到内核中 )

3 个参数 flags 指定了快速中断或中断共享等中断处理属性。

4 个参数 name 通常是设备驱动程序的名称。改值用在 /proc/interrupt 系统 (虚拟) 文件上,或内核发生中断错误时使用。

5 个参数 dev_id 可作为共享中断时的中断区别参数,也可以用来指定中断服务函数需要参考的数据地址。

返回值:函数运行正常时返回 0 ,否则返回对应错误的负值。

中断服务函数做了哪些事?我们看fts_ts_irq

3)分析中断服务函数fts_ts_irq

首先检测中断标志是否清除,如果没有清除,则清除,然后

if(!work_pending(&ft5x0x_ts->pen_event_work)){

            queue_work(ft5x0x_ts->ts_workqueue, &ft5x0x_ts->pen_event_work);

        }

即先检查ft5x0x_ts->pen_event_work所指的工作是不是在等待状态,如果不是,就调用

queue_work(ft5x0x_ts->ts_workqueue, &ft5x0x_ts->pen_event_work);

queue_work就是调度执行一个任务,这个任务的指针就是ft5x0x_ts->pen_event_work

由这里INIT_WORK(&ft5x0x_ts->pen_event_work, fts_work_func);

可以发现,ft5x0x_ts->pen_event_work这个任务指针其实就是fts_work_func

fts_work_func函数上面已经分析过,其实现了收集触摸信息,计算x,y坐标,并把这些信息上报给input系统的功能。

有关fts_work_func这个函数的详细分析,应该可以单独作为一篇或者更多篇文章了。

这里也验证了,中断服务程序一般分为中断上半部和下半部。其中上半部处理比较紧急的事情,这里是清中断标识,下半部处理其它事情。注意,中断上半部要尽量简短,以名影响其它中断,把比较耗时的任务应该放在中断下半部。中断下半部的实现方法有:软中断,tasklet,工作队列,详细可参考:

http://www.cnblogs.com/wang_yb/archive/2013/04/23/3037268.html

这里用到的是工作队列。

 

阅读(360) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~