]>
Commit | Line | Data |
---|---|---|
a972b8d7 MF |
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> | |
9165e842 | 11 | #include <errno.h> |
95a260a9 | 12 | #include <dm.h> |
f7ae49fc | 13 | #include <log.h> |
336d4615 | 14 | #include <malloc.h> |
dd2b8c11 DR |
15 | #ifdef CONFIG_CMD_GPIO_READ |
16 | #include <env.h> | |
17 | #endif | |
a972b8d7 | 18 | #include <asm/gpio.h> |
61b29b82 | 19 | #include <linux/err.h> |
a972b8d7 | 20 | |
5b5ac645 | 21 | __weak int name_to_gpio(const char *name) |
fd11bea2 | 22 | { |
0b1284eb | 23 | return dectoul(name, NULL); |
fd11bea2 | 24 | } |
a972b8d7 MF |
25 | |
26 | enum gpio_cmd { | |
66f657d1 SG |
27 | GPIOC_INPUT, |
28 | GPIOC_SET, | |
29 | GPIOC_CLEAR, | |
30 | GPIOC_TOGGLE, | |
dd2b8c11 DR |
31 | #ifdef CONFIG_CMD_GPIO_READ |
32 | GPIOC_READ, | |
33 | #endif | |
a972b8d7 MF |
34 | }; |
35 | ||
95a260a9 | 36 | #if defined(CONFIG_DM_GPIO) && !defined(gpio_status) |
95a260a9 | 37 | |
89e64054 SG |
38 | /* A few flags used by show_gpio() */ |
39 | enum { | |
40 | FLAG_SHOW_ALL = 1 << 0, | |
41 | FLAG_SHOW_BANK = 1 << 1, | |
42 | FLAG_SHOW_NEWLINE = 1 << 2, | |
43 | }; | |
44 | ||
0757535a | 45 | static void gpio_get_description(struct udevice *dev, const char *bank_name, |
b8989b53 | 46 | int offset, int *flagsp, bool show_all) |
95a260a9 | 47 | { |
95a260a9 SG |
48 | char buf[80]; |
49 | int ret; | |
50 | ||
0757535a SG |
51 | ret = gpio_get_function(dev, offset, NULL); |
52 | if (ret < 0) | |
53 | goto err; | |
b8989b53 | 54 | if (!show_all && !(*flagsp & FLAG_SHOW_ALL) && ret == GPIOF_UNUSED) |
89e64054 SG |
55 | return; |
56 | if ((*flagsp & FLAG_SHOW_BANK) && bank_name) { | |
57 | if (*flagsp & FLAG_SHOW_NEWLINE) { | |
58 | putc('\n'); | |
59 | *flagsp &= ~FLAG_SHOW_NEWLINE; | |
60 | } | |
61 | printf("Bank %s:\n", bank_name); | |
62 | *flagsp &= ~FLAG_SHOW_BANK; | |
63 | } | |
95a260a9 | 64 | |
0757535a SG |
65 | ret = gpio_get_status(dev, offset, buf, sizeof(buf)); |
66 | if (ret) | |
67 | goto err; | |
68 | ||
69 | printf("%s\n", buf); | |
70 | return; | |
71 | err: | |
72 | printf("Error %d\n", ret); | |
95a260a9 SG |
73 | } |
74 | ||
89e64054 | 75 | static int do_gpio_status(bool all, const char *gpio_name) |
95a260a9 | 76 | { |
54c5d08a | 77 | struct udevice *dev; |
89e64054 SG |
78 | int banklen; |
79 | int flags; | |
8676ae36 | 80 | int ret, err = 0; |
95a260a9 | 81 | |
89e64054 | 82 | flags = 0; |
95a260a9 SG |
83 | if (gpio_name && !*gpio_name) |
84 | gpio_name = NULL; | |
8676ae36 | 85 | for (ret = uclass_first_device_check(UCLASS_GPIO, &dev); |
95a260a9 | 86 | dev; |
8676ae36 | 87 | ret = uclass_next_device_check(&dev)) { |
95a260a9 SG |
88 | const char *bank_name; |
89 | int num_bits; | |
90 | ||
8676ae36 MS |
91 | if (ret) { |
92 | printf("GPIO device %s probe error %i\n", | |
93 | dev->name, ret); | |
94 | err = ret; | |
95 | continue; | |
96 | } | |
97 | ||
89e64054 SG |
98 | flags |= FLAG_SHOW_BANK; |
99 | if (all) | |
100 | flags |= FLAG_SHOW_ALL; | |
95a260a9 | 101 | bank_name = gpio_get_bank_info(dev, &num_bits); |
0757535a SG |
102 | if (!num_bits) { |
103 | debug("GPIO device %s has no bits\n", dev->name); | |
89e64054 | 104 | continue; |
0757535a | 105 | } |
89e64054 | 106 | banklen = bank_name ? strlen(bank_name) : 0; |
95a260a9 SG |
107 | |
108 | if (!gpio_name || !bank_name || | |
48ca6909 | 109 | !strncasecmp(gpio_name, bank_name, banklen)) { |
e946b5d2 | 110 | const char *p; |
95a260a9 SG |
111 | int offset; |
112 | ||
89e64054 SG |
113 | p = gpio_name + banklen; |
114 | if (gpio_name && *p) { | |
0b1284eb | 115 | offset = dectoul(p, NULL); |
0757535a | 116 | gpio_get_description(dev, bank_name, offset, |
b8989b53 | 117 | &flags, true); |
95a260a9 | 118 | } else { |
89e64054 | 119 | for (offset = 0; offset < num_bits; offset++) { |
0757535a | 120 | gpio_get_description(dev, bank_name, |
b8989b53 | 121 | offset, &flags, false); |
89e64054 | 122 | } |
95a260a9 SG |
123 | } |
124 | } | |
89e64054 SG |
125 | /* Add a newline between bank names */ |
126 | if (!(flags & FLAG_SHOW_BANK)) | |
127 | flags |= FLAG_SHOW_NEWLINE; | |
95a260a9 SG |
128 | } |
129 | ||
8676ae36 | 130 | return err; |
95a260a9 SG |
131 | } |
132 | #endif | |
133 | ||
09140113 SG |
134 | static int do_gpio(struct cmd_tbl *cmdtp, int flag, int argc, |
135 | char *const argv[]) | |
a972b8d7 | 136 | { |
95a260a9 | 137 | unsigned int gpio; |
a972b8d7 | 138 | enum gpio_cmd sub_cmd; |
b71bea71 | 139 | int value; |
95a260a9 | 140 | const char *str_cmd, *str_gpio = NULL; |
dd2b8c11 DR |
141 | #ifdef CONFIG_CMD_GPIO_READ |
142 | const char *str_var = NULL; | |
143 | #endif | |
9165e842 | 144 | int ret; |
95a260a9 | 145 | #ifdef CONFIG_DM_GPIO |
89e64054 | 146 | bool all = false; |
95a260a9 | 147 | #endif |
a972b8d7 | 148 | |
95a260a9 SG |
149 | if (argc < 2) |
150 | show_usage: | |
151 | return CMD_RET_USAGE; | |
152 | str_cmd = argv[1]; | |
89e64054 SG |
153 | argc -= 2; |
154 | argv += 2; | |
155 | #ifdef CONFIG_DM_GPIO | |
dd2b8c11 | 156 | if (argc > 0 && !strncmp(str_cmd, "status", 2) && !strcmp(*argv, "-a")) { |
89e64054 SG |
157 | all = true; |
158 | argc--; | |
159 | argv++; | |
160 | } | |
dd2b8c11 DR |
161 | #endif |
162 | #ifdef CONFIG_CMD_GPIO_READ | |
163 | if (argc > 0 && !strncmp(str_cmd, "read", 2)) { | |
164 | if (argc < 2) | |
165 | goto show_usage; | |
166 | str_var = *argv; | |
167 | argc--; | |
168 | argv++; | |
169 | } | |
89e64054 SG |
170 | #endif |
171 | if (argc > 0) | |
172 | str_gpio = *argv; | |
4c80c53c | 173 | if (!strncmp(str_cmd, "status", 2)) { |
95a260a9 | 174 | /* Support deprecated gpio_status() */ |
a972b8d7 | 175 | #ifdef gpio_status |
a972b8d7 MF |
176 | gpio_status(); |
177 | return 0; | |
95a260a9 | 178 | #elif defined(CONFIG_DM_GPIO) |
89e64054 | 179 | return cmd_process_error(cmdtp, do_gpio_status(all, str_gpio)); |
95a260a9 SG |
180 | #else |
181 | goto show_usage; | |
a972b8d7 | 182 | #endif |
95a260a9 | 183 | } |
a972b8d7 | 184 | |
95a260a9 SG |
185 | if (!str_gpio) |
186 | goto show_usage; | |
a972b8d7 MF |
187 | |
188 | /* parse the behavior */ | |
189 | switch (*str_cmd) { | |
66f657d1 SG |
190 | case 'i': |
191 | sub_cmd = GPIOC_INPUT; | |
192 | break; | |
193 | case 's': | |
194 | sub_cmd = GPIOC_SET; | |
195 | break; | |
196 | case 'c': | |
197 | sub_cmd = GPIOC_CLEAR; | |
198 | break; | |
199 | case 't': | |
200 | sub_cmd = GPIOC_TOGGLE; | |
201 | break; | |
dd2b8c11 DR |
202 | #ifdef CONFIG_CMD_GPIO_READ |
203 | case 'r': | |
204 | sub_cmd = GPIOC_READ; | |
205 | break; | |
206 | #endif | |
66f657d1 SG |
207 | default: |
208 | goto show_usage; | |
a972b8d7 MF |
209 | } |
210 | ||
95a260a9 SG |
211 | #if defined(CONFIG_DM_GPIO) |
212 | /* | |
213 | * TODO([email protected]): For now we must fit into the existing GPIO | |
214 | * framework, so we look up the name here and convert it to a GPIO number. | |
215 | * Once all GPIO drivers are converted to driver model, we can change the | |
216 | * code here to use the GPIO uclass interface instead of the numbered | |
217 | * GPIO compatibility layer. | |
218 | */ | |
219 | ret = gpio_lookup_name(str_gpio, NULL, NULL, &gpio); | |
66280e82 SG |
220 | if (ret) { |
221 | printf("GPIO: '%s' not found\n", str_gpio); | |
95a260a9 | 222 | return cmd_process_error(cmdtp, ret); |
66280e82 | 223 | } |
95a260a9 | 224 | #else |
a972b8d7 MF |
225 | /* turn the gpio name into a gpio number */ |
226 | gpio = name_to_gpio(str_gpio); | |
227 | if (gpio < 0) | |
228 | goto show_usage; | |
95a260a9 | 229 | #endif |
a972b8d7 | 230 | /* grab the pin before we tweak it */ |
9165e842 SG |
231 | ret = gpio_request(gpio, "cmd_gpio"); |
232 | if (ret && ret != -EBUSY) { | |
6801201e MF |
233 | printf("gpio: requesting pin %u failed\n", gpio); |
234 | return -1; | |
235 | } | |
a972b8d7 MF |
236 | |
237 | /* finally, let's do it: set direction and exec command */ | |
dd2b8c11 DR |
238 | if (sub_cmd == GPIOC_INPUT |
239 | #ifdef CONFIG_CMD_GPIO_READ | |
240 | || sub_cmd == GPIOC_READ | |
241 | #endif | |
242 | ) { | |
a972b8d7 MF |
243 | gpio_direction_input(gpio); |
244 | value = gpio_get_value(gpio); | |
245 | } else { | |
246 | switch (sub_cmd) { | |
66f657d1 | 247 | case GPIOC_SET: |
b71bea71 SG |
248 | value = 1; |
249 | break; | |
66f657d1 | 250 | case GPIOC_CLEAR: |
b71bea71 SG |
251 | value = 0; |
252 | break; | |
66f657d1 | 253 | case GPIOC_TOGGLE: |
b71bea71 SG |
254 | value = gpio_get_value(gpio); |
255 | if (!IS_ERR_VALUE(value)) | |
256 | value = !value; | |
257 | break; | |
258 | default: | |
259 | goto show_usage; | |
a972b8d7 MF |
260 | } |
261 | gpio_direction_output(gpio, value); | |
262 | } | |
b1970013 | 263 | printf("gpio: pin %s (gpio %u) value is ", str_gpio, gpio); |
4dbc107f LK |
264 | |
265 | if (IS_ERR_VALUE(value)) { | |
b71bea71 | 266 | printf("unknown (ret=%d)\n", value); |
4dbc107f LK |
267 | goto err; |
268 | } else { | |
b71bea71 | 269 | printf("%d\n", value); |
dd2b8c11 DR |
270 | #ifdef CONFIG_CMD_GPIO_READ |
271 | if (sub_cmd == GPIOC_READ) | |
272 | env_set_ulong(str_var, (ulong)value); | |
273 | #endif | |
4dbc107f LK |
274 | } |
275 | ||
dd2b8c11 DR |
276 | if (sub_cmd != GPIOC_INPUT && !IS_ERR_VALUE(value) |
277 | #ifdef CONFIG_CMD_GPIO_READ | |
278 | && sub_cmd != GPIOC_READ | |
279 | #endif | |
280 | ) { | |
b71bea71 SG |
281 | int nval = gpio_get_value(gpio); |
282 | ||
4dbc107f | 283 | if (IS_ERR_VALUE(nval)) { |
b71bea71 | 284 | printf(" Warning: no access to GPIO output value\n"); |
4dbc107f LK |
285 | goto err; |
286 | } else if (nval != value) { | |
b71bea71 | 287 | printf(" Warning: value of pin is still %d\n", nval); |
4dbc107f LK |
288 | goto err; |
289 | } | |
b71bea71 | 290 | } |
a972b8d7 | 291 | |
9165e842 SG |
292 | if (ret != -EBUSY) |
293 | gpio_free(gpio); | |
a972b8d7 | 294 | |
4af2a33e AK |
295 | /* |
296 | * Whilst wrong, the legacy gpio input command returns the pin | |
297 | * value, or CMD_RET_FAILURE (which is indistinguishable from a | |
298 | * valid pin value). | |
299 | */ | |
300 | return (sub_cmd == GPIOC_INPUT) ? value : CMD_RET_SUCCESS; | |
4dbc107f LK |
301 | |
302 | err: | |
303 | if (ret != -EBUSY) | |
304 | gpio_free(gpio); | |
305 | return CMD_RET_FAILURE; | |
a972b8d7 MF |
306 | } |
307 | ||
89e64054 SG |
308 | U_BOOT_CMD(gpio, 4, 0, do_gpio, |
309 | "query and control gpio pins", | |
310 | "<input|set|clear|toggle> <pin>\n" | |
311 | " - input/set/clear/toggle the specified pin\n" | |
dd2b8c11 DR |
312 | #ifdef CONFIG_CMD_GPIO_READ |
313 | "gpio read <name> <pin>\n" | |
314 | " - set environment variable 'name' to the specified pin\n" | |
315 | #endif | |
89e64054 | 316 | "gpio status [-a] [<bank> | <pin>] - show [all/claimed] GPIOs"); |