diff --git a/drivers/led/CMakeLists.txt b/drivers/led/CMakeLists.txt index 1d8b9d2aa960..6cbfb493fdfd 100644 --- a/drivers/led/CMakeLists.txt +++ b/drivers/led/CMakeLists.txt @@ -9,6 +9,7 @@ zephyr_library_sources_ifdef(CONFIG_HT16K33 ht16k33.c) zephyr_library_sources_ifdef(CONFIG_IS31FL3194 is31fl3194.c) zephyr_library_sources_ifdef(CONFIG_IS31FL3216A is31fl3216a.c) zephyr_library_sources_ifdef(CONFIG_IS31FL3733 is31fl3733.c) +zephyr_library_sources_ifdef(CONFIG_LEDS_GROUP_MULTICOLOR leds_group_multicolor.c) zephyr_library_sources_ifdef(CONFIG_LED_AXP192_AXP2101 led_axp192.c) zephyr_library_sources_ifdef(CONFIG_LED_DAC led_dac.c) zephyr_library_sources_ifdef(CONFIG_LED_GPIO led_gpio.c) diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig index 0e411ce21f04..c9139846c344 100644 --- a/drivers/led/Kconfig +++ b/drivers/led/Kconfig @@ -34,6 +34,7 @@ source "drivers/led/Kconfig.ht16k33" source "drivers/led/Kconfig.is31fl3194" source "drivers/led/Kconfig.is31fl3216a" source "drivers/led/Kconfig.is31fl3733" +source "drivers/led/Kconfig.leds-group-multicolor" source "drivers/led/Kconfig.lp3943" source "drivers/led/Kconfig.lp50xx" source "drivers/led/Kconfig.lp5562" diff --git a/drivers/led/Kconfig.leds-group-multicolor b/drivers/led/Kconfig.leds-group-multicolor new file mode 100644 index 000000000000..9340c4547703 --- /dev/null +++ b/drivers/led/Kconfig.leds-group-multicolor @@ -0,0 +1,12 @@ +# Copyright (c) 2025 Seagate Technology LLC +# SPDX-License-Identifier: Apache-2.0 + +config LEDS_GROUP_MULTICOLOR + bool "LEDs group multi-color driver" + default y + depends on DT_HAS_LEDS_GROUP_MULTICOLOR_ENABLED + help + Enable this driver to supports multi-color LEDs built with several + monochromatic LEDs. + + See the leds-group-multicolor DT binding for details. diff --git a/drivers/led/Kconfig.pwm b/drivers/led/Kconfig.pwm index 8247df198b47..977a0c009f38 100644 --- a/drivers/led/Kconfig.pwm +++ b/drivers/led/Kconfig.pwm @@ -4,6 +4,7 @@ config LED_PWM bool "PWM LED driver" default y - depends on PWM && DT_HAS_PWM_LEDS_ENABLED + depends on DT_HAS_PWM_LEDS_ENABLED + select PWM help Enable driver for PWM LEDs. diff --git a/drivers/led/leds_group_multicolor.c b/drivers/led/leds_group_multicolor.c new file mode 100644 index 000000000000..f9613a02244d --- /dev/null +++ b/drivers/led/leds_group_multicolor.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2025 Seagate Technology LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT leds_group_multicolor + +/** + * @file + * @brief Driver for multi-color LED built from monochromatic LEDs. + */ + +#include +#include +#include + +#include +LOG_MODULE_REGISTER(leds_group_multicolor, CONFIG_LED_LOG_LEVEL); + +struct leds_group_multicolor_config { + uint8_t num_leds; + const struct led_dt_spec *led; +}; + +static int leds_group_multicolor_set_color(const struct device *dev, uint32_t led, + uint8_t num_colors, const uint8_t *color) +{ + const struct leds_group_multicolor_config *config = dev->config; + + if (led != 0) { + return -EINVAL; + } + if (num_colors != config->num_leds) { + return -EINVAL; + } + + for (uint8_t i = 0; i < num_colors; i++) { + int err; + + err = led_set_brightness_dt(&config->led[i], color[i]); + if (err) { + return err; + } + } + + return 0; +} + +static int leds_group_multicolor_init(const struct device *dev) +{ + const struct leds_group_multicolor_config *config = dev->config; + + for (uint8_t i = 0; i < config->num_leds; i++) { + const struct led_dt_spec *led = &config->led[i]; + + if (!led_is_ready_dt(led)) { + LOG_ERR("%s: LED device %s is not ready", dev->name, led->dev->name); + return -ENODEV; + } + } + + return 0; +} + +static DEVICE_API(led, leds_group_multicolor_api) = { + .set_color = leds_group_multicolor_set_color, +}; + +#define LED_DT_SPEC_GET_BY_PHANDLE_IDX(node_id, prop, idx) \ + LED_DT_SPEC_GET(DT_PHANDLE_BY_IDX(node_id, prop, idx)) + +#define LEDS_GROUP_MULTICOLOR_DEVICE(inst) \ + \ + BUILD_ASSERT(DT_INST_PROP_LEN(inst, leds) > 0, \ + "at least one LED phandle must be present"); \ + \ + static const struct led_dt_spec led_group_multicolor_##inst[] = { \ + DT_INST_FOREACH_PROP_ELEM_SEP( \ + inst, leds, LED_DT_SPEC_GET_BY_PHANDLE_IDX, (,)) \ + }; \ + \ + static const struct leds_group_multicolor_config \ + leds_group_multicolor_config_##inst = { \ + .num_leds = ARRAY_SIZE(led_group_multicolor_##inst), \ + .led = led_group_multicolor_##inst, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, &leds_group_multicolor_init, NULL, \ + NULL, &leds_group_multicolor_config_##inst, \ + POST_KERNEL, CONFIG_LED_INIT_PRIORITY, \ + &leds_group_multicolor_api); + +DT_INST_FOREACH_STATUS_OKAY(LEDS_GROUP_MULTICOLOR_DEVICE) diff --git a/dts/bindings/led/gpio-leds.yaml b/dts/bindings/led/gpio-leds.yaml index 3589b394c8c9..13206fc9e307 100644 --- a/dts/bindings/led/gpio-leds.yaml +++ b/dts/bindings/led/gpio-leds.yaml @@ -36,13 +36,13 @@ compatible: "gpio-leds" child-binding: description: GPIO LED child node + + include: + - name: led-node.yaml + property-allowlist: + - label + properties: gpios: type: phandle-array required: true - label: - type: string - description: | - Human readable string describing the LED. It can be used by an - application to identify this LED or to retrieve its number/index - (i.e. child node number) on the parent device. diff --git a/dts/bindings/led/led-controller.yaml b/dts/bindings/led/led-controller.yaml index 86aac36baf51..30deb0f8b2ae 100644 --- a/dts/bindings/led/led-controller.yaml +++ b/dts/bindings/led/led-controller.yaml @@ -5,10 +5,10 @@ child-binding: description: LED child node + + include: led-node.yaml + properties: - label: - type: string - description: Human readable string describing the LED index: type: int description: | @@ -17,16 +17,3 @@ child-binding: controller. For example, this allows to handle boards where the LEDs in an array/strip are not wired following the LED order of the controller. - color-mapping: - type: array - description: | - Channel to color mapping of a multicolor LED. If a LED supports - several colors, then the color-mapping property can be used to - describe how the hardware channels and the colors are mapped. - - For example the channel to color mapping of RGB LEDs would be - - color-mapping = - , - , - ; diff --git a/dts/bindings/led/led-node.yaml b/dts/bindings/led/led-node.yaml new file mode 100644 index 000000000000..cd5b66394f9b --- /dev/null +++ b/dts/bindings/led/led-node.yaml @@ -0,0 +1,25 @@ +# Copyright (c) 2025 Seagate Technology LLC +# SPDX-License-Identifier: Apache-2.0 + +# Common fields for LED nodes + +properties: + label: + type: string + description: | + Human readable string describing the LED. It can be used by an + application to identify this LED or to retrieve its number/index + (i.e. child node number) on the parent device. + color-mapping: + type: array + description: | + Channel to color mapping of a multicolor LED. If a LED supports + several colors, then the color-mapping property can be used to + describe how the hardware channels and the colors are mapped. + + For example the channel to color mapping of RGB LEDs would be + + color-mapping = + , + , + ; diff --git a/dts/bindings/led/leds-group-multicolor.yaml b/dts/bindings/led/leds-group-multicolor.yaml new file mode 100644 index 000000000000..4a6008b151d2 --- /dev/null +++ b/dts/bindings/led/leds-group-multicolor.yaml @@ -0,0 +1,49 @@ +# Copyright (c) 2025 Seagate Technology LLC +# SPDX-License-Identifier: Apache-2.0 + +title: Combines several monochromatic LEDs into one multi-color LED. + +description: | + Here is an example that defines an RGB LED with a group of monochromatic + PWM LEDs. Note that the pwms property definition handle depends on the PWM + controller model. In this example, an STM32 PWM controller is assumed. + + #include + + / { + monochromatic-leds { + compatible = "pwm-leds"; + + red_pwm_led: led-0 { + pwms = <&pwm1 1 PWM_MSEC(20) PWM_POLARITY_NORMAL>; + }; + + green_pwm_led: led-1 { + pwms = <&pwm2 1 PWM_MSEC(20) PWM_POLARITY_NORMAL>; + }; + + blue_pwm_led: led-2 { + pwms = <&pwm3 1 PWM_MSEC(20) PWM_POLARITY_NORMAL>; + }; + }; + + rgb-led { + compatible = "leds-group-multicolor"; + + leds = <&red_pwm_led>, <&green_pwm_led>, <&blue_pwm_led>; + color-mapping = , + , + ; + }; + }; + +compatible: "leds-group-multicolor" + +include: led-node.yaml + +properties: + leds: + required: true + type: phandles + description: | + References to monochromatic LED nodes. diff --git a/dts/bindings/led/pwm-leds.yaml b/dts/bindings/led/pwm-leds.yaml index c5619e038831..0394d34bb9fe 100644 --- a/dts/bindings/led/pwm-leds.yaml +++ b/dts/bindings/led/pwm-leds.yaml @@ -10,6 +10,12 @@ compatible: "pwm-leds" child-binding: description: PWM LED child node + + include: + - name: led-node.yaml + property-allowlist: + - label + properties: pwms: required: true @@ -22,10 +28,3 @@ child-binding: brigtness granularity) and lesser than 50 milliseconds (average visual persistence time of the human eye). Typical values for the PWM period are 10 or 20 milliseconds. - - label: - type: string - description: | - Human readable string describing the LED. It can be used by an - application to identify this LED or to retrieve its number/index - (i.e. child node number) on the parent device. diff --git a/samples/drivers/led/pwm/prj.conf b/samples/drivers/led/pwm/prj.conf index b6286f0aa56a..547575b6dc9a 100644 --- a/samples/drivers/led/pwm/prj.conf +++ b/samples/drivers/led/pwm/prj.conf @@ -1,7 +1,5 @@ CONFIG_LOG=y -CONFIG_PWM=y - CONFIG_LED=y CONFIG_LOG_MODE_IMMEDIATE=y diff --git a/tests/drivers/build_all/led/app.overlay b/tests/drivers/build_all/led/app.overlay index ce0e7ee4ad62..185ea95960b5 100644 --- a/tests/drivers/build_all/led/app.overlay +++ b/tests/drivers/build_all/led/app.overlay @@ -207,6 +207,14 @@ test_pwm_led0: test_pwm_led_0 { pwms = <&test_pwm 0 0 0>; }; + test_pwm_led1: test_pwm_led_1 { + pwms = <&test_pwm 1 0 0>; + }; + }; + + multi-led { + compatible = "leds-group-multicolor"; + leds = <&test_pwm_led0>, <&test_pwm_led1>; }; }; }; diff --git a/tests/drivers/build_all/led/prj.conf b/tests/drivers/build_all/led/prj.conf index d3ea88e4d47f..ab827be3a48b 100644 --- a/tests/drivers/build_all/led/prj.conf +++ b/tests/drivers/build_all/led/prj.conf @@ -1,4 +1,3 @@ CONFIG_TEST=y CONFIG_TEST_USERSPACE=y CONFIG_LED=y -CONFIG_PWM=y