summaryrefslogtreecommitdiff
path: root/drivers/i2c
diff options
context:
space:
mode:
authorDirk Eibach <dirk.eibach@gdsys.cc>2014-10-29 14:56:44 (GMT)
committerHeiko Schocher <hs@denx.de>2014-11-10 05:44:30 (GMT)
commitb97cd6814ec08be56225975a050ee486bfa7c13a (patch)
treed62bf2d70db726db65020427cbcb793c5bd2f5aa /drivers/i2c
parent7e78f7ad7f7f666598bc2ff115ea7a35f8e059f1 (diff)
downloadu-boot-b97cd6814ec08be56225975a050ee486bfa7c13a.tar.xz
ppc4xx: Handle i2c stuck on combined xfer
ppc4xx i2c master gets stuck on errors while repeated start is active. Can be easily reproduced by "i2c md" on an unpopulated i2c address. There is not stop condition given, scl remains pulled low. The only way out seems to be doing a stop manually and then a soft reset. Signed-off-by: Dirk Eibach <dirk.eibach@gdsys.cc> Reviewed-by: Stefan Roese <sr@denx.de>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/ppc4xx_i2c.c21
1 files changed, 21 insertions, 0 deletions
diff --git a/drivers/i2c/ppc4xx_i2c.c b/drivers/i2c/ppc4xx_i2c.c
index d2ff86c..df88885 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;
}