RK3588 kernel-6.1 drivers/i2c 总线架构分析

RK3588 kernel-6.1 drivers/i2c 总线架构分析

1. 范围说明

本文聚焦目录:

  • rk3588/kernel-6.1/drivers/i2c

分析目标:

  • I2C 子系统在 Linux 设备模型中的位置
  • i2c-core 的总线、适配器、驱动、传输调用链
  • RK3588 所在 Rockchip I2C 主控驱动(i2c-rk3x.c)实现特点
  • 面向开发与排障的实践方法

2. 目录分层与模块组织

drivers/i2c/Makefile 可以看出四层结构:

  1. 核心层i2c-core-base.ci2c-core-smbus.ci2c-core-of.ci2c-core-acpi.c
    提供总线注册、设备/驱动匹配、传输入口、OF/ACPI 枚举与 SMBus 扩展能力。
  2. 用户态接口层i2c-dev.c
    对外暴露 /dev/i2c-*,用于用户态工具(如 i2c-tools)访问总线。
  3. 拓扑扩展层i2c-mux.c + muxes/
    把多路复用后的每条下游链路抽象成独立 i2c_adapter
  4. 控制器驱动层busses/
    各 SoC I2C Host Controller 驱动,Rockchip 关键文件是 busses/i2c-rk3x.c

这说明 I2C 架构本质上是:core 定义规则 + controller 驱动提供 algorithm + client 驱动按地址挂载到 adapter


3. I2C 在 Linux 设备模型中的角色

i2c-core-base.c 中,I2C 总线对象是 i2c_bus_type,并注册了:

  • .match:匹配 i2c_clienti2c_driver
  • .probe:调用 client 驱动探测逻辑
  • .remove:解绑时回收

因此,I2C 也是标准 bus_type,在系统里遵循统一的 device model 生命周期。

可以把三类对象理解为:

  • i2c_adapter:控制器实例(一条物理/逻辑总线)
  • i2c_client:该总线上的从设备抽象(地址 + 属性)
  • i2c_driver:具体芯片驱动(如触摸、PMIC、传感器)

4. 注册与绑定主链路

4.1 控制器侧(Host)注册

控制器驱动完成硬件初始化后,调用:

  • i2c_add_adapter()(动态 bus id)
  • i2c_add_numbered_adapter()(固定 bus id)

两者最终进入 i2c_register_adapter(),由 core 把 adapter 纳入 I2C 总线并触发设备侧匹配。

4.2 客户端驱动(Client)注册

I2C client 驱动通过 i2c_register_driver() 注册。
完成后 core 会尝试把该驱动与现有 i2c_client 逐个匹配。

4.3 匹配结果

匹配成功后进入 i2c_device_probe(),再调用具体 client 驱动的 probe
卸载走 i2c_device_remove()


5. 传输调用链(最关键)

I2C 数据传输链路分两层:

  1. i2c_transfer() / __i2c_transfer():core 通用入口,做重试、锁、trace、能力检查等。
  2. adapter->algo->master_xfer():具体控制器驱动实现,真正触发硬件收发。

也就是:协议框架在 core,时序细节在 bus controller 驱动

对 RK3588 来说,master_xfer() 对应 i2c-rk3x.c 中的 rk3x_i2c_xfer()


6. Rockchip I2C 控制器驱动架构(i2c-rk3x.c

i2c-rk3x.c 是平台驱动(platform_driver),通过 of_match_table 适配多代 Rockchip SoC。
该驱动对 RK3588 这类平台的价值是:把 SoC 寄存器/中断/时钟差异封装成统一 I2C adapter 能力

6.1 驱动入口与资源初始化

rk3x_i2c_probe() 主要做:

  • 解析 bus id(OF alias / ACPI UID)
  • 解析 timing(i2c_parse_fw_timings
  • 映射寄存器、申请 IRQ、获取时钟与复位
  • 设置 i2c_adapter 字段(algoretriesnrparent 等)
  • i2c_add_numbered_adapter() 向 core 注册

这条路径体现了 Linux 控制器驱动通用模板:platform probe -> resource init -> adapter register

6.2 i2c_algorithm 回调实现

Rockchip 驱动提供:

  • .master_xfer = rk3x_i2c_xfer
  • .master_xfer_atomic = rk3x_i2c_xfer_polling
  • .functionality = rk3x_i2c_func

其中 rk3x_i2c_xfer_common() 是核心传输函数,负责:

  • 消息分段处理(支持组合写读)
  • 中断模式与 polling 模式切换
  • 超时、NACK、STOP、恢复与错误上报

6.3 状态机与中断驱动执行

驱动内部状态机:

  • STATE_IDLE
  • STATE_WRITE
  • STATE_READ
  • STATE_STOP

IRQ 入口 rk3x_i2c_irq() 根据状态分发到:

  • rk3x_i2c_handle_write()
  • rk3x_i2c_handle_read()
  • rk3x_i2c_handle_stop()

这是典型主控 I2C 驱动范式:寄存器配置 + 中断推进状态机 + waitqueue 同步上层调用线程

6.4 FIFO 与 DMA 双通路

驱动根据消息长度/方向选择:

  • FIFO 路径(短消息)
  • DMA 路径(较长消息,含 bounce buffer 和 DMA map/unmap)

相关逻辑在:

  • rk3x_i2c_start_fifo()
  • rk3x_i2c_start_dma()
  • rk3x_i2c_complete_dma()

这套实现兼顾低延迟与吞吐量。

6.5 时序计算与动态时钟适配

Rockchip 驱动提供 v0/v1 两套 timing 计算函数:

  • rk3x_i2c_v0_calc_timings()
  • rk3x_i2c_v1_calc_timings()

并在时钟变化通知中重算分频:

  • rk3x_i2c_clk_notifier_cb()
  • rk3x_i2c_adapt_div()

这保证 DVFS 或时钟调整后,I2C 仍满足标准/快速/快速+模式时序约束。

6.6 SoC 差异封装点

通过 struct rk3x_i2c_soc_data 抽象差异:

  • grf_offset
  • calc_timings
  • dma_control

并在 rk3x_i2c_match[] 里按 compatible 选择具体实现。
这种做法能让同一驱动覆盖 rk3066/rk3399/rv1126 等多代硬件。


7. I2C 设备树与总线编号关系

该驱动通过 of_alias_get_id(np, "i2c") 获取 bus id,并赋给 adap.nr,最终对应用户态 i2c-X 编号。
所以系统里 i2c-0/i2c-1/... 稳定性很大程度取决于 DTS alias 配置。

此外,i2c_parse_fw_timings() 会读取固件里的时序属性(如 bus 频率、上升下降沿参数),直接影响硬件分频计算结果。


8. 用户态接口与调试入口

8.1 用户态接口

若使能 CONFIG_I2C_CHARDEVi2c-dev.c 会创建 /dev/i2c-*
这给 bring-up 和问题定位提供了快速验证通道。

8.2 常用排障思路

  1. 确认枚举
    • 适配器是否注册成功(i2c_add_numbered_adapter 路径)
    • /dev/i2c-* 是否出现(启用 I2C_CHARDEV
  2. 确认时序
    • i2c,clk-rate 与硬件支持模式是否匹配
    • 查看是否出现 timeout / NACK / SCL hold 报错
  3. 确认中断与状态机
    • IRQ 是否触发
    • 是否卡在 STATE_STOP 或等待队列超时
  4. 确认总线拓扑
    • 是否经过 mux,目标设备是否在正确下游 adapter

9. 面向驱动开发的结论

在 RK3588 kernel-6.1 中,I2C 架构可以总结为:

  • Core 负责“总线规则”:注册、匹配、生命周期与统一 API。
  • Controller 驱动负责“硬件执行”:时序、状态机、中断/DMA、容错恢复。
  • Client 驱动负责“芯片语义”:寄存器协议、功能逻辑、PM/中断等。

如果你要新增一个 I2C 设备驱动,优先关注的是 client 驱动;
如果你遇到“整条总线异常”,则应回到 i2c-rk3x.c 的传输状态机、时钟时序与中断链路。


10. 推荐阅读顺序(只看关键文件)

  1. drivers/i2c/i2c-core-base.c(总线/注册/传输主流程)
  2. drivers/i2c/i2c-core-of.c(OF 枚举)
  3. drivers/i2c/i2c-dev.c(用户态接口)
  4. drivers/i2c/busses/i2c-rk3x.c(Rockchip 控制器实现)
  5. drivers/i2c/muxes/* + drivers/i2c/i2c-mux.c(复杂拓扑场景)

一句话:RK3588 的 I2C 是“Linux 通用 I2C core + Rockchip rk3x 控制器状态机实现”的组合架构。

文章互动

阅读 --

留言

0 条留言

正在加载留言…