diff --git a/drivers/led_strip/CMakeLists.txt b/drivers/led_strip/CMakeLists.txt index b293782e620..9d7bf6ffcbe 100644 --- a/drivers/led_strip/CMakeLists.txt +++ b/drivers/led_strip/CMakeLists.txt @@ -10,3 +10,4 @@ zephyr_library_sources_ifdef(CONFIG_WS2812_STRIP_I2S ws2812_i2s.c) zephyr_library_sources_ifdef(CONFIG_WS2812_STRIP_RPI_PICO_PIO ws2812_rpi_pico_pio.c) zephyr_library_sources_ifdef(CONFIG_TLC5971_STRIP tlc5971.c) zephyr_library_sources_ifdef(CONFIG_TLC59731_STRIP tlc59731.c) +zephyr_library_sources_ifdef(CONFIG_MODULINO_SMARTLEDS modulino_smartleds.c) diff --git a/drivers/led_strip/Kconfig b/drivers/led_strip/Kconfig index 3be80de4729..2e0c54b1d0b 100644 --- a/drivers/led_strip/Kconfig +++ b/drivers/led_strip/Kconfig @@ -37,4 +37,6 @@ source "drivers/led_strip/Kconfig.tlc5971" source "drivers/led_strip/Kconfig.tlc59731" +source "drivers/led_strip/Kconfig.modulino" + endif # LED_STRIP diff --git a/drivers/led_strip/Kconfig.modulino b/drivers/led_strip/Kconfig.modulino new file mode 100644 index 00000000000..e60f2ac2493 --- /dev/null +++ b/drivers/led_strip/Kconfig.modulino @@ -0,0 +1,10 @@ +# Copyright (c) 2025 Google, LLC +# SPDX-License-Identifier: Apache-2.0 + +config MODULINO_SMARTLEDS + bool "Arduino Modulino smart LEDs" + default y + depends on DT_HAS_ARDUINO_MODULINO_SMARTLEDS_ENABLED + select I2C + help + Enable driver Arduino Modulino smart LEDs. diff --git a/drivers/led_strip/modulino_smartleds.c b/drivers/led_strip/modulino_smartleds.c new file mode 100644 index 00000000000..220a88799e5 --- /dev/null +++ b/drivers/led_strip/modulino_smartleds.c @@ -0,0 +1,119 @@ +/* + * Copyright 2025 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT arduino_modulino_smartleds + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(modulino_smartleds, CONFIG_LED_STRIP_LOG_LEVEL); + +#define MODULINO_SMARTLEDS_NUM_LEDS 8 + +/* This is a strip of LC8822 driven by the microcontroller on the Modulino + * board, the start frame is sent automatically, the rest uses the LC8822 + * protocol: + * - 4x "1" marker bits + * - 5x brightness bits + * - 3x bytes for B, G, R + */ + +#define MODULINO_SMARTLEDS_MARKER (0xe0 << 24) +#define MODULINO_SMARTLEDS_FULL_BRIGHTNESS (0x1f << 24) + +struct modulino_smartleds_config { + struct i2c_dt_spec bus; +}; + +struct modulino_smartleds_data { + uint32_t buf[MODULINO_SMARTLEDS_NUM_LEDS]; +}; + +static int modulino_smartleds_update_rgb(const struct device *dev, + struct led_rgb *pixels, + size_t count) +{ + const struct modulino_smartleds_config *cfg = dev->config; + struct modulino_smartleds_data *data = dev->data; + int ret; + + if (count > MODULINO_SMARTLEDS_NUM_LEDS) { + return -EINVAL; + } + + for (uint8_t i = 0; i < count; i++) { + data->buf[i] = sys_cpu_to_be32( + MODULINO_SMARTLEDS_MARKER | + MODULINO_SMARTLEDS_FULL_BRIGHTNESS | + (pixels[i].b << 16) | + (pixels[i].g << 8) | + pixels[i].r); + } + + ret = i2c_write_dt(&cfg->bus, (uint8_t *)data->buf, sizeof(data->buf)); + if (ret < 0) { + LOG_ERR("i2c write error: %d", ret); + return ret; + } + + return 0; +} + +static size_t modulino_smartleds_length(const struct device *dev) +{ + return MODULINO_SMARTLEDS_NUM_LEDS; +} + +static int modulino_smartleds_init(const struct device *dev) +{ + const struct modulino_smartleds_config *cfg = dev->config; + struct modulino_smartleds_data *data = dev->data; + int ret; + + if (!i2c_is_ready_dt(&cfg->bus)) { + LOG_ERR("Bus device is not ready"); + return -ENODEV; + } + + for (uint8_t i = 0; i < ARRAY_SIZE(data->buf); i++) { + data->buf[i] = sys_cpu_to_be32(MODULINO_SMARTLEDS_MARKER); + } + + /* Reset to all LEDs off */ + ret = i2c_write_dt(&cfg->bus, (uint8_t *)data->buf, sizeof(data->buf)); + if (ret < 0) { + LOG_ERR("i2c write error: %d", ret); + return ret; + } + + return 0; +} + +static DEVICE_API(led_strip, modulino_smartleds_api) = { + .update_rgb = modulino_smartleds_update_rgb, + .length = modulino_smartleds_length, +}; + +#define MODULINO_SMARTLEDS_INIT(inst) \ + static const struct modulino_smartleds_config \ + modulino_smartleds_cfg_##inst = { \ + .bus = I2C_DT_SPEC_INST_GET(inst), \ + }; \ + \ + static struct modulino_smartleds_data modulino_smartleds_data_##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, modulino_smartleds_init, NULL, \ + &modulino_smartleds_data_##inst, \ + &modulino_smartleds_cfg_##inst, \ + POST_KERNEL, CONFIG_LED_STRIP_INIT_PRIORITY, \ + &modulino_smartleds_api); + + +DT_INST_FOREACH_STATUS_OKAY(MODULINO_SMARTLEDS_INIT) diff --git a/dts/bindings/led_strip/arduino,modulino-smartleds.yaml b/dts/bindings/led_strip/arduino,modulino-smartleds.yaml new file mode 100644 index 00000000000..884f461775e --- /dev/null +++ b/dts/bindings/led_strip/arduino,modulino-smartleds.yaml @@ -0,0 +1,12 @@ +# Copyright (c) 2025 Google, LLC +# SPDX-License-Identifier: Apache-2.0 + +description: Arduino Modulino smart LEDs + +compatible: "arduino,modulino-smartleds" + +include: [led-strip.yaml, i2c-device.yaml] + +properties: + reg: + required: true