Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

i2c: testunit: add support for block process calls

Devices offering SMBus block process calls are rare, so add it to the
testunit. This is also a good test case for testing proper
I2C_M_RECV_LEN flag handling of I2C bus masters emulating SMBus.

Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Wolfram Sang <wsa@kernel.org>

authored by

Wolfram Sang and committed by
Wolfram Sang
b39ab96a bb3fe9ff

+31 -4
+21 -2
Documentation/i2c/slave-testunit-backend.rst
··· 22 22 23 23 After that, you will have a write-only device listening. Reads will just return 24 24 an 8-bit version number of the testunit. When writing, the device consists of 4 25 - 8-bit registers and all must be written to start a testcase, i.e. you must 26 - always write 4 bytes to the device. The registers are: 25 + 8-bit registers and, except for some "partial" commands, all registers must be 26 + written to start a testcase, i.e. you usually write 4 bytes to the device. The 27 + registers are: 27 28 28 29 0x00 CMD - which test to trigger 29 30 0x01 DATAL - configuration byte 1 for the test ··· 68 67 notification after 10ms: 69 68 70 69 # i2cset -y 0 0x30 0x02 0x42 0x64 0x01 i 70 + 71 + 0x03 SMBUS_BLOCK_PROC_CALL (partial command) 72 + DATAL - must be '1', i.e. one further byte will be written 73 + DATAH - number of bytes to be sent back 74 + DELAY - not applicable, partial command! 75 + 76 + This test will respond to a block process call as defined by the SMBus 77 + specification. The one data byte written specifies how many bytes will be sent 78 + back in the following read transfer. Note that in this read transfer, the 79 + testunit will prefix the length of the bytes to follow. So, if your host bus 80 + driver emulates SMBus calls like the majority does, it needs to support the 81 + I2C_M_RECV_LEN flag of an i2c_msg. This is a good testcase for it. The returned 82 + data consists of the length first, and then of an array of bytes from length-1 83 + to 0. Here is an example which emulates i2c_smbus_block_process_call() using 84 + i2ctransfer (you need i2c-tools v4.2 or later): 85 + 86 + # i2ctransfer -y 0 w3@0x30 0x03 0x01 0x10 r? 87 + 0x10 0x0f 0x0e 0x0d 0x0c 0x0b 0x0a 0x09 0x08 0x07 0x06 0x05 0x04 0x03 0x02 0x01 0x00
+10 -2
drivers/i2c/i2c-slave-testunit.c
··· 19 19 enum testunit_cmds { 20 20 TU_CMD_READ_BYTES = 1, /* save 0 for ABORT, RESET or similar */ 21 21 TU_CMD_HOST_NOTIFY, 22 + TU_CMD_SMBUS_BLOCK_PROC_CALL, 22 23 TU_NUM_CMDS 23 24 }; 24 25 ··· 89 88 enum i2c_slave_event event, u8 *val) 90 89 { 91 90 struct testunit_data *tu = i2c_get_clientdata(client); 91 + bool is_proc_call = tu->reg_idx == 3 && tu->regs[TU_REG_DATAL] == 1 && 92 + tu->regs[TU_REG_CMD] == TU_CMD_SMBUS_BLOCK_PROC_CALL; 92 93 int ret = 0; 93 94 94 95 switch (event) { ··· 121 118 fallthrough; 122 119 123 120 case I2C_SLAVE_WRITE_REQUESTED: 121 + memset(tu->regs, 0, TU_NUM_REGS); 124 122 tu->reg_idx = 0; 125 123 break; 126 124 127 - case I2C_SLAVE_READ_REQUESTED: 128 125 case I2C_SLAVE_READ_PROCESSED: 129 - *val = TU_CUR_VERSION; 126 + if (is_proc_call && tu->regs[TU_REG_DATAH]) 127 + tu->regs[TU_REG_DATAH]--; 128 + fallthrough; 129 + 130 + case I2C_SLAVE_READ_REQUESTED: 131 + *val = is_proc_call ? tu->regs[TU_REG_DATAH] : TU_CUR_VERSION; 130 132 break; 131 133 } 132 134