3. Linux 内核 I2C 子系统:I2C 核心层、总线驱动、设备驱动模型、设备树绑定
在嵌入式 Linux 系统中,FT5x06 与 GT911 等触控芯片均通过 I2C 总线与主控通信。理解 Linux I2C 子系统的分层架构,是驱动开发和性能调优的基础。本章将深入剖析 I2C 核心层、总线驱动、设备驱动模型以及设备树绑定的工作机制。
3.1 I2C 子系统整体架构
Linux I2C 子系统采用标准的分层设计,从上到下依次为:设备驱动层、核心层、总线驱动层。这种分层使得触控驱动开发者只需关注设备驱动层,而无需关心底层硬件差异。
关键概念: I2C 核心层是连接设备驱动与总线驱动的桥梁,提供统一的 API 接口、设备注册/注销机制以及总线访问方法。
3.2 I2C 核心层 (I2C Core)
I2C 核心层是子系统的中枢,主要职责包括:
- 设备与驱动管理: 维护 i2c_client 和 i2c_driver 的注册、匹配、移除生命周期。
- 总线访问抽象: 提供
i2c_transfer()、i2c_smbus_read_byte_data()等统一 API。 - 设备模型集成: 将 I2C 设备挂载到 Linux 设备模型 (device/driver/bus) 中。
- 用户态接口: 通过
/dev/i2c-N字符设备提供用户空间访问能力。
调优提示: 在触控驱动中,高频使用
i2c_transfer() 时,建议使用 struct i2c_msg 消息数组实现批量读写,减少总线锁定开销。
3.2.1 核心数据结构
| 数据结构 | 作用 | 触控驱动中的典型用法 |
|---|---|---|
struct i2c_client |
描述一个 I2C 从设备(如触控芯片) | 在 probe() 中通过 dev_get_drvdata() 获取 |
struct i2c_driver |
描述 I2C 设备驱动 | 定义 probe/remove/id_table 回调 |
struct i2c_adapter |
描述 I2C 总线控制器 | 通过 client->adapter 访问 |
struct i2c_msg |
描述一次 I2C 传输事务 | 构造读/写消息数组,调用 i2c_transfer() |
3.3 I2C 总线驱动 (Bus Adapter Driver)
总线驱动层直接操作硬件寄存器,实现 I2C 总线的时序控制。不同 SoC 平台需要不同的总线驱动,例如:
- i2c-imx.c: NXP i.MX 系列
- i2c-s3c2410.c: Samsung S3C/S5P 系列
- i2c-omap.c: TI OMAP 系列
- i2c-designware.c: Synopsys DesignWare I2C 控制器
总线驱动需要实现 struct i2c_algorithm 中的 master_xfer() 函数,该函数最终被核心层的 i2c_transfer() 调用。
/* i2c_algorithm 结构体核心成员 */
struct i2c_algorithm {
int (*master_xfer)(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num);
int (*smbus_xfer)(struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data *data);
u32 (*functionality)(struct i2c_adapter *adap);
};
性能瓶颈: 总线驱动的
master_xfer() 实现质量直接影响触控报点率。低效的实现可能引入额外延迟,导致触摸响应滞后。调优时需关注总线时钟频率 (如 400kHz) 和传输合并策略。
3.4 I2C 设备驱动模型
Linux 设备驱动模型为 I2C 子系统提供了统一的设备-驱动匹配框架。触控驱动作为 I2C 设备驱动,遵循标准的 probe/remove 生命周期。
3.4.1 驱动注册示例
/* FT5x06 I2C 驱动结构体定义 */
static const struct i2c_device_id ft5x06_id[] = {
{ "ft5x06", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ft5x06_id);
static const struct of_device_id ft5x06_of_match[] = {
{ .compatible = "focaltech,ft5x06" },
{ }
};
MODULE_DEVICE_TABLE(of, ft5x06_of_match);
static struct i2c_driver ft5x06_driver = {
.driver = {
.name = "ft5x06",
.of_match_table = ft5x06_of_match,
},
.probe = ft5x06_probe,
.remove = ft5x06_remove,
.id_table = ft5x06_id,
};
module_i2c_driver(ft5x06_driver);
3.5 设备树绑定 (Device Tree Binding)
设备树 (Device Tree) 是描述硬件拓扑的扁平数据结构,用于在系统启动时向内核传递硬件配置信息。对于 I2C 触控设备,设备树节点需要描述:
- compatible: 与驱动匹配的字符串
- reg: I2C 从设备地址 (7位或10位)
- interrupts: 触控中断引脚配置
- reset-gpios / irq-gpios: 复位和中断 GPIO (可选)
3.5.1 FT5x06 设备树节点示例
&i2c1 {
status = "okay";
clock-frequency = <400000>; /* 400kHz 高速模式 */
ft5x06: touchscreen@38 {
compatible = "focaltech,ft5x06";
reg = <0x38>;
interrupt-parent = <&gpio1>;
interrupts = <13 IRQ_TYPE_EDGE_FALLING>;
reset-gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;
touchscreen-size-x = <800>;
touchscreen-size-y = <480>;
};
};
3.5.2 GT911 设备树节点示例
&i2c2 {
status = "okay";
clock-frequency = <400000>;
gt911: touchscreen@5d {
compatible = "goodix,gt911";
reg = <0x5d>;
interrupt-parent = <&gpio3>;
interrupts = <7 IRQ_TYPE_EDGE_RISING>;
irq-gpios = <&gpio3 7 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio3 6 GPIO_ACTIVE_LOW>;
touchscreen-size-x = <1024>;
touchscreen-size-y = <600>;
};
};
调优要点: 设备树中的
clock-frequency 直接影响触控数据读取速度。FT5x06 和 GT911 均支持 400kHz 快速模式,部分芯片可尝试 1MHz 高速模式,但需验证总线信号完整性。
3.6 本章小结
| 层级 | 核心文件/结构 | 触控调优关注点 |
|---|---|---|
| I2C 核心层 | i2c-core.c, struct i2c_msg | 批量传输减少总线锁定 |
| 总线驱动层 | master_xfer() 实现 | 时钟频率、传输合并策略 |
| 设备驱动模型 | probe/remove 回调 | 中断注册时机、资源分配 |
| 设备树绑定 | compatible, reg, interrupts | 地址冲突、中断类型、GPIO 配置 |