xref: /rk3399_rockchip-uboot/cmd/gpio.c (revision 4c80c53c00ac6583f22938fc98e4df688acdf4ce)
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 
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 {
212e192b24SSimon Glass 	GPIO_INPUT,
222e192b24SSimon Glass 	GPIO_SET,
232e192b24SSimon Glass 	GPIO_CLEAR,
242e192b24SSimon Glass 	GPIO_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 
362e192b24SSimon Glass static void gpio_get_description(struct udevice *dev, const char *bank_name,
372e192b24SSimon Glass 				 int offset, int *flagsp)
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;
452e192b24SSimon Glass 	if (!(*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 
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 ||
932e192b24SSimon Glass 		    !strncmp(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,
1012e192b24SSimon Glass 						     &flags);
1022e192b24SSimon Glass 			} else {
1032e192b24SSimon Glass 				for (offset = 0; offset < num_bits; offset++) {
1042e192b24SSimon Glass 					gpio_get_description(dev, bank_name,
1052e192b24SSimon Glass 							     offset, &flags);
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 
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;
1222e192b24SSimon Glass 	ulong 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;
144*4c80c53cSSimon 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) {
1612e192b24SSimon Glass 		case 'i': sub_cmd = GPIO_INPUT;  break;
1622e192b24SSimon Glass 		case 's': sub_cmd = GPIO_SET;    break;
1632e192b24SSimon Glass 		case 'c': sub_cmd = GPIO_CLEAR;  break;
1642e192b24SSimon Glass 		case 't': sub_cmd = GPIO_TOGGLE; break;
1652e192b24SSimon Glass 		default:  goto show_usage;
1662e192b24SSimon Glass 	}
1672e192b24SSimon Glass 
1682e192b24SSimon Glass #if defined(CONFIG_DM_GPIO)
1692e192b24SSimon Glass 	/*
1702e192b24SSimon Glass 	 * TODO(sjg@chromium.org): For now we must fit into the existing GPIO
1712e192b24SSimon Glass 	 * framework, so we look up the name here and convert it to a GPIO number.
1722e192b24SSimon Glass 	 * Once all GPIO drivers are converted to driver model, we can change the
1732e192b24SSimon Glass 	 * code here to use the GPIO uclass interface instead of the numbered
1742e192b24SSimon Glass 	 * GPIO compatibility layer.
1752e192b24SSimon Glass 	 */
1762e192b24SSimon Glass 	ret = gpio_lookup_name(str_gpio, NULL, NULL, &gpio);
1772e192b24SSimon Glass 	if (ret) {
1782e192b24SSimon Glass 		printf("GPIO: '%s' not found\n", str_gpio);
1792e192b24SSimon Glass 		return cmd_process_error(cmdtp, ret);
1802e192b24SSimon Glass 	}
1812e192b24SSimon Glass #else
1822e192b24SSimon Glass 	/* turn the gpio name into a gpio number */
1832e192b24SSimon Glass 	gpio = name_to_gpio(str_gpio);
1842e192b24SSimon Glass 	if (gpio < 0)
1852e192b24SSimon Glass 		goto show_usage;
1862e192b24SSimon Glass #endif
1872e192b24SSimon Glass 	/* grab the pin before we tweak it */
1882e192b24SSimon Glass 	ret = gpio_request(gpio, "cmd_gpio");
1892e192b24SSimon Glass 	if (ret && ret != -EBUSY) {
1902e192b24SSimon Glass 		printf("gpio: requesting pin %u failed\n", gpio);
1912e192b24SSimon Glass 		return -1;
1922e192b24SSimon Glass 	}
1932e192b24SSimon Glass 
1942e192b24SSimon Glass 	/* finally, let's do it: set direction and exec command */
1952e192b24SSimon Glass 	if (sub_cmd == GPIO_INPUT) {
1962e192b24SSimon Glass 		gpio_direction_input(gpio);
1972e192b24SSimon Glass 		value = gpio_get_value(gpio);
1982e192b24SSimon Glass 	} else {
1992e192b24SSimon Glass 		switch (sub_cmd) {
2002e192b24SSimon Glass 			case GPIO_SET:    value = 1; break;
2012e192b24SSimon Glass 			case GPIO_CLEAR:  value = 0; break;
2022e192b24SSimon Glass 			case GPIO_TOGGLE: value = !gpio_get_value(gpio); break;
2032e192b24SSimon Glass 			default:          goto show_usage;
2042e192b24SSimon Glass 		}
2052e192b24SSimon Glass 		gpio_direction_output(gpio, value);
2062e192b24SSimon Glass 	}
2072e192b24SSimon Glass 	printf("gpio: pin %s (gpio %i) value is %lu\n",
2082e192b24SSimon Glass 		str_gpio, gpio, value);
2092e192b24SSimon Glass 
2102e192b24SSimon Glass 	if (ret != -EBUSY)
2112e192b24SSimon Glass 		gpio_free(gpio);
2122e192b24SSimon Glass 
2132e192b24SSimon Glass 	return value;
2142e192b24SSimon Glass }
2152e192b24SSimon Glass 
2162e192b24SSimon Glass U_BOOT_CMD(gpio, 4, 0, do_gpio,
2172e192b24SSimon Glass 	   "query and control gpio pins",
2182e192b24SSimon Glass 	   "<input|set|clear|toggle> <pin>\n"
2192e192b24SSimon Glass 	   "    - input/set/clear/toggle the specified pin\n"
2202e192b24SSimon Glass 	   "gpio status [-a] [<bank> | <pin>]  - show [all/claimed] GPIOs");
221