aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJean Delvare <khali@linux-fr.org>2007-05-01 17:26:29 -0400
committerJean Delvare <khali@hyperion.delvare>2007-05-01 17:26:29 -0400
commit209d27c3b1676c0497108f0642c51a08b98a7856 (patch)
tree434c063c4bd163ff242ae8a18bf65701bb6d39e6
parent1ecac07abaca1a4084d0259d4a15b55188852a2e (diff)
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>
-rw-r--r--drivers/i2c/i2c-core.c34
-rw-r--r--include/linux/i2c.h1
2 files changed, 27 insertions, 8 deletions
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index ae07b874a5d7..fd921ce0b75b 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -590,8 +590,9 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
590#ifdef DEBUG 590#ifdef DEBUG
591 for (ret = 0; ret < num; ret++) { 591 for (ret = 0; ret < num; ret++) {
592 dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, " 592 dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
593 "len=%d\n", ret, msgs[ret].flags & I2C_M_RD ? 593 "len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
594 'R' : 'W', msgs[ret].addr, msgs[ret].len); 594 ? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
595 (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
595 } 596 }
596#endif 597#endif
597 598
@@ -1050,9 +1051,9 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
1050 break; 1051 break;
1051 case I2C_SMBUS_BLOCK_DATA: 1052 case I2C_SMBUS_BLOCK_DATA:
1052 if (read_write == I2C_SMBUS_READ) { 1053 if (read_write == I2C_SMBUS_READ) {
1053 dev_err(&adapter->dev, "Block read not supported " 1054 msg[1].flags |= I2C_M_RECV_LEN;
1054 "under I2C emulation!\n"); 1055 msg[1].len = 1; /* block length will be added by
1055 return -1; 1056 the underlying bus driver */
1056 } else { 1057 } else {
1057 msg[0].len = data->block[0] + 2; 1058 msg[0].len = data->block[0] + 2;
1058 if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) { 1059 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 } 1067 }
1067 break; 1068 break;
1068 case I2C_SMBUS_BLOCK_PROC_CALL: 1069 case I2C_SMBUS_BLOCK_PROC_CALL:
1069 dev_dbg(&adapter->dev, "Block process call not supported " 1070 num = 2; /* Another special case */
1070 "under I2C emulation!\n"); 1071 read_write = I2C_SMBUS_READ;
1071 return -1; 1072 if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
1073 dev_err(&adapter->dev, "%s called with invalid "
1074 "block proc call size (%d)\n", __FUNCTION__,
1075 data->block[0]);
1076 return -1;
1077 }
1078 msg[0].len = data->block[0] + 2;
1079 for (i = 1; i < msg[0].len; i++)
1080 msgbuf0[i] = data->block[i-1];
1081 msg[1].flags |= I2C_M_RECV_LEN;
1082 msg[1].len = 1; /* block length will be added by
1083 the underlying bus driver */
1084 break;
1072 case I2C_SMBUS_I2C_BLOCK_DATA: 1085 case I2C_SMBUS_I2C_BLOCK_DATA:
1073 if (read_write == I2C_SMBUS_READ) { 1086 if (read_write == I2C_SMBUS_READ) {
1074 msg[1].len = I2C_SMBUS_BLOCK_MAX; 1087 msg[1].len = I2C_SMBUS_BLOCK_MAX;
@@ -1132,6 +1145,11 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
1132 for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++) 1145 for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++)
1133 data->block[i+1] = msgbuf1[i]; 1146 data->block[i+1] = msgbuf1[i];
1134 break; 1147 break;
1148 case I2C_SMBUS_BLOCK_DATA:
1149 case I2C_SMBUS_BLOCK_PROC_CALL:
1150 for (i = 0; i < msgbuf1[0] + 1; i++)
1151 data->block[i] = msgbuf1[i];
1152 break;
1135 } 1153 }
1136 return 0; 1154 return 0;
1137} 1155}
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 568dd1007b53..563c9651dd37 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -366,6 +366,7 @@ struct i2c_msg {
366#define I2C_M_REV_DIR_ADDR 0x2000 366#define I2C_M_REV_DIR_ADDR 0x2000
367#define I2C_M_IGNORE_NAK 0x1000 367#define I2C_M_IGNORE_NAK 0x1000
368#define I2C_M_NO_RD_ACK 0x0800 368#define I2C_M_NO_RD_ACK 0x0800
369#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
369 __u16 len; /* msg length */ 370 __u16 len; /* msg length */
370 __u8 *buf; /* pointer to msg data */ 371 __u8 *buf; /* pointer to msg data */
371}; 372};