2. Linux I2C 子系统架构:分层设计与数据流

Linux I2C 子系统采用经典的三层软件架构,将硬件适配器控制、核心协议管理与具体从设备驱动解耦。这种分层设计使得适配器驱动与从设备驱动可以独立开发,并通过 I2C 核心层提供的统一接口完成通信。理解每一层的职责与数据流是进行 I2C 驱动开发与调优的基础。

2.1 三层架构总览

I2C 子系统从上到下依次为:I2C 从设备驱动层、I2C 核心层、I2C 适配器驱动层。核心层作为中间枢纽,向上提供设备驱动注册与消息收发 API,向下定义适配器驱动的操作接口。

架构核心原则:从设备驱动不直接操作硬件寄存器,而是通过核心层调用适配器驱动的算法(algorithm)完成总线时序。适配器驱动不关心挂载在总线上的具体设备类型,只负责将核心层下发的消息转换为 I2C 总线上的 SCL/SDA 信号。
Linux I2C 子系统三层架构 I2C 从设备驱动层 i2c_driver / i2c_client 实现 probe()、remove()、id_table,调用 i2c_transfer() / i2c_smbus_*() I2C 核心层 i2c-core.c / i2c-dev.c 管理适配器与设备注册/注销、消息路由、SMBus 协议封装、sysfs 接口 I2C 适配器驱动层 i2c_adapter / i2c_algorithm 实现 master_xfer()、smbus_xfer(),操作硬件寄存器产生 SCL/SDA 时序

2.2 各层职责详解

2.2.1 I2C 核心层(I2C Core)

核心层是 I2C 子系统的中枢,由 drivers/i2c/i2c-core.c 及其辅助文件实现。它不直接操作硬件,而是提供框架与基础设施。

  • 适配器管理:提供 i2c_add_adapter() / i2c_del_adapter() 接口,管理适配器在系统中的注册与注销。
  • 设备管理:提供 i2c_new_device() / i2c_unregister_device(),将从设备(i2c_client)绑定到特定适配器。
  • 驱动管理:维护 i2c_driver 的注册与匹配,当 i2c_client 与 i2c_driver 的 id_table 匹配时,调用 probe()。
  • 消息传输:提供 i2c_transfer() 和 i2c_smbus_xfer() 封装,将消息路由到对应适配器的 algorithm。
  • sysfs 与用户态接口:通过 i2c-dev.c 提供 /dev/i2c-N 字符设备,允许用户态直接访问 I2C 总线。

2.2.2 I2C 适配器驱动层(I2C Adapter Driver)

适配器驱动负责与具体的 I2C 控制器硬件交互。每个 I2C 总线控制器对应一个 i2c_adapter 实例,其核心是 i2c_algorithm 结构体。

组件 数据结构 / 函数 职责说明
适配器实例 struct i2c_adapter 包含适配器编号、算法指针、锁、超时参数、DMA 设置等
算法接口 struct i2c_algorithm 定义 master_xfer() 和 smbus_xfer() 回调,实现总线时序
硬件操作 寄存器读写 配置控制器时钟、产生 START/STOP/ACK 信号、收发字节
平台绑定 platform_driver / of_match_table 通过设备树或 ACPI 匹配硬件,在 probe() 中初始化适配器
适配器驱动开发要点:实现 master_xfer() 时,需要正确处理消息数组(msg[])中的多条消息,支持复合事务(combined transaction)。对于不支持 SMBus 的硬件,核心层会自动将 SMBus 请求拆解为标准 I2C 消息。

2.2.3 I2C 从设备驱动层(I2C Client Driver)

从设备驱动面向具体的 I2C 外设芯片(如传感器、EEPROM、ADC 等),通过核心层提供的 API 与硬件通信。

  • 驱动结构:使用 struct i2c_driver 注册,包含 probe()、remove()、id_table 等成员。
  • 设备标识:通过 i2c_device_id 或设备树 compatible 字符串匹配硬件。
  • 通信方式:
    • i2c_transfer():发送/接收 struct i2c_msg 数组,支持多消息组合。
    • i2c_smbus_read_byte_data() / i2c_smbus_write_word_data() 等:SMBus 封装函数,简化单寄存器读写。
  • 生命周期:probe() 中完成设备初始化、注册输入设备或 hwmon 等子系统;remove() 中释放资源。

2.3 数据流与消息传递路径

当从设备驱动发起一次 I2C 读写操作时,数据流经过三个层次,形成完整的调用链。以下以 i2c_smbus_read_byte_data() 为例说明典型路径。

  1. 从设备驱动调用:i2c_smbus_read_byte_data(client, reg_addr)
  2. 核心层封装:i2c-core-smbus.c 将 SMBus 协议封装为 struct i2c_msg 数组(写寄存器地址 + 读数据)。
  3. 核心层路由:调用 i2c_transfer(),通过 adapter 的 algorithm 指针找到 master_xfer()。
  4. 适配器驱动执行:master_xfer() 操作硬件寄存器,在 I2C 总线上产生 START、发送设备地址+写位、发送寄存器地址、重复 START、发送设备地址+读位、读取数据、STOP。
  5. 数据返回:读取的数据通过 msg->buf 返回,逐层传回从设备驱动。
I2C 数据流调用链(以 SMBus 读为例) ① 从设备驱动 i2c_smbus_read_byte_data(client, 0x1A) ② I2C 核心层 封装为 i2c_msg[2]:写(0x1A) + 读(1 byte) ③ I2C 核心层(路由) i2c_transfer() → adapter->algo->master_xfer() ④ 适配器驱动 操作硬件寄存器 → SCL/SDA 总线时序 → 返回数据

2.4 关键数据结构关系

理解以下四个核心数据结构之间的关系,是掌握 I2C 子系统的关键。

数据结构 所属层 关键成员 作用
struct i2c_adapter 适配器层 nr, algo, lock, timeout, dev 代表一个 I2C 总线控制器
struct i2c_algorithm 适配器层 master_xfer, smbus_xfer 定义硬件操作回调
struct i2c_client 核心层/设备层 addr, adapter, driver, name 代表一个挂载在总线上的从设备
struct i2c_driver 从设备驱动层 probe, remove, id_table, driver 从设备驱动的注册结构
struct i2c_msg 核心层 addr, flags, len, buf 描述一次数据传输的报文
常见误区:初学者容易混淆 i2c_client 与 i2c_driver 的关系。一个 i2c_client 对应一个物理设备实例,由核心层在设备发现时创建;一个 i2c_driver 对应一种设备驱动,可以绑定多个同类型 i2c_client。驱动开发者的主要工作是填充 i2c_driver,而不是直接创建 i2c_client。

2.5 分层设计的优势

  • 可移植性:从设备驱动无需修改即可运行在不同 I2C 控制器上,适配器驱动更换不影响上层。
  • 模块化:适配器驱动与从设备驱动可以分别编译为内核模块,动态加载/卸载。
  • 复用性:核心层提供的 SMBus 封装、sysfs 接口、用户态访问等基础设施,所有驱动均可直接使用。
  • 调试便利:可以在核心层插入跟踪点(tracepoint)或使用 i2c-tools 工具,独立验证每一层的功能。