diff options
-rw-r--r-- | arch/powerpc/include/asm/ppc4xx-i2c.h | 2 | ||||
-rw-r--r-- | drivers/i2c/ppc4xx_i2c.c | 21 |
2 files changed, 23 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/ppc4xx-i2c.h b/arch/powerpc/include/asm/ppc4xx-i2c.h index 09189cf19b..df97f175b3 100644 --- a/arch/powerpc/include/asm/ppc4xx-i2c.h +++ b/arch/powerpc/include/asm/ppc4xx-i2c.h @@ -72,6 +72,8 @@ struct ppc4xx_i2c { #define IIC_EXTSTS_XFRA 0x01 #define IIC_EXTSTS_ICT 0x02 #define IIC_EXTSTS_LA 0x04 +#define IIC_EXTSTS_BCS_MASK 0x70 +#define IIC_EXTSTS_BCS_FREE 0x40 /* XTCNTLSS Register Bit definition */ #define IIC_XTCNTLSS_SRST 0x01 diff --git a/drivers/i2c/ppc4xx_i2c.c b/drivers/i2c/ppc4xx_i2c.c index d2ff86c99a..df8888550b 100644 --- a/drivers/i2c/ppc4xx_i2c.c +++ b/drivers/i2c/ppc4xx_i2c.c @@ -289,6 +289,27 @@ static int _i2c_transfer(struct i2c_adapter *adap, /* Transfer aborted? */ if (status & IIC_EXTSTS_XFRA) result = IIC_NOK_XFRA; + /* Is bus free? + * If error happened during combined xfer + * IIC interface is usually stuck in some strange + * state without a valid stop condition. + * Brute, but working: generate stop, then soft reset. + */ + if ((status & IIC_EXTSTS_BCS_MASK) + != IIC_EXTSTS_BCS_FREE){ + u8 mdcntl = in_8(&i2c->mdcntl); + + /* Generate valid stop condition */ + out_8(&i2c->xtcntlss, IIC_XTCNTLSS_SRST); + out_8(&i2c->directcntl, IIC_DIRCNTL_SCC); + udelay(10); + out_8(&i2c->directcntl, + IIC_DIRCNTL_SCC | IIC_DIRCNTL_SDAC); + out_8(&i2c->xtcntlss, 0); + + ppc4xx_i2c_init(adap, (mdcntl & IIC_MDCNTL_FSM) + ? 400000 : 100000, 0); + } } else if ( status & IIC_STS_PT) { result = IIC_NOK_TOUT; } |