]> git.kernelconcepts.de Git - karo-tx-uboot.git/commitdiff
ppc4xx: Handle i2c stuck on combined xfer
authorDirk Eibach <dirk.eibach@gdsys.cc>
Wed, 29 Oct 2014 14:56:44 +0000 (15:56 +0100)
committerHeiko Schocher <hs@denx.de>
Mon, 10 Nov 2014 05:44:30 +0000 (06:44 +0100)
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>
arch/powerpc/include/asm/ppc4xx-i2c.h
drivers/i2c/ppc4xx_i2c.c

index 09189cf19bc8f7470ee6f70dbfb764018886b4c9..df97f175b3637856da0f91ef8ee8e7da159af7dd 100644 (file)
@@ -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
index d2ff86c99abac6a5ca14c5386bf1ad446c5e100e..df8888550bb0e2010db25362ca9695b4ac7a293e 100644 (file)
@@ -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;
                }