1*2e192b24SSimon Glass /* 2*2e192b24SSimon Glass * Control GPIO pins on the fly 3*2e192b24SSimon Glass * 4*2e192b24SSimon Glass * Copyright (c) 2008-2011 Analog Devices Inc. 5*2e192b24SSimon Glass * 6*2e192b24SSimon Glass * Licensed under the GPL-2 or later. 7*2e192b24SSimon Glass */ 8*2e192b24SSimon Glass 9*2e192b24SSimon Glass #include <common.h> 10*2e192b24SSimon Glass #include <command.h> 11*2e192b24SSimon Glass #include <errno.h> 12*2e192b24SSimon Glass #include <dm.h> 13*2e192b24SSimon Glass #include <asm/gpio.h> 14*2e192b24SSimon Glass 15*2e192b24SSimon Glass __weak int name_to_gpio(const char *name) 16*2e192b24SSimon Glass { 17*2e192b24SSimon Glass return simple_strtoul(name, NULL, 10); 18*2e192b24SSimon Glass } 19*2e192b24SSimon Glass 20*2e192b24SSimon Glass enum gpio_cmd { 21*2e192b24SSimon Glass GPIO_INPUT, 22*2e192b24SSimon Glass GPIO_SET, 23*2e192b24SSimon Glass GPIO_CLEAR, 24*2e192b24SSimon Glass GPIO_TOGGLE, 25*2e192b24SSimon Glass }; 26*2e192b24SSimon Glass 27*2e192b24SSimon Glass #if defined(CONFIG_DM_GPIO) && !defined(gpio_status) 28*2e192b24SSimon Glass 29*2e192b24SSimon Glass /* A few flags used by show_gpio() */ 30*2e192b24SSimon Glass enum { 31*2e192b24SSimon Glass FLAG_SHOW_ALL = 1 << 0, 32*2e192b24SSimon Glass FLAG_SHOW_BANK = 1 << 1, 33*2e192b24SSimon Glass FLAG_SHOW_NEWLINE = 1 << 2, 34*2e192b24SSimon Glass }; 35*2e192b24SSimon Glass 36*2e192b24SSimon Glass static void gpio_get_description(struct udevice *dev, const char *bank_name, 37*2e192b24SSimon Glass int offset, int *flagsp) 38*2e192b24SSimon Glass { 39*2e192b24SSimon Glass char buf[80]; 40*2e192b24SSimon Glass int ret; 41*2e192b24SSimon Glass 42*2e192b24SSimon Glass ret = gpio_get_function(dev, offset, NULL); 43*2e192b24SSimon Glass if (ret < 0) 44*2e192b24SSimon Glass goto err; 45*2e192b24SSimon Glass if (!(*flagsp & FLAG_SHOW_ALL) && ret == GPIOF_UNUSED) 46*2e192b24SSimon Glass return; 47*2e192b24SSimon Glass if ((*flagsp & FLAG_SHOW_BANK) && bank_name) { 48*2e192b24SSimon Glass if (*flagsp & FLAG_SHOW_NEWLINE) { 49*2e192b24SSimon Glass putc('\n'); 50*2e192b24SSimon Glass *flagsp &= ~FLAG_SHOW_NEWLINE; 51*2e192b24SSimon Glass } 52*2e192b24SSimon Glass printf("Bank %s:\n", bank_name); 53*2e192b24SSimon Glass *flagsp &= ~FLAG_SHOW_BANK; 54*2e192b24SSimon Glass } 55*2e192b24SSimon Glass 56*2e192b24SSimon Glass ret = gpio_get_status(dev, offset, buf, sizeof(buf)); 57*2e192b24SSimon Glass if (ret) 58*2e192b24SSimon Glass goto err; 59*2e192b24SSimon Glass 60*2e192b24SSimon Glass printf("%s\n", buf); 61*2e192b24SSimon Glass return; 62*2e192b24SSimon Glass err: 63*2e192b24SSimon Glass printf("Error %d\n", ret); 64*2e192b24SSimon Glass } 65*2e192b24SSimon Glass 66*2e192b24SSimon Glass static int do_gpio_status(bool all, const char *gpio_name) 67*2e192b24SSimon Glass { 68*2e192b24SSimon Glass struct udevice *dev; 69*2e192b24SSimon Glass int banklen; 70*2e192b24SSimon Glass int flags; 71*2e192b24SSimon Glass int ret; 72*2e192b24SSimon Glass 73*2e192b24SSimon Glass flags = 0; 74*2e192b24SSimon Glass if (gpio_name && !*gpio_name) 75*2e192b24SSimon Glass gpio_name = NULL; 76*2e192b24SSimon Glass for (ret = uclass_first_device(UCLASS_GPIO, &dev); 77*2e192b24SSimon Glass dev; 78*2e192b24SSimon Glass ret = uclass_next_device(&dev)) { 79*2e192b24SSimon Glass const char *bank_name; 80*2e192b24SSimon Glass int num_bits; 81*2e192b24SSimon Glass 82*2e192b24SSimon Glass flags |= FLAG_SHOW_BANK; 83*2e192b24SSimon Glass if (all) 84*2e192b24SSimon Glass flags |= FLAG_SHOW_ALL; 85*2e192b24SSimon Glass bank_name = gpio_get_bank_info(dev, &num_bits); 86*2e192b24SSimon Glass if (!num_bits) { 87*2e192b24SSimon Glass debug("GPIO device %s has no bits\n", dev->name); 88*2e192b24SSimon Glass continue; 89*2e192b24SSimon Glass } 90*2e192b24SSimon Glass banklen = bank_name ? strlen(bank_name) : 0; 91*2e192b24SSimon Glass 92*2e192b24SSimon Glass if (!gpio_name || !bank_name || 93*2e192b24SSimon Glass !strncmp(gpio_name, bank_name, banklen)) { 94*2e192b24SSimon Glass const char *p = NULL; 95*2e192b24SSimon Glass int offset; 96*2e192b24SSimon Glass 97*2e192b24SSimon Glass p = gpio_name + banklen; 98*2e192b24SSimon Glass if (gpio_name && *p) { 99*2e192b24SSimon Glass offset = simple_strtoul(p, NULL, 10); 100*2e192b24SSimon Glass gpio_get_description(dev, bank_name, offset, 101*2e192b24SSimon Glass &flags); 102*2e192b24SSimon Glass } else { 103*2e192b24SSimon Glass for (offset = 0; offset < num_bits; offset++) { 104*2e192b24SSimon Glass gpio_get_description(dev, bank_name, 105*2e192b24SSimon Glass offset, &flags); 106*2e192b24SSimon Glass } 107*2e192b24SSimon Glass } 108*2e192b24SSimon Glass } 109*2e192b24SSimon Glass /* Add a newline between bank names */ 110*2e192b24SSimon Glass if (!(flags & FLAG_SHOW_BANK)) 111*2e192b24SSimon Glass flags |= FLAG_SHOW_NEWLINE; 112*2e192b24SSimon Glass } 113*2e192b24SSimon Glass 114*2e192b24SSimon Glass return ret; 115*2e192b24SSimon Glass } 116*2e192b24SSimon Glass #endif 117*2e192b24SSimon Glass 118*2e192b24SSimon Glass static int do_gpio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 119*2e192b24SSimon Glass { 120*2e192b24SSimon Glass unsigned int gpio; 121*2e192b24SSimon Glass enum gpio_cmd sub_cmd; 122*2e192b24SSimon Glass ulong value; 123*2e192b24SSimon Glass const char *str_cmd, *str_gpio = NULL; 124*2e192b24SSimon Glass int ret; 125*2e192b24SSimon Glass #ifdef CONFIG_DM_GPIO 126*2e192b24SSimon Glass bool all = false; 127*2e192b24SSimon Glass #endif 128*2e192b24SSimon Glass 129*2e192b24SSimon Glass if (argc < 2) 130*2e192b24SSimon Glass show_usage: 131*2e192b24SSimon Glass return CMD_RET_USAGE; 132*2e192b24SSimon Glass str_cmd = argv[1]; 133*2e192b24SSimon Glass argc -= 2; 134*2e192b24SSimon Glass argv += 2; 135*2e192b24SSimon Glass #ifdef CONFIG_DM_GPIO 136*2e192b24SSimon Glass if (argc > 0 && !strcmp(*argv, "-a")) { 137*2e192b24SSimon Glass all = true; 138*2e192b24SSimon Glass argc--; 139*2e192b24SSimon Glass argv++; 140*2e192b24SSimon Glass } 141*2e192b24SSimon Glass #endif 142*2e192b24SSimon Glass if (argc > 0) 143*2e192b24SSimon Glass str_gpio = *argv; 144*2e192b24SSimon Glass if (!strncmp(str_cmd, "status", 1)) { 145*2e192b24SSimon Glass /* Support deprecated gpio_status() */ 146*2e192b24SSimon Glass #ifdef gpio_status 147*2e192b24SSimon Glass gpio_status(); 148*2e192b24SSimon Glass return 0; 149*2e192b24SSimon Glass #elif defined(CONFIG_DM_GPIO) 150*2e192b24SSimon Glass return cmd_process_error(cmdtp, do_gpio_status(all, str_gpio)); 151*2e192b24SSimon Glass #else 152*2e192b24SSimon Glass goto show_usage; 153*2e192b24SSimon Glass #endif 154*2e192b24SSimon Glass } 155*2e192b24SSimon Glass 156*2e192b24SSimon Glass if (!str_gpio) 157*2e192b24SSimon Glass goto show_usage; 158*2e192b24SSimon Glass 159*2e192b24SSimon Glass /* parse the behavior */ 160*2e192b24SSimon Glass switch (*str_cmd) { 161*2e192b24SSimon Glass case 'i': sub_cmd = GPIO_INPUT; break; 162*2e192b24SSimon Glass case 's': sub_cmd = GPIO_SET; break; 163*2e192b24SSimon Glass case 'c': sub_cmd = GPIO_CLEAR; break; 164*2e192b24SSimon Glass case 't': sub_cmd = GPIO_TOGGLE; break; 165*2e192b24SSimon Glass default: goto show_usage; 166*2e192b24SSimon Glass } 167*2e192b24SSimon Glass 168*2e192b24SSimon Glass #if defined(CONFIG_DM_GPIO) 169*2e192b24SSimon Glass /* 170*2e192b24SSimon Glass * TODO(sjg@chromium.org): For now we must fit into the existing GPIO 171*2e192b24SSimon Glass * framework, so we look up the name here and convert it to a GPIO number. 172*2e192b24SSimon Glass * Once all GPIO drivers are converted to driver model, we can change the 173*2e192b24SSimon Glass * code here to use the GPIO uclass interface instead of the numbered 174*2e192b24SSimon Glass * GPIO compatibility layer. 175*2e192b24SSimon Glass */ 176*2e192b24SSimon Glass ret = gpio_lookup_name(str_gpio, NULL, NULL, &gpio); 177*2e192b24SSimon Glass if (ret) { 178*2e192b24SSimon Glass printf("GPIO: '%s' not found\n", str_gpio); 179*2e192b24SSimon Glass return cmd_process_error(cmdtp, ret); 180*2e192b24SSimon Glass } 181*2e192b24SSimon Glass #else 182*2e192b24SSimon Glass /* turn the gpio name into a gpio number */ 183*2e192b24SSimon Glass gpio = name_to_gpio(str_gpio); 184*2e192b24SSimon Glass if (gpio < 0) 185*2e192b24SSimon Glass goto show_usage; 186*2e192b24SSimon Glass #endif 187*2e192b24SSimon Glass /* grab the pin before we tweak it */ 188*2e192b24SSimon Glass ret = gpio_request(gpio, "cmd_gpio"); 189*2e192b24SSimon Glass if (ret && ret != -EBUSY) { 190*2e192b24SSimon Glass printf("gpio: requesting pin %u failed\n", gpio); 191*2e192b24SSimon Glass return -1; 192*2e192b24SSimon Glass } 193*2e192b24SSimon Glass 194*2e192b24SSimon Glass /* finally, let's do it: set direction and exec command */ 195*2e192b24SSimon Glass if (sub_cmd == GPIO_INPUT) { 196*2e192b24SSimon Glass gpio_direction_input(gpio); 197*2e192b24SSimon Glass value = gpio_get_value(gpio); 198*2e192b24SSimon Glass } else { 199*2e192b24SSimon Glass switch (sub_cmd) { 200*2e192b24SSimon Glass case GPIO_SET: value = 1; break; 201*2e192b24SSimon Glass case GPIO_CLEAR: value = 0; break; 202*2e192b24SSimon Glass case GPIO_TOGGLE: value = !gpio_get_value(gpio); break; 203*2e192b24SSimon Glass default: goto show_usage; 204*2e192b24SSimon Glass } 205*2e192b24SSimon Glass gpio_direction_output(gpio, value); 206*2e192b24SSimon Glass } 207*2e192b24SSimon Glass printf("gpio: pin %s (gpio %i) value is %lu\n", 208*2e192b24SSimon Glass str_gpio, gpio, value); 209*2e192b24SSimon Glass 210*2e192b24SSimon Glass if (ret != -EBUSY) 211*2e192b24SSimon Glass gpio_free(gpio); 212*2e192b24SSimon Glass 213*2e192b24SSimon Glass return value; 214*2e192b24SSimon Glass } 215*2e192b24SSimon Glass 216*2e192b24SSimon Glass U_BOOT_CMD(gpio, 4, 0, do_gpio, 217*2e192b24SSimon Glass "query and control gpio pins", 218*2e192b24SSimon Glass "<input|set|clear|toggle> <pin>\n" 219*2e192b24SSimon Glass " - input/set/clear/toggle the specified pin\n" 220*2e192b24SSimon Glass "gpio status [-a] [<bank> | <pin>] - show [all/claimed] GPIOs"); 221