1
0
mirror of https://xff.cz/git/u-boot/ synced 2025-10-18 08:23:24 +02:00

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>
This commit is contained in:
Heiko Schocher
2008-10-15 09:39:47 +02:00
committed by Wolfgang Denk
parent c24853644d
commit 67b23a3228
7 changed files with 367 additions and 2 deletions

View File

@@ -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 */