From 95a260a98c010321cdc5f2acd1f4272b9c0a19dc Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 26 Feb 2014 15:59:26 -0700 Subject: dm: Enable gpio command to support driver model Now that named GPIO banks are supported, along with a way of obtaining the status of a GPIO (input or output), we can provide an enhanced GPIO command for driver model. Where the driver provides its own operation for obtaining the GPIO state, this is used, otherwise a generic version is sufficient. Signed-off-by: Simon Glass --- common/cmd_gpio.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 116 insertions(+), 13 deletions(-) (limited to 'common') diff --git a/common/cmd_gpio.c b/common/cmd_gpio.c index 47eee89221..778aa5f098 100644 --- a/common/cmd_gpio.c +++ b/common/cmd_gpio.c @@ -8,7 +8,7 @@ #include #include - +#include #include #ifndef name_to_gpio @@ -22,25 +22,115 @@ enum gpio_cmd { GPIO_TOGGLE, }; +#if defined(CONFIG_DM_GPIO) && !defined(gpio_status) +static const char * const gpio_function[] = { + "input", + "output", + "unknown", +}; + +static void show_gpio(struct device *dev, const char *bank_name, int offset) +{ + struct dm_gpio_ops *ops = gpio_get_ops(dev); + char buf[80]; + int ret; + + *buf = '\0'; + if (ops->get_state) { + ret = ops->get_state(dev, offset, buf, sizeof(buf)); + if (ret) { + puts(""); + 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)); + } + + puts(buf); + puts("\n"); +} + +static int do_gpio_status(const char *gpio_name) +{ + struct device *dev; + int newline = 0; + int ret; + + if (gpio_name && !*gpio_name) + gpio_name = NULL; + for (ret = uclass_first_device(UCLASS_GPIO, &dev); + dev; + ret = uclass_next_device(&dev)) { + const char *bank_name; + int num_bits; + + bank_name = gpio_get_bank_info(dev, &num_bits); + + if (!gpio_name || !bank_name || + !strncmp(gpio_name, bank_name, strlen(bank_name))) { + 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); + offset = simple_strtoul(p, NULL, 10); + show_gpio(dev, bank_name, offset); + } else { + for (offset = 0; offset < num_bits; offset++) + show_gpio(dev, bank_name, offset); + } + } + } + + return ret; +} +#endif + static int do_gpio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - int gpio; + unsigned int gpio; enum gpio_cmd sub_cmd; ulong value; - const char *str_cmd, *str_gpio; + const char *str_cmd, *str_gpio = NULL; +#ifdef CONFIG_DM_GPIO + int ret; +#endif + if (argc < 2) + show_usage: + return CMD_RET_USAGE; + str_cmd = argv[1]; + if (argc > 2) + str_gpio = argv[2]; + if (!strcmp(str_cmd, "status")) { + /* Support deprecated gpio_status() */ #ifdef gpio_status - if (argc == 2 && !strcmp(argv[1], "status")) { gpio_status(); return 0; - } +#elif defined(CONFIG_DM_GPIO) + return cmd_process_error(cmdtp, do_gpio_status(str_gpio)); +#else + goto show_usage; #endif + } - if (argc != 3) - show_usage: - return CMD_RET_USAGE; - str_cmd = argv[1]; - str_gpio = argv[2]; + if (!str_gpio) + goto show_usage; /* parse the behavior */ switch (*str_cmd) { @@ -51,11 +141,23 @@ static int do_gpio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) default: goto show_usage; } +#if defined(CONFIG_DM_GPIO) + /* + * TODO(sjg@chromium.org): For now we must fit into the existing GPIO + * framework, so we look up the name here and convert it to a GPIO number. + * Once all GPIO drivers are converted to driver model, we can change the + * code here to use the GPIO uclass interface instead of the numbered + * GPIO compatibility layer. + */ + ret = gpio_lookup_name(str_gpio, NULL, NULL, &gpio); + if (ret) + return cmd_process_error(cmdtp, ret); +#else /* turn the gpio name into a gpio number */ gpio = name_to_gpio(str_gpio); if (gpio < 0) goto show_usage; - +#endif /* grab the pin before we tweak it */ if (gpio_request(gpio, "cmd_gpio")) { printf("gpio: requesting pin %u failed\n", gpio); @@ -84,6 +186,7 @@ static int do_gpio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) } U_BOOT_CMD(gpio, 3, 0, do_gpio, - "input/set/clear/toggle gpio pins", + "query and control gpio pins", " \n" - " - input/set/clear/toggle the specified pin"); + " - input/set/clear/toggle the specified pin\n" + "gpio status [ | ]"); -- cgit v1.2.1