xref: /openbmc/u-boot/cmd/gpio.c (revision c507d306)
12e192b24SSimon Glass /*
22e192b24SSimon Glass  * Control GPIO pins on the fly
32e192b24SSimon Glass  *
42e192b24SSimon Glass  * Copyright (c) 2008-2011 Analog Devices Inc.
52e192b24SSimon Glass  *
62e192b24SSimon Glass  * Licensed under the GPL-2 or later.
72e192b24SSimon Glass  */
82e192b24SSimon Glass 
92e192b24SSimon Glass #include <common.h>
102e192b24SSimon Glass #include <command.h>
112e192b24SSimon Glass #include <errno.h>
122e192b24SSimon Glass #include <dm.h>
132e192b24SSimon Glass #include <asm/gpio.h>
142e192b24SSimon Glass 
name_to_gpio(const char * name)152e192b24SSimon Glass __weak int name_to_gpio(const char *name)
162e192b24SSimon Glass {
172e192b24SSimon Glass 	return simple_strtoul(name, NULL, 10);
182e192b24SSimon Glass }
192e192b24SSimon Glass 
202e192b24SSimon Glass enum gpio_cmd {
2166f657d1SSimon Glass 	GPIOC_INPUT,
2266f657d1SSimon Glass 	GPIOC_SET,
2366f657d1SSimon Glass 	GPIOC_CLEAR,
2466f657d1SSimon Glass 	GPIOC_TOGGLE,
252e192b24SSimon Glass };
262e192b24SSimon Glass 
272e192b24SSimon Glass #if defined(CONFIG_DM_GPIO) && !defined(gpio_status)
282e192b24SSimon Glass 
292e192b24SSimon Glass /* A few flags used by show_gpio() */
302e192b24SSimon Glass enum {
312e192b24SSimon Glass 	FLAG_SHOW_ALL		= 1 << 0,
322e192b24SSimon Glass 	FLAG_SHOW_BANK		= 1 << 1,
332e192b24SSimon Glass 	FLAG_SHOW_NEWLINE	= 1 << 2,
342e192b24SSimon Glass };
352e192b24SSimon Glass 
gpio_get_description(struct udevice * dev,const char * bank_name,int offset,int * flagsp,bool show_all)362e192b24SSimon Glass static void gpio_get_description(struct udevice *dev, const char *bank_name,
37b8989b53SSimon Glass 				 int offset, int *flagsp, bool show_all)
382e192b24SSimon Glass {
392e192b24SSimon Glass 	char buf[80];
402e192b24SSimon Glass 	int ret;
412e192b24SSimon Glass 
422e192b24SSimon Glass 	ret = gpio_get_function(dev, offset, NULL);
432e192b24SSimon Glass 	if (ret < 0)
442e192b24SSimon Glass 		goto err;
45b8989b53SSimon Glass 	if (!show_all && !(*flagsp & FLAG_SHOW_ALL) && ret == GPIOF_UNUSED)
462e192b24SSimon Glass 		return;
472e192b24SSimon Glass 	if ((*flagsp & FLAG_SHOW_BANK) && bank_name) {
482e192b24SSimon Glass 		if (*flagsp & FLAG_SHOW_NEWLINE) {
492e192b24SSimon Glass 			putc('\n');
502e192b24SSimon Glass 			*flagsp &= ~FLAG_SHOW_NEWLINE;
512e192b24SSimon Glass 		}
522e192b24SSimon Glass 		printf("Bank %s:\n", bank_name);
532e192b24SSimon Glass 		*flagsp &= ~FLAG_SHOW_BANK;
542e192b24SSimon Glass 	}
552e192b24SSimon Glass 
562e192b24SSimon Glass 	ret = gpio_get_status(dev, offset, buf, sizeof(buf));
572e192b24SSimon Glass 	if (ret)
582e192b24SSimon Glass 		goto err;
592e192b24SSimon Glass 
602e192b24SSimon Glass 	printf("%s\n", buf);
612e192b24SSimon Glass 	return;
622e192b24SSimon Glass err:
632e192b24SSimon Glass 	printf("Error %d\n", ret);
642e192b24SSimon Glass }
652e192b24SSimon Glass 
do_gpio_status(bool all,const char * gpio_name)662e192b24SSimon Glass static int do_gpio_status(bool all, const char *gpio_name)
672e192b24SSimon Glass {
682e192b24SSimon Glass 	struct udevice *dev;
692e192b24SSimon Glass 	int banklen;
702e192b24SSimon Glass 	int flags;
712e192b24SSimon Glass 	int ret;
722e192b24SSimon Glass 
732e192b24SSimon Glass 	flags = 0;
742e192b24SSimon Glass 	if (gpio_name && !*gpio_name)
752e192b24SSimon Glass 		gpio_name = NULL;
762e192b24SSimon Glass 	for (ret = uclass_first_device(UCLASS_GPIO, &dev);
772e192b24SSimon Glass 	     dev;
782e192b24SSimon Glass 	     ret = uclass_next_device(&dev)) {
792e192b24SSimon Glass 		const char *bank_name;
802e192b24SSimon Glass 		int num_bits;
812e192b24SSimon Glass 
822e192b24SSimon Glass 		flags |= FLAG_SHOW_BANK;
832e192b24SSimon Glass 		if (all)
842e192b24SSimon Glass 			flags |= FLAG_SHOW_ALL;
852e192b24SSimon Glass 		bank_name = gpio_get_bank_info(dev, &num_bits);
862e192b24SSimon Glass 		if (!num_bits) {
872e192b24SSimon Glass 			debug("GPIO device %s has no bits\n", dev->name);
882e192b24SSimon Glass 			continue;
892e192b24SSimon Glass 		}
902e192b24SSimon Glass 		banklen = bank_name ? strlen(bank_name) : 0;
912e192b24SSimon Glass 
922e192b24SSimon Glass 		if (!gpio_name || !bank_name ||
93*48ca6909SSimon Glass 		    !strncasecmp(gpio_name, bank_name, banklen)) {
942e192b24SSimon Glass 			const char *p = NULL;
952e192b24SSimon Glass 			int offset;
962e192b24SSimon Glass 
972e192b24SSimon Glass 			p = gpio_name + banklen;
982e192b24SSimon Glass 			if (gpio_name && *p) {
992e192b24SSimon Glass 				offset = simple_strtoul(p, NULL, 10);
1002e192b24SSimon Glass 				gpio_get_description(dev, bank_name, offset,
101b8989b53SSimon Glass 						     &flags, true);
1022e192b24SSimon Glass 			} else {
1032e192b24SSimon Glass 				for (offset = 0; offset < num_bits; offset++) {
1042e192b24SSimon Glass 					gpio_get_description(dev, bank_name,
105b8989b53SSimon Glass 						     offset, &flags, false);
1062e192b24SSimon Glass 				}
1072e192b24SSimon Glass 			}
1082e192b24SSimon Glass 		}
1092e192b24SSimon Glass 		/* Add a newline between bank names */
1102e192b24SSimon Glass 		if (!(flags & FLAG_SHOW_BANK))
1112e192b24SSimon Glass 			flags |= FLAG_SHOW_NEWLINE;
1122e192b24SSimon Glass 	}
1132e192b24SSimon Glass 
1142e192b24SSimon Glass 	return ret;
1152e192b24SSimon Glass }
1162e192b24SSimon Glass #endif
1172e192b24SSimon Glass 
do_gpio(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])1182e192b24SSimon Glass static int do_gpio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
1192e192b24SSimon Glass {
1202e192b24SSimon Glass 	unsigned int gpio;
1212e192b24SSimon Glass 	enum gpio_cmd sub_cmd;
122b71bea71SSimon Glass 	int value;
1232e192b24SSimon Glass 	const char *str_cmd, *str_gpio = NULL;
1242e192b24SSimon Glass 	int ret;
1252e192b24SSimon Glass #ifdef CONFIG_DM_GPIO
1262e192b24SSimon Glass 	bool all = false;
1272e192b24SSimon Glass #endif
1282e192b24SSimon Glass 
1292e192b24SSimon Glass 	if (argc < 2)
1302e192b24SSimon Glass  show_usage:
1312e192b24SSimon Glass 		return CMD_RET_USAGE;
1322e192b24SSimon Glass 	str_cmd = argv[1];
1332e192b24SSimon Glass 	argc -= 2;
1342e192b24SSimon Glass 	argv += 2;
1352e192b24SSimon Glass #ifdef CONFIG_DM_GPIO
1362e192b24SSimon Glass 	if (argc > 0 && !strcmp(*argv, "-a")) {
1372e192b24SSimon Glass 		all = true;
1382e192b24SSimon Glass 		argc--;
1392e192b24SSimon Glass 		argv++;
1402e192b24SSimon Glass 	}
1412e192b24SSimon Glass #endif
1422e192b24SSimon Glass 	if (argc > 0)
1432e192b24SSimon Glass 		str_gpio = *argv;
1444c80c53cSSimon Glass 	if (!strncmp(str_cmd, "status", 2)) {
1452e192b24SSimon Glass 		/* Support deprecated gpio_status() */
1462e192b24SSimon Glass #ifdef gpio_status
1472e192b24SSimon Glass 		gpio_status();
1482e192b24SSimon Glass 		return 0;
1492e192b24SSimon Glass #elif defined(CONFIG_DM_GPIO)
1502e192b24SSimon Glass 		return cmd_process_error(cmdtp, do_gpio_status(all, str_gpio));
1512e192b24SSimon Glass #else
1522e192b24SSimon Glass 		goto show_usage;
1532e192b24SSimon Glass #endif
1542e192b24SSimon Glass 	}
1552e192b24SSimon Glass 
1562e192b24SSimon Glass 	if (!str_gpio)
1572e192b24SSimon Glass 		goto show_usage;
1582e192b24SSimon Glass 
1592e192b24SSimon Glass 	/* parse the behavior */
1602e192b24SSimon Glass 	switch (*str_cmd) {
16166f657d1SSimon Glass 	case 'i':
16266f657d1SSimon Glass 		sub_cmd = GPIOC_INPUT;
16366f657d1SSimon Glass 		break;
16466f657d1SSimon Glass 	case 's':
16566f657d1SSimon Glass 		sub_cmd = GPIOC_SET;
16666f657d1SSimon Glass 		break;
16766f657d1SSimon Glass 	case 'c':
16866f657d1SSimon Glass 		sub_cmd = GPIOC_CLEAR;
16966f657d1SSimon Glass 		break;
17066f657d1SSimon Glass 	case 't':
17166f657d1SSimon Glass 		sub_cmd = GPIOC_TOGGLE;
17266f657d1SSimon Glass 		break;
17366f657d1SSimon Glass 	default:
17466f657d1SSimon Glass 		goto show_usage;
1752e192b24SSimon Glass 	}
1762e192b24SSimon Glass 
1772e192b24SSimon Glass #if defined(CONFIG_DM_GPIO)
1782e192b24SSimon Glass 	/*
1792e192b24SSimon Glass 	 * TODO(sjg@chromium.org): For now we must fit into the existing GPIO
1802e192b24SSimon Glass 	 * framework, so we look up the name here and convert it to a GPIO number.
1812e192b24SSimon Glass 	 * Once all GPIO drivers are converted to driver model, we can change the
1822e192b24SSimon Glass 	 * code here to use the GPIO uclass interface instead of the numbered
1832e192b24SSimon Glass 	 * GPIO compatibility layer.
1842e192b24SSimon Glass 	 */
1852e192b24SSimon Glass 	ret = gpio_lookup_name(str_gpio, NULL, NULL, &gpio);
1862e192b24SSimon Glass 	if (ret) {
1872e192b24SSimon Glass 		printf("GPIO: '%s' not found\n", str_gpio);
1882e192b24SSimon Glass 		return cmd_process_error(cmdtp, ret);
1892e192b24SSimon Glass 	}
1902e192b24SSimon Glass #else
1912e192b24SSimon Glass 	/* turn the gpio name into a gpio number */
1922e192b24SSimon Glass 	gpio = name_to_gpio(str_gpio);
1932e192b24SSimon Glass 	if (gpio < 0)
1942e192b24SSimon Glass 		goto show_usage;
1952e192b24SSimon Glass #endif
1962e192b24SSimon Glass 	/* grab the pin before we tweak it */
1972e192b24SSimon Glass 	ret = gpio_request(gpio, "cmd_gpio");
1982e192b24SSimon Glass 	if (ret && ret != -EBUSY) {
1992e192b24SSimon Glass 		printf("gpio: requesting pin %u failed\n", gpio);
2002e192b24SSimon Glass 		return -1;
2012e192b24SSimon Glass 	}
2022e192b24SSimon Glass 
2032e192b24SSimon Glass 	/* finally, let's do it: set direction and exec command */
20466f657d1SSimon Glass 	if (sub_cmd == GPIOC_INPUT) {
2052e192b24SSimon Glass 		gpio_direction_input(gpio);
2062e192b24SSimon Glass 		value = gpio_get_value(gpio);
2072e192b24SSimon Glass 	} else {
2082e192b24SSimon Glass 		switch (sub_cmd) {
20966f657d1SSimon Glass 		case GPIOC_SET:
210b71bea71SSimon Glass 			value = 1;
211b71bea71SSimon Glass 			break;
21266f657d1SSimon Glass 		case GPIOC_CLEAR:
213b71bea71SSimon Glass 			value = 0;
214b71bea71SSimon Glass 			break;
21566f657d1SSimon Glass 		case GPIOC_TOGGLE:
216b71bea71SSimon Glass 			value = gpio_get_value(gpio);
217b71bea71SSimon Glass 			if (!IS_ERR_VALUE(value))
218b71bea71SSimon Glass 				value = !value;
219b71bea71SSimon Glass 			break;
220b71bea71SSimon Glass 		default:
221b71bea71SSimon Glass 			goto show_usage;
2222e192b24SSimon Glass 		}
2232e192b24SSimon Glass 		gpio_direction_output(gpio, value);
2242e192b24SSimon Glass 	}
225b1970013SHeinrich Schuchardt 	printf("gpio: pin %s (gpio %u) value is ", str_gpio, gpio);
226b71bea71SSimon Glass 	if (IS_ERR_VALUE(value))
227b71bea71SSimon Glass 		printf("unknown (ret=%d)\n", value);
228b71bea71SSimon Glass 	else
229b71bea71SSimon Glass 		printf("%d\n", value);
23066f657d1SSimon Glass 	if (sub_cmd != GPIOC_INPUT && !IS_ERR_VALUE(value)) {
231b71bea71SSimon Glass 		int nval = gpio_get_value(gpio);
232b71bea71SSimon Glass 
233b71bea71SSimon Glass 		if (IS_ERR_VALUE(nval))
234b71bea71SSimon Glass 			printf("   Warning: no access to GPIO output value\n");
235b71bea71SSimon Glass 		else if (nval != value)
236b71bea71SSimon Glass 			printf("   Warning: value of pin is still %d\n", nval);
237b71bea71SSimon Glass 	}
2382e192b24SSimon Glass 
2392e192b24SSimon Glass 	if (ret != -EBUSY)
2402e192b24SSimon Glass 		gpio_free(gpio);
2412e192b24SSimon Glass 
2422e192b24SSimon Glass 	return value;
2432e192b24SSimon Glass }
2442e192b24SSimon Glass 
2452e192b24SSimon Glass U_BOOT_CMD(gpio, 4, 0, do_gpio,
2462e192b24SSimon Glass 	   "query and control gpio pins",
2472e192b24SSimon Glass 	   "<input|set|clear|toggle> <pin>\n"
2482e192b24SSimon Glass 	   "    - input/set/clear/toggle the specified pin\n"
2492e192b24SSimon Glass 	   "gpio status [-a] [<bank> | <pin>]  - show [all/claimed] GPIOs");
250