Commit 95a260a98c010321cdc5f2acd1f4272b9c0a19dc

Authored by Simon Glass
Committed by Tom Rini
1 parent e2d8a714a7

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 <sjg@chromium.org>

Showing 1 changed file with 116 additions and 13 deletions Side-by-side Diff

... ... @@ -8,7 +8,7 @@
8 8  
9 9 #include <common.h>
10 10 #include <command.h>
11   -
  11 +#include <dm.h>
12 12 #include <asm/gpio.h>
13 13  
14 14 #ifndef name_to_gpio
15 15  
16 16  
17 17  
18 18  
19 19  
20 20  
21 21  
... ... @@ -22,25 +22,115 @@
22 22 GPIO_TOGGLE,
23 23 };
24 24  
  25 +#if defined(CONFIG_DM_GPIO) && !defined(gpio_status)
  26 +static const char * const gpio_function[] = {
  27 + "input",
  28 + "output",
  29 + "unknown",
  30 +};
  31 +
  32 +static void show_gpio(struct device *dev, const char *bank_name, int offset)
  33 +{
  34 + struct dm_gpio_ops *ops = gpio_get_ops(dev);
  35 + char buf[80];
  36 + int ret;
  37 +
  38 + *buf = '\0';
  39 + if (ops->get_state) {
  40 + ret = ops->get_state(dev, offset, buf, sizeof(buf));
  41 + if (ret) {
  42 + puts("<unknown>");
  43 + return;
  44 + }
  45 + } else {
  46 + int func = GPIOF_UNKNOWN;
  47 + int ret;
  48 +
  49 + if (ops->get_function) {
  50 + ret = ops->get_function(dev, offset);
  51 + if (ret >= 0 && ret < ARRAY_SIZE(gpio_function))
  52 + func = ret;
  53 + }
  54 + sprintf(buf, "%s%u: %8s %d", bank_name, offset,
  55 + gpio_function[func], ops->get_value(dev, offset));
  56 + }
  57 +
  58 + puts(buf);
  59 + puts("\n");
  60 +}
  61 +
  62 +static int do_gpio_status(const char *gpio_name)
  63 +{
  64 + struct device *dev;
  65 + int newline = 0;
  66 + int ret;
  67 +
  68 + if (gpio_name && !*gpio_name)
  69 + gpio_name = NULL;
  70 + for (ret = uclass_first_device(UCLASS_GPIO, &dev);
  71 + dev;
  72 + ret = uclass_next_device(&dev)) {
  73 + const char *bank_name;
  74 + int num_bits;
  75 +
  76 + bank_name = gpio_get_bank_info(dev, &num_bits);
  77 +
  78 + if (!gpio_name || !bank_name ||
  79 + !strncmp(gpio_name, bank_name, strlen(bank_name))) {
  80 + const char *p = NULL;
  81 + int offset;
  82 +
  83 + if (bank_name) {
  84 + if (newline)
  85 + putc('\n');
  86 + printf("Bank %s:\n", bank_name);
  87 + }
  88 + newline = 1;
  89 + if (gpio_name && bank_name) {
  90 + p = gpio_name + strlen(bank_name);
  91 + offset = simple_strtoul(p, NULL, 10);
  92 + show_gpio(dev, bank_name, offset);
  93 + } else {
  94 + for (offset = 0; offset < num_bits; offset++)
  95 + show_gpio(dev, bank_name, offset);
  96 + }
  97 + }
  98 + }
  99 +
  100 + return ret;
  101 +}
  102 +#endif
  103 +
25 104 static int do_gpio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
26 105 {
27   - int gpio;
  106 + unsigned int gpio;
28 107 enum gpio_cmd sub_cmd;
29 108 ulong value;
30   - const char *str_cmd, *str_gpio;
  109 + const char *str_cmd, *str_gpio = NULL;
  110 +#ifdef CONFIG_DM_GPIO
  111 + int ret;
  112 +#endif
31 113  
  114 + if (argc < 2)
  115 + show_usage:
  116 + return CMD_RET_USAGE;
  117 + str_cmd = argv[1];
  118 + if (argc > 2)
  119 + str_gpio = argv[2];
  120 + if (!strcmp(str_cmd, "status")) {
  121 + /* Support deprecated gpio_status() */
32 122 #ifdef gpio_status
33   - if (argc == 2 && !strcmp(argv[1], "status")) {
34 123 gpio_status();
35 124 return 0;
36   - }
  125 +#elif defined(CONFIG_DM_GPIO)
  126 + return cmd_process_error(cmdtp, do_gpio_status(str_gpio));
  127 +#else
  128 + goto show_usage;
37 129 #endif
  130 + }
38 131  
39   - if (argc != 3)
40   - show_usage:
41   - return CMD_RET_USAGE;
42   - str_cmd = argv[1];
43   - str_gpio = argv[2];
  132 + if (!str_gpio)
  133 + goto show_usage;
44 134  
45 135 /* parse the behavior */
46 136 switch (*str_cmd) {
47 137  
... ... @@ -51,11 +141,23 @@
51 141 default: goto show_usage;
52 142 }
53 143  
  144 +#if defined(CONFIG_DM_GPIO)
  145 + /*
  146 + * TODO(sjg@chromium.org): For now we must fit into the existing GPIO
  147 + * framework, so we look up the name here and convert it to a GPIO number.
  148 + * Once all GPIO drivers are converted to driver model, we can change the
  149 + * code here to use the GPIO uclass interface instead of the numbered
  150 + * GPIO compatibility layer.
  151 + */
  152 + ret = gpio_lookup_name(str_gpio, NULL, NULL, &gpio);
  153 + if (ret)
  154 + return cmd_process_error(cmdtp, ret);
  155 +#else
54 156 /* turn the gpio name into a gpio number */
55 157 gpio = name_to_gpio(str_gpio);
56 158 if (gpio < 0)
57 159 goto show_usage;
58   -
  160 +#endif
59 161 /* grab the pin before we tweak it */
60 162 if (gpio_request(gpio, "cmd_gpio")) {
61 163 printf("gpio: requesting pin %u failed\n", gpio);
62 164  
... ... @@ -84,7 +186,8 @@
84 186 }
85 187  
86 188 U_BOOT_CMD(gpio, 3, 0, do_gpio,
87   - "input/set/clear/toggle gpio pins",
  189 + "query and control gpio pins",
88 190 "<input|set|clear|toggle> <pin>\n"
89   - " - input/set/clear/toggle the specified pin");
  191 + " - input/set/clear/toggle the specified pin\n"
  192 + "gpio status [<bank> | <pin>]");