|
@@ -153,11 +153,60 @@ static uint omap24_i2c_setspeed(struct i2c_adapter *adap, uint speed)
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
+
|
|
|
+static void omap24_i2c_deblock(struct i2c_adapter *adap)
|
|
|
+{
|
|
|
+ struct i2c *i2c_base = omap24_get_base(adap);
|
|
|
+ int i;
|
|
|
+ u16 systest;
|
|
|
+ u16 orgsystest;
|
|
|
+
|
|
|
+ /* set test mode ST_EN = 1 */
|
|
|
+ orgsystest = readw(&i2c_base->systest);
|
|
|
+ systest = orgsystest;
|
|
|
+ /* enable testmode */
|
|
|
+ systest |= I2C_SYSTEST_ST_EN;
|
|
|
+ writew(systest, &i2c_base->systest);
|
|
|
+ systest &= ~I2C_SYSTEST_TMODE_MASK;
|
|
|
+ systest |= 3 << I2C_SYSTEST_TMODE_SHIFT;
|
|
|
+ writew(systest, &i2c_base->systest);
|
|
|
+
|
|
|
+ /* set SCL, SDA = 1 */
|
|
|
+ systest |= I2C_SYSTEST_SCL_O | I2C_SYSTEST_SDA_O;
|
|
|
+ writew(systest, &i2c_base->systest);
|
|
|
+ udelay(10);
|
|
|
+
|
|
|
+ /* toggle scl 9 clocks */
|
|
|
+ for (i = 0; i < 9; i++) {
|
|
|
+ /* SCL = 0 */
|
|
|
+ systest &= ~I2C_SYSTEST_SCL_O;
|
|
|
+ writew(systest, &i2c_base->systest);
|
|
|
+ udelay(10);
|
|
|
+ /* SCL = 1 */
|
|
|
+ systest |= I2C_SYSTEST_SCL_O;
|
|
|
+ writew(systest, &i2c_base->systest);
|
|
|
+ udelay(10);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* send stop */
|
|
|
+ systest &= ~I2C_SYSTEST_SDA_O;
|
|
|
+ writew(systest, &i2c_base->systest);
|
|
|
+ udelay(10);
|
|
|
+ systest |= I2C_SYSTEST_SCL_O | I2C_SYSTEST_SDA_O;
|
|
|
+ writew(systest, &i2c_base->systest);
|
|
|
+ udelay(10);
|
|
|
+
|
|
|
+ /* restore original mode */
|
|
|
+ writew(orgsystest, &i2c_base->systest);
|
|
|
+}
|
|
|
+
|
|
|
static void omap24_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
|
|
|
{
|
|
|
struct i2c *i2c_base = omap24_get_base(adap);
|
|
|
int timeout = I2C_TIMEOUT;
|
|
|
+ int deblock = 1;
|
|
|
|
|
|
+retry:
|
|
|
if (readw(&i2c_base->con) & I2C_CON_EN) {
|
|
|
writew(0, &i2c_base->con);
|
|
|
udelay(50000);
|
|
@@ -194,6 +243,14 @@ static void omap24_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
|
|
|
udelay(1000);
|
|
|
flush_fifo(adap);
|
|
|
writew(0xFFFF, &i2c_base->stat);
|
|
|
+
|
|
|
+ /* Handle possible failed I2C state */
|
|
|
+ if (wait_for_bb(adap))
|
|
|
+ if (deblock == 1) {
|
|
|
+ omap24_i2c_deblock(adap);
|
|
|
+ deblock = 0;
|
|
|
+ goto retry;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static void flush_fifo(struct i2c_adapter *adap)
|