MTK中的TP代码结构并不复杂,相比于其他的系统更为的简单些。它使用的是input子系统,通过该系统来上报触摸按键。

  首先我们来看看TP的文件夹下的各代码文件的功能。

文件名

具体功能

关系文件

tpd.h

一些宏和extern 函数,外部使用

Mtk_tpd.c

tpd_button.c

关于实体按键的定义

Tpd_calibrate.c

矫准,比如偏移,可能是MTK以前做电阻屏留下的架构

Tpd_calibrate.h

矫准,一些宏和数据结构

Tpd_debug.c

一些函数用于debug信息

Tpd_debug.h

一些dubug信息和函数申明

Tpd_default.c

函数似乎为完成,函数只有一个

Tpd_default.h

似乎未完成

Tpd_init.c

空文件夹

Tpd_misc.c

导出一些符号,基本都是切换模式函数

Tpd_setting.c

传些参数至上层应用

MTK_tpd.c

关键代码区

met_ftrace_touch.h

Ftrace工具,用来代码内追踪运行情况

以上代码文件中较为重要的就是mtk_tpd.c,故重点分析该文件。

在此会有以下几个关键的点:

1.mtk_tpd.c中的函数运行流程。

2.mtk_tpd.c中的input系统。

3.注册i2C

4.tpd_driver_add函数

5.LDO芯片设置

6.通过设备数或者其他方式获取RST,EINT引脚号

7.通过设备节点获得中断,并请求一个中断号,和注册中断handle

8.运行线程开启

9.中断处理函数,唤醒线程,并上报键值

在此,我将这几个分为一些几部分:

一、注册MTK下的TP框架,与建立I2C框架。

二、在probe函数中完成相应电源,设备数,硬件中断,GPIO等设置。

三、建立一个上报框架分为如下:1)开启一个线程2)申请一个中断irq来绑定硬件中断触发3)irq_handle中唤醒work 4)work在唤醒wait事件5)开启的线程等到wait事件执行上报关键代码。,否则睡眠。

四、填充关键的TP上报代码(input系统上报)。

1.mtk_tpd.c中的函数运行流程。
mtk_tpd.c中,我们最先查看init函数,也就是module添加。

 static int tpd_remove(struct platform_device *pdev)
{
input_unregister_device(tpd->dev);
return ;
} /* called when loaded into kernel */
static int __init tpd_device_init(void)
{
TPD_DEBUG("MediaTek touch panel driver init\n");
if (platform_driver_register(&tpd_driver) != ) {
TPD_DMESG("unable to register touch panel driver.\n");
return -;
}
return ;
}

可能有些版本的代码是使用了workqune去注册的,使用这个是让tpd的probe在所有子tp系统add之后再运行mtk_tpd中的probe。

看到上面代码中,在init中建立一个workqueue,这样使得tpd_init_work_callback中的platform_driver_register延迟工作,在被内核调度室才会进行注册,注册时的probe函数也随之延后运行。(具体作用暂时不知,我们仅仅知道注册了一个platform设备)。
接下来再看tpd_driver_add:

 /* Add driver: if find TPD_TYPE_CAPACITIVE driver successfully, loading it */
int tpd_driver_add(struct tpd_driver_t *tpd_drv)
{
int i; if (g_tpd_drv != NULL) {
TPD_DMESG("touch driver exist\n");
return -;
}
/* check parameter */
if (tpd_drv == NULL)
return -; //runyee zhou add device info,20161012
#if defined(CONFIG_RUNYEE_DEVICE_INFO_SUPPORT)
hct_touchpanel_device_add(tpd_drv,DEVICE_SUPPORTED);
#endif tpd_drv->tpd_have_button = tpd_dts_data.use_tpd_button;
/* R-touch 电阻屏,geneic也就是list[0]为电阻屏*/
if (strcmp(tpd_drv->tpd_device_name, "generic") == ) {
tpd_driver_list[].tpd_device_name = tpd_drv->tpd_device_name;
tpd_driver_list[].tpd_local_init = tpd_drv->tpd_local_init;
tpd_driver_list[].suspend = tpd_drv->suspend;
tpd_driver_list[].resume = tpd_drv->resume;
tpd_driver_list[].tpd_have_button = tpd_drv->tpd_have_button;
return ;
}
for (i = ; i < TP_DRV_MAX_COUNT; i++) {
/* add tpd driver into list 使用该函数就会被填入到list中*/
if (tpd_driver_list[i].tpd_device_name == NULL) {
tpd_driver_list[i].tpd_device_name = tpd_drv->tpd_device_name;
tpd_driver_list[i].tpd_local_init = tpd_drv->tpd_local_init;
tpd_driver_list[i].suspend = tpd_drv->suspend;
tpd_driver_list[i].resume = tpd_drv->resume;
tpd_driver_list[i].tpd_have_button = tpd_drv->tpd_have_button;
tpd_driver_list[i].attrs = tpd_drv->attrs;
#if 0
if (tpd_drv->tpd_local_init() == ) {
TPD_DMESG("load %s successfully\n",
tpd_driver_list[i].tpd_device_name);
g_tpd_drv = &tpd_driver_list[i];
}
#endif
break;
}
if (strcmp(tpd_driver_list[i].tpd_device_name, tpd_drv->tpd_device_name) == )
return ; /* driver exist */
} return ;
}

在此函数中的tpd_driver_list是一个全局的tpd_driver_t结构体,里面的TP_DRV_MAX_COUNT是支持的最大tp设备数。
驱动中调用add来向tpd_driver_list添加一个新的设备,并在添加前检查该名字是否为NULL,保证add在最末尾。
  接着看probe函数,我们跳过probe前面部分,直接到:

     /* save dev for regulator_get() before tpd_local_init() */
tpd->tpd_dev = &pdev->dev;
for (i = ; i < TP_DRV_MAX_COUNT; i++) {
/* add tpd driver into list */
if (tpd_driver_list[i].tpd_device_name != NULL) {
tpd_driver_list[i].tpd_local_init();//执行具体TP驱动的local_init
/* msleep(1); */
if (tpd_load_status == ) {
TPD_DMESG("[mtk-tpd]tpd_probe, tpd_driver_name=%s\n",
tpd_driver_list[i].tpd_device_name);
g_tpd_drv = &tpd_driver_list[i];
//
#if defined(CONFIG_RUNYEE_DEVICE_INFO_SUPPORT)
hct_set_touch_device_used(g_tpd_drv->tpd_device_name, );
#endif
break;
}
}
}
if (g_tpd_drv == NULL) {
if (tpd_driver_list[].tpd_device_name != NULL) {
g_tpd_drv = &tpd_driver_list[];
/* touch_type:0: r-touch, 1: C-touch */
touch_type = ;
g_tpd_drv->tpd_local_init();
TPD_DMESG("[mtk-tpd]Generic touch panel driver\n");
} else {
TPD_DMESG("[mtk-tpd]cap touch and Generic touch both are not loaded!!\n");
return ;
}
}

在这里面我们可以看到,这里会遍历tpd_driver_list这个表,并且执行表中所有的tpd_local_init函数,而tpd_local_init通常会注册i2C驱动,在register时会执行i2c的probe函数,这样在一个probe函数中将所有的TP注册全部完成。
在最末尾,执行了input系统注册:

     /* use fb_notifier */
tpd_fb_notifier.notifier_call = tpd_fb_notifier_callback;//和上层接收TP是否存在相关
if (fb_register_client(&tpd_fb_notifier))
TPD_DMESG("register fb_notifier fail!\n");
/* TPD_TYPE_CAPACITIVE handle */
if (touch_type == ) {
//正常的input设备注册
set_bit(ABS_MT_TRACKING_ID, tpd->dev->absbit);
set_bit(ABS_MT_TOUCH_MAJOR, tpd->dev->absbit);
set_bit(ABS_MT_TOUCH_MINOR, tpd->dev->absbit);
set_bit(ABS_MT_POSITION_X, tpd->dev->absbit);
set_bit(ABS_MT_POSITION_Y, tpd->dev->absbit);
input_set_abs_params(tpd->dev, ABS_MT_POSITION_X, , TPD_RES_X, , );
input_set_abs_params(tpd->dev, ABS_MT_POSITION_Y, , TPD_RES_Y, , );
#if defined(CONFIG_MTK_S3320) || defined(CONFIG_MTK_S3320_47) \
|| defined(CONFIG_MTK_S3320_50) || defined(CONFIG_MTK_MIT200) \
|| defined(CONFIG_TOUCHSCREEN_SYNAPTICS_S3528) || defined(CONFIG_MTK_S7020)
input_set_abs_params(tpd->dev, ABS_MT_PRESSURE, , , , );
input_set_abs_params(tpd->dev, ABS_MT_WIDTH_MAJOR, , , , );
input_set_abs_params(tpd->dev, ABS_MT_WIDTH_MINOR, , , , );
input_mt_init_slots(tpd->dev, , );
#else
input_set_abs_params(tpd->dev, ABS_MT_TOUCH_MAJOR, , , , );
input_set_abs_params(tpd->dev, ABS_MT_TOUCH_MINOR, , , , );
#endif /* CONFIG_MTK_S3320 */
TPD_DMESG("Cap touch panel driver\n");
}
input_set_abs_params(tpd->dev, ABS_X, , TPD_RES_X, , );
input_set_abs_params(tpd->dev, ABS_Y, , TPD_RES_Y, , );
input_abs_set_res(tpd->dev, ABS_X, TPD_RES_X);
input_abs_set_res(tpd->dev, ABS_Y, TPD_RES_Y);
input_set_abs_params(tpd->dev, ABS_PRESSURE, , , , );
input_set_abs_params(tpd->dev, ABS_MT_TRACKING_ID, , , , ); if (input_register_device(tpd->dev))
TPD_DMESG("input_register_device failed.(tpd)\n");

在此就不展开input_set_abs_params参数的意义,后面会继续深入。

2.mtk_tpd.c中的input系统

要向用户空间发送信息,且是中断,少不了input系统,这里使用MTK中自带的GT9XXTB_hotknot来分析:

 static int tpd_history_x = , tpd_history_y;
static void tpd_down(s32 x, s32 y, s32 size, s32 id)
{
if ((!size) && (!id)) {
input_report_abs(tpd->dev, ABS_MT_PRESSURE, );
input_report_abs(tpd->dev, ABS_MT_TOUCH_MAJOR, );
} else {
input_report_abs(tpd->dev, ABS_MT_PRESSURE, size);
input_report_abs(tpd->dev, ABS_MT_TOUCH_MAJOR, size);
/* track id Start 0 */
input_report_abs(tpd->dev, ABS_MT_TRACKING_ID, id);
} input_report_key(tpd->dev, BTN_TOUCH, );
input_report_abs(tpd->dev, ABS_MT_POSITION_X, x);
input_report_abs(tpd->dev, ABS_MT_POSITION_Y, y);
input_mt_sync(tpd->dev);
TPD_DEBUG_SET_TIME;
TPD_EM_PRINT(x, y, x, y, id, );
tpd_history_x = x;
tpd_history_y = y;
/* MMProfileLogEx(MMP_TouchPanelEvent, MMProfileFlagPulse, 1, x+y); */
if (tpd_dts_data.use_tpd_button) {
if (FACTORY_BOOT == get_boot_mode() ||
RECOVERY_BOOT == get_boot_mode())
tpd_button(x, y, );
}
}

这一段tdp_down是关键的上报代码,也就是说最后从TP芯片来的坐标数据需要通过以上input_report_adbs等函数来上报,那先暂时记住该部分。其中的input其实是不需要再次去注册的,因为在mtk_tpd.c中已经注册,只需要:extern struct tpd_device *tpd; 例子中在include/tpd_gt9xx_common.h有定义。

那么我们大概清楚了,MTK下的TP其实就是我们自己写驱动上报(我们需要做的事),其他的input系统注册我们就不操心了。那么大多数TP都是i2c,我们则需要进行i2c注册。

3.具体驱动中的i2c注册

注册I2C这里就简略提一下,i2C可以使用各种方式注册,在此实例使用的是i2c_board_info来注册,同样的先注册device,然后在drivers注册时会匹配进入probe,其中需要做以下事情:

static s32 tpd_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
//1.i2c_clien获得,给read,write函数使用
//2.上电,因为有些TP可能是使用LDO去控制的,所以要开启电源regulator_set_voltage或者mtk的hwPowerDown(MT65XX_POWER_LDO_VGP2, "TP");
//3.使用设备树,或者直接设置RST,INT脚的状态。
//4.简易的test测试tp是否存在,比如读取version,添加异常处理
//5.INT脚配置硬件中断申请,并链接处理函数
//6.使用 kthread_run开启一个可休眠线程,等待中断唤醒处理坐标上报
//7.添加自己的input参数,比如压力,按压面的size
//8.与芯片相关的其他操作
}

以上操作都可在代码中发现,也是一些基本的必须的设置,调试时应该先以大体框架通过为主,大体框架就是,local_init->i2c_probe->相关函数设置(thread_run有没有跑,中断函数是否申请了,设备树是否成功匹配),然后再去进行硬件调试:i2c通不通,中断是否能正常触发,能否读取版本等。

4.tpd_driver_add函数

 /* called when loaded into kernel */
static int __init tpd_driver_init(void)
{
GTP_INFO("MediaTek gt91xx touch panel driver init\n");
tpd_get_dts_info();
if (tpd_driver_add(&tpd_device_driver) < )
GTP_INFO("add generic driver failed\n"); return ;
}

在init函数中加入tpd_driver_add 函数。这样只要以下流程完成即可调试硬件。

至此,添加一个MTK TP的框架搭建完了,回顾下,主要是:
1. I2C框架,device与driver注册,还有probe函数(接下来的工作)
2. 使用tpd_driver_add向MTK TP框架添加设备,完成local_tpd_init函数
总结下运行流程如下:

 5.各操作实例

5.1.LDO芯片设置
有些硬件使用PMU来为TP供电,所以有可能需要使用代码来设备如:

如果没有的话就直接设置供电打开即可。

5.2通过设备树或者其他方式获取RST,EINT引脚号

有些平台使用的是设备树来获取的这两个引脚,这里我的是MTK6755平台,如下:

也可以使用GPIO_request来获取,只要能做到控制这两个引脚即可。

5.3通过设备节点获得中断,并请求一个中断号,和注册中断handle

因为上报事件应该定义为一个中断事件,故应该为ENIT引脚分配一个中断号,并申请中断handle。在此使用的是通过设备节点来申请的中断节点,也是使用的是MTK的设备树来获取的,所以可能需要修改dtsi。

紫色框中是MTK的注册硬件IRQ handle 的方法,而这里使用的是设备树获取中断硬件中断号,并分配中断向量号,之候使用request来注册中断handle。

5.4运行线程开启

报点需要高响应,延迟低,所以为TP开启一个线程来保证高效。具体代码如下:

我们进入ilitek_irq_handle_thread

红色框中是关键的TP坐标上报代码,而在此之前这个线程是睡眠的,只是偶尔运行一次,该线程等待中断事件打断,并运行,而唤醒的代码则在之前申请的硬件中断的handle中的work会唤醒。

5.5中断处理函数,唤醒线程,并上报键值

该函数则是唤醒wait,则在上节的线程会被唤醒,进行关键的上报代码。
也就是说当你的手触摸屏幕,屏幕的中断引脚会产生中断(拉低或者高),使得申请的硬件中断handle运行,handle中唤醒wait,接着运行着的线程被叫醒,执行坐标上报关键代码。

至此一个驱动大概框架就是这样,后面再为大家带来一些细致的讲解

MTK-TP(触屏)解读一的更多相关文章

  1. JavaScript触屏滑动API介绍

    随着触屏手机.平板电脑的普及和占有更多用户和使用时间,触屏的触碰.滑动等事件也成为javaScript开发不可避免的知识,现在何问起就和大家一起学习js的触屏操作,js的触屏touchmove事件,为 ...

  2. jQuery flickity 滑动触屏

    flickity是一款自适应手机触屏滑动插件,它的API参数很丰富,包括对齐方式.循环滚动.自动播放.是否支持拖动.是否开启分页.是否自适应窗口等. 在线实例 实例演示 使用方法 <div cl ...

  3. 转:Android随笔之——使用Root权限实现后台模拟全局按键、触屏事件方法(类似按键精灵)

    本文转载自CSDN的jzj1993,原文连接:http://blog.csdn.net/jzj1993/article/details/39158865 有时我们需要使用安卓实现在后台模拟系统按键,比 ...

  4. 触屏touchstart 与 click

    设计效果:当手指点击或触摸红框线menuList之外的部分时,弹框menuList消失. 问题:在优化触屏版的时候发现如图问题,当menuList弹出,手指触摸屏幕向下滑动时,menuList弹框不消 ...

  5. touch移动触屏滑动事件

    移动端触屏滑动的效果其实就是图片轮播,在PC的页面上很好实现,绑定click和mouseover等事件来完成.但是在移动设备上,要实现这种轮播的效果,就需要用到核心的touch事件.处理touch事件 ...

  6. 朋友圈常见单页面触屏滑动上下翻屏功能jQuery实现

    翻页插件:实现原理,用margin-top来控制页面容器位置来实现上下翻页.margin这属性很好用,可以用来制作侧栏动画滑出菜单(左菜单,右内容,控制两者的margin实现):或者head下滑菜单 ...

  7. 触屏手机3G网站设计

    随着智能手机iphone和Android的热潮,衍生出基于Safari和Chrome浏览器的触屏手机网站Touch Screen Mobile Website. 触屏手机网站在中国还属于起步阶段,从行 ...

  8. Unity学习疑问记录之触屏

    当将Unity游戏运行到ios或android设备上时,桌面系统中的鼠标左键操作可以自动变为手机屏幕上的触屏操作,但鼠标操作无法实现一些特有的触屏操作,比如多点触屏. 触控对于Android移动设备来 ...

  9. 原生js实现网页触屏滑动

    前言: 我有一个html格式的2048游戏,可以用键盘上下左右操作,但是放到手机上就抓瞎了.于是想修改一下代码,将键盘事件改成手机触屏事件. html5 的touch事件 html5支持touch事件 ...

随机推荐

  1. Nginx 自定义404、500、502 页面

    利用nginx的反向代理来实现 服务器404 和500 等状态码的自定义页面 1.nginx配置文件 nginx.conf 配置开启代理错误拦截 和配置页面  下划线部分  http { ...... ...

  2. python中matplotlib画图

    参考 https://blog.csdn.net/u010358304/article/details/78906768 https://www.cnblogs.com/onemorepoint/p/ ...

  3. BZOJ 1257 - 余数之和 - [CQOI2007]

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1257 题意: 给定正整数 $n,k$,求 $(k \bmod 1) + (k \bmod ...

  4. Git branch && Git checkout常见用法

    https://www.cnblogs.com/qianqiannian/p/6011404.html git branch 和 git checkout经常在一起使用,所以在此将它们合在一起 1.G ...

  5. configure文件的生成

    https://blog.csdn.net/mitesi/article/details/44773951 make 根据Makefile编译源代码,连接,生成目标文件,可执行文件. make cle ...

  6. mysql主从服务搭建

    一.安装mysql 检测当前centos是否安装了mysql:yum list installed | grep mysql yum list installed | grep mariadb    ...

  7. 转 linux安装jdk环境(多种方式)

    linux系统通用安装通过tar.gz压缩包安装此方法适用于绝大部分的linux系统 1.先下载tar.gz的压缩包,这里使用官网下载. 进入: http://www.oracle.com/techn ...

  8. 什么是span?跨径

    研究zipkin时候,发现有个span的概念 https://segmentfault.com/a/1190000012342007

  9. C++ 用三元组表示法存储稀疏矩阵

    若有一个矩阵(m*n),其中非0元素个数远少于数值为0的元素个数,若开辟一个m*n大空间,来存储这样一个很多元素值为0的矩阵,浪费空间,于是我们只存储这些非0的元素的下标及数值 用一个结构体——三元组 ...

  10. UGUI动态更换精灵图片

    //动态更换精灵图片 m_headimage.overrideSprite = Resources.Load("texture/"+info.HeadPortrait,typeof ...