1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2015 Google, Inc
4  * Written by Simon Glass <sjg@chromium.org>
5  */
6 
7 #define LOG_CATEGORY UCLASS_LED
8 
9 #include <dm.h>
10 #include <errno.h>
11 #include <led.h>
12 #include <dm/device-internal.h>
13 #include <dm/lists.h>
14 #include <dm/root.h>
15 #include <dm/uclass-internal.h>
16 #include <dt-bindings/leds/common.h>
17 
18 static 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 };
35 
led_bind_generic(struct udevice * parent,const char * driver_name)36 int 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 
led_get_by_label(const char * label,struct udevice ** devp)53 int 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) {
63 		struct led_uc_plat *uc_plat = dev_get_uclass_plat(dev);
64 
65 		/* Ignore the top-level LED node */
66 		if (uc_plat->label && !strcmp(label, uc_plat->label))
67 			return uclass_get_device_tail(dev, 0, devp);
68 	}
69 
70 	return -ENODEV;
71 }
72 
led_set_state(struct udevice * dev,enum led_state_t state)73 int led_set_state(struct udevice *dev, enum led_state_t state)
74 {
75 	struct led_ops *ops = led_get_ops(dev);
76 
77 	if (!ops->set_state)
78 		return -ENOSYS;
79 
80 	if (IS_ENABLED(CONFIG_LED_SW_BLINK) &&
81 	    led_sw_on_state_change(dev, state))
82 		return 0;
83 
84 	return ops->set_state(dev, state);
85 }
86 
led_get_state(struct udevice * dev)87 enum 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 
94 	if (IS_ENABLED(CONFIG_LED_SW_BLINK) &&
95 	    led_sw_is_blinking(dev))
96 		return LEDST_BLINK;
97 
98 	return ops->get_state(dev);
99 }
100 
led_set_period(struct udevice * dev,int period_ms)101 int led_set_period(struct udevice *dev, int period_ms)
102 {
103 #ifdef CONFIG_LED_BLINK
104 	struct led_ops *ops = led_get_ops(dev);
105 
106 	if (ops->set_period)
107 		return ops->set_period(dev, period_ms);
108 #endif
109 
110 	if (IS_ENABLED(CONFIG_LED_SW_BLINK))
111 		return led_sw_set_period(dev, period_ms);
112 
113 	return -ENOSYS;
114 }
115 
116 #ifdef CONFIG_LED_BOOT
led_boot_get(struct udevice ** devp,int * period_ms)117 static 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 
led_boot_on(void)137 int 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 
led_boot_off(void)149 int 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)
led_boot_blink(void)162 int 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 
185 #ifdef CONFIG_LED_ACTIVITY
led_activity_get(struct udevice ** devp,int * period_ms)186 static 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 
led_activity_on(void)206 int 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 
led_activity_off(void)218 int 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)
led_activity_blink(void)231 int 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 
led_get_function_name(struct udevice * dev)254 static 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 	/*
277 	 *  prevent coverity scan error CID 541279: (TAINTED_SCALAR)
278 	 *  only check the upper bound. No need to check the lower bound
279 	 *  as color is from type u32 and never can be lower than 0.
280 	 */
281 	if (color >= LED_COLOR_ID_MAX)
282 		cp = -EINVAL;
283 
284 	if (cp == 0 || func) {
285 		ret = dev_read_u32(dev, "function-enumerator", &enumerator);
286 		if (!ret) {
287 			snprintf(uc_plat->name, LED_MAX_NAME_SIZE,
288 				 "%s:%s-%d",
289 				 cp ? "" : led_colors[color],
290 				 func ? func : "", enumerator);
291 		} else {
292 			snprintf(uc_plat->name, LED_MAX_NAME_SIZE,
293 				 "%s:%s",
294 				 cp ? "" : led_colors[color],
295 				 func ? func : "");
296 		}
297 		uc_plat->label = uc_plat->name;
298 	}
299 
300 	return uc_plat->label;
301 }
302 
led_get_label(struct udevice * dev,ofnode node)303 static const char *led_get_label(struct udevice *dev, ofnode node)
304 {
305 	const char *label;
306 
307 	label = ofnode_read_string(node, "label");
308 	if (!label)
309 		label = led_get_function_name(dev);
310 	if (!label && !ofnode_read_string(node, "compatible"))
311 		label = ofnode_get_name(node);
312 
313 	return label;
314 }
315 
led_post_bind(struct udevice * dev)316 static int led_post_bind(struct udevice *dev)
317 {
318 	struct led_uc_plat *uc_plat = dev_get_uclass_plat(dev);
319 	const char *default_state;
320 
321 	if (!uc_plat->label)
322 		uc_plat->label = led_get_label(dev, dev_ofnode(dev));
323 
324 	uc_plat->default_state = LEDST_COUNT;
325 
326 	default_state = dev_read_string(dev, "default-state");
327 	if (!default_state)
328 		return 0;
329 
330 	if (!strncmp(default_state, "on", 2))
331 		uc_plat->default_state = LEDST_ON;
332 	else if (!strncmp(default_state, "off", 3))
333 		uc_plat->default_state = LEDST_OFF;
334 	else
335 		return 0;
336 
337 	if (IS_ENABLED(CONFIG_LED_BLINK)) {
338 		const char *trigger;
339 
340 		trigger = dev_read_string(dev, "linux,default-trigger");
341 		if (trigger && !strncmp(trigger, "pattern", 7))
342 			uc_plat->default_state = LEDST_BLINK;
343 	}
344 
345 	/*
346 	 * In case the LED has default-state DT property, trigger
347 	 * probe() to configure its default state during startup.
348 	 */
349 	dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
350 
351 	return 0;
352 }
353 
led_post_probe(struct udevice * dev)354 static int led_post_probe(struct udevice *dev)
355 {
356 	struct led_uc_plat *uc_plat = dev_get_uclass_plat(dev);
357 	int default_period_ms = 1000;
358 	int ret = 0;
359 
360 	switch (uc_plat->default_state) {
361 	case LEDST_ON:
362 	case LEDST_OFF:
363 		ret = led_set_state(dev, uc_plat->default_state);
364 		break;
365 	case LEDST_BLINK:
366 		ret = led_set_period(dev, default_period_ms);
367 		if (!ret)
368 			ret = led_set_state(dev, uc_plat->default_state);
369 		break;
370 	default:
371 		break;
372 	}
373 
374 	return ret;
375 }
376 
377 #if defined(CONFIG_LED_BOOT) || defined(CONFIG_LED_ACTIVITY)
led_init(struct uclass * uc)378 static int led_init(struct uclass *uc)
379 {
380 	struct led_uc_priv *priv = uclass_get_priv(uc);
381 	ofnode led_node;
382 	int ret;
383 
384 #ifdef CONFIG_LED_BOOT
385 	ret = ofnode_options_get_by_phandle("boot-led", &led_node);
386 	if (!ret)
387 		priv->boot_led_label = led_get_label(NULL, led_node);
388 	priv->boot_led_period = ofnode_options_read_int("boot-led-period-ms", 250);
389 #endif
390 
391 #ifdef CONFIG_LED_ACTIVITY
392 	ret = ofnode_options_get_by_phandle("activity-led", &led_node);
393 	if (!ret)
394 		priv->activity_led_label = led_get_label(NULL, led_node);
395 	priv->activity_led_period = ofnode_options_read_int("activity-led-period-ms",
396 							    250);
397 #endif
398 
399 	return 0;
400 }
401 #endif
402 
403 UCLASS_DRIVER(led) = {
404 	.id		= UCLASS_LED,
405 	.name		= "led",
406 	.per_device_plat_auto	= sizeof(struct led_uc_plat),
407 	.post_bind	= led_post_bind,
408 	.post_probe	= led_post_probe,
409 #if defined(CONFIG_LED_BOOT) || defined(CONFIG_LED_ACTIVITY)
410 	.init		= led_init,
411 	.priv_auto	= sizeof(struct led_uc_priv),
412 #endif
413 };
414