From 89e6405425c7b52fd1330c61b6f5526612b87516 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 11 Aug 2014 09:23:52 -0600 Subject: dm: gpio: Enhance gpio command to show only active GPIOs The GPIO list is very long in many cases and most of them are not used. By default, show only the GPIOs that are in use, and provide a flag to show all of them. This makes the 'gpio status' command much more pleasant. In order to do this, driver model now exposes a method for obtaining the 'function' of a GPIO, which describes whether it is an input or output, for example. Implementation of this method is optional. Signed-off-by: Simon Glass --- common/cmd_gpio.c | 101 +++++++++++++++++++++++++++++++-------------- include/asm-generic/gpio.h | 15 ++++++- 2 files changed, 82 insertions(+), 34 deletions(-) diff --git a/common/cmd_gpio.c b/common/cmd_gpio.c index 4634f914e6..b97533f313 100644 --- a/common/cmd_gpio.c +++ b/common/cmd_gpio.c @@ -24,18 +24,46 @@ enum gpio_cmd { }; #if defined(CONFIG_DM_GPIO) && !defined(gpio_status) -static const char * const gpio_function[] = { +static const char * const gpio_function[GPIOF_COUNT] = { "input", "output", + "unused", "unknown", + "func", }; -static void show_gpio(struct udevice *dev, const char *bank_name, int offset) +/* A few flags used by show_gpio() */ +enum { + FLAG_SHOW_ALL = 1 << 0, + FLAG_SHOW_BANK = 1 << 1, + FLAG_SHOW_NEWLINE = 1 << 2, +}; + +static void show_gpio(struct udevice *dev, const char *bank_name, int offset, + int *flagsp) { struct dm_gpio_ops *ops = gpio_get_ops(dev); + int func = GPIOF_UNKNOWN; char buf[80]; int ret; + BUILD_BUG_ON(GPIOF_COUNT != ARRAY_SIZE(gpio_function)); + + if (ops->get_function) { + ret = ops->get_function(dev, offset); + if (ret >= 0 && ret < ARRAY_SIZE(gpio_function)) + func = ret; + } + if (!(*flagsp & FLAG_SHOW_ALL) && func == GPIOF_UNUSED) + return; + if ((*flagsp & FLAG_SHOW_BANK) && bank_name) { + if (*flagsp & FLAG_SHOW_NEWLINE) { + putc('\n'); + *flagsp &= ~FLAG_SHOW_NEWLINE; + } + printf("Bank %s:\n", bank_name); + *flagsp &= ~FLAG_SHOW_BANK; + } *buf = '\0'; if (ops->get_state) { ret = ops->get_state(dev, offset, buf, sizeof(buf)); @@ -44,14 +72,6 @@ static void show_gpio(struct udevice *dev, const char *bank_name, int offset) return; } } else { - int func = GPIOF_UNKNOWN; - int ret; - - if (ops->get_function) { - ret = ops->get_function(dev, offset); - if (ret >= 0 && ret < ARRAY_SIZE(gpio_function)) - func = ret; - } sprintf(buf, "%s%u: %8s %d", bank_name, offset, gpio_function[func], ops->get_value(dev, offset)); } @@ -60,12 +80,14 @@ static void show_gpio(struct udevice *dev, const char *bank_name, int offset) puts("\n"); } -static int do_gpio_status(const char *gpio_name) +static int do_gpio_status(bool all, const char *gpio_name) { struct udevice *dev; - int newline = 0; + int banklen; + int flags; int ret; + flags = 0; if (gpio_name && !*gpio_name) gpio_name = NULL; for (ret = uclass_first_device(UCLASS_GPIO, &dev); @@ -74,28 +96,33 @@ static int do_gpio_status(const char *gpio_name) const char *bank_name; int num_bits; + flags |= FLAG_SHOW_BANK; + if (all) + flags |= FLAG_SHOW_ALL; bank_name = gpio_get_bank_info(dev, &num_bits); + if (!num_bits) + continue; + banklen = bank_name ? strlen(bank_name) : 0; if (!gpio_name || !bank_name || - !strncmp(gpio_name, bank_name, strlen(bank_name))) { + !strncmp(gpio_name, bank_name, banklen)) { const char *p = NULL; int offset; - if (bank_name) { - if (newline) - putc('\n'); - printf("Bank %s:\n", bank_name); - } - newline = 1; - if (gpio_name && bank_name) { - p = gpio_name + strlen(bank_name); + p = gpio_name + banklen; + if (gpio_name && *p) { offset = simple_strtoul(p, NULL, 10); - show_gpio(dev, bank_name, offset); + show_gpio(dev, bank_name, offset, &flags); } else { - for (offset = 0; offset < num_bits; offset++) - show_gpio(dev, bank_name, offset); + for (offset = 0; offset < num_bits; offset++) { + show_gpio(dev, bank_name, offset, + &flags); + } } } + /* Add a newline between bank names */ + if (!(flags & FLAG_SHOW_BANK)) + flags |= FLAG_SHOW_NEWLINE; } return ret; @@ -109,6 +136,7 @@ static int do_gpio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) ulong value; const char *str_cmd, *str_gpio = NULL; #ifdef CONFIG_DM_GPIO + bool all = false; int ret; #endif @@ -116,15 +144,24 @@ static int do_gpio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) show_usage: return CMD_RET_USAGE; str_cmd = argv[1]; - if (argc > 2) - str_gpio = argv[2]; + argc -= 2; + argv += 2; +#ifdef CONFIG_DM_GPIO + if (argc > 0 && !strcmp(*argv, "-a")) { + all = true; + argc--; + argv++; + } +#endif + if (argc > 0) + str_gpio = *argv; if (!strcmp(str_cmd, "status")) { /* Support deprecated gpio_status() */ #ifdef gpio_status gpio_status(); return 0; #elif defined(CONFIG_DM_GPIO) - return cmd_process_error(cmdtp, do_gpio_status(str_gpio)); + return cmd_process_error(cmdtp, do_gpio_status(all, str_gpio)); #else goto show_usage; #endif @@ -186,8 +223,8 @@ static int do_gpio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return value; } -U_BOOT_CMD(gpio, 3, 0, do_gpio, - "query and control gpio pins", - " \n" - " - input/set/clear/toggle the specified pin\n" - "gpio status [ | ]"); +U_BOOT_CMD(gpio, 4, 0, do_gpio, + "query and control gpio pins", + " \n" + " - input/set/clear/toggle the specified pin\n" + "gpio status [-a] [ | ] - show [all/claimed] GPIOs"); diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index a6e52a0de6..60539d8a9d 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -79,11 +79,15 @@ int gpio_get_value(unsigned gpio); */ int gpio_set_value(unsigned gpio, int value); -/* State of a GPIO, as reported by get_state() */ +/* State of a GPIO, as reported by get_function() */ enum { GPIOF_INPUT = 0, GPIOF_OUTPUT, - GPIOF_UNKNOWN, + GPIOF_UNUSED, /* Not claimed */ + GPIOF_UNKNOWN, /* Not known */ + GPIOF_FUNC, /* Not used as a GPIO */ + + GPIOF_COUNT, }; struct udevice; @@ -123,6 +127,13 @@ struct dm_gpio_ops { int value); int (*get_value)(struct udevice *dev, unsigned offset); int (*set_value)(struct udevice *dev, unsigned offset, int value); + /** + * get_function() Get the GPIO function + * + * @dev: Device to check + * @offset: GPIO offset within that device + * @return current function - GPIOF_... + */ int (*get_function)(struct udevice *dev, unsigned offset); int (*get_state)(struct udevice *dev, unsigned offset, char *state, int maxlen); -- cgit From 9165e8428d02b42b7f2b87083035e4e2493df721 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 11 Aug 2014 09:23:53 -0600 Subject: dm: gpio: Allow gpio command to adjust GPIOs that are busy The gpio command mostly relies on gpio_request() and gpio_free() being nops, in that you can request a GPIO twice. With driver model this is now implemented correctly, so it fails. Change the command to deal with a failure to claim the GPIO. Signed-off-by: Simon Glass --- common/cmd_gpio.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/common/cmd_gpio.c b/common/cmd_gpio.c index b97533f313..11f4e4031d 100644 --- a/common/cmd_gpio.c +++ b/common/cmd_gpio.c @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -135,9 +136,9 @@ static int do_gpio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) enum gpio_cmd sub_cmd; ulong value; const char *str_cmd, *str_gpio = NULL; + int ret; #ifdef CONFIG_DM_GPIO bool all = false; - int ret; #endif if (argc < 2) @@ -197,7 +198,8 @@ static int do_gpio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) goto show_usage; #endif /* grab the pin before we tweak it */ - if (gpio_request(gpio, "cmd_gpio")) { + ret = gpio_request(gpio, "cmd_gpio"); + if (ret && ret != -EBUSY) { printf("gpio: requesting pin %u failed\n", gpio); return -1; } @@ -218,7 +220,8 @@ static int do_gpio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) printf("gpio: pin %s (gpio %i) value is %lu\n", str_gpio, gpio, value); - gpio_free(gpio); + if (ret != -EBUSY) + gpio_free(gpio); return value; } -- cgit From 4bc9a19324ba27eb867316d2ea0d55bba95e8724 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 11 Aug 2014 09:24:03 -0600 Subject: dm: sandbox: dts: Add a GPIO bank Add a bank of GPIOs for sandbox which can be used for testing this functionality. Signed-off-by: Simon Glass --- arch/sandbox/dts/sandbox.dts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 62d803789c..efffacba1d 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -113,4 +113,12 @@ 0x070b0067 0x070c0069>; }; + gpio_a: gpios { + gpio-controller; + compatible = "sandbox,gpio"; + #gpio-cells = <1>; + gpio-bank-name = "a"; + num-gpios = <20>; + }; + }; -- cgit