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