1 /*
2 * Copyright (c) 2024 Javad Rahimipetroudi <javad.rahimipetroudi@mind.be>
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
rgb_pulse(const struct gpio_dt_spec * led_dev)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
rgb_write_bit(const struct gpio_dt_spec * led_dev,uint8_t data)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
rgb_write_data(const struct gpio_dt_spec * led_dev,uint8_t data)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
tlc59731_led_set_color(const struct device * dev,struct led_rgb * pixel)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
tlc59731_gpio_update_rgb(const struct device * dev,struct led_rgb * pixels,size_t num_pixels)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
tlc59731_length(const struct device * dev)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 DEVICE_API(led_strip, tlc59731_gpio_api) = {
143 .update_rgb = tlc59731_gpio_update_rgb,
144 .length = tlc59731_length,
145 };
146
tlc59731_gpio_init(const struct device * dev)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)
190