Skip to content

Commit 7224f30

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 sample: to also check for is31fl3197 boards Signed-off-by: Kurt Eckhardt <[email protected]>
1 parent b8a9e4a commit 7224f30

File tree

5 files changed

+199
-40
lines changed

5 files changed

+199
-40
lines changed

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: 105 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,15 @@
2121
#include <zephyr/dt-bindings/led/led.h>
2222

2323
LOG_MODULE_REGISTER(is31fl319x, CONFIG_LED_LOG_LEVEL);
24+
25+
/* define features that are specific subset of supported devices */
2426
#define REG_NOT_DEFINED 0xff
2527

28+
#define FEATURE_ID_IS_ADDR 0x01 /* The id is the bus address */
29+
#define FEATURE_SET_CURRENT 0x02 /* the device supports setting current limits */
30+
2631
struct is31f1319x_model {
32+
const uint8_t features;
2733
const uint8_t prod_id_reg;
2834
const uint8_t shutdown_reg;
2935
const uint8_t conf_reg;
@@ -38,7 +44,17 @@ struct is31f1319x_model {
3844
const uint8_t led_channels[];
3945
};
4046

47+
struct is31fl319x_config {
48+
struct i2c_dt_spec bus;
49+
uint8_t channel_count;
50+
uint8_t num_leds;
51+
const struct led_info *led_infos;
52+
const uint8_t *current_limits;
53+
const struct is31f1319x_model *model;
54+
};
4155

56+
#ifdef CONFIG_DT_HAS_ISSI_IS31FL3194_ENABLED
57+
/* IS31FL3194 model registers and values */
4258
#define IS31FL3194_PROD_ID_REG 0x00
4359
#define IS31FL3194_CONF_REG 0x01
4460
#define IS31FL3194_CURRENT_REG 0x03
@@ -54,6 +70,8 @@ struct is31f1319x_model {
5470
#define IS31FL3194_CHANNEL_COUNT 3
5571

5672
static const struct is31f1319x_model is31f13194_model = {
73+
.features = FEATURE_SET_CURRENT,
74+
5775
/* register indexes */
5876
.prod_id_reg = IS31FL3194_PROD_ID_REG,
5977
.shutdown_reg = REG_NOT_DEFINED,
@@ -69,15 +87,46 @@ static const struct is31f1319x_model is31f13194_model = {
6987

7088
/* channel output registers */
7189
.led_channels = {IS31FL3194_OUT1_REG, IS31FL3194_OUT2_REG, IS31FL3194_OUT3_REG}};
90+
#endif
7291

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;
92+
#ifdef CONFIG_DT_HAS_ISSI_IS31FL3197_ENABLED
93+
/* IS31FL3197 model registers and values */
94+
#define IS31FL3197_PROD_ID_REG 0x00
95+
#define IS31FL3197_SHUTDOWN_REG 0x01
96+
#define IS31FL3197_OPER_CONFIG_REG 0x02
97+
#define IS31FL3197_OUT1_REG 0x10
98+
#define IS31FL3197_OUT2_REG 0x11
99+
#define IS31FL3197_OUT3_REG 0x12
100+
#define IS31FL3197_OUT4_REG 0x13
101+
#define IS31FL3197_UPDATE_REG 0x2b
102+
103+
#define IS31FL3197_SHUTDOWN_REG_VAL 0xf1 /* enable all channels */
104+
#define IS31FL3197_OPER_CONFIG_REG_VAL 0xff /* set all to current level */
105+
#define IS31FL3197_UPDATE_VAL 0xc5
106+
107+
#define IS31FL3197_CHANNEL_COUNT 4
108+
109+
static const struct is31f1319x_model is31f13197_model = {
110+
.features = FEATURE_ID_IS_ADDR,
111+
112+
/* register indexes */
113+
.prod_id_reg = IS31FL3197_PROD_ID_REG,
114+
.shutdown_reg = IS31FL3197_SHUTDOWN_REG,
115+
.conf_reg = IS31FL3197_OPER_CONFIG_REG,
116+
.current_reg = REG_NOT_DEFINED,
117+
.update_reg = IS31FL3197_UPDATE_REG,
118+
119+
/* values for those registers */
120+
.prod_id_val = 0xff,
121+
.shutdown_reg_val = IS31FL3197_SHUTDOWN_REG_VAL,
122+
.conf_enable = IS31FL3197_OPER_CONFIG_REG_VAL,
123+
.update_val = IS31FL3197_UPDATE_VAL,
124+
125+
/* channel output registers */
126+
.led_channels = {IS31FL3197_OUT1_REG, IS31FL3197_OUT2_REG, IS31FL3197_OUT3_REG,
127+
IS31FL3197_OUT4_REG}
80128
};
129+
#endif
81130

82131
static const struct led_info *is31fl319x_led_to_info(const struct is31fl319x_config *config,
83132
uint32_t led)
@@ -123,7 +172,7 @@ static int is31fl319x_write_channels(const struct device *dev, uint32_t start_ch
123172
uint32_t num_channels, const uint8_t *buf)
124173
{
125174
const struct is31fl319x_config *config = dev->config;
126-
const struct is31f1319x_model *regs = config->regs;
175+
const struct is31f1319x_model *model = config->model;
127176
int ret;
128177
int i;
129178

@@ -132,7 +181,7 @@ static int is31fl319x_write_channels(const struct device *dev, uint32_t start_ch
132181
}
133182

134183
for (i = 0; i < num_channels; i++) {
135-
ret = i2c_reg_write_byte_dt(&config->bus, regs->led_channels[i + start_channel],
184+
ret = i2c_reg_write_byte_dt(&config->bus, model->led_channels[i + start_channel],
136185
buf[i]);
137186
if (ret != 0) {
138187
break;
@@ -141,8 +190,8 @@ static int is31fl319x_write_channels(const struct device *dev, uint32_t start_ch
141190

142191
if (ret == 0) {
143192
ret = i2c_reg_write_byte_dt(&config->bus,
144-
regs->update_reg,
145-
regs->update_val);
193+
model->update_reg,
194+
model->update_val);
146195
}
147196

148197
if (ret != 0) {
@@ -176,7 +225,7 @@ static int is31fl319x_set_brightness(const struct device *dev, uint32_t led, uin
176225
{
177226
const struct is31fl319x_config *config = dev->config;
178227
const struct led_info *info = is31fl319x_led_to_info(config, led);
179-
const struct is31f1319x_model *regs = config->regs;
228+
const struct is31f1319x_model *model = config->model;
180229
uint8_t channel_start;
181230

182231
int ret = 0;
@@ -194,11 +243,11 @@ static int is31fl319x_set_brightness(const struct device *dev, uint32_t led, uin
194243

195244
channel_start = is31fl319x_map_led_to_start_channel(config, led);
196245

197-
ret = i2c_reg_write_byte_dt(&config->bus, regs->led_channels[channel_start], value);
246+
ret = i2c_reg_write_byte_dt(&config->bus, model->led_channels[channel_start], value);
198247
if (ret == 0) {
199248
ret = i2c_reg_write_byte_dt(&config->bus,
200-
regs->update_reg,
201-
regs->update_val);
249+
model->update_reg,
250+
model->update_val);
202251
}
203252

204253
if (ret != 0) {
@@ -232,8 +281,8 @@ static int is31fl319x_init(const struct device *dev)
232281
{
233282
const struct is31fl319x_config *config = dev->config;
234283
const struct led_info *info = NULL;
235-
const struct is31f1319x_model *regs = config->regs;
236-
int i, j, ret;
284+
const struct is31f1319x_model *model = config->model;
285+
int ret;
237286
uint8_t prod_id, band, channel;
238287
uint8_t current_reg = 0;
239288
int i, j;
@@ -248,20 +297,30 @@ static int is31fl319x_init(const struct device *dev)
248297
return -ENODEV;
249298
}
250299

251-
ret = i2c_reg_read_byte_dt(&config->bus, regs->prod_id_reg, &prod_id);
300+
ret = i2c_reg_read_byte_dt(&config->bus, model->prod_id_reg, &prod_id);
252301
if (ret != 0) {
253302
LOG_ERR("%s: failed to read product ID", dev->name);
254303
return ret;
255304
}
256305

257-
if (prod_id != regs->prod_id_val) {
258-
LOG_ERR("%s: invalid product ID 0x%02x (expected 0x%02x)", dev->name, prod_id,
259-
regs->prod_id_val);
260-
return -ENODEV;
306+
307+
if (model->features & FEATURE_ID_IS_ADDR) {
308+
/* The product ID (8 bit) should be the I2C address(7 bit) */
309+
if (prod_id != (config->bus.addr << 1)) {
310+
LOG_ERR("%s: invalid product ID 0x%02x (expected 0x%02x)", dev->name,
311+
prod_id, config->bus.addr << 1);
312+
return -ENODEV;
313+
}
314+
} else {
315+
if (prod_id != model->prod_id_val) {
316+
LOG_ERR("%s: invalid product ID 0x%02x (expected 0x%02x)", dev->name,
317+
prod_id, model->prod_id_val);
318+
return -ENODEV;
319+
}
261320
}
262321

263322
/* calc current limit register value */
264-
if (regs->current_reg != REG_NOT_DEFINED) {
323+
if (model->features & FEATURE_SET_CURRENT) {
265324
channel = 0;
266325
for (i = 0; i < config->num_leds; i++) {
267326
info = &config->led_infos[i];
@@ -273,15 +332,24 @@ static int is31fl319x_init(const struct device *dev)
273332
}
274333
}
275334

276-
ret = i2c_reg_write_byte_dt(&config->bus, regs->current_reg, current_reg);
335+
ret = i2c_reg_write_byte_dt(&config->bus, model->current_reg, current_reg);
277336
if (ret != 0) {
278337
LOG_ERR("%s: failed to set current limit", dev->name);
279338
return ret;
280339
}
281340
}
341+
if (model->shutdown_reg != REG_NOT_DEFINED) {
342+
ret = i2c_reg_write_byte_dt(&config->bus, model->shutdown_reg,
343+
model->shutdown_reg_val);
344+
if (ret != 0) {
345+
LOG_ERR("%s: failed to set current limit", dev->name);
346+
return ret;
347+
}
348+
}
349+
282350
/* enable device */
283-
return i2c_reg_write_byte_dt(&config->bus, regs->conf_reg,
284-
regs->conf_enable);
351+
return i2c_reg_write_byte_dt(&config->bus, model->conf_reg,
352+
model->conf_enable);
285353
}
286354

287355
static DEVICE_API(led, is31fl319x_led_api) = {
@@ -305,7 +373,7 @@ static DEVICE_API(led, is31fl319x_led_api) = {
305373
#define LED_CURRENT(led_node_id) \
306374
DT_PROP(led_node_id, current_limit),
307375

308-
#define IS31FL319X_DEVICE(n, id, nchannels, pregs) \
376+
#define IS31FL319X_DEVICE(n, id, nchannels, pmodel) \
309377
\
310378
DT_INST_FOREACH_CHILD(n, COLOR_MAPPING) \
311379
\
@@ -323,12 +391,21 @@ static DEVICE_API(led, is31fl319x_led_api) = {
323391
.num_leds = ARRAY_SIZE(is31fl319##id##_leds_##n), \
324392
.led_infos = is31fl319##id##_leds_##n, \
325393
.current_limits = is31fl319##id##_currents_##n, \
326-
.regs = pregs, \
394+
.model = pmodel, \
327395
}; \
328396
DEVICE_DT_INST_DEFINE(n, &is31fl319x_init, NULL, NULL, \
329397
&is31fl319##id##_config_##n, POST_KERNEL, \
330398
CONFIG_LED_INIT_PRIORITY, &is31fl319x_led_api);
331399

400+
#ifdef CONFIG_DT_HAS_ISSI_IS31FL3194_ENABLED
332401
#define DT_DRV_COMPAT issi_is31fl3194
333402
DT_INST_FOREACH_STATUS_OKAY_VARGS(IS31FL319X_DEVICE, 4, IS31FL3194_CHANNEL_COUNT,
334403
&is31f13194_model)
404+
#endif
405+
406+
#ifdef CONFIG_DT_HAS_ISSI_IS31FL3197_ENABLED
407+
#undef DT_DRV_COMPAT
408+
#define DT_DRV_COMPAT issi_is31fl3197
409+
DT_INST_FOREACH_STATUS_OKAY_VARGS(IS31FL319X_DEVICE, 7, IS31FL3197_CHANNEL_COUNT,
410+
&is31f13197_model)
411+
#endif
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,is31fl3197` 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.

0 commit comments

Comments
 (0)