[U-Boot] [PATCH V2 4/4] lpi2c: Add bus busy error handling

Peng Fan peng.fan at nxp.com
Sun Jul 8 03:46:43 UTC 2018


From: Ye Li <ye.li at nxp.com>

When doing "i2c dev 4; i2c probe" with ENET daughter card connected
on iMX8QXP MEK board, we met a i2c bus busy issue, that the BBF of
lpi2c always show busy, but the master is idle, and stop is detected
(SDF set).

This patch addes a handling to re-init the lpi2c master for this
case. Then the issue can be worked around.

Signed-off-by: Ye Li <ye.li at nxp.com>
Acked-by: Peng Fan <peng.fan at nxp.com>
Reviewed-by: Heiko Schocher <hs at denx.de>
---

V2: Add review tag.
Heiko, I have no idea why the busy show, from the bus, we measured it
is idle, but the controller bit shows busy. We followed Linux kernel's
method to reinit the bus and all works.

 drivers/i2c/imx_lpi2c.c | 53 +++++++++++++++++++++++++++++--------------------
 1 file changed, 32 insertions(+), 21 deletions(-)

diff --git a/drivers/i2c/imx_lpi2c.c b/drivers/i2c/imx_lpi2c.c
index 585787a35c..ff07ca34aa 100644
--- a/drivers/i2c/imx_lpi2c.c
+++ b/drivers/i2c/imx_lpi2c.c
@@ -18,6 +18,8 @@
 #define LPI2C_NACK_TOUT_MS 1
 #define LPI2C_TIMEOUT_MS 100
 
+static int bus_i2c_init(struct udevice *bus, int speed);
+
 /* Weak linked function for overridden by some SoC power function */
 int __weak init_i2c_power(unsigned i2c_num)
 {
@@ -91,8 +93,9 @@ static int bus_i2c_wait_for_tx_ready(struct imx_lpi2c_reg *regs)
 	return result;
 }
 
-static int bus_i2c_send(struct imx_lpi2c_reg *regs, u8 *txbuf, int len)
+static int bus_i2c_send(struct udevice *bus, u8 *txbuf, int len)
 {
+	struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)devfdt_get_addr(bus);
 	lpi2c_status_t result = LPI2C_SUCESS;
 
 	/* empty tx */
@@ -111,8 +114,9 @@ static int bus_i2c_send(struct imx_lpi2c_reg *regs, u8 *txbuf, int len)
 	return result;
 }
 
-static int bus_i2c_receive(struct imx_lpi2c_reg *regs, u8 *rxbuf, int len)
+static int bus_i2c_receive(struct udevice *bus, u8 *rxbuf, int len)
 {
+	struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)devfdt_get_addr(bus);
 	lpi2c_status_t result = LPI2C_SUCESS;
 	u32 val;
 	ulong start_time = get_timer(0);
@@ -153,15 +157,24 @@ static int bus_i2c_receive(struct imx_lpi2c_reg *regs, u8 *rxbuf, int len)
 	return result;
 }
 
-static int bus_i2c_start(struct imx_lpi2c_reg *regs, u8 addr, u8 dir)
+static int bus_i2c_start(struct udevice *bus, u8 addr, u8 dir)
 {
 	lpi2c_status_t result;
+	struct imx_lpi2c_reg *regs =
+		(struct imx_lpi2c_reg *)devfdt_get_addr(bus);
 	u32 val;
 
 	result = imx_lpci2c_check_busy_bus(regs);
 	if (result) {
 		debug("i2c: start check busy bus: 0x%x\n", result);
-		return result;
+
+		/* Try to init the lpi2c then check the bus busy again */
+		bus_i2c_init(bus, 100000);
+		result = imx_lpci2c_check_busy_bus(regs);
+		if (result) {
+			printf("i2c: Error check busy bus: 0x%x\n", result);
+			return result;
+		}
 	}
 	/* clear all status flags */
 	writel(0x7f00, &regs->msr);
@@ -181,9 +194,11 @@ static int bus_i2c_start(struct imx_lpi2c_reg *regs, u8 addr, u8 dir)
 	return result;
 }
 
-static int bus_i2c_stop(struct imx_lpi2c_reg *regs)
+static int bus_i2c_stop(struct udevice *bus)
 {
 	lpi2c_status_t result;
+	struct imx_lpi2c_reg *regs =
+		(struct imx_lpi2c_reg *)devfdt_get_addr(bus);
 	u32 status;
 	ulong start_time;
 
@@ -217,28 +232,28 @@ static int bus_i2c_stop(struct imx_lpi2c_reg *regs)
 	return result;
 }
 
-static int bus_i2c_read(struct imx_lpi2c_reg *regs, u32 chip, u8 *buf, int len)
+static int bus_i2c_read(struct udevice *bus, u32 chip, u8 *buf, int len)
 {
 	lpi2c_status_t result;
 
-	result = bus_i2c_start(regs, chip, 1);
+	result = bus_i2c_start(bus, chip, 1);
 	if (result)
 		return result;
-	result = bus_i2c_receive(regs, buf, len);
+	result = bus_i2c_receive(bus, buf, len);
 	if (result)
 		return result;
 
 	return result;
 }
 
-static int bus_i2c_write(struct imx_lpi2c_reg *regs, u32 chip, u8 *buf, int len)
+static int bus_i2c_write(struct udevice *bus, u32 chip, u8 *buf, int len)
 {
 	lpi2c_status_t result;
 
-	result = bus_i2c_start(regs, chip, 0);
+	result = bus_i2c_start(bus, chip, 0);
 	if (result)
 		return result;
-	result = bus_i2c_send(regs, buf, len);
+	result = bus_i2c_send(bus, buf, len);
 	if (result)
 		return result;
 
@@ -353,18 +368,16 @@ static int bus_i2c_init(struct udevice *bus, int speed)
 static int imx_lpi2c_probe_chip(struct udevice *bus, u32 chip,
 				u32 chip_flags)
 {
-	struct imx_lpi2c_reg *regs;
 	lpi2c_status_t result;
 
-	regs = (struct imx_lpi2c_reg *)devfdt_get_addr(bus);
-	result = bus_i2c_start(regs, chip, 0);
+	result = bus_i2c_start(bus, chip, 0);
 	if (result) {
-		bus_i2c_stop(regs);
+		bus_i2c_stop(bus);
 		bus_i2c_init(bus, 100000);
 		return result;
 	}
 
-	result = bus_i2c_stop(regs);
+	result = bus_i2c_stop(bus);
 	if (result)
 		bus_i2c_init(bus, 100000);
 
@@ -373,16 +386,14 @@ static int imx_lpi2c_probe_chip(struct udevice *bus, u32 chip,
 
 static int imx_lpi2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
 {
-	struct imx_lpi2c_reg *regs;
 	int ret = 0, ret_stop;
 
-	regs = (struct imx_lpi2c_reg *)devfdt_get_addr(bus);
 	for (; nmsgs > 0; nmsgs--, msg++) {
 		debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
 		if (msg->flags & I2C_M_RD)
-			ret = bus_i2c_read(regs, msg->addr, msg->buf, msg->len);
+			ret = bus_i2c_read(bus, msg->addr, msg->buf, msg->len);
 		else {
-			ret = bus_i2c_write(regs, msg->addr, msg->buf,
+			ret = bus_i2c_write(bus, msg->addr, msg->buf,
 					    msg->len);
 			if (ret)
 				break;
@@ -392,7 +403,7 @@ static int imx_lpi2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
 	if (ret)
 		debug("i2c_write: error sending\n");
 
-	ret_stop = bus_i2c_stop(regs);
+	ret_stop = bus_i2c_stop(bus);
 	if (ret_stop)
 		debug("i2c_xfer: stop bus error\n");
 
-- 
2.14.1



More information about the U-Boot mailing list