|
@@ -0,0 +1,92 @@
|
|
|
|
+diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
|
|
|
|
+index 5d784d4..946f850 100644
|
|
|
|
+--- a/drivers/i2c/busses/i2c-omap.c
|
|
|
|
++++ b/drivers/i2c/busses/i2c-omap.c
|
|
|
|
+@@ -474,34 +474,11 @@ static int omap_i2c_init(struct omap_i2c_dev *omap)
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+-static void omap_i2c_clock_pulse(struct omap_i2c_dev *dev)
|
|
|
|
+-{
|
|
|
|
+- u32 reg;
|
|
|
|
+- int i;
|
|
|
|
+-
|
|
|
|
+- /* Enable testmode */
|
|
|
|
+- reg = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
|
|
|
|
+- reg |= OMAP_I2C_SYSTEST_ST_EN;
|
|
|
|
+- omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg);
|
|
|
|
+-
|
|
|
|
+- for (i = 0; i < 9; i++) {
|
|
|
|
+- reg |= OMAP_I2C_SYSTEST_SCL_O;
|
|
|
|
+- omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg);
|
|
|
|
+- mdelay(100);
|
|
|
|
+- reg &= ~OMAP_I2C_SYSTEST_SCL_O;
|
|
|
|
+- omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg);
|
|
|
|
+- mdelay(100);
|
|
|
|
+- }
|
|
|
|
+-
|
|
|
|
+- /* Disable testmode */
|
|
|
|
+- reg &= ~OMAP_I2C_SYSTEST_ST_EN;
|
|
|
|
+- omap_i2c_write_reg(dev, OMAP_I2C_SYSTEST_REG, reg);
|
|
|
|
+-}
|
|
|
|
+-
|
|
|
|
+-static void omap_i2c_bus_recover(struct omap_i2c_dev *dev)
|
|
|
|
++static int omap_i2c_bus_recover(struct omap_i2c_dev *dev)
|
|
|
|
+ {
|
|
|
|
+ u32 reg1;
|
|
|
|
+ u32 reg2;
|
|
|
|
++ int ret = 0;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * First differentiate SCL stuck low from SDA stuck low using our
|
|
|
|
+@@ -513,7 +490,7 @@ static void omap_i2c_bus_recover(struct omap_i2c_dev *dev)
|
|
|
|
+ * bus, there's nothing more we can do; we will still try to Reset
|
|
|
|
+ * our I2C IP anyway.
|
|
|
|
+ */
|
|
|
|
+-
|
|
|
|
++ dev_err(dev->dev, "--> omap_i2c_bus_recover called!\n");
|
|
|
|
+ reg1 = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
|
|
|
|
+ msleep(1);
|
|
|
|
+ reg2 = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
|
|
|
|
+@@ -527,18 +504,21 @@ static void omap_i2c_bus_recover(struct omap_i2c_dev *dev)
|
|
|
|
+ if (!(reg1 & OMAP_I2C_SYSTEST_SDA_I_FUNC) &&
|
|
|
|
+ !(reg2 & OMAP_I2C_SYSTEST_SDA_I_FUNC)) {
|
|
|
|
+ dev_err(dev->dev, "SDA is stuck low, driving 9 pulses on SCL\n");
|
|
|
|
+- omap_i2c_clock_pulse(dev);
|
|
|
|
++ i2c_generic_scl_recovery(&dev->adapter);
|
|
|
|
+
|
|
|
|
+ reg1 = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
|
|
|
|
+ msleep(1);
|
|
|
|
+ reg2 = omap_i2c_read_reg(dev, OMAP_I2C_SYSTEST_REG);
|
|
|
|
+
|
|
|
|
+- if ((reg1 & OMAP_I2C_SYSTEST_SDA_I_FUNC) &&
|
|
|
|
+- (reg2 & OMAP_I2C_SYSTEST_SDA_I_FUNC)) {
|
|
|
|
++ if (!(reg1 & OMAP_I2C_SYSTEST_SDA_I_FUNC) &&
|
|
|
|
++ !(reg2 & OMAP_I2C_SYSTEST_SDA_I_FUNC)) {
|
|
|
|
+ dev_err(dev->dev, "SDA still stuck, resetting\n");
|
|
|
|
++ ret = -EBUSY;
|
|
|
|
+ omap_i2c_reset(dev);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
++
|
|
|
|
++ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+@@ -776,10 +756,13 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
|
|
|
|
+ timeout = wait_for_completion_timeout(&omap->cmd_complete,
|
|
|
|
+ OMAP_I2C_TIMEOUT);
|
|
|
|
+ if (timeout == 0) {
|
|
|
|
++ int ret;
|
|
|
|
++
|
|
|
|
+ dev_err(omap->dev, "controller timed out\n");
|
|
|
|
+- omap_i2c_reset(omap);
|
|
|
|
+- __omap_i2c_init(omap);
|
|
|
|
+- return -ETIMEDOUT;
|
|
|
|
++ if((ret = omap_i2c_bus_recover(omap)))
|
|
|
|
++ return ret;
|
|
|
|
++ else
|
|
|
|
++ return -ETIMEDOUT;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (likely(!omap->cmd_err))
|