读一款TP驱动

最近工作中遇到的,这里只做技术分析,不分享相关代码了。

触摸屏原理其实是这样的,有两组控制端口,一组是I2C,一组是一个GPIO做中断。当中断触发时,系统会通过I2C去读取触屏的触摸事件。

控制的关键内容如下:

I2C 通信:在中断处理程序中,使用 i2c_master_recv 函数从触摸屏读取数据。数据的格式由具体的触摸屏硬件决定。
中断处理:当触摸屏检测到触摸事件时,它会触发一个 GPIO 中断,驱动程序的中断处理程序 ts_irq_handler 负责读取数据并向上层报告触摸事件。
输入子系统集成:驱动程序通过 Linux 输入子系统(input_dev)报告触摸事件,最终可以在用户空间接收到这些事件。

这次看到的代码大概是这样的:

Core.c

----lib

----chips

代码大概是三个部分。

先看看Core吧

还是标准的内核module流程。

late_initcall(xxx_ts_init);
// module_init(xxx_ts_init);
module_exit(xxx_ts_exit);

MODULE_AUTHOR("XXX Driver Team");
MODULE_DESCRIPTION("XXX Touchscreen Driver");
MODULE_LICENSE("GPL v2");

这个TP是根据I2C来进行处理的。

#ifdef I2C_PORT

static const struct i2c_device_id hyn_id_table[] = {

    {.name = HYN_DRIVER_NAME, .driver_data = 0,},

    {},

};



static struct i2c_driver xxx_ts_driver = {

    .probe = xxx_ts_probe,

    .remove = xxx_ts_remove,

    .driver = {

        .name = xxx_DRIVER_NAME,

        .owner = THIS_MODULE,

        .of_match_table = xxx_of_match_table,

    },

    .id_table = xxx_id_table,

};

match是用来匹配设备树的,这里很重要的就是probe和remove两个函数。虽然现在有init和exit两个函数,但是明显大部分内容都是在probe和remove里面做的。

probe比较复杂。

里面就是调用linux内核的I2C函数,比如i2c_check_functionality,然后开始poweron,这里主要是用pinctrl设置端口,然后regulator_set_voltage设置端口电压。

之后是根据设备树判断设备是否加载,之后开始处理中断。创建中断线程。创建驱动节点。

 标准中断流程:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/irq.h>

// 定义中断号 (通常需要从设备树或硬件文档中获取)
#define MY_IRQ_LINE 17

// 中断处理函数
static irqreturn_t my_irq_handler(int irq, void *dev_id)
{
    printk(KERN_INFO "Interrupt occurred! IRQ: %d\n", irq);
    // 处理中断的逻辑
    return IRQ_HANDLED; // 表示中断已经被处理
}

// 初始化模块
static int __init my_driver_init(void)
{
    int ret;

    printk(KERN_INFO "Initializing interrupt driver...\n");

    // 申请中断
    ret = request_irq(MY_IRQ_LINE, my_irq_handler, IRQF_SHARED, "my_irq_handler", (void *)(my_irq_handler));
    if (ret) {
        printk(KERN_ERR "Failed to request IRQ: %d\n", MY_IRQ_LINE);
        return ret;
    }

    printk(KERN_INFO "Interrupt handler registered.\n");
    return 0;
}

// 卸载模块
static void __exit my_driver_exit(void)
{
    printk(KERN_INFO "Exiting interrupt driver...\n");

    // 释放中断
    free_irq(MY_IRQ_LINE, (void *)(my_irq_handler));

    printk(KERN_INFO "Interrupt handler unregistered.\n");
}

module_init(my_driver_init);
module_exit(my_driver_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple interrupt handler example");

但是这里用的是request_threaded_irq,看说明是新Linux内核可以更高效用多核的方法。

remove则相对比较简单。

待续。。。

当中断响应时,每次发送是一帧:

struct ts_frame{
    u8 rep_num;
    enum report_typ report_need;
    u8 key_id;
    u8 key_state;
    struct {
        u8 pos_id;
        u8 event;
        u16 pos_x;
        u16 pos_y;
        u16 pres_z;
    }pos_info[MAX_POINTS_REPORT];
};

Lib里面主要是一些辅助操作,大概如下:

1 创建驱动节点封装

2 I2C封装

3 手势功能封装

4 升级功能封装

5 其它一些辅助函数

Chips里面主要就是固件

然后有一个硬件操作的封装,这个不是TP本身的版本,而且高通芯片的版本。也就是说各个高通芯片注册,初始化,reset的方法都会不同。

struct hyn_ts_fuc{
    void (*tp_rest)(void);
    int (*tp_report)(void);
    int (*tp_supend)(void);
    int (*tp_resum)(void);
    int (*tp_chip_init)(struct hyn_ts_data *ts_data);
    int (*tp_updata_fw)(u8 *bin_addr, u16 len);
    int (*tp_set_workmode)(enum work_mode mode,u8 enable);
    u32 (*tp_check_esd)(void);
    int (*tp_prox_handle)(u8 cmd);
    int (*tp_get_dbg_data)(u8 *buf,u16 len);
    int (*tp_get_test_result)(u8 *buf,u16 len);
};

在上面的probe和remove中,会根据不同的芯片平台,选择不同的回调函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值