drivers: led: lp503x: extend driver to all lp50xx devices
Add support for LP5009, LP5012, LP5018 and LP5024 devices which only
differ by the number of LEDs they can control.
Also, update application sample to run on all these new supported
devices.
Based on initial work from:
- Marek Janus <marek.janus@grinn-global.com>
- Rico Ganahl <rico.ganahl@bytesatwork.ch>
Signed-off-by: Mathieu Anquetin <mathieu.anquetin@groupe-cahors.com>
diff --git a/drivers/led/CMakeLists.txt b/drivers/led/CMakeLists.txt
index 2560b03..6bd4e67 100644
--- a/drivers/led/CMakeLists.txt
+++ b/drivers/led/CMakeLists.txt
@@ -11,7 +11,7 @@
zephyr_library_sources_ifdef(CONFIG_LED_PWM led_pwm.c)
zephyr_library_sources_ifdef(CONFIG_LED_XEC led_mchp_xec.c)
zephyr_library_sources_ifdef(CONFIG_LP3943 lp3943.c)
-zephyr_library_sources_ifdef(CONFIG_LP503X lp503x.c)
+zephyr_library_sources_ifdef(CONFIG_LP50XX lp50xx.c)
zephyr_library_sources_ifdef(CONFIG_LP5562 lp5562.c)
zephyr_library_sources_ifdef(CONFIG_LP5569 lp5569.c)
zephyr_library_sources_ifdef(CONFIG_PCA9633 pca9633.c)
diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig
index 65d2449..e129017 100644
--- a/drivers/led/Kconfig
+++ b/drivers/led/Kconfig
@@ -30,7 +30,7 @@
source "drivers/led/Kconfig.ht16k33"
source "drivers/led/Kconfig.is31fl3216a"
source "drivers/led/Kconfig.lp3943"
-source "drivers/led/Kconfig.lp503x"
+source "drivers/led/Kconfig.lp50xx"
source "drivers/led/Kconfig.lp5562"
source "drivers/led/Kconfig.lp5569"
source "drivers/led/Kconfig.npm1300"
diff --git a/drivers/led/Kconfig.lp503x b/drivers/led/Kconfig.lp503x
deleted file mode 100644
index 70d272c..0000000
--- a/drivers/led/Kconfig.lp503x
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright (c) 2020 Seagate Technology LLC
-# SPDX-License-Identifier: Apache-2.0
-
-config LP503X
- bool "LP503X LED controller"
- default y
- depends on DT_HAS_TI_LP503X_ENABLED
- select I2C
- help
- Enable driver for the Texas Instruments LP5030 and LP5036 I2C LED
- controllers. They are respectively supporting up to 10 and 12 LEDs.
diff --git a/drivers/led/Kconfig.lp50xx b/drivers/led/Kconfig.lp50xx
new file mode 100644
index 0000000..faf7746
--- /dev/null
+++ b/drivers/led/Kconfig.lp50xx
@@ -0,0 +1,15 @@
+# Copyright (c) 2020 Seagate Technology LLC
+# Copyright (c) 2022 Grinn
+# SPDX-License-Identifier: Apache-2.0
+
+config LP50XX
+ bool "LP50XX LED controller"
+ default y
+ depends on DT_HAS_TI_LP5009_ENABLED || DT_HAS_TI_LP5012_ENABLED || \
+ DT_HAS_TI_LP5018_ENABLED || DT_HAS_TI_LP5024_ENABLED || \
+ DT_HAS_TI_LP5030_ENABLED || DT_HAS_TI_LP5036_ENABLED
+ select I2C
+ help
+ Enable driver for the Texas Instruments LP50XX I2C LED
+ controllers. It supports: LP5009, LP5012, LP5018, LP5024,
+ LP5030 and LP5036.
diff --git a/drivers/led/lp503x.c b/drivers/led/lp503x.c
deleted file mode 100644
index fac9eca..0000000
--- a/drivers/led/lp503x.c
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * Copyright (c) 2020 Seagate Technology LLC
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-
-#define DT_DRV_COMPAT ti_lp503x
-
-/**
- * @file
- * @brief LP503x LED controller
- */
-
-#include <zephyr/drivers/i2c.h>
-#include <zephyr/drivers/led.h>
-#include <zephyr/drivers/led/lp503x.h>
-#include <zephyr/device.h>
-#include <zephyr/kernel.h>
-
-#define LOG_LEVEL CONFIG_LED_LOG_LEVEL
-#include <zephyr/logging/log.h>
-LOG_MODULE_REGISTER(lp503x);
-
-#define LP503X_DEVICE_CONFIG0 0
-#define CONFIG0_CHIP_EN BIT(6)
-
-#define LP503X_DEVICE_CONFIG1 0x1
-#define CONFIG1_LED_GLOBAL_OFF BIT(0)
-#define CONFIG1_MAX_CURRENT_OPT BIT(1)
-#define CONFIG1_PWM_DITHERING_EN BIT(2)
-#define CONFIG1_AUTO_INCR_EN BIT(3)
-#define CONFIG1_POWER_SAVE_EN BIT(4)
-#define CONFIG1_LOG_SCALE_EN BIT(5)
-
-#define LP503X_LED_CONFIG0 0x2
-#define CONFIG0_LED0_BANK_EN BIT(0)
-#define CONFIG0_LED1_BANK_EN BIT(1)
-#define CONFIG0_LED2_BANK_EN BIT(2)
-#define CONFIG0_LED3_BANK_EN BIT(3)
-#define CONFIG0_LED4_BANK_EN BIT(4)
-#define CONFIG0_LED5_BANK_EN BIT(5)
-#define CONFIG0_LED6_BANK_EN BIT(6)
-#define CONFIG0_LED7_BANK_EN BIT(7)
-
-#define LP503X_LED_CONFIG1 0x3
-#define CONFIG1_LED8_BANK_EN BIT(0)
-#define CONFIG1_LED9_BANK_EN BIT(1)
-#define CONFIG1_LED10_BANK_EN BIT(2)
-#define CONFIG1_LED11_BANK_EN BIT(3)
-
-#define LP503X_BANK_BRIGHTNESS 0x4
-#define LP503X_BANK_A_COLOR 0x5
-#define LP503X_BANK_B_COLOR 0x6
-#define LP503X_BANK_C_COLOR 0x7
-
-#define LP503X_LED_BRIGHTNESS_BASE 0x8
-#define LP503X_OUT_COLOR_BASE 0x14
-
-/* Expose channels starting from the bank registers. */
-#define LP503X_CHANNEL_BASE LP503X_BANK_BRIGHTNESS
-
-struct lp503x_config {
- struct i2c_dt_spec bus;
- uint8_t num_leds;
- bool log_scale_en;
- bool max_curr_opt;
- const struct led_info *leds_info;
-};
-
-struct lp503x_data {
- uint8_t *chan_buf;
-};
-
-static const struct led_info *
-lp503x_led_to_info(const struct lp503x_config *config, uint32_t led)
-{
- int i;
-
- for (i = 0; i < config->num_leds; i++) {
- if (config->leds_info[i].index == led) {
- return &config->leds_info[i];
- }
- }
- return NULL;
-}
-
-static int lp503x_get_info(const struct device *dev, uint32_t led,
- const struct led_info **info)
-{
- const struct lp503x_config *config = dev->config;
- const struct led_info *led_info = lp503x_led_to_info(config, led);
-
- if (!led_info) {
- return -EINVAL;
- }
-
- *info = led_info;
-
- return 0;
-}
-
-static int lp503x_set_brightness(const struct device *dev,
- uint32_t led, uint8_t value)
-{
- const struct lp503x_config *config = dev->config;
- const struct led_info *led_info = lp503x_led_to_info(config, led);
- uint8_t buf[2];
-
- if (!led_info || value > 100) {
- return -EINVAL;
- }
-
- buf[0] = LP503X_LED_BRIGHTNESS_BASE + led_info->index;
- buf[1] = (value * 0xff) / 100;
-
- return i2c_write_dt(&config->bus, buf, sizeof(buf));
-}
-
-static int lp503x_on(const struct device *dev, uint32_t led)
-{
- return lp503x_set_brightness(dev, led, 100);
-}
-
-static int lp503x_off(const struct device *dev, uint32_t led)
-{
- return lp503x_set_brightness(dev, led, 0);
-}
-
-static int lp503x_set_color(const struct device *dev, uint32_t led,
- uint8_t num_colors, const uint8_t *color)
-{
- const struct lp503x_config *config = dev->config;
- const struct led_info *led_info = lp503x_led_to_info(config, led);
- uint8_t buf[4];
-
- if (!led_info || num_colors != led_info->num_colors) {
- return -EINVAL;
- }
-
- buf[0] = LP503X_OUT_COLOR_BASE + 3 * led_info->index;
- buf[1] = color[0];
- buf[2] = color[1];
- buf[3] = color[2];
-
- return i2c_write_dt(&config->bus, buf, sizeof(buf));
-}
-
-static int lp503x_write_channels(const struct device *dev,
- uint32_t start_channel,
- uint32_t num_channels, const uint8_t *buf)
-{
- const struct lp503x_config *config = dev->config;
- struct lp503x_data *data = dev->data;
-
- if (start_channel >= LP503X_NUM_CHANNELS ||
- start_channel + num_channels > LP503X_NUM_CHANNELS) {
- return -EINVAL;
- }
-
- /*
- * Unfortunately this controller don't support commands split into
- * two I2C messages.
- */
- data->chan_buf[0] = LP503X_CHANNEL_BASE + start_channel;
- memcpy(data->chan_buf + 1, buf, num_channels);
-
- return i2c_write_dt(&config->bus, data->chan_buf, num_channels + 1);
-}
-
-static int lp503x_init(const struct device *dev)
-{
- const struct lp503x_config *config = dev->config;
- uint8_t buf[3];
- int err;
-
- if (!device_is_ready(config->bus.bus)) {
- LOG_ERR("I2C device not ready");
- return -ENODEV;
- }
- if (config->num_leds > LP503X_MAX_LEDS) {
- LOG_ERR("%s: invalid number of LEDs %d (max %d)",
- dev->name, config->num_leds, LP503X_MAX_LEDS);
- return -EINVAL;
- }
-
- /*
- * Since the status of the LP503x controller is unknown when entering
- * this function, and since there is no way to reset it, then the whole
- * configuration must be applied.
- */
-
- /* Disable bank control for all LEDs. */
- buf[0] = LP503X_LED_CONFIG0;
- buf[1] = 0;
- buf[2] = 0;
- err = i2c_write_dt(&config->bus, buf, 3);
- if (err < 0) {
- return err;
- }
-
- /* Enable LED controller. */
- buf[0] = LP503X_DEVICE_CONFIG0;
- buf[1] = CONFIG0_CHIP_EN;
- err = i2c_write_dt(&config->bus, buf, 2);
- if (err < 0) {
- return err;
- }
-
- /* Apply configuration. */
- buf[0] = LP503X_DEVICE_CONFIG1;
- buf[1] = CONFIG1_PWM_DITHERING_EN | CONFIG1_AUTO_INCR_EN
- | CONFIG1_POWER_SAVE_EN;
- if (config->max_curr_opt) {
- buf[1] |= CONFIG1_MAX_CURRENT_OPT;
- }
- if (config->log_scale_en) {
- buf[1] |= CONFIG1_LOG_SCALE_EN;
- }
-
- return i2c_write_dt(&config->bus, buf, 2);
-}
-
-static const struct led_driver_api lp503x_led_api = {
- .on = lp503x_on,
- .off = lp503x_off,
- .get_info = lp503x_get_info,
- .set_brightness = lp503x_set_brightness,
- .set_color = lp503x_set_color,
- .write_channels = lp503x_write_channels,
-};
-
-#define COLOR_MAPPING(led_node_id) \
-const uint8_t color_mapping_##led_node_id[] = \
- DT_PROP(led_node_id, color_mapping);
-
-#define LED_INFO(led_node_id) \
-{ \
- .label = DT_PROP(led_node_id, label), \
- .index = DT_PROP(led_node_id, index), \
- .num_colors = \
- DT_PROP_LEN(led_node_id, color_mapping), \
- .color_mapping = color_mapping_##led_node_id, \
-},
-
-#define LP503x_DEVICE(id) \
- \
-DT_INST_FOREACH_CHILD(id, COLOR_MAPPING) \
- \
-const struct led_info lp503x_leds_##id[] = { \
- DT_INST_FOREACH_CHILD(id, LED_INFO) \
-}; \
- \
-static uint8_t lp503x_chan_buf_##id[LP503X_NUM_CHANNELS + 1]; \
- \
-static const struct lp503x_config lp503x_config_##id = { \
- .bus = I2C_DT_SPEC_INST_GET(id), \
- .num_leds = ARRAY_SIZE(lp503x_leds_##id), \
- .max_curr_opt = DT_INST_PROP(id, max_curr_opt), \
- .log_scale_en = DT_INST_PROP(id, log_scale_en), \
- .leds_info = lp503x_leds_##id, \
-}; \
- \
-static struct lp503x_data lp503x_data_##id = { \
- .chan_buf = lp503x_chan_buf_##id, \
-}; \
- \
-DEVICE_DT_INST_DEFINE(id, \
- &lp503x_init, \
- NULL, \
- &lp503x_data_##id, \
- &lp503x_config_##id, \
- POST_KERNEL, CONFIG_LED_INIT_PRIORITY, \
- &lp503x_led_api);
-
-DT_INST_FOREACH_STATUS_OKAY(LP503x_DEVICE)
diff --git a/drivers/led/lp50xx.c b/drivers/led/lp50xx.c
new file mode 100644
index 0000000..38c2a1e
--- /dev/null
+++ b/drivers/led/lp50xx.c
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2020 Seagate Technology LLC
+ * Copyright (c) 2022 Grinn
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/**
+ * @file
+ * @brief LP50xx LED controller
+ */
+#include <errno.h>
+#include <zephyr/device.h>
+#include <zephyr/devicetree.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/drivers/led.h>
+#include <zephyr/drivers/led/lp50xx.h>
+#include <zephyr/kernel.h>
+#include <zephyr/sys/util.h>
+
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(lp50xx, CONFIG_LED_LOG_LEVEL);
+
+#define LP50XX_MIN_BRIGHTNESS 0U
+#define LP50XX_MAX_BRIGHTNESS 100U
+
+/*
+ * Number of supported RGB led modules per chipset.
+ *
+ * For each module, there are 4 associated registers:
+ * - 1 brightness register
+ * - 3 color registers (RGB)
+ *
+ * A chipset can have more modules than leds. In this case, the
+ * associated registers will simply be inactive.
+ */
+#define LP5012_NUM_MODULES 4
+#define LP5024_NUM_MODULES 8
+#define LP5036_NUM_MODULES 12
+
+/* Maximum number of channels */
+#define LP50XX_MAX_CHANNELS(nmodules) \
+ ((LP50XX_COLORS_PER_LED + 1) * ((nmodules) + 1))
+
+/* Base registers */
+#define LP50XX_DEVICE_CONFIG0 0x00
+#define LP50XX_DEVICE_CONFIG1 0x01
+#define LP50XX_LED_CONFIG0 0x02
+
+#define LP50XX_BANK_BASE(nmodules) \
+ (0x03 + (((nmodules) - 1) / 8))
+
+#define LP50XX_LED0_BRIGHTNESS(nmodules) \
+ ((LP50XX_BANK_BASE(nmodules)) + 4)
+
+#define LP50XX_OUT0_COLOR(nmodules) \
+ (LP50XX_LED0_BRIGHTNESS(nmodules) + (nmodules))
+
+/* Register values */
+#define CONFIG0_CHIP_EN BIT(6)
+
+#define CONFIG1_LED_GLOBAL_OFF BIT(0)
+#define CONFIG1_MAX_CURRENT_OPT BIT(1)
+#define CONFIG1_PWM_DITHERING_EN BIT(2)
+#define CONFIG1_AUTO_INCR_EN BIT(3)
+#define CONFIG1_POWER_SAVE_EN BIT(4)
+#define CONFIG1_LOG_SCALE_EN BIT(5)
+
+struct lp50xx_config {
+ struct i2c_dt_spec bus;
+ uint8_t num_modules;
+ uint8_t max_leds;
+ uint8_t num_leds;
+ bool log_scale_en;
+ bool max_curr_opt;
+ const struct led_info *leds_info;
+};
+
+struct lp50xx_data {
+ uint8_t *chan_buf;
+};
+
+static const struct led_info *lp50xx_led_to_info(
+ const struct lp50xx_config *config, uint32_t led)
+{
+ const struct led_info *led_info = NULL;
+
+ for (uint8_t i = 0; i < config->num_leds; i++) {
+ if (config->leds_info[i].index == led) {
+ led_info = &config->leds_info[i];
+ }
+ }
+ return led_info;
+}
+
+static int lp50xx_get_info(const struct device *dev, uint32_t led,
+ const struct led_info **info)
+{
+ const struct lp50xx_config *config = dev->config;
+ const struct led_info *led_info = lp50xx_led_to_info(config, led);
+
+ if (!led_info) {
+ return -EINVAL;
+ }
+
+ *info = led_info;
+
+ return 0;
+}
+
+static int lp50xx_set_brightness(const struct device *dev,
+ uint32_t led, uint8_t value)
+{
+ const struct lp50xx_config *config = dev->config;
+ const struct led_info *led_info = lp50xx_led_to_info(config, led);
+ uint8_t buf[2];
+
+ if (!led_info) {
+ return -ENODEV;
+ }
+
+ if (!IN_RANGE(value, LP50XX_MIN_BRIGHTNESS, LP50XX_MAX_BRIGHTNESS)) {
+ LOG_ERR("%s: brightness value out of bounds: "
+ "val=%d, min=%d, max=%d",
+ dev->name,
+ value,
+ LP50XX_MIN_BRIGHTNESS,
+ LP50XX_MAX_BRIGHTNESS);
+ return -EINVAL;
+ }
+
+ buf[0] = LP50XX_LED0_BRIGHTNESS(config->num_modules) + led_info->index;
+ buf[1] = (value * 0xff) / 100;
+
+ return i2c_write_dt(&config->bus, buf, sizeof(buf));
+}
+
+static int lp50xx_on(const struct device *dev, uint32_t led)
+{
+ return lp50xx_set_brightness(dev, led, 100);
+}
+
+static int lp50xx_off(const struct device *dev, uint32_t led)
+{
+ return lp50xx_set_brightness(dev, led, 0);
+}
+
+static int lp50xx_set_color(const struct device *dev, uint32_t led,
+ uint8_t num_colors, const uint8_t *color)
+{
+ const struct lp50xx_config *config = dev->config;
+ const struct led_info *led_info = lp50xx_led_to_info(config, led);
+ uint8_t buf[4];
+
+ if (!led_info) {
+ return -ENODEV;
+ }
+
+ if (num_colors != led_info->num_colors) {
+ LOG_ERR("%s: invalid number of colors: got=%d, expected=%d",
+ dev->name,
+ num_colors,
+ led_info->num_colors);
+ return -EINVAL;
+ }
+
+ buf[0] = LP50XX_OUT0_COLOR(config->num_modules);
+ buf[0] += LP50XX_COLORS_PER_LED * led_info->index;
+
+ buf[1] = color[0];
+ buf[2] = color[1];
+ buf[3] = color[2];
+
+ return i2c_write_dt(&config->bus, buf, sizeof(buf));
+}
+
+static int lp50xx_write_channels(const struct device *dev,
+ uint32_t start_channel,
+ uint32_t num_channels, const uint8_t *buf)
+{
+ const struct lp50xx_config *config = dev->config;
+ struct lp50xx_data *data = dev->data;
+ uint8_t base_channel, end_channel, max_channels;
+
+ base_channel = LP50XX_BANK_BASE(config->num_modules);
+ end_channel = base_channel + start_channel + num_channels;
+ max_channels = base_channel + LP50XX_MAX_CHANNELS(config->num_modules);
+
+ if (end_channel > max_channels) {
+ return -EINVAL;
+ }
+
+ /*
+ * Unfortunately this controller doesn't support commands split into
+ * two I2C messages.
+ */
+ data->chan_buf[0] = base_channel + start_channel;
+ memcpy(data->chan_buf + 1, buf, num_channels);
+
+ return i2c_write_dt(&config->bus, data->chan_buf, num_channels + 1);
+}
+
+static int lp50xx_init(const struct device *dev)
+{
+ const struct lp50xx_config *config = dev->config;
+ uint8_t buf[3];
+ int err;
+
+ if (!i2c_is_ready_dt(&config->bus)) {
+ LOG_ERR("%s: I2C device not ready", dev->name);
+ return -ENODEV;
+ }
+
+ if (config->num_leds > config->max_leds) {
+ LOG_ERR("%s: invalid number of LEDs %d (max %d)",
+ dev->name,
+ config->num_leds,
+ config->max_leds);
+ return -EINVAL;
+ }
+
+ /*
+ * Since the status of the LP503x controller is unknown when entering
+ * this function, and since there is no way to reset it, then the whole
+ * configuration must be applied.
+ */
+
+ /* Disable bank control for all LEDs. */
+ buf[0] = LP50XX_LED_CONFIG0;
+ buf[1] = 0;
+ buf[2] = 0;
+ if (config->chip == LP5009 || config->chip == LP5012) {
+ err = i2c_write_dt(&config->bus, buf, 2);
+ } else {
+ err = i2c_write_dt(&config->bus, buf, 3);
+ }
+ if (err < 0) {
+ return err;
+ }
+
+ /* Enable LED controller. */
+ buf[0] = LP50XX_DEVICE_CONFIG0;
+ buf[1] = CONFIG0_CHIP_EN;
+ err = i2c_write_dt(&config->bus, buf, 2);
+ if (err < 0) {
+ return err;
+ }
+
+ /* Apply configuration. */
+ buf[0] = LP50XX_DEVICE_CONFIG1;
+ buf[1] = CONFIG1_PWM_DITHERING_EN | CONFIG1_AUTO_INCR_EN
+ | CONFIG1_POWER_SAVE_EN;
+ if (config->max_curr_opt) {
+ buf[1] |= CONFIG1_MAX_CURRENT_OPT;
+ }
+ if (config->log_scale_en) {
+ buf[1] |= CONFIG1_LOG_SCALE_EN;
+ }
+
+ return i2c_write_dt(&config->bus, buf, 2);
+}
+
+static const struct led_driver_api lp50xx_led_api = {
+ .on = lp50xx_on,
+ .off = lp50xx_off,
+ .get_info = lp50xx_get_info,
+ .set_brightness = lp50xx_set_brightness,
+ .set_color = lp50xx_set_color,
+ .write_channels = lp50xx_write_channels,
+};
+
+#define COLOR_MAPPING(led_node_id) \
+ const uint8_t color_mapping_##led_node_id[] = \
+ DT_PROP(led_node_id, color_mapping);
+
+#define LED_INFO(led_node_id) \
+ { \
+ .label = DT_PROP(led_node_id, label), \
+ .index = DT_PROP(led_node_id, index), \
+ .num_colors = \
+ DT_PROP_LEN(led_node_id, color_mapping), \
+ .color_mapping = color_mapping_##led_node_id, \
+ },
+
+#define LP50XX_DEVICE(n, id, nmodules) \
+ DT_INST_FOREACH_CHILD(n, COLOR_MAPPING) \
+ \
+ static const struct led_info lp##id##_leds_##n[] = { \
+ DT_INST_FOREACH_CHILD(n, LED_INFO) \
+ }; \
+ \
+ static const struct lp50xx_config lp##id##_config_##n = { \
+ .bus = I2C_DT_SPEC_INST_GET(n), \
+ .num_modules = nmodules, \
+ .max_leds = LP##id##_MAX_LEDS, \
+ .num_leds = ARRAY_SIZE(lp##id##_leds_##n), \
+ .log_scale_en = DT_INST_PROP(n, log_scale_en), \
+ .max_curr_opt = DT_INST_PROP(n, max_curr_opt), \
+ .leds_info = lp##id##_leds_##n, \
+ }; \
+ \
+ static uint8_t lp##id##_chan_buf_##n[LP50XX_MAX_CHANNELS(nmodules) + 1];\
+ \
+ static struct lp50xx_data lp##id##_data_##n = { \
+ .chan_buf = lp##id##_chan_buf_##n, \
+ }; \
+ \
+ DEVICE_DT_INST_DEFINE(n, \
+ lp50xx_init, \
+ NULL, \
+ &lp##id##_data_##n, \
+ &lp##id##_config_##n, \
+ POST_KERNEL, CONFIG_LED_INIT_PRIORITY, \
+ &lp50xx_led_api);
+
+#undef DT_DRV_COMPAT
+#define DT_DRV_COMPAT ti_lp5009
+DT_INST_FOREACH_STATUS_OKAY_VARGS(LP50XX_DEVICE, 5009, LP5012_NUM_MODULES)
+
+#undef DT_DRV_COMPAT
+#define DT_DRV_COMPAT ti_lp5012
+DT_INST_FOREACH_STATUS_OKAY_VARGS(LP50XX_DEVICE, 5012, LP5012_NUM_MODULES)
+
+#undef DT_DRV_COMPAT
+#define DT_DRV_COMPAT ti_lp5018
+DT_INST_FOREACH_STATUS_OKAY_VARGS(LP50XX_DEVICE, 5018, LP5024_NUM_MODULES)
+
+#undef DT_DRV_COMPAT
+#define DT_DRV_COMPAT ti_lp5024
+DT_INST_FOREACH_STATUS_OKAY_VARGS(LP50XX_DEVICE, 5024, LP5024_NUM_MODULES)
+
+#undef DT_DRV_COMPAT
+#define DT_DRV_COMPAT ti_lp5030
+DT_INST_FOREACH_STATUS_OKAY_VARGS(LP50XX_DEVICE, 5030, LP5036_NUM_MODULES)
+
+#undef DT_DRV_COMPAT
+#define DT_DRV_COMPAT ti_lp5036
+DT_INST_FOREACH_STATUS_OKAY_VARGS(LP50XX_DEVICE, 5036, LP5036_NUM_MODULES)
diff --git a/dts/bindings/led/ti,lp5009.yaml b/dts/bindings/led/ti,lp5009.yaml
new file mode 100644
index 0000000..d6fdafe
--- /dev/null
+++ b/dts/bindings/led/ti,lp5009.yaml
@@ -0,0 +1,5 @@
+description: Texas Instruments LP5009 I2C LED controller node
+
+compatible: ti,lp5009
+
+include: ti,lp50xx.yaml
diff --git a/dts/bindings/led/ti,lp5012.yaml b/dts/bindings/led/ti,lp5012.yaml
new file mode 100644
index 0000000..6be0abf
--- /dev/null
+++ b/dts/bindings/led/ti,lp5012.yaml
@@ -0,0 +1,5 @@
+description: Texas Instruments LP5012 I2C LED controller node
+
+compatible: ti,lp5012
+
+include: ti,lp50xx.yaml
diff --git a/dts/bindings/led/ti,lp5018.yaml b/dts/bindings/led/ti,lp5018.yaml
new file mode 100644
index 0000000..1d86419
--- /dev/null
+++ b/dts/bindings/led/ti,lp5018.yaml
@@ -0,0 +1,5 @@
+description: Texas Instruments LP5018 I2C LED controller node
+
+compatible: ti,lp5018
+
+include: ti,lp50xx.yaml
diff --git a/dts/bindings/led/ti,lp5024.yaml b/dts/bindings/led/ti,lp5024.yaml
new file mode 100644
index 0000000..f9161b0
--- /dev/null
+++ b/dts/bindings/led/ti,lp5024.yaml
@@ -0,0 +1,5 @@
+description: Texas Instruments LP5024 I2C LED controller node
+
+compatible: ti,lp5024
+
+include: ti,lp50xx.yaml
diff --git a/dts/bindings/led/ti,lp5030.yaml b/dts/bindings/led/ti,lp5030.yaml
new file mode 100644
index 0000000..13d775a
--- /dev/null
+++ b/dts/bindings/led/ti,lp5030.yaml
@@ -0,0 +1,5 @@
+description: Texas Instruments LP5030 I2C LED controller node
+
+compatible: ti,lp5030
+
+include: ti,lp50xx.yaml
diff --git a/dts/bindings/led/ti,lp5036.yaml b/dts/bindings/led/ti,lp5036.yaml
new file mode 100644
index 0000000..c031059
--- /dev/null
+++ b/dts/bindings/led/ti,lp5036.yaml
@@ -0,0 +1,5 @@
+description: Texas Instruments LP5036 I2C LED controller node
+
+compatible: ti,lp5036
+
+include: ti,lp50xx.yaml
diff --git a/dts/bindings/led/ti,lp503x.yaml b/dts/bindings/led/ti,lp50xx.yaml
similarity index 89%
rename from dts/bindings/led/ti,lp503x.yaml
rename to dts/bindings/led/ti,lp50xx.yaml
index feac4f2..4c0a140 100644
--- a/dts/bindings/led/ti,lp503x.yaml
+++ b/dts/bindings/led/ti,lp50xx.yaml
@@ -1,10 +1,6 @@
# Copyright (c) 2020 Seagate Technology LLC
# SPDX-License-Identifier: Apache-2.0
-description: TI LP503x LED controller node
-
-compatible: "ti,lp503x"
-
include: ["i2c-device.yaml", "led-controller.yaml"]
properties:
diff --git a/include/zephyr/drivers/led/lp503x.h b/include/zephyr/drivers/led/lp503x.h
deleted file mode 100644
index 3fcce29..0000000
--- a/include/zephyr/drivers/led/lp503x.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2020 Seagate Technology LLC
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-
-
-#ifndef ZEPHYR_INCLUDE_DRIVERS_LED_LP503X_H_
-#define ZEPHYR_INCLUDE_DRIVERS_LED_LP503X_H_
-
-#define LP503X_MAX_LEDS 12
-#define LP503X_COLORS_PER_LED 3
-
-/*
- * LED channels mapping.
- */
-
-#define LP503X_NUM_CHANNELS 52
-
-/* Bank channels. */
-#define LP503X_BANK_CHAN_BASE 0
-#define LP503X_BANK_BRIGHT_CHAN LP503X_BANK_CHAN_BASE
-#define LP503X_BANK_COL1_CHAN(led) (LP503X_BANK_CHAN_BASE + 1)
-#define LP503X_BANK_COL2_CHAN(led) (LP503X_BANK_CHAN_BASE + 2)
-#define LP503X_BANK_COL3_CHAN(led) (LP503X_BANK_CHAN_BASE + 3)
-
-/* LED brightness channels. */
-#define LP503X_LED_BRIGHT_CHAN_BASE 4
-#define LP503X_LED_BRIGHT_CHAN(led) (LP503X_LED_BRIGHT_CHAN_BASE + led)
-
-/* LED color channels. */
-#define LP503X_LED_COL_CHAN_BASE 16
-#define LP503X_LED_COL1_CHAN(led) (LP503X_LED_COL_CHAN_BASE + \
- led * LP503X_COLORS_PER_LED)
-#define LP503X_LED_COL2_CHAN(led) (LP503X_LED_COL_CHAN_BASE + \
- led * LP503X_COLORS_PER_LED + 1)
-#define LP503X_LED_COL3_CHAN(led) (LP503X_LED_COL_CHAN_BASE + \
- led * LP503X_COLORS_PER_LED + 2)
-
-#endif /* ZEPHYR_INCLUDE_DRIVERS_LED_LP503X_H_ */
diff --git a/include/zephyr/drivers/led/lp50xx.h b/include/zephyr/drivers/led/lp50xx.h
new file mode 100644
index 0000000..d18c9cb
--- /dev/null
+++ b/include/zephyr/drivers/led/lp50xx.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2020 Seagate Technology LLC
+ * Copyright (c) 2022 Grinn
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+
+#ifndef ZEPHYR_INCLUDE_DRIVERS_LED_LP50XX_H_
+#define ZEPHYR_INCLUDE_DRIVERS_LED_LP50XX_H_
+
+#define LP50XX_COLORS_PER_LED 3
+
+#define LP5009_MAX_LEDS 3
+#define LP5012_MAX_LEDS 4
+#define LP5018_MAX_LEDS 6
+#define LP5024_MAX_LEDS 8
+#define LP5030_MAX_LEDS 10
+#define LP5036_MAX_LEDS 12
+
+/*
+ * LED channels mapping.
+ */
+
+/* Bank channels */
+#define LP50XX_BANK_CHAN_BASE 0
+#define LP50XX_BANK_BRIGHT_CHAN LP50XX_BANK_CHAN_BASE
+#define LP50XX_BANK_COL1_CHAN(led) (LP50XX_BANK_CHAN_BASE + 1)
+#define LP50XX_BANK_COL2_CHAN(led) (LP50XX_BANK_CHAN_BASE + 2)
+#define LP50XX_BANK_COL3_CHAN(led) (LP50XX_BANK_CHAN_BASE + 3)
+
+/* LED brightness channels. */
+#define LP50XX_LED_BRIGHT_CHAN_BASE 4
+#define LP50XX_LED_BRIGHT_CHAN(led) (LP50XX_LED_BRIGHT_CHAN_BASE + led)
+
+/*
+ * LED color channels.
+ *
+ * Each channel definition is compatible with the following chips:
+ * - LP5012_XXX => LP5009 / LP5012
+ * - LP5024_XXX => LP5018 / LP5024
+ * - LP5036_XXX => LP5030 / LP5036
+ */
+#define LP5012_LED_COL_CHAN_BASE 8
+#define LP5012_LED_COL1_CHAN(led) \
+ (LP5012_LED_COL_CHAN_BASE + led * LP50XX_COLORS_PER_LED)
+#define LP5012_LED_COL2_CHAN(led) \
+ (LP5012_LED_COL_CHAN_BASE + led * LP50XX_COLORS_PER_LED + 1)
+#define LP5012_LED_COL3_CHAN(led) \
+ (LP5012_LED_COL_CHAN_BASE + led * LP50XX_COLORS_PER_LED + 2)
+
+#define LP5024_LED_COL_CHAN_BASE 12
+#define LP5024_LED_COL1_CHAN(led) \
+ (LP5024_LED_COL_CHAN_BASE + led * LP50XX_COLORS_PER_LED)
+#define LP5024_LED_COL2_CHAN(led) \
+ (LP5024_LED_COL_CHAN_BASE + led * LP50XX_COLORS_PER_LED + 1)
+#define LP5024_LED_COL3_CHAN(led) \
+ (LP5024_LED_COL_CHAN_BASE + led * LP50XX_COLORS_PER_LED + 2)
+
+#define LP5036_LED_COL_CHAN_BASE 16
+#define LP5036_LED_COL1_CHAN(led) \
+ (LP5036_LED_COL_CHAN_BASE + led * LP50XX_COLORS_PER_LED)
+#define LP5036_LED_COL2_CHAN(led) \
+ (LP5036_LED_COL_CHAN_BASE + led * LP50XX_COLORS_PER_LED + 1)
+#define LP5036_LED_COL3_CHAN(led) \
+ (LP5036_LED_COL_CHAN_BASE + led * LP50XX_COLORS_PER_LED + 2)
+
+#endif /* ZEPHYR_INCLUDE_DRIVERS_LED_LP50XX_H_ */
diff --git a/samples/drivers/led_lp503x/sample.yaml b/samples/drivers/led_lp503x/sample.yaml
deleted file mode 100644
index bb17bfe..0000000
--- a/samples/drivers/led_lp503x/sample.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-sample:
- description: Demonstration of the LP503x LED driver
- name: LP503x sample
-tests:
- sample.drivers.led.lp503x:
- filter: dt_compat_enabled("ti,lp503x")
- tags: LED
- depends_on: i2c
diff --git a/samples/drivers/led_lp503x/src/main.c b/samples/drivers/led_lp503x/src/main.c
deleted file mode 100644
index 4cf1b97..0000000
--- a/samples/drivers/led_lp503x/src/main.c
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * Copyright (c) 2020 Seagate Technology LLC
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-
-#include <zephyr/device.h>
-#include <errno.h>
-#include <zephyr/drivers/led.h>
-#include <zephyr/drivers/led/lp503x.h>
-#include <zephyr/sys/util.h>
-#include <zephyr/kernel.h>
-
-#define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
-#include <zephyr/logging/log.h>
-LOG_MODULE_REGISTER(main);
-
-#define MAX_BRIGHTNESS 100
-
-#define SLEEP_DELAY_MS 1000
-#define FADE_DELAY_MS 10
-
-#define FADE_DELAY K_MSEC(FADE_DELAY_MS)
-#define SLEEP_DELAY K_MSEC(SLEEP_DELAY_MS)
-
-/*
- * The following colors are shown in the given order.
- */
-static uint8_t colors[][3] = {
- { 0xFF, 0x00, 0x00 }, /* Red */
- { 0x00, 0xFF, 0x00 }, /* Green */
- { 0x00, 0x00, 0xFF }, /* Blue */
- { 0xFF, 0xFF, 0xFF }, /* White */
- { 0xFF, 0xFF, 0x00 }, /* Yellow */
- { 0xFF, 0x00, 0xFF }, /* Purple */
- { 0x00, 0xFF, 0xFF }, /* Cyan */
- { 0xF4, 0x79, 0x20 }, /* Orange */
-};
-
-/**
- * @brief Run tests on a single LED using the LED-based API syscalls.
- *
- * @param lp503x_dev LP503X LED controller device.
- * @param led Number of the LED to test.
- */
-static int run_led_test(const struct device *lp503x_dev, uint8_t led)
-{
- uint8_t idx;
- int err;
-
- LOG_INF("Testing LED %d (LED API)", led);
-
- for (idx = 0; idx < ARRAY_SIZE(colors); idx++) {
- uint16_t level;
-
- /* Update LED color. */
- err = led_set_color(lp503x_dev, led, 3, colors[idx]);
- if (err < 0) {
- LOG_ERR("Failed to set LED %d color to "
- "%02x:%02x:%02x, err=%d", led,
- colors[idx][0], colors[idx][1],
- colors[idx][2], err);
- return err;
- }
- k_sleep(SLEEP_DELAY);
-
- /* Turn LED on. */
- err = led_on(lp503x_dev, led);
- if (err < 0) {
- LOG_ERR("Failed to turn LED %d on, err=%d", led, err);
- return err;
- }
- k_sleep(SLEEP_DELAY);
-
- /* Turn LED off. */
- err = led_off(lp503x_dev, led);
- if (err < 0) {
- LOG_ERR("Failed to turn LED %d off, err=%d", led, err);
- return err;
- }
- k_sleep(SLEEP_DELAY);
-
- /* Set LED brightness gradually to the maximum level. */
- for (level = 0; level <= MAX_BRIGHTNESS; level++) {
- err = led_set_brightness(lp503x_dev, led, level);
- if (err < 0) {
- LOG_ERR("Failed to set LED %d brightness to %d"
- ", err=%d\n", led, level, err);
- return err;
- }
- k_sleep(FADE_DELAY);
- }
- k_sleep(SLEEP_DELAY);
-
- /* Turn LED off. */
- err = led_off(lp503x_dev, led);
- if (err < 0) {
- LOG_ERR("Failed to turn LED %d off, err=%d", led, err);
- return err;
- }
- k_sleep(SLEEP_DELAY);
- }
-
- return 0;
-}
-
-/**
- * @brief Run tests on all the LEDs using the channel-based API syscalls.
- *
- * @param lp503x_dev LP503X LED controller device.
- */
-static int run_channel_test(const struct device *lp503x_dev)
-{
- uint8_t idx;
- uint8_t buffer[LP503X_COLORS_PER_LED * LP503X_MAX_LEDS];
- int err;
-
- LOG_INF("Testing all LEDs (channel API)");
-
- for (idx = 0; idx < ARRAY_SIZE(colors); idx++) {
- uint8_t led;
- uint16_t level;
-
- /* Update LEDs colors. */
- for (led = 0; led < LP503X_MAX_LEDS; led++) {
- uint8_t *col = &buffer[led * 3];
-
- col[0] = colors[idx][0];
- col[1] = colors[idx][1];
- col[2] = colors[idx][2];
- }
- err = led_write_channels(lp503x_dev, LP503X_LED_COL1_CHAN(0),
- LP503X_COLORS_PER_LED *
- LP503X_MAX_LEDS,
- buffer);
- if (err < 0) {
- LOG_ERR("Failed to write channels, start=%d num=%d"
- " err=%d\n", LP503X_LED_COL1_CHAN(0),
- LP503X_COLORS_PER_LED * LP503X_MAX_LEDS, err);
- return err;
- }
- k_sleep(SLEEP_DELAY);
-
- /* Turn LEDs on. */
- for (led = 0; led < LP503X_MAX_LEDS; led++) {
- buffer[led] = MAX_BRIGHTNESS;
- }
- err = led_write_channels(lp503x_dev,
- LP503X_LED_BRIGHT_CHAN(0),
- LP503X_MAX_LEDS, buffer);
- if (err < 0) {
- LOG_ERR("Failed to write channels, start=%d num=%d"
- " err=%d\n", LP503X_LED_BRIGHT_CHAN(0),
- LP503X_MAX_LEDS, err);
- return err;
- }
- k_sleep(SLEEP_DELAY);
-
- /* Turn LEDs off. */
- for (led = 0; led < LP503X_MAX_LEDS; led++) {
- buffer[led] = 0;
- }
- err = led_write_channels(lp503x_dev,
- LP503X_LED_BRIGHT_CHAN(0),
- LP503X_MAX_LEDS, buffer);
- if (err < 0) {
- LOG_ERR("Failed to write channels, start=%d num=%d"
- " err=%d\n", LP503X_LED_BRIGHT_CHAN(0),
- LP503X_MAX_LEDS, err);
- return err;
- }
- k_sleep(SLEEP_DELAY);
-
- /* Set LEDs brightnesses gradually to the maximum level. */
- for (level = 0; level <= MAX_BRIGHTNESS; level++) {
- for (led = 0; led < LP503X_MAX_LEDS; led++) {
- buffer[led] = level;
- }
- err = led_write_channels(lp503x_dev,
- LP503X_LED_BRIGHT_CHAN(0),
- LP503X_MAX_LEDS, buffer);
- if (err < 0) {
- LOG_ERR("Failed to write channels, start=%d"
- " num=%d err=%d\n",
- LP503X_LED_BRIGHT_CHAN(0),
- LP503X_MAX_LEDS, err);
- return err;
- }
- k_sleep(FADE_DELAY);
- }
- k_sleep(SLEEP_DELAY);
-
- /* Turn LEDs off. */
- for (led = 0; led < LP503X_MAX_LEDS; led++) {
- buffer[led] = 0;
- }
- err = led_write_channels(lp503x_dev,
- LP503X_LED_BRIGHT_CHAN(0),
- LP503X_MAX_LEDS, buffer);
- if (err < 0) {
- LOG_ERR("Failed to write channels, start=%d "
- "num=%d err=%d\n", LP503X_LED_BRIGHT_CHAN(0),
- LP503X_MAX_LEDS, err);
- return err;
- }
- k_sleep(SLEEP_DELAY);
- }
-
- return 0;
-}
-
-int main(void)
-{
- const struct device *const lp503x_dev = DEVICE_DT_GET_ANY(ti_lp503x);
-
- int err;
- uint8_t led;
- uint8_t num_leds = 0;
-
- if (!lp503x_dev) {
- LOG_ERR("No device with compatible ti,lp503x found");
- return 0;
- } else if (!device_is_ready(lp503x_dev)) {
- LOG_ERR("LED controller %s is not ready", lp503x_dev->name);
- return 0;
- }
- LOG_INF("Found LED controller %s", lp503x_dev->name);
-
- for (led = 0; led < LP503X_MAX_LEDS; led++) {
- int col;
- const struct led_info *info;
-
- err = led_get_info(lp503x_dev, led, &info);
- if (err < 0) {
- LOG_DBG("Failed to get information for LED %d (err=%d)",
- led, err);
- break;
- }
-
- /* Display LED information. */
- printk("Found LED %d", led);
- if (info->label) {
- printk(" - %s", info->label);
- }
- printk(" - index:%d", info->index);
- printk(" - %d colors", info->num_colors);
- if (!info->color_mapping) {
- continue;
- }
- printk(" - %d", info->color_mapping[0]);
- for (col = 1; col < info->num_colors; col++) {
- printk(":%d", info->color_mapping[col]);
- }
- printk("\n");
- }
- num_leds = led;
- if (!num_leds) {
- LOG_ERR("No LEDs found");
- return 0;
- }
-
- do {
- err = run_channel_test(lp503x_dev);
- if (err) {
- return 0;
- }
- for (led = 0; led < num_leds; led++) {
- err = run_led_test(lp503x_dev, led);
- if (err) {
- return 0;
- }
- }
- } while (true);
- return 0;
-}
diff --git a/samples/drivers/led_lp503x/CMakeLists.txt b/samples/drivers/led_lp50xx/CMakeLists.txt
similarity index 91%
rename from samples/drivers/led_lp503x/CMakeLists.txt
rename to samples/drivers/led_lp50xx/CMakeLists.txt
index d7c5d6e..b4c030a 100644
--- a/samples/drivers/led_lp503x/CMakeLists.txt
+++ b/samples/drivers/led_lp50xx/CMakeLists.txt
@@ -3,7 +3,7 @@
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
-project(led_lp503x)
+project(led_lp50xx)
FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})
diff --git a/samples/drivers/led_lp503x/README.rst b/samples/drivers/led_lp50xx/README.rst
similarity index 69%
rename from samples/drivers/led_lp503x/README.rst
rename to samples/drivers/led_lp50xx/README.rst
index 13f5ea0..afad1ee 100644
--- a/samples/drivers/led_lp503x/README.rst
+++ b/samples/drivers/led_lp50xx/README.rst
@@ -1,12 +1,12 @@
-.. _lp503x:
+.. _lp50xx:
-LP5030/6: 10 or 12 RGB channels
+LP50XX: up to 12 RGB channels
###############################
Overview
********
-This sample controls up to 12 LEDs connected to a LP503x driver.
+This sample controls up to 12 LEDs connected to a LP50xx driver.
First, for each LED information is retrieved using the led_get_info syscall
and printed in the log messages. Next, from an infinite loop, a test pattern
@@ -30,9 +30,9 @@
Building and Running
********************
-This sample can be built and executed on boards with an I2C LP5030/6 LED driver
-connected. A node matching the "ti,lp503x" binding should be defined in the
-board DTS files.
+This sample can be built and executed on boards with an I2C LP5009, LP5012,
+LP5018, LP5024, LP5030 or LP5036 LED driver connected. A node matching the
+the device type binding should be defined in the board DTS files.
As an example this sample provides a DTS overlay for the :ref:`lpcxpresso11u68`
board (:file:`boards/lpcxpresso11u68.overlay`). It assumes that a I2C LP5030
@@ -41,4 +41,6 @@
References
**********
-- LP503x: https://www.ti.com/lit/ds/symlink/lp5036.pdf
+- LP5009/LP5012: https://www.ti.com/lit/ds/symlink/lp5012.pdf
+- LP5018/LP5024: https://www.ti.com/lit/ds/symlink/lp5024.pdf
+- LP5030/LP5036: https://www.ti.com/lit/ds/symlink/lp5036.pdf
diff --git a/samples/drivers/led_lp503x/boards/lpcxpresso11u68.overlay b/samples/drivers/led_lp50xx/boards/lpcxpresso11u68.overlay
similarity index 96%
rename from samples/drivers/led_lp503x/boards/lpcxpresso11u68.overlay
rename to samples/drivers/led_lp50xx/boards/lpcxpresso11u68.overlay
index 2930007..8a081ef 100644
--- a/samples/drivers/led_lp503x/boards/lpcxpresso11u68.overlay
+++ b/samples/drivers/led_lp50xx/boards/lpcxpresso11u68.overlay
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2020 Seagate Technology LLC
+ * Copyright (c) 2022 Grinn
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -9,7 +10,7 @@
&i2c0 {
/* TI LP5030 LED controller connected to I2C0. */
lp5030@30 {
- compatible = "ti,lp5030", "ti,lp503x";
+ compatible = "ti,lp5030";
reg = <0x30>;
led_0 {
diff --git a/samples/drivers/led_lp503x/prj.conf b/samples/drivers/led_lp50xx/prj.conf
similarity index 100%
rename from samples/drivers/led_lp503x/prj.conf
rename to samples/drivers/led_lp50xx/prj.conf
diff --git a/samples/drivers/led_lp50xx/sample.yaml b/samples/drivers/led_lp50xx/sample.yaml
new file mode 100644
index 0000000..bcb89dc
--- /dev/null
+++ b/samples/drivers/led_lp50xx/sample.yaml
@@ -0,0 +1,13 @@
+sample:
+ description: Demonstration of the LP50xx LED driver
+ name: LP50xx sample
+tests:
+ sample.drivers.led.lp50xx:
+ filter: dt_compat_enabled("ti,lp5009") or
+ dt_compat_enabled("ti,lp5012") or
+ dt_compat_enabled("ti,lp5018") or
+ dt_compat_enabled("ti,lp5024") or
+ dt_compat_enabled("ti,lp5030") or
+ dt_compat_enabled("ti,lp5036")
+ tags: LED
+ depends_on: i2c
diff --git a/samples/drivers/led_lp50xx/src/main.c b/samples/drivers/led_lp50xx/src/main.c
new file mode 100644
index 0000000..c8eee3b
--- /dev/null
+++ b/samples/drivers/led_lp50xx/src/main.c
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2020 Seagate Technology LLC
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <zephyr/device.h>
+#include <zephyr/devicetree.h>
+#include <zephyr/drivers/led.h>
+#include <zephyr/drivers/led/lp50xx.h>
+#include <zephyr/kernel.h>
+#include <zephyr/sys/util.h>
+
+#define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(main);
+
+#define MAX_BRIGHTNESS 100
+
+#define SLEEP_DELAY_MS 1000
+#define FADE_DELAY_MS 10
+
+#define FADE_DELAY K_MSEC(FADE_DELAY_MS)
+#define SLEEP_DELAY K_MSEC(SLEEP_DELAY_MS)
+
+/*
+ * The following colors are shown in the given order.
+ */
+static uint8_t colors[][3] = {
+ { 0xFF, 0x00, 0x00 }, /* Red */
+ { 0x00, 0xFF, 0x00 }, /* Green */
+ { 0x00, 0x00, 0xFF }, /* Blue */
+ { 0xFF, 0xFF, 0xFF }, /* White */
+ { 0xFF, 0xFF, 0x00 }, /* Yellow */
+ { 0xFF, 0x00, 0xFF }, /* Purple */
+ { 0x00, 0xFF, 0xFF }, /* Cyan */
+ { 0xF4, 0x79, 0x20 }, /* Orange */
+};
+
+/**
+ * @brief Run tests on a single LED using the LED-based API syscalls.
+ *
+ * @param lp50xx_dev LP50XX LED controller device.
+ * @param led Number of the LED to test.
+ */
+static int run_led_test(const struct device *lp50xx_dev, uint8_t led)
+{
+ uint8_t idx;
+ int err;
+
+ LOG_INF("Testing LED %d (LED API)", led);
+
+ for (idx = 0; idx < ARRAY_SIZE(colors); idx++) {
+ uint16_t level;
+
+ /* Update LED color. */
+ err = led_set_color(lp50xx_dev, led, 3, colors[idx]);
+ if (err < 0) {
+ LOG_ERR("Failed to set LED %d color to "
+ "%02x:%02x:%02x, err=%d", led,
+ colors[idx][0], colors[idx][1],
+ colors[idx][2], err);
+ return err;
+ }
+ k_sleep(SLEEP_DELAY);
+
+ /* Turn LED on. */
+ err = led_on(lp50xx_dev, led);
+ if (err < 0) {
+ LOG_ERR("Failed to turn LED %d on, err=%d", led, err);
+ return err;
+ }
+ k_sleep(SLEEP_DELAY);
+
+ /* Turn LED off. */
+ err = led_off(lp50xx_dev, led);
+ if (err < 0) {
+ LOG_ERR("Failed to turn LED %d off, err=%d", led, err);
+ return err;
+ }
+ k_sleep(SLEEP_DELAY);
+
+ /* Set LED brightness gradually to the maximum level. */
+ for (level = 0; level <= MAX_BRIGHTNESS; level++) {
+ err = led_set_brightness(lp50xx_dev, led, level);
+ if (err < 0) {
+ LOG_ERR("Failed to set LED %d brightness to %d"
+ ", err=%d\n", led, level, err);
+ return err;
+ }
+ k_sleep(FADE_DELAY);
+ }
+ k_sleep(SLEEP_DELAY);
+
+ /* Turn LED off. */
+ err = led_off(lp50xx_dev, led);
+ if (err < 0) {
+ LOG_ERR("Failed to turn LED %d off, err=%d", led, err);
+ return err;
+ }
+ k_sleep(SLEEP_DELAY);
+ }
+
+ return 0;
+}
+
+/**
+ * @brief Run tests on all the LEDs using the channel-based API syscalls.
+ *
+ * @param lp50xx_dev LP50XX LED controller device.
+ */
+static int run_channel_test(const struct device *lp50xx_dev,
+ const uint8_t max_leds,
+ const uint8_t bright_chan,
+ const uint8_t color_chan)
+{
+ uint8_t idx;
+ uint8_t buffer[LP50XX_COLORS_PER_LED * max_leds];
+ int err;
+
+ LOG_INF("Testing all LEDs (channel API)");
+
+ for (idx = 0; idx < ARRAY_SIZE(colors); idx++) {
+ uint8_t led;
+ uint16_t level;
+
+ /* Update LEDs colors. */
+ for (led = 0; led < max_leds; led++) {
+ uint8_t *col = &buffer[led * 3];
+
+ col[0] = colors[idx][0];
+ col[1] = colors[idx][1];
+ col[2] = colors[idx][2];
+ }
+ err = led_write_channels(lp50xx_dev, color_chan,
+ LP50XX_COLORS_PER_LED *
+ max_leds,
+ buffer);
+ if (err < 0) {
+ LOG_ERR("Failed to write channels, start=%d num=%d"
+ " err=%d\n", color_chan,
+ LP50XX_COLORS_PER_LED * max_leds, err);
+ return err;
+ }
+ k_sleep(SLEEP_DELAY);
+
+ /* Turn LEDs on. */
+ for (led = 0; led < max_leds; led++) {
+ buffer[led] = MAX_BRIGHTNESS;
+ }
+ err = led_write_channels(lp50xx_dev,
+ bright_chan,
+ max_leds, buffer);
+ if (err < 0) {
+ LOG_ERR("Failed to write channels, start=%d num=%d"
+ " err=%d\n", bright_chan,
+ max_leds, err);
+ return err;
+ }
+ k_sleep(SLEEP_DELAY);
+
+ /* Turn LEDs off. */
+ for (led = 0; led < max_leds; led++) {
+ buffer[led] = 0;
+ }
+ err = led_write_channels(lp50xx_dev,
+ bright_chan,
+ max_leds, buffer);
+ if (err < 0) {
+ LOG_ERR("Failed to write channels, start=%d num=%d"
+ " err=%d\n", bright_chan,
+ max_leds, err);
+ return err;
+ }
+ k_sleep(SLEEP_DELAY);
+
+ /* Set LEDs brightnesses gradually to the maximum level. */
+ for (level = 0; level <= MAX_BRIGHTNESS; level++) {
+ for (led = 0; led < max_leds; led++) {
+ buffer[led] = level;
+ }
+ err = led_write_channels(lp50xx_dev,
+ bright_chan,
+ max_leds, buffer);
+ if (err < 0) {
+ LOG_ERR("Failed to write channels, start=%d"
+ " num=%d err=%d\n",
+ bright_chan,
+ max_leds, err);
+ return err;
+ }
+ k_sleep(FADE_DELAY);
+ }
+ k_sleep(SLEEP_DELAY);
+
+ /* Turn LEDs off. */
+ for (led = 0; led < max_leds; led++) {
+ buffer[led] = 0;
+ }
+ err = led_write_channels(lp50xx_dev,
+ bright_chan,
+ max_leds, buffer);
+ if (err < 0) {
+ LOG_ERR("Failed to write channels, start=%d "
+ "num=%d err=%d\n", bright_chan,
+ max_leds, err);
+ return err;
+ }
+ k_sleep(SLEEP_DELAY);
+ }
+
+ return 0;
+}
+
+static int run_test(const struct device *const lp50xx_dev,
+ const uint8_t max_leds,
+ const uint8_t bright_chan,
+ const uint8_t color_chan)
+{
+ int err;
+ uint8_t led;
+ uint8_t num_leds = 0;
+
+ for (led = 0; led < max_leds; led++) {
+ int col;
+ const struct led_info *info;
+
+ err = led_get_info(lp50xx_dev, led, &info);
+ if (err < 0) {
+ LOG_DBG("Failed to get information for LED %d (err=%d)",
+ led, err);
+ break;
+ }
+
+ /* Display LED information. */
+ printk("Found LED %d", led);
+ if (info->label) {
+ printk(" - %s", info->label);
+ }
+ printk(" - index:%d", info->index);
+ printk(" - %d colors", info->num_colors);
+ if (!info->color_mapping) {
+ continue;
+ }
+ printk(" - %d", info->color_mapping[0]);
+ for (col = 1; col < info->num_colors; col++) {
+ printk(":%d", info->color_mapping[col]);
+ }
+ printk("\n");
+ }
+
+ num_leds = led;
+ if (!num_leds) {
+ LOG_ERR("No LEDs found");
+ return 0;
+ }
+
+ do {
+ err = run_channel_test(lp50xx_dev, max_leds, bright_chan,
+ color_chan);
+ if (err) {
+ return 0;
+ }
+ for (led = 0; led < num_leds; led++) {
+ err = run_led_test(lp50xx_dev, led);
+ if (err) {
+ return 0;
+ }
+ }
+ } while (true);
+ return 0;
+}
+
+void main(void)
+{
+ const struct device *lp50xx_dev;
+ bool found = false;
+
+ lp50xx_dev = DEVICE_DT_GET_ANY(ti_lp5009);
+ if (lp50xx_dev) {
+ LOG_INF("Found LED controller %s", lp50xx_dev->name);
+ found = true;
+
+ if (device_is_ready(lp50xx_dev)) {
+ run_test(lp50xx_dev,
+ LP5009_MAX_LEDS,
+ LP50XX_LED_BRIGHT_CHAN_BASE,
+ LP5012_LED_COL_CHAN_BASE);
+ } else {
+ LOG_ERR("LED controller %s is not ready",
+ lp50xx_dev->name);
+ }
+ }
+
+ lp50xx_dev = DEVICE_DT_GET_ANY(ti_lp5012);
+ if (lp50xx_dev) {
+ LOG_INF("Found LED controller %s", lp50xx_dev->name);
+ found = true;
+
+ if (device_is_ready(lp50xx_dev)) {
+ run_test(lp50xx_dev,
+ LP5012_MAX_LEDS,
+ LP50XX_LED_BRIGHT_CHAN_BASE,
+ LP5012_LED_COL_CHAN_BASE);
+ } else {
+ LOG_ERR("LED controller %s is not ready",
+ lp50xx_dev->name);
+ }
+ }
+
+ lp50xx_dev = DEVICE_DT_GET_ANY(ti_lp5018);
+ if (lp50xx_dev) {
+ LOG_INF("Found LED controller %s", lp50xx_dev->name);
+ found = true;
+
+ if (device_is_ready(lp50xx_dev)) {
+ run_test(lp50xx_dev,
+ LP5018_MAX_LEDS,
+ LP50XX_LED_BRIGHT_CHAN_BASE,
+ LP5024_LED_COL_CHAN_BASE);
+ } else {
+ LOG_ERR("LED controller %s is not ready",
+ lp50xx_dev->name);
+ }
+ }
+
+ lp50xx_dev = DEVICE_DT_GET_ANY(ti_lp5024);
+ if (lp50xx_dev) {
+ LOG_INF("Found LED controller %s", lp50xx_dev->name);
+ found = true;
+
+ if (device_is_ready(lp50xx_dev)) {
+ run_test(lp50xx_dev,
+ LP5024_MAX_LEDS,
+ LP50XX_LED_BRIGHT_CHAN_BASE,
+ LP5024_LED_COL_CHAN_BASE);
+ } else {
+ LOG_ERR("LED controller %s is not ready",
+ lp50xx_dev->name);
+ }
+ }
+
+ lp50xx_dev = DEVICE_DT_GET_ANY(ti_lp5030);
+ if (lp50xx_dev) {
+ LOG_INF("Found LED controller %s", lp50xx_dev->name);
+ found = true;
+
+ if (device_is_ready(lp50xx_dev)) {
+ run_test(lp50xx_dev,
+ LP5030_MAX_LEDS,
+ LP50XX_LED_BRIGHT_CHAN_BASE,
+ LP5036_LED_COL_CHAN_BASE);
+ } else {
+ LOG_ERR("LED controller %s is not ready",
+ lp50xx_dev->name);
+ }
+ }
+
+ lp50xx_dev = DEVICE_DT_GET_ANY(ti_lp5036);
+ if (lp50xx_dev) {
+ LOG_INF("Found LED controller %s", lp50xx_dev->name);
+ found = true;
+
+ if (device_is_ready(lp50xx_dev)) {
+ run_test(lp50xx_dev,
+ LP5036_MAX_LEDS,
+ LP50XX_LED_BRIGHT_CHAN_BASE,
+ LP5036_LED_COL_CHAN_BASE);
+ } else {
+ LOG_ERR("LED controller %s is not ready",
+ lp50xx_dev->name);
+ }
+ }
+
+ if (!found) {
+ LOG_ERR("No LP50XX LED controller found");
+ }
+}