
diff -purN u-boot.orig/common/cmd_i2c.c u-boot/common/cmd_i2c.c --- u-boot.orig/common/cmd_i2c.c 2008-11-25 16:41:07.000000000 -0800 +++ u-boot/common/cmd_i2c.c 2009-01-23 16:01:48.000000000 -0800 @@ -1,4 +1,9 @@ /* + * (C) Copyright 2009 + * Sergey Kubushyn, himself, ksi@koi8.net + * + * Changes for unified multibus/multiadapter I2C support. + * * (C) Copyright 2001 * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com. * @@ -106,7 +111,7 @@ static uint i2c_mm_last_alen; * pairs. The following macros take care of this */
#if defined(CONFIG_SYS_I2C_NOPROBES) -#if defined(CONFIG_I2C_MULTI_BUS) +#if CONFIG_SYS_NUM_I2C_BUSSES > 1 static struct { uchar bus; @@ -122,19 +127,11 @@ static uchar i2c_no_probes[] = CONFIG_SY #define COMPARE_BUS(b,i) ((b) == 0) /* Make compiler happy */ #define COMPARE_ADDR(a,i) (i2c_no_probes[(i)] == (a)) #define NO_PROBE_ADDR(i) i2c_no_probes[(i)] -#endif /* CONFIG_MULTI_BUS */ +#endif /* CONFIG_SYS_NUM_I2C_BUSSES > 1 */
#define NUM_ELEMENTS_NOPROBE (sizeof(i2c_no_probes)/sizeof(i2c_no_probes[0])) #endif
-#if defined(CONFIG_I2C_MUX) -static I2C_MUX_DEVICE *i2c_mux_devices = NULL; -static int i2c_mux_busid = CONFIG_SYS_MAX_I2C_BUS; - -DECLARE_GLOBAL_DATA_PTR; - -#endif - static int mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char *argv[]);
@@ -548,10 +545,10 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrfl */ int do_i2c_probe (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { - int j; + int j; #if defined(CONFIG_SYS_I2C_NOPROBES) - int k, skip; - uchar bus = GET_BUS_NUM; + int k, skip; + unsigned int bus = GET_BUS_NUM; #endif /* NOPROBES */
puts ("Valid chip addresses:"); @@ -1189,59 +1186,79 @@ int do_sdram (cmd_tbl_t * cmdtp, int fla #if defined(CONFIG_I2C_CMD_TREE) int do_i2c_reset(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) { - i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + i2c_init (ADAP(i2c_get_bus_num())->speed, ADAP(i2c_get_bus_num())->slaveaddr); return 0; }
-#if defined(CONFIG_I2C_MUX) -int do_i2c_add_bus(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +int do_i2c_show_bus(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) { - int ret=0; + int i; +#ifndef CONFIG_SYS_I2C_DIRECT_BUS + int j; +#endif
if (argc == 1) { /* show all busses */ - I2C_MUX *mux; - I2C_MUX_DEVICE *device = i2c_mux_devices; - - printf ("Busses reached over muxes:\n"); - while (device != NULL) { - printf ("Bus ID: %x\n", device->busid); - printf (" reached over Mux(es):\n"); - mux = device->mux; - while (mux != NULL) { - printf (" %s@%x ch: %x\n", mux->name, mux->chip, mux->channel); - mux = mux->next; + for (i = 0; i < CONFIG_SYS_NUM_I2C_BUSSES; i++) { + printf("Bus %d:\t%s", i, ADAP(i)->name); +#ifndef CONFIG_SYS_I2C_DIRECT_BUS + for (j = 0; j < CONFIG_SYS_I2C_MAX_HOPS; j++) { + if (i2c_bus[i].next_hop[j].chip == 0) break; + printf("->%s@0x%2x:%d", + i2c_bus[i].next_hop[j].mux.name, + i2c_bus[i].next_hop[j].chip, + i2c_bus[i].next_hop[j].channel); } - device = device->next; +#endif + printf("\n"); } - } else { - I2C_MUX_DEVICE *dev;
- dev = i2c_mux_ident_muxstring ((uchar *)argv[1]); - ret = 0; + } else { + /* show specific bus */ + i = simple_strtoul(argv[1], NULL, 10); + if (i >= CONFIG_SYS_NUM_I2C_BUSSES) { + printf("Invalid bus %d\n", i); + return(-1); + } + printf("Bus %d:\t%s", i, ADAP(i)->name); +#ifndef CONFIG_SYS_I2C_DIRECT_BUS + for (j = 0; j < CONFIG_SYS_I2C_MAX_HOPS; j++) { + if (i2c_bus[i].next_hop[j].chip == 0) break; + printf("->%s@0x%2x:%d", + i2c_bus[i].next_hop[j].mux.name, + i2c_bus[i].next_hop[j].chip, + i2c_bus[i].next_hop[j].channel); + } +#endif + printf("\n"); } - return ret; + + return(0); } -#endif /* CONFIG_I2C_MUX */
-#if defined(CONFIG_I2C_MULTI_BUS) +#if CONFIG_SYS_NUM_I2C_BUSSES > 1 int do_i2c_bus_num(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) { - int bus_idx, ret=0; + int ret=0; + unsigned int bus_no;
if (argc == 1) /* querying current setting */ printf("Current bus is %d\n", i2c_get_bus_num()); else { - bus_idx = simple_strtoul(argv[1], NULL, 10); - printf("Setting bus to %d\n", bus_idx); - ret = i2c_set_bus_num(bus_idx); + bus_no = simple_strtoul(argv[1], NULL, 10); + if (bus_no >= CONFIG_SYS_NUM_I2C_BUSSES) { + printf("Invalid bus %d\n", bus_no); + return(-1); + } + printf("Setting bus to %d\n", bus_no); + ret = i2c_set_bus_num(bus_no); if (ret) printf("Failure changing bus number (%d)\n", ret); } return ret; } -#endif /* CONFIG_I2C_MULTI_BUS */ +#endif /* CONFIG_SYS_NUM_I2C_BUSSES > 1 */
int do_i2c_bus_speed(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) { @@ -1262,16 +1279,16 @@ int do_i2c_bus_speed(cmd_tbl_t * cmdtp,
int do_i2c(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) { -#if defined(CONFIG_I2C_MUX) +#if CONFIG_SYS_NUM_I2C_BUSSES > 1 if (!strncmp(argv[1], "bu", 2)) - return do_i2c_add_bus(cmdtp, flag, --argc, ++argv); -#endif /* CONFIG_I2C_MUX */ + return do_i2c_show_bus(cmdtp, flag, --argc, ++argv); +#endif /* CONFIG_SYS_NUM_I2C_BUSSES > 1 */ if (!strncmp(argv[1], "sp", 2)) return do_i2c_bus_speed(cmdtp, flag, --argc, ++argv); -#if defined(CONFIG_I2C_MULTI_BUS) +#if CONFIG_SYS_NUM_I2C_BUSSES > 1 if (!strncmp(argv[1], "de", 2)) return do_i2c_bus_num(cmdtp, flag, --argc, ++argv); -#endif /* CONFIG_I2C_MULTI_BUS */ +#endif /* CONFIG_SYS_NUM_I2C_BUSSES > 1 */ if (!strncmp(argv[1], "md", 2)) return do_i2c_md(cmdtp, flag, --argc, ++argv); if (!strncmp(argv[1], "mm", 2)) @@ -1304,13 +1321,11 @@ int do_i2c(cmd_tbl_t * cmdtp, int flag, U_BOOT_CMD( i2c, 6, 1, do_i2c, "i2c - I2C sub-system\n", -#if defined(CONFIG_I2C_MUX) - "bus [muxtype:muxaddr:muxchannel] - add a new bus reached over muxes.\n" -#endif /* CONFIG_I2C_MUX */ - "speed [speed] - show or set I2C bus speed\n" -#if defined(CONFIG_I2C_MULTI_BUS) +#if CONFIG_SYS_NUM_I2C_BUSSES > 1 + "bus [bus_no] - show I2C bus info.\n" "i2c dev [dev] - show or set current I2C bus\n" -#endif /* CONFIG_I2C_MULTI_BUS */ +#endif /* CONFIG_SYS_NUM_I2C_BUSSES > 1 */ + "i2c speed [speed] - show or set I2C bus speed\n" "i2c md chip address[.0, .1, .2] [# of objects] - read from I2C device\n" "i2c mm chip address[.0, .1, .2] - write to I2C device (auto-incrementing)\n" "i2c mw chip address[.0, .1, .2] value [count] - write to I2C device (fill)\n" @@ -1323,7 +1338,7 @@ U_BOOT_CMD( "i2c sdram chip - print SDRAM configuration information\n" #endif ); -#endif /* CONFIG_I2C_CMD_TREE */ +#else /* CONFIG_I2C_CMD_TREE */ U_BOOT_CMD( imd, 4, 1, do_i2c_md, \ "imd - i2c memory display\n", \ @@ -1378,221 +1393,4 @@ U_BOOT_CMD( " (valid chip values 50..57)\n" ); #endif - -#if defined(CONFIG_I2C_MUX) - -int i2c_mux_add_device(I2C_MUX_DEVICE *dev) -{ - I2C_MUX_DEVICE *devtmp = i2c_mux_devices; - - if (i2c_mux_devices == NULL) { - i2c_mux_devices = dev; - return 0; - } - while (devtmp->next != NULL) - devtmp = devtmp->next; - - devtmp->next = dev; - return 0; -} - -I2C_MUX_DEVICE *i2c_mux_search_device(int id) -{ - I2C_MUX_DEVICE *device = i2c_mux_devices; - - while (device != NULL) { - if (device->busid == id) - return device; - device = device->next; - } - return NULL; -} - -/* searches in the buf from *pos the next ':'. - * returns: - * 0 if found (with *pos = where) - * < 0 if an error occured - * > 0 if the end of buf is reached - */ -static int i2c_mux_search_next (int *pos, uchar *buf, int len) -{ - while ((buf[*pos] != ':') && (*pos < len)) { - *pos += 1; - } - if (*pos >= len) - return 1; - if (buf[*pos] != ':') - return -1; - return 0; -} - -static int i2c_mux_get_busid (void) -{ - int tmp = i2c_mux_busid; - - i2c_mux_busid ++; - return tmp; -} - -/* Analyses a Muxstring and sends immediately the - Commands to the Muxes. Runs from Flash. - */ -int i2c_mux_ident_muxstring_f (uchar *buf) -{ - int pos = 0; - int oldpos; - int ret = 0; - int len = strlen((char *)buf); - int chip; - uchar channel; - int was = 0; - - while (ret == 0) { - oldpos = pos; - /* search name */ - ret = i2c_mux_search_next(&pos, buf, len); - if (ret != 0) - printf ("ERROR\n"); - /* search address */ - pos ++; - oldpos = pos; - ret = i2c_mux_search_next(&pos, buf, len); - if (ret != 0) - printf ("ERROR\n"); - buf[pos] = 0; - chip = simple_strtoul((char *)&buf[oldpos], NULL, 16); - buf[pos] = ':'; - /* search channel */ - pos ++; - oldpos = pos; - ret = i2c_mux_search_next(&pos, buf, len); - if (ret < 0) - printf ("ERROR\n"); - was = 0; - if (buf[pos] != 0) { - buf[pos] = 0; - was = 1; - } - channel = simple_strtoul((char *)&buf[oldpos], NULL, 16); - if (was) - buf[pos] = ':'; - if (i2c_write(chip, 0, 0, &channel, 1) != 0) { - printf ("Error setting Mux: chip:%x channel: \ - %x\n", chip, channel); - return -1; - } - pos ++; - oldpos = pos; - - } - - return 0; -} - -/* Analyses a Muxstring and if this String is correct - * adds a new I2C Bus. - */ -I2C_MUX_DEVICE *i2c_mux_ident_muxstring (uchar *buf) -{ - I2C_MUX_DEVICE *device; - I2C_MUX *mux; - int pos = 0; - int oldpos; - int ret = 0; - int len = strlen((char *)buf); - int was = 0; - - device = (I2C_MUX_DEVICE *)malloc (sizeof(I2C_MUX_DEVICE)); - device->mux = NULL; - device->busid = i2c_mux_get_busid (); - device->next = NULL; - while (ret == 0) { - mux = (I2C_MUX *)malloc (sizeof(I2C_MUX)); - mux->next = NULL; - /* search name of mux */ - oldpos = pos; - ret = i2c_mux_search_next(&pos, buf, len); - if (ret != 0) - printf ("%s no name.\n", __FUNCTION__); - mux->name = (char *)malloc (pos - oldpos + 1); - memcpy (mux->name, &buf[oldpos], pos - oldpos); - mux->name[pos - oldpos] = 0; - /* search address */ - pos ++; - oldpos = pos; - ret = i2c_mux_search_next(&pos, buf, len); - if (ret != 0) - printf ("%s no mux address.\n", __FUNCTION__); - buf[pos] = 0; - mux->chip = simple_strtoul((char *)&buf[oldpos], NULL, 16); - buf[pos] = ':'; - /* search channel */ - pos ++; - oldpos = pos; - ret = i2c_mux_search_next(&pos, buf, len); - if (ret < 0) - printf ("%s no mux channel.\n", __FUNCTION__); - was = 0; - if (buf[pos] != 0) { - buf[pos] = 0; - was = 1; - } - mux->channel = simple_strtoul((char *)&buf[oldpos], NULL, 16); - if (was) - buf[pos] = ':'; - if (device->mux == NULL) - device->mux = mux; - else { - I2C_MUX *muxtmp = device->mux; - while (muxtmp->next != NULL) { - muxtmp = muxtmp->next; - } - muxtmp->next = mux; - } - pos ++; - oldpos = pos; - } - if (ret > 0) { - /* Add Device */ - i2c_mux_add_device (device); - return device; - } - - return NULL; -} - -int i2x_mux_select_mux(int bus) -{ - I2C_MUX_DEVICE *dev; - I2C_MUX *mux; - - if ((gd->flags & GD_FLG_RELOC) != GD_FLG_RELOC) { - /* select Default Mux Bus */ -#if defined(CONFIG_SYS_I2C_IVM_BUS) - i2c_mux_ident_muxstring_f ((uchar *)CONFIG_SYS_I2C_IVM_BUS); -#else - { - unsigned char *buf; - buf = (unsigned char *) getenv("EEprom_ivm"); - if (buf != NULL) - i2c_mux_ident_muxstring_f (buf); - } -#endif - return 0; - } - dev = i2c_mux_search_device(bus); - if (dev == NULL) - return -1; - - mux = dev->mux; - while (mux != NULL) { - if (i2c_write(mux->chip, 0, 0, &mux->channel, 1) != 0) { - printf ("Error setting Mux: chip:%x channel: \ - %x\n", mux->chip, mux->channel); - return -1; - } - mux = mux->next; - } - return 0; -} -#endif /* CONFIG_I2C_MUX */ +#endif /* CONFIG_I2C_CMD_TREE */ diff -purN u-boot.orig/common/devices.c u-boot/common/devices.c --- u-boot.orig/common/devices.c 2008-10-20 13:59:38.000000000 -0700 +++ u-boot/common/devices.c 2009-01-23 16:01:48.000000000 -0800 @@ -1,4 +1,8 @@ /* + * Copyright (C) 2009 Sergey Kubushyn ksi@koi8.net + * + * Changes for multibus/multiadapter I2C support. + * * (C) Copyright 2000 * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it * @@ -30,7 +34,7 @@ #ifdef CONFIG_LOGBUFFER #include <logbuff.h> #endif -#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C) +#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C) || defined(CONFIG_SYS_I2C_ADAPTERS) #include <i2c.h> #endif
@@ -215,9 +219,15 @@ int devices_init (void) /* Initialize the list */ INIT_LIST_HEAD(&(devs.list));
+#ifdef CONFIG_NEW_I2C +#ifdef CONFIG_SYS_I2C_ADAPTERS + i2c_init_all(); +#endif +#else #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C) i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); #endif +#endif #ifdef CONFIG_LCD drv_lcd_init (); #endif diff -purN u-boot.orig/drivers/i2c/i2c_core.c u-boot/drivers/i2c/i2c_core.c --- u-boot.orig/drivers/i2c/i2c_core.c 1969-12-31 16:00:00.000000000 -0800 +++ u-boot/drivers/i2c/i2c_core.c 2009-01-23 16:01:48.000000000 -0800 @@ -0,0 +1,335 @@ +/* + * Copyright (C) 2009 Sergey Kubushyn ksi@koi8.net + * + * Multibus/multiadapter I2C core functions (wrappers) + */ +#include <common.h> +#include <i2c.h> + +#ifdef CONFIG_FSL_UNI_I2C +extern i2c_adap_t fsl_i2c_adap[]; +#endif + +#ifdef CONFIG_SM502_I2C +extern i2c_adap_t sm501_i2c_adap; +#endif + +i2c_adap_t *i2c_adap[CONFIG_SYS_NUM_I2C_ADAPTERS] = CONFIG_SYS_I2C_ADAPTERS; +#ifndef CONFIG_SYS_I2C_DIRECT_BUS +i2c_bus_t i2c_bus[CONFIG_SYS_NUM_I2C_BUSSES] = CONFIG_SYS_I2C_BUSSES; +#endif + +static unsigned int i2c_cur_bus __attribute__ ((section (".data"))) = CONFIG_SYS_SPD_BUS_NUM; + +DECLARE_GLOBAL_DATA_PTR; + +void i2c_reloc_fixup(void) +{ + int i; + unsigned long addr; + + /* Adapters */ + for (i = 0; i < CONFIG_SYS_NUM_I2C_ADAPTERS; i++) { + /* Adapter itself */ + addr = (unsigned long)i2c_adap[i]; + if (addr != 0) addr += gd->reloc_off; + i2c_adap[i] = (i2c_adap_t *)addr; + /* i2c_init() */ + addr = (unsigned long)i2c_adap[i]->init; + if (addr != 0) addr += gd->reloc_off; + i2c_adap[i]->init = (void (*)(int, int))addr; + /* i2c_probe() */ + addr = (unsigned long)i2c_adap[i]->probe; + if (addr != 0) addr += gd->reloc_off; + i2c_adap[i]->probe = (int (*)(u_int8_t))addr; + /* i2c_read() */ + addr = (unsigned long)i2c_adap[i]->read; + if (addr != 0) addr += gd->reloc_off; + i2c_adap[i]->read = (int (*)(u_int8_t, uint, int, u_int8_t *, int))addr; + /* i2c_write() */ + addr = (unsigned long)i2c_adap[i]->write; + if (addr != 0) addr += gd->reloc_off; + i2c_adap[i]->write = (int (*)(u_int8_t, uint, int, u_int8_t *, int))addr; + /* i2c_set_bus_speed() */ + addr = (unsigned long)i2c_adap[i]->set_bus_speed; + if (addr != 0) addr += gd->reloc_off; + i2c_adap[i]->set_bus_speed = (uint (*)(uint))addr; + /* i2c_get_bus_speed() */ + addr = (unsigned long)i2c_adap[i]->get_bus_speed; + if (addr != 0) addr += gd->reloc_off; + i2c_adap[i]->get_bus_speed = (uint (*)(void))addr; + /* name */ + addr = (unsigned long)i2c_adap[i]->name; + if (addr != 0) addr += gd->reloc_off; + i2c_adap[i]->name = (char *)addr; + } +} + +#ifndef CONFIG_SYS_I2C_DIRECT_BUS +/* + * i2c_mux_set() + * ------------- + * + * This turns on the given channel on I2C multiplexer chip connected to + * a given I2C adapter directly or via other multiplexers. In the latter + * case the entire multiplexer chain must be initialized first starting + * with the one connected directly to the adapter. When disabling a chain + * muxes must be programmed in reverse order, starting with the one + * farthest from the adapter. + * + * mux_id is the multiplexer chip type from defined in i2c.h. So far only + * NXP (Philips) PCA954x multiplexers are supported. Switches are NOT + * supported (anybody uses them?) + */ + +static int i2c_mux_set(int adapter, int mux_id, int chip, int channel) +{ + u_int8_t buf; + + /* channel < 0 - turn off the mux */ + if (channel < 0) { + buf = 0; + return(i2c_adap[adapter]->write(chip, 0, 0, &buf, 1)); + } + + switch (mux_id) { + case I2C_MUX_PCA9540_ID: + case I2C_MUX_PCA9542_ID: + if (channel > 1) return(-1); + buf = (u_int8_t)((channel & 0x01) | (1 << 2)); + break; + case I2C_MUX_PCA9544_ID: + if (channel > 3) return(-1); + buf = (u_int8_t)((channel & 0x03) | (1 << 2)); + break; + case I2C_MUX_PCA9547_ID: + if (channel > 7) return(-1); + buf = (u_int8_t)((channel & 0x07) | (1 << 3)); + break; + default: + return(-1); + } + + return(i2c_adap[adapter]->write(chip, 0, 0, &buf, 1)); +} +#endif + +/* + * i2c_get_bus_num(): + * ------------------ + * + * Returns index of currently active I2C bus. Zero-based. + */ +unsigned int i2c_get_bus_num(void) +{ + return(i2c_cur_bus); +} + +/* + * i2c_set_bus_num(): + * ------------------ + * + * Change the active I2C bus. Subsequent read/write calls will + * go to this one. Sets all of the muxes in a proper condition + * if that bus is behind muxes. Fails if called before relocation. + * If previously selected bus is behind the muxes turns off all the + * muxes along the path to that bus. + * + * bus - bus index, zero based + * + * Returns: 0 on success, not 0 on failure + */ +int i2c_set_bus_num(unsigned int bus) +{ +#ifndef CONFIG_SYS_I2C_DIRECT_BUS + int i; + u_int8_t buf; +#endif + + if ((bus >= CONFIG_SYS_NUM_I2C_BUSSES) || !(gd->flags & GD_FLG_RELOC)) + return(-1); + +#ifndef CONFIG_SYS_I2C_DIRECT_BUS + /* Disconnect current bus (turn off muxes if any) */ + if ((i2c_bus[i2c_cur_bus].next_hop[0].chip != 0) && + (ADAP(i2c_cur_bus)->init_done != 0)) { + + i = CONFIG_SYS_I2C_MAX_HOPS; + + do { + u_int8_t chip; + + if ((chip = i2c_bus[i2c_cur_bus].next_hop[--i].chip) == 0) + continue; + + ADAP(i2c_cur_bus)->write(chip, 0, 0, &buf, 1); + + } while (i > 0); + } + + /* Connect requested bus if behind muxes */ + if ((i2c_bus[bus].next_hop[0].chip != 0) && + (ADAP(bus)->init_done != 0)) { + + /* Set all muxes along the path to that bus */ + for (i = 0; i < CONFIG_SYS_I2C_MAX_HOPS; i++) { + + if (i2c_bus[bus].next_hop[i].chip == 0) break; + + i2c_mux_set(i2c_bus[bus].adapter, + i2c_bus[bus].next_hop[i].mux.id, + i2c_bus[bus].next_hop[i].chip, + i2c_bus[bus].next_hop[i].channel); + } + } +#endif + + i2c_cur_bus = bus; + return(0); +} + + +/* + * i2c_init_bus(): + * --------------- + * + * Initializes one bus. Will initialize the parent adapter. No current bus + * changes, no mux (if any) setup. + */ +static void i2c_init_bus(unsigned int bus_no, int speed, int slaveaddr) +{ + if (bus_no >= CONFIG_SYS_NUM_I2C_BUSSES) + return; + + ADAP(bus_no)->init(speed, slaveaddr); + + if (gd->flags & GD_FLG_RELOC) { + ADAP(bus_no)->init_done = 1; + ADAP(bus_no)->speed = speed; + ADAP(bus_no)->slaveaddr = slaveaddr; + } +} + + +/* + * i2c_init_all(): + * + * Initializes all I2C adapters in the system. All i2c_adap_t structures in + * i2c_adap[] must be initialized beforehead with function pointers and + * data, including speed and slaveaddr. + */ +void i2c_init_all(void) +{ + int i; + + for (i = 0; i < CONFIG_SYS_NUM_I2C_ADAPTERS; i++) { + if ((i2c_adap[i]->speed != 0) && (i2c_adap[i]->init != NULL)) { + i2c_adap[i]->init(i2c_adap[i]->speed, i2c_adap[i]->slaveaddr); + if (gd->flags & GD_FLG_RELOC) + i2c_adap[i]->init_done = 1; + } + } +} + + +/* + * Probe the given I2C chip address. Returns 0 if a chip responded, + * not 0 on failure. + */ +int i2c_probe(u_int8_t chip) +{ + return(ADAP(i2c_cur_bus)->probe(chip)); +} + +/* + * Read/Write interface: + * chip: I2C chip address, range 0..127 + * addr: Memory (register) address within the chip + * alen: Number of bytes to use for addr (typically 1, 2 for larger + * memories, 0 for register type devices with only one + * register) + * buffer: Where to read/write the data + * len: How many bytes to read/write + * + * Returns: 0 on success, not 0 on failure + */ +int i2c_read(u_int8_t chip, unsigned int addr, int alen, + u_int8_t *buffer, int len) +{ + return(ADAP(i2c_cur_bus)->read(chip, addr, alen, buffer, len)); +} + +int i2c_write(u_int8_t chip, unsigned int addr, int alen, + u_int8_t *buffer, int len) +{ + return(ADAP(i2c_cur_bus)->write(chip, addr, alen, buffer, len)); +} + + +unsigned int i2c_set_bus_speed(unsigned int speed) +{ + return(ADAP(i2c_cur_bus)->set_bus_speed(speed)); +} + +unsigned int i2c_get_bus_speed(void) +{ + return(ADAP(i2c_cur_bus)->get_bus_speed()); +} + + +u_int8_t i2c_reg_read(u_int8_t addr, u_int8_t reg) +{ + u_int8_t buf; + +#ifdef CONFIG_8xx + /* MPC8xx needs this. Maybe one day we can get rid of it. */ + i2c_init_bus(i2c_cur_bus, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); +#endif + +#ifdef CONFIG_BLACKFIN + /* This ifdef will become unneccessary in a future version of the + * blackfin I2C driver. + */ + i2c_read(addr, reg, 0, &buf, 1); +#else + i2c_read(addr, reg, 1, &buf, 1); +#endif + +#ifdef DEBUG + printf("%s: bus=%d addr=0x%02x, reg=0x%02x, val=0x%02x\n", + __func__, i2c_cur_bus, addr, reg, buf); +#endif + + return buf; +} + +void i2c_reg_write(u_int8_t addr, u_int8_t reg, u_int8_t val) +{ +#ifdef CONFIG_8xx + /* MPC8xx needs this. Maybe one day we can get rid of it. */ + i2c_init_bus(i2c_cur_bus, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); +#endif + +#ifdef DEBUG + printf("%s: bus=%d addr=0x%02x, reg=0x%02x, val=0x%02x\n", + __func__, i2c_cur_bus, addr, reg, val); +#endif + +#ifdef CONFIG_BLACKFIN + /* This ifdef will become unneccessary in a future version of the + * blackfin I2C driver. + */ + i2c_write(addr, reg, 0, &val, 1); +#else + i2c_write(addr, reg, 1, &val, 1); +#endif +} + + +void inline __i2c_init(unsigned int speed, int slaveaddr) +{ + i2c_init_bus(i2c_cur_bus, speed, slaveaddr); +} + +void inline i2c_init(unsigned int speed, int slaveaddr) + __attribute__((weak, alias("__i2c_init"))); diff -purN u-boot.orig/drivers/i2c/Makefile u-boot/drivers/i2c/Makefile --- u-boot.orig/drivers/i2c/Makefile 2008-09-12 10:10:35.000000000 -0700 +++ u-boot/drivers/i2c/Makefile 2009-01-23 16:01:48.000000000 -0800 @@ -26,13 +26,15 @@ include $(TOPDIR)/config.mk LIB := $(obj)libi2c.a
COBJS-$(CONFIG_FSL_I2C) += fsl_i2c.o +COBJS-$(CONFIG_FSL_UNI_I2C) += fsl_uni_i2c.o COBJS-$(CONFIG_I2C_MXC) += mxc_i2c.o COBJS-$(CONFIG_DRIVER_OMAP1510_I2C) += omap1510_i2c.o COBJS-$(CONFIG_DRIVER_OMAP24XX_I2C) += omap24xx_i2c.o COBJS-$(CONFIG_SOFT_I2C) += soft_i2c.o COBJS-$(CONFIG_TSI108_I2C) += tsi108_i2c.o +COBJS-$(CONFIG_SM502_I2C) += sm502_i2c.o
-COBJS := $(COBJS-y) +COBJS := i2c_core.o $(COBJS-y) SRCS := $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(COBJS))
diff -purN u-boot.orig/include/i2c.h u-boot/include/i2c.h --- u-boot.orig/include/i2c.h 2008-12-16 15:32:13.000000000 -0800 +++ u-boot/include/i2c.h 2009-01-23 16:01:48.000000000 -0800 @@ -1,4 +1,7 @@ /* + * Copyright (C) 2009 Sergey Kubushyn ksi@koi8.net + * Changes for multibus/multiadapter I2C support. + * * (C) Copyright 2001 * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com. * @@ -46,14 +49,20 @@ */ #define I2C_RXTX_LEN 128 /* maximum tx/rx buffer length */
-#if defined(CONFIG_I2C_MULTI_BUS) -#define CONFIG_SYS_MAX_I2C_BUS 2 -#define I2C_GET_BUS() i2c_get_bus_num() -#define I2C_SET_BUS(a) i2c_set_bus_num(a) +#ifndef CONFIG_SYS_NUM_I2C_ADAPTERS +#define CONFIG_SYS_NUM_I2C_ADAPTERS 1 +#endif + +#if !defined(CONFIG_SYS_I2C_MAX_HOPS) || (CONFIG_SYS_I2C_MAX_HOPS == 0) +#define CONFIG_SYS_I2C_DIRECT_BUS 1 +#if !defined(CONFIG_SYS_NUM_I2C_BUSSES) || (CONFIG_SYS_NUM_I2C_BUSSES != CONFIG_SYS_NUM_I2C_ADAPTERS) +#define CONFIG_SYS_NUM_I2C_BUSSES CONFIG_SYS_NUM_I2C_ADAPTERS +#endif #else -#define CONFIG_SYS_MAX_I2C_BUS 1 -#define I2C_GET_BUS() 0 -#define I2C_SET_BUS(a) +#undef CONFIG_SYS_I2C_DIRECT_BUS +#ifndef CONFIG_SYS_NUM_I2C_BUSSES +#define CONFIG_SYS_NUM_I2C_BUSSES 1 +#endif #endif
/* define the I2C bus number for RTC and DTT if not already done */ @@ -67,66 +76,111 @@ #define CONFIG_SYS_SPD_BUS_NUM 0 #endif
-#ifndef I2C_SOFT_DECLARATIONS -# if defined(CONFIG_MPC8260) -# define I2C_SOFT_DECLARATIONS volatile ioport_t *iop = ioport_addr((immap_t *)CONFIG_SYS_IMMR, I2C_PORT); -# elif defined(CONFIG_8xx) -# define I2C_SOFT_DECLARATIONS volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR; -# else -# define I2C_SOFT_DECLARATIONS -# endif +#ifndef CONFIG_SYS_I2C_DIRECT_BUS +#define ADAP(bus) i2c_adap[i2c_bus[(bus)].adapter] +#else +#define ADAP(bus) i2c_adap[(bus)] #endif
-#ifdef CONFIG_8xx -/* Set default values for the I2C bus speed and slave address on 8xx. In the - * future, we'll define these in all 8xx board config files. - */ -#ifndef CONFIG_SYS_I2C_SPEED -#define CONFIG_SYS_I2C_SPEED 50000 -#endif +typedef struct i2c_adapter { + void (*init)(int speed, int slaveaddr); + int (*probe)(u_int8_t chip); + int (*read)(u_int8_t chip, uint addr, int alen, + u_int8_t *buffer, int len); + int (*write)(u_int8_t chip, uint addr, int alen, + u_int8_t *buffer, int len); + uint (*set_bus_speed)(uint speed); + uint (*get_bus_speed)(void); + + int speed; + int slaveaddr; + int init_done; + char *name; +} i2c_adap_t; + + +#ifndef CONFIG_SYS_I2C_DIRECT_BUS +#define I2C_MUX_PCA9540_ID 1 +#define I2C_MUX_PCA9540 {I2C_MUX_PCA9540_ID, "PCA9540B"} +#define I2C_MUX_PCA9542_ID 2 +#define I2C_MUX_PCA9542 {I2C_MUX_PCA9542_ID, "PCA9542A"} +#define I2C_MUX_PCA9544_ID 3 +#define I2C_MUX_PCA9544 {I2C_MUX_PCA9544_ID, "PCA9544A"} +#define I2C_MUX_PCA9547_ID 4 +#define I2C_MUX_PCA9547 {I2C_MUX_PCA9547_ID, "PCA9547A"} + +typedef struct i2c_mux { + int id; + char name[16]; +} i2c_mux_t; + +typedef struct i2c_next_hop { + i2c_mux_t mux; + u_int8_t chip; + u_int8_t channel; +} i2c_next_hop_t; + + +typedef struct i2c_bus_hose { + int adapter; + i2c_next_hop_t next_hop[CONFIG_SYS_I2C_MAX_HOPS]; +} i2c_bus_t;
-#ifndef CONFIG_SYS_I2C_SLAVE -#define CONFIG_SYS_I2C_SLAVE 0xFE -#endif +#define I2C_NULL_HOP {{-1, ""}, 0, 0} + +extern i2c_bus_t i2c_bus[]; #endif
+extern i2c_adap_t *i2c_adap[]; + +/* + * i2c_get_bus_num: + * + * Returns index of currently active I2C bus. Zero-based. + */ +unsigned int i2c_get_bus_num(void); + + /* + * i2c_set_bus_num: + * + * Change the active I2C bus. Subsequent read/write calls will + * go to this one. + * + * bus - bus index, zero based + * + * Returns: 0 on success, not 0 on failure + * + */ +int i2c_set_bus_num(unsigned int bus); + + +/* + * i2c_init_bus() + * * Initialization, must be called once on start up, may be called - * repeatedly to change the speed and slave addresses. + * repeatedly to change the speed and slave addresses. This initializes + * a single current i2c bus. */ -void i2c_init(int speed, int slaveaddr); -#ifdef CONFIG_SYS_I2C_INIT_BOARD -void i2c_init_board(void); -#endif +/* void i2c_init_bus(int speed, int slaveaddr); */
-#if defined(CONFIG_I2C_MUX)
-typedef struct _mux { - uchar chip; - uchar channel; - char *name; - struct _mux *next; -} I2C_MUX; - -typedef struct _mux_device { - int busid; - I2C_MUX *mux; /* List of muxes, to reach the device */ - struct _mux_device *next; -} I2C_MUX_DEVICE; - -int i2c_mux_add_device(I2C_MUX_DEVICE *dev); - -I2C_MUX_DEVICE *i2c_mux_search_device(int id); -I2C_MUX_DEVICE *i2c_mux_ident_muxstring (uchar *buf); -int i2x_mux_select_mux(int bus); -int i2c_mux_ident_muxstring_f (uchar *buf); -#endif +/* + * i2c_init_all(): + * + * Initializes all I2C adapters in the system. All i2c_adap structures must + * be initialized beforehead with function pointers and data, including + * speed and slaveaddr. Returns 0 on success, non-0 on failure. + */ +void i2c_init_all(void); +
/* * Probe the given I2C chip address. Returns 0 if a chip responded, * not 0 on failure. */ -int i2c_probe(uchar chip); +int i2c_probe(u_int8_t chip); +
/* * Read/Write interface: @@ -140,83 +194,25 @@ int i2c_probe(uchar chip); * * Returns: 0 on success, not 0 on failure */ -int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len); -int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len); +int i2c_read(u_int8_t chip, unsigned int addr, int alen, + u_int8_t *buffer, int len); + +int i2c_write(u_int8_t chip, unsigned int addr, int alen, + u_int8_t *buffer, int len); +
/* * Utility routines to read/write registers. */ -static inline u8 i2c_reg_read(u8 addr, u8 reg) -{ - u8 buf; - -#ifdef CONFIG_8xx - /* MPC8xx needs this. Maybe one day we can get rid of it. */ - i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); -#endif +u_int8_t i2c_reg_read(u_int8_t addr, u_int8_t reg);
-#ifdef DEBUG - printf("%s: addr=0x%02x, reg=0x%02x\n", __func__, addr, reg); -#endif +void i2c_reg_write(u_int8_t addr, u_int8_t reg, u_int8_t val);
-#ifdef CONFIG_BLACKFIN - /* This ifdef will become unneccessary in a future version of the - * blackfin I2C driver. - */ - i2c_read(addr, reg, 0, &buf, 1); -#else - i2c_read(addr, reg, 1, &buf, 1); -#endif - - return buf; -} - -static inline void i2c_reg_write(u8 addr, u8 reg, u8 val) -{ -#ifdef CONFIG_8xx - /* MPC8xx needs this. Maybe one day we can get rid of it. */ - i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); -#endif - -#ifdef DEBUG - printf("%s: addr=0x%02x, reg=0x%02x, val=0x%02x\n", - __func__, addr, reg, val); -#endif - -#ifdef CONFIG_BLACKFIN - /* This ifdef will become unneccessary in a future version of the - * blackfin I2C driver. - */ - i2c_write(addr, reg, 0, &val, 1); -#else - i2c_write(addr, reg, 1, &val, 1); -#endif -}
/* * Functions for setting the current I2C bus and its speed */
-/* - * i2c_set_bus_num: - * - * Change the active I2C bus. Subsequent read/write calls will - * go to this one. - * - * bus - bus index, zero based - * - * Returns: 0 on success, not 0 on failure - * - */ -int i2c_set_bus_num(unsigned int bus); - -/* - * i2c_get_bus_num: - * - * Returns index of currently active I2C bus. Zero-based. - */ - -unsigned int i2c_get_bus_num(void);
/* * i2c_set_bus_speed: @@ -225,10 +221,10 @@ unsigned int i2c_get_bus_num(void); * * speed - bus speed in Hz * - * Returns: 0 on success, not 0 on failure + * Returns: new bus speed * */ -int i2c_set_bus_speed(unsigned int); +unsigned int i2c_set_bus_speed(unsigned int speed);
/* * i2c_get_bus_speed: @@ -238,4 +234,44 @@ int i2c_set_bus_speed(unsigned int);
unsigned int i2c_get_bus_speed(void);
+/* + * i2c_reloc_fixup: + * + * Adjusts I2C pointers after U-Boot is relocated to DRAM + */ +void i2c_reloc_fixup(void); + + +#ifndef I2C_SOFT_DECLARATIONS +# if defined(CONFIG_MPC8260) +# define I2C_SOFT_DECLARATIONS volatile ioport_t *iop = ioport_addr((immap_t *)CONFIG_SYS_IMMR, I2C_PORT); +# elif defined(CONFIG_8xx) +# define I2C_SOFT_DECLARATIONS volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR; +# else +# define I2C_SOFT_DECLARATIONS +# endif +#endif + +#ifdef CONFIG_8xx +/* Set default values for the I2C bus speed and slave address on 8xx. In the + * future, we'll define these in all 8xx board config files. + */ +#ifndef CONFIG_SYS_I2C_SPEED +#define CONFIG_SYS_I2C_SPEED 50000 +#endif + +#ifndef CONFIG_SYS_I2C_SLAVE +#define CONFIG_SYS_I2C_SLAVE 0xFE +#endif +#endif + +/* + * Initialization, must be called once on start up, may be called + * repeatedly to change the speed and slave addresses. + */ +void i2c_init(unsigned int speed, int slaveaddr); +#ifdef CONFIG_SYS_I2C_INIT_BOARD +void i2c_init_board(void); +#endif + #endif /* _I2C_H_ */ diff -purN u-boot.orig/lib_ppc/board.c u-boot/lib_ppc/board.c --- u-boot.orig/lib_ppc/board.c 2009-01-23 10:39:27.000000000 -0800 +++ u-boot/lib_ppc/board.c 2009-01-23 16:01:48.000000000 -0800 @@ -91,7 +91,8 @@ extern void sc3_read_eeprom(void); void doc_init (void); #endif #if defined(CONFIG_HARD_I2C) || \ - defined(CONFIG_SOFT_I2C) + defined(CONFIG_SOFT_I2C) || \ + defined(CONFIG_SYS_I2C_ADAPTERS) #include <i2c.h> #endif #include <spi.h> @@ -234,11 +235,15 @@ static int init_func_ram (void)
/***********************************************************************/
-#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C) +#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C) || defined(CONFIG_SYS_I2C_ADAPTERS) static int init_func_i2c (void) { puts ("I2C: "); +#ifdef CONFIG_NEW_I2C + i2c_init_all(); +#else i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); +#endif puts ("ready\n"); return (0); } @@ -333,7 +338,7 @@ init_fnc_t *init_sequence[] = { misc_init_f, #endif INIT_FUNC_WATCHDOG_RESET -#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C) +#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C) || defined(CONFIG_SYS_I2C_ADAPTERS) init_func_i2c, #endif #if defined(CONFIG_HARD_SPI) @@ -863,6 +868,11 @@ void board_init_r (gd_t *id, ulong dest_ * the environment is in EEPROM. */
+#if defined(CONFIG_NEW_I2C) && defined(CONFIG_SYS_I2C_ADAPTERS) + /* Adjust I2C subsystem pointers after relocation */ + i2c_reloc_fixup(); +#endif + #if defined(CONFIG_SYS_EXTBDINFO) #if defined(CONFIG_405GP) || defined(CONFIG_405EP) #if defined(CONFIG_I2CFAST) diff -purN u-boot.orig/include/configs/MPC8548CDS.h u-boot/include/configs/MPC8548CDS.h --- u-boot.orig/include/configs/MPC8548CDS.h 2008-12-16 15:32:13.000000000 -0800 +++ u-boot/include/configs/MPC8548CDS.h 2009-01-23 16:01:48.000000000 -0800 @@ -52,6 +52,8 @@
#define CONFIG_FSL_VIA
+#define CONFIG_NEW_I2C + /* * When initializing flash, if we cannot find the manufacturer ID, * assume this is the AMD flash associated with the CDS board. @@ -343,6 +345,8 @@ extern unsigned long get_clock_freq(void #define CONFIG_SYS_64BIT_VSPRINTF 1 #define CONFIG_SYS_64BIT_STRTOUL 1
+ +#ifndef CONFIG_NEW_I2C /* * I2C */ @@ -353,6 +357,57 @@ extern unsigned long get_clock_freq(void #define CONFIG_SYS_I2C_SLAVE 0x7F #define CONFIG_SYS_I2C_NOPROBES {0x69} /* Don't probe these addrs */ #define CONFIG_SYS_I2C_OFFSET 0x3000 +#else /* CONFIG_NEW_I2C */ +#if 0 +/* + * Illustrative example with 3 I2C adapters and 5 I2C busses. + * + * Adapters: 2x FSL_I2C (0 and 1) and SM502 adapter (3) + * + * Busses: + * + * 0: Direct off of FSL_I2C[0] + * 1: FSL_I2C[1]->PCA9542(0)->PCA9542(0) + * 2: FSL_I2C[1]->PCA9542(0)->PCA9542(1) + * 3: FSL_I2C[1]->PCA9542(1) + * 4: SM502_I2C + * + * This might not have sense (it is much more logical to use a single + * PCA9544 for 3 busses off of FSL_I2C[1]) but it is just an illustrative + * example. + */ +#define CONFIG_SYS_NUM_I2C_ADAPTERS 3 +#define CONFIG_SYS_NUM_I2C_BUSSES 5 +#define CONFIG_SYS_I2C_MAX_HOPS 2 +#define CONFIG_SM502_I2C /* Use SM502 I2C driver */ +#define CONFIG_SYS_SM501_I2C_SPEED 400000 /* I2C speed and slave address */ +#define CONFIG_SYS_SM501_I2C_SLAVE 0x7F /* Adapter #1 */ +#define CONFIG_SYS_SM501_BASEADDR 0x80000000 /* Bogus */ +#define CONFIG_FSL_UNI_I2C /* Use FSL common I2C driver */ +#define CONFIG_SYS_FSL_I2C_SPEED 400000 /* I2C speed and slave address */ +#define CONFIG_SYS_FSL_I2C_SLAVE 0x7F /* Adapter #1 */ +#define CONFIG_SYS_FSL_I2C_OFFSET 0x3000 +#define CONFIG_SYS_FSL_I2C2_SPEED 400000 /* I2C speed and slave address */ +#define CONFIG_SYS_FSL_I2C2_SLAVE 0x7F /* Adapter #2 */ +#define CONFIG_SYS_FSL_I2C2_OFFSET 0x3100 +#define CONFIG_SYS_I2C_ADAPTERS {&fsl_i2c_adap[0], &fsl_i2c_adap[1], &sm501_i2c_adap} +#define CONFIG_SYS_I2C_BUSSES { {0, {I2C_NULL_HOP, I2C_NULL_HOP}}, \ + {1, {{I2C_MUX_PCA9542, 0x70, 0}, {I2C_MUX_PCA9542, 0x71, 0}}}, \ + {1, {{I2C_MUX_PCA9542, 0x70, 0}, {I2C_MUX_PCA9542, 0x71, 1}}}, \ + {1, {{I2C_MUX_PCA9542, 0x70, 1}, I2C_NULL_HOP}}, \ + {2, {I2C_NULL_HOP, I2C_NULL_HOP}}} +#define CONFIG_SYS_I2C_NOPROBES {{0,0x69},{1,0x69}} /* Don't probe these addrs */ +#else +#define CONFIG_SYS_NUM_I2C_ADAPTERS 1 +#define CONFIG_SYS_NUM_I2C_BUSSES 1 +#define CONFIG_FSL_UNI_I2C /* Use FSL common I2C driver */ +#define CONFIG_SYS_FSL_I2C_SPEED 400000 /* I2C speed and slave address */ +#define CONFIG_SYS_FSL_I2C_SLAVE 0x7F /* Adapter #1 */ +#define CONFIG_SYS_FSL_I2C_OFFSET 0x3000 +#define CONFIG_SYS_I2C_NOPROBES {0x69} /* Don't probe these addrs */ +#define CONFIG_SYS_I2C_ADAPTERS {&fsl_i2c_adap[0]} +#endif +#endif /* CONFIG_NEW_I2C */
/* EEPROM */ #define CONFIG_ID_EEPROM @@ -482,8 +537,11 @@ extern unsigned long get_clock_freq(void */ #include <config_cmd_default.h>
+#define CONFIG_I2C_CMD_TREE + #define CONFIG_CMD_PING #define CONFIG_CMD_I2C +#define CONFIG_CMD_SDRAM #define CONFIG_CMD_MII #define CONFIG_CMD_ELF #define CONFIG_CMD_IRQ
--- ****************************************************************** * KSI@home KOI8 Net < > The impossible we do immediately. * * Las Vegas NV, USA < > Miracles require 24-hour notice. * ******************************************************************