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 { 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 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 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 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