mirror of https://gitee.com/openkylin/linux.git
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
|
@ -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");
|
||||
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 New Issue