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 		gpio_port_pins_t reserved_mask = GPIO_DT_RESERVED_RANGES_NGPIOS_SHELL(node_id);    \
107 		uint8_t line_names_len = DT_PROP_LEN_OR(node_id, gpio_line_names, 0);              \
108                                                                                                    \
109 		port_pin_get(reserved_mask, node_id##line_names, line_names_len, idx, entry);      \
110 		entry->subcmd = NULL;                                                              \
111 	}                                                                                          \
112                                                                                                    \
113 	SHELL_DYNAMIC_CMD_CREATE(node_id##sub_gpio_pin, node_id##cmd_gpio_pin_get);
114 
115 #define IS_GPIO_CTRL_PIN_GET(node_id)                                                              \
116 	COND_CODE_1(DT_PROP(node_id, gpio_controller), (GPIO_CTRL_PIN_GET_FN(node_id)), ())
117 
118 DT_FOREACH_STATUS_OKAY_NODE(IS_GPIO_CTRL_PIN_GET)
119 
120 #define GPIO_CTRL_LIST_ENTRY(node_id)                                                              \
121 	{                                                                                          \
122 		.dev = DEVICE_DT_GET(node_id),                                                     \
123 		.ngpios = DT_PROP_OR(node_id, ngpios, NGPIOS_UNKNOWN),                             \
124 		.reserved_mask = GPIO_DT_RESERVED_RANGES_NGPIOS_SHELL(node_id),                    \
125 		.line_names = node_id##line_names,                                                 \
126 		.line_names_len = DT_PROP_LEN_OR(node_id, gpio_line_names, 0),                     \
127 		.subcmd = &node_id##sub_gpio_pin,                                                  \
128 	},
129 
130 #define IS_GPIO_CTRL_LIST(node_id)                                                                 \
131 	COND_CODE_1(DT_PROP(node_id, gpio_controller), (GPIO_CTRL_LIST_ENTRY(node_id)), ())
132 
133 static const struct gpio_ctrl gpio_list[] = {DT_FOREACH_STATUS_OKAY_NODE(IS_GPIO_CTRL_LIST)};
134 
get_gpio_ctrl(const char * name)135 static const struct gpio_ctrl *get_gpio_ctrl(const char *name)
136 {
137 	size_t i;
138 	const struct device *dev = shell_device_get_binding(name);
139 
140 	if (dev == NULL) {
141 		return NULL;
142 	}
143 
144 	for (i = 0; i < ARRAY_SIZE(gpio_list); i++) {
145 		if (gpio_list[i].dev == dev) {
146 			return &gpio_list[i];
147 		}
148 	}
149 
150 	return NULL;
151 }
152 
line_cmp(const char * input,const char * line_name)153 static int line_cmp(const char *input, const char *line_name)
154 {
155 	int i = 0;
156 
157 	while (true) {
158 		if ((input[i] == '_') && (line_name[i] == ' ')) {
159 			/* Allow input underscore to match line_name space */
160 		} else if (input[i] != line_name[i]) {
161 			return (input[i] > line_name[i]) ? 1 : -1;
162 		} else if (line_name[i] == '\0') {
163 			return 0;
164 		}
165 		i++;
166 	}
167 }
168 
get_gpio_pin(const struct shell * sh,const struct gpio_ctrl * ctrl,char * line_name)169 static int get_gpio_pin(const struct shell *sh, const struct gpio_ctrl *ctrl, char *line_name)
170 {
171 	gpio_pin_t pin = PIN_NOT_FOUND;
172 	gpio_pin_t i;
173 	int result;
174 
175 	for (i = 0; i < ctrl->ngpios && i < ctrl->line_names_len; i++) {
176 		result = line_cmp(line_name, ctrl->line_names[i]);
177 		if (result == 0) {
178 			if ((BIT64(i) & ctrl->reserved_mask) != 0) {
179 				shell_error(sh, "Reserved pin");
180 				return -EACCES;
181 			} else if (pin == PIN_NOT_FOUND) {
182 				pin = i;
183 			} else {
184 				shell_error(sh, "Line name ambiguous");
185 				return -EFAULT;
186 			}
187 		}
188 	}
189 
190 	if (pin == PIN_NOT_FOUND) {
191 		shell_error(sh, "Line name not found: '%s'", line_name);
192 		return -ENOENT;
193 	}
194 
195 	return pin;
196 }
197 
get_sh_gpio(const struct shell * sh,char ** argv,struct sh_gpio * gpio)198 static int get_sh_gpio(const struct shell *sh, char **argv, struct sh_gpio *gpio)
199 {
200 	const struct gpio_ctrl *ctrl;
201 	int ret = 0;
202 	int pin;
203 
204 	ctrl = get_gpio_ctrl(argv[ARGV_DEV]);
205 	if (ctrl == NULL) {
206 		shell_error(sh, "unknown gpio controller: %s", argv[ARGV_DEV]);
207 		return -EINVAL;
208 	}
209 	gpio->dev = ctrl->dev;
210 	pin = shell_strtoul(argv[ARGV_PIN], 0, &ret);
211 	if (ret != 0) {
212 		pin = get_gpio_pin(sh, ctrl, argv[ARGV_PIN]);
213 		if (pin < 0) {
214 			return pin;
215 		}
216 	} else if ((BIT64(pin) & ctrl->reserved_mask) != 0) {
217 		shell_error(sh, "Reserved pin");
218 		return -EACCES;
219 	}
220 	gpio->pin = pin;
221 
222 	return 0;
223 }
224 
cmd_gpio_conf(const struct shell * sh,size_t argc,char ** argv)225 static int cmd_gpio_conf(const struct shell *sh, size_t argc, char **argv)
226 {
227 	gpio_flags_t flags = 0;
228 	gpio_flags_t vendor_specific;
229 	struct sh_gpio gpio;
230 	int ret;
231 	size_t len;
232 
233 	ret = get_sh_gpio(sh, argv, &gpio);
234 	if (ret != 0) {
235 		shell_help(sh);
236 		return SHELL_CMD_HELP_PRINTED;
237 	}
238 
239 	len = strlen(argv[ARGV_CONF]);
240 	for (int i = 0; i < len; 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;
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;
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 
gpio_device_name(const struct device * dev)477 static const char *gpio_device_name(const struct device *dev)
478 {
479 #ifdef CONFIG_DEVICE_DT_METADATA
480 	const struct device_dt_nodelabels *nl = device_get_dt_nodelabels(dev);
481 
482 	if (nl != NULL && nl->num_nodelabels > 0) {
483 		return nl->nodelabels[0];
484 	}
485 #endif
486 	return dev->name;
487 }
488 
device_name_get(size_t idx,struct shell_static_entry * entry)489 static void device_name_get(size_t idx, struct shell_static_entry *entry)
490 {
491 	const struct device *dev = gpio_list[idx].dev;
492 
493 	if (idx >= ARRAY_SIZE(gpio_list)) {
494 		entry->syntax = NULL;
495 		return;
496 	}
497 
498 	entry->syntax = gpio_device_name(dev);
499 	entry->handler = NULL;
500 	entry->help = "Device";
501 	entry->subcmd = gpio_list[idx].subcmd;
502 }
503 
504 SHELL_DYNAMIC_CMD_CREATE(sub_gpio_dev, device_name_get);
505 
506 struct pin_info {
507 	const struct device *dev;
508 	bool reserved;
509 	gpio_pin_t pin;
510 	const char *line_name;
511 };
512 
513 struct pin_order_user_data {
514 	const struct shell *sh;
515 	struct pin_info prev;
516 	struct pin_info next;
517 };
518 
519 typedef void (*pin_foreach_func_t)(const struct pin_info *info, void *user_data);
520 
print_gpio_ctrl_info(const struct shell * sh,const struct gpio_ctrl * ctrl)521 static void print_gpio_ctrl_info(const struct shell *sh, const struct gpio_ctrl *ctrl)
522 {
523 	gpio_pin_t pin;
524 	bool reserved;
525 	const char *line_name;
526 
527 	shell_print(sh, " ngpios: %u", ctrl->ngpios);
528 	shell_print(sh, " Reserved pin mask: 0x%08X\n", ctrl->reserved_mask);
529 
530 	shell_print(sh, " Reserved  Pin  Line Name");
531 	for (pin = 0; pin < ctrl->ngpios; pin++) {
532 		reserved = (BIT64(pin) & ctrl->reserved_mask) != 0;
533 		if (pin < ctrl->line_names_len) {
534 			line_name = ctrl->line_names[pin];
535 		} else {
536 			line_name = "";
537 		}
538 		shell_print(sh, "     %c     %2u    %s", reserved ? '*' : ' ', pin, line_name);
539 	}
540 }
541 
foreach_pin(pin_foreach_func_t func,void * user_data)542 static void foreach_pin(pin_foreach_func_t func, void *user_data)
543 {
544 	gpio_port_pins_t reserved_mask;
545 	struct pin_info info;
546 	gpio_pin_t pin;
547 	size_t i;
548 
549 	for (i = 0; i < ARRAY_SIZE(gpio_list); i++) {
550 		for (pin = 0; pin < gpio_list[i].ngpios; pin++) {
551 			info.dev = gpio_list[i].dev;
552 			reserved_mask = gpio_list[i].reserved_mask;
553 			info.reserved = (BIT64(pin) & reserved_mask) != 0;
554 			info.pin = pin;
555 			if (pin < gpio_list[i].line_names_len) {
556 				info.line_name = gpio_list[i].line_names[pin];
557 			} else {
558 				info.line_name = "";
559 			}
560 			func(&info, user_data);
561 		}
562 	}
563 }
564 
pin_cmp(const struct pin_info * a,const struct pin_info * b)565 static int pin_cmp(const struct pin_info *a, const struct pin_info *b)
566 {
567 	int result = strcmp(a->line_name, b->line_name);
568 
569 	if (result != 0) {
570 		return result;
571 	}
572 	result = strcmp(a->dev->name, b->dev->name);
573 	if (result != 0) {
574 		return result;
575 	}
576 	result = (int)a->pin - (int)b->pin;
577 
578 	return result;
579 }
580 
pin_get_next(const struct pin_info * info,void * user_data)581 static void pin_get_next(const struct pin_info *info, void *user_data)
582 {
583 	struct pin_order_user_data *data = user_data;
584 	int result;
585 
586 	if (data->prev.line_name != NULL) {
587 		result = pin_cmp(info, &data->prev);
588 	} else {
589 		result = 1;
590 	}
591 	if (result > 0) {
592 		if (data->next.line_name == NULL) {
593 			data->next = *info;
594 			return;
595 		}
596 		result = pin_cmp(info, &data->next);
597 		if (result < 0) {
598 			data->next = *info;
599 		}
600 	}
601 }
602 
pin_ordered(const struct pin_info * info,void * user_data)603 static void pin_ordered(const struct pin_info *info, void *user_data)
604 {
605 	struct pin_order_user_data *data = user_data;
606 
607 	ARG_UNUSED(info);
608 
609 	foreach_pin(pin_get_next, data);
610 
611 	shell_print(data->sh, "   %-12s %-8c %-16s %2u",
612 		    data->next.line_name,
613 		    data->next.reserved ? '*' : ' ',
614 		    gpio_device_name(data->next.dev),
615 		    data->next.pin);
616 
617 	data->prev = data->next;
618 	data->next.line_name = NULL;
619 }
620 
print_ordered_info(const struct shell * sh)621 static void print_ordered_info(const struct shell *sh)
622 {
623 	struct pin_order_user_data data = {0};
624 
625 	data.sh = sh;
626 
627 	shell_print(sh, "  %-12s %-8s %-16s %-3s",
628 		"Line", "Reserved", "Device", "Pin");
629 
630 	foreach_pin(pin_ordered, &data);
631 }
632 
cmd_gpio_info(const struct shell * sh,size_t argc,char ** argv)633 static int cmd_gpio_info(const struct shell *sh, size_t argc, char **argv)
634 {
635 	const struct gpio_ctrl *ctrl = get_gpio_ctrl(argv[ARGV_DEV]);
636 
637 	if (ctrl == NULL) {
638 		/* No device specified */
639 		print_ordered_info(sh);
640 		return 0;
641 	}
642 
643 	print_gpio_ctrl_info(sh, ctrl);
644 
645 	return 0;
646 }
647 
648 SHELL_STATIC_SUBCMD_SET_CREATE(sub_gpio,
649 	SHELL_CMD_ARG(conf, &sub_gpio_dev,
650 		"Configure GPIO pin\n"
651 		"Usage: gpio conf <device> <pin> <configuration <i|o>[u|d][h|l][0|1]> [vendor specific]\n"
652 		"<i|o> - input|output\n"
653 		"[u|d] - pull up|pull down, otherwise open\n"
654 		"[h|l] - active high|active low, otherwise defaults to active high\n"
655 		"[0|1] - initialise to logic 0|logic 1, otherwise defaults to logic 0\n"
656 		"[vendor specific] - configuration flags within the mask 0xFF00\n"
657 		"                    see include/zephyr/dt-bindings/gpio/",
658 		cmd_gpio_conf, 4, 1),
659 	SHELL_CMD_ARG(get, &sub_gpio_dev,
660 		"Get GPIO pin value\n"
661 		"Usage: gpio get <device> <pin>", cmd_gpio_get, 3, 0),
662 	SHELL_CMD_ARG(set, &sub_gpio_dev,
663 		"Set GPIO pin value\n"
664 		"Usage: gpio set <device> <pin> <level 0|1>", cmd_gpio_set, 4, 0),
665 	SHELL_COND_CMD_ARG(CONFIG_GPIO_SHELL_TOGGLE_CMD, toggle, &sub_gpio_dev,
666 		"Toggle GPIO pin\n"
667 		"Usage: gpio toggle <device> <pin>", cmd_gpio_toggle, 3, 0),
668 	SHELL_CMD(devices, NULL,
669 		"List all GPIO devices\n"
670 		"Usage: gpio devices", cmd_gpio_devices),
671 	SHELL_COND_CMD_ARG(CONFIG_GPIO_SHELL_BLINK_CMD, blink, &sub_gpio_dev,
672 		"Blink GPIO pin\n"
673 		"Usage: gpio blink <device> <pin>", cmd_gpio_blink, 3, 0),
674 	SHELL_COND_CMD_ARG(CONFIG_GPIO_SHELL_INFO_CMD, info, &sub_gpio_dev,
675 		"GPIO Information\n"
676 		"Usage: gpio info [device]", cmd_gpio_info, 1, 1),
677 	SHELL_SUBCMD_SET_END /* Array terminated. */
678 );
679 
680 SHELL_CMD_REGISTER(gpio, &sub_gpio, "GPIO commands", NULL);
681