Linux I2C 从设备测试单元后端¶
由 Wolfram Sang <wsa@sang-engineering.com> 于 2020 年编写
此后端可用于触发 I2C 总线主控的测试用例,这些测试用例需要具有某些功能的远程设备(通常不容易获得)。例如,多主控测试和 SMBus 主机通知测试。对于某些测试,I2C 从控制器必须能够在主控模式和从属模式之间切换,因为它也需要发送数据。
请注意,这是一个用于测试和调试的设备。不应在生产版本中启用它。虽然有一些版本控制,并且我们尽力保持向后兼容性,但不能保证稳定的 ABI!
实例化设备是常规的。总线 0,地址 0x30 的示例
# echo "slave-testunit 0x1030" > /sys/bus/i2c/devices/i2c-0/new_device
或使用固件节点。这是一个设备树示例(请注意,这只是一个调试设备,因此没有官方的 DT 绑定)
&i2c0 {
...
testunit@30 {
compatible = "slave-testunit";
reg = <(0x30 | I2C_OWN_SLAVE_ADDRESS)>;
};
};
之后,您将拥有正在侦听的设备。读取将返回单个字节。如果测试单元处于空闲状态,则其值为 0,否则为当前正在运行的命令的命令号。
写入时,该设备由 4 个 8 位寄存器组成,并且除了某些“部分”命令外,必须写入所有寄存器才能启动测试用例,即通常将 4 个字节写入设备。寄存器是
偏移量 |
名称 |
描述 |
---|---|---|
0x00 |
CMD |
要触发哪个测试 |
0x01 |
DATAL |
测试的配置字节 1 |
0x02 |
DATAH |
测试的配置字节 2 |
0x03 |
DELAY |
延迟 n * 10 毫秒,直到测试开始 |
使用 i2c-tools 包中的 'i2cset',通用命令如下所示
# i2cset -y <bus_num> <testunit_address> <CMD> <DATAL> <DATAH> <DELAY> i
DELAY 是一个通用参数,它将延迟 CMD 中测试的执行。当一个命令正在运行时(包括延迟),新的命令将不会被确认。您需要等待直到旧命令完成。
命令在以下部分中描述。无效命令将导致传输未被确认。
命令¶
0x00 NOOP¶
保留供将来使用。
0x01 READ_BYTES¶
CMD |
DATAL |
DATAH |
DELAY |
---|---|---|---|
0x01 |
从中读取数据的地址(低 7 位,最高位当前未使用) |
要读取的字节数 |
n * 10 毫秒 |
还需要主控模式。这对于测试您的总线主控驱动程序是否正确处理多主控非常有用。您可以触发测试单元从总线上的另一个设备读取字节。如果正在测试的总线主控也想同时访问总线,则总线将处于忙碌状态。示例:延迟 50 毫秒后从设备 0x50 读取 128 个字节
# i2cset -y 0 0x30 1 0x50 0x80 5 i
0x02 SMBUS_HOST_NOTIFY¶
CMD |
DATAL |
DATAH |
DELAY |
---|---|---|---|
0x02 |
要发送的状态字的低字节 |
要发送的状态字的高字节 |
n * 10 毫秒 |
还需要主控模式。此测试将向主机发送 SMBUS_HOST_NOTIFY 消息。请注意,状态字目前在 Linux 内核中被忽略。示例:延迟 10 毫秒后发送状态字 0x6442 的通知
# i2cset -y 0 0x30 2 0x42 0x64 1 i
如果主机控制器支持 HostNotify,则应显示带有调试级别的此消息(Linux 6.11 及更高版本)
Detected HostNotify from address 0x30
0x03 SMBUS_BLOCK_PROC_CALL¶
CMD |
DATAL |
DATAH |
DELAY |
---|---|---|---|
0x03 |
0x01(即,将写入另一个字节) |
要发送回的字节数 |
省略,部分命令! |
部分命令。此测试将响应 SMBus 规范定义的块进程调用。写入的一个数据字节指定在后续读取传输中将发送回多少字节。请注意,在此读取传输中,测试单元将在要跟随的字节前加上长度。因此,如果您的主机总线驱动程序像大多数驱动程序一样模拟 SMBus 调用,则它需要支持 i2c_msg 的 I2C_M_RECV_LEN 标志。这是一个很好的测试用例。返回的数据首先由长度组成,然后是由从长度 - 1 到 0 的字节数组组成。以下示例使用 i2ctransfer 模拟 i2c_smbus_block_process_call()(您需要 i2c-tools v4.2 或更高版本)
# i2ctransfer -y 0 w3@0x30 3 1 0x10 r?
0x10 0x0f 0x0e 0x0d 0x0c 0x0b 0x0a 0x09 0x08 0x07 0x06 0x05 0x04 0x03 0x02 0x01 0x00
0x04 GET_VERSION_WITH_REP_START¶
CMD |
DATAL |
DATAH |
DELAY |
---|---|---|---|
0x04 |
目前未使用 |
目前未使用 |
省略,部分命令! |
部分命令。发送此命令后,测试单元将使用基于 UTS_RELEASE 的以 NUL 结尾的版本字符串回复读取消息。第一个字符始终为“v”,版本字符串的最大长度为 128 字节。但是,仅当读取消息通过重复启动连接到写入消息时,它才会响应。如果您的控制器驱动程序正确处理重复启动,则此操作将起作用
# i2ctransfer -y 0 w3@0x30 4 0 0 r128
0x76 0x36 0x2e 0x31 0x31 0x2e 0x30 0x2d 0x72 0x63 0x31 0x2d 0x30 0x30 0x30 0x30 ...
如果您有 i2c-tools 4.4 或更高版本,则可以立即打印出数据
# i2ctransfer -y -b 0 w3@0x30 4 0 0 r128
v6.11.0-rc1-00009-gd37a1b4d3fd0
两个消息之间的 STOP/START 组合将不起作用,因为它们不等同于重复启动。例如,这仅返回默认响应
# i2cset -y 0 0x30 4 0 0 i; i2cget -y 0 0x30
0x00
0x05 SMBUS_ALERT_REQUEST¶
CMD |
DATAL |
DATAH |
DELAY |
---|---|---|---|
0x05 |
响应值(7 个最高有效位解释为 I2C 地址) |
目前未使用 |
n * 10 毫秒 |
此测试通过 SMBAlert 引脚引发中断,主机控制器必须处理该中断。该引脚必须作为 GPIO 连接到测试单元。不允许 GPIO 访问进入睡眠状态。当前,只能使用固件节点来描述这一点。因此,对于设备树,您需要将类似以下内容添加到测试单元节点
gpios = <&gpio1 24 GPIO_ACTIVE_LOW>;
以下命令将以 1 秒的延迟触发警报,响应值为 0xc9
# i2cset -y 0 0x30 5 0xc9 0x00 100 i
如果主机控制器支持 SMBusAlert,则应显示带有调试级别的此消息
smbus_alert 0-000c: SMBALERT# from dev 0x64, flag 1
此消息可能会出现多次,因为测试单元是软件而不是硬件,因此可能无法足够快地响应主机的响应。但是,中断计数应仅增加 1
# cat /proc/interrupts | grep smbus_alert
93: 1 gpio-rcar 26 Edge smbus_alert
如果主机未在 1 秒内响应警报,则测试将中止,并且测试单元将报告错误。
对于此测试,测试单元将短暂地删除其分配的地址,并在 SMBus 警报响应地址 (0x0c) 上进行侦听。之后,它将重新分配其原始地址。