|
@@ -486,6 +486,22 @@ static int omap_i2c_init(struct omap_i2c_dev *omap)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * 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
|
|
|
*/
|
|
@@ -496,7 +512,7 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *omap)
|
|
|
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);
|
|
|
msleep(1);
|
|
|
}
|
|
|
|
|
@@ -577,8 +593,13 @@ static int omap_i2c_wait_for_bb_valid(struct omap_i2c_dev *omap)
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
}
|
|
|
|
|
|
msleep(1);
|