[U-Boot] [PATCH] 1/12 Multiadapter/multibus I2C, common part 1, fixed

Initial multiadapter/multibus I2C support.
Signed-off-by: Sergey Kubushyn ksi@koi8.net --- diff -purN u-boot-i2c.orig/common/cmd_date.c u-boot-i2c/common/cmd_date.c --- u-boot-i2c.orig/common/cmd_date.c 2009-02-12 10:43:41.000000000 -0800 +++ u-boot-i2c/common/cmd_date.c 2009-02-12 10:46:00.000000000 -0800 @@ -46,8 +46,13 @@ int do_date (cmd_tbl_t *cmdtp, int flag, int old_bus;
/* switch to correct I2C bus */ +#ifdef CONFIG_NEW_I2C + old_bus = i2c_get_bus_num(); + i2c_set_bus_num(CONFIG_SYS_RTC_BUS_NUM); +#else old_bus = I2C_GET_BUS(); I2C_SET_BUS(CONFIG_SYS_RTC_BUS_NUM); +#endif
switch (argc) { case 2: /* set date & time */ @@ -94,7 +99,11 @@ int do_date (cmd_tbl_t *cmdtp, int flag, }
/* switch back to original I2C bus */ +#ifdef CONFIG_NEW_I2C + i2c_set_bus_num(old_bus); +#else I2C_SET_BUS(old_bus); +#endif
return rcode; } diff -purN u-boot-i2c.orig/common/cmd_dtt.c u-boot-i2c/common/cmd_dtt.c --- u-boot-i2c.orig/common/cmd_dtt.c 2009-02-12 10:43:41.000000000 -0800 +++ u-boot-i2c/common/cmd_dtt.c 2009-02-12 10:46:00.000000000 -0800 @@ -35,8 +35,13 @@ int do_dtt (cmd_tbl_t * cmdtp, int flag, int old_bus;
/* switch to correct I2C bus */ +#ifdef CONFIG_NEW_I2C + old_bus = i2c_get_bus_num(); + i2c_set_bus_num(CONFIG_SYS_DTT_BUS_NUM); +#else old_bus = I2C_GET_BUS(); I2C_SET_BUS(CONFIG_SYS_DTT_BUS_NUM); +#endif
/* * Loop through sensors, read @@ -46,7 +51,11 @@ int do_dtt (cmd_tbl_t * cmdtp, int flag, printf ("DTT%d: %i C\n", i + 1, dtt_get_temp (sensors[i]));
/* switch back to original I2C bus */ +#ifdef CONFIG_NEW_I2C + i2c_set_bus_num(old_bus); +#else I2C_SET_BUS(old_bus); +#endif
return 0; } /* do_dtt() */ diff -purN u-boot-i2c.orig/common/cmd_i2c.c u-boot-i2c/common/cmd_i2c.c --- u-boot-i2c.orig/common/cmd_i2c.c 2009-02-12 10:43:41.000000000 -0800 +++ u-boot-i2c/common/cmd_i2c.c 2009-02-12 10:46:00.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 sub-system", -#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, \ "i2c memory display", \ @@ -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-i2c.orig/common/devices.c u-boot-i2c/common/devices.c --- u-boot-i2c.orig/common/devices.c 2009-02-12 10:43:41.000000000 -0800 +++ u-boot-i2c/common/devices.c 2009-02-12 10:46:00.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-i2c.orig/drivers/hwmon/adm1021.c u-boot-i2c/drivers/hwmon/adm1021.c --- u-boot-i2c.orig/drivers/hwmon/adm1021.c 2009-02-12 10:43:41.000000000 -0800 +++ u-boot-i2c/drivers/hwmon/adm1021.c 2009-02-12 10:46:00.000000000 -0800 @@ -174,7 +174,11 @@ dtt_init (void) const char *const header = "DTT: ";
/* switch to correct I2C bus */ +#ifdef CONFIG_NEW_I2C + i2c_set_bus_num(CONFIG_SYS_DTT_BUS_NUM); +#else I2C_SET_BUS(CONFIG_SYS_DTT_BUS_NUM); +#endif
for (i = 0; i < sizeof(sensors); i++) { if (_dtt_init(sensors[i]) != 0) diff -purN u-boot-i2c.orig/drivers/hwmon/lm75.c u-boot-i2c/drivers/hwmon/lm75.c --- u-boot-i2c.orig/drivers/hwmon/lm75.c 2009-02-12 10:43:41.000000000 -0800 +++ u-boot-i2c/drivers/hwmon/lm75.c 2009-02-12 10:46:00.000000000 -0800 @@ -156,8 +156,13 @@ int dtt_init (void) int old_bus;
/* switch to correct I2C bus */ +#ifdef CONFIG_NEW_I2C + old_bus = i2c_get_bus_num(); + i2c_set_bus_num(CONFIG_SYS_DTT_BUS_NUM); +#else old_bus = I2C_GET_BUS(); I2C_SET_BUS(CONFIG_SYS_DTT_BUS_NUM); +#endif
for (i = 0; i < sizeof(sensors); i++) { if (_dtt_init(sensors[i]) != 0) @@ -167,7 +172,11 @@ int dtt_init (void) dtt_get_temp(sensors[i])); } /* switch back to original I2C bus */ +#ifdef CONFIG_NEW_I2C + i2c_set_bus_num(old_bus); +#else I2C_SET_BUS(old_bus); +#endif
return (0); } /* dtt_init() */ diff -purN u-boot-i2c.orig/drivers/i2c/i2c_core.c u-boot-i2c/drivers/i2c/i2c_core.c --- u-boot-i2c.orig/drivers/i2c/i2c_core.c 1969-12-31 16:00:00.000000000 -0800 +++ u-boot-i2c/drivers/i2c/i2c_core.c 2009-02-12 11:06:54.000000000 -0800 @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2009 Sergey Kubushyn ksi@koi8.net + * + * Multibus/multiadapter I2C core functions (wrappers) + */ +#include <common.h> +#include <i2c.h> + +#ifdef CONFIG_BFIN_TWI_I2C +extern i2c_adap_t bfin_twi_i2c_adap; +#endif + +#ifdef CONFIG_FSL_I2C +extern i2c_adap_t fsl_i2c_adap[]; +#endif + +#ifdef CONFIG_MXC_I2C +extern i2c_adap_t mxc_i2c_adap[]; +#endif + +#ifdef CONFIG_OMAP1510_I2C +extern i2c_adap_t omap1510_i2c_adap; +#endif + +#ifdef CONFIG_OMAP24XX_I2C +extern i2c_adap_t omap24xx_i2c_adap[]; +#endif + +#ifdef CONFIG_SM502_I2C +extern i2c_adap_t sm501_i2c_adap; +#endif + +#ifdef CONFIG_SOFT_I2C +extern i2c_adap_t soft_i2c_adap[]; +#endif + +#ifdef CONFIG_TSI108_I2C +extern i2c_adap_t tsi108_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; + + 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 + i2c_read(addr, reg, 1, &buf, 1); + +#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 + + i2c_write(addr, reg, 1, &val, 1); +} + +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-i2c.orig/drivers/i2c/Makefile u-boot-i2c/drivers/i2c/Makefile --- u-boot-i2c.orig/drivers/i2c/Makefile 2009-02-12 10:43:41.000000000 -0800 +++ u-boot-i2c/drivers/i2c/Makefile 2009-02-12 10:46:00.000000000 -0800 @@ -27,12 +27,13 @@ LIB := $(obj)libi2c.a
COBJS-$(CONFIG_BFIN_TWI_I2C) += bfin-twi_i2c.o COBJS-$(CONFIG_FSL_I2C) += fsl_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_DRIVER_OMAP34XX_I2C) += omap24xx_i2c.o +COBJS-$(CONFIG_MXC_I2C) += mxc_i2c.o +COBJS-$(CONFIG_OMAP1510_I2C) += omap1510_i2c.o +COBJS-$(CONFIG_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-$(CONFIG_NEW_I2C) += i2c_core.o
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff -purN u-boot-i2c.orig/include/i2c.h u-boot-i2c/include/i2c.h --- u-boot-i2c.orig/include/i2c.h 2009-02-12 10:43:41.000000000 -0800 +++ u-boot-i2c/include/i2c.h 2009-02-12 11:00:50.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,95 @@ #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[]; + /* - * Initialization, must be called once on start up, may be called - * repeatedly to change the speed and slave addresses. + * i2c_get_bus_num: + * + * Returns index of currently active I2C bus. Zero-based. */ -void i2c_init(int speed, int slaveaddr); -#ifdef CONFIG_SYS_I2C_INIT_BOARD -void i2c_init_board(void); -#endif +unsigned int i2c_get_bus_num(void);
-#if defined(CONFIG_I2C_MUX) +/* + * 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);
-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,88 +178,62 @@ 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 - -#ifdef DEBUG - printf("%s: addr=0x%02x, reg=0x%02x\n", __func__, addr, reg); -#endif - - i2c_read(addr, reg, 1, &buf, 1); +u_int8_t i2c_reg_read(u_int8_t addr, u_int8_t reg);
- 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 - - i2c_write(addr, reg, 1, &val, 1); -} - -/* - * Functions for setting the current I2C bus and its speed - */ +void i2c_reg_write(u_int8_t addr, u_int8_t reg, u_int8_t val);
/* - * i2c_set_bus_num: + * i2c_set_bus_speed: * - * Change the active I2C bus. Subsequent read/write calls will - * go to this one. + * Change the speed of the active I2C bus * - * bus - bus index, zero based + * speed - bus speed in Hz * - * Returns: 0 on success, not 0 on failure + * Returns: new bus speed * */ -int i2c_set_bus_num(unsigned int bus); +unsigned int i2c_set_bus_speed(unsigned int speed);
/* - * i2c_get_bus_num: + * i2c_get_bus_speed: * - * Returns index of currently active I2C bus. Zero-based. + * Returns speed of currently active I2C bus in Hz */
-unsigned int i2c_get_bus_num(void); +unsigned int i2c_get_bus_speed(void);
/* - * i2c_set_bus_speed: - * - * Change the speed of the active I2C bus - * - * speed - bus speed in Hz - * - * Returns: 0 on success, not 0 on failure + * i2c_reloc_fixup: * + * Adjusts I2C pointers after U-Boot is relocated to DRAM */ -int i2c_set_bus_speed(unsigned int); +void i2c_reloc_fixup(void); + +#ifndef I2C_SOFT_DEFS +# if defined(CONFIG_MPC8260) +# define I2C_SOFT_DEFS volatile ioport_t *iop = ioport_addr((immap_t *)CONFIG_SYS_IMMR, I2C_PORT); +# elif defined(CONFIG_8xx) +# define I2C_SOFT_DEFS volatile immap_t *immr = (immap_t *)CONFIG_SYS_IMMR; +# else +# define I2C_SOFT_DEFS +# endif
/* - * i2c_get_bus_speed: - * - * Returns speed of currently active I2C bus in Hz + * Initialization, must be called once on start up, may be called + * repeatedly to change the speed and slave addresses. */ - -unsigned int i2c_get_bus_speed(void); +void i2c_init(unsigned int speed, int slaveaddr); +#ifdef CONFIG_SYS_I2C_INIT_BOARD +void i2c_init_board(void); +#endif
#endif /* _I2C_H_ */

Dear ksi@koi8.net,
In message Pine.LNX.4.64ksi.0902131347140.27097@home-gw.koi8.net you wrote:
Initial multiadapter/multibus I2C support.
Signed-off-by: Sergey Kubushyn ksi@koi8.net
Please start versioning your patches, and make sure it is clear which parts belong to which series.
Do not add such comments as "fixed" to the subject as this will go into the commit message.
Note that (as far as I can see) all my comments to the repvious patche series still apply.
Best regards,
Wolfgang Denk

On Mon, 16 Feb 2009, Wolfgang Denk wrote:
Dear ksi@koi8.net,
In message Pine.LNX.4.64ksi.0902131347140.27097@home-gw.koi8.net you wrote:
Initial multiadapter/multibus I2C support.
Signed-off-by: Sergey Kubushyn ksi@koi8.net
Please start versioning your patches, and make sure it is clear which parts belong to which series.
Do not add such comments as "fixed" to the subject as this will go into the commit message.
Note that (as far as I can see) all my comments to the repvious patche series still apply.
Sure. I will keep reposting the entire set until we had something in that i2c-git. And only then I will start to make incremental targeted patches.
--- ****************************************************************** * KSI@home KOI8 Net < > The impossible we do immediately. * * Las Vegas NV, USA < > Miracles require 24-hour notice. * ******************************************************************
participants (2)
-
ksi@koi8.net
-
Wolfgang Denk