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