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