1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2017 Google, Inc
4  * Written by Simon Glass <sjg@chromium.org>
5  */
6 
7 #include <common.h>
8 #include <command.h>
9 #include <dm.h>
10 #include <led.h>
11 #include <dm/uclass-internal.h>
12 
13 #define LED_TOGGLE LEDST_COUNT
14 
15 static const char *const state_label[] = {
16 	[LEDST_OFF]	= "off",
17 	[LEDST_ON]	= "on",
18 	[LEDST_TOGGLE]	= "toggle",
19 #ifdef CONFIG_LED_BLINK
20 	[LEDST_BLINK]	= "blink",
21 #endif
22 };
23 
get_led_cmd(char * var)24 enum led_state_t get_led_cmd(char *var)
25 {
26 	int i;
27 
28 	for (i = 0; i < LEDST_COUNT; i++) {
29 		if (!strncmp(var, state_label[i], strlen(var)))
30 			return i;
31 	}
32 
33 	return -1;
34 }
35 
show_led_state(struct udevice * dev)36 static int show_led_state(struct udevice *dev)
37 {
38 	int ret;
39 
40 	ret = led_get_state(dev);
41 	if (ret >= LEDST_COUNT)
42 		ret = -EINVAL;
43 	if (ret >= 0)
44 		printf("%s\n", state_label[ret]);
45 
46 	return ret;
47 }
48 
list_leds(void)49 static int list_leds(void)
50 {
51 	struct udevice *dev;
52 	int ret;
53 
54 	for (uclass_find_first_device(UCLASS_LED, &dev);
55 	     dev;
56 	     uclass_find_next_device(&dev)) {
57 		struct led_uc_plat *plat = dev_get_uclass_plat(dev);
58 
59 		if (!plat->label)
60 			continue;
61 		printf("%-15s ", plat->label);
62 		if (device_active(dev)) {
63 			ret = show_led_state(dev);
64 			if (ret < 0)
65 				printf("Error %d\n", ret);
66 		} else {
67 			printf("<inactive>\n");
68 		}
69 	}
70 
71 	return 0;
72 }
73 
do_led(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])74 int do_led(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
75 {
76 	enum led_state_t cmd;
77 	const char *led_label;
78 	struct udevice *dev;
79 #ifdef CONFIG_LED_BLINK
80 	int freq_ms = 0;
81 #endif
82 	int ret;
83 
84 	/* Validate arguments */
85 	if (argc < 2)
86 		return CMD_RET_USAGE;
87 	led_label = argv[1];
88 	if (strncmp(led_label, "list", 4) == 0)
89 		return list_leds();
90 
91 	cmd = argc > 2 ? get_led_cmd(argv[2]) : LEDST_COUNT;
92 #ifdef CONFIG_LED_BLINK
93 	if (cmd == LEDST_BLINK) {
94 		if (argc < 4)
95 			return CMD_RET_USAGE;
96 		freq_ms = simple_strtoul(argv[3], NULL, 10);
97 	}
98 #endif
99 	ret = led_get_by_label(led_label, &dev);
100 	if (ret) {
101 		printf("LED '%s' not found (err=%d)\n", led_label, ret);
102 		return CMD_RET_FAILURE;
103 	}
104 	switch (cmd) {
105 	case LEDST_OFF:
106 	case LEDST_ON:
107 	case LEDST_TOGGLE:
108 		ret = led_set_state(dev, cmd);
109 		break;
110 #ifdef CONFIG_LED_BLINK
111 	case LEDST_BLINK:
112 		ret = led_set_period(dev, freq_ms);
113 		if (!ret)
114 			ret = led_set_state(dev, LEDST_BLINK);
115 		break;
116 #endif
117 	case LEDST_COUNT:
118 		printf("LED '%s': ", led_label);
119 		ret = show_led_state(dev);
120 		break;
121 	}
122 	if (ret < 0) {
123 		printf("LED '%s' operation failed (err=%d)\n", led_label, ret);
124 		return CMD_RET_FAILURE;
125 	}
126 
127 	return 0;
128 }
129 
130 #ifdef CONFIG_LED_BLINK
131 #define BLINK "|blink [blink-freq in ms]"
132 #else
133 #define BLINK ""
134 #endif
135 
136 U_BOOT_CMD(
137 	led, 4, 1, do_led,
138 	"manage LEDs",
139 	"<led_label> on|off|toggle" BLINK "\tChange LED state\n"
140 	"led <led_label>\tGet LED state\n"
141 	"led list\t\tshow a list of LEDs"
142 );
143