Commit 209d27c3 authored by Jean Delvare's avatar Jean Delvare Committed by Jean Delvare

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: default avatarJean Delvare <khali@linux-fr.org>
parent 1ecac07a
...@@ -590,8 +590,9 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num) ...@@ -590,8 +590,9 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
#ifdef DEBUG #ifdef DEBUG
for (ret = 0; ret < num; ret++) { for (ret = 0; ret < num; ret++) {
dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, " dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
"len=%d\n", ret, msgs[ret].flags & I2C_M_RD ? "len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
'R' : 'W', msgs[ret].addr, msgs[ret].len); ? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
(msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
} }
#endif #endif
...@@ -1050,9 +1051,9 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, ...@@ -1050,9 +1051,9 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
break; break;
case I2C_SMBUS_BLOCK_DATA: case I2C_SMBUS_BLOCK_DATA:
if (read_write == I2C_SMBUS_READ) { if (read_write == I2C_SMBUS_READ) {
dev_err(&adapter->dev, "Block read not supported " msg[1].flags |= I2C_M_RECV_LEN;
"under I2C emulation!\n"); msg[1].len = 1; /* block length will be added by
return -1; the underlying bus driver */
} else { } else {
msg[0].len = data->block[0] + 2; msg[0].len = data->block[0] + 2;
if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 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, ...@@ -1066,9 +1067,21 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
} }
break; break;
case I2C_SMBUS_BLOCK_PROC_CALL: case I2C_SMBUS_BLOCK_PROC_CALL:
dev_dbg(&adapter->dev, "Block process call not supported " num = 2; /* Another special case */
"under I2C emulation!\n"); 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; 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: case I2C_SMBUS_I2C_BLOCK_DATA:
if (read_write == I2C_SMBUS_READ) { if (read_write == I2C_SMBUS_READ) {
msg[1].len = I2C_SMBUS_BLOCK_MAX; msg[1].len = I2C_SMBUS_BLOCK_MAX;
...@@ -1132,6 +1145,11 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, ...@@ -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++) for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++)
data->block[i+1] = msgbuf1[i]; data->block[i+1] = msgbuf1[i];
break; 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; return 0;
} }
......
...@@ -366,6 +366,7 @@ struct i2c_msg { ...@@ -366,6 +366,7 @@ struct i2c_msg {
#define I2C_M_REV_DIR_ADDR 0x2000 #define I2C_M_REV_DIR_ADDR 0x2000
#define I2C_M_IGNORE_NAK 0x1000 #define I2C_M_IGNORE_NAK 0x1000
#define I2C_M_NO_RD_ACK 0x0800 #define I2C_M_NO_RD_ACK 0x0800
#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
__u16 len; /* msg length */ __u16 len; /* msg length */
__u8 *buf; /* pointer to msg data */ __u8 *buf; /* pointer to msg data */
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment