Skip to content

Commit ce5812a

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 5297d61 commit ce5812a

File tree

6 files changed

+215
-45
lines changed

6 files changed

+215
-45
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: 110 additions & 33 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,15 +172,15 @@ 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;
127-
int ret;
175+
const struct is31f1319x_model *model = config->model;
176+
int ret = 0;
128177

129178
if ((start_channel + num_channels) > config->channel_count) {
130179
return -ENOTSUP;
131180
}
132181

133182
for (int i = 0; i < num_channels; i++) {
134-
ret = i2c_reg_write_byte_dt(&config->bus, regs->led_channels[i + start_channel],
183+
ret = i2c_reg_write_byte_dt(&config->bus, model->led_channels[i + start_channel],
135184
buf[i]);
136185
if (ret != 0) {
137186
break;
@@ -140,8 +189,8 @@ static int is31fl319x_write_channels(const struct device *dev, uint32_t start_ch
140189

141190
if (ret == 0) {
142191
ret = i2c_reg_write_byte_dt(&config->bus,
143-
regs->update_reg,
144-
regs->update_val);
192+
model->update_reg,
193+
model->update_val);
145194
}
146195

147196
if (ret != 0) {
@@ -174,7 +223,7 @@ static int is31fl319x_set_brightness(const struct device *dev, uint32_t led, uin
174223
{
175224
const struct is31fl319x_config *config = dev->config;
176225
const struct led_info *info = is31fl319x_led_to_info(config, led);
177-
const struct is31f1319x_model *regs = config->regs;
226+
const struct is31f1319x_model *model = config->model;
178227

179228
int ret = 0;
180229

@@ -191,11 +240,11 @@ static int is31fl319x_set_brightness(const struct device *dev, uint32_t led, uin
191240

192241
uint8_t channel_start = is31fl319x_map_led_to_start_channel(config, led);
193242

194-
ret = i2c_reg_write_byte_dt(&config->bus, regs->led_channels[channel_start], value);
243+
ret = i2c_reg_write_byte_dt(&config->bus, model->led_channels[channel_start], value);
195244
if (ret == 0) {
196245
ret = i2c_reg_write_byte_dt(&config->bus,
197-
regs->update_reg,
198-
regs->update_val);
246+
model->update_reg,
247+
model->update_val);
199248
}
200249

201250
if (ret != 0) {
@@ -210,10 +259,9 @@ static int is31fl319x_check_config(const struct device *dev)
210259
const struct is31fl319x_config *config = dev->config;
211260
const struct led_info *info;
212261
uint8_t rgb_count = 0;
213-
uint8_t i;
214262

215263
/* verify that number of leds defined is not > number of channels */
216-
for (i = 0; i < config->num_leds; i++) {
264+
for (int i = 0; i < config->num_leds; i++) {
217265
info = &config->led_infos[i];
218266
rgb_count += info->num_colors;
219267
}
@@ -229,8 +277,8 @@ static int is31fl319x_init(const struct device *dev)
229277
{
230278
const struct is31fl319x_config *config = dev->config;
231279
const struct led_info *info = NULL;
232-
const struct is31f1319x_model *regs = config->regs;
233-
int i, j, ret;
280+
const struct is31f1319x_model *model = config->model;
281+
int ret;
234282
uint8_t prod_id, band, channel;
235283
uint8_t current_reg = 0;
236284

@@ -244,40 +292,59 @@ static int is31fl319x_init(const struct device *dev)
244292
return -ENODEV;
245293
}
246294

247-
ret = i2c_reg_read_byte_dt(&config->bus, regs->prod_id_reg, &prod_id);
295+
ret = i2c_reg_read_byte_dt(&config->bus, model->prod_id_reg, &prod_id);
248296
if (ret != 0) {
249297
LOG_ERR("%s: failed to read product ID", dev->name);
250298
return ret;
251299
}
252300

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;
301+
302+
if (model->features & FEATURE_ID_IS_ADDR) {
303+
/* The product ID (8 bit) should be the I2C address(7 bit) */
304+
if (prod_id != (config->bus.addr << 1)) {
305+
LOG_ERR("%s: invalid product ID 0x%02x (expected 0x%02x)", dev->name,
306+
prod_id, config->bus.addr << 1);
307+
return -ENODEV;
308+
}
309+
} else {
310+
if (prod_id != model->prod_id_val) {
311+
LOG_ERR("%s: invalid product ID 0x%02x (expected 0x%02x)", dev->name,
312+
prod_id, model->prod_id_val);
313+
return -ENODEV;
314+
}
257315
}
258316

259317
/* calc current limit register value */
260-
if (regs->current_reg != REG_NOT_DEFINED) {
318+
if (model->features & FEATURE_SET_CURRENT) {
261319
channel = 0;
262-
for (i = 0; i < config->num_leds; i++) {
320+
for (int i = 0; i < config->num_leds; i++) {
263321
info = &config->led_infos[i];
264322
band = (config->current_limits[i] / 10) - 1;
265323

266-
for (j = 0; j < info->num_colors; j++) {
324+
for (int j = 0; j < info->num_colors; j++) {
267325
current_reg |= band << (2 * channel);
268326
channel++;
269327
}
270328
}
271329

272-
ret = i2c_reg_write_byte_dt(&config->bus, regs->current_reg, current_reg);
330+
ret = i2c_reg_write_byte_dt(&config->bus, model->current_reg, current_reg);
331+
if (ret != 0) {
332+
LOG_ERR("%s: failed to set current limit", dev->name);
333+
return ret;
334+
}
335+
}
336+
if (model->shutdown_reg != REG_NOT_DEFINED) {
337+
ret = i2c_reg_write_byte_dt(&config->bus, model->shutdown_reg,
338+
model->shutdown_reg_val);
273339
if (ret != 0) {
274340
LOG_ERR("%s: failed to set current limit", dev->name);
275341
return ret;
276342
}
277343
}
344+
278345
/* enable device */
279-
return i2c_reg_write_byte_dt(&config->bus, regs->conf_reg,
280-
regs->conf_enable);
346+
return i2c_reg_write_byte_dt(&config->bus, model->conf_reg,
347+
model->conf_enable);
281348
}
282349

283350
static DEVICE_API(led, is31fl319x_led_api) = {
@@ -301,7 +368,7 @@ static DEVICE_API(led, is31fl319x_led_api) = {
301368
#define LED_CURRENT(led_node_id) \
302369
DT_PROP(led_node_id, current_limit),
303370

304-
#define IS31FL319X_DEVICE(n, id, nchannels, pregs) \
371+
#define IS31FL319X_DEVICE(n, id, nchannels, pmodel) \
305372
\
306373
DT_INST_FOREACH_CHILD(n, COLOR_MAPPING) \
307374
\
@@ -319,13 +386,23 @@ static DEVICE_API(led, is31fl319x_led_api) = {
319386
.num_leds = ARRAY_SIZE(is31fl319##id##_leds_##n), \
320387
.led_infos = is31fl319##id##_leds_##n, \
321388
.current_limits = is31fl319##id##_currents_##n, \
322-
.regs = pregs, \
389+
.model = pmodel, \
323390
}; \
324391
DEVICE_DT_INST_DEFINE(n, &is31fl319x_init, NULL, NULL, \
325392
&is31fl319##id##_config_##n, POST_KERNEL, \
326393
CONFIG_LED_INIT_PRIORITY, &is31fl319x_led_api);
327394

328395
#undef DT_DRV_COMPAT
396+
#ifdef CONFIG_DT_HAS_ISSI_IS31FL3194_ENABLED
329397
#define DT_DRV_COMPAT issi_is31fl3194
330398
DT_INST_FOREACH_STATUS_OKAY_VARGS(IS31FL319X_DEVICE, 4, IS31FL3194_CHANNEL_COUNT,
331399
&is31f13194_model)
400+
#endif
401+
402+
#ifdef CONFIG_DT_HAS_ISSI_IS31FL3197_ENABLED
403+
#undef DT_DRV_COMPAT
404+
#define DT_DRV_COMPAT issi_is31fl3197
405+
DT_INST_FOREACH_STATUS_OKAY_VARGS(IS31FL319X_DEVICE, 7, IS31FL3197_CHANNEL_COUNT,
406+
&is31f13197_model)
407+
#endif
408+
#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.

0 commit comments

Comments
 (0)