mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	i2c: Emulate SMBus block read over I2C
Let the I2C bus drivers emulate the SMBus Block Read and Block Process Call transactions if they wish. This requires to define a new message flag, which i2c-core will use to let the underlying I2C bus driver know that the first received byte will specify the length of the read message. Signed-off-by: Jean Delvare <khali@linux-fr.org>
This commit is contained in:
		
							parent
							
								
									1ecac07aba
								
							
						
					
					
						commit
						209d27c3b1
					
				
					 2 changed files with 27 additions and 8 deletions
				
			
		| 
						 | 
				
			
			@ -590,8 +590,9 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
 | 
			
		|||
#ifdef DEBUG
 | 
			
		||||
		for (ret = 0; ret < num; ret++) {
 | 
			
		||||
			dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
 | 
			
		||||
				"len=%d\n", ret, msgs[ret].flags & I2C_M_RD ?
 | 
			
		||||
				'R' : 'W', msgs[ret].addr, msgs[ret].len);
 | 
			
		||||
				"len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
 | 
			
		||||
				? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
 | 
			
		||||
				(msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
 | 
			
		||||
		}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1050,9 +1051,9 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
 | 
			
		|||
		break;
 | 
			
		||||
	case I2C_SMBUS_BLOCK_DATA:
 | 
			
		||||
		if (read_write == I2C_SMBUS_READ) {
 | 
			
		||||
			dev_err(&adapter->dev, "Block read not supported "
 | 
			
		||||
			       "under I2C emulation!\n");
 | 
			
		||||
			return -1;
 | 
			
		||||
			msg[1].flags |= I2C_M_RECV_LEN;
 | 
			
		||||
			msg[1].len = 1; /* block length will be added by
 | 
			
		||||
					   the underlying bus driver */
 | 
			
		||||
		} else {
 | 
			
		||||
			msg[0].len = data->block[0] + 2;
 | 
			
		||||
			if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1066,9 +1067,21 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
 | 
			
		|||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	case I2C_SMBUS_BLOCK_PROC_CALL:
 | 
			
		||||
		dev_dbg(&adapter->dev, "Block process call not supported "
 | 
			
		||||
		       "under I2C emulation!\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
		num = 2; /* Another special case */
 | 
			
		||||
		read_write = I2C_SMBUS_READ;
 | 
			
		||||
		if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
 | 
			
		||||
			dev_err(&adapter->dev, "%s called with invalid "
 | 
			
		||||
				"block proc call size (%d)\n", __FUNCTION__,
 | 
			
		||||
				data->block[0]);
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		msg[0].len = data->block[0] + 2;
 | 
			
		||||
		for (i = 1; i < msg[0].len; i++)
 | 
			
		||||
			msgbuf0[i] = data->block[i-1];
 | 
			
		||||
		msg[1].flags |= I2C_M_RECV_LEN;
 | 
			
		||||
		msg[1].len = 1; /* block length will be added by
 | 
			
		||||
				   the underlying bus driver */
 | 
			
		||||
		break;
 | 
			
		||||
	case I2C_SMBUS_I2C_BLOCK_DATA:
 | 
			
		||||
		if (read_write == I2C_SMBUS_READ) {
 | 
			
		||||
			msg[1].len = I2C_SMBUS_BLOCK_MAX;
 | 
			
		||||
| 
						 | 
				
			
			@ -1132,6 +1145,11 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
 | 
			
		|||
				for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++)
 | 
			
		||||
					data->block[i+1] = msgbuf1[i];
 | 
			
		||||
				break;
 | 
			
		||||
			case I2C_SMBUS_BLOCK_DATA:
 | 
			
		||||
			case I2C_SMBUS_BLOCK_PROC_CALL:
 | 
			
		||||
				for (i = 0; i < msgbuf1[0] + 1; i++)
 | 
			
		||||
					data->block[i] = msgbuf1[i];
 | 
			
		||||
				break;
 | 
			
		||||
		}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -366,6 +366,7 @@ struct i2c_msg {
 | 
			
		|||
#define I2C_M_REV_DIR_ADDR	0x2000
 | 
			
		||||
#define I2C_M_IGNORE_NAK	0x1000
 | 
			
		||||
#define I2C_M_NO_RD_ACK		0x0800
 | 
			
		||||
#define I2C_M_RECV_LEN		0x0400 /* length will be first received byte */
 | 
			
		||||
	__u16 len;		/* msg length				*/
 | 
			
		||||
	__u8 *buf;		/* pointer to msg data			*/
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue