focaltech(敦泰)触摸屏驱动Ft5306.c学习记录

本文详细介绍了Focaltech FT5306触摸屏驱动的开发过程,包括驱动的注册与退出、I2C板级信息初始化、I2C客户端与驱动的匹配、中断下半部工作队列软件实现、通过I2C数据读取、Linux内核多点触控协议、触摸数据解析上报分析、DTS设备树等关键内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


最近正在做安卓系统的驱动开发工作,学习了focaltech(敦泰)触摸屏驱动Ft5306.c,简单总结如下(未完,待续)。因为刚接触驱动开发,许多知识没有彻底理解,如有错误请指正。

1 概述

   linux触摸屏驱动基于linux input 子系统,层次上位于input系统的第三层,主要是完成具体输入设备的驱动功能程序,Ft5306.c源文件位于kernel下drivers\input\touchscreen目录下,属于字符型驱动,ft5306使用的多点触控协议是A协议。

Ft5306驱动主要涉及的知识架构有:

linux驱动开始相关知识;

linux input 子系统机制;

linux I2C总线结构及I2C协议; 

中断下半部处理机制-工作队列;

linux内核多点触控协议;

触摸屏实现原理;

其他:如platform机制、dts设备结构树,安卓下的唤醒机制、virtualkeys触摸按键发送方法等;

2 具体分析

2.1 驱动的注册及退出:ft5306.c

         module_init(focaltech_ft5306_init);

         module_exit(focaltech_ft5306_exit);

         注意:驱动入口函数focaltech_ft5306_init有固定格式要求:函数入参必须为void,返回值类型必须为int。

2.2 I2C板级信息初始化

: 注意:0x70 >> 1为I2C通信中的从地址,通常从芯片手册中获取的地址需要右移1位;ps:board-granet.c(不同平台源文件可能不同)

         staticstruct i2c_board_info __initdata ft5306_info[] = {

         {                           /* New touch screeni2c slave address. */

          I2C_BOARD_INFO("FocalTech-Ft5306",(0x70 >> 1)),

          .platform_data= &ft5306_plat_data,

          .irq= gpio_to_irq(TSC_GPIO_IRQ_PIN),

          },};

       i2c_board_info结构体用来保存I2C设备的相关信息,Linux根据这些信息创建I2C设备相关的设备模型树。对于mainboards,通过调  用i2c_register_board_info()静态完成。对于add-on boards,通过调用i2c_new_device()动态完成。i2c_board_info结构体有两个成员必须初始化,一个是type,用来初始化i2c_client.name;另一个是addr,用来初始化i2c_client.addr。其它i2c_board_info结构体成员根据需要赋值或保持为空。

2.3 I2c_client (I2C 适配器)注册(并没有创建)

:使用i2c_register_board_info(3, ft5306_info,ARRAY_SIZE(ft5306_info));board-granet.c

2.4 I2Cdriver的注册:ft5306.c

       首先定义结构体:i2c_driver focaltech_ft5306_driver,注意.name 成员必须与ft5306_info中I2C_BOARD_INFO第一个参数相同,否则I2c_client 与I2C driver不会匹配成功

       staticstruct i2c_driver focaltech_ft5306_driver = {

         .probe                = focaltech_ft5306_probe,

         .remove            = focaltech_ft5306_remove,

           #ifndef CONFIG_HAS_EARLYSUSPEND

         .suspend  = focaltech_ft5306_suspend,

         .resume            = focaltech_ft5306_resume,

           #endif

         .id_table  = focaltech_ft5306_id,

         .driver= {

                   .name       = "FocalTech-Ft5306",

         },               }   ;

      其次注册:在focaltech_ft5306_init   调用i2c_add_driver(&focaltech_ft5306_driver); 

      最后注销:i2c_driver注销 是在驱动文件中exit函数,例如 focaltech_ft5306_exit 调用i2c_del_driver;

2.5 I2Cclient 与driver的匹配:ft5306.c

foc   focaltech_ft5306_init -> i2c_add_driver-> i2c_register_driver-driver_register->调用i2c_for_each_dev遍历所有已存在的i2c_adapter->…-> i2c_do_add_adapter(该函数主要完成i2c_driver与i2c_adapter上的i2c设备的匹配工作,根据i2c_client.name与 driver.name 是否相同来匹配。如果匹配成功,初始化并创建对应的i2c_client。)                        在driver_register执行过程中,如果I2C总线上找到了与该驱动匹配的I2C设备,则i2c_driver.probe函数会被调用执行。

 

当进入i2c_driver.probe后,依次执行:

2.6 初始化input_dev 结构体

2.7.设置设备支持的事件类型

input_set_abs_params(ts->input_dev,ABS_MT_POSITION_X, 0, ts_x_max_value, 0, 0);

         input_set_abs_params(ts->input_dev,ABS_MT_POSITION_Y, 0, ts_y_max_value, 0, 0);

         input_set_abs_params(ts->input_dev,ABS_MT_TOUCH_MAJOR, 0, 8, 0, 0);

ABS_MT_POSITION_X等中表示多点触控协议的事件类型

2.8 注册input系统

在 Probe方式下(input系统外添加字符驱动的位置在probe使用input_register_device函数中,注销字符驱动的位置的remove中).   Linux input 字符设备的注册是在evdev_connect 函数中实现的,使用的是cdev_add 函数,字符设备的删除是在evdev_cleanup函数中实现的。xxx_fops在cdev_init(&xxx_dev.cdev, &xxx_fops)的语句中被建立与cdev的连接。

2.9 申请中断request_irq

                   if(request_irq(GPIO_TO_IRQ(ts_gpio_irq_pin), focaltech_ft5306_irq_handler,

                                     IRQF_TRIGGER_FALLING,client->name, ts) >= 0) {

                            printk("RequestedIRQ\n");

                            ts->use_irq= 1;

                            printk(KERN_INFO"GPIO_%d INT: %d", ts_gpio_irq_pin,

                                                        GPIO_TO_IRQ(ts_gpio_irq_pin));

                            /*if((ret = set_irq_wake(client->irq, 1)) < 0) {

                                     printk(KERN_ERR"failed to set IRQ wake: %d\n", ret);

                            }*/

                   }

2.10 实现睡眠唤醒机制

         #ifdefCONFIG_HAS_EARLYSUSPEND

         ts->early_suspend.level= EARLY_SUSPEND_LEVEL_BLANK_SCREEN;

         ts->early_suspend.suspend= focaltech_ft5306_early_suspend;

         ts->early_suspend.resume= focaltech_ft5306_late_resume;

         register_early_suspend(&ts->early_suspend);

3 重点分析

3.1中断下半部工作队列软件实现:

focaltech_ft5306_irq_handler中断处理函数

focaltech_ft5306_work_func  中断处理后半部函数

l 声明工作队列结构体:static struct workqueue_struct *synaptics_wq;

l 初始化创建工作队列:        

synaptics_wq =create_singlethread_workqueue("synaptics_wq");

if (!synaptics_wq) {

printk(KERN_ERR"Could not create work queue synaptics_wq: no memory");

return -ENOMEM;

l 在工作队列中添加一个工作:

INIT_WORK(&ts->work, focaltech_ft5306_work_func);

// focaltech_ft5306_work_func为处理函数,ts->work(ts为触摸屏结构体synaptics_rmi4)

focaltech_ft5306_work_func为使用container_of实现data指针的传递。

l probe函数中使用request_irq申请中断,绑定中断处理函数focaltech_ft5306_irq_handler

l 安排任务进工作队列:中断处理函数focaltech_ft5306_irq_handler中,queue_work(synaptics_wq,&ts->work);

l focaltech_ft5306_work_func函数中实现数据的上报等

l 工作队列的销毁focaltech_ft5306_exit中,

if (synaptics_wq)

                   destroy_workqueue(synaptics_wq);

 

3.2通过I2C数据读取

协议要求

l 从I2C从设备读取数据时,应先调用i2c_master_recv()发送I2C从设备的寄存器地址(I2C从设备的寄存器地址独立于 CPU 内存地址空间,因此不需要做 ioremap()映射),再调用i2c_master_send()读取数据。

l I2C 总线控制器从 I2C 从设备读取数据,只需要调用i2c_master_send(),buf[0]是 I2C 从设备的寄存器地址。

Ft306I2C接口使用:ft520x_i2c_rxdataft520x_i2c_txdata

调用关系:focaltech_ft5306_work_func->fts_ctpm_get_touch_info –>ft520x_i2c_rxdata-> i2c_transfer (相当于调用i2c_master_send,因为ft520x_i2c_rxdata做了部分初始化)

数据封装:

i2c发送或者接收一次数据都以数据包 structi2c_msg封装
struct i2c_msg { 
    __u16 addr;     // 从机地址 
    __u16 flags;    // 标志 
#define I2C_M_TEN   0x0010  // 十位地址标志 
#define I2C_M_RD    0x0001  // 接收数据标志 
    __u16 len;      // 数据长度 
    __u8 *buf;      // 数据指针 
}; 
其中addr为从机地址;flags则是这次通信的标志,发送数据为0,接收数据则为 I2C_M_RD;len为此次通信的数据字节数;buf 为发送或接收数据的指针。在设备驱动中我们通常调用 i2c-core 定义的接口 i2c_master_send 和 i2c_master_recv 来发送或接收一次数据。

i2c_transfer(client->adapter,msgs, 2);  // 这里 num = 2,通信成功 ret = 2 

使用i2c_transfer接口读取数据时,返回的data中,data[0]为寄存器的地址,data[1]以后才是读取的有效数据。

3.3 linux内核多点触控协议

3.4 触摸数据解析上报分析

3.5 dts设备树



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值