summaryrefslogtreecommitdiff
path: root/drivers/i2c/busses/i2c-imx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c/busses/i2c-imx.c')
-rw-r--r--drivers/i2c/busses/i2c-imx.c31
1 files changed, 28 insertions, 3 deletions
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index dc5aff8cdc7c..4ed74f303681 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -371,6 +371,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
{
int i, result;
unsigned int temp;
+ int block_data = msgs->flags & I2C_M_RECV_LEN;
dev_dbg(&i2c_imx->adapter.dev,
"<%s> write slave address: addr=0x%x\n",
@@ -390,7 +391,12 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
/* setup bus to read data */
temp = readb(i2c_imx->base + IMX_I2C_I2CR);
temp &= ~I2CR_MTX;
- if (msgs->len - 1)
+
+ /*
+ * Reset the I2CR_TXAK flag initially for SMBus block read since the
+ * length is unknown
+ */
+ if ((msgs->len - 1) || block_data)
temp &= ~I2CR_TXAK;
writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
readb(i2c_imx->base + IMX_I2C_I2DR); /* dummy read */
@@ -399,9 +405,24 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
/* read data */
for (i = 0; i < msgs->len; i++) {
+ u8 len = 0;
result = i2c_imx_trx_complete(i2c_imx);
if (result)
return result;
+ /*
+ * First byte is the length of remaining packet
+ * in the SMBus block data read. Add it to
+ * msgs->len.
+ */
+ if ((!i) && block_data) {
+ len = readb(i2c_imx->base + IMX_I2C_I2DR);
+ if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX))
+ return -EPROTO;
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<%s> read length: 0x%X\n",
+ __func__, len);
+ msgs->len += len;
+ }
if (i == (msgs->len - 1)) {
/* It must generate STOP before read I2DR to prevent
controller from generating another clock cycle */
@@ -419,7 +440,10 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
temp |= I2CR_TXAK;
writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
}
- msgs->buf[i] = readb(i2c_imx->base + IMX_I2C_I2DR);
+ if ((!i) && block_data)
+ msgs->buf[0] = len;
+ else
+ msgs->buf[i] = readb(i2c_imx->base + IMX_I2C_I2DR);
dev_dbg(&i2c_imx->adapter.dev,
"<%s> read byte: B%d=0x%X\n",
__func__, i, msgs->buf[i]);
@@ -502,7 +526,8 @@ fail0:
static u32 i2c_imx_func(struct i2c_adapter *adapter)
{
- return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
+ | I2C_FUNC_SMBUS_READ_BLOCK_DATA;
}
static struct i2c_algorithm i2c_imx_algo = {