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
15static 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
24enum 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
36static 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
49static 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
74int 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 = dectoul(argv[3], NULL);
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
136U_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