Patchwork [U-Boot,2/2] I2C: mxc_i2c: Add support for Vybrid VF610 platform

login
register
mail settings
Submitter Alison Wang
Date June 17, 2013, 7:30 a.m.
Message ID <1371454239-24655-3-git-send-email-b18965@freescale.com>
Download mbox | patch
Permalink /patch/251784/
State Accepted
Delegated to: Heiko Schocher
Headers show

Comments

Alison Wang - June 17, 2013, 7:30 a.m.
This patch adds support for Vybrid VF610 platform.

There are some differences between i.MX6 and Vybrid for I2C controller.
(1) The registers' offset are different.
(2) The I2C clock divider values are different.
(3) In I2C control register, the enable/disable/reset bit is inverted for Vybrid comparing to i.MX6.
(4) In I2C status register, the interrupt flag bit is cleared by writing "1" for Vybrid.
For i.MX6, this bit is cleared by writing "0".
(5) In I2C status register, the arbitration lost flag bit is cleared by writing "1" for Vybrid.
For i.MX6, this bit is cleared by writing "0".

Signed-off-by: Alison Wang <b18965@freescale.com>
---
 drivers/i2c/mxc_i2c.c | 62 +++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 55 insertions(+), 7 deletions(-)

Patch

diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c
index a73b10b..85e3e8b 100644
--- a/drivers/i2c/mxc_i2c.c
+++ b/drivers/i2c/mxc_i2c.c
@@ -38,6 +38,15 @@ 
 #include <i2c.h>
 #include <watchdog.h>
 
+#ifdef I2C_QUIRK_REG
+struct mxc_i2c_regs {
+	uint8_t		iadr;
+	uint8_t		ifdr;
+	uint8_t		i2cr;
+	uint8_t		i2sr;
+	uint8_t		i2dr;
+};
+#else
 struct mxc_i2c_regs {
 	uint32_t	iadr;
 	uint32_t	ifdr;
@@ -45,8 +54,8 @@  struct mxc_i2c_regs {
 	uint32_t	i2sr;
 	uint32_t	i2dr;
 };
+#endif
 
-#define I2CR_IEN	(1 << 7)
 #define I2CR_IIEN	(1 << 6)
 #define I2CR_MSTA	(1 << 5)
 #define I2CR_MTX	(1 << 4)
@@ -59,10 +68,39 @@  struct mxc_i2c_regs {
 #define I2SR_IIF	(1 << 1)
 #define I2SR_RX_NO_AK	(1 << 0)
 
+#ifdef I2C_QUIRK_REG
+#define I2CR_IEN	(0 << 7)
+#define I2CR_IDIS	(1 << 7)
+#define I2SR_IIF_CLEAR	(1 << 1)
+#else
+#define I2CR_IEN	(1 << 7)
+#define I2CR_IDIS	(0 << 7)
+#define I2SR_IIF_CLEAR	(0 << 1)
+#endif
+
 #if defined(CONFIG_HARD_I2C) && !defined(CONFIG_SYS_I2C_BASE)
 #error "define CONFIG_SYS_I2C_BASE to use the mxc_i2c driver"
 #endif
 
+#ifdef I2C_QUIRK_REG
+static u16 i2c_clk_div[60][2] = {
+	{ 20,	0x00 }, { 22,	0x01 }, { 24,	0x02 }, { 26,	0x03 },
+	{ 28,	0x04 },	{ 30,	0x05 },	{ 32,	0x09 }, { 34,	0x06 },
+	{ 36,	0x0A }, { 40,	0x07 }, { 44,	0x0C }, { 48,	0x0D },
+	{ 52,	0x43 },	{ 56,	0x0E }, { 60,	0x45 }, { 64,	0x12 },
+	{ 68,	0x0F },	{ 72,	0x13 },	{ 80,	0x14 },	{ 88,	0x15 },
+	{ 96,	0x19 },	{ 104,	0x16 },	{ 112,	0x1A },	{ 128,	0x17 },
+	{ 136,	0x4F }, { 144,	0x1C },	{ 160,	0x1D }, { 176,	0x55 },
+	{ 192,	0x1E }, { 208,	0x56 },	{ 224,	0x22 }, { 228,	0x24 },
+	{ 240,	0x1F },	{ 256,	0x23 }, { 288,	0x5C },	{ 320,	0x25 },
+	{ 384,	0x26 }, { 448,	0x2A },	{ 480,	0x27 }, { 512,	0x2B },
+	{ 576,	0x2C },	{ 640,	0x2D },	{ 768,	0x31 }, { 896,	0x32 },
+	{ 960,	0x2F },	{ 1024,	0x33 },	{ 1152,	0x34 }, { 1280,	0x35 },
+	{ 1536,	0x36 }, { 1792,	0x3A },	{ 1920,	0x37 },	{ 2048,	0x3B },
+	{ 2304,	0x3C },	{ 2560,	0x3D },	{ 3072,	0x3E }, { 3584,	0x7A },
+	{ 3840,	0x3F }, { 4096,	0x7B }, { 5120,	0x7D },	{ 6144,	0x7E },
+};
+#else
 static u16 i2c_clk_div[50][2] = {
 	{ 22,	0x20 }, { 24,	0x21 }, { 26,	0x22 }, { 28,	0x23 },
 	{ 30,	0x00 }, { 32,	0x24 }, { 36,	0x25 }, { 40,	0x26 },
@@ -78,6 +116,7 @@  static u16 i2c_clk_div[50][2] = {
 	{ 1920,	0x1B }, { 2048,	0x3F }, { 2304,	0x1C }, { 2560,	0x1D },
 	{ 3072,	0x1E }, { 3840,	0x1F }
 };
+#endif
 
 /*
  * Calculate and set proper clock divider
@@ -125,7 +164,7 @@  static int bus_i2c_set_bus_speed(void *base, int speed)
 	writeb(idx, &i2c_regs->ifdr);
 
 	/* Reset module */
-	writeb(0, &i2c_regs->i2cr);
+	writeb(I2CR_IDIS, &i2c_regs->i2cr);
 	writeb(0, &i2c_regs->i2sr);
 	return 0;
 }
@@ -157,7 +196,11 @@  static int wait_for_sr_state(struct mxc_i2c_regs *i2c_regs, unsigned state)
 	for (;;) {
 		sr = readb(&i2c_regs->i2sr);
 		if (sr & I2SR_IAL) {
+#ifdef I2C_QUIRK_REG
+			writeb(sr | I2SR_IAL, &i2c_regs->i2sr);
+#else
 			writeb(sr & ~I2SR_IAL, &i2c_regs->i2sr);
+#endif
 			printf("%s: Arbitration lost sr=%x cr=%x state=%x\n",
 				__func__, sr, readb(&i2c_regs->i2cr), state);
 			return -ERESTART;
@@ -178,7 +221,7 @@  static int tx_byte(struct mxc_i2c_regs *i2c_regs, u8 byte)
 {
 	int ret;
 
-	writeb(0, &i2c_regs->i2sr);
+	writeb(I2SR_IIF_CLEAR, &i2c_regs->i2sr);
 	writeb(byte, &i2c_regs->i2dr);
 	ret = wait_for_sr_state(i2c_regs, ST_IIF);
 	if (ret < 0)
@@ -214,14 +257,18 @@  static int i2c_init_transfer_(struct mxc_i2c_regs *i2c_regs,
 	int ret;
 
 	/* Enable I2C controller */
+#ifdef I2C_QUIRK_REG
+	if (readb(&i2c_regs->i2cr) & I2CR_IDIS) {
+#else
 	if (!(readb(&i2c_regs->i2cr) & I2CR_IEN)) {
+#endif
 		writeb(I2CR_IEN, &i2c_regs->i2cr);
 		/* Wait for controller to be stable */
 		udelay(50);
 	}
 	if (readb(&i2c_regs->iadr) == (chip << 1))
 		writeb((chip << 1) ^ 2, &i2c_regs->iadr);
-	writeb(0, &i2c_regs->i2sr);
+	writeb(I2SR_IIF_CLEAR, &i2c_regs->i2sr);
 	ret = wait_for_sr_state(i2c_regs, ST_BUS_IDLE);
 	if (ret < 0)
 		return ret;
@@ -269,7 +316,8 @@  static int i2c_init_transfer(struct mxc_i2c_regs *i2c_regs,
 		printf("%s: failed for chip 0x%x retry=%d\n", __func__, chip,
 				retry);
 		if (ret != -ERESTART)
-			writeb(0, &i2c_regs->i2cr);	/* Disable controller */
+			/* Disable controller */
+			writeb(I2CR_IDIS, &i2c_regs->i2cr);
 		udelay(100);
 		if (i2c_idle_bus(i2c_regs) < 0)
 			break;
@@ -309,7 +357,7 @@  int bus_i2c_read(void *base, uchar chip, uint addr, int alen, uchar *buf,
 	if (len == 1)
 		temp |= I2CR_TX_NO_AK;
 	writeb(temp, &i2c_regs->i2cr);
-	writeb(0, &i2c_regs->i2sr);
+	writeb(I2SR_IIF_CLEAR, &i2c_regs->i2sr);
 	readb(&i2c_regs->i2dr);		/* dummy read to clear ICF */
 
 	/* read data */
@@ -331,7 +379,7 @@  int bus_i2c_read(void *base, uchar chip, uint addr, int alen, uchar *buf,
 			temp |= I2CR_TX_NO_AK;
 			writeb(temp, &i2c_regs->i2cr);
 		}
-		writeb(0, &i2c_regs->i2sr);
+		writeb(I2SR_IIF_CLEAR, &i2c_regs->i2sr);
 		buf[i] = readb(&i2c_regs->i2dr);
 	}
 	i2c_imx_stop(i2c_regs);