summaryrefslogtreecommitdiff
path: root/drivers/i2c/omap24xx_i2c.c
diff options
context:
space:
mode:
authorStefano Babic <sbabic@denx.de>2014-08-08 10:18:40 +0200
committerStefano Babic <sbabic@denx.de>2014-08-08 10:18:40 +0200
commitc23154aab5825fec81d5500c53eaa686646c76b5 (patch)
tree32b0aafae49f664a65ced50981492bb031f006b8 /drivers/i2c/omap24xx_i2c.c
parentcb07d74e2e0c0a41533b6bcd551af9bf2ebcf2bc (diff)
parent9d195a546179bc732aba9eacccf0a9a3db591288 (diff)
downloadu-boot-imx-c23154aab5825fec81d5500c53eaa686646c76b5.zip
u-boot-imx-c23154aab5825fec81d5500c53eaa686646c76b5.tar.gz
u-boot-imx-c23154aab5825fec81d5500c53eaa686646c76b5.tar.bz2
Merge branch 'master' of git://git.denx.de/u-boot-arm
Diffstat (limited to 'drivers/i2c/omap24xx_i2c.c')
-rw-r--r--drivers/i2c/omap24xx_i2c.c57
1 files changed, 57 insertions, 0 deletions
diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c
index a39b591..0f1e35c 100644
--- a/drivers/i2c/omap24xx_i2c.c
+++ b/drivers/i2c/omap24xx_i2c.c
@@ -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)