]> Git Repo - u-boot.git/blame - drivers/led/led-uclass.c
Merge branch 'master' of https://source.denx.de/u-boot/custodians/u-boot-sh
[u-boot.git] / drivers / led / led-uclass.c
CommitLineData
83d290c5 1// SPDX-License-Identifier: GPL-2.0+
5917112c
SG
2/*
3 * Copyright (c) 2015 Google, Inc
4 * Written by Simon Glass <[email protected]>
5917112c
SG
5 */
6
b953ec2b
PD
7#define LOG_CATEGORY UCLASS_LED
8
5917112c
SG
9#include <dm.h>
10#include <errno.h>
11#include <led.h>
d7a435a2 12#include <dm/device-internal.h>
3bf0515a 13#include <dm/lists.h>
5917112c
SG
14#include <dm/root.h>
15#include <dm/uclass-internal.h>
592b6f39
HS
16#include <dt-bindings/leds/common.h>
17
18static const char * const led_colors[LED_COLOR_ID_MAX] = {
19 [LED_COLOR_ID_WHITE] = "white",
20 [LED_COLOR_ID_RED] = "red",
21 [LED_COLOR_ID_GREEN] = "green",
22 [LED_COLOR_ID_BLUE] = "blue",
23 [LED_COLOR_ID_AMBER] = "amber",
24 [LED_COLOR_ID_VIOLET] = "violet",
25 [LED_COLOR_ID_YELLOW] = "yellow",
26 [LED_COLOR_ID_IR] = "ir",
27 [LED_COLOR_ID_MULTI] = "multicolor",
28 [LED_COLOR_ID_RGB] = "rgb",
29 [LED_COLOR_ID_PURPLE] = "purple",
30 [LED_COLOR_ID_ORANGE] = "orange",
31 [LED_COLOR_ID_PINK] = "pink",
32 [LED_COLOR_ID_CYAN] = "cyan",
33 [LED_COLOR_ID_LIME] = "lime",
34};
5917112c 35
3bf0515a
RV
36int led_bind_generic(struct udevice *parent, const char *driver_name)
37{
38 struct udevice *dev;
39 ofnode node;
40 int ret;
41
42 dev_for_each_subnode(node, parent) {
43 ret = device_bind_driver_to_node(parent, driver_name,
44 ofnode_get_name(node),
45 node, &dev);
46 if (ret)
47 return ret;
48 }
49
50 return 0;
51}
52
5917112c
SG
53int led_get_by_label(const char *label, struct udevice **devp)
54{
55 struct udevice *dev;
56 struct uclass *uc;
57 int ret;
58
59 ret = uclass_get(UCLASS_LED, &uc);
60 if (ret)
61 return ret;
62 uclass_foreach_dev(dev, uc) {
caa4daa2 63 struct led_uc_plat *uc_plat = dev_get_uclass_plat(dev);
5917112c 64
fb8a5ffc
SG
65 /* Ignore the top-level LED node */
66 if (uc_plat->label && !strcmp(label, uc_plat->label))
5917112c
SG
67 return uclass_get_device_tail(dev, 0, devp);
68 }
69
fb8a5ffc 70 return -ENODEV;
5917112c
SG
71}
72
ddae9fcd 73int led_set_state(struct udevice *dev, enum led_state_t state)
5917112c
SG
74{
75 struct led_ops *ops = led_get_ops(dev);
76
ddae9fcd 77 if (!ops->set_state)
5917112c
SG
78 return -ENOSYS;
79
b557f55e
MP
80 if (IS_ENABLED(CONFIG_LED_SW_BLINK) &&
81 led_sw_on_state_change(dev, state))
82 return 0;
83
ddae9fcd 84 return ops->set_state(dev, state);
5917112c
SG
85}
86
8f4b6123
SG
87enum led_state_t led_get_state(struct udevice *dev)
88{
89 struct led_ops *ops = led_get_ops(dev);
90
91 if (!ops->get_state)
92 return -ENOSYS;
93
b557f55e
MP
94 if (IS_ENABLED(CONFIG_LED_SW_BLINK) &&
95 led_sw_is_blinking(dev))
96 return LEDST_BLINK;
97
8f4b6123
SG
98 return ops->get_state(dev);
99}
100
53378dac
SG
101int led_set_period(struct udevice *dev, int period_ms)
102{
2a15c676 103#ifdef CONFIG_LED_BLINK
53378dac
SG
104 struct led_ops *ops = led_get_ops(dev);
105
2a15c676
MK
106 if (ops->set_period)
107 return ops->set_period(dev, period_ms);
108#endif
53378dac 109
b557f55e
MP
110 if (IS_ENABLED(CONFIG_LED_SW_BLINK))
111 return led_sw_set_period(dev, period_ms);
112
2a15c676 113 return -ENOSYS;
53378dac 114}
53378dac 115
914fd75a
CM
116#ifdef CONFIG_LED_BOOT
117static int led_boot_get(struct udevice **devp, int *period_ms)
118{
119 struct led_uc_priv *priv;
120 struct uclass *uc;
121 int ret;
122
123 ret = uclass_get(UCLASS_LED, &uc);
124 if (ret)
125 return ret;
126
127 priv = uclass_get_priv(uc);
128 if (!priv->boot_led_label)
129 return -ENOENT;
130
131 if (period_ms)
132 *period_ms = priv->boot_led_period;
133
134 return led_get_by_label(priv->boot_led_label, devp);
135}
136
137int led_boot_on(void)
138{
139 struct udevice *dev;
140 int ret;
141
142 ret = led_boot_get(&dev, NULL);
143 if (ret)
144 return ret;
145
146 return led_set_state(dev, LEDST_ON);
147}
148
149int led_boot_off(void)
150{
151 struct udevice *dev;
152 int ret;
153
154 ret = led_boot_get(&dev, NULL);
155 if (ret)
156 return ret;
157
158 return led_set_state(dev, LEDST_OFF);
159}
160
161#if defined(CONFIG_LED_BLINK) || defined(CONFIG_LED_SW_BLINK)
162int led_boot_blink(void)
163{
164 struct udevice *dev;
165 int period_ms, ret;
166
167 ret = led_boot_get(&dev, &period_ms);
168 if (ret)
169 return ret;
170
171 ret = led_set_period(dev, period_ms);
172 if (ret) {
173 if (ret != -ENOSYS)
174 return ret;
175
176 /* fallback to ON with no set_period and no SW_BLINK */
177 return led_set_state(dev, LEDST_ON);
178 }
179
180 return led_set_state(dev, LEDST_BLINK);
181}
182#endif
183#endif
184
aad8cfa3
CM
185#ifdef CONFIG_LED_ACTIVITY
186static int led_activity_get(struct udevice **devp, int *period_ms)
187{
188 struct led_uc_priv *priv;
189 struct uclass *uc;
190 int ret;
191
192 ret = uclass_get(UCLASS_LED, &uc);
193 if (ret)
194 return ret;
195
196 priv = uclass_get_priv(uc);
197 if (!priv->activity_led_label)
198 return -ENOENT;
199
200 if (period_ms)
201 *period_ms = priv->activity_led_period;
202
203 return led_get_by_label(priv->activity_led_label, devp);
204}
205
206int led_activity_on(void)
207{
208 struct udevice *dev;
209 int ret;
210
211 ret = led_activity_get(&dev, NULL);
212 if (ret)
213 return ret;
214
215 return led_set_state(dev, LEDST_ON);
216}
217
218int led_activity_off(void)
219{
220 struct udevice *dev;
221 int ret;
222
223 ret = led_activity_get(&dev, NULL);
224 if (ret)
225 return ret;
226
227 return led_set_state(dev, LEDST_OFF);
228}
229
230#if defined(CONFIG_LED_BLINK) || defined(CONFIG_LED_SW_BLINK)
231int led_activity_blink(void)
232{
233 struct udevice *dev;
234 int period_ms, ret;
235
236 ret = led_activity_get(&dev, &period_ms);
237 if (ret)
238 return ret;
239
240 ret = led_set_period(dev, period_ms);
241 if (ret) {
242 if (ret != -ENOSYS)
243 return ret;
244
245 /* fallback to ON with no set_period and no SW_BLINK */
246 return led_set_state(dev, LEDST_ON);
247 }
248
249 return led_set_state(dev, LEDST_BLINK);
250}
251#endif
252#endif
253
592b6f39
HS
254static const char *led_get_function_name(struct udevice *dev)
255{
256 struct led_uc_plat *uc_plat;
257 const char *func;
258 u32 color;
259 u32 enumerator;
260 int ret;
261 int cp;
262
263 if (!dev)
264 return NULL;
265
266 uc_plat = dev_get_uclass_plat(dev);
267 if (!uc_plat)
268 return NULL;
269
270 if (uc_plat->label)
271 return uc_plat->label;
272
273 /* Now try to detect function label name */
274 func = dev_read_string(dev, "function");
275 cp = dev_read_u32(dev, "color", &color);
276 if (cp == 0 || func) {
277 ret = dev_read_u32(dev, "function-enumerator", &enumerator);
278 if (!ret) {
279 snprintf(uc_plat->name, LED_MAX_NAME_SIZE,
280 "%s:%s-%d",
281 cp ? "" : led_colors[color],
282 func ? func : "", enumerator);
283 } else {
284 snprintf(uc_plat->name, LED_MAX_NAME_SIZE,
285 "%s:%s",
286 cp ? "" : led_colors[color],
287 func ? func : "");
288 }
289 uc_plat->label = uc_plat->name;
290 }
291
292 return uc_plat->label;
293}
294
295static const char *led_get_label(struct udevice *dev, ofnode node)
69542d06
CM
296{
297 const char *label;
298
299 label = ofnode_read_string(node, "label");
592b6f39
HS
300 if (!label)
301 label = led_get_function_name(dev);
69542d06
CM
302 if (!label && !ofnode_read_string(node, "compatible"))
303 label = ofnode_get_name(node);
304
305 return label;
306}
307
83c63f0d
MV
308static int led_post_bind(struct udevice *dev)
309{
310 struct led_uc_plat *uc_plat = dev_get_uclass_plat(dev);
72675b06 311 const char *default_state;
83c63f0d 312
5bf61f91 313 if (!uc_plat->label)
592b6f39 314 uc_plat->label = led_get_label(dev, dev_ofnode(dev));
83c63f0d 315
72675b06
MV
316 uc_plat->default_state = LEDST_COUNT;
317
318 default_state = dev_read_string(dev, "default-state");
319 if (!default_state)
320 return 0;
321
322 if (!strncmp(default_state, "on", 2))
323 uc_plat->default_state = LEDST_ON;
324 else if (!strncmp(default_state, "off", 3))
325 uc_plat->default_state = LEDST_OFF;
326 else
327 return 0;
328
f15e89ef
MP
329 if (IS_ENABLED(CONFIG_LED_BLINK)) {
330 const char *trigger;
331
332 trigger = dev_read_string(dev, "linux,default-trigger");
333 if (trigger && !strncmp(trigger, "pattern", 7))
334 uc_plat->default_state = LEDST_BLINK;
335 }
336
72675b06
MV
337 /*
338 * In case the LED has default-state DT property, trigger
339 * probe() to configure its default state during startup.
340 */
c438866b
MV
341 dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
342
343 return 0;
72675b06
MV
344}
345
346static int led_post_probe(struct udevice *dev)
347{
348 struct led_uc_plat *uc_plat = dev_get_uclass_plat(dev);
f15e89ef
MP
349 int default_period_ms = 1000;
350 int ret = 0;
351
352 switch (uc_plat->default_state) {
353 case LEDST_ON:
354 case LEDST_OFF:
355 ret = led_set_state(dev, uc_plat->default_state);
356 break;
357 case LEDST_BLINK:
358 ret = led_set_period(dev, default_period_ms);
359 if (!ret)
360 ret = led_set_state(dev, uc_plat->default_state);
361 break;
362 default:
363 break;
364 }
72675b06 365
f15e89ef 366 return ret;
83c63f0d
MV
367}
368
aad8cfa3 369#if defined(CONFIG_LED_BOOT) || defined(CONFIG_LED_ACTIVITY)
914fd75a
CM
370static int led_init(struct uclass *uc)
371{
372 struct led_uc_priv *priv = uclass_get_priv(uc);
69542d06
CM
373 ofnode led_node;
374 int ret;
914fd75a 375
aad8cfa3 376#ifdef CONFIG_LED_BOOT
69542d06
CM
377 ret = ofnode_options_get_by_phandle("boot-led", &led_node);
378 if (!ret)
592b6f39 379 priv->boot_led_label = led_get_label(NULL, led_node);
69542d06 380 priv->boot_led_period = ofnode_options_read_int("boot-led-period-ms", 250);
aad8cfa3
CM
381#endif
382
383#ifdef CONFIG_LED_ACTIVITY
69542d06
CM
384 ret = ofnode_options_get_by_phandle("activity-led", &led_node);
385 if (!ret)
592b6f39 386 priv->activity_led_label = led_get_label(NULL, led_node);
69542d06 387 priv->activity_led_period = ofnode_options_read_int("activity-led-period-ms",
aad8cfa3
CM
388 250);
389#endif
914fd75a
CM
390
391 return 0;
392}
393#endif
394
5917112c
SG
395UCLASS_DRIVER(led) = {
396 .id = UCLASS_LED,
397 .name = "led",
caa4daa2 398 .per_device_plat_auto = sizeof(struct led_uc_plat),
83c63f0d 399 .post_bind = led_post_bind,
72675b06 400 .post_probe = led_post_probe,
aad8cfa3 401#if defined(CONFIG_LED_BOOT) || defined(CONFIG_LED_ACTIVITY)
914fd75a
CM
402 .init = led_init,
403 .priv_auto = sizeof(struct led_uc_priv),
404#endif
5917112c 405};
This page took 0.294278 seconds and 4 git commands to generate.