Mtk touch panel驱动/TP驱动详解

TP还算是比LCM好理解的多。
在启动过程中,先注册/mediatek/custom/command/kernel/touchpanel目录下的具体驱动(如focaltech_driver.c),init函数里实现i2c_register_board_info后把该tp加入到一个数组tpd_driver_list[i]中。之后注册mtk_tpd.c,该文件会在init函数里注册platform设备驱动,直接来到mtk_tpd.c中的tpd_probe中,在probe执行的过程中会实现与tpd_driver_list[i]这个进行匹配找出具体驱动里tpd_driver,然后调用focaltech_driver.c里边的tpd_local_init函数,该函数里边一开始直接调用i2c_add_driver函数,然后就来到focaltech_driver.c该文件的tpd_probe文件。下面的文章介绍仅仅放出了两个文件的函数说明,这里我理清了思路之后放出来方便阅读。
文章来自:http://blog.csdn.net/sunweizhong1024/article/details/8572121

1、

MTk Touch驱动程序
1.1、    MTKTouch 驱动的组成
Mtk  Touch  driver 驱动包括:Mtkplatform 虚拟平台设备驱动、Module touch IC 驱动、Inputsubsystem。
Mtk platform 设备驱动是mtk为了兼容多个touch IC驱动而设计出来的虚拟驱动,它会去遍历每一个touch  IC驱动,直到其中一个初始化成功。
Linux input_subsystem是linux的输入子系统,我们的输入设备都要通过这个子系统进行上报事件以及设置事件的类型。
 
图1 MTk Touch 架构图
1.2、    Platform驱动
Platfiorm 驱动主要是负责mtk虚拟touch 平台的驱动的注册,执行probe函数遍历每一个具体的touch IC驱动。
   Kernel/touchpanel/src/mtk_tpd.c
Platform 设备moudle_init 函数:

static int __init tpd_device_init(void) {
         printk("MediaTek touch panel driverinit\n");
         if(platform_driver_register(&tpd_driver)!=0){
       TPD_DMESG("unable to register touch paneldriver.\n");
       return -1;
      }  
      return 0;

}
module_init(tpd_device_init)
上面的moduel_init首先加载的函数tpd_device_init函数中调用platform_driver_register进行注册一个mtk_touch_driver平台驱动。
其中注册的平台驱动tpd_driver定义如下:
static struct platform_driver tpd_driver = {
   .remove    = tpd_remove,
   .shutdown   =NULL,
   .probe     = tpd_probe,
    #ifndefCONFIG_HAS_EARLYSUSPEND
   .suspend    =NULL,
   .resume    = NULL,
   #endif
   .driver    = {
       .name = TPD_DEVICE,
   },
};

根据platform bus mathc的规则:driver_name和device_name相同就会调用platform_drive的probe函数。这里牵扯到Linux的设备模型知识,需要了解的人可以看下Linux platformbus。
#defineTPD_DEVICE           "mtk-tpd"
Platform device 注册:retval =platform_device_register(&mtk_tpd_dev);
mtk_tpd_dev的定义如下:
static struct platform_device mtk_tpd_dev = {
    .name ="mtk-tpd",
   .id   = -1,
};
/mediatek/platform/mt6589/kernel/core/mt_devs.c
上面这个路径是mtk的板极支持的文件,很多板极的注册和初始化的动作都是放在上面的C文件里面的。
根据我上面所说的platform bus的match 规则,设备名字和驱动名字相同。进而就会调用
1.2.1、Platform 驱动入口probe函数
static int tpd_probe(struct platform_device *pdev){
      int  touch_type = 1; //0:R-touch, 1: Cap-touch
      int i=0;
     TPD_DMESG("enter %s, %d\n",__FUNCTION__, __LINE__); 
    
     //if(g_tpd_drv == NULL||tpd_load_status ==0) 
   if((tpd=(struct tpd_device*)kmalloc(sizeof(struct tpd_device),GFP_KERNEL))==NULL) return -ENOMEM;//分配一个Mtktpd_device
    memset(tpd,0, sizeof(struct tpd_device));

if((tpd->dev=input_allocate_device())==NULL) { kfree(tpd);return -ENOMEM; }
  //上面是分配一个input 设备
    TPD_RES_X =simple_strtoul(LCM_WIDTH, NULL, 0);
    TPD_RES_Y =simple_strtoul(LCM_HEIGHT, NULL, 0);
  
   printk("mtk_tpd: TPD_RES_X = %d, TPD_RES_Y = %d\n", TPD_RES_X,TPD_RES_Y);
  
    tpd_mode =TPD_MODE_NORMAL;
   tpd_mode_axis = 0;
    tpd_mode_min= TPD_RES_Y/2;
    tpd_mode_max= TPD_RES_Y;
   tpd_mode_keypad_tolerance =TPD_RES_X*TPD_RES_X/1600;
   
   tpd->dev->name = TPD_DEVICE;
   set_bit(EV_ABS, tpd->dev->evbit);
   set_bit(EV_KEY, tpd->dev->evbit);
   set_bit(ABS_X, tpd->dev->absbit);
   set_bit(ABS_Y, tpd->dev->absbit);
   set_bit(ABS_PRESSURE, tpd->dev->absbit);
   set_bit(BTN_TOUCH, tpd->dev->keybit);
set_bit(INPUT_PROP_DIRECT,tpd->dev->propbit);
//上面都是input 设备事件类型的设置
#if 1   
  for(i = 1; i < TP_DRV_MAX_COUNT;i++)
   {
         
      if(tpd_driver_list[i].tpd_device_name !=NULL)//这里是在遍历mtk的tpd_driver_list里面的所有的驱动,判断名字是否为NULL,每一个moduletouch IC 驱动都会添加到这个静态数组里面
      {
         tpd_driver_list[i].tpd_local_init();
         //msleep(1);
         if(tpd_load_status ==1) {//这里我们会判断我们所遍历的每一个moduleIC驱动的初始化函数。成功的话就会将tpd_load_status至1,所以我们就是通过这个值判断哪一个驱动的
            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];
            break;
         }
      }   
  }
。。。。。。。。。。。。。。
。。。。。。。。。。。。。。
    #ifdefCONFIG_HAS_EARLYSUSPEND
   MTK_TS_early_suspend_handler.suspend =g_tpd_drv->suspend;
   MTK_TS_early_suspend_handler.resume =g_tpd_drv->resume;
register_early_suspend(&MTK_TS_early_suspend_handler);
//touch 的suspend应该属于eraly_suspend
   #endif        
#endif     
。。。。。。。。。。。。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。。。。。。。。。。
   if(input_register_device(tpd->dev))//将我们的touch以Input方式进行注册
       TPD_DMESG("input_register_device failed.(tpd)\n");
   else
         tpd_register_flag = 1;
   
    #if0
     if(touch_type ==0) 
     {
        g_tpd_drv->tpd_local_init();
    }   
      #endif
   if(g_tpd_drv->tpd_have_button)
   {
      tpd_button_init();
   }

return0;
}


1.3、    Ft6306module driver
Ft6306是敦泰的Touch IC ,这个里面,我们可以进行IC的上电、设置中断、UpdateFW等动作。
Ft6306中首先执行的代码是:
static int __init tpd_driver_init(void) {
    printk("MediaTek FT5206 touch panel driverinit\n");
    i2c_register_board_info(0, &ft5206_i2c_tpd,1);
       if(tpd_driver_add(&tpd_device_driver) <0)
          TPD_DMESG("add FT5206 driverfailed\n");
     return0;
 }
module_init(tpd_driver_init);
tpd_driver_init函数会注册一个I2CTouch设备、调用tpd_driver_add添加添加一个驱动,其实就是讲这个驱动添加到上面说的静态数组pd_driver_lis里面。
Tpd_driver_add函数定义如下:
int tpd_driver_add(struct tpd_driver_t *tpd_drv)
{
。。。。。。。。。。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。。。。。。。。   
for(i = 1; i < TP_DRV_MAX_COUNT; i++)
   {
      
      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;
         #if 0
         if(tpd_drv->tpd_local_init()==0)
         {
            TPD_DMESG("load %s sucessfully\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) == 0)
      {
         return 1; // driver exist
      }
   }
   
    return0;
}
上面会将我们的每一个注册的Moudle IC touch驱动进行添加到tpd_driver_list数组中。添加进去后,我们就会调用tpd_local_init函数进行touch IC的初始化。

1.3.1、Module tpd_local_init函数
static int tpd_local_init(void)
 {
    inti;
 
  TPD_DMESG("Focaltech FT5206 I2C TouchscreenDriver (Built %s @ %s)\n", __DATE__, __TIME__);
 
 
  if(i2c_add_driver(&tpd_i2c_driver)!=0)
     {
        TPD_DMESG("unable to add i2cdriver.\n");
        return -1;
}
。。。。。。
}
/kernel/touchpanel/ft6106/ft5206_drive.c
上面是以I2C的方式注册FT 驱动。记得在前面我们有注册一个I2C 设备。I2C总线也有一套自己的匹配方式,是通过id_table里面的值进行匹配的,当匹配成功就会调用I2c驱动的probe函数。
 tpd_i2c_driver定义如下:
static struct i2c_driver tpd_i2c_driver = {
  .driver = {
     .name =TPD_DEVICE,
     .owner =THIS_MODULE,
  },
  .probe = tpd_probe,
  .remove =__devexit_p(tpd_remove),
  .id_table = ft5206_tpd_id,
  .detect = tpd_detect,
//  .address_data =&addr_data,
  .address_list = (const unsigned short*)forces,
 };

当我们匹配成功后,我们就会调用上面的tpd_probe函数。
1.3.1.1、module I2C probe函数
Tpd_probe函数是touch IC 的核心函数,在里面我们会进行上电、申请中断、设置GPIO等、UpdateFW、IC提供的控制 touch 的interface等。
tpd_probe函数定义如下:
static int __devinit tpd_probe(struct i2c_client *client, conststruct i2c_device_id *id)
 {    
    int retval =TPD_OK;
    chardata;
    i2c_client =client;
#if (defined(MT6575)||defined( MT6577)||defined(CONFIG_ARCH_MT6589))
    //power on,need confirm with SA
   hwPowerOn(TPD_POWER_SOURCE_CUSTOM, VOL_2800,"TP");//这里是在上电,我在porting的过程中就遇到了上电没有成功,后来查看电路才上对Pin脚,下面会有touch的电路图

mt_set_gpio_mode(GPIO_CTP_RST_PIN,GPIO_CTP_RST_PIN_M_GPIO);//设置GPIO的工作模式
   mt_set_gpio_dir(GPIO_CTP_RST_PIN,GPIO_DIR_OUT);//将GPIO设置成out方向
   mt_set_gpio_out(GPIO_CTP_RST_PIN,GPIO_OUT_ONE);
   msleep(2);
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
   }
    else if(data== 0x55)
   {
      sprintf(tpd_chip_name,"%s","FT5x06");
   }

tpd_load_status = 1;
    thread =kthread_run(touch_event_handler, 0,TPD_DEVICE);//这里是创建一个线程,我们会执行这个线程
    if(IS_ERR(thread))
   { 
      retval = PTR_ERR(thread);
      TPD_DMESG(TPD_DEVICE " failed to create kernelthread: %d\n", retval);
   }

上面创建的线程,我们会进行申请中断、读取坐标,上报坐位给上层使用。(这部分最重要的东西作者你居然就这样一句话给跳过了,无语无语,从上边跟到这里不就是为了最后这部分代码里实现的内容。然后再去网上找发现关于这部分的资料还真少,这里我整理了一下这边导师做的归纳之后奉献出来)

二:中断处理流程

注册中断后,每次触摸到TP就会产生硬件中断,调用到中断处理函数tpd_eint_interrupt_handler

从中断处理函数tpd_eint_interrupt_handler()分析下TP的触摸事件处理流程

static voidtpd_eint_interrupt_handler(void)

{

TPD_DEBUG_PRINT_INT;

tpd_flag = 1;

//唤醒内核进程touch_event_handler中的等待队列

wake_up_interruptible(&waiter);

}

static int touch_event_handler(void*unused)

{

//设置Task的状态为可中断的等待状态

set_current_state(TASK_INTERRUPTIBLE);

//满足tpd_flag!=0就唤醒队列

wait_event_interruptible(waiter,tpd_flag!=0);

tpd_flag = 0;  //改变条件

//设置Task的状态为执行态

set_current_state(TASK_RUNNING);

//touchinfo 函数获取手指触摸TP的信息,譬如按下的手指数目,每个点的坐标

if (tpd_touchinfo(&cinfo,&pinfo))

//tpd_down 上报按下的坐标信息

tpd_down(cinfo.Point[i].X, cinfo.Point[i].Y, i);

input_report_key(tpd->dev, BTN_TOUCH,1);

input_report_abs(tpd->dev, ABS_MT_TOUCH_MAJOR,20);

input_report_abs(tpd->dev, ABS_MT_POSITION_X,x);

input_report_abs(tpd->dev, ABS_MT_POSITION_Y,y);

//tpd_up 上报离开的信息

tpd_up(map_x, map_y, 0);

input_mt_sync      //单点同步,每个点上报后都需要同步

input_sync(tpd->dev); //每一次操作结束后的同步,不论是多点还是单点值,


 图2:touch 的电路图,我们上电的就是VGP4。

这里面,我们看到几个新函数
tpd_calibrate,tpd_down,tpd_up
主要是通过传入坐标值,对TOUCH的down和up值做处理。
void tpd_down(int raw_x, int raw_y, int x, int y, int p){
if(tpd &&tpd->dev && tpd_register_flag==1) {
input_report_abs(tpd->dev, ABS_PRESSURE,p/PRESSURE_FACTOR);
input_report_key(tpd->dev, BTN_TOUCH, 1);
input_report_abs(tpd->dev, ABS_MT_TOUCH_MAJOR,p/PRESSURE_FACTOR);
input_report_abs(tpd->dev, ABS_MT_WIDTH_MAJOR,p/PRESSURE_FACTOR);
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("D[M M M]\n",x, y, p);
TPD_EM_PRINT(raw_x,raw_y, x, y, p, 1);
}  
}
void tpd_up(int raw_x, int raw_y, int x, int y, int p) {
if(tpd &&tpd->dev && tpd_register_flag==1) {
input_report_abs(tpd->dev, ABS_PRESSURE, 0);
input_report_key(tpd->dev, BTN_TOUCH, 0);
input_report_abs(tpd->dev, ABS_MT_TOUCH_MAJOR, 0);
input_report_abs(tpd->dev, ABS_MT_WIDTH_MAJOR, 0);
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("U[M M M]\n",x, y, 0);
TPD_EM_PRINT(raw_x,raw_y, x, y, p, 0);
}  
}
这里面主要通过驱动linux的输入设备驱动函数input_report_abs,input_report_key把linux输入设备的坐标和输入设备事件提交到linux内核里面去。 

MTK 驱动(64)---Mtk touch panel驱动/TP驱动详解相关推荐

  1. 和tp数据库_CAN / CAN FD传输层(TP)详解

    本文分享CAN / CAN FD在TP层传输规则详解,因为是从个人角度解读协议,有不精准之处,希望指出. CAN/CAN FD总线TP层映射到OSI计算机七层模型是在第三层和第四层: 对应CAN Fr ...

  2. 64位JVM的Java对象头详解

    关注"Java艺术"一起来充电吧! 我们编写一个Java类,编译后会生成.class文件,当类加载器将class文件加载到jvm时,会生成一个Klass类型的对象(c++),称为类 ...

  3. android mtk平台的fm停止搜索,【MTK平台,手机工程模式知识及方法详解】

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 mtk手机工程模式下的几个应用 "MP3.MP4播放不论是用耳机还是机内喇叭,音量关到最小仍然觉得大",解决方法如下: 1)打开数字键 ...

  4. linux网卡驱动离线安装_Linux下安装网卡驱动程序详解 | 吴文辉博客

    我的centos 5.5网卡驱动是r8169,而官方网站出来了最新驱动是r8168,这让我感觉很怪异,r8169这些数据难道不代表驱动版本,还是r8169不是官方开发的.以防万一换了在说.下面将以我的 ...

  5. springboot 引入jdbc驱动_SpringBoot整合jdbc、durid、mybatis详解,数据库的连接就是这么简单...

    SpringBoot底层统一采用SpringData处理数据库,这一章主要来讲一下SpringBoot整合jdbc.durid.mybatis的方式. (一)整合jdbc 整合jdbc主要有三步: 1 ...

  6. centos7配网卡_centos7 无线网卡驱动的安装及无线网络的配置详解

    centos7 无线网卡驱动的安装及无线网络的配置 我的无线网卡的型号是:水星MERCURY 支持linux的驱动程序包是:RTL8188eus_USB_linux_v3.4.4_4749.20121 ...

  7. 你知道安卓的3D Touch吗?(Shortcut详解,你想知道的我都有)

    前因后果 苹果在iPhone 6s和iPhone 6s Plus开始新增了3D Touch,这个功能褒贬不一,但我觉得还是特别好用的,特别是在微信上付款.加好友.扫二维码,或是在支付宝上付款等等场景. ...

  8. Intel 64/x86_64/x86/IA-32处理器标志寄存器详解(6) - 64位RFLAGS

    64位标志寄存器RFLAGS 在64位模式下,RFLAGS标志寄存器扩展到了64个比特位,但是最高32比特位全部是保留位.RFLAGS(64位模式)与EFLAGS(兼容模式)的系统标志位一致,没有增加 ...

  9. Intel 64/x86_64/x86/IA-32处理器标志寄存器详解(2) - 32位EFLAGS - 80386(386, Intel386)/80486(486, Intel486)

    80386/386/Intel386标志寄存器EFLAGS 80386增加了RF/VM标志位,用于支持虚拟8086模式与指令断点调试. 80486/486/Intel486标志寄存器EFLAGS (1 ...

  10. 64位进程调用32位DLL详解

    64位进程调用32位DLL------探索 相关资料: 微软公司的官方网站针对这个问题描述如下: 在64位的windows系统中,一个64位进程不能加载一个32位dll,同理一个32位进程也不能加载一 ...

最新文章

  1. OC学习笔记之Foundation框架NSNumber、NSValue和NSDate(转)
  2. pythontkinter真实的例子_python小实例——tkinter实战(计算器)
  3. css flex属性学习笔记
  4. Android为网络请求自定义加载动画
  5. PWN-PRACTICE-BUUCTF-13
  6. Visual Studio.net 2010 Windows Service 开发,安装与调试
  7. js 获取子节点个数
  8. Unix Vi命令基本用法
  9. BOOST库介绍(八)——deadline_timer
  10. 恢复mysql数据--使用frm和ibd文件
  11. 震惊·X话最少的~“原理图更新到PCB时出现Unknown Pin: PinXXX 问题解决方案”
  12. Matlab线型、标记、颜色表示代码
  13. 2021年01月18号学习产品经理之电商项目从0-1
  14. 【分享】精通并发与Netty教程
  15. 分布式任务调度:你知道和不知道的事
  16. 什么是UE设计?UI设计又是什么?UE和UI有什么区别?
  17. 〖Python 数据库开发实战 - Python与MySQL交互篇⑫〗- 项目实战- 实现新闻管理模块
  18. 【Linux】定时任务crontab和at命令详解
  19. SpringBoot整合Jbpm4(一)
  20. 1美元从零开始训练Bert,手把手教你优雅地薅谷歌云TPU羊毛

热门文章

  1. JSON在android中应用
  2. Ffmpeg快速应用开发
  3. Revit二次开发The symbol is not active
  4. Kafka系列之-Kafka监控工具KafkaOffsetMonitor配置及使用
  5. dubbo 配置及分析
  6. 面向对象之: 类空间问题及类之间的关系
  7. C#解析JSON数据
  8. BZOJ.4727.[POI2017]Turysta(哈密顿路径/回路 竞赛图)
  9. 控制台异常:Could not connection
  10. ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var mysql 启动不了(转载)...