I2C / TWI support in u-boot to read EEPROM on efusA9X

      I2C / TWI support in u-boot to read EEPROM on efusA9X

      Hello,

      I need to read out a EEPROM-IC via I2C in u-boot. I noticed that there is no I2C support for the efusA9X module, see "No I2C used in U-Boot on F&S i.MX6 SoloX boards" (UBOOT/include/configs/fsimx6sx.h).

      Is there a other board with the imx6sx processor or a source that provided support for the I2C bus, or what else can I do to communicate in u-boot with the EEPROM?


      Thanks.
      Yes, we currently do not need I2C in U-Boot and therefore we haven't activated it, yet. But there are quite a few drivers available, so you do not write the driver from scratch.

      When you are on a dedicated I2C bus, then you can use drivers/i2c/mxc_i2c.c. This is the driver for all i.MX6 CPU variants. If you only can use regular GPIOs and need a bitbanging I2C, then drivers/i2c/soft_i2c.c may help. These drivers register with the generic i2C framework in drivers/i2c/i2c_core.c. This is the file that also provides the functions to be used from outside to access I2C.

      Unfortunately I'm not exactly sure how I2C works in U-Boot. If there is some board-specific initialization required, you can add this function to board/F+S/fsimx6sx/fsimx6sx.c, where all our i.MX6-SoloX specific stuff is located. There you have to configure the pads used for I2C. I think the best way to learn how this works on i.MX6 is by looking at the NXP code itself, which is for example in board/freescale/mx6sabresd/mx6sabresd.c. Here they seem to initialize the I2C pads and then they call a function setup_i2c() which is defined in arch/arm/imx-common/i2c-mxv7.c.

      Your own code that actually reads from I2C EEPROM can also be added to fsimx6sx.c, maybe in board_init() or board_late_init().

      Your F&S Support Team
      F&S Elektronik Systeme GmbH
      As this is an international forum, please try to post in English.
      Da dies ein internationales Forum ist, bitten wir darum, Beiträge möglichst in Englisch zu verfassen.
      Hello,

      I edited board/F+S/fsimx6sx/fsimx6sx.c according board/freescale/mx6sabresd/mx6sabresd.c and arch/arm/include/asm/arch/mx6sx_pins.h (for the PADs).

      I also enabled the i2c and the eeprom command in uboot for debugging.

      I am able to compile UBOOT. But there is no way to access the I2C bus. Please give me a hint what is wrong or how I can check/debug my errors.

      The hardware is fine. In LINUX the EEPROM can be read and write out of the box.


      COMMANDS:

      Source Code

      1. setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x53, &i2c_pad_info0); (in board/F+S/fsimx6sx/fsimx6sx.c)
      2. force_idle_bus: sda=1 scl=0 sda.gp=0x3 scl.gp=0x2
      3. force_idle_bus: failed to clear bus, sda=1 scl=0


      Source Code

      1. efusA9X # i2c probe 0x53 ( in UBOOT)
      2. Valid chip addresses:wait_for_sr_state: failed sr=81 cr=0 state=2020
      3. i2c_init_transfer: failed for chip 0x53 retry=0
      4. wait_for_sr_state: failed sr=81 cr=0 state=2020
      5. i2c_init_transfer: failed for chip 0x53 retry=1
      6. i2c_init_transfer: give up i2c_regs=021a0000



      FILES:

      Difference-File

      1. --- /home/brenkem/svn/efusA9X/UBOOT/trunk/board/F+S/fsimx6sx/fsimx6sx.c 2017-07-11 16:15:31.801530806 +0200
      2. +++ board/F+S/fsimx6sx/fsimx6sx.c 2017-08-01 15:19:48.381134339 +0200
      3. @@ -44,6 +44,12 @@
      4. #include <usb.h> /* USB_INIT_HOST, USB_INIT_DEVICE */
      5. #include <malloc.h> /* free() */
      6. +
      7. +//////////////////////
      8. +#include <i2c.h>
      9. +#include <asm/imx-common/mxc_i2c.h>
      10. +
      11. +
      12. /* ------------------------------------------------------------------------- */
      13. #define NBOOT_ARGS_BASE (PHYS_SDRAM + 0x00001000) /* Arguments from NBoot */
      14. @@ -95,6 +101,16 @@
      15. PAD_CTL_DSE_80ohm | PAD_CTL_SRE_FAST | PAD_CTL_HYS)
      16. +/////////////////////////////////
      17. +#define I2C_PAD_CTRL (PAD_CTL_PUS_100K_UP | \
      18. + PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | PAD_CTL_HYS | \
      19. + PAD_CTL_ODE | PAD_CTL_SRE_FAST)
      20. +#define I2C_PAD MUX_PAD_CTRL(I2C_PAD_CTRL)
      21. struct board_info {
      22. char *name; /* Device name */
      23. unsigned int mach_type; /* Device machine ID */
      24. @@ -317,6 +333,55 @@
      25. /* Now RAM is valid, U-Boot is relocated. From now on we can use variables */
      26. +/////////////////
      27. +static struct i2c_pads_info i2c_pad_info0 = {
      28. + .scl = {
      29. + // I2C_C
      30. + .i2c_mode = MX6_PAD_GPIO1_IO02__I2C2_SCL | I2C_PAD,
      31. + .gpio_mode = MX6_PAD_GPIO1_IO02__GPIO1_IO_2 | I2C_PAD,
      32. + .gp = IMX_GPIO_NR(1, 2)
      33. + },
      34. + .sda = {
      35. + // I2C_C
      36. + .i2c_mode = MX6_PAD_GPIO1_IO03__I2C2_SDA | I2C_PAD,
      37. + .gpio_mode = MX6_PAD_GPIO1_IO03__GPIO1_IO_3 | I2C_PAD,
      38. + .gp = IMX_GPIO_NR(1, 3)
      39. + }
      40. +};
      41. +
      42. +static struct i2c_pads_info i2c_pad_info1 = {
      43. + .scl = {
      44. + // I2C_A
      45. + .i2c_mode = MX6_PAD_GPIO1_IO00__I2C1_SCL | I2C_PAD,
      46. + .gpio_mode = MX6_PAD_GPIO1_IO00__GPIO1_IO_0 | I2C_PAD,
      47. + .gp = IMX_GPIO_NR(1, 0)
      48. + },
      49. + .sda = {
      50. + // I2C_A
      51. + .i2c_mode = MX6_PAD_GPIO1_IO01__I2C1_SDA | I2C_PAD,
      52. + .gpio_mode = MX6_PAD_GPIO1_IO01__GPIO1_IO_1 | I2C_PAD,
      53. + .gp = IMX_GPIO_NR(1, 1)
      54. + }
      55. +};
      56. +
      57. +static struct i2c_pads_info i2c_pad_info2 = {
      58. + .scl = {
      59. + // I2C_B
      60. + .i2c_mode = MX6_PAD_KEY_COL4__I2C3_SCL | I2C_PAD,
      61. + .gpio_mode = MX6_PAD_KEY_COL4__GPIO2_IO_14 | I2C_PAD,
      62. + .gp = IMX_GPIO_NR(2, 14)
      63. + },
      64. + .sda = {
      65. + // I2C_B
      66. + .i2c_mode = MX6_PAD_KEY_ROW4__I2C3_SDA | I2C_PAD,
      67. + .gpio_mode = MX6_PAD_KEY_ROW4__GPIO2_IO_19 | I2C_PAD,
      68. + .gp = IMX_GPIO_NR(2, 19)
      69. + }
      70. +};
      71. +
      72. +
      73. +
      74. static iomux_v3_cfg_t const reset_pads[] = {
      75. IOMUX_PADS(PAD_ENET1_CRS__GPIO2_IO_1 | MUX_PAD_CTRL(NO_PAD_CTRL)),
      76. };
      77. @@ -775,6 +840,15 @@
      78. setup_var("fdt", bi->fdt, 1);
      79. setup_var("bootargs", "set_bootargs", 1);
      80. +
      81. +
      82. +///////////////////////////
      83. +//setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x53, &i2c_pad_info0);
      84. +setup_i2c(1, CONFIG_SYS_I2C_SPEED, 0x53, &i2c_pad_info1);
      85. +setup_i2c(2, CONFIG_SYS_I2C_SPEED, 0x53, &i2c_pad_info2);
      86. +
      87. +
      88. +
      89. return 0;
      90. }
      91. #endif


      ---------------------------------------------

      Difference-File

      1. --- /home/brenkem/svn/efusA9X/UBOOT/STACCserver/trunk/include/configs/fsimx6sx.h 2017-07-20 13:24:09.185495621 +0200
      2. +++ include/configs/fsimx6sx.h 2017-08-01 15:01:13.692821671 +0200
      3. @@ -207,6 +207,11 @@
      4. * I2C
      5. ************************************************************************/
      6. +#define CONFIG_SYS_I2C
      7. +#define CONFIG_SYS_I2C_MXC
      8. +#define I2C_DELAY udelay(5)
      9. +#define CONFIG_SYS_I2C_SPEED 100000
      10. /************************************************************************
      11. @@ -222,6 +227,14 @@
      12. /************************************************************************
      13. + * EEPROM
      14. + ************************************************************************/
      15. +
      16. +#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 1 // 8-bit EEPROM page address
      17. +#define CONFIG_ENV_EEPROM_IS_ON_I2C
      18. /************************************************************************
      19. * Real Time Clock (RTC)
      20. ************************************************************************/
      21. /* ###TODO### */
      22. @@ -396,7 +409,10 @@
      23. #undef CONFIG_CMD_DTT /* No digital thermometer and thermostat */
      24. #define CONFIG_CMD_ECHO /* Have echo command */
      25. #define CONFIG_CMD_EDITENV /* Allow editing of environment variables */
      26. -#undef CONFIG_CMD_EEPROM /* No EEPROM support */
      27. +
      28. +//#undef CONFIG_CMD_EEPROM /* No EEPROM support */
      29. +#define CONFIG_CMD_EEPROM /* EEPROM support */
      30. +
      31. #undef CONFIG_CMD_ELF /* No support to boot ELF images */
      32. #define CONFIG_CMD_EXT2 /* Support for EXT2 commands */
      33. #define CONFIG_CMD_EXT4 /* Support for EXT4 commands */
      34. @@ -413,7 +429,10 @@
      35. #undef CONFIG_CMD_GREPENV /* No support to search in environment */
      36. #undef CONFIG_CMD_HASH /* No hash command */
      37. #undef CONFIG_CMD_HWFLOW /* No switching of serial flow control */
      38. -#undef CONFIG_CMD_I2C /* No I2C support */
      39. +
      40. +//#undef CONFIG_CMD_I2C /* No I2C support */
      41. +#define CONFIG_CMD_I2C /* I2C support */
      42. +
      43. #undef CONFIG_CMD_IDE /* No IDE disk support */
      44. #define CONFIG_CMD_IMI /* Image information (iminfo) */
      45. #undef CONFIG_CMD_IMLS /* No support to list all found images */

      Post was edited 1 time, last by “BrenkeM” ().

      UPDATE:

      After changing the addr to 0x7F (see github.com/boundarydevices/u-b…rogen6x/nitrogen6x.c#L915) I was able to access the i2c bus 0 and 2:
      setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info0);


      The error from bus 0 (I2C_C) is still present. But the bus works:

      Source Code

      1. force_idle_bus: sda=1 scl=0 sda.gp=0x3 scl.gp=0x2
      2. force_idle_bus: failed to clear bus, sda=1 scl=0



      The bus number 1 is still not working, but the error message has changed to:

      Source Code

      1. efusA9X # i2c dev 1
      2. efusA9X # i2c probe 0x53
      3. Valid chip addresses:wait_for_sr_state: Arbitration lost sr=93 cr=80 state=2020
      4. i2c_init_transfer: failed for chip 0x53 retry=0
      5. wait_for_sr_state: Arbitration lost sr=93 cr=80 state=2020
      6. i2c_init_transfer: failed for chip 0x53 retry=1
      7. i2c_init_transfer: give up i2c_regs=021a4000

      I2C_B alias I2C3 is correct, this is on pads KEY_ROW4 and KEY_COL4. This is why this port works.
      I2C_C alias I2C1 is correct, this is on pads GPIO1_IO00 and GPIO1_IO01. This is why this port works. Only your comment is wrong where you name this as I2C_A.
      But I2C_A alias I2C2 is wrong. On our board this is on pads QSPI1B_DATA2 and QSPI1B_DATA3. This is why this port does not work. The pins that you defined are actually used for other signals on our board.

      Your F&S Support Team
      F&S Elektronik Systeme GmbH
      As this is an international forum, please try to post in English.
      Da dies ein internationales Forum ist, bitten wir darum, Beiträge möglichst in Englisch zu verfassen.
      Thanks for your help. Now every thing is working great.

      I configured all PADs as recommended. The error "force_idle_bus: sda=1 scl=0 sda.gp=0x3 scl.gp=0x2" and "force_idle_bus: failed to clear bus, sda=1 scl=0" are gone.
      All i2c buses works in UBOOT.

      Below the needed changed to enable I2C in UBOOT for the efusA9X / fsimx6sx: (NOTE that the 5µs delay is specific for my EEPROM)

      Difference-File

      1. --- ../u-boot-2014.07-fsimx6sx-V2.0/include/configs/fsimx6sx.h 2016-08-20 00:57:44.000000000 +0200
      2. +++ include/configs/fsimx6sx.h 2017-08-02 12:56:35.869322396 +0200
      3. @@ -198,7 +206,10 @@
      4. /************************************************************************
      5. * I2C
      6. ************************************************************************/
      7. -/* No I2C used in U-Boot on F&S i.MX6 SoloX boards */
      8. +#define CONFIG_SYS_I2C
      9. +#define CONFIG_SYS_I2C_MXC
      10. +#define I2C_DELAY udelay(5)
      11. +#define CONFIG_SYS_I2C_SPEED 100000


      Difference-File

      1. --- ../u-boot-2014.07-fsimx6sx-V2.0/board/F+S/fsimx6sx/fsimx6sx.c 2016-08-20 00:57:44.000000000 +0200
      2. +++ board/F+S/fsimx6sx/fsimx6sx.c 2017-08-03 10:47:46.303261540 +0200
      3. @@ -44,6 +44,10 @@
      4. #include <usb.h> /* USB_INIT_HOST, USB_INIT_DEVICE */
      5. #include <malloc.h> /* free() */
      6. +#include <i2c.h>
      7. +#include <asm/imx-common/mxc_i2c.h>
      8. +
      9. +
      10. /* ------------------------------------------------------------------------- */
      11. #define NBOOT_ARGS_BASE (PHYS_SDRAM + 0x00001000) /* Arguments from NBoot */
      12. @@ -94,6 +99,11 @@
      13. PAD_CTL_PUS_22K_UP | PAD_CTL_SPEED_LOW | \
      14. PAD_CTL_DSE_80ohm | PAD_CTL_SRE_FAST | PAD_CTL_HYS)
      15. +#define I2C_PAD_CTRL (PAD_CTL_PUS_100K_UP | \
      16. + PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | PAD_CTL_HYS | \
      17. + PAD_CTL_ODE | PAD_CTL_SRE_FAST)
      18. +#define I2C_PAD MUX_PAD_CTRL(I2C_PAD_CTRL)
      19. +
      20. struct board_info {
      21. char *name; /* Device name */
      22. @@ -310,9 +324,48 @@
      23. return 0;
      24. }
      25. /* Now RAM is valid, U-Boot is relocated. From now on we can use variables */
      26. +// define I2C PADs for bus #0, #1, #2
      27. +static struct i2c_pads_info i2c_pad_info0 = { // I2C_C; I2C1; Bus #0
      28. + .scl = {
      29. + .i2c_mode = MX6_PAD_GPIO1_IO00__I2C1_SCL | I2C_PAD,
      30. + .gpio_mode = MX6_PAD_GPIO1_IO00__GPIO1_IO_0 | I2C_PAD,
      31. + .gp = IMX_GPIO_NR(1, 0)
      32. + },
      33. + .sda = {
      34. + .i2c_mode = MX6_PAD_GPIO1_IO01__I2C1_SDA | I2C_PAD,
      35. + .gpio_mode = MX6_PAD_GPIO1_IO01__GPIO1_IO_1 | I2C_PAD,
      36. + .gp = IMX_GPIO_NR(1, 1)
      37. + }
      38. +};
      39. +
      40. +static struct i2c_pads_info i2c_pad_info1 = { // I2C_A; I2C2; Bus #1
      41. + .scl = {
      42. + .i2c_mode = MX6_PAD_QSPI1B_DATA3__I2C2_SCL | I2C_PAD,
      43. + .gpio_mode = MX6_PAD_QSPI1B_DATA3__GPIO4_IO_27 | I2C_PAD,
      44. + .gp = IMX_GPIO_NR(4, 27)
      45. + },
      46. + .sda = {
      47. + .i2c_mode = MX6_PAD_QSPI1B_DATA2__I2C2_SDA | I2C_PAD,
      48. + .gpio_mode = MX6_PAD_QSPI1B_DATA2__GPIO4_IO_26 | I2C_PAD,
      49. + .gp = IMX_GPIO_NR(4, 26)
      50. + }
      51. +};
      52. +
      53. +static struct i2c_pads_info i2c_pad_info2 = { // I2C_B; I2C3; Bus #2
      54. + .scl = {
      55. + .i2c_mode = MX6_PAD_KEY_COL4__I2C3_SCL | I2C_PAD,
      56. + .gpio_mode = MX6_PAD_KEY_COL4__GPIO2_IO_14 | I2C_PAD,
      57. + .gp = IMX_GPIO_NR(2, 14)
      58. + },
      59. + .sda = {
      60. + .i2c_mode = MX6_PAD_KEY_ROW4__I2C3_SDA | I2C_PAD,
      61. + .gpio_mode = MX6_PAD_KEY_ROW4__GPIO2_IO_19 | I2C_PAD,
      62. + .gp = IMX_GPIO_NR(2, 19)
      63. + }
      64. +};
      65. +
      66. static iomux_v3_cfg_t const reset_pads[] = {
      67. IOMUX_PADS(PAD_ENET1_CRS__GPIO2_IO_1 | MUX_PAD_CTRL(NO_PAD_CTRL)),
      68. };
      69. @@ -771,6 +824,31 @@
      70. setup_var("fdt", bi->fdt, 1);
      71. setup_var("bootargs", "set_bootargs", 1);
      72. + // init i2c bus for uboot
      73. + setup_i2c(0, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info0);
      74. + setup_i2c(1, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info1);
      75. + setup_i2c(2, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info2);
      76. return 0;
      77. }
      78. #endif

      Post was edited 1 time, last by “BrenkeM” ().