diff options
author | Jean Delvare <khali@linux-fr.org> | 2007-05-01 17:26:29 -0400 |
---|---|---|
committer | Jean Delvare <khali@hyperion.delvare> | 2007-05-01 17:26:29 -0400 |
commit | 209d27c3b1676c0497108f0642c51a08b98a7856 (patch) | |
tree | 434c063c4bd163ff242ae8a18bf65701bb6d39e6 | |
parent | 1ecac07abaca1a4084d0259d4a15b55188852a2e (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.c | 34 | ||||
-rw-r--r-- | include/linux/i2c.h | 1 |
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 | }; |