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