Patch "i2c: omap: Trigger bus recovery in lockup case" has been added to the 4.14-stable tree

gregkh at gregkh at
Mon Nov 11 01:43:33 PST 2019

This is a note to let you know that I've just added the patch titled

    i2c: omap: Trigger bus recovery in lockup case

to the 4.14-stable tree which can be found at:;a=summary

The filename of the patch is:
and it can be found in the queue-4.14 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable at> know about it.

>From foo at baz Mon 11 Nov 2019 10:07:22 AM CET
From: Mathieu Poirier <mathieu.poirier at>
Date: Thu,  5 Sep 2019 10:17:58 -0600
Subject: i2c: omap: Trigger bus recovery in lockup case
To: stable at
Cc: linux-usb at, linux-kernel at, linux-pm at, dri-devel at, linux-omap at, linux-i2c at, linux-pci at, linux-mtd at
Message-ID: <20190905161759.28036-18-mathieu.poirier at>

From: Claudio Foellmi <claudio.foellmi at>

commit 93367bfca98f36cece57c01dbce6ea1b4ac58245 upstream

A very conservative check for bus activity (to prevent interference
in multimaster setups) prevented the bus recovery methods from being
triggered in the case that SDA or SCL was stuck low.
This defeats the purpose of the recovery mechanism, which was introduced
for exactly this situation (a slave device keeping SDA pulled down).

Also added a check to make sure SDA is low before attempting recovery.
If SDA is not stuck low, recovery will not help, so we can skip it.

Note that bus lockups can persist across reboots. The only other options
are to reset or power cycle the offending slave device, and many i2c
slaves do not even have a reset pin.

If we see that one of the lines is low for the entire timeout duration,
we can actually be sure that there is no other master driving the bus.
It is therefore save for us to attempt a bus recovery.

Signed-off-by: Claudio Foellmi <claudio.foellmi at>
Tested-by: Vignesh R <vigneshr at>
Reviewed-by: Grygorii Strashko <grygorii.strashko at>
[wsa: fixed one return code to -EBUSY]
Signed-off-by: Wolfram Sang <wsa at>
Signed-off-by: Mathieu Poirier <mathieu.poirier at>
Signed-off-by: Greg Kroah-Hartman <gregkh at>
 drivers/i2c/busses/i2c-omap.c |   25 +++++++++++++++++++++++--
 1 file changed, 23 insertions(+), 2 deletions(-)

--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -487,6 +487,22 @@ static int omap_i2c_init(struct omap_i2c
+ * Try bus recovery, but only if SDA is actually low.
+ */
+static int omap_i2c_recover_bus(struct omap_i2c_dev *omap)
+	u16 systest;
+	systest = omap_i2c_read_reg(omap, OMAP_I2C_SYSTEST_REG);
+	if ((systest & OMAP_I2C_SYSTEST_SCL_I_FUNC) &&
+	    (systest & OMAP_I2C_SYSTEST_SDA_I_FUNC))
+		return 0; /* bus seems to already be fine */
+	if (!(systest & OMAP_I2C_SYSTEST_SCL_I_FUNC))
+		return -EBUSY; /* recovery would not fix SCL */
+	return i2c_recover_bus(&omap->adapter);
  * Waiting on Bus Busy
 static int omap_i2c_wait_for_bb(struct omap_i2c_dev *omap)
@@ -496,7 +512,7 @@ static int omap_i2c_wait_for_bb(struct o
 	timeout = jiffies + OMAP_I2C_TIMEOUT;
 	while (omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) {
 		if (time_after(jiffies, timeout))
-			return i2c_recover_bus(&omap->adapter);
+			return omap_i2c_recover_bus(omap);
@@ -577,8 +593,13 @@ static int omap_i2c_wait_for_bb_valid(st
 		if (time_after(jiffies, timeout)) {
+			/*
+			 * SDA or SCL were low for the entire timeout without
+			 * any activity detected. Most likely, a slave is
+			 * locking up the bus with no master driving the clock.
+			 */
 			dev_warn(omap->dev, "timeout waiting for bus ready\n");
-			return -ETIMEDOUT;
+			return omap_i2c_recover_bus(omap);

Patches currently in stable-queue which might be from mathieu.poirier at are


More information about the linux-mtd mailing list