How to use I2C in U-Boot SPL

Simon Glass sjg at chromium.org
Sat Dec 2 19:27:13 CET 2023


kHi Thomas,

On Wed, 22 Nov 2023 at 13:57, Thomas Thielemann <th.thielemann at web.de> wrote:
>
> Hello U-Boot,
>
> I was able to use the I2C commands from within U-Boot to control my I2C device:
>
> Configured the Processor GPIOs for the I2C bus in device tree
> Enabled the I2C bus in device tree
> Added my device to the I2C bus in device tree
> Wrote my script into a U-Boot variable
> Run my script
> Now I want to do the same from within the U-Boot SPL. I extended int board_early_init_f(void) in board.c for my hardware. The debug output is printed at run time. But the I2C device is not found.
>
> How do I review whether the I2C bus is using the right GPIOs and whether my device is configured right?
>
> static int i2c_get_dev(uint bus_num, uint dev_num, struct udevice **i2c_dev)
> {
>     int ret;
>
>     if (!i2c_led_bus) {
>         ret = uclass_get_device_by_seq(UCLASS_I2C, bus_num, &i2c_led_bus);
>         if (ret) {
>             printf("I2C bus %i not found (%d)\n", dev_num, ret);
>             return -ENODEV;
>         }
>     }
>
>     return i2c_get_chip(i2c_led_bus, dev_num, bus_num, i2c_dev);
> }
> #endif
>
> static int i2c_enable_leds(void)
> {
>     log_info("i2c_enable_leds\n");
>     const uint  bus_num = 1;    // i2c bus
>     const uint  dev_num = 0x28;     // i2c chip address
>     const uint  dev_addr = 0x00;    // write all bytes in one junk from start
>     const uint  dev_addr_len = 1;
>     int     ret;
>     const uint  cmd_len = 29;       // cmd_len is the number of bytes.
>     uchar   cmd[29] = {
>         0x40, 0x3c, // init
>         0x00, 0x00, 0x00, 0x00, 0x00, // unused
>         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // set intensitiy to max
>         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // unused
>         0xff, 0x00, 0x00, // RGB LED
>         0xff, 0x00, 0x00 // RGB LED
>     };
> #if CONFIG_IS_ENABLED(DM_I2C)
>     struct udevice *i2c_dev;
>     struct dm_i2c_chip *i2c_chip;
> #endif
>
> #if CONFIG_IS_ENABLED(DM_I2C)
>     ret = i2c_get_dev(bus_num, dev_num, &i2c_dev);
>     if (!ret)
>         ret = i2c_set_chip_offset_len(i2c_dev, dev_addr_len);
>     if (ret) {
>         log_err("Failed to write to 0x28 (%d)\n", ret);
>         return ret;
>     }
>     i2c_chip = dev_get_parent_plat(i2c_dev);
>     if (!i2c_chip) {
>         log_err("Failed to write to 0x28 (%d)\n", ret);
>         return ret;
>     }
> #endif
>
> #if CONFIG_IS_ENABLED(DM_I2C)
>         i2c_chip->flags &= ~DM_I2C_CHIP_WR_ADDRESS;
>         ret = dm_i2c_write(i2c_dev, dev_addr, cmd, cmd_len);
> #else
>         ret = i2c_write(dev_num, dev_addr, dev_addr_len, cmd, cmd_len);
> #endif
>         if (ret)
>             log_err("Failed to write to 0x28 (%d)\n", ret);
>
>     return 0;
> }
> int board_early_init_f(void)
> {
>     i2c_enable_leds();
>
>     return 0;
> }

You should use driver mode for this, i.e. add your i2c device to the
devicetree with a suitable driver in place, then probe it, e.g. with
uclass_first_device(UCLASS_LED)

Accessing the chip directly like this is a bit hacky :-)

If you include a bit more info about what piece breaks, it would help
people to offer ideas.

Regards,
SImon


More information about the U-Boot mailing list