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