Skip to content

Commit 9d15f66

Browse files
Javad Rahimipetroudinashif
authored andcommitted
driver: led: add support for TI TLC59731 RGB STRIP controller
TLC59731 is a 3-Channel, 8-Bit, PWM LED Driver with TI Single-Wire interface (EasySet) protocol. Signed-off-by: Javad Rahimipetroudi <[email protected]>
1 parent 1ed9ef4 commit 9d15f66

File tree

5 files changed

+216
-0
lines changed

5 files changed

+216
-0
lines changed

drivers/led_strip/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ zephyr_library_sources_ifdef(CONFIG_WS2812_STRIP_SPI ws2812_spi.c)
99
zephyr_library_sources_ifdef(CONFIG_WS2812_STRIP_I2S ws2812_i2s.c)
1010
zephyr_library_sources_ifdef(CONFIG_WS2812_STRIP_RPI_PICO_PIO ws2812_rpi_pico_pio.c)
1111
zephyr_library_sources_ifdef(CONFIG_TLC5971_STRIP tlc5971.c)
12+
zephyr_library_sources_ifdef(CONFIG_TLC59731_STRIP tlc59731.c)

drivers/led_strip/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,6 @@ source "drivers/led_strip/Kconfig.apa102"
3535

3636
source "drivers/led_strip/Kconfig.tlc5971"
3737

38+
source "drivers/led_strip/Kconfig.tlc59731"
39+
3840
endif # LED_STRIP

drivers/led_strip/Kconfig.tlc59731

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Copyright (c) 2024 Javad Rahimipetroudi <[email protected]>
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config TLC59731_STRIP
5+
bool "TLC59731 LED controller"
6+
default y
7+
depends on DT_HAS_TI_TLC59731_ENABLED
8+
select GPIO
9+
help
10+
Enable driver for the Texas Instruments TLC59731 EasySet LED
11+
controllers.

drivers/led_strip/tlc59731.c

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
/*
2+
* Copyright (c) 2024 Javad Rahimipetroudi <[email protected]>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT ti_tlc59731
8+
9+
/**
10+
* @file
11+
* @brief LED driver for the TLC59731 LED driver.
12+
*
13+
* TLC59731 is a 3-Channel, 8-Bit, PWM LED Driver
14+
* With Single-Wire Interface (EasySet)
15+
*
16+
* The EasySet protocol is based on short pulses and the time between
17+
* them. At least one pulse must be sent every T_CYCLE, which can be
18+
* between 1.67us and 50us. We want to go as fast as possible, but
19+
* delays under 1us don't work very well, so we settle on 5us for the
20+
* cycle time.
21+
* A pulse must be high for at least 14ns. In practice, turning a GPIO on
22+
* and immediately off again already takes longer than that, so no delay
23+
* is needed there.
24+
* A zero is represented by no additional pulses within a cycle.
25+
* A one is represented by an additional pulse between 275ns and 2.5us
26+
* (half a cycle) after the first one. We need at least some delay to get to
27+
* 275ns, but because of the limited granularity of k_busy_wait we use a
28+
* full 1us. After the pulse, we wait an additional T_CYCLE_1 to complete
29+
* the cycle. This time can be slightly shorter because the second pulse
30+
* already closes the cycle.
31+
* Finally we need to keep the line low for T_H0 to complete the address
32+
* for a single chip, and T_H1 to complete the write for all chips.
33+
*/
34+
35+
#include <zephyr/drivers/led_strip.h>
36+
#include <zephyr/drivers/gpio.h>
37+
#include <zephyr/device.h>
38+
#include <zephyr/kernel.h>
39+
40+
#include <zephyr/logging/log.h>
41+
LOG_MODULE_REGISTER(tlc59731, CONFIG_LED_STRIP_LOG_LEVEL);
42+
43+
/* Pulse timing */
44+
#define TLC59731_DELAY 0x01 /* us */
45+
#define TLC59731_T_CYCLE_0 0x04 /* us */
46+
#define TLC59731_T_CYCLE_1 0x01 /* us */
47+
#define TLC59731_T_H0 (4 * TLC59731_T_CYCLE_0)
48+
#define TLC59731_T_H1 (8 * TLC59731_T_CYCLE_0)
49+
/* Threshould levels */
50+
#define TLC59731_HIGH 0x01
51+
#define TLC59731_LOW 0x00
52+
53+
/* Write command */
54+
#define TLC59731_WR 0x3A
55+
56+
struct tlc59731_cfg {
57+
struct gpio_dt_spec sdi_gpio;
58+
size_t length;
59+
};
60+
61+
static inline int rgb_pulse(const struct gpio_dt_spec *led_dev)
62+
{
63+
int fret = 0;
64+
65+
fret = gpio_pin_set_dt(led_dev, TLC59731_HIGH);
66+
if (fret != 0) {
67+
return fret;
68+
}
69+
70+
fret = gpio_pin_set_dt(led_dev, TLC59731_LOW);
71+
if (fret != 0) {
72+
return fret;
73+
}
74+
75+
return fret;
76+
}
77+
78+
static int rgb_write_bit(const struct gpio_dt_spec *led_dev, uint8_t data)
79+
{
80+
rgb_pulse(led_dev);
81+
82+
k_busy_wait(TLC59731_DELAY);
83+
84+
if (data) {
85+
rgb_pulse(led_dev);
86+
k_busy_wait(TLC59731_T_CYCLE_1);
87+
} else {
88+
k_busy_wait(TLC59731_T_CYCLE_0);
89+
}
90+
91+
return 0;
92+
}
93+
94+
static int rgb_write_data(const struct gpio_dt_spec *led_dev, uint8_t data)
95+
{
96+
int8_t idx = 7;
97+
98+
while (idx >= 0) {
99+
rgb_write_bit(led_dev, data & BIT((idx--)));
100+
}
101+
102+
return 0;
103+
}
104+
105+
static int tlc59731_led_set_color(const struct device *dev, struct led_rgb *pixel)
106+
{
107+
108+
const struct tlc59731_cfg *tlc_conf = dev->config;
109+
const struct gpio_dt_spec *led_gpio = &tlc_conf->sdi_gpio;
110+
111+
rgb_write_data(led_gpio, TLC59731_WR);
112+
rgb_write_data(led_gpio, pixel->r);
113+
rgb_write_data(led_gpio, pixel->g);
114+
rgb_write_data(led_gpio, pixel->b);
115+
116+
return 0;
117+
}
118+
119+
static int tlc59731_gpio_update_rgb(const struct device *dev, struct led_rgb *pixels,
120+
size_t num_pixels)
121+
{
122+
size_t i;
123+
int err = 0;
124+
125+
for (i = 0; i < num_pixels; i++) {
126+
err = tlc59731_led_set_color(dev, &pixels[i]);
127+
if (err) {
128+
break;
129+
}
130+
}
131+
132+
return err;
133+
}
134+
135+
static size_t tlc59731_length(const struct device *dev)
136+
{
137+
const struct tlc59731_cfg *config = dev->config;
138+
139+
return config->length;
140+
}
141+
142+
static const struct led_strip_driver_api tlc59731_gpio_api = {
143+
.update_rgb = tlc59731_gpio_update_rgb,
144+
.length = tlc59731_length,
145+
};
146+
147+
static int tlc59731_gpio_init(const struct device *dev)
148+
{
149+
const struct tlc59731_cfg *tlc_conf = dev->config;
150+
const struct gpio_dt_spec *led = &tlc_conf->sdi_gpio;
151+
int err = 0;
152+
153+
if (!device_is_ready(led->port)) {
154+
LOG_ERR("%s: no LEDs found (DT child nodes missing)", dev->name);
155+
err = -ENODEV;
156+
goto scape;
157+
}
158+
159+
err = gpio_pin_configure_dt(led, GPIO_OUTPUT_ACTIVE);
160+
if (err < 0) {
161+
LOG_ERR("%s: Unable to setup SDI port", dev->name);
162+
err = -EIO;
163+
goto scape;
164+
}
165+
166+
err = gpio_pin_set_dt(led, TLC59731_LOW);
167+
if (err < 0) {
168+
LOG_ERR("%s: Unable to set the SDI-GPIO)", dev->name);
169+
err = -EIO;
170+
goto scape;
171+
}
172+
173+
gpio_pin_set_dt(led, TLC59731_HIGH);
174+
gpio_pin_set_dt(led, TLC59731_LOW);
175+
176+
k_busy_wait((TLC59731_DELAY + TLC59731_T_CYCLE_0));
177+
scape:
178+
return err;
179+
}
180+
181+
#define TLC59731_DEVICE(i) \
182+
static struct tlc59731_cfg tlc59731_cfg_##i = { \
183+
.sdi_gpio = GPIO_DT_SPEC_INST_GET(i, gpios), \
184+
.length = DT_INST_PROP(i, chain_length), \
185+
}; \
186+
\
187+
DEVICE_DT_INST_DEFINE(i, tlc59731_gpio_init, NULL, NULL, &tlc59731_cfg_##i, POST_KERNEL, \
188+
CONFIG_LED_STRIP_INIT_PRIORITY, &tlc59731_gpio_api);
189+
DT_INST_FOREACH_STATUS_OKAY(TLC59731_DEVICE)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright (c) 2024 Javad Rahimipetroudi <[email protected]>
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
compatible: "ti,tlc59731"
5+
description: TLC59731 RGB LED Controller
6+
include: [led-strip.yaml]
7+
8+
properties:
9+
gpios:
10+
required: true
11+
type: phandle-array
12+
description: |
13+
GPIO to send command data to the controller.

0 commit comments

Comments
 (0)