Linux I2C 子系统设计得非常灵活,层次分明,旨在支持各种硬件平台和外设。理解其整体架构有助于我们快速定位问题和编写驱动。
1. 架构概览
I2C 子系统主要分为三层:
- I2C Core (核心层)
- I2C Bus Driver (总线驱动/适配器驱动)
- I2C Device Driver (设备驱动/客户驱动)
plaintext
+-------------------------------------------------+
| User Space Applications |
| (Sysfs, /dev/i2c-x, ioctl, read/write) |
+-------------------------------------------------+
^
|
+------------------------+------------------------+
| I2C Subsystem |
| |
| +-------------------------------------------+ |
| | I2C Device Driver | |
| | (EEPROM, Sensor, Touch, PMIC, Input...) | |
| +-------------------------------------------+ |
| ^ |
| | i2c_transfer |
| +-------------------------------------------+ |
| | I2C Core | |
| | (i2c-core.c, algorithm, bus) | |
| +-------------------------------------------+ |
| ^ |
| | master_xfer |
| +-------------------------------------------+ |
| | I2C Bus Driver | |
| | (Rockchip I2C, GPIO Bitbanging...) | |
| +-------------------------------------------+ |
| |
+------------------------+------------------------+
^
|
+------------------------+------------------------+
| Hardware |
| (SoC I2C Controller <-> Slaves) |
+-------------------------------------------------+1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2. 各层职责
2.1 I2C Core (drivers/i2c/i2c-core-base.c)
- 维护总线: 管理
i2c_bus_type,处理设备和驱动的注册、注销、匹配。 - 提供接口: 向下提供注册 Adapter 的接口,向上提供数据传输的统一接口 (
i2c_transfer,i2c_smbus_...)。 - 抽象算法: 定义了
i2c_algorithm结构,允许不同的适配器实现相同的通信协议。
2.2 I2C Bus Driver (drivers/i2c/busses/)
- 硬件操作: 直接操作 SoC 的 I2C 控制器寄存器。
- 实现算法: 实现
i2c_algorithm中的master_xfer函数,完成实际的比特流传输。 - 注册适配器: 将
struct i2c_adapter注册到 Core 层。
2.3 I2C Device Driver (drivers/i2c/, drivers/input/, drivers/iio/ ...)
- 设备逻辑: 了解具体外设的寄存器含义(如:向 0x00 寄存器写 1 启动测量)。
- 暴露接口: 向用户空间或其他内核子系统暴露功能(如:生成 input event,读取温度值)。
- 调用 Core: 使用
i2c_transfer等函数与硬件交互,不关心底层是通过硬件控制器还是 GPIO 模拟实现的。
3. 关键文件
include/linux/i2c.h: 定义了所有的核心结构体 (i2c_client,i2c_driver,i2c_adapter,i2c_msg)。drivers/i2c/i2c-core-base.c: 核心功能的实现。drivers/i2c/i2c-dev.c: 实现了/dev/i2c-x字符设备接口,允许用户空间直接访问 I2C。drivers/i2c/busses/i2c-rk3x.c: Rockchip 平台的 I2C 控制器驱动。
4. 设备与驱动的匹配
在嵌入式 Linux (ARM) 中,主要依赖 Device Tree (设备树) 进行匹配。
- I2C Adapter: 内核启动时解析 dts 中的 i2c 节点(如
i2c0),加载i2c-rk3x驱动,注册为i2c_adapter。 - I2C Client: 适配器注册后,Core 层会扫描该 i2c 节点下的子节点(挂载的设备),实例化
i2c_client。 - I2C Driver: 驱动加载时,调用
i2c_register_driver。 - Match: I2C Bus 的
match函数会比较i2c_client->name(或 compatible) 与i2c_driver->id_table(或 of_match_table)。 - Probe: 匹配成功后,调用
i2c_driver->probe(client, ...)。
5. 总结
I2C 子系统的分层设计使得:
- 可移植性强: 设备驱动不需要关心底层的 I2C 控制器是 Rockchip 的还是 STM32 的,只要内核有对应的 Adapter 驱动即可。
- 开发简化: 开发者只需关注设备本身的寄存器操作,底层的时序和协议由 Core 和 Bus Driver 处理。