]> git.sur5r.net Git - u-boot/commitdiff
Multi-bus I2C implementation of MPC834x
authorBen Warren <bwarren@qstreams.com>
Thu, 7 Sep 2006 20:51:04 +0000 (16:51 -0400)
committerKim Phillips <kim.phillips@freescale.com>
Sat, 4 Nov 2006 01:42:19 +0000 (19:42 -0600)
Hello,

Attached is a patch implementing multiple I2C buses on the MPC834x CPU
family and the MPC8349EMDS board in particular.
This patch requires Patch 1 (Add support for multiple I2C buses).
Testing was performed on a 533MHz board.

/*** Note: This patch replaces ticket DNX#2006083042000027 ***/

Signed-off-by: Ben Warren <bwarren@qstreams.com>
CHANGELOG:
        Implemented driver-level code to support two I2C buses on the
MPC834x CPU family and the MPC8349EMDS board.  Available I2C bus speeds
are 50kHz, 100kHz and 400kHz on each bus.

regards,
Ben

cpu/mpc83xx/i2c.c
include/asm-ppc/i2c.h
include/configs/MPC8349EMDS.h

index 723feeb44fae830a04417b43c18f44c8895b3976..fc89fb1e259e935fde52b85ebd5aa7e630c2177d 100644 (file)
 #include <i2c.h>
 #include <asm/i2c.h>
 
-#if defined(CONFIG_MPC8349EMDS) || defined(CONFIG_TQM834X)
-i2c_t * mpc83xx_i2c = (i2c_t*)(CFG_IMMRBAR + CFG_I2C_OFFSET);
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Three I2C bus speeds are supported here (50kHz, 100kHz
+ * and 400kHz).  It should be easy to add more.  Note that
+ * the maximum bus speed for I2C bus 1 is CSB/3, while I2C
+ * bus 2 can go as high as CSB.
+ * Typical values for CSB are 266MHz and 200MHz.  */
+
+                                                                      /* 50kH  100kHz  400kHz */
+static const uchar speed_map_266[][3] =
+                                                                      {{0x2e,         0x2a,   0x20},  /* base 88MHz */
+                                                                       {0x34,         0x30,   0x28}}; /* base 266 MHz */
+
+static const uchar speed_map_200[][3] =
+                                                                      {{0x2c,         0x28,   0x20},  /* base 66 MHz */
+                                                                       {0x33,         0x2f,   0x26}}; /* base 200 MHz */
+
+/* Initialize the bus pointer to whatever one the SPD EEPROM is on.
+ * Default is bus 1.  This is necessary because the DDR initialization
+ * runs from ROM, and we can't switch buses because we can't modify
+ * the i2c_dev variable.  Everything gets straightened out once i2c_init
+ * is called from RAM.  */
+
+#if defined CFG_SPD_BUS_NUM
+static i2c_t *i2c_dev = CFG_SPD_BUS_NUM;
+#else
+static i2c_t *i2c_dev = I2C_1;
 #endif
 
-void
-i2c_init(int speed, int slaveadd)
+static uchar busNum = I2C_BUS_1 ;
+static int bus_speed[2] = {0, 0};
+
+static int set_speed(int speed)
+{
+      uchar value;
+      const uchar *spdPtr;
+
+      /* Global data contains maximum I2C bus 1 speed, which is CSB/3 */
+      if(gd->i2c_clk == 88000000)
+      {
+              spdPtr = speed_map_266[busNum];
+      }
+      else if(gd->i2c_clk == 66000000)
+      {
+              spdPtr = speed_map_200[busNum];
+      }
+      else
+      {
+              printf("Max I2C bus speed %d not supported\n", gd->i2c_clk);
+              return -1;
+      }
+
+      switch(speed)
+      {
+              case 50000:
+                      value   = *(spdPtr + 0);
+                      break;
+              case 100000:
+                      value   = *(spdPtr + 1);
+                      break;
+              case 400000:
+                      value   = *(spdPtr + 2);
+                      break;
+              default:
+                      printf("I2C bus speed %d not supported\n", speed);
+                      return -2;
+      }
+      /* set clock */
+      writeb(value, &i2c_dev->fdr);
+      bus_speed[busNum] = speed;
+      return 0;
+}
+
+
+static void _i2c_init(int speed, int slaveadd)
 {
        /* stop I2C controller */
-       writeb(0x00 , &I2C->cr);
+       writeb(0x00 , &i2c_dev->cr);
 
        /* set clock */
-       writeb(speed, &I2C->fdr);
+       writeb(speed, &i2c_dev->fdr);
 
        /* set default filter */
-       writeb(0x10,&I2C->dfsrr);
+       writeb(0x10,&i2c_dev->dfsrr);
 
        /* write slave address */
-       writeb(slaveadd, &I2C->adr);
+       writeb(slaveadd, &i2c_dev->adr);
 
        /* clear status register */
-       writeb(0x00, &I2C->sr);
+       writeb(0x00, &i2c_dev->sr);
 
        /* start I2C controller */
-       writeb(I2C_CR_MEN, &I2C->cr);
+       writeb(I2C_CR_MEN, &i2c_dev->cr);
+}
+
+void i2c_init(int speed, int slaveadd)
+{
+      /* Set both interfaces to the same speed and slave address */
+      /* Note: This function gets called twice - before and after
+       * relocation to RAM.  The first time it's called, we are unable
+       * to change buses, so whichever one 'i2c_dev' was initialized to
+       * gets set twice.  When run from RAM both buses get set properly */
+
+      i2c_set_bus_num(I2C_BUS_1);
+      _i2c_init(speed, slaveadd);
+#ifdef        CFG_I2C2_OFFSET
+      i2c_set_bus_num(I2C_BUS_2);
+      _i2c_init(speed, slaveadd);
+      i2c_set_bus_num(I2C_BUS_1);
+#endif        /* CFG_I2C2_OFFSET */
 }
 
 static __inline__ int
 i2c_wait4bus (void)
 {
        ulong timeval = get_timer (0);
-       while (readb(&I2C->sr) & I2C_SR_MBB) {
+       while (readb(&i2c_dev->sr) & I2C_SR_MBB) {
                if (get_timer (timeval) > I2C_TIMEOUT) {
                        return -1;
                }
@@ -89,12 +175,12 @@ i2c_wait (int write)
        u32 csr;
        ulong timeval = get_timer(0);
        do {
-               csr = readb(&I2C->sr);
+               csr = readb(&i2c_dev->sr);
 
                if (!(csr & I2C_SR_MIF))
                        continue;
 
-               writeb(0x0, &I2C->sr);
+               writeb(0x0, &i2c_dev->sr);
 
                if (csr & I2C_SR_MAL) {
                        debug("i2c_wait: MAL\n");
@@ -123,9 +209,9 @@ i2c_write_addr (u8 dev, u8 dir, int rsta)
 {
        writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX |
               (rsta?I2C_CR_RSTA:0),
-              &I2C->cr);
+              &i2c_dev->cr);
 
-       writeb((dev << 1) | dir, &I2C->dr);
+       writeb((dev << 1) | dir, &i2c_dev->dr);
 
        if (i2c_wait (I2C_WRITE) < 0)
                return 0;
@@ -138,10 +224,10 @@ __i2c_write (u8 *data, int length)
        int i;
 
        writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX,
-              &I2C->cr);
+              &i2c_dev->cr);
 
        for (i=0; i < length; i++) {
-               writeb(data[i], &I2C->dr);
+               writeb(data[i], &i2c_dev->dr);
 
                if (i2c_wait (I2C_WRITE) < 0)
                        break;
@@ -156,10 +242,10 @@ __i2c_read (u8 *data, int length)
 
        writeb(I2C_CR_MEN | I2C_CR_MSTA |
               ((length == 1) ? I2C_CR_TXAK : 0),
-              &I2C->cr);
+              &i2c_dev->cr);
 
        /* dummy read */
-       readb(&I2C->dr);
+       readb(&i2c_dev->dr);
 
        for (i=0; i < length; i++) {
                if (i2c_wait (I2C_READ) < 0)
@@ -169,13 +255,13 @@ __i2c_read (u8 *data, int length)
                if (i == length - 2)
                        writeb(I2C_CR_MEN | I2C_CR_MSTA |
                               I2C_CR_TXAK,
-                              &I2C->cr);
+                              &i2c_dev->cr);
 
                /* Generate stop on last byte */
                if (i == length - 1)
-                       writeb(I2C_CR_MEN | I2C_CR_TXAK, &I2C->cr);
+                       writeb(I2C_CR_MEN | I2C_CR_TXAK, &i2c_dev->cr);
 
-               data[i] = readb(&I2C->dr);
+               data[i] = readb(&i2c_dev->dr);
        }
        return i;
 }
@@ -201,7 +287,7 @@ i2c_read (u8 dev, uint addr, int alen, u8 *data, int length)
        i = __i2c_read (data, length);
 
  exit:
-       writeb(I2C_CR_MEN, &I2C->cr);
+       writeb(I2C_CR_MEN, &i2c_dev->cr);
        return !(i == length);
 }
 
@@ -223,7 +309,7 @@ i2c_write (u8 dev, uint addr, int alen, u8 *data, int length)
        i = __i2c_write (data, length);
 
  exit:
-       writeb(I2C_CR_MEN, &I2C->cr);
+       writeb(I2C_CR_MEN, &i2c_dev->cr);
        return !(i == length);
 }
 
@@ -254,4 +340,38 @@ void i2c_reg_write (uchar i2c_addr, uchar reg, uchar val)
        i2c_write (i2c_addr, reg, 1, &val, 1);
 }
 
+int    i2c_set_bus_num(uchar bus)
+{
+       if(bus == I2C_BUS_1)
+       {
+               i2c_dev = I2C_1;
+       }
+#ifdef CFG_I2C2_OFFSET
+       else if(bus == I2C_BUS_2)
+       {
+               i2c_dev = I2C_2;
+       }
+#endif /* CFG_I2C2_OFFSET */
+       else
+       {
+               return -1;
+       }
+       busNum = bus;
+       return 0;
+}
+
+int    i2c_set_bus_speed(int speed)
+{
+       return set_speed(speed);
+}
+
+uchar i2c_get_bus_num(void)
+{
+       return busNum;
+}
+
+int    i2c_get_bus_speed(void)
+{
+       return bus_speed[busNum];
+}
 #endif /* CONFIG_HARD_I2C */
index 2ae33670fde1ec72af1ec8282bfc687559423b57..baf9d9a2628bbb885ceecaa0029115e02b17d56f 100644 (file)
@@ -79,6 +79,12 @@ typedef struct i2c
 #endif
 #define I2C_TIMEOUT (CFG_HZ/4)
 
+enum   I2C_BUS_NUM
+{
+       I2C_BUS_1 = 0,
+       I2C_BUS_2,
+};
+
 #ifndef CFG_IMMRBAR
 #error CFG_IMMRBAR is not defined in /include/configs/${BOARD}.h
 #endif
@@ -87,15 +93,12 @@ typedef struct i2c
 #error CFG_I2C_OFFSET is not defined in /include/configs/${BOARD}.h
 #endif
 
-#if defined(CONFIG_MPC8349EMDS) || defined(CONFIG_TQM834X)
-/*
- * MPC8349 have two i2c bus
- */
-extern i2c_t * mpc83xx_i2c;
-#define I2C mpc83xx_i2c
-#else
-#define I2C ((i2c_t*)(CFG_IMMRBAR + CFG_I2C_OFFSET))
-#endif
+#define I2C_1 ((i2c_t*)(CFG_IMMRBAR + CFG_I2C_OFFSET))
+
+/* Optional support for second I2C bus */
+#ifdef        CFG_I2C2_OFFSET
+#define I2C_2 ((i2c_t*)(CFG_IMMRBAR + CFG_I2C2_OFFSET))
+#endif        /* CFG_I2C2_OFFSET */
 
 #define I2C_READ  1
 #define I2C_WRITE 0
index 66f164660ee038f07b4caaac52b9e631a7a3d0f5..4d5ad57192bdf77ce9768e570ce5750c791a648d 100644 (file)
@@ -35,7 +35,7 @@
  * High Level Configuration Options
  */
 #define CONFIG_E300            1       /* E300 Family */
-#define CONFIG_MPC83XX         1       /* MPC83XX family */
+#define CONFIG_MPC834X         1       /* MPC834X family */
 #define CONFIG_MPC8349         1       /* MPC8349 specific */
 #define CONFIG_MPC8349EMDS     1       /* MPC8349EMDS board specific */
 
 /* I2C */
 #define CONFIG_HARD_I2C                        /* I2C with hardware support*/
 #undef CONFIG_SOFT_I2C                 /* I2C bit-banged */
+#define CONFIG_I2C_MULTI_BUS
+#define CONFIG_I2C_CMD_TREE
 #define CFG_I2C_SPEED          400000  /* I2C speed and slave address */
 #define CFG_I2C_SLAVE          0x7F
-#define CFG_I2C_NOPROBES       {0x69}  /* Don't probe these addrs */
+#define CFG_I2C_NOPROBES       {{0,0x69}}      /* Don't probe these addrs */
 #define CFG_I2C_OFFSET         0x3000
 #define CFG_I2C2_OFFSET                0x3100