Skip to content

Commit c8b96ea

Browse files
committed
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 <[email protected]>
1 parent e0dd3f4 commit c8b96ea

File tree

6 files changed

+188
-32
lines changed

6 files changed

+188
-32
lines changed

drivers/led/Kconfig.is31fl3197

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Copyright (c) 2024 Arduino SA
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config IS31FL3197
5+
bool "IS31FL3197 LED driver"
6+
default y
7+
depends on DT_HAS_ISSI_IS31FL3197_ENABLED
8+
select I2C
9+
help
10+
Enable LED driver for Lumissil Microsystems (a division of ISSI)
11+
IS31FL3197. This chip supports one RGB LED or 4 independent LEDs.

drivers/led/Kconfig.is31fl319x

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
config IS31FL319X
55
bool "IS31FL319X LED driver"
66
default y
7-
depends on DT_HAS_ISSI_IS31FL3194_ENABLED
7+
depends on DT_HAS_ISSI_IS31FL3194_ENABLED || DT_HAS_ISSI_IS31FL3197_ENABLED
88
select I2C
99
help
1010
Enable LED driver for Lumissil Microsystems (a division of ISSI)
1111
IS31FL3194. This chip supports one RGB LED or 3 independent LEDs.
12+
IS31FL3197. This chip supports 4 LEDs.

drivers/led/is31fl319x.c

Lines changed: 84 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,17 @@ struct is31f1319x_model {
3838
const uint8_t led_channels[];
3939
};
4040

41+
struct is31fl319x_config {
42+
struct i2c_dt_spec bus;
43+
uint8_t channel_count;
44+
uint8_t num_leds;
45+
const struct led_info *led_infos;
46+
const uint8_t *current_limits;
47+
const struct is31f1319x_model *regs;
48+
};
4149

50+
#ifdef CONFIG_DT_HAS_ISSI_IS31FL3194_ENABLED
51+
/* IS31FL3194 model registers and values */
4252
#define IS31FL3194_PROD_ID_REG 0x00
4353
#define IS31FL3194_CONF_REG 0x01
4454
#define IS31FL3194_CURRENT_REG 0x03
@@ -69,15 +79,44 @@ static const struct is31f1319x_model is31f13194_model = {
6979

7080
/* channel output registers */
7181
.led_channels = {IS31FL3194_OUT1_REG, IS31FL3194_OUT2_REG, IS31FL3194_OUT3_REG}};
82+
#endif
83+
84+
#ifdef CONFIG_DT_HAS_ISSI_IS31FL3197_ENABLED
85+
/* IS31FL3197 model registers and values */
86+
#define IS31FL3197_PROD_ID_REG 0x00
87+
#define IS31FL3197_SHUTDOWN_REG 0x01
88+
#define IS31FL3197_OPER_CONFIG_REG 0x02
89+
#define IS31FL3197_OUT1_REG 0x10
90+
#define IS31FL3197_OUT2_REG 0x11
91+
#define IS31FL3197_OUT3_REG 0x12
92+
#define IS31FL3197_OUT4_REG 0x13
93+
#define IS31FL3197_UPDATE_REG 0x2b
94+
95+
#define IS31FL3197_SHUTDOWN_REG_VAL 0xf1 /* enable all channels */
96+
#define IS31FL3197_OPER_CONFIG_REG_VAL 0xff /* set all to current level */
97+
#define IS31FL3197_UPDATE_VAL 0xc5
98+
99+
#define IS31FL3197_CHANNEL_COUNT 4
100+
101+
static const struct is31f1319x_model is31f13197_model = {
102+
/* register indexes */
103+
.prod_id_reg = IS31FL3197_PROD_ID_REG,
104+
.shutdown_reg = IS31FL3197_SHUTDOWN_REG,
105+
.conf_reg = IS31FL3197_OPER_CONFIG_REG,
106+
.current_reg = REG_NOT_DEFINED,
107+
.update_reg = IS31FL3197_UPDATE_REG,
72108

73-
struct is31fl319x_config {
74-
struct i2c_dt_spec bus;
75-
uint8_t channel_count;
76-
uint8_t num_leds;
77-
const struct led_info *led_infos;
78-
const uint8_t *current_limits;
79-
const struct is31f1319x_model *regs;
109+
/* values for those registers */
110+
.prod_id_val = 0xff,
111+
.shutdown_reg_val = IS31FL3197_SHUTDOWN_REG_VAL,
112+
.conf_enable = IS31FL3197_OPER_CONFIG_REG_VAL,
113+
.update_val = IS31FL3197_UPDATE_VAL,
114+
115+
/* channel output registers */
116+
.led_channels = {IS31FL3197_OUT1_REG, IS31FL3197_OUT2_REG, IS31FL3197_OUT3_REG,
117+
IS31FL3197_OUT4_REG}
80118
};
119+
#endif
81120

82121
static const struct led_info *is31fl319x_led_to_info(const struct is31fl319x_config *config,
83122
uint32_t led)
@@ -124,7 +163,7 @@ static int is31fl319x_write_channels(const struct device *dev, uint32_t start_ch
124163
{
125164
const struct is31fl319x_config *config = dev->config;
126165
const struct is31f1319x_model *regs = config->regs;
127-
int ret;
166+
int ret = 0;
128167

129168
if ((start_channel + num_channels) > config->channel_count) {
130169
return -ENOTSUP;
@@ -210,10 +249,9 @@ static int is31fl319x_check_config(const struct device *dev)
210249
const struct is31fl319x_config *config = dev->config;
211250
const struct led_info *info;
212251
uint8_t rgb_count = 0;
213-
uint8_t i;
214252

215253
/* verify that number of leds defined is not > number of channels */
216-
for (i = 0; i < config->num_leds; i++) {
254+
for (int i = 0; i < config->num_leds; i++) {
217255
info = &config->led_infos[i];
218256
rgb_count += info->num_colors;
219257
}
@@ -230,7 +268,7 @@ static int is31fl319x_init(const struct device *dev)
230268
const struct is31fl319x_config *config = dev->config;
231269
const struct led_info *info = NULL;
232270
const struct is31f1319x_model *regs = config->regs;
233-
int i, j, ret;
271+
int ret;
234272
uint8_t prod_id, band, channel;
235273
uint8_t current_reg = 0;
236274

@@ -250,20 +288,30 @@ static int is31fl319x_init(const struct device *dev)
250288
return ret;
251289
}
252290

253-
if (prod_id != regs->prod_id_val) {
254-
LOG_ERR("%s: invalid product ID 0x%02x (expected 0x%02x)", dev->name, prod_id,
255-
regs->prod_id_val);
256-
return -ENODEV;
291+
if (regs->prod_id_val != 0xff) {
292+
if (prod_id != regs->prod_id_val) {
293+
LOG_ERR("%s: invalid product ID 0x%02x (expected 0x%02x)", dev->name,
294+
prod_id, regs->prod_id_val);
295+
return -ENODEV;
296+
}
297+
} else {
298+
299+
/* The product ID (8 bit) should be the I2C address(7 bit) */
300+
if (prod_id != (config->bus.addr << 1)) {
301+
LOG_ERR("%s: invalid product ID 0x%02x (expected 0x%02x)", dev->name,
302+
prod_id, config->bus.addr << 1);
303+
return -ENODEV;
304+
}
257305
}
258306

259307
/* calc current limit register value */
260308
if (regs->current_reg != REG_NOT_DEFINED) {
261309
channel = 0;
262-
for (i = 0; i < config->num_leds; i++) {
310+
for (int i = 0; i < config->num_leds; i++) {
263311
info = &config->led_infos[i];
264312
band = (config->current_limits[i] / 10) - 1;
265313

266-
for (j = 0; j < info->num_colors; j++) {
314+
for (int j = 0; j < info->num_colors; j++) {
267315
current_reg |= band << (2 * channel);
268316
channel++;
269317
}
@@ -275,6 +323,15 @@ static int is31fl319x_init(const struct device *dev)
275323
return ret;
276324
}
277325
}
326+
if (regs->shutdown_reg != REG_NOT_DEFINED) {
327+
ret = i2c_reg_write_byte_dt(&config->bus, regs->shutdown_reg,
328+
regs->shutdown_reg_val);
329+
if (ret != 0) {
330+
LOG_ERR("%s: failed to set current limit", dev->name);
331+
return ret;
332+
}
333+
}
334+
278335
/* enable device */
279336
return i2c_reg_write_byte_dt(&config->bus, regs->conf_reg,
280337
regs->conf_enable);
@@ -326,6 +383,16 @@ static DEVICE_API(led, is31fl319x_led_api) = {
326383
CONFIG_LED_INIT_PRIORITY, &is31fl319x_led_api);
327384

328385
#undef DT_DRV_COMPAT
386+
#ifdef CONFIG_DT_HAS_ISSI_IS31FL3194_ENABLED
329387
#define DT_DRV_COMPAT issi_is31fl3194
330388
DT_INST_FOREACH_STATUS_OKAY_VARGS(IS31FL319X_DEVICE, 4, IS31FL3194_CHANNEL_COUNT,
331389
&is31f13194_model)
390+
#endif
391+
392+
#ifdef CONFIG_DT_HAS_ISSI_IS31FL3197_ENABLED
393+
#undef DT_DRV_COMPAT
394+
#define DT_DRV_COMPAT issi_is31fl3197
395+
DT_INST_FOREACH_STATUS_OKAY_VARGS(IS31FL319X_DEVICE, 7, IS31FL3197_CHANNEL_COUNT,
396+
&is31f13197_model)
397+
#endif
398+
#undef DT_DRV_COMPAT
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Copyright (c) 2024 Arduino SA
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: |
5+
IS31FL3197 4-channel LED driver with programmable pattern sequencing
6+
7+
This driver supports single-channel and RGB LEDs. For single channel LEDs,
8+
the led_set_brightness() API can be used to set the brightness of each LED.
9+
For RGB LEDs, the led_set_color() API can be used to set the red, green and
10+
blue components; the driver takes care of routing to the outputs described
11+
by the color-mapping property.
12+
13+
The LED_SHELL application can be used for testing.
14+
15+
The following shows configuration for Arduino Giga Display shield
16+
17+
This driver supports single-channel and RGB and maybe RGBW LEDs. For single
18+
channel LEDs, the led_set_brightness() API can be used to set the brightness
19+
of each LED. For RGB LEDs, the led_set_color() API can be used to set the red,
20+
green and blue and white components; the driver takes care of routing to the
21+
outputs described by the color-mapping property.
22+
23+
The LED_SHELL application can be used for testing.
24+
25+
The following defines a single RGB LED in the is31fl3197 DT node:
26+
27+
is31fl3197@50 {
28+
compatible = "issi,is31fl3197";
29+
reg = <0x50>;
30+
31+
led_0 {
32+
label = "RGB LED";
33+
color-mapping =
34+
<LED_COLOR_ID_RED>,
35+
<LED_COLOR_ID_GREEN>,
36+
<LED_COLOR_ID_BLUE>;
37+
};
38+
};
39+
40+
The following example defines three single-channel LEDs in the is31fl3197 DT node:
41+
42+
is31fl3197@50 {
43+
compatible = "issi,is31fl3197";
44+
reg = <0x50>;
45+
46+
led_0 {
47+
label = "RED LED";
48+
color-mapping = <LED_COLOR_ID_RED>;
49+
};
50+
51+
led_1 {
52+
label = "GREEN LED";
53+
color-mapping = <LED_COLOR_ID_GREEN>;
54+
};
55+
56+
led_2 {
57+
label = "BLUE LED";
58+
color-mapping = <LED_COLOR_ID_BLUE>;
59+
};
60+
};
61+
62+
compatible: "issi,is31fl3197"
63+
64+
include: ["i2c-device.yaml", "led-controller.yaml"]
65+
66+
child-binding:
67+
properties:
68+
label:
69+
required: true
70+
71+
color-mapping:
72+
required: true
73+
74+
current-limit:
75+
type: int
76+
default: 10
77+
enum:
78+
- 10
79+
description: |
80+
The current limit for the LED in mA.

samples/drivers/led/is31fl319x/README.rst

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,15 @@ Building and Running
2525

2626
This sample can be built and executed on an Arduino Nicla Sense ME, or on
2727
any board where the devicetree has an I2C device node with compatible
28-
:dtcompatible:`issi,is31fl3194` enabled, along with the relevant bus
29-
controller node also being enabled.
28+
:dtcompatible:`issi,is31fl3194` or :dtcompatible:`issi,is31fl319` with the
29+
relevant bus controller node also being enabled.
3030

3131
.. zephyr-app-commands::
3232
:zephyr-app: samples/drivers/led/is31fl319x
3333
:board: arduino_nicla_sense_me
3434
:goals: build flash
3535
:compact:
3636

37-
.. zephyr-app-commands::
38-
:zephyr-app: samples/drivers/led/is31fl319x
39-
:board: arduino_giga_r1//m7
40-
:shield: arduino_giga_display_shield
41-
:goals: build flash
42-
:compact:
43-
4437
After flashing, the LED starts to switch colors and messages with the current
4538
LED color are printed on the console. If a runtime error occurs, the sample
4639
exits without printing to the console.

samples/drivers/led/is31fl319x/src/main.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,10 @@ static const struct color_data color_sequence[] = {
3131
};
3232

3333
/*
34-
* A build error on this line means your board is unsupported.
34+
* A build error on these lines means your board is unsupported.
3535
*/
36-
#ifdef CONFIG_IS31FL3194
37-
const struct device *led_dev = DEVICE_DT_GET_ANY(issi_is31fl3194);
38-
#endif
36+
const struct device *led4_dev = DEVICE_DT_GET_ANY(issi_is31fl3194);
37+
const struct device *led7_dev = DEVICE_DT_GET_ANY(issi_is31fl3197);
3938

4039
uint8_t rgb_mapping[3] = {0, 0, 0}; /* R G B */
4140

@@ -53,7 +52,13 @@ int main(void)
5352
{
5453
int i = 0;
5554

55+
const struct device *led_dev = led4_dev;
56+
if (led_dev == NULL) {
57+
led_dev = led7_dev;
58+
}
59+
5660
if (!device_is_ready(led_dev)) {
61+
printk("No devices were found");
5762
return 0;
5863
}
5964

@@ -155,4 +160,3 @@ bool output_rgb_color(const struct device *dev, uint32_t led, const uint8_t *co
155160

156161
return led_set_color(dev, led, 3, mapped_colors) >= 0;
157162
}
158-

0 commit comments

Comments
 (0)