summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHeiko Schocher <hs@denx.de>2014-06-30 09:12:09 +0200
committerHeiko Schocher <hs@denx.de>2014-07-16 05:18:55 +0200
commitf7c105353593907da7cbcb1590d5c1c616b7c91e (patch)
tree55ffae91f62c4039c9935e75ce8e0bbde542bb94
parent524123a70761110c5cf3ccc5f52f6d4da071b959 (diff)
downloadu-boot-imx-f7c105353593907da7cbcb1590d5c1c616b7c91e.zip
u-boot-imx-f7c105353593907da7cbcb1590d5c1c616b7c91e.tar.gz
u-boot-imx-f7c105353593907da7cbcb1590d5c1c616b7c91e.tar.bz2
i2c, omap24xx: add i2c deblock sequenz
If a bus busy is detected when intializing the driver, toggle 9 times the scl pin. Therefore enable the test mode of the controller, in which the scl, sda pins can be controlled manually. Tested on the siemens boards pxm2, rut and dxr2. Signed-off-by: Heiko Schocher <hs@denx.de> Cc: Tom Rini <trini@ti.com> Cc: Hannes Petermaier <oe5hpm@oevsv.at> Cc: Lubomir Popov <lpopov@mm-sol.com> Cc: Steve Sakoman <steve@sakoman.com> Cc: Sandeep Paulraj <s-paulraj@ti.com> Cc: Vincent Stehlé <v-stehle@ti.com> Cc: Samuel Egli <samuel.egli@siemens.com>
-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)