Skip to content

Commit 02298e9

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 0bf39d4 commit 02298e9

File tree

6 files changed

+193
-51
lines changed

6 files changed

+193
-51
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: 110 additions & 36 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,16 +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;
128-
int i;
175+
const struct is31f1319x_model *model = config->model;
176+
int ret = 0;
129177

130178
if ((start_channel + num_channels) > config->channel_count) {
131179
return -ENOTSUP;
132180
}
133181

134-
for (i = 0; i < num_channels; i++) {
135-
ret = i2c_reg_write_byte_dt(&config->bus, regs->led_channels[i + start_channel],
182+
for (int i = 0; i < num_channels; i++) {
183+
ret = i2c_reg_write_byte_dt(&config->bus, model->led_channels[i + start_channel],
136184
buf[i]);
137185
if (ret != 0) {
138186
break;
@@ -141,8 +189,8 @@ static int is31fl319x_write_channels(const struct device *dev, uint32_t start_ch
141189

142190
if (ret == 0) {
143191
ret = i2c_reg_write_byte_dt(&config->bus,
144-
regs->update_reg,
145-
regs->update_val);
192+
model->update_reg,
193+
model->update_val);
146194
}
147195

148196
if (ret != 0) {
@@ -176,7 +224,7 @@ static int is31fl319x_set_brightness(const struct device *dev, uint32_t led, uin
176224
{
177225
const struct is31fl319x_config *config = dev->config;
178226
const struct led_info *info = is31fl319x_led_to_info(config, led);
179-
const struct is31f1319x_model *regs = config->regs;
227+
const struct is31f1319x_model *model = config->model;
180228
uint8_t channel_start;
181229

182230
int ret = 0;
@@ -194,11 +242,11 @@ static int is31fl319x_set_brightness(const struct device *dev, uint32_t led, uin
194242

195243
channel_start = is31fl319x_map_led_to_start_channel(config, led);
196244

197-
ret = i2c_reg_write_byte_dt(&config->bus, regs->led_channels[channel_start], value);
245+
ret = i2c_reg_write_byte_dt(&config->bus, model->led_channels[channel_start], value);
198246
if (ret == 0) {
199247
ret = i2c_reg_write_byte_dt(&config->bus,
200-
regs->update_reg,
201-
regs->update_val);
248+
model->update_reg,
249+
model->update_val);
202250
}
203251

204252
if (ret != 0) {
@@ -213,10 +261,9 @@ static int is31fl319x_check_config(const struct device *dev)
213261
const struct is31fl319x_config *config = dev->config;
214262
const struct led_info *info;
215263
uint8_t rgb_count = 0;
216-
uint8_t i;
217264

218265
/* verify that number of leds defined is not > number of channels */
219-
for (i = 0; i < config->num_leds; i++) {
266+
for (uint8_t i = 0; i < config->num_leds; i++) {
220267
info = &config->led_infos[i];
221268
rgb_count += info->num_colors;
222269
}
@@ -232,11 +279,10 @@ static int is31fl319x_init(const struct device *dev)
232279
{
233280
const struct is31fl319x_config *config = dev->config;
234281
const struct led_info *info = NULL;
235-
const struct is31f1319x_model *regs = config->regs;
236-
int i, j, ret;
282+
const struct is31f1319x_model *model = config->model;
283+
int ret;
237284
uint8_t prod_id, band, channel;
238285
uint8_t current_reg = 0;
239-
int i, j;
240286

241287
ret = is31fl319x_check_config(dev);
242288
if (ret != 0) {
@@ -248,40 +294,59 @@ static int is31fl319x_init(const struct device *dev)
248294
return -ENODEV;
249295
}
250296

251-
ret = i2c_reg_read_byte_dt(&config->bus, regs->prod_id_reg, &prod_id);
297+
ret = i2c_reg_read_byte_dt(&config->bus, model->prod_id_reg, &prod_id);
252298
if (ret != 0) {
253299
LOG_ERR("%s: failed to read product ID", dev->name);
254300
return ret;
255301
}
256302

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

263319
/* calc current limit register value */
264-
if (regs->current_reg != REG_NOT_DEFINED) {
320+
if (model->features & FEATURE_SET_CURRENT) {
265321
channel = 0;
266-
for (i = 0; i < config->num_leds; i++) {
322+
for (int i = 0; i < config->num_leds; i++) {
267323
info = &config->led_infos[i];
268324
band = (config->current_limits[i] / 10) - 1;
269325

270-
for (j = 0; j < info->num_colors; j++) {
326+
for (int j = 0; j < info->num_colors; j++) {
271327
current_reg |= band << (2 * channel);
272328
channel++;
273329
}
274330
}
275331

276-
ret = i2c_reg_write_byte_dt(&config->bus, regs->current_reg, current_reg);
332+
ret = i2c_reg_write_byte_dt(&config->bus, model->current_reg, current_reg);
277333
if (ret != 0) {
278334
LOG_ERR("%s: failed to set current limit", dev->name);
279335
return ret;
280336
}
281337
}
338+
if (model->shutdown_reg != REG_NOT_DEFINED) {
339+
ret = i2c_reg_write_byte_dt(&config->bus, model->shutdown_reg,
340+
model->shutdown_reg_val);
341+
if (ret != 0) {
342+
LOG_ERR("%s: failed to set current limit", dev->name);
343+
return ret;
344+
}
345+
}
346+
282347
/* enable device */
283-
return i2c_reg_write_byte_dt(&config->bus, regs->conf_reg,
284-
regs->conf_enable);
348+
return i2c_reg_write_byte_dt(&config->bus, model->conf_reg,
349+
model->conf_enable);
285350
}
286351

287352
static DEVICE_API(led, is31fl319x_led_api) = {
@@ -305,7 +370,7 @@ static DEVICE_API(led, is31fl319x_led_api) = {
305370
#define LED_CURRENT(led_node_id) \
306371
DT_PROP(led_node_id, current_limit),
307372

308-
#define IS31FL319X_DEVICE(n, id, nchannels, pregs) \
373+
#define IS31FL319X_DEVICE(n, id, nchannels, pmodel) \
309374
\
310375
DT_INST_FOREACH_CHILD(n, COLOR_MAPPING) \
311376
\
@@ -323,12 +388,21 @@ static DEVICE_API(led, is31fl319x_led_api) = {
323388
.num_leds = ARRAY_SIZE(is31fl319##id##_leds_##n), \
324389
.led_infos = is31fl319##id##_leds_##n, \
325390
.current_limits = is31fl319##id##_currents_##n, \
326-
.regs = pregs, \
391+
.model = pmodel, \
327392
}; \
328393
DEVICE_DT_INST_DEFINE(n, &is31fl319x_init, NULL, NULL, \
329394
&is31fl319##id##_config_##n, POST_KERNEL, \
330395
CONFIG_LED_INIT_PRIORITY, &is31fl319x_led_api);
331396

397+
#ifdef CONFIG_DT_HAS_ISSI_IS31FL3194_ENABLED
332398
#define DT_DRV_COMPAT issi_is31fl3194
333399
DT_INST_FOREACH_STATUS_OKAY_VARGS(IS31FL319X_DEVICE, 4, IS31FL3194_CHANNEL_COUNT,
334400
&is31f13194_model)
401+
#endif
402+
403+
#ifdef CONFIG_DT_HAS_ISSI_IS31FL3197_ENABLED
404+
#undef DT_DRV_COMPAT
405+
#define DT_DRV_COMPAT issi_is31fl3197
406+
DT_INST_FOREACH_STATUS_OKAY_VARGS(IS31FL319X_DEVICE, 7, IS31FL3197_CHANNEL_COUNT,
407+
&is31f13197_model)
408+
#endif
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Copyright (c) 2024 Arduino SA
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: |
5+
IS31FL3197 4-channel LED controller with programmable pattern sequencing
6+
7+
Supports single-channel and RGB and maybe RGBW LEDs. For single
8+
channel LEDs.
9+
10+
The following shows configuration for Arduino Giga Display shield
11+
12+
The following defines a single RGB LED in the is31fl3197 DT node:
13+
14+
is31fl3197@50 {
15+
compatible = "issi,is31fl3197";
16+
reg = <0x50>;
17+
18+
led_0 {
19+
label = "RGB LED";
20+
color-mapping =
21+
<LED_COLOR_ID_RED>,
22+
<LED_COLOR_ID_GREEN>,
23+
<LED_COLOR_ID_BLUE>;
24+
};
25+
};
26+
27+
The following example defines three single-channel LEDs in the is31fl3197 DT node:
28+
29+
is31fl3197@50 {
30+
compatible = "issi,is31fl3197";
31+
reg = <0x50>;
32+
33+
led_0 {
34+
label = "RED LED";
35+
color-mapping = <LED_COLOR_ID_RED>;
36+
};
37+
38+
led_1 {
39+
label = "GREEN LED";
40+
color-mapping = <LED_COLOR_ID_GREEN>;
41+
};
42+
43+
led_2 {
44+
label = "BLUE LED";
45+
color-mapping = <LED_COLOR_ID_BLUE>;
46+
};
47+
};
48+
49+
compatible: "issi,is31fl3197"
50+
51+
include: ["i2c-device.yaml", "led-controller.yaml"]
52+
53+
child-binding:
54+
properties:
55+
label:
56+
required: true
57+
58+
color-mapping:
59+
required: true
60+
61+
current-limit:
62+
type: int
63+
default: 10
64+
enum:
65+
- 10
66+
description: |
67+
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.

samples/drivers/led/is31fl319x/sample.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ sample:
33
name: is31fl319x sample
44
tests:
55
sample.drivers.led.is31fl319x:
6-
filter: dt_compat_enabled("issi,is31fl3194")
6+
filter: dt_compat_enabled("issi,is31fl3194") or dt_compat_enabled("issi,is31fl3197")
77
tags: LED
88
depends_on: i2c
99
integration_platforms:

0 commit comments

Comments
 (0)