RK3588 kernel-6.1/drivers/i2c/algos 目录功能详细分析
1. 文档范围
本文分析目录:
- 源码:
rk3588/kernel-6.1/drivers/i2c/algos - 文档:
linuxDoc/drivers/i2c/
核心定位: algos/ 提供 I2C 传输算法(struct i2c_algorithm) 的软件实现,本身不直接操作具体 SoC 硬件。各 bus 控制器驱动(busses/)或 GPIO I2C 驱动 负责提供底层读写 SDA/SCL 或桥接芯片寄存器的回调,再调用 i2c_bit_add_bus() / i2c_pca_add_bus() / i2c_pcf_add_bus() 将算法挂到 i2c_adapter 上。
2. 在 I2C 子系统中的位置
1 | i2c-core (i2c_transfer) |
与 RK3588 内置 I2C(i2c-rk3x.c)的关系:
| 对比项 | algos/ |
i2c-rk3x.c |
|---|---|---|
| 角色 | 通用 算法库 | 硬件主机控制器 |
master_xfer |
bit/pca/pcf 软件实现 | rk3x_i2c_xfer 寄存器+中断 |
| RK3588 默认 | 通常不启用(有硬件 I2C) | 主要路径 |
| 可选场景 | CONFIG_I2C_GPIO + I2C_ALGOBIT 用 GPIO 模拟 I2C |
所有 i2c0~i2c7 |
3. 目录与构建
3.1 文件列表
| 文件 | 说明 |
|---|---|
i2c-algo-bit.c |
位带(bit-banging)算法,最常用 |
i2c-algo-pca.c |
NXP PCA9564 / PCA9665 并行总线桥算法 |
i2c-algo-pcf.c |
Philips PCF8584 算法 |
i2c-algo-pcf.h |
PCF8584 寄存器位定义(内部头文件) |
Makefile / Kconfig |
三模块独立编译选项 |
3.2 Kconfig
| 选项 | 模块 | 功能 |
|---|---|---|
I2C_ALGOBIT |
i2c-algo-bit.ko |
GPIO/并口等位带 I2C |
I2C_ALGOPCA |
i2c-algo-pca.ko |
PCA9564/9665 桥 |
I2C_ALGOPCF |
i2c-algo-pcf.ko |
PCF8584 桥 |
顶层 drivers/i2c/Kconfig 中 I2C_HELPER_AUTO(默认 y)会在需要时自动选中对应 algo,无需手动配置。
menu "I2C Algorithms" 仅在 !I2C_HELPER_AUTO 时对用户可见。
4. 算法层设计模式(共性)
三类算法均遵循同一模式:
- Bus 驱动 分配
i2c_adapter,在algo_data中填入硬件相关结构体; - 调用
i2c_*_add_bus()/i2c_*_add_numbered_bus(); - Add 函数内设置
adap->algo = &xxx_algo,再i2c_add_adapter(); - Core 调用
adap->algo->master_xfer()完成传输。
对外导出的符号(供 bus 驱动链接):
| 算法 | 导出接口 | 算法结构体 |
|---|---|---|
| bit | i2c_bit_add_bus, i2c_bit_add_numbered_bus |
i2c_bit_algo |
| pca | i2c_pca_add_bus, i2c_pca_add_numbered_bus |
内部 pca_algo |
| pcf | i2c_pcf_add_bus |
内部 pcf_algo |
5. i2c-algo-bit.c — 软件位带算法(核心)
5.1 适用场景
- 无专用 I2C 硬件 IP,仅用 GPIO 或并口线模拟 SDA/SCL;
- 老平台、FPGA、扩展板、调试用 bit-bang;
- RK3588 上对应驱动:
busses/i2c-gpio.c(compatible = "i2c-gpio")。
5.2 底层回调结构(include/linux/i2c-algo-bit.h)
1 | struct i2c_algo_bit_data { |
Bus 驱动只需实现 拉高/拉低/读取 SDA/SCL;时序由 algo 统一完成。
5.3 时序原语
| 函数 | I2C 语义 |
|---|---|
i2c_start() |
START:SDA 高→低,SCL 高→低 |
i2c_repstart() |
Repeated START |
i2c_stop() |
STOP:SCL 高,SDA 低→高 |
i2c_outb() |
发送 8 bit + 读 ACK |
i2c_inb() |
接收 8 bit |
sclhi() |
SCL 置高并等待(支持 clock stretching 检测) |
udelay 决定速率:例如 udelay=5 约对应标准模式量级(需结合上升沿实测)。
5.4 传输主流程 bit_xfer()
1 | pre_xfer (可选) |
支持特性(bit_func()):
- 标准 I2C、SMBus 模拟(含 block read
I2C_M_RECV_LEN); I2C_M_NOSTART、I2C_M_STOP、I2C_M_IGNORE_NAK;- 10 位地址
I2C_M_TEN; master_xfer_atomic(需can_do_atomic)。
5.5 总线自检 test_bus()
i2c_bit_add_bus() 时若 bit_test 模块参数非 0,会:
- 检查 SDA/SCL 是否空闲;
- 拉低/拉高 SDA、SCL 验证线路未 stuck;
bit_test=2时失败则拒绝注册 adapter。
5.6 依赖本算法的 bus 驱动(节选)
| 驱动 | 平台/用途 |
|---|---|
i2c-gpio.c |
GPIO 模拟 I2C(与嵌入式最相关) |
i2c-parport.c |
并口 |
i2c-acorn.c |
Acorn |
i2c-hydra.c |
Mac Hydra |
i2c-via.c |
VIA 芯片组 |
i2c-simtec.c |
Simtec 板 |
i2c-versatile.c |
ARM Versatile |
5.7 RK3588 上的 i2c-gpio 示例
i2c-gpio.c 通过 GPIO 子系统获取 sda/scl,填入 i2c_algo_bit_data,最后:
1 | ret = i2c_bit_add_numbered_bus(adap); |
设备树典型节点:
1 | i2c_gpio: i2c-gpio { |
RK3588 默认 defconfig 通常不启用 I2C_GPIO,仅在缺硬件通道或特殊板级需要时打开。
6. i2c-algo-pca.c — PCA9564/PCA9665 算法
6.1 适用场景
NXP PCA9564 / PCA9665 为 I2C 转并行总线 的桥接芯片:主机通过访问桥上的寄存器,由芯片硬件状态机产生 SDA/SCL 波形。
6.2 底层回调(include/linux/i2c-algo-pca.h)
1 | struct i2c_algo_pca_data { |
Bus 驱动(i2c-pca-platform.c、i2c-pca-isa.c)负责 MMIO/ISA 端口读写与中断等待。
6.3 寄存器与芯片差异
| 寄存器 | PCA9564 | PCA9665 |
|---|---|---|
| 控制 | I2C_PCA_CON (STA/STO/SI/ENSIO) |
间接寄存器 I2C_PCA_INDPTR + I2C_PCA_IND |
| 数据 | I2C_PCA_DAT |
同上 |
| 状态 | I2C_PCA_STA (类似 0xF8 idle) |
状态机码相同风格 |
pca_probe_chip():写 I2C_PCA_IADR 探测是否为 9665,否则按 9564 处理。
6.4 传输状态机 pca_xfer()
基于 状态寄存器值(如 0xF8 idle、0x08 START 已发、0x18 SLA+W ACK)驱动:
1 | 等待 bus idle (0xF8) |
错误处理:0x20/0x30/0x38 NAK/仲裁丢失、0x70/0x90 SDA/SCL stuck 时 pca_reset()。
6.5 时钟配置
- PCA9564:8 档固定频率(330kHz~36kHz),
i2c_clock可为 Hz 或档位索引; - PCA9665:按目标 Hz 计算
tlow/thi,支持 Standard / Fast / Fast+ / Turbo 模式。
6.6 能力
pca_func():I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL(无 10bit、无 NOSTART 等 bit 算法的灵活标志)。
7. i2c-algo-pcf.c — PCF8584 算法
7.1 适用场景
Philips PCF8584 为较老的 I2C 总线控制器(并行接口),用于 ISA/定制总线扩展。现多见于 复古硬件(如 i2c-elektor.c、i2c-icy.c)。
7.2 底层回调(include/linux/i2c-algo-pcf.h)
1 | struct i2c_algo_pcf_data { |
7.3 控制/状态位(i2c-algo-pcf.h)
| 宏 | 含义 |
|---|---|
I2C_PCF_STA / STO |
START / STOP |
I2C_PCF_BB |
Bus Busy |
I2C_PCF_LRB |
Last Received Bit (ACK) |
I2C_PCF_LAB |
Lost Arbitration |
7.4 传输流程 pcf_xfer()
1 | xfer_begin |
多主: wait_for_pin 返回 -EINTR 表示仲裁丢失,handle_lab() 复位 PCF 并 lab_mdelay 退避。
7.5 初始化 pcf_init_8584()
检测 PCF8584 是否存在(写 OWNADR/CLKREG 等),配置时钟与 ESO。
7.6 能力
I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING(无 atomic xfer)。
8. 三种算法对比总表
| 特性 | bit-bang | PCA9564/9665 | PCF8584 |
|---|---|---|---|
| 硬件形态 | GPIO/并口线 | I2C-Parallel 桥 | 并行 I2C 控制器 |
| 时序实现 | 软件 bit 操作 | 芯片状态机+主机轮询/中断 | 芯片状态机+PIN |
| Clock stretch | 支持(需 getscl) | 硬件处理 | 硬件处理 |
| 10 位地址 | 支持 | 不支持 | 不支持 |
| SMBus block | 支持(RECV_LEN) | 模拟 | 模拟 |
| 多主仲裁 | 未完整实现 | 有(0x38) | LAB + mdelay |
| 典型年代 | 一直使用 | 2000s 工业板 | 1990s |
| RK3588 相关性 | 可选(GPIO I2C) | 低 | 极低 |
9. 与 i2c-core 的衔接细节
9.1 谁调用算法
1 | /* i2c-core-base.c */ |
9.2 Quirks(bit 专用)
若 getscl == NULL,i2c_bit_add_bus() 设置:
1 | adap->quirks = &i2c_bit_quirk_no_clk_stretch; /* I2C_AQ_NO_CLK_STRETCH */ |
告知上层该总线可能无法正确处理从设备拉长 SCL。
9.3 调试
CONFIG_I2C_DEBUG_ALGO→ccflags -DDEBUG(bit 中bit_dbg);- bit 模块参数:
bit_test、i2c_debug; - pca/pcf 模块参数:
i2c_debug。
10. RK3588 平台实践说明
10.1 默认路径
RK3588 使用 DesignWare 风格 Rockchip I2C IP(i2c-rk3x.c),在 adapter 内直接实现 i2c_algorithm,不经过 algos/。
10.2 何时需要 algos
| 需求 | 配置建议 |
|---|---|
| 额外 GPIO 模拟 I2C | CONFIG_I2C_GPIO=y + CONFIG_I2C_ALGOBIT=y(通常由 HELPER_AUTO 选中) |
| 外接 PCA9564 并口桥 | CONFIG_I2C_ALGOPCA + i2c-pca-platform |
| 复古/特殊 PCF8584 板 | CONFIG_I2C_ALGOPCF + 对应 bus 驱动 |
在 arch/arm64/configs/*rk3588* 中一般看不到 I2C_ALGOBIT;部分 RK 衍生配置(如 rv1126b_robot.config)会显式 CONFIG_I2C_ALGOBIT=y。
10.3 与总线恢复的关系
i2c-core-base.c 中 i2c_generic_scl_recovery() 在 adapter 有 bus_recovery_info 时,也可用 GPIO bit-bang 恢复卡死的 SDA/SCL;这与 i2c-algo-bit 思想相同,但是 core 内独立路径,不要求加载 i2c-algo-bit 模块。
11. 数据流示意(以 GPIO I2C 为例)
1 | 传感器驱动 / i2c_transfer() |
12. 调试建议
| 问题 | 排查 |
|---|---|
| GPIO I2C 无响应 | 检查 i2c-gpio,delay-us、上拉、开漏配置 |
Not I2C compliant: can't read SCL |
未接 getscl,clock stretch 不可靠 |
test_bus 失败 |
SDA/SCL stuck,硬件短路或外设拉死 |
| PCA 超时 0x?? | wait_for_completion 中断未接;时钟配置错误 |
PCF Timeout waiting for BB |
总线被占用或多主冲突 |
1 | # 查看是否加载算法模块 |
13. 结论
drivers/i2c/algos 目录包含 3 个可加载的 I2C 算法模块,职责是:
- 实现统一的
i2c_algorithm.master_xfer; - 将 I2C 协议时序(START/STOP/字节/ACK)从 bus 驱动中解耦;
- 通过 回调结构体 适配 GPIO、PCA 桥、PCF8584 等不同硬件形态。
对 RK3588 而言:
- 主 I2C 走
i2c-rk3x,与algos/无关; - 扩展/备用 总线可通过
i2c-gpio+i2c-algo-bit实现; i2c-algo-pca/i2c-algo-pcf主要用于特定外设桥与 legacy 硬件,产品树中较少出现。
理解 algos/ 有助于区分「硬件控制器驱动」与「纯软件/GPIO/桥片算法」两条 I2C 主机实现路径。
14. 推荐阅读顺序
include/linux/i2c-algo-bit.h— 回调接口algos/i2c-algo-bit.c—bit_xfer、i2c_bit_add_busbusses/i2c-gpio.c— RK 平台最可能用到的组合algos/i2c-algo-pca.c— 状态机桥接范例i2c-core-base.c—i2c_transfer入口
15. 相关文档
rk3588-kernel-6.1-drivers-i2c目录功能详细分析_zh.mdrk3588-kernel-6.1-drivers-i2c-muxes目录功能详细分析_zh.mdrk3588-kernel-6.1-i2c总线架构分析.md
文档版本:基于 rk3588/kernel-6.1 源码树 drivers/i2c/algos 分析。
正在加载留言…