[linux-yocto] [PATCH 02/39] i2c-axxia: Fix broken smbus block read

Charlie Paul cpaul.windriver at gmail.com
Fri Apr 11 14:13:03 PDT 2014


From: Anders Berg <anders.berg at lsi.com>

Changed the initial transfer size on block reads from 1 to I2C_SMBUS_BLOCK_MAX.
The size is adjusted when the first byte (block length) is received. Having the
initial size set to 1 could cause the controller to stop the transfter after
the block length byte, if the transfter length register wasn't updated in time.

Signed-off-by: Anders Berg <anders.berg at lsi.com>
---
 drivers/i2c/busses/i2c-axxia.c |   20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/drivers/i2c/busses/i2c-axxia.c b/drivers/i2c/busses/i2c-axxia.c
index e0a4b24..a46d2d3 100644
--- a/drivers/i2c/busses/i2c-axxia.c
+++ b/drivers/i2c/busses/i2c-axxia.c
@@ -260,15 +260,18 @@ axxia_i2c_empty_rx_fifo(struct axxia_i2c_dev *idev)
 	while (0 < bytes_to_transfer--) {
 		int c = readl(&idev->regs->mst_data);
 		if (idev->msg_xfrd == 0 && i2c_m_recv_len(msg)) {
-			if (c == 0 || c > I2C_SMBUS_BLOCK_MAX) {
+			/*
+			 * Check length byte for SMBus block read
+			 */
+			if (c <= 0) {
 				idev->msg_err = -EPROTO;
 				i2c_int_disable(idev, ~0);
-				dev_err(idev->dev,
-					"invalid SMBus block size (%d)\n", c);
 				complete(&idev->msg_complete);
 				break;
+			} else if (c > I2C_SMBUS_BLOCK_MAX) {
+				c = I2C_SMBUS_BLOCK_MAX;
 			}
-			msg->len += c;
+			msg->len = 1 + c;
 			writel(msg->len, &idev->regs->mst_rx_xfer);
 		}
 		msg->buf[idev->msg_xfrd++] = c;
@@ -330,7 +333,7 @@ axxia_i2c_isr(int irq, void *_dev)
 	if (unlikely(status & MST_STATUS_ERR)) {
 		idev->msg_err = status & MST_STATUS_ERR;
 		i2c_int_disable(idev, ~0);
-		dev_err(idev->dev, "error %s, rx=%u/%u tx=%u/%u\n",
+		dev_dbg(idev->dev, "error %s, rx=%u/%u tx=%u/%u\n",
 			status_str(idev->msg_err),
 			readl(&idev->regs->mst_rx_bytes_xfrd),
 			readl(&idev->regs->mst_rx_xfer),
@@ -389,7 +392,10 @@ axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
 		/* TX 0 bytes */
 		writel(0, &idev->regs->mst_tx_xfer);
 		/* RX # bytes */
-		writel(msg->len, &idev->regs->mst_rx_xfer);
+		if (i2c_m_recv_len(msg))
+			writel(I2C_SMBUS_BLOCK_MAX, &idev->regs->mst_rx_xfer);
+		else
+			writel(msg->len, &idev->regs->mst_rx_xfer);
 		/* Chip address for write */
 		writel(CHIP_READ(msg->addr), &idev->regs->mst_addr_1);
 	} else {
@@ -421,7 +427,7 @@ axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
 
 	WARN_ON(readl(&idev->regs->mst_command) & 0x8);
 
-	if (WARN_ON(ret == 0)) {
+	if (ret == 0) {
 		dev_warn(idev->dev, "xfer timeout (%#x)\n", msg->addr);
 		axxia_i2c_init(idev);
 		return -ETIMEDOUT;
-- 
1.7.9.5



More information about the linux-yocto mailing list