From b24f119d672b709d153ff2ac091d4aa63ec6877d Mon Sep 17 00:00:00 2001 From: Ben Warren Date: Thu, 7 Sep 2006 16:51:04 -0400 Subject: [PATCH] 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 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 | 168 +++++++++++++++++++++++++++++----- include/asm-ppc/i2c.h | 21 +++-- include/configs/MPC8349EMDS.h | 6 +- 3 files changed, 160 insertions(+), 35 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 #include -#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 */ diff --git a/include/asm-ppc/i2c.h b/include/asm-ppc/i2c.h index 2ae33670fd..baf9d9a262 100644 --- a/include/asm-ppc/i2c.h +++ b/include/asm-ppc/i2c.h @@ -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 diff --git a/include/configs/MPC8349EMDS.h b/include/configs/MPC8349EMDS.h index 66f164660e..4d5ad57192 100644 --- a/include/configs/MPC8349EMDS.h +++ b/include/configs/MPC8349EMDS.h @@ -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 */ @@ -311,9 +311,11 @@ /* 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 -- 2.39.5