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

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

1. 文档范围与说明

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

  • rk3588/kernel-6.1/drivers/i2c/i2c-slave-testunit.c(约 193 行)

编译关系:

1
obj-$(CONFIG_I2C_SLAVE_TESTUNIT) += i2c-slave-testunit.o

依赖:

1
2
CONFIG_I2C_SLAVE_TESTUNIT  →  依赖 CONFIG_I2C_SLAVE
CONFIG_I2C_SLAVE → i2c-core-slave.o + 主机 reg_slave/unreg_slave

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

定位: I2C 从机模式测试单元(testunit)后端,供 I2C 主机控制器驱动开发与回归测试 使用。外部测试主机通过 写 4 字节寄存器 触发用例;从机在 workqueue 中可再作为 Master 发起 i2c_transfer(多主、Host Notify 等场景)。非生产用途,ABI 不保证稳定。

与 RK3588 的关系:

项目 RK3588 典型情况
CONFIG_I2C_SLAVE / TESTUNIT defconfig 通常未启用
i2c-rk3x 无从机 + 无 master/slave 切换 → 本驱动 无法在 rk3x 上正常工作
用途 主要在 其它支持 I2C Slave 的控制器 上验证主机驱动;RK3588 文档供架构对照

2. 功能总览

模块 符号 作用
寄存器协议 enum testunit_regs CMD / DATAL / DATAH / DELAY
测试命令 enum testunit_cmds READ_BYTES、HOST_NOTIFY、SMBUS_BLOCK_PROC_CALL
从机回调 i2c_slave_testunit_slave_cb() 解析主机写入、处理读版本号 / Block Proc Call
延迟执行 i2c_slave_testunit_work() STOP 后按 DELAY 在 workqueue 执行测试
注册 i2c_slave_register() 挂接从机事件
实例化 slave-testunit 经 sysfs new_device

3. 设计目的与使用场景

内核文档 Documentation/i2c/slave-testunit-backend.rst 说明:

  • 难以获得的远程从设备能力 提供可编程替身(多主机仲裁、SMBus Host Notify、Block Process Call 等);
  • 部分测试要求从机控制器能在 Slave ↔ Master 间切换(本驱动在 work 里调用 i2c_transfer);
  • 禁止用于量产镜像;带版本号 TU_CUR_VERSION = 0x01,读操作返回该版本。

4. 架构与数据流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
测试用 I2C Master (PC/另一 SoC/自测脚本)
│ 写 4 字节: CMD, DATAL, DATAH, DELAY

┌──────────────────┐
│ 被测 SoC 控制器 │ Slave 模式接收
│ + testunit 驱动 │ i2c_slave_testunit_slave_cb()
└────────┬─────────┘
│ STOP 且 reg_idx==4

queue_delayed_work(DELAY * 10ms)


i2c_slave_testunit_work()
│ 可能 i2c_transfer() 作为 Master

总线上其它设备 / Host Notify 地址 0x08

i2c-slave-eeprom.c 对比:

维度 slave-eeprom slave-testunit
目的 模拟 EEPROM 存储 触发主机驱动测试用例
用户接口 sysfs slave-eeprom 仅 I2C 寄存器协议
Master 行为 work 中可 i2c_transfer
读默认 EEPROM 数据 版本号 0x01

5. 寄存器与命令协议

5.1 四个写寄存器(须完整写入 4 字节触发,Block Proc Call 除外)

偏移 名称 含义
TU_REG_CMD (0) CMD 测试命令编号
TU_REG_DATAL (1) DATAL 参数低字节
TU_REG_DATAH (2) DATAH 参数高字节
TU_REG_DELAY (3) DELAY 延迟 = DELAY × 10ms 后执行

实例化示例:

1
echo slave-testunit 0x1030 > /sys/bus/i2c/devices/i2c-0/new_device

0x1030 = 0x1000 + 7 位地址 0x30,与从机 new_device 约定一致。)

i2c-tools 通用写法:

1
i2cset -y <bus> <addr> <CMD> <DATAL> <DATAH> <DELAY> i

5.2 命令列表

CMD 名称 需要 Master 模式 DATAL / DATAH 行为
0x01 TU_CMD_READ_BYTES DATAL=从地址(7bit),DATAH=读长度 work 中对 adapter 发起 读传输,测多主机
0x02 TU_CMD_HOST_NOTIFY 状态字低/高字节(Linux 侧可忽略) 向地址 0x08 写 3 字节 SMBus Host Notify
0x03 TU_CMD_SMBUS_BLOCK_PROC_CALL 否(从机读侧模拟) DATAL=1,DATAH=返回字节数 从机在后续 读事务 中模拟 Block Process Call 响应

TU_CMD >= TU_NUM_CMDS 时从机回调返回 -EINVAL(主机应 NACK)。

保留: CMD 0x00 为 NOOP(未实现)。


6. i2c_slave_testunit_slave_cb() 详解

6.1 I2C_SLAVE_WRITE_REQUESTED

  • TU_FLAG_IN_PROCESS 已置位 → -EBUSY(上一命令未结束);
  • 清零 regs[]reg_idx = 0

6.2 I2C_SLAVE_WRITE_RECEIVED

  • 忙时返回 -EBUSY
  • 按序写入 regs[reg_idx]reg_idx++
  • 写满 4 寄存器后校验 regs[TU_REG_CMD] < TU_NUM_CMDS,否则 -EINVAL
  • 超出 4 字节 → -EMSGSIZE

6.3 I2C_SLAVE_STOP

  • reg_idx == TU_NUM_REGS(4)
    • TU_FLAG_IN_PROCESS
    • queue_delayed_work(system_long_wq, delay = 10ms * regs[TU_REG_DELAY])
  • reg_idx = 0(避免后续读事务重复排队;不清 regs,work 仍需要)。

6.4 读路径

场景 *val
普通读 TU_CUR_VERSION (0x01)
Block Proc Call 模拟 (reg_idx==3 且 CMD=0x03 且 DATAL=1) 递减序列:先返回 DATAH,每次 READ_PROCESSEDDATAH--

Block Proc Call 时主机随后发起读;从机按 SMBus 语义在首字节放 长度,后续字节为 length-1 … 0(由 DATAH 递减实现,见内核文档 i2ctransfer 示例)。


7. i2c_slave_testunit_work() — 测试执行

在延迟结束后运行,根据 TU_REG_CMD 构造 i2c_msgi2c_transfer(tu->client->adapter, &msg, 1)

7.1 TU_CMD_READ_BYTES

1
2
3
msg.addr = tu->regs[TU_REG_DATAL];   /* 7 位从地址 */
msg.flags = I2C_M_RD;
msg.len = tu->regs[TU_REG_DATAH];

用于验证:被测主机驱动testunit 发起的读 同时访问总线时的仲裁/忙处理。

示例(文档):

1
i2cset -y 0 0x30 0x01 0x50 0x80 0x05 i   # 50ms 后从 0x50 读 128 字节

7.2 TU_CMD_HOST_NOTIFY

1
2
3
4
5
msg.addr = 0x08;
msg.len = 3;
msgbuf[0] = tu->client->addr;
msgbuf[1] = DATAL;
msgbuf[2] = DATAH;

SMBus Host Notify 地址 发送通知,测试主机侧 Host Notify 处理路径(与 i2c-core-base.c / i2c-smbus.c 中 Host Notify 相关)。

7.3 完成与错误

  • i2c_transfer 返回 0 条消息时转为 -EIO
  • 失败 dev_err 打印 CMD 与 errno;
  • clear_bit(TU_FLAG_IN_PROCESS),允许下一条命令。

8. Probe / Remove

8.1 i2c_slave_testunit_probe()

1
2
3
4
devm_kzalloc(testunit_data)
tu->client = client
INIT_DELAYED_WORK(&tu->worker, i2c_slave_testunit_work)
i2c_slave_register(client, i2c_slave_testunit_slave_cb)

使用 probe_new(无 id 参数,匹配靠 id_table 在绑定前完成)。

8.2 i2c_slave_testunit_remove()

1
2
cancel_delayed_work_sync(&tu->worker)
i2c_slave_unregister(client)

8.3 模块

  • 单一型号: { "slave-testunit", 0 }
  • of_match_table — 典型通过 new_device 创建,非 DT compatible

9. 与 I2C 子系统的关系

组件 关系
i2c-core-slave.c i2c_slave_register / i2c_slave_event
i2c-core-base.c work 中 i2c_transfer、Host Notify 消费端
i2c-core-smbus.c Block Proc Call 常经 SMBus 模拟;需 I2C_M_RECV_LEN
主机驱动 必须 reg_slave;READ_BYTES/HOST_NOTIFY 还需 同一 adapter 可作 Master

10. RK3588 平台说明

10.1 默认不可用原因

  1. CONFIG_I2C_SLAVE_TESTUNIT 未开 → 驱动不编译;
  2. i2c-rk3x 仅实现 Master(master_xfer), reg_slave
  3. 即使强行加载,i2c_slave_register() 返回 -EOPNOTSUPP
  4. 测试用例依赖的 Slave 期间再 Master 发送 在 rk3x 上 无硬件/驱动支持

10.2 若用于验证 RK3588 主机驱动

需在 支持 I2C Slave(及 preferably 主从切换) 的平台上运行 testunit,或使用 USB-I2C 适配器 + 另一套 slave 控制器 作为对端;不能 把 testunit 挂在 rk3x 控制器上作为完整方案。

10.3 与 slave-eeprom 选型

需求 选用
模拟 EEPROM、用户空间读写镜像 i2c-slave-eeprom.c
主机驱动回归、多主/Notify/Block Proc Call i2c-slave-testunit.c(本文)

11. 测试示例摘要(来自内核文档)

多主读字节:

1
i2cset -y 0 0x30 0x01 0x50 0x80 0x05 i

Host Notify:

1
i2cset -y 0 0x30 0x02 0x42 0x64 0x01 i

Block Process Call(i2ctransfer ≥ 4.2):

1
2
i2ctransfer -y 0 w3@0x30 0x03 0x01 0x10 r?
# 期望: 0x10 0x0f ... 0x00

12. 并发与状态标志

标志 含义
TU_FLAG_IN_PROCESS 命令已排队或 work 执行中;新写/新写请求返回 -EBUSY

DELAY 期间 主机写入会被拒绝,需等待 work 完成。


13. 源码结构速查(约 193 行)

1
2
3
4
5
6
L17-44   版本、命令/寄存器/标志、testunit_data
L46-86 i2c_slave_testunit_work()
L88-149 i2c_slave_testunit_slave_cb()
L151-164 probe (probe_new)
L166-172 remove
L174-188 id_table + i2c_driver + module_i2c_driver

14. 结论

i2c-slave-testunit.cI2C 从机框架的测试专用后端

  1. 通过 4 字节寄存器协议 远程触发 READ_BYTES / HOST_NOTIFY / SMBUS_BLOCK_PROC_CALL
  2. workqueue 中可切换为 Master 发送,用于 多主机与 SMBus 特性 验证;
  3. 从机读路径提供 版本号Block Proc Call 响应模拟;
  4. 依赖 CONFIG_I2C_SLAVE 与主机 reg_slave不保证稳定 ABI
  5. RK3588 rk3x 默认栈不支持,属开发与它平台主机驱动测试工具。

rk3588-kernel-6.1-i2c-slave-eeprom.c功能详细分析_zh.md 同属从机后端,但面向 总线主机驱动 QA 而非存储仿真。


15. 推荐阅读顺序

  1. Documentation/i2c/slave-testunit-backend.rst — 命令与示例
  2. i2c-slave-testunit.cslave_cbwork
  3. Documentation/i2c/slave-interface.rst — 从机事件语义
  4. i2c-core-slave.c — 注册与事件投递
  5. i2c-core-smbus.c — Block 读与 I2C_M_RECV_LEN

16. 相关文档


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

文章互动

阅读 --

留言

0 条留言

正在加载留言…