提交 b24f119d 编写于 作者: B Ben Warren 提交者: Kim Phillips

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: NBen 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
上级 bb99ad6d
...@@ -45,37 +45,123 @@ ...@@ -45,37 +45,123 @@
#include <i2c.h> #include <i2c.h>
#include <asm/i2c.h> #include <asm/i2c.h>
#if defined(CONFIG_MPC8349EMDS) || defined(CONFIG_TQM834X) DECLARE_GLOBAL_DATA_PTR;
i2c_t * mpc83xx_i2c = (i2c_t*)(CFG_IMMRBAR + CFG_I2C_OFFSET);
/* 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 #endif
void static uchar busNum = I2C_BUS_1 ;
i2c_init(int speed, int slaveadd) 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 */ /* stop I2C controller */
writeb(0x00 , &I2C->cr); writeb(0x00 , &i2c_dev->cr);
/* set clock */ /* set clock */
writeb(speed, &I2C->fdr); writeb(speed, &i2c_dev->fdr);
/* set default filter */ /* set default filter */
writeb(0x10,&I2C->dfsrr); writeb(0x10,&i2c_dev->dfsrr);
/* write slave address */ /* write slave address */
writeb(slaveadd, &I2C->adr); writeb(slaveadd, &i2c_dev->adr);
/* clear status register */ /* clear status register */
writeb(0x00, &I2C->sr); writeb(0x00, &i2c_dev->sr);
/* start I2C controller */ /* 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 static __inline__ int
i2c_wait4bus (void) i2c_wait4bus (void)
{ {
ulong timeval = get_timer (0); 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) { if (get_timer (timeval) > I2C_TIMEOUT) {
return -1; return -1;
} }
...@@ -89,12 +175,12 @@ i2c_wait (int write) ...@@ -89,12 +175,12 @@ i2c_wait (int write)
u32 csr; u32 csr;
ulong timeval = get_timer(0); ulong timeval = get_timer(0);
do { do {
csr = readb(&I2C->sr); csr = readb(&i2c_dev->sr);
if (!(csr & I2C_SR_MIF)) if (!(csr & I2C_SR_MIF))
continue; continue;
writeb(0x0, &I2C->sr); writeb(0x0, &i2c_dev->sr);
if (csr & I2C_SR_MAL) { if (csr & I2C_SR_MAL) {
debug("i2c_wait: MAL\n"); debug("i2c_wait: MAL\n");
...@@ -123,9 +209,9 @@ i2c_write_addr (u8 dev, u8 dir, int rsta) ...@@ -123,9 +209,9 @@ i2c_write_addr (u8 dev, u8 dir, int rsta)
{ {
writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX | writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX |
(rsta?I2C_CR_RSTA:0), (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) if (i2c_wait (I2C_WRITE) < 0)
return 0; return 0;
...@@ -138,10 +224,10 @@ __i2c_write (u8 *data, int length) ...@@ -138,10 +224,10 @@ __i2c_write (u8 *data, int length)
int i; int i;
writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX, writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX,
&I2C->cr); &i2c_dev->cr);
for (i=0; i < length; i++) { for (i=0; i < length; i++) {
writeb(data[i], &I2C->dr); writeb(data[i], &i2c_dev->dr);
if (i2c_wait (I2C_WRITE) < 0) if (i2c_wait (I2C_WRITE) < 0)
break; break;
...@@ -156,10 +242,10 @@ __i2c_read (u8 *data, int length) ...@@ -156,10 +242,10 @@ __i2c_read (u8 *data, int length)
writeb(I2C_CR_MEN | I2C_CR_MSTA | writeb(I2C_CR_MEN | I2C_CR_MSTA |
((length == 1) ? I2C_CR_TXAK : 0), ((length == 1) ? I2C_CR_TXAK : 0),
&I2C->cr); &i2c_dev->cr);
/* dummy read */ /* dummy read */
readb(&I2C->dr); readb(&i2c_dev->dr);
for (i=0; i < length; i++) { for (i=0; i < length; i++) {
if (i2c_wait (I2C_READ) < 0) if (i2c_wait (I2C_READ) < 0)
...@@ -169,13 +255,13 @@ __i2c_read (u8 *data, int length) ...@@ -169,13 +255,13 @@ __i2c_read (u8 *data, int length)
if (i == length - 2) if (i == length - 2)
writeb(I2C_CR_MEN | I2C_CR_MSTA | writeb(I2C_CR_MEN | I2C_CR_MSTA |
I2C_CR_TXAK, I2C_CR_TXAK,
&I2C->cr); &i2c_dev->cr);
/* Generate stop on last byte */ /* Generate stop on last byte */
if (i == length - 1) 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; return i;
} }
...@@ -201,7 +287,7 @@ i2c_read (u8 dev, uint addr, int alen, u8 *data, int length) ...@@ -201,7 +287,7 @@ i2c_read (u8 dev, uint addr, int alen, u8 *data, int length)
i = __i2c_read (data, length); i = __i2c_read (data, length);
exit: exit:
writeb(I2C_CR_MEN, &I2C->cr); writeb(I2C_CR_MEN, &i2c_dev->cr);
return !(i == length); return !(i == length);
} }
...@@ -223,7 +309,7 @@ i2c_write (u8 dev, uint addr, int alen, u8 *data, int length) ...@@ -223,7 +309,7 @@ i2c_write (u8 dev, uint addr, int alen, u8 *data, int length)
i = __i2c_write (data, length); i = __i2c_write (data, length);
exit: exit:
writeb(I2C_CR_MEN, &I2C->cr); writeb(I2C_CR_MEN, &i2c_dev->cr);
return !(i == length); return !(i == length);
} }
...@@ -254,4 +340,38 @@ void i2c_reg_write (uchar i2c_addr, uchar reg, uchar val) ...@@ -254,4 +340,38 @@ void i2c_reg_write (uchar i2c_addr, uchar reg, uchar val)
i2c_write (i2c_addr, reg, 1, &val, 1); 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 */ #endif /* CONFIG_HARD_I2C */
...@@ -79,6 +79,12 @@ typedef struct i2c ...@@ -79,6 +79,12 @@ typedef struct i2c
#endif #endif
#define I2C_TIMEOUT (CFG_HZ/4) #define I2C_TIMEOUT (CFG_HZ/4)
enum I2C_BUS_NUM
{
I2C_BUS_1 = 0,
I2C_BUS_2,
};
#ifndef CFG_IMMRBAR #ifndef CFG_IMMRBAR
#error CFG_IMMRBAR is not defined in /include/configs/${BOARD}.h #error CFG_IMMRBAR is not defined in /include/configs/${BOARD}.h
#endif #endif
...@@ -87,15 +93,12 @@ typedef struct i2c ...@@ -87,15 +93,12 @@ typedef struct i2c
#error CFG_I2C_OFFSET is not defined in /include/configs/${BOARD}.h #error CFG_I2C_OFFSET is not defined in /include/configs/${BOARD}.h
#endif #endif
#if defined(CONFIG_MPC8349EMDS) || defined(CONFIG_TQM834X) #define I2C_1 ((i2c_t*)(CFG_IMMRBAR + CFG_I2C_OFFSET))
/*
* MPC8349 have two i2c bus /* Optional support for second I2C bus */
*/ #ifdef CFG_I2C2_OFFSET
extern i2c_t * mpc83xx_i2c; #define I2C_2 ((i2c_t*)(CFG_IMMRBAR + CFG_I2C2_OFFSET))
#define I2C mpc83xx_i2c #endif /* CFG_I2C2_OFFSET */
#else
#define I2C ((i2c_t*)(CFG_IMMRBAR + CFG_I2C_OFFSET))
#endif
#define I2C_READ 1 #define I2C_READ 1
#define I2C_WRITE 0 #define I2C_WRITE 0
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
* High Level Configuration Options * High Level Configuration Options
*/ */
#define CONFIG_E300 1 /* E300 Family */ #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_MPC8349 1 /* MPC8349 specific */
#define CONFIG_MPC8349EMDS 1 /* MPC8349EMDS board specific */ #define CONFIG_MPC8349EMDS 1 /* MPC8349EMDS board specific */
...@@ -311,9 +311,11 @@ ...@@ -311,9 +311,11 @@
/* I2C */ /* I2C */
#define CONFIG_HARD_I2C /* I2C with hardware support*/ #define CONFIG_HARD_I2C /* I2C with hardware support*/
#undef CONFIG_SOFT_I2C /* I2C bit-banged */ #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_SPEED 400000 /* I2C speed and slave address */
#define CFG_I2C_SLAVE 0x7F #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_I2C_OFFSET 0x3000
#define CFG_I2C2_OFFSET 0x3100 #define CFG_I2C2_OFFSET 0x3100
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册