How to use I2C in U-Boot SPL

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; }
Regards, Thomas

kHi Thomas,
On Wed, 22 Nov 2023 at 13:57, Thomas Thielemann th.thielemann@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
participants (2)
-
Simon Glass
-
Thomas Thielemann