Commit 67b23a322848d828a5e45c0567b72762bfde7abf

Authored by Heiko Schocher
Committed by Wolfgang Denk
1 parent c24853644d

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>

Showing 7 changed files with 367 additions and 2 deletions Side-by-side Diff

... ... @@ -1429,6 +1429,53 @@
1429 1429 Define this option if you want to use Freescale's I2C driver in
1430 1430 drivers/i2c/fsl_i2c.c.
1431 1431  
  1432 + CONFIG_I2C_MUX
  1433 +
  1434 + Define this option if you have I2C devices reached over 1 .. n
  1435 + I2C Muxes like the pca9544a. This option addes a new I2C
  1436 + Command "i2c bus [muxtype:muxaddr:muxchannel]" which adds a
  1437 + new I2C Bus to the existing I2C Busses. If you select the
  1438 + new Bus with "i2c dev", u-bbot sends first the commandos for
  1439 + the muxes to activate this new "bus".
  1440 +
  1441 + CONFIG_I2C_MULTI_BUS must be also defined, to use this
  1442 + feature!
  1443 +
  1444 + Example:
  1445 + Adding a new I2C Bus reached over 2 pca9544a muxes
  1446 + The First mux with address 70 and channel 6
  1447 + The Second mux with address 71 and channel 4
  1448 +
  1449 + => i2c bus pca9544a:70:6:pca9544a:71:4
  1450 +
  1451 + Use the "i2c bus" command without parameter, to get a list
  1452 + of I2C Busses with muxes:
  1453 +
  1454 + => i2c bus
  1455 + Busses reached over muxes:
  1456 + Bus ID: 2
  1457 + reached over Mux(es):
  1458 + pca9544a@70 ch: 4
  1459 + Bus ID: 3
  1460 + reached over Mux(es):
  1461 + pca9544a@70 ch: 6
  1462 + pca9544a@71 ch: 4
  1463 + =>
  1464 +
  1465 + If you now switch to the new I2C Bus 3 with "i2c dev 3"
  1466 + u-boot sends First the Commando to the mux@70 to enable
  1467 + channel 6, and then the Commando to the mux@71 to enable
  1468 + the channel 4.
  1469 +
  1470 + After that, you can use the "normal" i2c commands as
  1471 + usual, to communicate with your I2C devices behind
  1472 + the 2 muxes.
  1473 +
  1474 + This option is actually implemented for the bitbanging
  1475 + algorithm in common/soft_i2c.c and for the Hardware I2C
  1476 + Bus on the MPC8260. But it should be not so difficult
  1477 + to add this option to other architectures.
  1478 +
1432 1479  
1433 1480 - SPI Support: CONFIG_SPI
1434 1481  
... ... @@ -83,7 +83,9 @@
83 83  
84 84 #include <common.h>
85 85 #include <command.h>
  86 +#include <environment.h>
86 87 #include <i2c.h>
  88 +#include <malloc.h>
87 89 #include <asm/byteorder.h>
88 90  
89 91 /* Display values from last command.
... ... @@ -125,6 +127,14 @@
125 127 #define NUM_ELEMENTS_NOPROBE (sizeof(i2c_no_probes)/sizeof(i2c_no_probes[0]))
126 128 #endif
127 129  
  130 +#if defined(CONFIG_I2C_MUX)
  131 +static I2C_MUX_DEVICE *i2c_mux_devices = NULL;
  132 +static int i2c_mux_busid = CFG_MAX_I2C_BUS;
  133 +
  134 +DECLARE_GLOBAL_DATA_PTR;
  135 +
  136 +#endif
  137 +
128 138 static int
129 139 mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char *argv[]);
130 140  
... ... @@ -1188,6 +1198,37 @@
1188 1198 return 0;
1189 1199 }
1190 1200  
  1201 +#if defined(CONFIG_I2C_MUX)
  1202 +int do_i2c_add_bus(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
  1203 +{
  1204 + int ret=0;
  1205 +
  1206 + if (argc == 1) {
  1207 + /* show all busses */
  1208 + I2C_MUX *mux;
  1209 + I2C_MUX_DEVICE *device = i2c_mux_devices;
  1210 +
  1211 + printf ("Busses reached over muxes:\n");
  1212 + while (device != NULL) {
  1213 + printf ("Bus ID: %x\n", device->busid);
  1214 + printf (" reached over Mux(es):\n");
  1215 + mux = device->mux;
  1216 + while (mux != NULL) {
  1217 + printf (" %s@%x ch: %x\n", mux->name, mux->chip, mux->channel);
  1218 + mux = mux->next;
  1219 + }
  1220 + device = device->next;
  1221 + }
  1222 + } else {
  1223 + I2C_MUX_DEVICE *dev;
  1224 +
  1225 + dev = i2c_mux_ident_muxstring ((uchar *)argv[1]);
  1226 + ret = 0;
  1227 + }
  1228 + return ret;
  1229 +}
  1230 +#endif /* CONFIG_I2C_MUX */
  1231 +
1191 1232 #if defined(CONFIG_I2C_MULTI_BUS)
1192 1233 int do_i2c_bus_num(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
1193 1234 {
... ... @@ -1226,6 +1267,10 @@
1226 1267  
1227 1268 int do_i2c(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
1228 1269 {
  1270 +#if defined(CONFIG_I2C_MUX)
  1271 + if (!strncmp(argv[1], "bu", 2))
  1272 + return do_i2c_add_bus(cmdtp, flag, --argc, ++argv);
  1273 +#endif /* CONFIG_I2C_MUX */
1229 1274 if (!strncmp(argv[1], "sp", 2))
1230 1275 return do_i2c_bus_speed(cmdtp, flag, --argc, ++argv);
1231 1276 #if defined(CONFIG_I2C_MULTI_BUS)
... ... @@ -1264,6 +1309,9 @@
1264 1309 U_BOOT_CMD(
1265 1310 i2c, 6, 1, do_i2c,
1266 1311 "i2c - I2C sub-system\n",
  1312 +#if defined(CONFIG_I2C_MUX)
  1313 + "bus [muxtype:muxaddr:muxchannel] - add a new bus reached over muxes.\n"
  1314 +#endif /* CONFIG_I2C_MUX */
1267 1315 "speed [speed] - show or set I2C bus speed\n"
1268 1316 #if defined(CONFIG_I2C_MULTI_BUS)
1269 1317 "i2c dev [dev] - show or set current I2C bus\n"
... ... @@ -1335,4 +1383,222 @@
1335 1383 " (valid chip values 50..57)\n"
1336 1384 );
1337 1385 #endif
  1386 +
  1387 +#if defined(CONFIG_I2C_MUX)
  1388 +
  1389 +int i2c_mux_add_device(I2C_MUX_DEVICE *dev)
  1390 +{
  1391 + I2C_MUX_DEVICE *devtmp = i2c_mux_devices;
  1392 +
  1393 + if (i2c_mux_devices == NULL) {
  1394 + i2c_mux_devices = dev;
  1395 + return 0;
  1396 + }
  1397 + while (devtmp->next != NULL)
  1398 + devtmp = devtmp->next;
  1399 +
  1400 + devtmp->next = dev;
  1401 + return 0;
  1402 +}
  1403 +
  1404 +I2C_MUX_DEVICE *i2c_mux_search_device(int id)
  1405 +{
  1406 + I2C_MUX_DEVICE *device = i2c_mux_devices;
  1407 +
  1408 + while (device != NULL) {
  1409 + if (device->busid == id)
  1410 + return device;
  1411 + device = device->next;
  1412 + }
  1413 + return NULL;
  1414 +}
  1415 +
  1416 +/* searches in the buf from *pos the next ':'.
  1417 + * returns:
  1418 + * 0 if found (with *pos = where)
  1419 + * < 0 if an error occured
  1420 + * > 0 if the end of buf is reached
  1421 + */
  1422 +static int i2c_mux_search_next (int *pos, uchar *buf, int len)
  1423 +{
  1424 + while ((buf[*pos] != ':') && (*pos < len)) {
  1425 + *pos += 1;
  1426 + }
  1427 + if (*pos >= len)
  1428 + return 1;
  1429 + if (buf[*pos] != ':')
  1430 + return -1;
  1431 + return 0;
  1432 +}
  1433 +
  1434 +static int i2c_mux_get_busid (void)
  1435 +{
  1436 + int tmp = i2c_mux_busid;
  1437 +
  1438 + i2c_mux_busid ++;
  1439 + return tmp;
  1440 +}
  1441 +
  1442 +/* Analyses a Muxstring and sends immediately the
  1443 + Commands to the Muxes. Runs from Flash.
  1444 + */
  1445 +int i2c_mux_ident_muxstring_f (uchar *buf)
  1446 +{
  1447 + int pos = 0;
  1448 + int oldpos;
  1449 + int ret = 0;
  1450 + int len = strlen((char *)buf);
  1451 + int chip;
  1452 + uchar channel;
  1453 + int was = 0;
  1454 +
  1455 + while (ret == 0) {
  1456 + oldpos = pos;
  1457 + /* search name */
  1458 + ret = i2c_mux_search_next(&pos, buf, len);
  1459 + if (ret != 0)
  1460 + printf ("ERROR\n");
  1461 + /* search address */
  1462 + pos ++;
  1463 + oldpos = pos;
  1464 + ret = i2c_mux_search_next(&pos, buf, len);
  1465 + if (ret != 0)
  1466 + printf ("ERROR\n");
  1467 + buf[pos] = 0;
  1468 + chip = simple_strtoul((char *)&buf[oldpos], NULL, 16);
  1469 + buf[pos] = ':';
  1470 + /* search channel */
  1471 + pos ++;
  1472 + oldpos = pos;
  1473 + ret = i2c_mux_search_next(&pos, buf, len);
  1474 + if (ret < 0)
  1475 + printf ("ERROR\n");
  1476 + was = 0;
  1477 + if (buf[pos] != 0) {
  1478 + buf[pos] = 0;
  1479 + was = 1;
  1480 + }
  1481 + channel = simple_strtoul((char *)&buf[oldpos], NULL, 16);
  1482 + if (was)
  1483 + buf[pos] = ':';
  1484 + if (i2c_write(chip, 0, 0, &channel, 1) != 0) {
  1485 + printf ("Error setting Mux: chip:%x channel: \
  1486 + %x\n", chip, channel);
  1487 + return -1;
  1488 + }
  1489 + pos ++;
  1490 + oldpos = pos;
  1491 +
  1492 + }
  1493 +
  1494 + return 0;
  1495 +}
  1496 +
  1497 +/* Analyses a Muxstring and if this String is correct
  1498 + * adds a new I2C Bus.
  1499 + */
  1500 +I2C_MUX_DEVICE *i2c_mux_ident_muxstring (uchar *buf)
  1501 +{
  1502 + I2C_MUX_DEVICE *device;
  1503 + I2C_MUX *mux;
  1504 + int pos = 0;
  1505 + int oldpos;
  1506 + int ret = 0;
  1507 + int len = strlen((char *)buf);
  1508 + int was = 0;
  1509 +
  1510 + device = (I2C_MUX_DEVICE *)malloc (sizeof(I2C_MUX_DEVICE));
  1511 + device->mux = NULL;
  1512 + device->busid = i2c_mux_get_busid ();
  1513 + device->next = NULL;
  1514 + while (ret == 0) {
  1515 + mux = (I2C_MUX *)malloc (sizeof(I2C_MUX));
  1516 + mux->next = NULL;
  1517 + /* search name of mux */
  1518 + oldpos = pos;
  1519 + ret = i2c_mux_search_next(&pos, buf, len);
  1520 + if (ret != 0)
  1521 + printf ("%s no name.\n", __FUNCTION__);
  1522 + mux->name = (char *)malloc (pos - oldpos + 1);
  1523 + memcpy (mux->name, &buf[oldpos], pos - oldpos);
  1524 + mux->name[pos - oldpos] = 0;
  1525 + /* search address */
  1526 + pos ++;
  1527 + oldpos = pos;
  1528 + ret = i2c_mux_search_next(&pos, buf, len);
  1529 + if (ret != 0)
  1530 + printf ("%s no mux address.\n", __FUNCTION__);
  1531 + buf[pos] = 0;
  1532 + mux->chip = simple_strtoul((char *)&buf[oldpos], NULL, 16);
  1533 + buf[pos] = ':';
  1534 + /* search channel */
  1535 + pos ++;
  1536 + oldpos = pos;
  1537 + ret = i2c_mux_search_next(&pos, buf, len);
  1538 + if (ret < 0)
  1539 + printf ("%s no mux channel.\n", __FUNCTION__);
  1540 + was = 0;
  1541 + if (buf[pos] != 0) {
  1542 + buf[pos] = 0;
  1543 + was = 1;
  1544 + }
  1545 + mux->channel = simple_strtoul((char *)&buf[oldpos], NULL, 16);
  1546 + if (was)
  1547 + buf[pos] = ':';
  1548 + if (device->mux == NULL)
  1549 + device->mux = mux;
  1550 + else {
  1551 + I2C_MUX *muxtmp = device->mux;
  1552 + while (muxtmp->next != NULL) {
  1553 + muxtmp = muxtmp->next;
  1554 + }
  1555 + muxtmp->next = mux;
  1556 + }
  1557 + pos ++;
  1558 + oldpos = pos;
  1559 + }
  1560 + if (ret > 0) {
  1561 + /* Add Device */
  1562 + i2c_mux_add_device (device);
  1563 + return device;
  1564 + }
  1565 +
  1566 + return NULL;
  1567 +}
  1568 +
  1569 +int i2x_mux_select_mux(int bus)
  1570 +{
  1571 + I2C_MUX_DEVICE *dev;
  1572 + I2C_MUX *mux;
  1573 +
  1574 + if ((gd->flags & GD_FLG_RELOC) != GD_FLG_RELOC) {
  1575 + /* select Default Mux Bus */
  1576 +#if defined(CFG_I2C_IVM_BUS)
  1577 + i2c_mux_ident_muxstring_f ((uchar *)CFG_I2C_IVM_BUS);
  1578 +#else
  1579 + {
  1580 + unsigned char *buf;
  1581 + buf = (unsigned char *) getenv("EEprom_ivm");
  1582 + if (buf != NULL)
  1583 + i2c_mux_ident_muxstring_f (buf);
  1584 + }
  1585 +#endif
  1586 + return 0;
  1587 + }
  1588 + dev = i2c_mux_search_device(bus);
  1589 + if (dev == NULL)
  1590 + return -1;
  1591 +
  1592 + mux = dev->mux;
  1593 + while (mux != NULL) {
  1594 + if (i2c_write(mux->chip, 0, 0, &mux->channel, 1) != 0) {
  1595 + printf ("Error setting Mux: chip:%x channel: \
  1596 + %x\n", mux->chip, mux->channel);
  1597 + return -1;
  1598 + }
  1599 + mux = mux->next;
  1600 + }
  1601 + return 0;
  1602 +}
  1603 +#endif /* CONFIG_I2C_MUX */
... ... @@ -780,10 +780,23 @@
780 780  
781 781 int i2c_set_bus_num(unsigned int bus)
782 782 {
  783 +#if defined(CONFIG_I2C_MUX)
  784 + if (bus < CFG_MAX_I2C_BUS) {
  785 + i2c_bus_num = bus;
  786 + } else {
  787 + int ret;
  788 +
  789 + ret = i2x_mux_select_mux(bus);
  790 + if (ret == 0)
  791 + i2c_bus_num = bus;
  792 + else
  793 + return ret;
  794 + }
  795 +#else
783 796 if (bus >= CFG_MAX_I2C_BUS)
784 797 return -1;
785 798 i2c_bus_num = bus;
786   -
  799 +#endif
787 800 return 0;
788 801 }
789 802 /* TODO: add 100/400k switching */
drivers/i2c/soft_i2c.c
... ... @@ -223,10 +223,23 @@
223 223  
224 224 int i2c_set_bus_num(unsigned int bus)
225 225 {
  226 +#if defined(CONFIG_I2C_MUX)
  227 + if (bus < CFG_MAX_I2C_BUS) {
  228 + i2c_bus_num = bus;
  229 + } else {
  230 + int ret;
  231 +
  232 + ret = i2x_mux_select_mux(bus);
  233 + if (ret == 0)
  234 + i2c_bus_num = bus;
  235 + else
  236 + return ret;
  237 + }
  238 +#else
226 239 if (bus >= CFG_MAX_I2C_BUS)
227 240 return -1;
228 241 i2c_bus_num = bus;
229   -
  242 +#endif
230 243 return 0;
231 244 }
232 245  
include/configs/mgcoge.h
... ... @@ -203,6 +203,7 @@
203 203 #define CONFIG_I2C_CMD_TREE 1
204 204 #define CFG_MAX_I2C_BUS 2
205 205 #define CFG_I2C_INIT_BOARD 1
  206 +#define CONFIG_I2C_MUX 1
206 207  
207 208 /* EEprom support */
208 209 #define CFG_I2C_EEPROM_ADDR_LEN 1
include/configs/mgsuvd.h
... ... @@ -374,6 +374,7 @@
374 374 #define CONFIG_I2C_CMD_TREE 1
375 375 #define CFG_MAX_I2C_BUS 2
376 376 #define CFG_I2C_INIT_BOARD 1
  377 +#define CONFIG_I2C_MUX 1
377 378  
378 379 /* EEprom support */
379 380 #define CFG_I2C_EEPROM_ADDR_LEN 1
... ... @@ -85,6 +85,29 @@
85 85 void i2c_init_board(void);
86 86 #endif
87 87  
  88 +#if defined(CONFIG_I2C_MUX)
  89 +
  90 +typedef struct _mux {
  91 + uchar chip;
  92 + uchar channel;
  93 + char *name;
  94 + struct _mux *next;
  95 +} I2C_MUX;
  96 +
  97 +typedef struct _mux_device {
  98 + int busid;
  99 + I2C_MUX *mux; /* List of muxes, to reach the device */
  100 + struct _mux_device *next;
  101 +} I2C_MUX_DEVICE;
  102 +
  103 +int i2c_mux_add_device(I2C_MUX_DEVICE *dev);
  104 +
  105 +I2C_MUX_DEVICE *i2c_mux_search_device(int id);
  106 +I2C_MUX_DEVICE *i2c_mux_ident_muxstring (uchar *buf);
  107 +int i2x_mux_select_mux(int bus);
  108 +int i2c_mux_ident_muxstring_f (uchar *buf);
  109 +#endif
  110 +
88 111 /*
89 112 * Probe the given I2C chip address. Returns 0 if a chip responded,
90 113 * not 0 on failure.