mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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>
This commit is contained in:
		
							parent
							
								
									bb3fe9ff53
								
							
						
					
					
						commit
						b39ab96aa8
					
				
					 2 changed files with 31 additions and 4 deletions
				
			
		| 
						 | 
					@ -22,8 +22,9 @@ Instantiating the device is regular. Example for bus 0, address 0x30:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
After that, you will have a write-only device listening. Reads will just return
 | 
					After that, you will have a write-only device listening. Reads will just return
 | 
				
			||||||
an 8-bit version number of the testunit. When writing, the device consists of 4
 | 
					an 8-bit version number of the testunit. When writing, the device consists of 4
 | 
				
			||||||
8-bit registers and all must be written to start a testcase, i.e. you must
 | 
					8-bit registers and, except for some "partial" commands, all registers must be
 | 
				
			||||||
always write 4 bytes to the device. The registers are:
 | 
					written to start a testcase, i.e. you usually write 4 bytes to the device. The
 | 
				
			||||||
 | 
					registers are:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
0x00 CMD   - which test to trigger
 | 
					0x00 CMD   - which test to trigger
 | 
				
			||||||
0x01 DATAL - configuration byte 1 for the test
 | 
					0x01 DATAL - configuration byte 1 for the test
 | 
				
			||||||
| 
						 | 
					@ -67,3 +68,21 @@ status word is currently ignored in the Linux Kernel. Example to send a
 | 
				
			||||||
notification after 10ms:
 | 
					notification after 10ms:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# i2cset -y 0 0x30 0x02 0x42 0x64 0x01 i
 | 
					# i2cset -y 0 0x30 0x02 0x42 0x64 0x01 i
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					0x03 SMBUS_BLOCK_PROC_CALL (partial command)
 | 
				
			||||||
 | 
					   DATAL - must be '1', i.e. one further byte will be written
 | 
				
			||||||
 | 
					   DATAH - number of bytes to be sent back
 | 
				
			||||||
 | 
					   DELAY - not applicable, partial command!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This test will respond to a block process call as defined by the SMBus
 | 
				
			||||||
 | 
					specification. The one data byte written specifies how many bytes will be sent
 | 
				
			||||||
 | 
					back in the following read transfer. Note that in this read transfer, the
 | 
				
			||||||
 | 
					testunit will prefix the length of the bytes to follow. So, if your host bus
 | 
				
			||||||
 | 
					driver emulates SMBus calls like the majority does, it needs to support the
 | 
				
			||||||
 | 
					I2C_M_RECV_LEN flag of an i2c_msg. This is a good testcase for it. The returned
 | 
				
			||||||
 | 
					data consists of the length first, and then of an array of bytes from length-1
 | 
				
			||||||
 | 
					to 0. Here is an example which emulates i2c_smbus_block_process_call() using
 | 
				
			||||||
 | 
					i2ctransfer (you need i2c-tools v4.2 or later):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# i2ctransfer -y 0 w3@0x30 0x03 0x01 0x10 r?
 | 
				
			||||||
 | 
					0x10 0x0f 0x0e 0x0d 0x0c 0x0b 0x0a 0x09 0x08 0x07 0x06 0x05 0x04 0x03 0x02 0x01 0x00
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,6 +19,7 @@
 | 
				
			||||||
enum testunit_cmds {
 | 
					enum testunit_cmds {
 | 
				
			||||||
	TU_CMD_READ_BYTES = 1,	/* save 0 for ABORT, RESET or similar */
 | 
						TU_CMD_READ_BYTES = 1,	/* save 0 for ABORT, RESET or similar */
 | 
				
			||||||
	TU_CMD_HOST_NOTIFY,
 | 
						TU_CMD_HOST_NOTIFY,
 | 
				
			||||||
 | 
						TU_CMD_SMBUS_BLOCK_PROC_CALL,
 | 
				
			||||||
	TU_NUM_CMDS
 | 
						TU_NUM_CMDS
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -88,6 +89,8 @@ static int i2c_slave_testunit_slave_cb(struct i2c_client *client,
 | 
				
			||||||
				     enum i2c_slave_event event, u8 *val)
 | 
									     enum i2c_slave_event event, u8 *val)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct testunit_data *tu = i2c_get_clientdata(client);
 | 
						struct testunit_data *tu = i2c_get_clientdata(client);
 | 
				
			||||||
 | 
						bool is_proc_call = tu->reg_idx == 3 && tu->regs[TU_REG_DATAL] == 1 &&
 | 
				
			||||||
 | 
								    tu->regs[TU_REG_CMD] == TU_CMD_SMBUS_BLOCK_PROC_CALL;
 | 
				
			||||||
	int ret = 0;
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (event) {
 | 
						switch (event) {
 | 
				
			||||||
| 
						 | 
					@ -118,12 +121,17 @@ static int i2c_slave_testunit_slave_cb(struct i2c_client *client,
 | 
				
			||||||
		fallthrough;
 | 
							fallthrough;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case I2C_SLAVE_WRITE_REQUESTED:
 | 
						case I2C_SLAVE_WRITE_REQUESTED:
 | 
				
			||||||
 | 
							memset(tu->regs, 0, TU_NUM_REGS);
 | 
				
			||||||
		tu->reg_idx = 0;
 | 
							tu->reg_idx = 0;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case I2C_SLAVE_READ_REQUESTED:
 | 
					 | 
				
			||||||
	case I2C_SLAVE_READ_PROCESSED:
 | 
						case I2C_SLAVE_READ_PROCESSED:
 | 
				
			||||||
		*val = TU_CUR_VERSION;
 | 
							if (is_proc_call && tu->regs[TU_REG_DATAH])
 | 
				
			||||||
 | 
								tu->regs[TU_REG_DATAH]--;
 | 
				
			||||||
 | 
							fallthrough;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case I2C_SLAVE_READ_REQUESTED:
 | 
				
			||||||
 | 
							*val = is_proc_call ? tu->regs[TU_REG_DATAH] : TU_CUR_VERSION;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue