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(char * name)137 static const struct gpio_ctrl *get_gpio_ctrl(char *name)
138 {
139 const struct device *dev = device_get_binding(name);
140 size_t i;
141
142 for (i = 0; i < ARRAY_SIZE(gpio_list); i++) {
143 if (gpio_list[i].dev == dev) {
144 return &gpio_list[i];
145 }
146 }
147 return NULL;
148 }
149
line_cmp(const char * input,const char * line_name)150 int line_cmp(const char *input, const char *line_name)
151 {
152 int i = 0;
153
154 while (true) {
155 if ((input[i] == '_') && (line_name[i] == ' ')) {
156 /* Allow input underscore to match line_name space */
157 } else if (input[i] != line_name[i]) {
158 return (input[i] > line_name[i]) ? 1 : -1;
159 } else if (line_name[i] == '\0') {
160 return 0;
161 }
162 i++;
163 }
164 }
165
get_gpio_pin(const struct shell * sh,const struct gpio_ctrl * ctrl,char * line_name)166 static int get_gpio_pin(const struct shell *sh, const struct gpio_ctrl *ctrl, char *line_name)
167 {
168 gpio_pin_t pin = PIN_NOT_FOUND;
169 gpio_pin_t i;
170 int result;
171
172 for (i = 0; i < ctrl->ngpios; i++) {
173 result = line_cmp(line_name, ctrl->line_names[i]);
174 if (result == 0) {
175 if ((BIT64(i) & ctrl->reserved_mask) != 0) {
176 shell_error(sh, "Reserved pin");
177 return -EACCES;
178 } else if (pin == PIN_NOT_FOUND) {
179 pin = i;
180 } else {
181 shell_error(sh, "Line name ambiguous");
182 return -EFAULT;
183 }
184 }
185 }
186
187 if (pin == PIN_NOT_FOUND) {
188 shell_error(sh, "Line name not found: '%s'", line_name);
189 return -ENOENT;
190 }
191
192 return pin;
193 }
194
get_sh_gpio(const struct shell * sh,char ** argv,struct sh_gpio * gpio)195 static int get_sh_gpio(const struct shell *sh, char **argv, struct sh_gpio *gpio)
196 {
197 const struct gpio_ctrl *ctrl;
198 int ret = 0;
199 int pin;
200
201 ctrl = get_gpio_ctrl(argv[ARGV_DEV]);
202 if (ctrl == NULL) {
203 shell_error(sh, "unknown gpio controller: %s", argv[ARGV_DEV]);
204 return -EINVAL;
205 }
206 gpio->dev = ctrl->dev;
207 pin = shell_strtoul(argv[ARGV_PIN], 0, &ret);
208 if (ret != 0) {
209 pin = get_gpio_pin(sh, ctrl, argv[ARGV_PIN]);
210 if (pin < 0) {
211 return pin;
212 }
213 } else if ((BIT64(pin) & ctrl->reserved_mask) != 0) {
214 shell_error(sh, "Reserved pin");
215 return -EACCES;
216 }
217 gpio->pin = pin;
218
219 return 0;
220 }
221
cmd_gpio_conf(const struct shell * sh,size_t argc,char ** argv,void * data)222 static int cmd_gpio_conf(const struct shell *sh, size_t argc, char **argv, void *data)
223 {
224 gpio_flags_t flags = 0;
225 gpio_flags_t vendor_specific;
226 struct sh_gpio gpio;
227 int ret = 0;
228
229 ret = get_sh_gpio(sh, argv, &gpio);
230 if (ret != 0) {
231 shell_help(sh);
232 return SHELL_CMD_HELP_PRINTED;
233 }
234
235 for (int i = 0; i < strlen(argv[ARGV_CONF]); i++) {
236 switch (argv[ARGV_CONF][i]) {
237 case 'i':
238 flags |= GPIO_INPUT;
239 break;
240 case 'o':
241 flags |= GPIO_OUTPUT;
242 break;
243 case 'u':
244 flags |= GPIO_PULL_UP;
245 break;
246 case 'd':
247 flags |= GPIO_PULL_DOWN;
248 break;
249 case 'h':
250 flags |= GPIO_ACTIVE_HIGH;
251 break;
252 case 'l':
253 flags |= GPIO_ACTIVE_LOW;
254 break;
255 case '0':
256 flags |= GPIO_OUTPUT_INIT_LOGICAL | GPIO_OUTPUT_INIT_LOW;
257 break;
258 case '1':
259 flags |= GPIO_OUTPUT_INIT_LOGICAL | GPIO_OUTPUT_INIT_HIGH;
260 break;
261 default:
262 shell_error(sh, "Unknown: '%c'", argv[ARGV_CONF][i]);
263 shell_help(sh);
264 return SHELL_CMD_HELP_PRINTED;
265 }
266 }
267
268 if (((flags & GPIO_INPUT) != 0) == ((flags & GPIO_OUTPUT) != 0)) {
269 shell_error(sh, "must be either input or output");
270 shell_help(sh);
271 return SHELL_CMD_HELP_PRINTED;
272 }
273
274 if (((flags & GPIO_PULL_UP) != 0) && ((flags & GPIO_PULL_DOWN) != 0)) {
275 shell_error(sh, "cannot be pull up and pull down");
276 shell_help(sh);
277 return SHELL_CMD_HELP_PRINTED;
278 }
279
280 if (((flags & GPIO_ACTIVE_LOW) != 0) && ((flags & GPIO_ACTIVE_HIGH) != 0)) {
281 shell_error(sh, "cannot be active low and active high");
282 shell_help(sh);
283 return SHELL_CMD_HELP_PRINTED;
284 }
285
286 if ((flags & GPIO_OUTPUT) != 0) {
287 /* Default to active high if not specified */
288 if ((flags & (GPIO_ACTIVE_LOW | GPIO_ACTIVE_HIGH)) == 0) {
289 flags |= GPIO_ACTIVE_HIGH;
290 }
291 /* Default to initialisation to logic 0 if not specified */
292 if ((flags & GPIO_OUTPUT_INIT_LOGICAL) == 0) {
293 flags |= GPIO_OUTPUT_INIT_LOGICAL | GPIO_OUTPUT_INIT_LOW;
294 }
295 }
296
297 if (((flags & GPIO_INPUT) != 0) && ((flags & GPIO_OUTPUT_INIT_LOGICAL) != 0)) {
298 shell_error(sh, "an input cannot be initialised to a logic level");
299 shell_help(sh);
300 return SHELL_CMD_HELP_PRINTED;
301 }
302
303 if (((flags & GPIO_OUTPUT_INIT_LOW) != 0) && ((flags & GPIO_OUTPUT_INIT_HIGH) != 0)) {
304 shell_error(sh, "cannot initialise to logic 0 and logic 1");
305 shell_help(sh);
306 return SHELL_CMD_HELP_PRINTED;
307 }
308
309 if (argc == 5) {
310 vendor_specific = shell_strtoul(argv[ARGV_VENDOR_SPECIFIC], 0, &ret);
311 if ((ret == 0) && ((vendor_specific & ~(0xFF00U)) == 0)) {
312 flags |= vendor_specific;
313 } else {
314 /*
315 * See include/zephyr/dt-bindings/gpio/ for the
316 * available flags for your vendor.
317 */
318 shell_error(sh, "vendor specific flags must be within "
319 "the mask 0xFF00");
320 shell_help(sh);
321 return SHELL_CMD_HELP_PRINTED;
322 }
323 }
324
325 ret = gpio_pin_configure(gpio.dev, gpio.pin, flags);
326 if (ret != 0) {
327 shell_error(sh, "error: %d", ret);
328 return ret;
329 }
330
331 return 0;
332 }
333
cmd_gpio_get(const struct shell * sh,size_t argc,char ** argv)334 static int cmd_gpio_get(const struct shell *sh, size_t argc, char **argv)
335 {
336 struct sh_gpio gpio;
337 int value;
338 int ret;
339
340 ret = get_sh_gpio(sh, argv, &gpio);
341 if (ret != 0) {
342 shell_help(sh);
343 return SHELL_CMD_HELP_PRINTED;
344 }
345
346 value = gpio_pin_get(gpio.dev, gpio.pin);
347 if (value >= 0) {
348 shell_print(sh, "%u", value);
349 } else {
350 shell_error(sh, "error: %d", value);
351 return value;
352 }
353
354 return 0;
355 }
356
cmd_gpio_set(const struct shell * sh,size_t argc,char ** argv)357 static int cmd_gpio_set(const struct shell *sh, size_t argc, char **argv)
358 {
359 struct sh_gpio gpio;
360 unsigned long value;
361 int ret = 0;
362
363 ret = get_sh_gpio(sh, argv, &gpio);
364 if (ret != 0) {
365 shell_help(sh);
366 return SHELL_CMD_HELP_PRINTED;
367 }
368
369 value = shell_strtoul(argv[ARGV_VALUE], 0, &ret);
370 if (ret != 0) {
371 shell_help(sh);
372 return SHELL_CMD_HELP_PRINTED;
373 }
374
375 ret = gpio_pin_set(gpio.dev, gpio.pin, value != 0);
376 if (ret != 0) {
377 shell_error(sh, "error: %d", ret);
378 return ret;
379 }
380
381 return 0;
382 }
383
384 /* 500 msec = 1/2 sec */
385 #define SLEEP_TIME_MS 500
386
cmd_gpio_blink(const struct shell * sh,size_t argc,char ** argv)387 static int cmd_gpio_blink(const struct shell *sh, size_t argc, char **argv)
388 {
389 bool msg_one_shot = true;
390 struct sh_gpio gpio;
391 size_t count;
392 char data;
393 int ret;
394
395 ret = get_sh_gpio(sh, argv, &gpio);
396 if (ret != 0) {
397 shell_help(sh);
398 return SHELL_CMD_HELP_PRINTED;
399 }
400
401 /* dummy read to clear any pending input */
402 (void)sh->iface->api->read(sh->iface, &data, sizeof(data), &count);
403
404 while (true) {
405 (void)sh->iface->api->read(sh->iface, &data, sizeof(data), &count);
406 if (count != 0) {
407 break;
408 }
409 ret = gpio_pin_toggle(gpio.dev, gpio.pin);
410 if (ret != 0) {
411 shell_error(sh, "%d", ret);
412 break;
413 } else if (msg_one_shot) {
414 msg_one_shot = false;
415 shell_print(sh, "Hit any key to exit");
416 }
417 k_msleep(SLEEP_TIME_MS);
418 }
419
420 return 0;
421 }
422
device_name_get(size_t idx,struct shell_static_entry * entry)423 static void device_name_get(size_t idx, struct shell_static_entry *entry)
424 {
425 if (idx >= ARRAY_SIZE(gpio_list)) {
426 entry->syntax = NULL;
427 return;
428 }
429
430 entry->syntax = gpio_list[idx].dev->name;
431 entry->handler = NULL;
432 entry->help = "Device";
433 entry->subcmd = gpio_list[idx].subcmd;
434 }
435
436 SHELL_DYNAMIC_CMD_CREATE(sub_gpio_dev, device_name_get);
437
438 struct pin_info {
439 const struct device *dev;
440 bool reserved;
441 gpio_pin_t pin;
442 const char *line_name;
443 };
444
445 struct pin_order_user_data {
446 const struct shell *sh;
447 struct pin_info prev;
448 struct pin_info next;
449 };
450
451 typedef void (*pin_foreach_func_t)(const struct pin_info *info, void *user_data);
452
print_gpio_ctrl_info(const struct shell * sh,const struct gpio_ctrl * ctrl)453 static void print_gpio_ctrl_info(const struct shell *sh, const struct gpio_ctrl *ctrl)
454 {
455 gpio_pin_t pin;
456 bool reserved;
457
458 shell_print(sh, " ngpios: %u", ctrl->ngpios);
459 shell_print(sh, " Reserved pin mask: 0x%08X", ctrl->reserved_mask);
460
461 shell_print(sh, "");
462
463 shell_print(sh, " Reserved Pin Line Name");
464 for (pin = 0; pin < GPIO_MAX_PINS_PER_PORT; pin++) {
465 if ((pin >= ctrl->ngpios) && (pin >= ctrl->line_names_len)) {
466 /* Out of info */
467 break;
468 }
469 reserved = (BIT64(pin) & ctrl->reserved_mask) != 0;
470 shell_print(sh, " %c %2u %s", reserved ? '*' : ' ',
471 pin, ctrl->line_names[pin]);
472 }
473 }
474
foreach_pin(pin_foreach_func_t func,void * user_data)475 static void foreach_pin(pin_foreach_func_t func, void *user_data)
476 {
477 gpio_port_pins_t reserved_mask;
478 struct pin_info info;
479 gpio_pin_t pin;
480 size_t i;
481
482 for (i = 0; i < ARRAY_SIZE(gpio_list); i++) {
483 for (pin = 0; pin < gpio_list[i].ngpios; pin++) {
484 info.dev = gpio_list[i].dev;
485 reserved_mask = gpio_list[i].reserved_mask;
486 info.reserved = (BIT64(pin) & reserved_mask) != 0;
487 info.pin = pin;
488 if (pin < gpio_list[i].line_names_len) {
489 info.line_name = gpio_list[i].line_names[pin];
490 } else {
491 info.line_name = "";
492 }
493 func(&info, user_data);
494 }
495 }
496 }
497
pin_cmp(const struct pin_info * a,const struct pin_info * b)498 static int pin_cmp(const struct pin_info *a, const struct pin_info *b)
499 {
500 int result = strcmp(a->line_name, b->line_name);
501
502 if (result != 0) {
503 return result;
504 }
505 result = strcmp(a->dev->name, b->dev->name);
506 if (result != 0) {
507 return result;
508 }
509 result = (int)a->pin - (int)b->pin;
510
511 return result;
512 }
513
pin_get_next(const struct pin_info * info,void * user_data)514 static void pin_get_next(const struct pin_info *info, void *user_data)
515 {
516 struct pin_order_user_data *data = user_data;
517 int result;
518
519 if (data->prev.line_name != NULL) {
520 result = pin_cmp(info, &data->prev);
521 } else {
522 result = 1;
523 }
524 if (result > 0) {
525 if (data->next.line_name == NULL) {
526 data->next = *info;
527 return;
528 }
529 result = pin_cmp(info, &data->next);
530 if (result < 0) {
531 data->next = *info;
532 }
533 }
534 }
535
pin_ordered(const struct pin_info * info,void * user_data)536 static void pin_ordered(const struct pin_info *info, void *user_data)
537 {
538 struct pin_order_user_data *data = user_data;
539
540 ARG_UNUSED(info);
541
542 foreach_pin(pin_get_next, data);
543
544 shell_print(data->sh, " %-12s %-8c %-16s %2u",
545 data->next.line_name,
546 data->next.reserved ? '*' : ' ',
547 data->next.dev->name,
548 data->next.pin);
549
550 data->prev = data->next;
551 data->next.line_name = NULL;
552 }
553
print_ordered_info(const struct shell * sh)554 static void print_ordered_info(const struct shell *sh)
555 {
556 struct pin_order_user_data data = {0};
557
558 data.sh = sh;
559
560 shell_print(sh, " %-12s %-8s %-16s %-3s",
561 "Line", "Reserved", "Device", "Pin");
562
563 foreach_pin(pin_ordered, &data);
564 }
565
cmd_gpio_info(const struct shell * sh,size_t argc,char ** argv)566 static int cmd_gpio_info(const struct shell *sh, size_t argc, char **argv)
567 {
568 const struct gpio_ctrl *ctrl = get_gpio_ctrl(argv[ARGV_DEV]);
569
570 if (ctrl == NULL) {
571 /* No device specified */
572 print_ordered_info(sh);
573 return 0;
574 }
575
576 print_gpio_ctrl_info(sh, ctrl);
577
578 return 0;
579 }
580
581 SHELL_STATIC_SUBCMD_SET_CREATE(sub_gpio,
582 SHELL_CMD_ARG(conf, &sub_gpio_dev,
583 "Configure GPIO pin\n"
584 "Usage: gpio conf <device> <pin> <configuration <i|o>[u|d][h|l][0|1]> [vendor specific]\n"
585 "<i|o> - input|output\n"
586 "[u|d] - pull up|pull down, otherwise open\n"
587 "[h|l] - active high|active low, otherwise defaults to active high\n"
588 "[0|1] - initialise to logic 0|logic 1, otherwise defaults to logic 0\n"
589 "[vendor specific] - configuration flags within the mask 0xFF00\n"
590 " see include/zephyr/dt-bindings/gpio/",
591 cmd_gpio_conf, 4, 1),
592 SHELL_CMD_ARG(get, &sub_gpio_dev,
593 "Get GPIO pin value\n"
594 "Usage: gpio get <device> <pin>", cmd_gpio_get, 3, 0),
595 SHELL_CMD_ARG(set, &sub_gpio_dev,
596 "Set GPIO pin value\n"
597 "Usage: gpio set <device> <pin> <level 0|1>", cmd_gpio_set, 4, 0),
598 SHELL_COND_CMD_ARG(CONFIG_GPIO_SHELL_BLINK_CMD, blink, &sub_gpio_dev,
599 "Blink GPIO pin\n"
600 "Usage: gpio blink <device> <pin>", cmd_gpio_blink, 3, 0),
601 SHELL_COND_CMD_ARG(CONFIG_GPIO_SHELL_INFO_CMD, info, &sub_gpio_dev,
602 "GPIO Information\n"
603 "Usage: gpio info [device]", cmd_gpio_info, 1, 1),
604 SHELL_SUBCMD_SET_END /* Array terminated. */
605 );
606
607 SHELL_CMD_REGISTER(gpio, &sub_gpio, "GPIO commands", NULL);
608