惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google DeepMind News
Google DeepMind News
Stack Overflow Blog
Stack Overflow Blog
Hugging Face - Blog
Hugging Face - Blog
博客园_首页
T
The Blog of Author Tim Ferriss
博客园 - 叶小钗
N
Netflix TechBlog - Medium
腾讯CDC
C
Check Point Blog
P
Proofpoint News Feed
Engineering at Meta
Engineering at Meta
GbyAI
GbyAI
S
SegmentFault 最新的问题
F
Fortinet All Blogs
美团技术团队
U
Unit 42
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - 司徒正美
F
Full Disclosure
Recorded Future
Recorded Future
D
DataBreaches.Net
博客园 - 【当耐特】
Martin Fowler
Martin Fowler
J
Java Code Geeks
I
InfoQ
Y
Y Combinator Blog
A
About on SuperTechFans
AI
AI
爱范儿
爱范儿
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Forbes - Security
Forbes - Security
W
WeLiveSecurity
M
MIT News - Artificial intelligence
雷峰网
雷峰网
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Simon Willison's Weblog
Simon Willison's Weblog
Schneier on Security
Schneier on Security
The GitHub Blog
The GitHub Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
aimingoo的专栏
aimingoo的专栏
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
G
GRAHAM CLULEY
Know Your Adversary
Know Your Adversary
Latest news
Latest news
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
D
Docker
Recent Commits to openclaw:main
Recent Commits to openclaw:main
量子位
V2EX - 技术
V2EX - 技术
Project Zero
Project Zero

博客园 - 萧佰刚

深圳市鑫侑触控技术有限公司 电容式触摸屏|电容式触摸屏厂|手机触摸屏厂|偏光片贴合 Qt Creator 常用快捷键 结构体指针的指针使用(转) System V共享内存资料 "互斥锁用于上锁,条件变量则用于等待" Linux下UDP编程 Linux Socket编程学习 linux管道学习资料 linux进程间通信——消息队列 C实现单链表(转) c语言 位操作 C语言枚举类型使用简介 指向结构体指针的例子 字符数组 字符指针 sizeof strlen 的区别 Linux进程间共享临界区“信号量”编程 Linux下Socket编程 Linux下常用函数- 信号处理函数(转) linux信号signal常用信号 Linux 守护进程的编程方法(转)
Mtk Ft6306 touch 驱动 .
萧佰刚 · 2013-10-24 · via 博客园 - 萧佰刚

1.1、    MTK Touch 驱动的组成
Mtk  Touch  driver 驱动包括:Mtk platform 虚拟平台设备驱动、Module touch IC 驱动、Input subsystem。
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 driver init\n");
            if(platform_driver_register(&tpd_driver)!=0) {
        TPD_DMESG("unable to register touch panel driver.\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,
    #ifndef CONFIG_HAS_EARLYSUSPEND
    .suspend    = NULL,
    .resume     = NULL,
    #endif
    .driver     = {
        .name = TPD_DEVICE,
    },
};

根据platform bus mathc的规则:driver_name 和device_name相同就会调用platform_drive 的probe函数。这里牵扯到Linux的设备模型知识,需要了解的人可以看下Linux platform bus。
#define TPD_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__);
      /* Select R-Touch */
     // if(g_tpd_drv == NULL||tpd_load_status == 0)
    if((tpd=(struct tpd_device*)kmalloc(sizeof(struct tpd_device), GFP_KERNEL))==NULL) return -ENOMEM;//分配一个Mtk tpd_device
    memset(tpd, 0, sizeof(struct tpd_device));

    /* allocate input 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;
    /* struct input_dev dev initialization and registration */
    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++)
    {
            /* add tpd driver into list */
        if(tpd_driver_list[i].tpd_device_name != NULL)//这里是在遍历mtk的tpd_driver_list里面的所有的驱动,判断名字是否为NULL,每一个module touch IC 驱动都会添加到这个静态数组里面
        {
            tpd_driver_list[i].tpd_local_init();
            //msleep(1);
            if(tpd_load_status ==1) {//这里我们会判断我们所遍历的每一个module IC 驱动的初始化函数。成功的话就会将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;
            }
        }    
  }
。。。。。。。。。。。。。。
。。。。。。。。。。。。。。
    #ifdef CONFIG_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;
    /* init R-Touch */
    #if 0
      if(touch_type == 0)
      {
          g_tpd_drv->tpd_local_init();
      }    
        #endif
    if(g_tpd_drv->tpd_have_button)
    {
        tpd_button_init();
    }

    return 0;
}

1.3、    Ft6306 module driver
Ft6306是敦泰的Touch IC ,这个里面,我们可以进行IC的上电、设置中断、Update FW等动作。
Ft6306中首先执行的代码是:
static int __init tpd_driver_init(void) {
     printk("MediaTek FT5206 touch panel driver init\n");
     i2c_register_board_info(0, &ft5206_i2c_tpd, 1);
         if(tpd_driver_add(&tpd_device_driver) < 0)
             TPD_DMESG("add FT5206 driver failed\n");
     return 0;
 }
module_init(tpd_driver_init);
tpd_driver_init函数会注册一个I2C Touch设备、调用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++)
    {
        /* add tpd driver into 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;
            #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
        }
    }
    
    return 0;
}
上面会将我们的每一个注册的Moudle IC touch驱动进行添加到 tpd_driver_list数组中。添加进去后,我们就会调用tpd_local_init函数进行touch IC 的初始化。

1.3.1、Module tpd_local_init函数
static int tpd_local_init(void)
 {
    int i;
 
  TPD_DMESG("Focaltech FT5206 I2C Touchscreen Driver (Built %s @ %s)\n", __DATE__, __TIME__);
 
 
   if(i2c_add_driver(&tpd_i2c_driver)!=0)
       {
          TPD_DMESG("unable to add i2c driver.\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等、Update FW、IC提供的控制 touch 的interface等。
tpd_probe函数定义如下:
static int __devinit tpd_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {    
    int retval = TPD_OK;
    char data;
    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 kernel thread: %d\n", retval);
    }