TP驱动——I2C驱动,细节分析——dts设备树

1.小序

TP驱动程序,是指带屏幕设备的触屏功能调用的驱动程序。TP外设与主板之间的关系如下框图:
TP外设框图
产品常用的屏幕单元为液晶显示屏幕,TP的触摸功能也是一同集成到一起的,通过控制芯片以及外围电路、i2c总线与主板进行通信。

TP驱动的功能逻辑:

  • 当有触点发生时,TP芯片向主板传递中断信号
  • 驱动在收到中断后,调用驱动的中断处理函数
  • 中断处理函数中,唤醒触点处理线程
  • 处理线程通过 i2c 读取TP-IC内寄存器里的数据并处理

2.module_init之后的流程

在这里插入图片描述
此处在添加TP-I2C驱动,通过driver来匹配device中的 compatible 来识别dts 设备树中的节点。
我们通过一段地址跟踪来看TP-I2C driver的添加过程。
在这里插入图片描述
通过 i2c_add_driver() 函数调用到 i2c 驱动中 i2c_register_driver() ,使用的是TP外设中定义的tpd_i2c_driver->driver,在添加 i2c 驱动过程中match对应的device

static struct i2c_driver tpd_i2c_driver = {
	.driver = {
 		.name = "gt9xx",
#ifdef CONFIG_OF
        .of_match_table = of_match_ptr(gt9xx_dt_match),
#endif
     },
	.probe = tpd_i2c_probe,
    .remove = tpd_i2c_remove,
    .detect = tpd_i2c_detect,
    .id_table = tpd_i2c_id,
    .address_list = (const unsigned short *) forces,
};

tpd_i2c_driver->driver中的 “.of_match_table = of_match_ptr(gt9xx_dt_match), ” 这一行根据驱动中的定义

static const struct of_device_id gt9xx_dt_match[] = { {.compatible = “mediatek,goodix_touch”}, {},};

对应dts中i2c节点内子节点的 compatiable 信息。

3 获取对应pin信息

devm_pinctrl_get() 是Linux内获取对应节点内pin信息的函数,通过打印日志可以看到,在添加外设的 i2c_driver 时,触发此函数获取dits中的pin信息。调用函数如日志中一般,详细过程可跟Linux源码分析,此处详细说一下与dts有关的设置。
首先看一下dts中的内容,以下是 第一种情况 \color{#FF3030}{第一种情况} 第一种情况

&i2c0 {
    status = "okay";
    goodix_touch@5d {
        pinctrl-names = "default", "sleep";
	    pinctrl-0 = <&i2c0_pins>;
	    pinctrl-1 = <&i2c0_pins_sleep>;
        compatible = "mediatek,goodix_touch";
        reg = <0x5d>;
        status = "okay" ;
        interrupt-parent = <&pio>;
        interrupts = <0 IRQ_TYPE_EDGE_FALLING 0 0>;
        int-gpio = <&pio 0 0>;
        rst-gpio = <&pio 174 0>;
    };
};

这些pin信息
pinctrl-names = “default”, “sleep”;
pinctrl-0 = <&i2c0_pins>;
pinctrl-1 = <&i2c0_pins_sleep>;
是定义在对应外设TP节点内部,因此在外设添加 i2c_driver 时,匹配到对应 device 后,打印出 dev_name 信息为 0-005d。
内核的 i2c 驱动加载时,i2c0总线打印的dev_name 则为11007000@i2c0

以下是 第二种情况 \color{#FF3030}{第二种情况} 第二种情况

&i2c0 {
    pinctrl-names = "default", "sleep";
    pinctrl-0 = <&i2c0_pins>;
    pinctrl-1 = <&i2c0_pins_sleep>;
    status = "okay";
    goodix_touch@5d {
        compatible = "mediatek,goodix_touch";
        reg = <0x5d>;
        status = "okay" ;
        interrupt-parent = <&pio>;
        interrupts = <0 IRQ_TYPE_EDGE_FALLING 0 0>;
        int-gpio = <&pio 0 0>;
        rst-gpio = <&pio 174 0>;
    };
};

pinctrl-names = “default”, “sleep”;
pinctrl-0 = <&i2c0_pins>;
pinctrl-1 = <&i2c0_pins_sleep>;
这些pin信息的定义是在 i2c0节点下的,因此在 i2c 驱动加载时,匹配i2c的compatible信息获取此处的pinctrl信息。打印的log如下
在这里插入图片描述
1、是i2c驱动的入口处;
2、是i2c驱动的driver地址,对照6处,i2c-0和i2c-1是先后加载到内核中的,他们在dts中有一样的compatible;
3、依次匹配的device节点,dev_name是设备树节点的name;
4、把dts中,i2c0节点下的 pinctrl 信息绑定到此处,此处可以用作对i2c0总线的操作;如果某外设要自身操作,参考上面第一种情况。
5、由于绑定的是总线driver,直接调用drv->probe。如果是外设添加driver,则首先调用总线probe,再调用drv->probe。

3.1 小注

Q:通过dts添加的pinctrl信息,将i2c的SDA和SCL两根线上下电
A:在dts中添加pinctrl信息后,如果采用第二种情况,对i2c总线整体操作,效果不生效,可能是probe中没有将pinctrl信息获取。是否欠缺此处代码。
在这里插入图片描述

  • 0
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在Linux中,可以通过编写TP驱动程序来进行I2C设备的读写操作。下面是一个简单的示例代码,演示了如何在TP驱动中读写I2C设备: ```c #include <linux/i2c.h> #include <linux/i2c-dev.h> #include <linux/module.h> static struct i2c_client *tp_client; static int tp_read_reg(struct i2c_client *client, u8 reg, u8 *value) { struct i2c_msg msgs[2]; u8 buf[2]; int ret; buf[0] = reg; msgs[0].addr = client->addr; msgs[0].flags = 0; msgs[0].buf = buf; msgs[0].len = 1; msgs[1].addr = client->addr; msgs[1].flags = I2C_M_RD; msgs[1].buf = value; msgs[1].len = 1; ret = i2c_transfer(client->adapter, msgs, 2); if (ret != 2) { pr_err("Failed to read register 0x%02x\n", reg); return ret < 0 ? ret : -EIO; } return 0; } static int tp_write_reg(struct i2c_client *client, u8 reg, u8 value) { struct i2c_msg msg; u8 buf[2]; int ret; buf[0] = reg; buf[1] = value; msg.addr = client->addr; msg.flags = 0; msg.buf = buf; msg.len = 2; ret = i2c_transfer(client->adapter, &msg, 1); if (ret != 1) { pr_err("Failed to write register 0x%02x\n", reg); return ret < 0 ? ret : -EIO; } return 0; } static int __init tp_driver_init(void) { struct i2c_adapter *adapter; struct i2c_board_info board_info; struct i2c_client *client; int ret; // 获取I2C适配器 adapter = i2c_get_adapter(0); if (!adapter) { pr_err("Failed to get I2C adapter\n"); return -ENODEV; } // 填充设备信息 memset(&board_info, 0, sizeof(struct i2c_board_info)); strlcpy(board_info.type, "my_i2c_device", I2C_NAME_SIZE); // 注册I2C设备 client = i2c_new_device(adapter, &board_info); if (!client) { pr_err("Failed to register I2C device\n"); i2c_put_adapter(adapter); return -ENODEV; } // 保存设备指针 tp_client = client; // 读取寄存器示例 u8 reg_value; ret = tp_read_reg(tp_client, 0x00, &reg_value); if (ret) { pr_err("Failed to read register\n"); i2c_unregister_device(tp_client); i2c_put_adapter(adapter); return ret; } // 写入寄存器示例 ret = tp_write_reg(tp_client, 0x01, 0xFF); if (ret) { pr_err("Failed to write register\n"); i2c_unregister_device(tp_client); i2c_put_adapter(adapter); return ret; } return 0; } static void __exit tp_driver_exit(void) { if (tp_client) { i2c_unregister_device(tp_client); i2c_put_adapter(tp_client->adapter); } } module_init(tp_driver_init); module_exit(tp_driver_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("TP Driver"); ``` 在上述示例代码中,我们首先通过`i2c_get_adapter()`函数获取I2C适配器,然后填充设备信息并注册I2C设备。接着,我们可以使用`tp_read_reg()`函数和`tp_write_reg()`函数来读取和写入I2C设备的寄存器。最后,在驱动程序的初始化函数中,我们进行了读取和写入寄存器的示例操作。 需要注意的是,上述代码仅为示例,实际应用中需要根据具体的硬件和需求进行修改和适配。同时,还需要确保相关的I2C驱动程序已经加载并正确配置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝冰露

感谢老板打赏~~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值