diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/cmd_i2c.c | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/common/cmd_i2c.c b/common/cmd_i2c.c index ef9123e..8d287fe 100644 --- a/common/cmd_i2c.c +++ b/common/cmd_i2c.c @@ -83,7 +83,9 @@ #include <common.h> #include <command.h> +#include <environment.h> #include <i2c.h> +#include <malloc.h> #include <asm/byteorder.h> /* Display values from last command. @@ -125,6 +127,14 @@ static uchar i2c_no_probes[] = CFG_I2C_NOPROBES; #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 = CFG_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[]); @@ -1188,6 +1198,37 @@ int do_i2c_reset(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) return 0; } +#if defined(CONFIG_I2C_MUX) +int do_i2c_add_bus(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + int ret=0; + + 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; + } + device = device->next; + } + } else { + I2C_MUX_DEVICE *dev; + + dev = i2c_mux_ident_muxstring ((uchar *)argv[1]); + ret = 0; + } + return ret; +} +#endif /* CONFIG_I2C_MUX */ + #if defined(CONFIG_I2C_MULTI_BUS) int do_i2c_bus_num(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) { @@ -1226,6 +1267,10 @@ int do_i2c_bus_speed(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) int do_i2c(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) { +#if defined(CONFIG_I2C_MUX) + if (!strncmp(argv[1], "bu", 2)) + return do_i2c_add_bus(cmdtp, flag, --argc, ++argv); +#endif /* CONFIG_I2C_MUX */ if (!strncmp(argv[1], "sp", 2)) return do_i2c_bus_speed(cmdtp, flag, --argc, ++argv); #if defined(CONFIG_I2C_MULTI_BUS) @@ -1264,6 +1309,9 @@ int do_i2c(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) 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) "i2c dev [dev] - show or set current I2C bus\n" @@ -1335,3 +1383,222 @@ 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(CFG_I2C_IVM_BUS) + i2c_mux_ident_muxstring_f ((uchar *)CFG_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 */ + |