1 /*
2 * Copyright (c) 2018 Intel Corporation
3 * Copyright (c) 2021 Dennis Ruffer <daruffer@gmail.com>
4 * Copyright (c) 2023 Nick Ward <nix.ward@gmail.com>
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <zephyr/drivers/gpio.h>
10 #include <zephyr/shell/shell.h>
11
12 #include <stdio.h>
13
14 #define ARGV_DEV 1
15 #define ARGV_PIN 2
16 #define ARGV_CONF 3
17 #define ARGV_VALUE 3
18 #define ARGV_VENDOR_SPECIFIC 4
19
20 #define NGPIOS_UNKNOWN -1
21 #define PIN_NOT_FOUND UINT8_MAX
22
23 /* Pin syntax maximum length */
24 #define PIN_SYNTAX_MAX 32
25 #define PIN_NUM_MAX 4
26
27 struct gpio_ctrl {
28 const struct device *dev;
29 int8_t ngpios;
30 gpio_port_pins_t reserved_mask;
31 const char **line_names;
32 uint8_t line_names_len;
33 const union shell_cmd_entry *subcmd;
34 };
35
36 struct sh_gpio {
37 const struct device *dev;
38 gpio_pin_t pin;
39 };
40 /*
41 * Find idx-th pin reference from the set of non reserved
42 * pin numbers and provided line names.
43 */
port_pin_get(gpio_port_pins_t reserved_mask,const char ** line_names,uint8_t line_names_len,size_t idx,struct shell_static_entry * entry)44 static void port_pin_get(gpio_port_pins_t reserved_mask, const char **line_names,
45 uint8_t line_names_len, size_t idx, struct shell_static_entry *entry)
46 {
47 static char pin_syntax[PIN_SYNTAX_MAX];
48 static char pin_num[PIN_NUM_MAX];
49 const char *name;
50 gpio_pin_t pin;
51 bool reserved;
52
53 entry->handler = NULL;
54
55 /* Find allowed numeric pin reference */
56 for (pin = 0; pin < GPIO_MAX_PINS_PER_PORT; pin++) {
57 reserved = ((BIT64(pin) & reserved_mask) != 0);
58 if (!reserved) {
59 if (idx == 0) {
60 break;
61 }
62 idx--;
63 }
64 }
65
66 if (pin < GPIO_MAX_PINS_PER_PORT) {
67 sprintf(pin_num, "%u", pin);
68 if ((pin < line_names_len) && (strlen(line_names[pin]) > 0)) {
69 /* pin can be specified by line name */
70 name = line_names[pin];
71 for (int i = 0; i < (sizeof(pin_syntax) - 1); i++) {
72 /*
73 * For line-name tab completion to work replace any
74 * space characters with '_'.
75 */
76 pin_syntax[i] = (name[i] != ' ') ? name[i] : '_';
77 if (name[i] == '\0') {
78 break;
79 }
80 }
81 pin_syntax[sizeof(pin_syntax) - 1] = '\0';
82 entry->syntax = pin_syntax;
83 entry->help = pin_num;
84 } else {
85 /* fallback to pin specified by pin number */
86 entry->syntax = pin_num;
87 entry->help = NULL;
88 }
89 } else {
90 /* No more pins */
91 entry->syntax = NULL;
92 entry->help = NULL;
93 }
94 }
95
96 #define GPIO_DT_RESERVED_RANGES_NGPIOS_SHELL(node_id) \
97 COND_CODE_1(DT_NODE_HAS_PROP(node_id, ngpios), \
98 (GPIO_DT_RESERVED_RANGES_NGPIOS(node_id, DT_PROP(node_id, ngpios))), \
99 (GPIO_MAX_PINS_PER_PORT))
100
101 #define GPIO_CTRL_PIN_GET_FN(node_id) \
102 static const char *node_id##line_names[] = DT_PROP_OR(node_id, gpio_line_names, {NULL}); \
103 \
104 static void node_id##cmd_gpio_pin_get(size_t idx, struct shell_static_entry *entry); \
105 \
106 SHELL_DYNAMIC_CMD_CREATE(node_id##sub_gpio_pin, node_id##cmd_gpio_pin_get); \
107 \
108 static void node_id##cmd_gpio_pin_get(size_t idx, struct shell_static_entry *entry) \
109 { \
110 gpio_port_pins_t reserved_mask = GPIO_DT_RESERVED_RANGES_NGPIOS_SHELL(node_id); \
111 uint8_t line_names_len = DT_PROP_LEN_OR(node_id, gpio_line_names, 0); \
112 \
113 port_pin_get(reserved_mask, node_id##line_names, line_names_len, idx, entry); \
114 entry->subcmd = NULL; \
115 }
116
117 #define IS_GPIO_CTRL_PIN_GET(node_id) \
118 COND_CODE_1(DT_PROP(node_id, gpio_controller), (GPIO_CTRL_PIN_GET_FN(node_id)), ())
119
120 DT_FOREACH_STATUS_OKAY_NODE(IS_GPIO_CTRL_PIN_GET)
121
122 #define GPIO_CTRL_LIST_ENTRY(node_id) \
123 { \
124 .dev = DEVICE_DT_GET(node_id), \
125 .ngpios = DT_PROP_OR(node_id, ngpios, NGPIOS_UNKNOWN), \
126 .reserved_mask = GPIO_DT_RESERVED_RANGES_NGPIOS_SHELL(node_id), \
127 .line_names = node_id##line_names, \
128 .line_names_len = DT_PROP_LEN_OR(node_id, gpio_line_names, 0), \
129 .subcmd = &node_id##sub_gpio_pin, \
130 },
131
132 #define IS_GPIO_CTRL_LIST(node_id) \
133 COND_CODE_1(DT_PROP(node_id, gpio_controller), (GPIO_CTRL_LIST_ENTRY(node_id)), ())
134
135 static const struct gpio_ctrl gpio_list[] = {DT_FOREACH_STATUS_OKAY_NODE(IS_GPIO_CTRL_LIST)};
136
get_gpio_ctrl(const char * name)137 static const struct gpio_ctrl *get_gpio_ctrl(const char *name)
138 {
139 size_t i;
140 const struct device *dev = shell_device_get_binding(name);
141
142 if (dev == NULL) {
143 return NULL;
144 }
145
146 for (i = 0; i < ARRAY_SIZE(gpio_list); i++) {
147 if (gpio_list[i].dev == dev) {
148 return &gpio_list[i];
149 }
150 }
151
152 return NULL;
153 }
154
line_cmp(const char * input,const char * line_name)155 int line_cmp(const char *input, const char *line_name)
156 {
157 int i = 0;
158
159 while (true) {
160 if ((input[i] == '_') && (line_name[i] == ' ')) {
161 /* Allow input underscore to match line_name space */
162 } else if (input[i] != line_name[i]) {
163 return (input[i] > line_name[i]) ? 1 : -1;
164 } else if (line_name[i] == '\0') {
165 return 0;
166 }
167 i++;
168 }
169 }
170
get_gpio_pin(const struct shell * sh,const struct gpio_ctrl * ctrl,char * line_name)171 static int get_gpio_pin(const struct shell *sh, const struct gpio_ctrl *ctrl, char *line_name)
172 {
173 gpio_pin_t pin = PIN_NOT_FOUND;
174 gpio_pin_t i;
175 int result;
176
177 for (i = 0; i < ctrl->ngpios; i++) {
178 result = line_cmp(line_name, ctrl->line_names[i]);
179 if (result == 0) {
180 if ((BIT64(i) & ctrl->reserved_mask) != 0) {
181 shell_error(sh, "Reserved pin");
182 return -EACCES;
183 } else if (pin == PIN_NOT_FOUND) {
184 pin = i;
185 } else {
186 shell_error(sh, "Line name ambiguous");
187 return -EFAULT;
188 }
189 }
190 }
191
192 if (pin == PIN_NOT_FOUND) {
193 shell_error(sh, "Line name not found: '%s'", line_name);
194 return -ENOENT;
195 }
196
197 return pin;
198 }
199
get_sh_gpio(const struct shell * sh,char ** argv,struct sh_gpio * gpio)200 static int get_sh_gpio(const struct shell *sh, char **argv, struct sh_gpio *gpio)
201 {
202 const struct gpio_ctrl *ctrl;
203 int ret = 0;
204 int pin;
205
206 ctrl = get_gpio_ctrl(argv[ARGV_DEV]);
207 if (ctrl == NULL) {
208 shell_error(sh, "unknown gpio controller: %s", argv[ARGV_DEV]);
209 return -EINVAL;
210 }
211 gpio->dev = ctrl->dev;
212 pin = shell_strtoul(argv[ARGV_PIN], 0, &ret);
213 if (ret != 0) {
214 pin = get_gpio_pin(sh, ctrl, argv[ARGV_PIN]);
215 if (pin < 0) {
216 return pin;
217 }
218 } else if ((BIT64(pin) & ctrl->reserved_mask) != 0) {
219 shell_error(sh, "Reserved pin");
220 return -EACCES;
221 }
222 gpio->pin = pin;
223
224 return 0;
225 }
226
cmd_gpio_conf(const struct shell * sh,size_t argc,char ** argv,void * data)227 static int cmd_gpio_conf(const struct shell *sh, size_t argc, char **argv, void *data)
228 {
229 gpio_flags_t flags = 0;
230 gpio_flags_t vendor_specific;
231 struct sh_gpio gpio;
232 int ret = 0;
233
234 ret = get_sh_gpio(sh, argv, &gpio);
235 if (ret != 0) {
236 shell_help(sh);
237 return SHELL_CMD_HELP_PRINTED;
238 }
239
240 for (int i = 0; i < strlen(argv[ARGV_CONF]); i++) {
241 switch (argv[ARGV_CONF][i]) {
242 case 'i':
243 flags |= GPIO_INPUT;
244 break;
245 case 'o':
246 flags |= GPIO_OUTPUT;
247 break;
248 case 'u':
249 flags |= GPIO_PULL_UP;
250 break;
251 case 'd':
252 flags |= GPIO_PULL_DOWN;
253 break;
254 case 'h':
255 flags |= GPIO_ACTIVE_HIGH;
256 break;
257 case 'l':
258 flags |= GPIO_ACTIVE_LOW;
259 break;
260 case '0':
261 flags |= GPIO_OUTPUT_INIT_LOGICAL | GPIO_OUTPUT_INIT_LOW;
262 break;
263 case '1':
264 flags |= GPIO_OUTPUT_INIT_LOGICAL | GPIO_OUTPUT_INIT_HIGH;
265 break;
266 default:
267 shell_error(sh, "Unknown: '%c'", argv[ARGV_CONF][i]);
268 shell_help(sh);
269 return SHELL_CMD_HELP_PRINTED;
270 }
271 }
272
273 if (((flags & GPIO_INPUT) != 0) == ((flags & GPIO_OUTPUT) != 0)) {
274 shell_error(sh, "must be either input or output");
275 shell_help(sh);
276 return SHELL_CMD_HELP_PRINTED;
277 }
278
279 if (((flags & GPIO_PULL_UP) != 0) && ((flags & GPIO_PULL_DOWN) != 0)) {
280 shell_error(sh, "cannot be pull up and pull down");
281 shell_help(sh);
282 return SHELL_CMD_HELP_PRINTED;
283 }
284
285 if (((flags & GPIO_ACTIVE_LOW) != 0) && ((flags & GPIO_ACTIVE_HIGH) != 0)) {
286 shell_error(sh, "cannot be active low and active high");
287 shell_help(sh);
288 return SHELL_CMD_HELP_PRINTED;
289 }
290
291 if ((flags & GPIO_OUTPUT) != 0) {
292 /* Default to active high if not specified */
293 if ((flags & (GPIO_ACTIVE_LOW | GPIO_ACTIVE_HIGH)) == 0) {
294 flags |= GPIO_ACTIVE_HIGH;
295 }
296 /* Default to initialisation to logic 0 if not specified */
297 if ((flags & GPIO_OUTPUT_INIT_LOGICAL) == 0) {
298 flags |= GPIO_OUTPUT_INIT_LOGICAL | GPIO_OUTPUT_INIT_LOW;
299 }
300 }
301
302 if (((flags & GPIO_INPUT) != 0) && ((flags & GPIO_OUTPUT_INIT_LOGICAL) != 0)) {
303 shell_error(sh, "an input cannot be initialised to a logic level");
304 shell_help(sh);
305 return SHELL_CMD_HELP_PRINTED;
306 }
307
308 if (((flags & GPIO_OUTPUT_INIT_LOW) != 0) && ((flags & GPIO_OUTPUT_INIT_HIGH) != 0)) {
309 shell_error(sh, "cannot initialise to logic 0 and logic 1");
310 shell_help(sh);
311 return SHELL_CMD_HELP_PRINTED;
312 }
313
314 if (argc == 5) {
315 vendor_specific = shell_strtoul(argv[ARGV_VENDOR_SPECIFIC], 0, &ret);
316 if ((ret == 0) && ((vendor_specific & ~(0xFF00U)) == 0)) {
317 flags |= vendor_specific;
318 } else {
319 /*
320 * See include/zephyr/dt-bindings/gpio/ for the
321 * available flags for your vendor.
322 */
323 shell_error(sh, "vendor specific flags must be within "
324 "the mask 0xFF00");
325 shell_help(sh);
326 return SHELL_CMD_HELP_PRINTED;
327 }
328 }
329
330 ret = gpio_pin_configure(gpio.dev, gpio.pin, flags);
331 if (ret != 0) {
332 shell_error(sh, "error: %d", ret);
333 return ret;
334 }
335
336 return 0;
337 }
338
cmd_gpio_get(const struct shell * sh,size_t argc,char ** argv)339 static int cmd_gpio_get(const struct shell *sh, size_t argc, char **argv)
340 {
341 struct sh_gpio gpio;
342 int value;
343 int ret;
344
345 ret = get_sh_gpio(sh, argv, &gpio);
346 if (ret != 0) {
347 shell_help(sh);
348 return SHELL_CMD_HELP_PRINTED;
349 }
350
351 value = gpio_pin_get(gpio.dev, gpio.pin);
352 if (value >= 0) {
353 shell_print(sh, "%u", value);
354 } else {
355 shell_error(sh, "error: %d", value);
356 return value;
357 }
358
359 return 0;
360 }
361
cmd_gpio_set(const struct shell * sh,size_t argc,char ** argv)362 static int cmd_gpio_set(const struct shell *sh, size_t argc, char **argv)
363 {
364 struct sh_gpio gpio;
365 unsigned long value;
366 int ret = 0;
367
368 ret = get_sh_gpio(sh, argv, &gpio);
369 if (ret != 0) {
370 shell_help(sh);
371 return SHELL_CMD_HELP_PRINTED;
372 }
373
374 value = shell_strtoul(argv[ARGV_VALUE], 0, &ret);
375 if (ret != 0) {
376 shell_help(sh);
377 return SHELL_CMD_HELP_PRINTED;
378 }
379
380 ret = gpio_pin_set(gpio.dev, gpio.pin, value != 0);
381 if (ret != 0) {
382 shell_error(sh, "error: %d", ret);
383 return ret;
384 }
385
386 return 0;
387 }
388
cmd_gpio_toggle(const struct shell * sh,size_t argc,char ** argv)389 static int cmd_gpio_toggle(const struct shell *sh, size_t argc, char **argv)
390 {
391 struct sh_gpio gpio;
392 int ret = 0;
393
394 ret = get_sh_gpio(sh, argv, &gpio);
395 if (ret != 0) {
396 shell_help(sh);
397 return SHELL_CMD_HELP_PRINTED;
398 }
399
400 ret = gpio_pin_toggle(gpio.dev, gpio.pin);
401 if (ret != 0) {
402 shell_error(sh, "error: %d", ret);
403 return ret;
404 }
405
406 return 0;
407 }
408
cmd_gpio_devices(const struct shell * sh,size_t argc,char ** argv)409 static int cmd_gpio_devices(const struct shell *sh, size_t argc, char **argv)
410 {
411 size_t i;
412
413 shell_fprintf(sh, SHELL_NORMAL, "%-16s Other names\n", "Device");
414
415 for (i = 0; i < ARRAY_SIZE(gpio_list); i++) {
416 const struct device *dev = gpio_list[i].dev;
417
418 shell_fprintf(sh, SHELL_NORMAL, "%-16s", dev->name);
419
420 #ifdef CONFIG_DEVICE_DT_METADATA
421 const struct device_dt_nodelabels *nl = device_get_dt_nodelabels(dev);
422
423 if (nl != NULL && nl->num_nodelabels > 0) {
424 for (size_t j = 0; j < nl->num_nodelabels; j++) {
425 const char *nodelabel = nl->nodelabels[j];
426
427 shell_fprintf(sh, SHELL_NORMAL, " %s", nodelabel);
428 }
429 }
430 #endif
431
432 shell_fprintf(sh, SHELL_NORMAL, "\n");
433 }
434
435 return 0;
436 }
437
438 /* 500 msec = 1/2 sec */
439 #define SLEEP_TIME_MS 500
440
cmd_gpio_blink(const struct shell * sh,size_t argc,char ** argv)441 static int cmd_gpio_blink(const struct shell *sh, size_t argc, char **argv)
442 {
443 bool msg_one_shot = true;
444 struct sh_gpio gpio;
445 size_t count;
446 char data;
447 int ret;
448
449 ret = get_sh_gpio(sh, argv, &gpio);
450 if (ret != 0) {
451 shell_help(sh);
452 return SHELL_CMD_HELP_PRINTED;
453 }
454
455 /* dummy read to clear any pending input */
456 (void)sh->iface->api->read(sh->iface, &data, sizeof(data), &count);
457
458 while (true) {
459 (void)sh->iface->api->read(sh->iface, &data, sizeof(data), &count);
460 if (count != 0) {
461 break;
462 }
463 ret = gpio_pin_toggle(gpio.dev, gpio.pin);
464 if (ret != 0) {
465 shell_error(sh, "%d", ret);
466 break;
467 } else if (msg_one_shot) {
468 msg_one_shot = false;
469 shell_print(sh, "Hit any key to exit");
470 }
471 k_msleep(SLEEP_TIME_MS);
472 }
473
474 return 0;
475 }
476
device_name_get(size_t idx,struct shell_static_entry * entry)477 static void device_name_get(size_t idx, struct shell_static_entry *entry)
478 {
479 if (idx >= ARRAY_SIZE(gpio_list)) {
480 entry->syntax = NULL;
481 return;
482 }
483
484 entry->syntax = gpio_list[idx].dev->name;
485 entry->handler = NULL;
486 entry->help = "Device";
487 entry->subcmd = gpio_list[idx].subcmd;
488 }
489
490 SHELL_DYNAMIC_CMD_CREATE(sub_gpio_dev, device_name_get);
491
492 struct pin_info {
493 const struct device *dev;
494 bool reserved;
495 gpio_pin_t pin;
496 const char *line_name;
497 };
498
499 struct pin_order_user_data {
500 const struct shell *sh;
501 struct pin_info prev;
502 struct pin_info next;
503 };
504
505 typedef void (*pin_foreach_func_t)(const struct pin_info *info, void *user_data);
506
print_gpio_ctrl_info(const struct shell * sh,const struct gpio_ctrl * ctrl)507 static void print_gpio_ctrl_info(const struct shell *sh, const struct gpio_ctrl *ctrl)
508 {
509 gpio_pin_t pin;
510 bool reserved;
511 const char *line_name;
512
513 shell_print(sh, " ngpios: %u", ctrl->ngpios);
514 shell_print(sh, " Reserved pin mask: 0x%08X", ctrl->reserved_mask);
515
516 shell_print(sh, "");
517
518 shell_print(sh, " Reserved Pin Line Name");
519 for (pin = 0; pin < ctrl->ngpios; pin++) {
520 reserved = (BIT64(pin) & ctrl->reserved_mask) != 0;
521 if (pin < ctrl->line_names_len) {
522 line_name = ctrl->line_names[pin];
523 } else {
524 line_name = "";
525 }
526 shell_print(sh, " %c %2u %s", reserved ? '*' : ' ', pin, line_name);
527 }
528 }
529
foreach_pin(pin_foreach_func_t func,void * user_data)530 static void foreach_pin(pin_foreach_func_t func, void *user_data)
531 {
532 gpio_port_pins_t reserved_mask;
533 struct pin_info info;
534 gpio_pin_t pin;
535 size_t i;
536
537 for (i = 0; i < ARRAY_SIZE(gpio_list); i++) {
538 for (pin = 0; pin < gpio_list[i].ngpios; pin++) {
539 info.dev = gpio_list[i].dev;
540 reserved_mask = gpio_list[i].reserved_mask;
541 info.reserved = (BIT64(pin) & reserved_mask) != 0;
542 info.pin = pin;
543 if (pin < gpio_list[i].line_names_len) {
544 info.line_name = gpio_list[i].line_names[pin];
545 } else {
546 info.line_name = "";
547 }
548 func(&info, user_data);
549 }
550 }
551 }
552
pin_cmp(const struct pin_info * a,const struct pin_info * b)553 static int pin_cmp(const struct pin_info *a, const struct pin_info *b)
554 {
555 int result = strcmp(a->line_name, b->line_name);
556
557 if (result != 0) {
558 return result;
559 }
560 result = strcmp(a->dev->name, b->dev->name);
561 if (result != 0) {
562 return result;
563 }
564 result = (int)a->pin - (int)b->pin;
565
566 return result;
567 }
568
pin_get_next(const struct pin_info * info,void * user_data)569 static void pin_get_next(const struct pin_info *info, void *user_data)
570 {
571 struct pin_order_user_data *data = user_data;
572 int result;
573
574 if (data->prev.line_name != NULL) {
575 result = pin_cmp(info, &data->prev);
576 } else {
577 result = 1;
578 }
579 if (result > 0) {
580 if (data->next.line_name == NULL) {
581 data->next = *info;
582 return;
583 }
584 result = pin_cmp(info, &data->next);
585 if (result < 0) {
586 data->next = *info;
587 }
588 }
589 }
590
pin_ordered(const struct pin_info * info,void * user_data)591 static void pin_ordered(const struct pin_info *info, void *user_data)
592 {
593 struct pin_order_user_data *data = user_data;
594
595 ARG_UNUSED(info);
596
597 foreach_pin(pin_get_next, data);
598
599 shell_print(data->sh, " %-12s %-8c %-16s %2u",
600 data->next.line_name,
601 data->next.reserved ? '*' : ' ',
602 data->next.dev->name,
603 data->next.pin);
604
605 data->prev = data->next;
606 data->next.line_name = NULL;
607 }
608
print_ordered_info(const struct shell * sh)609 static void print_ordered_info(const struct shell *sh)
610 {
611 struct pin_order_user_data data = {0};
612
613 data.sh = sh;
614
615 shell_print(sh, " %-12s %-8s %-16s %-3s",
616 "Line", "Reserved", "Device", "Pin");
617
618 foreach_pin(pin_ordered, &data);
619 }
620
cmd_gpio_info(const struct shell * sh,size_t argc,char ** argv)621 static int cmd_gpio_info(const struct shell *sh, size_t argc, char **argv)
622 {
623 const struct gpio_ctrl *ctrl = get_gpio_ctrl(argv[ARGV_DEV]);
624
625 if (ctrl == NULL) {
626 /* No device specified */
627 print_ordered_info(sh);
628 return 0;
629 }
630
631 print_gpio_ctrl_info(sh, ctrl);
632
633 return 0;
634 }
635
636 SHELL_STATIC_SUBCMD_SET_CREATE(sub_gpio,
637 SHELL_CMD_ARG(conf, &sub_gpio_dev,
638 "Configure GPIO pin\n"
639 "Usage: gpio conf <device> <pin> <configuration <i|o>[u|d][h|l][0|1]> [vendor specific]\n"
640 "<i|o> - input|output\n"
641 "[u|d] - pull up|pull down, otherwise open\n"
642 "[h|l] - active high|active low, otherwise defaults to active high\n"
643 "[0|1] - initialise to logic 0|logic 1, otherwise defaults to logic 0\n"
644 "[vendor specific] - configuration flags within the mask 0xFF00\n"
645 " see include/zephyr/dt-bindings/gpio/",
646 cmd_gpio_conf, 4, 1),
647 SHELL_CMD_ARG(get, &sub_gpio_dev,
648 "Get GPIO pin value\n"
649 "Usage: gpio get <device> <pin>", cmd_gpio_get, 3, 0),
650 SHELL_CMD_ARG(set, &sub_gpio_dev,
651 "Set GPIO pin value\n"
652 "Usage: gpio set <device> <pin> <level 0|1>", cmd_gpio_set, 4, 0),
653 SHELL_COND_CMD_ARG(CONFIG_GPIO_SHELL_TOGGLE_CMD, toggle, &sub_gpio_dev,
654 "Toggle GPIO pin\n"
655 "Usage: gpio toggle <device> <pin>", cmd_gpio_toggle, 3, 0),
656 SHELL_CMD(devices, NULL,
657 "List all GPIO devices\n"
658 "Usage: gpio devices", cmd_gpio_devices),
659 SHELL_COND_CMD_ARG(CONFIG_GPIO_SHELL_BLINK_CMD, blink, &sub_gpio_dev,
660 "Blink GPIO pin\n"
661 "Usage: gpio blink <device> <pin>", cmd_gpio_blink, 3, 0),
662 SHELL_COND_CMD_ARG(CONFIG_GPIO_SHELL_INFO_CMD, info, &sub_gpio_dev,
663 "GPIO Information\n"
664 "Usage: gpio info [device]", cmd_gpio_info, 1, 1),
665 SHELL_SUBCMD_SET_END /* Array terminated. */
666 );
667
668 SHELL_CMD_REGISTER(gpio, &sub_gpio, "GPIO commands", NULL);
669