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 2 3 4 5 6 7 8 9 10 11 12 13 i2c-core (i2c_transfer) │ ▼ adapter->algo->master_xfer() ← algos/ 目录实现 │ ├── i2c-algo-bit.c (软件位带 START/STOP/字节/ACK) ├── i2c-algo-pca.c (PCA9564/9665 状态机) └── i2c-algo-pcf.c (PCF8584 状态机) │ ▼ busses/*.c 提供的底层回调 例: i2c-gpio.c → setsda/setscl/getsda/getscl i2c-pca-platform.c → read_byte/write_byte/wait_for_completion
与 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 2 3 4 5 6 7 8 9 10 11 12 struct i2c_algo_bit_data { void *data; void (*setsda)(void *data, int state); void (*setscl)(void *data, int state); int (*getsda)(void *data); int (*getscl)(void *data); int (*pre_xfer)(struct i2c_adapter *); void (*post_xfer)(struct i2c_adapter *); int udelay; int timeout; bool can_do_atomic; };
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 2 3 4 5 6 7 8 pre_xfer (可选) → i2c_start() → 对每条 i2c_msg: 若非 I2C_M_NOSTART: bit_doAddress() (7/10 位地址 + 重试) 若 I2C_M_RD: readbytes() + ACK/NAK 否则: sendbytes() → i2c_stop() post_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 2 3 4 5 6 7 8 i2c_gpio: i2c-gpio { compatible = "i2c-gpio" ; gpios = <&gpio SDA GPIO_ACTIVE_HIGH> , <&gpio SCL GPIO_ACTIVE_HIGH> ; i2c-gpio,delay-us = <5 > ; #address-cells = <1>; #size-cells = <0>; };
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 2 3 4 5 6 7 8 9 10 struct i2c_algo_pca_data { void *data; void (*write_byte)(void *data, int reg, int val); int (*read_byte)(void *data, int reg); int (*wait_for_completion)(void *data); void (*reset_chip)(void *data); unsigned int i2c_clock; unsigned int chip; struct pca_i2c_bus_settings bus_settings ; };
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 2 3 4 5 6 等待 bus idle (0xF8) → pca_start / pca_repeated_start → pca_address (写 DAT + 清 SI) → 写路径: pca_tx_byte 循环 → 读路径: pca_rx_ack + pca_rx_byte → pca_stop
错误处理: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 2 3 4 5 6 7 8 9 10 struct i2c_algo_pcf_data { void *data; void (*setpcf)(void *data, int ctl, int val); int (*getpcf)(void *data, int ctl); int (*getown)(void *data); int (*getclock)(void *data); void (*waitforpin)(void *data); void (*xfer_begin/end)(void *data); unsigned long lab_mdelay; };
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 2 3 4 5 6 7 8 9 xfer_begin → wait_for_bb() /* 等待总线空闲 */ → 每条 msg: pcf_doAddress i2c_start (首条) wait_for_pin /* 等待 PIN 中断 */ 写: pcf_sendbytes 读: pcf_readbytes (含 dummy read) → xfer_end
多主: 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 2 3 4 5 6 int i2c_transfer (struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { ... ret = adap->algo->master_xfer(adap, msgs, num); }
9.2 Quirks(bit 专用) 若 getscl == NULL,i2c_bit_add_bus() 设置:
1 adap->quirks = &i2c_bit_quirk_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 2 3 4 5 6 7 8 9 10 11 12 13 14 传感器驱动 / i2c_transfer() │ ▼ i2c-gpio adapter (i2c-10) │ ▼ i2c_bit_algo.master_xfer ← i2c-algo-bit.c │ ├── setsda(0/1) ──► gpiod_set_value (SDA) ├── setscl(0/1) ──► gpiod_set_value (SCL) └── getsda/getscl ──► gpiod_get_value │ ▼ 物理 SDA/SCL 引脚
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 2 3 4 5 lsmod | grep i2c_algo ls /sys/bus/i2c/devices/ | grep muxi2cdetect -y <bus>
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_bus
busses/i2c-gpio.c — RK 平台最可能用到的组合
algos/i2c-algo-pca.c — 状态机桥接范例
i2c-core-base.c — i2c_transfer 入口
15. 相关文档
文档版本:基于 rk3588/kernel-6.1 源码树 drivers/i2c/algos 分析。