| From c6ebcedbab7ca78984959386012a17b21183e1a3 Mon Sep 17 00:00:00 2001 |
| From: Pontus Andersson <epontan@gmail.com> |
| Date: Mon, 2 Oct 2017 14:45:19 +0200 |
| Subject: i2c: ismt: Separate I2C block read from SMBus block read |
| |
| From: Pontus Andersson <epontan@gmail.com> |
| |
| commit c6ebcedbab7ca78984959386012a17b21183e1a3 upstream. |
| |
| Commit b6c159a9cb69 ("i2c: ismt: Don't duplicate the receive length for |
| block reads") broke I2C block reads. It aimed to fix normal SMBus block |
| read, but changed the correct behavior of I2C block read in the process. |
| |
| According to Documentation/i2c/smbus-protocol, one vital difference |
| between normal SMBus block read and I2C block read is that there is no |
| byte count prefixed in the data sent on the wire: |
| |
| SMBus Block Read: i2c_smbus_read_block_data() |
| S Addr Wr [A] Comm [A] |
| S Addr Rd [A] [Count] A [Data] A [Data] A ... A [Data] NA P |
| |
| I2C Block Read: i2c_smbus_read_i2c_block_data() |
| S Addr Wr [A] Comm [A] |
| S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P |
| |
| Therefore the two transaction types need to be processed differently in |
| the driver by copying of the dma_buffer as done previously for the |
| I2C_SMBUS_I2C_BLOCK_DATA case. |
| |
| Fixes: b6c159a9cb69 ("i2c: ismt: Don't duplicate the receive length for block reads") |
| Signed-off-by: Pontus Andersson <epontan@gmail.com> |
| Tested-by: Stephen Douthit <stephend@adiengineering.com> |
| Signed-off-by: Wolfram Sang <wsa@the-dreams.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/i2c/busses/i2c-ismt.c | 5 ++++- |
| 1 file changed, 4 insertions(+), 1 deletion(-) |
| |
| --- a/drivers/i2c/busses/i2c-ismt.c |
| +++ b/drivers/i2c/busses/i2c-ismt.c |
| @@ -339,12 +339,15 @@ static int ismt_process_desc(const struc |
| data->word = dma_buffer[0] | (dma_buffer[1] << 8); |
| break; |
| case I2C_SMBUS_BLOCK_DATA: |
| - case I2C_SMBUS_I2C_BLOCK_DATA: |
| if (desc->rxbytes != dma_buffer[0] + 1) |
| return -EMSGSIZE; |
| |
| memcpy(data->block, dma_buffer, desc->rxbytes); |
| break; |
| + case I2C_SMBUS_I2C_BLOCK_DATA: |
| + memcpy(&data->block[1], dma_buffer, desc->rxbytes); |
| + data->block[0] = desc->rxbytes; |
| + break; |
| } |
| return 0; |
| } |