diff options
| author | Heiko Schocher <hs@denx.de> | 2008-10-15 09:39:47 +0200 | 
|---|---|---|
| committer | Wolfgang Denk <wd@denx.de> | 2008-10-18 21:54:02 +0200 | 
| commit | 67b23a322848d828a5e45c0567b72762bfde7abf (patch) | |
| tree | 8dc26375504482eaa0e9600a6a52a6bb047dccf3 /common/cmd_i2c.c | |
| parent | c24853644ddd2dd2e4246b5854a93e6254a14092 (diff) | |
| download | olio-uboot-2014.01-67b23a322848d828a5e45c0567b72762bfde7abf.tar.xz olio-uboot-2014.01-67b23a322848d828a5e45c0567b72762bfde7abf.zip | |
I2C: adding new "i2c bus" Command to the I2C Subsystem.
With this Command it is possible to add new I2C Busses,
which are behind 1 .. n I2C Muxes. Details see README.
Signed-off-by: Heiko Schocher <hs@denx.de>
Diffstat (limited to 'common/cmd_i2c.c')
| -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 ef9123ebf..8d287fe5f 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 */ + |