summaryrefslogtreecommitdiffstats
path: root/cpu/mpc83xx
diff options
context:
space:
mode:
authorBen Warren <bwarren@qstreams.com>2006-09-07 16:51:04 -0400
committerKim Phillips <kim.phillips@freescale.com>2006-11-03 19:42:19 -0600
commitb24f119d672b709d153ff2ac091d4aa63ec6877d (patch)
treefd336614e7e0b3363512be41e501b6e9d6a5331a /cpu/mpc83xx
parentbb99ad6d8257bf828f150d40f507b30d80a4a7ae (diff)
downloadblackbird-obmc-uboot-b24f119d672b709d153ff2ac091d4aa63ec6877d.tar.gz
blackbird-obmc-uboot-b24f119d672b709d153ff2ac091d4aa63ec6877d.zip
Multi-bus I2C implementation of MPC834x
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
Diffstat (limited to 'cpu/mpc83xx')
-rw-r--r--cpu/mpc83xx/i2c.c168
1 files changed, 144 insertions, 24 deletions
diff --git a/cpu/mpc83xx/i2c.c b/cpu/mpc83xx/i2c.c
index 723feeb44f..fc89fb1e25 100644
--- a/cpu/mpc83xx/i2c.c
+++ b/cpu/mpc83xx/i2c.c
@@ -45,37 +45,123 @@
#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 */
OpenPOWER on IntegriCloud