From 9ca880a250870a7d55754291b5591d2b5fe89b54 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Tue, 31 Oct 2006 21:23:16 -0600 Subject: mpc83xx: Fix dual I2C support for the MPC8349ITX, MPC8349EMDS, TQM834x, and MPC8360EMDS This patch also adds an improved I2C set_speed(), which handles all clock frequencies. Signed-off-by: Timur Tabi --- board/mpc8349emds/pci.c | 8 +- board/mpc8349itx/mpc8349itx.c | 6 +- board/mpc8349itx/pci.c | 2 +- board/mpc8360emds/pci.c | 11 ++- cpu/mpc83xx/i2c.c | 214 +++++++++++++++++++++++++----------------- include/asm-ppc/i2c.h | 10 +- include/configs/MPC8349ITX.h | 2 +- include/configs/TQM834x.h | 2 +- include/i2c.h | 8 +- 9 files changed, 154 insertions(+), 109 deletions(-) diff --git a/board/mpc8349emds/pci.c b/board/mpc8349emds/pci.c index a916245aea..93827f11d8 100644 --- a/board/mpc8349emds/pci.c +++ b/board/mpc8349emds/pci.c @@ -75,10 +75,8 @@ pib_init(void) /* Switch temporarily to I2C bus #2 */ orig_i2c_bus = i2c_get_bus_num(); - if(orig_i2c_bus != I2C_BUS_2) - i2c_set_bus_num(I2C_BUS_2); - - i2c_init(CFG_I2C_SPEED, CFG_I2C_SLAVE); + if(orig_i2c_bus != 2) + i2c_set_bus_num(2); val8 = 0; i2c_write(0x23, 0x6, 1, &val8, 1); @@ -124,7 +122,7 @@ pib_init(void) printf("PCI2: 32-bit on PMC3\n"); #endif /* Reset to original I2C bus */ - if(orig_i2c_bus != I2C_BUS_2) + if(orig_i2c_bus != 2) i2c_set_bus_num(orig_i2c_bus); } diff --git a/board/mpc8349itx/mpc8349itx.c b/board/mpc8349itx/mpc8349itx.c index 9a5cbec858..4662645886 100644 --- a/board/mpc8349itx/mpc8349itx.c +++ b/board/mpc8349itx/mpc8349itx.c @@ -259,7 +259,7 @@ int checkboard(void) puts("Board: Freescale MPC8349E-mITX"); #ifdef CONFIG_HARD_I2C - i2c_set_bus_num(I2C_BUS_2); + i2c_set_bus_num(2); if (i2c_read(CFG_I2C_8574A_ADDR2, 0, 0, &i2c_data, sizeof(i2c_data)) == 0) printf(" %u.%u (PCF8475A)", (i2c_data & 0x02) >> 1, @@ -379,7 +379,7 @@ int misc_init_r(void) u8 data[sizeof(eeprom_data)]; - i2c_set_bus_num(I2C_BUS_1); + i2c_set_bus_num(1); if (i2c_read(CFG_I2C_EEPROM_ADDR, 0, 2, data, sizeof(data)) == 0) { if (memcmp(data, eeprom_data, sizeof(data)) != 0) { @@ -397,7 +397,7 @@ int misc_init_r(void) #endif #ifdef CFG_I2C_RTC_ADDR - i2c_set_bus_num(I2C_BUS_2); + i2c_set_bus_num(2); if (i2c_read(CFG_I2C_RTC_ADDR, 0, 1, ds1339_data, sizeof(ds1339_data)) == 0) { diff --git a/board/mpc8349itx/pci.c b/board/mpc8349itx/pci.c index acac185d54..cf07020b62 100644 --- a/board/mpc8349itx/pci.c +++ b/board/mpc8349itx/pci.c @@ -105,7 +105,7 @@ void pci_init_board(void) udelay(2000); #ifdef CONFIG_HARD_I2C - i2c_set_bus_num(I2C_BUS_2); + i2c_set_bus_num(2); /* Read the PCI_M66EN jumper setting */ if ((i2c_read(CFG_I2C_8574_ADDR2, 0, 0, ®8, sizeof(reg8)) == 0) || (i2c_read(CFG_I2C_8574A_ADDR2, 0, 0, ®8, sizeof(reg8)) == 0)) { diff --git a/board/mpc8360emds/pci.c b/board/mpc8360emds/pci.c index 880b2ecc3e..64ea50979d 100644 --- a/board/mpc8360emds/pci.c +++ b/board/mpc8360emds/pci.c @@ -198,8 +198,11 @@ void pci_init_board(void) * Assign PIB PMC slot to desired PCI bus */ - mpc83xx_i2c = (i2c_t *) (CFG_IMMRBAR + CFG_I2C2_OFFSET); - i2c_init(CFG_I2C_SPEED, CFG_I2C_SLAVE); + /* Switch temporarily to I2C bus #2 */ + orig_i2c_bus = i2c_get_bus_num(); + + if(orig_i2c_bus != 2) + i2c_set_bus_num(2); val8 = 0; i2c_write(0x23, 0x6, 1, &val8, 1); @@ -227,6 +230,10 @@ void pci_init_board(void) i2c_write(0x27, 0x3, 1, &val8, 1); asm("eieio"); + /* Reset to original I2C bus */ + if(orig_i2c_bus != 2) + i2c_set_bus_num(orig_i2c_bus); + /* * Release PCI RST Output signal */ diff --git a/cpu/mpc83xx/i2c.c b/cpu/mpc83xx/i2c.c index fc89fb1e25..ce78491616 100644 --- a/cpu/mpc83xx/i2c.c +++ b/cpu/mpc83xx/i2c.c @@ -47,75 +47,121 @@ 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; +#ifndef CFG_SPD_BUS_NUM +#define CFG_SPD_BUS_NUM 1 +#endif + +static unsigned int i2c_bus_num = CFG_SPD_BUS_NUM; + +#if CFG_SPD_BUS_NUM == 1 +static volatile i2c_t *i2c_dev = I2C_1; #else -static i2c_t *i2c_dev = I2C_1; +static volatile i2c_t *i2c_dev = I2C_2; #endif -static uchar busNum = I2C_BUS_1 ; -static int bus_speed[2] = {0, 0}; +static int i2c_bus_speed[2] = {0, 0}; -static int set_speed(int speed) +/* + * Map the frequency divider to the FDR. This data is taken from table 17-5 + * of the MPC8349EA reference manual, with duplicates removed. + */ +static struct { + unsigned int divider; + u8 fdr; +} i2c_speed_map[] = { - 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; + {0, 0x20}, + {256, 0x20}, + {288, 0x21}, + {320, 0x22}, + {352, 0x23}, + {384, 0x24}, + {416, 0x01}, + {448, 0x25}, + {480, 0x02}, + {512, 0x26}, + {576, 0x27}, + {640, 0x28}, + {704, 0x05}, + {768, 0x29}, + {832, 0x06}, + {896, 0x2A}, + {1024, 0x2B}, + {1152, 0x08}, + {1280, 0x2C}, + {1536, 0x2D}, + {1792, 0x2E}, + {1920, 0x0B}, + {2048, 0x2F}, + {2304, 0x0C}, + {2560, 0x30}, + {3072, 0x31}, + {3584, 0x32}, + {3840, 0x0F}, + {4096, 0x33}, + {4608, 0x10}, + {5120, 0x34}, + {6144, 0x35}, + {7168, 0x36}, + {7680, 0x13}, + {8192, 0x37}, + {9216, 0x14}, + {10240, 0x38}, + {12288, 0x39}, + {14336, 0x3A}, + {15360, 0x17}, + {16384, 0x3B}, + {18432, 0x18}, + {20480, 0x3C}, + {24576, 0x3D}, + {28672, 0x3E}, + {30720, 0x1B}, + {32768, 0x3F}, + {36864, 0x1C}, + {40960, 0x1D}, + {49152, 0x1E}, + {61440, 0x1F}, + {-1, 0x1F} +}; + +#define NUM_I2C_SPEEDS (sizeof(i2c_speed_map) / sizeof(i2c_speed_map[0])) + +static int set_speed(unsigned int speed) +{ + unsigned long i2c_clk; + unsigned int divider, i; + u8 fdr = 0x3F; + + i2c_clk = (i2c_bus_num == 2) ? gd->i2c2_clk : gd->i2c1_clk; + + divider = i2c_clk / speed; + + /* Scan i2c_speed_map[] for the closest matching divider.*/ + + for (i = 0; i < NUM_I2C_SPEEDS-1; i++) { + /* Locate our divider in between two entries in i2c_speed_map[] */ + if ((divider >= i2c_speed_map[i].divider) && + (divider <= i2c_speed_map[i+1].divider)) { + /* Which one is closer? */ + if ((divider - i2c_speed_map[i].divider) < (i2c_speed_map[i+1].divider - divider)) { + fdr = i2c_speed_map[i].fdr; + } else { + fdr = i2c_speed_map[i+1].fdr; + } + break; + } + } + + writeb(fdr, &i2c_dev->fdr); + i2c_bus_speed[i2c_bus_num - 1] = speed; + + return 0; } @@ -125,16 +171,16 @@ static void _i2c_init(int speed, int slaveadd) writeb(0x00 , &i2c_dev->cr); /* set clock */ - writeb(speed, &i2c_dev->fdr); + set_speed(speed); /* set default filter */ - writeb(0x10,&i2c_dev->dfsrr); + writeb(IC2_FDR,&i2c_dev->dfsrr); /* write slave address */ writeb(slaveadd, &i2c_dev->adr); /* clear status register */ - writeb(0x00, &i2c_dev->sr); + writeb(I2C_CR_MTX, &i2c_dev->sr); /* start I2C controller */ writeb(I2C_CR_MEN, &i2c_dev->cr); @@ -142,19 +188,19 @@ static void _i2c_init(int speed, int slaveadd) 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 */ + /* 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(1); + _i2c_init(speed, slaveadd); +#ifdef CFG_I2C2_OFFSET + i2c_set_bus_num(2); + _i2c_init(speed, slaveadd); + i2c_set_bus_num(1); +#endif /* CFG_I2C2_OFFSET */ } static __inline__ int @@ -340,38 +386,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) +int i2c_set_bus_num(unsigned int bus) { - if(bus == I2C_BUS_1) + if(bus == 1) { i2c_dev = I2C_1; } #ifdef CFG_I2C2_OFFSET - else if(bus == I2C_BUS_2) + else if(bus == 2) { i2c_dev = I2C_2; } -#endif /* CFG_I2C2_OFFSET */ +#endif else { return -1; } - busNum = bus; + i2c_bus_num = bus; return 0; } -int i2c_set_bus_speed(int speed) +int i2c_set_bus_speed(unsigned int speed) { return set_speed(speed); } -uchar i2c_get_bus_num(void) +unsigned int i2c_get_bus_num(void) { - return busNum; + return i2c_bus_num; } -int i2c_get_bus_speed(void) +unsigned int i2c_get_bus_speed(void) { - return bus_speed[busNum]; + return i2c_bus_speed[i2c_bus_num - 1]; } #endif /* CONFIG_HARD_I2C */ diff --git a/include/asm-ppc/i2c.h b/include/asm-ppc/i2c.h index baf9d9a262..8afdda2ce2 100644 --- a/include/asm-ppc/i2c.h +++ b/include/asm-ppc/i2c.h @@ -79,12 +79,6 @@ 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 @@ -96,9 +90,9 @@ enum I2C_BUS_NUM #define I2C_1 ((i2c_t*)(CFG_IMMRBAR + CFG_I2C_OFFSET)) /* Optional support for second I2C bus */ -#ifdef CFG_I2C2_OFFSET +#ifdef CFG_I2C2_OFFSET #define I2C_2 ((i2c_t*)(CFG_IMMRBAR + CFG_I2C2_OFFSET)) -#endif /* CFG_I2C2_OFFSET */ +#endif /* CFG_I2C2_OFFSET */ #define I2C_READ 1 #define I2C_WRITE 0 diff --git a/include/configs/MPC8349ITX.h b/include/configs/MPC8349ITX.h index 20f3c6d399..2fbc736182 100644 --- a/include/configs/MPC8349ITX.h +++ b/include/configs/MPC8349ITX.h @@ -81,7 +81,7 @@ #define CONFIG_I2C_CMD_TREE #define CFG_I2C_OFFSET 0x3000 #define CFG_I2C2_OFFSET 0x3100 -#define CFG_SPD_BUS_NUM I2C_2 +#define CFG_SPD_BUS_NUM 2 #define CFG_I2C_8574_ADDR1 0x20 /* I2C2, PCF8574 */ #define CFG_I2C_8574_ADDR2 0x21 /* I2C2, PCF8574 */ diff --git a/include/configs/TQM834x.h b/include/configs/TQM834x.h index f0e49007d0..727094b203 100644 --- a/include/configs/TQM834x.h +++ b/include/configs/TQM834x.h @@ -36,8 +36,8 @@ */ #define CONFIG_E300 1 /* E300 Family */ #define CONFIG_MPC83XX 1 /* MPC83XX family */ -#define CONFIG_MPC8349 1 /* MPC8349 specific */ #define CONFIG_MPC834X 1 /* MPC834X specific */ +#define CONFIG_MPC8349 1 /* MPC8349 specific */ #define CONFIG_TQM834X 1 /* TQM834X board specific */ /* IMMR Base Addres Register, use Freescale default: 0xff400000 */ diff --git a/include/i2c.h b/include/i2c.h index 97e006163a..a8f729afe0 100644 --- a/include/i2c.h +++ b/include/i2c.h @@ -97,7 +97,7 @@ void i2c_reg_write(uchar chip, uchar reg, uchar val); * Returns: 0 on success, not 0 on failure * */ -int i2c_set_bus_num(uchar bus); +int i2c_set_bus_num(unsigned int bus); /* * i2c_get_bus_num: @@ -105,7 +105,7 @@ int i2c_set_bus_num(uchar bus); * Returns index of currently active I2C bus. Zero-based. */ -uchar i2c_get_bus_num(void); +unsigned int i2c_get_bus_num(void); /* * i2c_set_bus_speed: @@ -117,7 +117,7 @@ uchar i2c_get_bus_num(void); * Returns: 0 on success, not 0 on failure * */ -int i2c_set_bus_speed(int); +int i2c_set_bus_speed(unsigned int); /* * i2c_get_bus_speed: @@ -125,6 +125,6 @@ int i2c_set_bus_speed(int); * Returns speed of currently active I2C bus in Hz */ -int i2c_get_bus_speed(void); +unsigned int i2c_get_bus_speed(void); #endif /* _I2C_H_ */ -- cgit v1.2.3