Эх сурвалжийг харах

Merge branch 'master' of git://git.denx.de/u-boot-i2c

Tom Rini 10 жил өмнө
parent
commit
1e4b45c8f7

+ 2 - 0
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

+ 1 - 1
drivers/i2c/fsl_i2c.c

@@ -38,7 +38,7 @@
  * generic value.
  */
 #ifndef CONFIG_I2C_TIMEOUT
-#define CONFIG_I2C_TIMEOUT	10000
+#define CONFIG_I2C_TIMEOUT	100000
 #endif
 
 #define I2C_READ_BIT  1

+ 26 - 4
drivers/i2c/ppc4xx_i2c.c

@@ -158,8 +158,7 @@ static void ppc4xx_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
  *
  * Typical case is a Write of an addr followd by a Read. The
  * IBM FAQ does not cover this. On the last byte of the write
- * we don't set the creg CHT bit, and on the first bytes of the
- * read we set the RPST bit.
+ * we don't set the creg CHT bit but the RPST bit.
  *
  * It does not support address only transfers, there must be
  * a data part. If you want to write the address yourself, put
@@ -247,6 +246,10 @@ static int _i2c_transfer(struct i2c_adapter *adap,
 		if ((!cmd_type && (ptr == addr)) || ((tran + bc) != cnt))
 			creg |= IIC_CNTL_CHT;
 
+		/* last part of address, prepare for repeated start on read */
+		if (cmd_type && (ptr == addr) && ((tran + bc) == cnt))
+			creg |= IIC_CNTL_RPST;
+
 		if (reading) {
 			creg |= IIC_CNTL_READ;
 		} else {
@@ -286,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;
 		}
@@ -314,8 +338,6 @@ static int _i2c_transfer(struct i2c_adapter *adap,
 			cnt = data_len;
 			tran = 0;
 			reading = cmd_type;
-			if (reading)
-				creg = IIC_CNTL_RPST;
 		}
 	}
 	return result;

+ 2 - 2
drivers/i2c/rcar_i2c.c

@@ -119,10 +119,10 @@ rcar_i2c_raw_read(struct rcar_i2c *dev, u8 chip, uint addr)
 
 	/* set slave address, receive */
 	writel((chip << 1) | 1, &dev->icmar);
-	/* clear status */
-	writel(0, &dev->icmsr);
 	/* start master receive */
 	writel(MCR_MDBS | MCR_MIE | MCR_ESG, &dev->icmcr);
+	/* clear status */
+	writel(0, &dev->icmsr);
 
 	while ((readl(&dev->icmsr) & (MSR_MAT | MSR_MDR))
 		!= (MSR_MAT | MSR_MDR))