RK3588 kernel-6.1/drivers/i2c/i2c-core-slave.c 功能详细分析

RK3588 kernel-6.1/drivers/i2c/i2c-core-slave.c 功能详细分析

1. 文档范围与说明

路径说明: 用户表述为「i2c-core-slave.c 目录」,实际为 单个源文件

  • rk3588/kernel-6.1/drivers/i2c/i2c-core-slave.c(约 128 行)

编译关系: 仅在启用 CONFIG_I2C_SLAVE 时编入 i2c-core.ko

1
i2c-core-$(CONFIG_I2C_SLAVE) += i2c-core-slave.o

文档保存路径: linuxDoc/drivers/i2c/

定位: I2C 子系统的 从机(Slave)模式核心薄层:在已有 i2c_clienti2c_adapter 框架上,提供 注册/注销从机回调向从机后端投递总线事件、以及 从 DT 检测控制器是否应工作在从机模式 的通用 API。具体从机行为由 后端驱动(如 i2c-slave-eeprom.c)和 主机控制器驱动的 reg_slave/unreg_slave 实现。

与 RK3588 的关系:

项目 RK3588 典型情况
CONFIG_I2C_SLAVE Rockchip arm64 defconfig 通常未启用 → 本文件 默认不链接
i2c-rk3x.c 未实现 algo->reg_slave / unreg_slave
产品角色 SoC I2C 控制器作 主设备(Master) 访问传感器/PMIC 等

若需让 RK3588 Linux 作为 I2C 从设备 被外部主机访问,除打开 CONFIG_I2C_SLAVE 外,还须 硬件与 i2c-rk3x 驱动支持从机模式(当前树中未提供)。本文仍完整说明本文件机制及与 DT、其它驱动的衔接。


2. 功能总览

符号 导出 作用
i2c_slave_register() GPL 绑定 slave_cb,调用 adapter reg_slave
i2c_slave_unregister() GPL 调用 adapter unreg_slave,清除回调
i2c_slave_event() GPL 主机驱动收到总线活动时调用,转发至 slave_cb
i2c_detect_slave_mode() GPL 扫描 DT 子节点 reg 是否含 I2C_OWN_SLAVE_ADDRESS

Tracepoint: trace/events/i2c_slave.htrace_i2c_slave),在 i2c_slave_event() 中可选记录。


3. I2C 从机模式架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
外部 I2C Master                    Linux SoC
───────────────── ─────────
│ │
│ START + 从机地址 + R/W │
▼ ▼
┌─────────┐ IRQ/DMA ┌──────────────────┐
│ 总线 │──────────────►│ bus driver │
└─────────┘ │ (reg_slave 实现) │
│ i2c_slave_event │
└────────┬─────────┘

┌────────▼─────────┐
│ i2c-core-slave.c │ ← 本文(转发)
└────────┬─────────┘
│ slave_cb
┌────────▼─────────┐
│ 后端驱动 │
│ slave-eeprom 等 │
└────────┬─────────┘
│ sysfs 等
┌────────▼─────────┐
│ 用户空间 / 内核 │
└──────────────────┘

内核文档:Documentation/i2c/slave-interface.rst

要点: i2c-core-slave.c 不处理硬件寄存器;仅协调 adapter 算法从机后端回调


4. 数据结构与事件类型(include/linux/i2c.h

4.1 回调类型

1
2
typedef int (*i2c_slave_cb_t)(struct i2c_client *client,
enum i2c_slave_event event, u8 *val);

struct i2c_client 含成员 i2c_slave_cb_t slave_cbCONFIG_I2C_SLAVE 时有效)。

4.2 事件枚举

事件 含义(简述)
I2C_SLAVE_WRITE_REQUESTED 主机发起写:地址+写位已匹配,尚未收数据
I2C_SLAVE_WRITE_RECEIVED 收到一字节写数据(val 为数据)
I2C_SLAVE_READ_REQUESTED 主机发起读:应填充首字节到 *val
I2C_SLAVE_READ_PROCESSED 上一读字节已发出,准备下一字节
I2C_SLAVE_STOP 检测到 STOP(或等效结束)

后端在 READ_REQUESTED / READ_PROCESSED 中通过 *val 提供读出数据;WRITE_RECEIVED*val 取写入数据。详见 slave-interface.rst 中 mandatory/optional 说明。


5. i2c_slave_register() — 注册从机

1
int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb);

5.1 流程

1
2
3
4
5
6
7
8
参数检查 (client, slave_cb)
→ 7 位地址: i2c_check_7bit_addr_validity_strict()
→ 检查 client->adapter->algo->reg_slave 非空
→ client->slave_cb = slave_cb
→ i2c_lock_bus(ROOT_ADAPTER)
→ ret = adap->algo->reg_slave(client)
→ i2c_unlock_bus()
→ 失败则 slave_cb = NULL

5.2 注意事项

检查 行为
未设置 I2C_CLIENT_SLAVE 仅警告,仍继续注册(可能与其它 master 地址冲突)
reg_slave -EOPNOTSUPP
10 位地址 跳过 strict 7 位检查

谁调用: 从机后端在 probe 中调用,例如 i2c-slave-eeprom.ci2c-slave-testunit.ci2c-smbus.c 中 Host Notify 从机路径(CONFIG_I2C_SLAVE)。


6. i2c_slave_unregister() — 注销从机

1
int i2c_slave_unregister(struct i2c_client *client);

对称调用 adap->algo->unreg_slave(client),成功则 client->slave_cb = NULL。无 unreg_slave 时返回 -EOPNOTSUPP

调用时机: 后端驱动 remove、或 Host Notify 客户端拆除时。


7. i2c_slave_event() — 事件投递

1
2
int i2c_slave_event(struct i2c_client *client,
enum i2c_slave_event event, u8 *val);
  • 调用 client->slave_cb(client, event, val)
  • 若启用 trace,记录 trace_i2c_slave(client, event, val, ret)
  • 返回值供 总线驱动 决定 ACK/NACK 等(依控制器实现)。

调用者:实现了从机模式的 I2C 主机驱动(如 i2c-stm32f7.ci2c-imx.ci2c-rcar.c 等在 ISR/状态机中调用)。

示例(STM32):

1
2
3
i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value);
i2c_slave_event(i2c_dev->slave_running, I2C_SLAVE_WRITE_RECEIVED, &val);
i2c_slave_event(i2c_dev->slave_running, I2C_SLAVE_STOP, &val);

8. i2c_detect_slave_mode() — DT 从机模式检测

1
bool i2c_detect_slave_mode(struct device *dev);

8.1 逻辑

dev->of_node 存在,遍历其 直接子节点,读取 reg

1
2
if (reg & I2C_OWN_SLAVE_ADDRESS)
return true;

I2C_OWN_SLAVE_ADDRESS 定义于 include/dt-bindings/i2c/i2c.h(1 << 30)

8.2 与 i2c-core-of.c 的配合

of_i2c_get_board_info() 解析子设备时:

1
2
3
4
if (addr & I2C_OWN_SLAVE_ADDRESS) {
addr &= ~I2C_OWN_SLAVE_ADDRESS;
info->flags |= I2C_CLIENT_SLAVE;
}
  • 子设备I2C_OWN_SLAVE_ADDRESS → 创建的 client 带 I2C_CLIENT_SLAVE
  • i2c_detect_slave_mode(dev)控制器设备 dev 上扫描子节点,判断整路 I2C 是否配置为从机控制器模式(任一子节点声明 own-slave 地址即返回 true)。

8.3 使用方

驱动 用途
i2c-designware-core i2c_dw_configure() 选择 master/slave 硬件配置
i2c-at91-core dev->slave_detected 标志

RK3588 i2c-rk3x 源码中 未调用 i2c_detect_slave_mode()

8.4 ACPI

1
2
3
} else if (IS_BUILTIN(CONFIG_ACPI) && ACPI_HANDLE(dev)) {
dev_dbg(dev, "ACPI slave is not supported yet\n");
}

ACPI 从机检测 尚未实现,恒返回 false。


9. Kconfig 与相关模块

9.1 CONFIG_I2C_SLAVE

1
2
3
4
5
config I2C_SLAVE
bool "I2C slave support"
help
This enables Linux to act as an I2C slave device. Note that your I2C
bus master driver also needs to support this functionality.

依赖链:

1
2
3
4
5
CONFIG_I2C_SLAVE=y
→ i2c-core-slave.o 链接进 i2c-core.ko
→ 可选:
CONFIG_I2C_SLAVE_EEPROM (i2c-slave-eeprom.ko)
CONFIG_I2C_SLAVE_TESTUNIT (i2c-slave-testunit.ko)

9.2 从机后端驱动(同目录,非本文)

文件 作用
i2c-slave-eeprom.c 模拟 I2C EEPROM,用户空间经 sysfs 读写“存储”
i2c-slave-testunit.c 测试用从机,配合总线 master 测试多主机、Host Notify 等

9.3 i2c-smbus.c 中的从机用法

启用 CONFIG_I2C_SLAVE 时,SMBus Host Notify 可注册从机回调 i2c_slave_host_notify_cb,在收到主机写通知时置位 status->host_notifywake_up


10. 主机驱动支持情况(本树)

algo->reg_slave / unreg_slave 在部分 busses/ 驱动中实现,例如:

  • i2c-stm32f7.c
  • i2c-imx.c
  • i2c-rcar.c
  • i2c-pxa.c
  • i2c-npcm7xx.c
  • i2c-mlxbf.c
  • i2c-emev2.c
  • DesignWare 系列(配合 i2c_detect_slave_mode 配置 master/slave)

未实现(RK3588 相关):

  • i2c-rk3x.c reg_slave / unreg_slave

因此即使打开 CONFIG_I2C_SLAVE,在 RK3588 上对 rk3x 控制器 调用 i2c_slave_register() 仍会得到 -EOPNOTSUPP


11. Device Tree 与实例化

11.1 从机后端设备节点

从机后端仍是标准 I2C client,在 DT 中挂在某条 I2C 总线下,且 reg 需体现从机地址。文档说明实例化时地址空间需加 0x1000 偏移(历史约定,与 I2C_OWN_SLAVE_ADDRESS 标志配合使用)。

用户空间示例(slave-interface.rst):

1
echo slave-24c02 0x1064 > /sys/bus/i2c/devices/i2c-1/new_device

0x1064 = 0x1000 + 7 位地址 0x64)

11.2 控制器“从机模式”检测示例

若某 DT 设计让 Linux 控制器监听固定地址,子节点可写:

1
2
3
4
linux-i2c-slave@50 {
reg = <0x50 | (1 << 30)>; /* I2C_OWN_SLAVE_ADDRESS */
compatible = "...";
};

i2c_detect_slave_mode(&controller->dev) 返回 true → DesignWare 等驱动配置为 硬件从机

RK3588 产品 DTS 极少 这样配置;常见为 SoC 作 master 访问外设。


12. 与 Master 路径对比

维度 Master(RK3588 常态) Slave(本文件)
配置 默认 CONFIG_I2C_SLAVE
传输 API i2c_transfer() / SMBus 无主动 transfer;被动 i2c_slave_event
Adapter algo master_xfer reg_slave / unreg_slave
DT 标志 reg = <0xNN> reg 含 bit30 或实例化 0x1xxx
RK3x 支持 不支持

13. 源码全文结构(约 128 行)

1
2
3
4
5
L17-18   trace/events/i2c_slave.h
L20-57 i2c_slave_register()
L60-83 i2c_slave_unregister()
L85-95 i2c_slave_event()
L97-127 i2c_detect_slave_mode()

无其它隐藏逻辑;文件刻意保持 薄封装,便于总线驱动与后端解耦。


14. 启用与调试(非 RK3588 默认)

14.1 内核配置

1
2
CONFIG_I2C_SLAVE=y
CONFIG_I2C_SLAVE_EEPROM=m # 可选

重新编译 i2c-core 及所需 bus 驱动、后端模块。

14.2 验证 API 是否编入

1
grep i2c_slave_register /proc/kallsyms   # 需 CONFIG_KALLSYMS

14.3 Trace

1
2
# 若配置了 tracepoint
echo 1 > /sys/kernel/debug/tracing/events/i2c_slave/enable

14.4 常见错误

现象 原因
-EOPNOTSUPP on register adapter 无 reg_slaverk3x
地址冲突警告 未设 I2C_CLIENT_SLAVE 且与其它 client 同址
invalid address 7 位保留地址未通过 strict 检查

15. RK3588 结论与扩展方向

  1. i2c-core-slave.c 提供 Linux I2C 从机框架的 4 个核心 API,本身仅约 128 行。
  2. 默认 Rockchip 内核 通常 不启用 CONFIG_I2C_SLAVE,且 rk3x 无硬件从机钩子,故 RK3588 量产路径 不依赖 本文件。
  3. 若产品需要 SoC 作 I2C 从设备(例如被 MCU/FPGA 访问),需要:
    • 确认 RK3588 I2C IP 是否支持 slave 模式(数据手册);
    • i2c-rk3x.c 中实现 reg_slave/unreg_slave 及中断路径中调用 i2c_slave_event
    • 打开 CONFIG_I2C_SLAVE 并编写或复用从机后端驱动。

16. 推荐阅读顺序

  1. i2c-core-slave.c — 四个导出函数
  2. Documentation/i2c/slave-interface.rst — 事件语义与后端编写
  3. i2c-slave-eeprom.c — 完整后端示例
  4. drivers/i2c/busses/i2c-stm32f7.creg_slave + i2c_slave_event 调用示例
  5. i2c-core-of.cI2C_OWN_SLAVE_ADDRESS 解析

17. 相关文档


文档版本:基于 rk3588/kernel-6.1 源码树 drivers/i2c/i2c-core-slave.c 分析。

文章互动

阅读 --

留言

0 条留言

正在加载留言…