From 95f8b0cbac5550c362366caabff93547ee7a9614 Mon Sep 17 00:00:00 2001 From: Kurt Eckhardt Date: Fri, 3 Oct 2025 13:15:53 -0700 Subject: [PATCH 1/5] drivers: led: rename IS31FL3194 to 9x In preparation to allow this driver to support more than one IS31FL319x object such as ...97, rename the source file and the functions to make them more generic. I also changed the enumeration/creation of object to generate the right names for the current 94 objects Still have not renamed the Kconfig file yet as was having issues with it not building... Did not load the .c file Update README.rst one Kconfig Delete Kconfig.is31fl3194 Fix documents run drivers: led: IS31FL3194 to 9x fix redirects,py Signed-off-by: Kurt Eckhardt --- doc/_scripts/redirects.py | 2 +- drivers/led/CMakeLists.txt | 2 +- drivers/led/Kconfig | 2 +- ...{Kconfig.is31fl3194 => Kconfig.is31fl319x} | 4 +- drivers/led/{is31fl3194.c => is31fl319x.c} | 88 ++++++++++--------- .../{is31fl3194 => is31fl319x}/CMakeLists.txt | 2 +- .../led/{is31fl3194 => is31fl319x}/README.rst | 4 +- .../led/{is31fl3194 => is31fl319x}/prj.conf | 0 .../{is31fl3194 => is31fl319x}/sample.yaml | 6 +- .../led/{is31fl3194 => is31fl319x}/src/main.c | 0 10 files changed, 56 insertions(+), 54 deletions(-) rename drivers/led/{Kconfig.is31fl3194 => Kconfig.is31fl319x} (85%) rename drivers/led/{is31fl3194.c => is31fl319x.c} (71%) rename samples/drivers/led/{is31fl3194 => is31fl319x}/CMakeLists.txt (87%) rename samples/drivers/led/{is31fl3194 => is31fl319x}/README.rst (92%) rename samples/drivers/led/{is31fl3194 => is31fl319x}/prj.conf (100%) rename samples/drivers/led/{is31fl3194 => is31fl319x}/sample.yaml (57%) rename samples/drivers/led/{is31fl3194 => is31fl319x}/src/main.c (100%) diff --git a/doc/_scripts/redirects.py b/doc/_scripts/redirects.py index fbc7afd4131b2..5c4255fdedd6e 100644 --- a/doc/_scripts/redirects.py +++ b/doc/_scripts/redirects.py @@ -292,7 +292,7 @@ ('samples/boards/stm32/steval_stwinbx1/sensors/README', 'samples/boards/st/steval_stwinbx1/sensors/README'), ('samples/drivers/adc/README', 'samples/drivers/adc/adc_dt/README'), ('samples/drivers/led_apa102/README', 'samples/drivers/led_strip/README'), - ('samples/drivers/led_is31fl3194/README', 'samples/drivers/led/is31fl3194/README'), + ('samples/drivers/led_is31fl319x/README', 'samples/drivers/led/is31fl319x/README'), ('samples/drivers/led_is31fl3216a/README', 'samples/drivers/led/is31fl3216a/README'), ('samples/drivers/led_is31fl3733/README', 'samples/drivers/led/is31fl3733/README'), ('samples/drivers/led_lp3943/README', 'samples/drivers/led/lp3943/README'), diff --git a/drivers/led/CMakeLists.txt b/drivers/led/CMakeLists.txt index 9a53ac7c2827e..708f441580d20 100644 --- a/drivers/led/CMakeLists.txt +++ b/drivers/led/CMakeLists.txt @@ -6,7 +6,7 @@ zephyr_library() # zephyr-keep-sorted-start zephyr_library_sources_ifdef(CONFIG_HT16K33 ht16k33.c) -zephyr_library_sources_ifdef(CONFIG_IS31FL3194 is31fl3194.c) +zephyr_library_sources_ifdef(CONFIG_IS31FL319X is31fl319x.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) diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig index f6809fc7c9dd7..098b3e9e32b6b 100644 --- a/drivers/led/Kconfig +++ b/drivers/led/Kconfig @@ -31,7 +31,7 @@ source "drivers/led/Kconfig.axp192" source "drivers/led/Kconfig.dac" source "drivers/led/Kconfig.gpio" source "drivers/led/Kconfig.ht16k33" -source "drivers/led/Kconfig.is31fl3194" +source "drivers/led/Kconfig.is31fl319x" source "drivers/led/Kconfig.is31fl3216a" source "drivers/led/Kconfig.is31fl3733" source "drivers/led/Kconfig.leds-group-multicolor" diff --git a/drivers/led/Kconfig.is31fl3194 b/drivers/led/Kconfig.is31fl319x similarity index 85% rename from drivers/led/Kconfig.is31fl3194 rename to drivers/led/Kconfig.is31fl319x index 42166805a1d16..d6cb8198a7967 100644 --- a/drivers/led/Kconfig.is31fl3194 +++ b/drivers/led/Kconfig.is31fl319x @@ -1,8 +1,8 @@ # Copyright (c) 2024 Arduino SA # SPDX-License-Identifier: Apache-2.0 -config IS31FL3194 - bool "IS31FL3194 LED driver" +config IS31FL319X + bool "IS31FL319X LED driver" default y depends on DT_HAS_ISSI_IS31FL3194_ENABLED select I2C diff --git a/drivers/led/is31fl3194.c b/drivers/led/is31fl319x.c similarity index 71% rename from drivers/led/is31fl3194.c rename to drivers/led/is31fl319x.c index 6ae0d6ab44db8..432cb640539b5 100644 --- a/drivers/led/is31fl3194.c +++ b/drivers/led/is31fl319x.c @@ -4,7 +4,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#define DT_DRV_COMPAT issi_is31fl3194 /** * @file @@ -21,7 +20,7 @@ #include -LOG_MODULE_REGISTER(is31fl3194, CONFIG_LED_LOG_LEVEL); +LOG_MODULE_REGISTER(is31fl319x, CONFIG_LED_LOG_LEVEL); #define IS31FL3194_PROD_ID_REG 0x00 #define IS31FL3194_CONF_REG 0x01 @@ -43,14 +42,14 @@ static const uint8_t led_channels[] = { IS31FL3194_OUT3_REG }; -struct is31fl3194_config { +struct is31fl319x_config { struct i2c_dt_spec bus; uint8_t num_leds; const struct led_info *led_infos; const uint8_t *current_limits; }; -static const struct led_info *is31fl3194_led_to_info(const struct is31fl3194_config *config, +static const struct led_info *is31fl319x_led_to_info(const struct is31fl319x_config *config, uint32_t led) { if (led < config->num_leds) { @@ -60,12 +59,12 @@ static const struct led_info *is31fl3194_led_to_info(const struct is31fl3194_con return NULL; } -static int is31fl3194_get_info(const struct device *dev, +static int is31fl319x_get_info(const struct device *dev, uint32_t led, const struct led_info **info_out) { - const struct is31fl3194_config *config = dev->config; - const struct led_info *info = is31fl3194_led_to_info(config, led); + const struct is31fl319x_config *config = dev->config; + const struct led_info *info = is31fl319x_led_to_info(config, led); if (info == NULL) { return -EINVAL; @@ -75,11 +74,11 @@ static int is31fl3194_get_info(const struct device *dev, return 0; } -static int is31fl3194_set_color(const struct device *dev, uint32_t led, uint8_t num_colors, +static int is31fl319x_set_color(const struct device *dev, uint32_t led, uint8_t num_colors, const uint8_t *color) { - const struct is31fl3194_config *config = dev->config; - const struct led_info *info = is31fl3194_led_to_info(config, led); + const struct is31fl319x_config *config = dev->config; + const struct led_info *info = is31fl319x_led_to_info(config, led); int ret; if (info == NULL) { @@ -108,7 +107,7 @@ static int is31fl3194_set_color(const struct device *dev, uint32_t led, uint8_t value = color[2]; break; default: - /* unreachable: mapping already tested in is31fl3194_check_config */ + /* unreachable: mapping already tested in is31fl319x_check_config */ return -EINVAL; } @@ -131,10 +130,10 @@ static int is31fl3194_set_color(const struct device *dev, uint32_t led, uint8_t return ret; } -static int is31fl3194_set_brightness(const struct device *dev, uint32_t led, uint8_t value) +static int is31fl319x_set_brightness(const struct device *dev, uint32_t led, uint8_t value) { - const struct is31fl3194_config *config = dev->config; - const struct led_info *info = is31fl3194_led_to_info(config, led); + const struct is31fl319x_config *config = dev->config; + const struct led_info *info = is31fl319x_led_to_info(config, led); int ret = 0; if (info == NULL) { @@ -166,7 +165,7 @@ static int is31fl3194_set_brightness(const struct device *dev, uint32_t led, uin * Counts red, green, blue channels; returns true if color_id is valid * and no more than one channel maps to the same color */ -static bool is31fl3194_count_colors(const struct device *dev, +static bool is31fl319x_count_colors(const struct device *dev, uint8_t color_id, uint8_t *rgb_counts) { bool ret = false; @@ -191,9 +190,9 @@ static bool is31fl3194_count_colors(const struct device *dev, return ret; } -static int is31fl3194_check_config(const struct device *dev) +static int is31fl319x_check_config(const struct device *dev) { - const struct is31fl3194_config *config = dev->config; + const struct is31fl319x_config *config = dev->config; const struct led_info *info; uint8_t rgb_counts[3] = { 0 }; uint8_t i; @@ -211,7 +210,7 @@ static int is31fl3194_check_config(const struct device *dev) } for (i = 0; i < 3; i++) { - if (!is31fl3194_count_colors(dev, info->color_mapping[i], rgb_counts)) { + if (!is31fl319x_count_colors(dev, info->color_mapping[i], rgb_counts)) { return -EINVAL; } @@ -229,7 +228,7 @@ static int is31fl3194_check_config(const struct device *dev) return -EINVAL; } - if (!is31fl3194_count_colors(dev, info->color_mapping[0], rgb_counts)) { + if (!is31fl319x_count_colors(dev, info->color_mapping[0], rgb_counts)) { return -EINVAL; } } @@ -243,15 +242,15 @@ static int is31fl3194_check_config(const struct device *dev) return 0; } -static int is31fl3194_init(const struct device *dev) +static int is31fl319x_init(const struct device *dev) { - const struct is31fl3194_config *config = dev->config; + const struct is31fl319x_config *config = dev->config; const struct led_info *info = NULL; int i, ret; uint8_t prod_id, band; uint8_t current_reg = 0; - ret = is31fl3194_check_config(dev); + ret = is31fl319x_check_config(dev); if (ret != 0) { return ret; } @@ -299,10 +298,10 @@ static int is31fl3194_init(const struct device *dev) return i2c_reg_write_byte_dt(&config->bus, IS31FL3194_CONF_REG, IS31FL3194_CONF_ENABLE); } -static DEVICE_API(led, is31fl3194_led_api) = { - .set_brightness = is31fl3194_set_brightness, - .get_info = is31fl3194_get_info, - .set_color = is31fl3194_set_color, +static DEVICE_API(led, is31fl319x_led_api) = { + .set_brightness = is31fl319x_set_brightness, + .get_info = is31fl319x_get_info, + .set_color = is31fl319x_set_color, }; #define COLOR_MAPPING(led_node_id) \ @@ -319,25 +318,28 @@ static DEVICE_API(led, is31fl3194_led_api) = { #define LED_CURRENT(led_node_id) \ DT_PROP(led_node_id, current_limit), -#define IS31FL3194_DEFINE(id) \ +#define IS31FL319X_DEVICE(n, id) \ + \ + DT_INST_FOREACH_CHILD(n, COLOR_MAPPING) \ \ - DT_INST_FOREACH_CHILD(id, COLOR_MAPPING) \ + static const struct led_info is31fl319##id##_leds_##n[] = \ + { DT_INST_FOREACH_CHILD(n, LED_INFO) }; \ \ - static const struct led_info is31fl3194_leds_##id[] = \ - { DT_INST_FOREACH_CHILD(id, LED_INFO) }; \ - static const uint8_t is31fl3194_currents_##id[] = \ - { DT_INST_FOREACH_CHILD(id, LED_CURRENT) }; \ - BUILD_ASSERT(ARRAY_SIZE(is31fl3194_leds_##id) > 0, \ - "No LEDs defined for " #id); \ + static const uint8_t is31fl319##id##_currents_##n[] = \ + { DT_INST_FOREACH_CHILD(n, LED_CURRENT) }; \ + BUILD_ASSERT(ARRAY_SIZE(is31fl319##id##_leds_##n) > 0, \ + "No LEDs defined for " #n); \ \ - static const struct is31fl3194_config is31fl3194_config_##id = { \ - .bus = I2C_DT_SPEC_INST_GET(id), \ - .num_leds = ARRAY_SIZE(is31fl3194_leds_##id), \ - .led_infos = is31fl3194_leds_##id, \ - .current_limits = is31fl3194_currents_##id, \ + static const struct is31fl319x_config is31fl319##id##_config_##n = { \ + .bus = I2C_DT_SPEC_INST_GET(n), \ + .num_leds = ARRAY_SIZE(is31fl319##id##_leds_##n), \ + .led_infos = is31fl319##id##_leds_##n, \ + .current_limits = is31fl319##id##_currents_##n, \ }; \ - DEVICE_DT_INST_DEFINE(id, &is31fl3194_init, NULL, NULL, \ - &is31fl3194_config_##id, POST_KERNEL, \ - CONFIG_LED_INIT_PRIORITY, &is31fl3194_led_api); + DEVICE_DT_INST_DEFINE(n, &is31fl319x_init, NULL, NULL, \ + &is31fl319##id##_config_##n, POST_KERNEL, \ + CONFIG_LED_INIT_PRIORITY, &is31fl319x_led_api); -DT_INST_FOREACH_STATUS_OKAY(IS31FL3194_DEFINE) +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT issi_is31fl3194 +DT_INST_FOREACH_STATUS_OKAY_VARGS(IS31FL319X_DEVICE, 4) diff --git a/samples/drivers/led/is31fl3194/CMakeLists.txt b/samples/drivers/led/is31fl319x/CMakeLists.txt similarity index 87% rename from samples/drivers/led/is31fl3194/CMakeLists.txt rename to samples/drivers/led/is31fl319x/CMakeLists.txt index ed52c77a3fd0e..91cfa7707b7c6 100644 --- a/samples/drivers/led/is31fl3194/CMakeLists.txt +++ b/samples/drivers/led/is31fl319x/CMakeLists.txt @@ -2,6 +2,6 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(led_is31fl3194) +project(led_is31fl319x) target_sources(app PRIVATE src/main.c) diff --git a/samples/drivers/led/is31fl3194/README.rst b/samples/drivers/led/is31fl319x/README.rst similarity index 92% rename from samples/drivers/led/is31fl3194/README.rst rename to samples/drivers/led/is31fl319x/README.rst index cee837f4fe93d..740e4f7757cf4 100644 --- a/samples/drivers/led/is31fl3194/README.rst +++ b/samples/drivers/led/is31fl319x/README.rst @@ -1,5 +1,5 @@ -.. zephyr:code-sample:: is31fl3194 - :name: IS31FL3194 RGB LED +.. zephyr:code-sample:: is31fl319x + :name: IS31FL319x RGB LED :relevant-api: led_interface Cycle colors on an RGB LED connected to the IS31FL3194 using the LED API. diff --git a/samples/drivers/led/is31fl3194/prj.conf b/samples/drivers/led/is31fl319x/prj.conf similarity index 100% rename from samples/drivers/led/is31fl3194/prj.conf rename to samples/drivers/led/is31fl319x/prj.conf diff --git a/samples/drivers/led/is31fl3194/sample.yaml b/samples/drivers/led/is31fl319x/sample.yaml similarity index 57% rename from samples/drivers/led/is31fl3194/sample.yaml rename to samples/drivers/led/is31fl319x/sample.yaml index 0cb932b05d2ee..ca87c1ce3b3bd 100644 --- a/samples/drivers/led/is31fl3194/sample.yaml +++ b/samples/drivers/led/is31fl319x/sample.yaml @@ -1,8 +1,8 @@ sample: - description: Demonstration of the IS31FL3194 LED driver - name: is31fl3194 sample + description: Demonstration of the IS31FL319x LED driver + name: is31fl319x sample tests: - sample.drivers.led.is31fl3194: + sample.drivers.led.is31fl319x: filter: dt_compat_enabled("issi,is31fl3194") tags: LED depends_on: i2c diff --git a/samples/drivers/led/is31fl3194/src/main.c b/samples/drivers/led/is31fl319x/src/main.c similarity index 100% rename from samples/drivers/led/is31fl3194/src/main.c rename to samples/drivers/led/is31fl319x/src/main.c From d9f973d5f876fed330f0de2c2d5ae5e171a39dc2 Mon Sep 17 00:00:00 2001 From: Kurt Eckhardt Date: Sat, 4 Oct 2025 06:51:24 -0700 Subject: [PATCH 2/5] drivers: led: is31fl319x - hard coded registers more refactoring, don't use the 94 registers everywhere. Introduce structure, with registers and fixed values, and use it. Signed-off-by: Kurt Eckhardt --- drivers/led/is31fl319x.c | 88 ++++++++++++++++++++++++++++------------ 1 file changed, 63 insertions(+), 25 deletions(-) diff --git a/drivers/led/is31fl319x.c b/drivers/led/is31fl319x.c index 432cb640539b5..f94ed44ad83be 100644 --- a/drivers/led/is31fl319x.c +++ b/drivers/led/is31fl319x.c @@ -21,6 +21,23 @@ #include LOG_MODULE_REGISTER(is31fl319x, CONFIG_LED_LOG_LEVEL); +#define REG_NOT_DEFINED 0xff + +struct is31f1319x_model { + const uint8_t prod_id_reg; + const uint8_t shutdown_reg; + const uint8_t conf_reg; + const uint8_t current_reg; + const uint8_t update_reg; + + const uint8_t prod_id_val; + const uint8_t shutdown_reg_val; + const uint8_t conf_enable; + const uint8_t update_val; + + const uint8_t led_channels[]; +}; + #define IS31FL3194_PROD_ID_REG 0x00 #define IS31FL3194_CONF_REG 0x01 @@ -36,17 +53,30 @@ LOG_MODULE_REGISTER(is31fl319x, CONFIG_LED_LOG_LEVEL); #define IS31FL3194_CHANNEL_COUNT 3 -static const uint8_t led_channels[] = { - IS31FL3194_OUT1_REG, - IS31FL3194_OUT2_REG, - IS31FL3194_OUT3_REG -}; +static const struct is31f1319x_model is31f13194_model = { + /* register indexes */ + .prod_id_reg = IS31FL3194_PROD_ID_REG, + .shutdown_reg = REG_NOT_DEFINED, + .conf_reg = IS31FL3194_CONF_REG, + .current_reg = IS31FL3194_CURRENT_REG, + .update_reg = IS31FL3194_UPDATE_REG, + + /* values for those registers */ + .prod_id_val = IS31FL3194_PROD_ID_VAL, + .shutdown_reg_val = 0, + .conf_enable = IS31FL3194_CONF_ENABLE, + .update_val = IS31FL3194_UPDATE_VAL, + + /* channel output registers */ + .led_channels = {IS31FL3194_OUT1_REG, IS31FL3194_OUT2_REG, IS31FL3194_OUT3_REG}}; struct is31fl319x_config { struct i2c_dt_spec bus; + uint8_t channel_count; uint8_t num_leds; const struct led_info *led_infos; const uint8_t *current_limits; + const struct is31f1319x_model *regs; }; static const struct led_info *is31fl319x_led_to_info(const struct is31fl319x_config *config, @@ -79,21 +109,22 @@ static int is31fl319x_set_color(const struct device *dev, uint32_t led, uint8_t { const struct is31fl319x_config *config = dev->config; const struct led_info *info = is31fl319x_led_to_info(config, led); + const struct is31f1319x_model *regs = config->regs; int ret; if (info == NULL) { return -ENODEV; } - if (info->num_colors != 3) { + if (info->num_colors > config->channel_count) { return -ENOTSUP; } - if (num_colors != 3) { - return -EINVAL; + if (num_colors > config->channel_count) { + return -ENOTSUP; } - for (int i = 0; i < 3; i++) { + for (int i = 0; i < num_colors; i++) { uint8_t value; switch (info->color_mapping[i]) { @@ -111,7 +142,7 @@ static int is31fl319x_set_color(const struct device *dev, uint32_t led, uint8_t return -EINVAL; } - ret = i2c_reg_write_byte_dt(&config->bus, led_channels[i], value); + ret = i2c_reg_write_byte_dt(&config->bus, regs->led_channels[i], value); if (ret != 0) { break; } @@ -119,8 +150,8 @@ static int is31fl319x_set_color(const struct device *dev, uint32_t led, uint8_t if (ret == 0) { ret = i2c_reg_write_byte_dt(&config->bus, - IS31FL3194_UPDATE_REG, - IS31FL3194_UPDATE_VAL); + regs->update_reg, + regs->update_val); } if (ret != 0) { @@ -134,6 +165,8 @@ static int is31fl319x_set_brightness(const struct device *dev, uint32_t led, uin { const struct is31fl319x_config *config = dev->config; const struct led_info *info = is31fl319x_led_to_info(config, led); + const struct is31f1319x_model *regs = config->regs; + int ret = 0; if (info == NULL) { @@ -147,11 +180,11 @@ static int is31fl319x_set_brightness(const struct device *dev, uint32_t led, uin /* Rescale 0..100 to 0..255 */ value = value * 255 / LED_BRIGHTNESS_MAX; - ret = i2c_reg_write_byte_dt(&config->bus, led_channels[led], value); + ret = i2c_reg_write_byte_dt(&config->bus, regs->led_channels[led], value); if (ret == 0) { ret = i2c_reg_write_byte_dt(&config->bus, - IS31FL3194_UPDATE_REG, - IS31FL3194_UPDATE_VAL); + regs->update_reg, + regs->update_val); } if (ret != 0) { @@ -246,6 +279,7 @@ static int is31fl319x_init(const struct device *dev) { const struct is31fl319x_config *config = dev->config; const struct led_info *info = NULL; + const struct is31f1319x_model *regs = config->regs; int i, ret; uint8_t prod_id, band; uint8_t current_reg = 0; @@ -260,15 +294,15 @@ static int is31fl319x_init(const struct device *dev) return -ENODEV; } - ret = i2c_reg_read_byte_dt(&config->bus, IS31FL3194_PROD_ID_REG, &prod_id); + ret = i2c_reg_read_byte_dt(&config->bus, regs->prod_id_reg, &prod_id); if (ret != 0) { LOG_ERR("%s: failed to read product ID", dev->name); return ret; } - if (prod_id != IS31FL3194_PROD_ID_VAL) { + if (prod_id != regs->prod_id_val) { LOG_ERR("%s: invalid product ID 0x%02x (expected 0x%02x)", dev->name, prod_id, - IS31FL3194_PROD_ID_VAL); + regs->prod_id_val); return -ENODEV; } @@ -295,7 +329,8 @@ static int is31fl319x_init(const struct device *dev) } /* enable device */ - return i2c_reg_write_byte_dt(&config->bus, IS31FL3194_CONF_REG, IS31FL3194_CONF_ENABLE); + return i2c_reg_write_byte_dt(&config->bus, regs->conf_reg, + regs->conf_enable); } static DEVICE_API(led, is31fl319x_led_api) = { @@ -318,12 +353,12 @@ static DEVICE_API(led, is31fl319x_led_api) = { #define LED_CURRENT(led_node_id) \ DT_PROP(led_node_id, current_limit), -#define IS31FL319X_DEVICE(n, id) \ +#define IS31FL319X_DEVICE(n, id, nchannels, pregs) \ \ DT_INST_FOREACH_CHILD(n, COLOR_MAPPING) \ \ static const struct led_info is31fl319##id##_leds_##n[] = \ - { DT_INST_FOREACH_CHILD(n, LED_INFO) }; \ + { DT_INST_FOREACH_CHILD(n, LED_INFO) }; \ \ static const uint8_t is31fl319##id##_currents_##n[] = \ { DT_INST_FOREACH_CHILD(n, LED_CURRENT) }; \ @@ -331,15 +366,18 @@ static DEVICE_API(led, is31fl319x_led_api) = { "No LEDs defined for " #n); \ \ static const struct is31fl319x_config is31fl319##id##_config_##n = { \ - .bus = I2C_DT_SPEC_INST_GET(n), \ + .bus = I2C_DT_SPEC_INST_GET(n), \ + .channel_count = nchannels, \ .num_leds = ARRAY_SIZE(is31fl319##id##_leds_##n), \ .led_infos = is31fl319##id##_leds_##n, \ .current_limits = is31fl319##id##_currents_##n, \ + .regs = pregs, \ }; \ - DEVICE_DT_INST_DEFINE(n, &is31fl319x_init, NULL, NULL, \ - &is31fl319##id##_config_##n, POST_KERNEL, \ + DEVICE_DT_INST_DEFINE(n, &is31fl319x_init, NULL, NULL, \ + &is31fl319##id##_config_##n, POST_KERNEL, \ CONFIG_LED_INIT_PRIORITY, &is31fl319x_led_api); #undef DT_DRV_COMPAT #define DT_DRV_COMPAT issi_is31fl3194 -DT_INST_FOREACH_STATUS_OKAY_VARGS(IS31FL319X_DEVICE, 4) +DT_INST_FOREACH_STATUS_OKAY_VARGS(IS31FL319X_DEVICE, 4, IS31FL3194_CHANNEL_COUNT, + &is31f13194_model) From 5297d61ff9e8f8b36db99d25983cb728a48a36f2 Mon Sep 17 00:00:00 2001 From: Kurt Eckhardt Date: Sat, 4 Oct 2025 11:18:09 -0700 Subject: [PATCH 3/5] drivers: led: is31fl319x - redo color to channel Removed the driver knowing anything about what color each channel is. When you output to an LED with a buffer it simply writes the channels out with buffer. Also removed the assumptions that the leds are either a) RGB or b) 3 channels and instead use them the way they are defined. That is for example if we have 4 channels, we could define an LED with just one color in it and we could define another with three. The user can define 4 leds each with color yellow. For each LED it counts how many buffers were used by previous LEDs and starts there and outputs N channels. Decided it looked cleaner to use helper function write channels, so implemented it and added it to the call table. Updated example sketch: It manually computes which channel maps to red, green and blue and then uses those indexes to map the table of colors to the right channels. Signed-off-by: Kurt Eckhardt Update main.c Update main.c --- drivers/led/is31fl319x.c | 184 ++++++++-------------- samples/drivers/led/is31fl319x/README.rst | 24 ++- samples/drivers/led/is31fl319x/src/main.c | 107 ++++++++++++- 3 files changed, 189 insertions(+), 126 deletions(-) diff --git a/drivers/led/is31fl319x.c b/drivers/led/is31fl319x.c index f94ed44ad83be..f6e51b8b2c7d7 100644 --- a/drivers/led/is31fl319x.c +++ b/drivers/led/is31fl319x.c @@ -104,45 +104,35 @@ static int is31fl319x_get_info(const struct device *dev, return 0; } -static int is31fl319x_set_color(const struct device *dev, uint32_t led, uint8_t num_colors, - const uint8_t *color) +static uint8_t is31fl319x_map_led_to_start_channel(const struct is31fl319x_config *config, + uint32_t led) +{ + /* It is assumed that led has been validated before calling this */ + const struct led_info *info = config->led_infos; + uint8_t channel = 0; + + while (led) { + channel += info->num_colors; + led--; + info++; + } + return channel; +} + +static int is31fl319x_write_channels(const struct device *dev, uint32_t start_channel, + uint32_t num_channels, const uint8_t *buf) { const struct is31fl319x_config *config = dev->config; - const struct led_info *info = is31fl319x_led_to_info(config, led); const struct is31f1319x_model *regs = config->regs; int ret; - if (info == NULL) { - return -ENODEV; - } - - if (info->num_colors > config->channel_count) { + if ((start_channel + num_channels) > config->channel_count) { return -ENOTSUP; } - if (num_colors > config->channel_count) { - return -ENOTSUP; - } - - for (int i = 0; i < num_colors; i++) { - uint8_t value; - - switch (info->color_mapping[i]) { - case LED_COLOR_ID_RED: - value = color[0]; - break; - case LED_COLOR_ID_GREEN: - value = color[1]; - break; - case LED_COLOR_ID_BLUE: - value = color[2]; - break; - default: - /* unreachable: mapping already tested in is31fl319x_check_config */ - return -EINVAL; - } - - ret = i2c_reg_write_byte_dt(&config->bus, regs->led_channels[i], value); + for (int i = 0; i < num_channels; i++) { + ret = i2c_reg_write_byte_dt(&config->bus, regs->led_channels[i + start_channel], + buf[i]); if (ret != 0) { break; } @@ -161,6 +151,25 @@ static int is31fl319x_set_color(const struct device *dev, uint32_t led, uint8_t return ret; } +static int is31fl319x_set_color(const struct device *dev, uint32_t led, uint8_t num_colors, + const uint8_t *color) +{ + const struct is31fl319x_config *config = dev->config; + const struct led_info *info = is31fl319x_led_to_info(config, led); + + if (info == NULL) { + return -ENODEV; + } + + uint8_t channel_start = is31fl319x_map_led_to_start_channel(config, led); + + if (info->num_colors > config->channel_count) { + return -ENOTSUP; + } + + return is31fl319x_write_channels(dev, channel_start, num_colors, color); +} + static int is31fl319x_set_brightness(const struct device *dev, uint32_t led, uint8_t value) { const struct is31fl319x_config *config = dev->config; @@ -180,7 +189,9 @@ static int is31fl319x_set_brightness(const struct device *dev, uint32_t led, uin /* Rescale 0..100 to 0..255 */ value = value * 255 / LED_BRIGHTNESS_MAX; - ret = i2c_reg_write_byte_dt(&config->bus, regs->led_channels[led], value); + uint8_t channel_start = is31fl319x_map_led_to_start_channel(config, led); + + ret = i2c_reg_write_byte_dt(&config->bus, regs->led_channels[channel_start], value); if (ret == 0) { ret = i2c_reg_write_byte_dt(&config->bus, regs->update_reg, @@ -194,81 +205,20 @@ static int is31fl319x_set_brightness(const struct device *dev, uint32_t led, uin return ret; } -/* - * Counts red, green, blue channels; returns true if color_id is valid - * and no more than one channel maps to the same color - */ -static bool is31fl319x_count_colors(const struct device *dev, - uint8_t color_id, uint8_t *rgb_counts) -{ - bool ret = false; - - switch (color_id) { - case LED_COLOR_ID_RED: - ret = (++rgb_counts[0] == 1); - break; - case LED_COLOR_ID_GREEN: - ret = (++rgb_counts[1] == 1); - break; - case LED_COLOR_ID_BLUE: - ret = (++rgb_counts[2] == 1); - break; - } - - if (!ret) { - LOG_ERR("%s: invalid color %d (duplicate or not RGB)", - dev->name, color_id); - } - - return ret; -} - static int is31fl319x_check_config(const struct device *dev) { const struct is31fl319x_config *config = dev->config; const struct led_info *info; - uint8_t rgb_counts[3] = { 0 }; + uint8_t rgb_count = 0; uint8_t i; - switch (config->num_leds) { - case 1: - /* check that it is a three-channel LED */ - info = &config->led_infos[0]; - - if (info->num_colors != 3) { - LOG_ERR("%s: invalid number of colors %d " - "(must be 3 for RGB LED)", - dev->name, info->num_colors); - return -EINVAL; - } - - for (i = 0; i < 3; i++) { - if (!is31fl319x_count_colors(dev, info->color_mapping[i], rgb_counts)) { - return -EINVAL; - } - - } - break; - case 3: - /* check that each LED is single-color */ - for (i = 0; i < 3; i++) { - info = &config->led_infos[i]; - - if (info->num_colors != 1) { - LOG_ERR("%s: invalid number of colors %d " - "(must be 1 when defining multiple LEDs)", - dev->name, info->num_colors); - return -EINVAL; - } + /* verify that number of leds defined is not > number of channels */ + for (i = 0; i < config->num_leds; i++) { + info = &config->led_infos[i]; + rgb_count += info->num_colors; + } - if (!is31fl319x_count_colors(dev, info->color_mapping[0], rgb_counts)) { - return -EINVAL; - } - } - break; - default: - LOG_ERR("%s: invalid number of LEDs %d (must be 1 or 3)", - dev->name, config->num_leds); + if (rgb_count > config->channel_count) { return -EINVAL; } @@ -280,8 +230,8 @@ static int is31fl319x_init(const struct device *dev) const struct is31fl319x_config *config = dev->config; const struct led_info *info = NULL; const struct is31f1319x_model *regs = config->regs; - int i, ret; - uint8_t prod_id, band; + int i, j, ret; + uint8_t prod_id, band, channel; uint8_t current_reg = 0; ret = is31fl319x_check_config(dev); @@ -307,27 +257,24 @@ static int is31fl319x_init(const struct device *dev) } /* calc current limit register value */ - info = &config->led_infos[0]; - if (info->num_colors == IS31FL3194_CHANNEL_COUNT) { - /* one RGB LED: set all channels to the same current limit */ - band = (config->current_limits[0] / 10) - 1; - for (i = 0; i < IS31FL3194_CHANNEL_COUNT; i++) { - current_reg |= band << (2 * i); - } - } else { - /* single-channel LEDs: independent limits */ + if (regs->current_reg != REG_NOT_DEFINED) { + channel = 0; for (i = 0; i < config->num_leds; i++) { + info = &config->led_infos[i]; band = (config->current_limits[i] / 10) - 1; - current_reg |= band << (2 * i); + + for (j = 0; j < info->num_colors; j++) { + current_reg |= band << (2 * channel); + channel++; + } } - } - ret = i2c_reg_write_byte_dt(&config->bus, IS31FL3194_CURRENT_REG, current_reg); - if (ret != 0) { - LOG_ERR("%s: failed to set current limit", dev->name); - return ret; + ret = i2c_reg_write_byte_dt(&config->bus, regs->current_reg, current_reg); + if (ret != 0) { + LOG_ERR("%s: failed to set current limit", dev->name); + return ret; + } } - /* enable device */ return i2c_reg_write_byte_dt(&config->bus, regs->conf_reg, regs->conf_enable); @@ -337,6 +284,7 @@ static DEVICE_API(led, is31fl319x_led_api) = { .set_brightness = is31fl319x_set_brightness, .get_info = is31fl319x_get_info, .set_color = is31fl319x_set_color, + .write_channels = is31fl319x_write_channels, }; #define COLOR_MAPPING(led_node_id) \ diff --git a/samples/drivers/led/is31fl319x/README.rst b/samples/drivers/led/is31fl319x/README.rst index 740e4f7757cf4..02dba98d2a097 100644 --- a/samples/drivers/led/is31fl319x/README.rst +++ b/samples/drivers/led/is31fl319x/README.rst @@ -2,12 +2,23 @@ :name: IS31FL319x RGB LED :relevant-api: led_interface - Cycle colors on an RGB LED connected to the IS31FL3194 using the LED API. + Cycle colors on an RGB LED connected to the IS31FL3194 or IS31FL3197 + using the LED API. Overview ******** -This sample cycles several colors on an RGB LED forever using the LED API. +This sample first looks through the color table to map which channels +map to Red, Green and Blue. + +It then shows the mapping, but setting one color on and fading it +off. First Red, then Green and finally Blue. + +It then forever cycles through several colors on an RGB LED. It uses a +helper function, that maps the RGB colors into the correct order +for the actual hardware LED, as some hardware LEDs will be defined in +RGB order whereas others may be in another order such as BGR. +Once mapped it calls off to the led library to display the color. Building and Running ******************** @@ -18,11 +29,18 @@ any board where the devicetree has an I2C device node with compatible controller node also being enabled. .. zephyr-app-commands:: - :zephyr-app: samples/drivers/led/is31fl3194 + :zephyr-app: samples/drivers/led/is31fl319x :board: arduino_nicla_sense_me :goals: build flash :compact: +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/led/is31fl319x + :board: arduino_giga_r1//m7 + :shield: arduino_giga_display_shield + :goals: build flash + :compact: + After flashing, the LED starts to switch colors and messages with the current LED color are printed on the console. If a runtime error occurs, the sample exits without printing to the console. diff --git a/samples/drivers/led/is31fl319x/src/main.c b/samples/drivers/led/is31fl319x/src/main.c index 335d152101b0f..af5df59d0d4eb 100644 --- a/samples/drivers/led/is31fl319x/src/main.c +++ b/samples/drivers/led/is31fl319x/src/main.c @@ -7,6 +7,7 @@ #include #include #include +#include /* 1000 msec = 1 sec */ #define SLEEP_TIME_MS 1000 @@ -32,20 +33,42 @@ static const struct color_data color_sequence[] = { /* * A build error on this line means your board is unsupported. */ -const struct device *led = DEVICE_DT_GET_ANY(issi_is31fl3194); +const struct device *led_dev = DEVICE_DT_GET_ANY(issi_is31fl3194); +uint8_t rgb_mapping[3] = {0, 0, 0}; /* R G B */ + +/* + * forward references + */ +extern bool generate_rgb_color_mapping(const struct device *dev, uint32_t led); +extern bool output_rgb_color(const struct device *dev, uint32_t led, const uint8_t *colors); +extern void fade_one_channel(const struct device *dev, uint8_t rgb_color_index, const char *name); + +/* + * main + */ int main(void) { - int ret; int i = 0; - if (!device_is_ready(led)) { + if (!device_is_ready(led_dev)) { return 0; } + if (!generate_rgb_color_mapping(led_dev, 0)) { + printk("Failed to generate RGB Color mapping\n"); + return 0; + } + + /* lets try to verify the color indexes */ + fade_one_channel(led_dev, 0, "Red"); + fade_one_channel(led_dev, 1, "Green"); + fade_one_channel(led_dev, 2, "Blue"); + while (1) { - ret = led_set_color(led, 0, 3, &(color_sequence[i].r)); - if (ret < 0) { + /* map the colors */ + if (!output_rgb_color(led_dev, 0, &(color_sequence[i].r))) { + printk("call to led_set_color failed\n"); return 0; } @@ -56,3 +79,77 @@ int main(void) return 0; } + +/* + * Generate RGB color mapping + */ +bool generate_rgb_color_mapping(const struct device *dev, uint32_t led) +{ + const struct led_info *info; + + /* find the Red, Green, and blue color indexes */ + if (led_get_info(dev, led, &info) < 0) { + printk("Failed to retrieve LED info\n"); + return false; + } + /* generate color mapping table for this device */ + for (int i = 0; i < info->num_colors; i++) { + switch (info->color_mapping[i]) { + case LED_COLOR_ID_RED: + rgb_mapping[0] = i; + break; + case LED_COLOR_ID_GREEN: + rgb_mapping[1] = i; + break; + case LED_COLOR_ID_BLUE: + rgb_mapping[2] = i; + break; + default: + printk("Unknown color: %x found in index %d\n", info->color_mapping[i], i); + /* Ignore */ + break; + } + } + + printk("Color indexes: R:%u G:%u B:%u\n", rgb_mapping[0], + rgb_mapping[1], rgb_mapping[2]); + return true; +} + +/* + * Set one color (R or G or B) to all on and then fade it down to off + */ +void fade_one_channel(const struct device *dev, uint8_t rgb_color_index, const char *name) +{ + uint8_t colors[3] = {0, 0, 0}; + int color = 0xff; + + /* make sure all of the leds are off */ + if (led_set_color(dev, 0, 3, colors) < 0) { + return; + } + + printk("Test fading %s\n", name); + for (;;) { + led_set_channel(dev, rgb_mapping[rgb_color_index], color); + if (color == 0) { + break; + } + k_msleep(SLEEP_TIME_MS); + color >>= 2; + } +} + +/* + * Map the RGB color to the mapping order and output to the LED. + */ +bool output_rgb_color(const struct device *dev, uint32_t led, const uint8_t *colors) +{ + uint8_t mapped_colors[3]; + + for (uint8_t i = 0; i < 3; i++) { + mapped_colors[rgb_mapping[i]] = colors[i]; + } + + return led_set_color(dev, led, 3, mapped_colors) >= 0; +} From ce5812a8c7b06185fc3b042a02cc982972555a9d Mon Sep 17 00:00:00 2001 From: Kurt Eckhardt Date: Sun, 5 Oct 2025 08:24:36 -0700 Subject: [PATCH 4/5] drivers: led: is31fl319x add is31fl3197 support Add the registers and the like to the .c file plus add a Kconf file plus bindings. Updated example sketch: to also check for is31fl3197 boards Signed-off-by: Kurt Eckhardt --- drivers/led/Kconfig.is31fl3197 | 11 ++ drivers/led/Kconfig.is31fl319x | 3 +- drivers/led/is31fl319x.c | 143 +++++++++++++++++----- dts/bindings/led/issi,is31fl3197.yaml | 80 ++++++++++++ samples/drivers/led/is31fl319x/README.rst | 11 +- samples/drivers/led/is31fl319x/src/main.c | 12 +- 6 files changed, 215 insertions(+), 45 deletions(-) create mode 100644 drivers/led/Kconfig.is31fl3197 create mode 100644 dts/bindings/led/issi,is31fl3197.yaml diff --git a/drivers/led/Kconfig.is31fl3197 b/drivers/led/Kconfig.is31fl3197 new file mode 100644 index 0000000000000..f1cb8357e4c89 --- /dev/null +++ b/drivers/led/Kconfig.is31fl3197 @@ -0,0 +1,11 @@ +# Copyright (c) 2024 Arduino SA +# SPDX-License-Identifier: Apache-2.0 + +config IS31FL3197 + bool "IS31FL3197 LED driver" + default y + depends on DT_HAS_ISSI_IS31FL3197_ENABLED + select I2C + help + Enable LED driver for Lumissil Microsystems (a division of ISSI) + IS31FL3197. This chip supports one RGB LED or 4 independent LEDs. diff --git a/drivers/led/Kconfig.is31fl319x b/drivers/led/Kconfig.is31fl319x index d6cb8198a7967..5c3d48bba7cb7 100644 --- a/drivers/led/Kconfig.is31fl319x +++ b/drivers/led/Kconfig.is31fl319x @@ -4,8 +4,9 @@ config IS31FL319X bool "IS31FL319X LED driver" default y - depends on DT_HAS_ISSI_IS31FL3194_ENABLED + depends on DT_HAS_ISSI_IS31FL3194_ENABLED || DT_HAS_ISSI_IS31FL3197_ENABLED select I2C help Enable LED driver for Lumissil Microsystems (a division of ISSI) IS31FL3194. This chip supports one RGB LED or 3 independent LEDs. + IS31FL3197. This chip supports 4 LEDs. diff --git a/drivers/led/is31fl319x.c b/drivers/led/is31fl319x.c index f6e51b8b2c7d7..02bc211ff8d25 100644 --- a/drivers/led/is31fl319x.c +++ b/drivers/led/is31fl319x.c @@ -21,9 +21,15 @@ #include LOG_MODULE_REGISTER(is31fl319x, CONFIG_LED_LOG_LEVEL); + +/* define features that are specific subset of supported devices */ #define REG_NOT_DEFINED 0xff +#define FEATURE_ID_IS_ADDR 0x01 /* The id is the bus address */ +#define FEATURE_SET_CURRENT 0x02 /* the device supports setting current limits */ + struct is31f1319x_model { + const uint8_t features; const uint8_t prod_id_reg; const uint8_t shutdown_reg; const uint8_t conf_reg; @@ -38,7 +44,17 @@ struct is31f1319x_model { const uint8_t led_channels[]; }; +struct is31fl319x_config { + struct i2c_dt_spec bus; + uint8_t channel_count; + uint8_t num_leds; + const struct led_info *led_infos; + const uint8_t *current_limits; + const struct is31f1319x_model *model; +}; +#ifdef CONFIG_DT_HAS_ISSI_IS31FL3194_ENABLED +/* IS31FL3194 model registers and values */ #define IS31FL3194_PROD_ID_REG 0x00 #define IS31FL3194_CONF_REG 0x01 #define IS31FL3194_CURRENT_REG 0x03 @@ -54,6 +70,8 @@ struct is31f1319x_model { #define IS31FL3194_CHANNEL_COUNT 3 static const struct is31f1319x_model is31f13194_model = { + .features = FEATURE_SET_CURRENT, + /* register indexes */ .prod_id_reg = IS31FL3194_PROD_ID_REG, .shutdown_reg = REG_NOT_DEFINED, @@ -69,15 +87,46 @@ static const struct is31f1319x_model is31f13194_model = { /* channel output registers */ .led_channels = {IS31FL3194_OUT1_REG, IS31FL3194_OUT2_REG, IS31FL3194_OUT3_REG}}; +#endif -struct is31fl319x_config { - struct i2c_dt_spec bus; - uint8_t channel_count; - uint8_t num_leds; - const struct led_info *led_infos; - const uint8_t *current_limits; - const struct is31f1319x_model *regs; +#ifdef CONFIG_DT_HAS_ISSI_IS31FL3197_ENABLED +/* IS31FL3197 model registers and values */ +#define IS31FL3197_PROD_ID_REG 0x00 +#define IS31FL3197_SHUTDOWN_REG 0x01 +#define IS31FL3197_OPER_CONFIG_REG 0x02 +#define IS31FL3197_OUT1_REG 0x10 +#define IS31FL3197_OUT2_REG 0x11 +#define IS31FL3197_OUT3_REG 0x12 +#define IS31FL3197_OUT4_REG 0x13 +#define IS31FL3197_UPDATE_REG 0x2b + +#define IS31FL3197_SHUTDOWN_REG_VAL 0xf1 /* enable all channels */ +#define IS31FL3197_OPER_CONFIG_REG_VAL 0xff /* set all to current level */ +#define IS31FL3197_UPDATE_VAL 0xc5 + +#define IS31FL3197_CHANNEL_COUNT 4 + +static const struct is31f1319x_model is31f13197_model = { + .features = FEATURE_ID_IS_ADDR, + + /* register indexes */ + .prod_id_reg = IS31FL3197_PROD_ID_REG, + .shutdown_reg = IS31FL3197_SHUTDOWN_REG, + .conf_reg = IS31FL3197_OPER_CONFIG_REG, + .current_reg = REG_NOT_DEFINED, + .update_reg = IS31FL3197_UPDATE_REG, + + /* values for those registers */ + .prod_id_val = 0xff, + .shutdown_reg_val = IS31FL3197_SHUTDOWN_REG_VAL, + .conf_enable = IS31FL3197_OPER_CONFIG_REG_VAL, + .update_val = IS31FL3197_UPDATE_VAL, + + /* channel output registers */ + .led_channels = {IS31FL3197_OUT1_REG, IS31FL3197_OUT2_REG, IS31FL3197_OUT3_REG, + IS31FL3197_OUT4_REG} }; +#endif static const struct led_info *is31fl319x_led_to_info(const struct is31fl319x_config *config, uint32_t led) @@ -123,15 +172,15 @@ static int is31fl319x_write_channels(const struct device *dev, uint32_t start_ch uint32_t num_channels, const uint8_t *buf) { const struct is31fl319x_config *config = dev->config; - const struct is31f1319x_model *regs = config->regs; - int ret; + const struct is31f1319x_model *model = config->model; + int ret = 0; if ((start_channel + num_channels) > config->channel_count) { return -ENOTSUP; } for (int i = 0; i < num_channels; i++) { - ret = i2c_reg_write_byte_dt(&config->bus, regs->led_channels[i + start_channel], + ret = i2c_reg_write_byte_dt(&config->bus, model->led_channels[i + start_channel], buf[i]); if (ret != 0) { break; @@ -140,8 +189,8 @@ static int is31fl319x_write_channels(const struct device *dev, uint32_t start_ch if (ret == 0) { ret = i2c_reg_write_byte_dt(&config->bus, - regs->update_reg, - regs->update_val); + model->update_reg, + model->update_val); } if (ret != 0) { @@ -174,7 +223,7 @@ static int is31fl319x_set_brightness(const struct device *dev, uint32_t led, uin { const struct is31fl319x_config *config = dev->config; const struct led_info *info = is31fl319x_led_to_info(config, led); - const struct is31f1319x_model *regs = config->regs; + const struct is31f1319x_model *model = config->model; int ret = 0; @@ -191,11 +240,11 @@ static int is31fl319x_set_brightness(const struct device *dev, uint32_t led, uin uint8_t channel_start = is31fl319x_map_led_to_start_channel(config, led); - ret = i2c_reg_write_byte_dt(&config->bus, regs->led_channels[channel_start], value); + ret = i2c_reg_write_byte_dt(&config->bus, model->led_channels[channel_start], value); if (ret == 0) { ret = i2c_reg_write_byte_dt(&config->bus, - regs->update_reg, - regs->update_val); + model->update_reg, + model->update_val); } if (ret != 0) { @@ -210,10 +259,9 @@ static int is31fl319x_check_config(const struct device *dev) const struct is31fl319x_config *config = dev->config; const struct led_info *info; uint8_t rgb_count = 0; - uint8_t i; /* verify that number of leds defined is not > number of channels */ - for (i = 0; i < config->num_leds; i++) { + for (int i = 0; i < config->num_leds; i++) { info = &config->led_infos[i]; rgb_count += info->num_colors; } @@ -229,8 +277,8 @@ static int is31fl319x_init(const struct device *dev) { const struct is31fl319x_config *config = dev->config; const struct led_info *info = NULL; - const struct is31f1319x_model *regs = config->regs; - int i, j, ret; + const struct is31f1319x_model *model = config->model; + int ret; uint8_t prod_id, band, channel; uint8_t current_reg = 0; @@ -244,40 +292,59 @@ static int is31fl319x_init(const struct device *dev) return -ENODEV; } - ret = i2c_reg_read_byte_dt(&config->bus, regs->prod_id_reg, &prod_id); + ret = i2c_reg_read_byte_dt(&config->bus, model->prod_id_reg, &prod_id); if (ret != 0) { LOG_ERR("%s: failed to read product ID", dev->name); return ret; } - if (prod_id != regs->prod_id_val) { - LOG_ERR("%s: invalid product ID 0x%02x (expected 0x%02x)", dev->name, prod_id, - regs->prod_id_val); - return -ENODEV; + + if (model->features & FEATURE_ID_IS_ADDR) { + /* The product ID (8 bit) should be the I2C address(7 bit) */ + if (prod_id != (config->bus.addr << 1)) { + LOG_ERR("%s: invalid product ID 0x%02x (expected 0x%02x)", dev->name, + prod_id, config->bus.addr << 1); + return -ENODEV; + } + } else { + if (prod_id != model->prod_id_val) { + LOG_ERR("%s: invalid product ID 0x%02x (expected 0x%02x)", dev->name, + prod_id, model->prod_id_val); + return -ENODEV; + } } /* calc current limit register value */ - if (regs->current_reg != REG_NOT_DEFINED) { + if (model->features & FEATURE_SET_CURRENT) { channel = 0; - for (i = 0; i < config->num_leds; i++) { + for (int i = 0; i < config->num_leds; i++) { info = &config->led_infos[i]; band = (config->current_limits[i] / 10) - 1; - for (j = 0; j < info->num_colors; j++) { + for (int j = 0; j < info->num_colors; j++) { current_reg |= band << (2 * channel); channel++; } } - ret = i2c_reg_write_byte_dt(&config->bus, regs->current_reg, current_reg); + ret = i2c_reg_write_byte_dt(&config->bus, model->current_reg, current_reg); + if (ret != 0) { + LOG_ERR("%s: failed to set current limit", dev->name); + return ret; + } + } + if (model->shutdown_reg != REG_NOT_DEFINED) { + ret = i2c_reg_write_byte_dt(&config->bus, model->shutdown_reg, + model->shutdown_reg_val); if (ret != 0) { LOG_ERR("%s: failed to set current limit", dev->name); return ret; } } + /* enable device */ - return i2c_reg_write_byte_dt(&config->bus, regs->conf_reg, - regs->conf_enable); + return i2c_reg_write_byte_dt(&config->bus, model->conf_reg, + model->conf_enable); } static DEVICE_API(led, is31fl319x_led_api) = { @@ -301,7 +368,7 @@ static DEVICE_API(led, is31fl319x_led_api) = { #define LED_CURRENT(led_node_id) \ DT_PROP(led_node_id, current_limit), -#define IS31FL319X_DEVICE(n, id, nchannels, pregs) \ +#define IS31FL319X_DEVICE(n, id, nchannels, pmodel) \ \ DT_INST_FOREACH_CHILD(n, COLOR_MAPPING) \ \ @@ -319,13 +386,23 @@ static DEVICE_API(led, is31fl319x_led_api) = { .num_leds = ARRAY_SIZE(is31fl319##id##_leds_##n), \ .led_infos = is31fl319##id##_leds_##n, \ .current_limits = is31fl319##id##_currents_##n, \ - .regs = pregs, \ + .model = pmodel, \ }; \ DEVICE_DT_INST_DEFINE(n, &is31fl319x_init, NULL, NULL, \ &is31fl319##id##_config_##n, POST_KERNEL, \ CONFIG_LED_INIT_PRIORITY, &is31fl319x_led_api); #undef DT_DRV_COMPAT +#ifdef CONFIG_DT_HAS_ISSI_IS31FL3194_ENABLED #define DT_DRV_COMPAT issi_is31fl3194 DT_INST_FOREACH_STATUS_OKAY_VARGS(IS31FL319X_DEVICE, 4, IS31FL3194_CHANNEL_COUNT, &is31f13194_model) +#endif + +#ifdef CONFIG_DT_HAS_ISSI_IS31FL3197_ENABLED +#undef DT_DRV_COMPAT +#define DT_DRV_COMPAT issi_is31fl3197 +DT_INST_FOREACH_STATUS_OKAY_VARGS(IS31FL319X_DEVICE, 7, IS31FL3197_CHANNEL_COUNT, + &is31f13197_model) +#endif +#undef DT_DRV_COMPAT diff --git a/dts/bindings/led/issi,is31fl3197.yaml b/dts/bindings/led/issi,is31fl3197.yaml new file mode 100644 index 0000000000000..93d232e2240f3 --- /dev/null +++ b/dts/bindings/led/issi,is31fl3197.yaml @@ -0,0 +1,80 @@ +# Copyright (c) 2024 Arduino SA +# SPDX-License-Identifier: Apache-2.0 + +description: | + IS31FL3197 4-channel LED driver with programmable pattern sequencing + + This driver supports single-channel and RGB LEDs. For single channel LEDs, + the led_set_brightness() API can be used to set the brightness of each LED. + For RGB LEDs, the led_set_color() API can be used to set the red, green and + blue components; the driver takes care of routing to the outputs described + by the color-mapping property. + + The LED_SHELL application can be used for testing. + + The following shows configuration for Arduino Giga Display shield + + This driver supports single-channel and RGB and maybe RGBW LEDs. For single + channel LEDs, the led_set_brightness() API can be used to set the brightness + of each LED. For RGB LEDs, the led_set_color() API can be used to set the red, + green and blue and white components; the driver takes care of routing to the + outputs described by the color-mapping property. + + The LED_SHELL application can be used for testing. + + The following defines a single RGB LED in the is31fl3197 DT node: + + is31fl3197@50 { + compatible = "issi,is31fl3197"; + reg = <0x50>; + + led_0 { + label = "RGB LED"; + color-mapping = + , + , + ; + }; + }; + + The following example defines three single-channel LEDs in the is31fl3197 DT node: + + is31fl3197@50 { + compatible = "issi,is31fl3197"; + reg = <0x50>; + + led_0 { + label = "RED LED"; + color-mapping = ; + }; + + led_1 { + label = "GREEN LED"; + color-mapping = ; + }; + + led_2 { + label = "BLUE LED"; + color-mapping = ; + }; + }; + +compatible: "issi,is31fl3197" + +include: ["i2c-device.yaml", "led-controller.yaml"] + +child-binding: + properties: + label: + required: true + + color-mapping: + required: true + + current-limit: + type: int + default: 10 + enum: + - 10 + description: | + The current limit for the LED in mA. diff --git a/samples/drivers/led/is31fl319x/README.rst b/samples/drivers/led/is31fl319x/README.rst index 02dba98d2a097..da81b5d21ca41 100644 --- a/samples/drivers/led/is31fl319x/README.rst +++ b/samples/drivers/led/is31fl319x/README.rst @@ -25,8 +25,8 @@ Building and Running This sample can be built and executed on an Arduino Nicla Sense ME, or on any board where the devicetree has an I2C device node with compatible -:dtcompatible:`issi,is31fl3194` enabled, along with the relevant bus -controller node also being enabled. +:dtcompatible:`issi,is31fl3194` or :dtcompatible:`issi,is31fl3197` with the +relevant bus controller node also being enabled. .. zephyr-app-commands:: :zephyr-app: samples/drivers/led/is31fl319x @@ -34,13 +34,6 @@ controller node also being enabled. :goals: build flash :compact: -.. zephyr-app-commands:: - :zephyr-app: samples/drivers/led/is31fl319x - :board: arduino_giga_r1//m7 - :shield: arduino_giga_display_shield - :goals: build flash - :compact: - After flashing, the LED starts to switch colors and messages with the current LED color are printed on the console. If a runtime error occurs, the sample exits without printing to the console. diff --git a/samples/drivers/led/is31fl319x/src/main.c b/samples/drivers/led/is31fl319x/src/main.c index af5df59d0d4eb..c2d4d92e7470d 100644 --- a/samples/drivers/led/is31fl319x/src/main.c +++ b/samples/drivers/led/is31fl319x/src/main.c @@ -31,9 +31,10 @@ static const struct color_data color_sequence[] = { }; /* - * A build error on this line means your board is unsupported. + * A build error on these lines means your board is unsupported. */ -const struct device *led_dev = DEVICE_DT_GET_ANY(issi_is31fl3194); +const struct device *led4_dev = DEVICE_DT_GET_ANY(issi_is31fl3194); +const struct device *led7_dev = DEVICE_DT_GET_ANY(issi_is31fl3197); uint8_t rgb_mapping[3] = {0, 0, 0}; /* R G B */ @@ -51,7 +52,14 @@ int main(void) { int i = 0; + const struct device *led_dev = led4_dev; + + if (led_dev == NULL) { + led_dev = led7_dev; + } + if (!device_is_ready(led_dev)) { + printk("No devices were found"); return 0; } From f4e7c5c010d5a12f884a70a5068d194457963aca Mon Sep 17 00:00:00 2001 From: Kurt Eckhardt Date: Sun, 5 Oct 2025 08:29:14 -0700 Subject: [PATCH 5/5] boards: shields: arduino_giga_display_shield: add LED to DT Added is31fl3197@50 to overlay Also updated GIGA board yaml file to say that it supports i2c And updated sample sketch to mention it Signed-off-by: Kurt Eckhardt --- .../giga_r1/arduino_giga_r1_stm32h747xx_m7.yaml | 1 + .../boards/arduino_giga_r1_m7.overlay | 12 ++++++++++++ samples/drivers/led/is31fl319x/README.rst | 14 +++++++++++--- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/boards/arduino/giga_r1/arduino_giga_r1_stm32h747xx_m7.yaml b/boards/arduino/giga_r1/arduino_giga_r1_stm32h747xx_m7.yaml index 285330d8b011c..53bb6d3bd7049 100644 --- a/boards/arduino/giga_r1/arduino_giga_r1_stm32h747xx_m7.yaml +++ b/boards/arduino/giga_r1/arduino_giga_r1_stm32h747xx_m7.yaml @@ -12,6 +12,7 @@ supported: - gpio - arduino_spi - spi + - i2c - memc - usb_device vendor: arduino diff --git a/boards/shields/arduino_giga_display_shield/boards/arduino_giga_r1_m7.overlay b/boards/shields/arduino_giga_display_shield/boards/arduino_giga_r1_m7.overlay index 5c9ce42074458..464e37e8528cb 100644 --- a/boards/shields/arduino_giga_display_shield/boards/arduino_giga_r1_m7.overlay +++ b/boards/shields/arduino_giga_display_shield/boards/arduino_giga_r1_m7.overlay @@ -5,6 +5,7 @@ */ #include +#include / { lvgl_pointer { @@ -93,4 +94,15 @@ reset-gpios = <&gpioi 2 GPIO_ACTIVE_LOW>; irq-gpios = <&gpioi 1 GPIO_ACTIVE_HIGH>; }; + is31fl3197@50 { + compatible = "issi,is31fl3197"; + reg = <0x50>; + + led_rgb { + label = "RGB LED"; + color-mapping = , + , + ; + }; + }; }; diff --git a/samples/drivers/led/is31fl319x/README.rst b/samples/drivers/led/is31fl319x/README.rst index da81b5d21ca41..7549488c23372 100644 --- a/samples/drivers/led/is31fl319x/README.rst +++ b/samples/drivers/led/is31fl319x/README.rst @@ -23,10 +23,11 @@ Once mapped it calls off to the led library to display the color. Building and Running ******************** -This sample can be built and executed on an Arduino Nicla Sense ME, or on +This sample can be built and executed on an Arduino Nicla Sense ME, or +Arduino Giga with an Arduino Giga Display shield, or on any board where the devicetree has an I2C device node with compatible -:dtcompatible:`issi,is31fl3194` or :dtcompatible:`issi,is31fl3197` with the -relevant bus controller node also being enabled. +:dtcompatible:`issi,is31fl3194` or :dtcompatible:`issi,is31fl3197` +with the relevant bus controller node also being enabled. .. zephyr-app-commands:: :zephyr-app: samples/drivers/led/is31fl319x @@ -34,6 +35,13 @@ relevant bus controller node also being enabled. :goals: build flash :compact: +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/led/is31fl319x + :board: arduino_giga_r1//m7 + :shield: arduino_giga_display_shield + :goals: build flash + :compact: + After flashing, the LED starts to switch colors and messages with the current LED color are printed on the console. If a runtime error occurs, the sample exits without printing to the console.