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