]>
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> |
a972b8d7 MF |
13 | #include <asm/gpio.h> |
14 | ||
5b5ac645 | 15 | __weak int name_to_gpio(const char *name) |
fd11bea2 IC |
16 | { |
17 | return simple_strtoul(name, NULL, 10); | |
18 | } | |
a972b8d7 MF |
19 | |
20 | enum gpio_cmd { | |
66f657d1 SG |
21 | GPIOC_INPUT, |
22 | GPIOC_SET, | |
23 | GPIOC_CLEAR, | |
24 | GPIOC_TOGGLE, | |
a972b8d7 MF |
25 | }; |
26 | ||
95a260a9 | 27 | #if defined(CONFIG_DM_GPIO) && !defined(gpio_status) |
95a260a9 | 28 | |
89e64054 SG |
29 | /* A few flags used by show_gpio() */ |
30 | enum { | |
31 | FLAG_SHOW_ALL = 1 << 0, | |
32 | FLAG_SHOW_BANK = 1 << 1, | |
33 | FLAG_SHOW_NEWLINE = 1 << 2, | |
34 | }; | |
35 | ||
0757535a | 36 | static void gpio_get_description(struct udevice *dev, const char *bank_name, |
b8989b53 | 37 | int offset, int *flagsp, bool show_all) |
95a260a9 | 38 | { |
95a260a9 SG |
39 | char buf[80]; |
40 | int ret; | |
41 | ||
0757535a SG |
42 | ret = gpio_get_function(dev, offset, NULL); |
43 | if (ret < 0) | |
44 | goto err; | |
b8989b53 | 45 | if (!show_all && !(*flagsp & FLAG_SHOW_ALL) && ret == GPIOF_UNUSED) |
89e64054 SG |
46 | return; |
47 | if ((*flagsp & FLAG_SHOW_BANK) && bank_name) { | |
48 | if (*flagsp & FLAG_SHOW_NEWLINE) { | |
49 | putc('\n'); | |
50 | *flagsp &= ~FLAG_SHOW_NEWLINE; | |
51 | } | |
52 | printf("Bank %s:\n", bank_name); | |
53 | *flagsp &= ~FLAG_SHOW_BANK; | |
54 | } | |
95a260a9 | 55 | |
0757535a SG |
56 | ret = gpio_get_status(dev, offset, buf, sizeof(buf)); |
57 | if (ret) | |
58 | goto err; | |
59 | ||
60 | printf("%s\n", buf); | |
61 | return; | |
62 | err: | |
63 | printf("Error %d\n", ret); | |
95a260a9 SG |
64 | } |
65 | ||
89e64054 | 66 | static int do_gpio_status(bool all, const char *gpio_name) |
95a260a9 | 67 | { |
54c5d08a | 68 | struct udevice *dev; |
89e64054 SG |
69 | int banklen; |
70 | int flags; | |
95a260a9 SG |
71 | int ret; |
72 | ||
89e64054 | 73 | flags = 0; |
95a260a9 SG |
74 | if (gpio_name && !*gpio_name) |
75 | gpio_name = NULL; | |
76 | for (ret = uclass_first_device(UCLASS_GPIO, &dev); | |
77 | dev; | |
78 | ret = uclass_next_device(&dev)) { | |
79 | const char *bank_name; | |
80 | int num_bits; | |
81 | ||
89e64054 SG |
82 | flags |= FLAG_SHOW_BANK; |
83 | if (all) | |
84 | flags |= FLAG_SHOW_ALL; | |
95a260a9 | 85 | bank_name = gpio_get_bank_info(dev, &num_bits); |
0757535a SG |
86 | if (!num_bits) { |
87 | debug("GPIO device %s has no bits\n", dev->name); | |
89e64054 | 88 | continue; |
0757535a | 89 | } |
89e64054 | 90 | banklen = bank_name ? strlen(bank_name) : 0; |
95a260a9 SG |
91 | |
92 | if (!gpio_name || !bank_name || | |
48ca6909 | 93 | !strncasecmp(gpio_name, bank_name, banklen)) { |
95a260a9 SG |
94 | const char *p = NULL; |
95 | int offset; | |
96 | ||
89e64054 SG |
97 | p = gpio_name + banklen; |
98 | if (gpio_name && *p) { | |
95a260a9 | 99 | offset = simple_strtoul(p, NULL, 10); |
0757535a | 100 | gpio_get_description(dev, bank_name, offset, |
b8989b53 | 101 | &flags, true); |
95a260a9 | 102 | } else { |
89e64054 | 103 | for (offset = 0; offset < num_bits; offset++) { |
0757535a | 104 | gpio_get_description(dev, bank_name, |
b8989b53 | 105 | offset, &flags, false); |
89e64054 | 106 | } |
95a260a9 SG |
107 | } |
108 | } | |
89e64054 SG |
109 | /* Add a newline between bank names */ |
110 | if (!(flags & FLAG_SHOW_BANK)) | |
111 | flags |= FLAG_SHOW_NEWLINE; | |
95a260a9 SG |
112 | } |
113 | ||
114 | return ret; | |
115 | } | |
116 | #endif | |
117 | ||
a972b8d7 MF |
118 | static int do_gpio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
119 | { | |
95a260a9 | 120 | unsigned int gpio; |
a972b8d7 | 121 | enum gpio_cmd sub_cmd; |
b71bea71 | 122 | int value; |
95a260a9 | 123 | const char *str_cmd, *str_gpio = NULL; |
9165e842 | 124 | int ret; |
95a260a9 | 125 | #ifdef CONFIG_DM_GPIO |
89e64054 | 126 | bool all = false; |
95a260a9 | 127 | #endif |
a972b8d7 | 128 | |
95a260a9 SG |
129 | if (argc < 2) |
130 | show_usage: | |
131 | return CMD_RET_USAGE; | |
132 | str_cmd = argv[1]; | |
89e64054 SG |
133 | argc -= 2; |
134 | argv += 2; | |
135 | #ifdef CONFIG_DM_GPIO | |
136 | if (argc > 0 && !strcmp(*argv, "-a")) { | |
137 | all = true; | |
138 | argc--; | |
139 | argv++; | |
140 | } | |
141 | #endif | |
142 | if (argc > 0) | |
143 | str_gpio = *argv; | |
4c80c53c | 144 | if (!strncmp(str_cmd, "status", 2)) { |
95a260a9 | 145 | /* Support deprecated gpio_status() */ |
a972b8d7 | 146 | #ifdef gpio_status |
a972b8d7 MF |
147 | gpio_status(); |
148 | return 0; | |
95a260a9 | 149 | #elif defined(CONFIG_DM_GPIO) |
89e64054 | 150 | return cmd_process_error(cmdtp, do_gpio_status(all, str_gpio)); |
95a260a9 SG |
151 | #else |
152 | goto show_usage; | |
a972b8d7 | 153 | #endif |
95a260a9 | 154 | } |
a972b8d7 | 155 | |
95a260a9 SG |
156 | if (!str_gpio) |
157 | goto show_usage; | |
a972b8d7 MF |
158 | |
159 | /* parse the behavior */ | |
160 | switch (*str_cmd) { | |
66f657d1 SG |
161 | case 'i': |
162 | sub_cmd = GPIOC_INPUT; | |
163 | break; | |
164 | case 's': | |
165 | sub_cmd = GPIOC_SET; | |
166 | break; | |
167 | case 'c': | |
168 | sub_cmd = GPIOC_CLEAR; | |
169 | break; | |
170 | case 't': | |
171 | sub_cmd = GPIOC_TOGGLE; | |
172 | break; | |
173 | default: | |
174 | goto show_usage; | |
a972b8d7 MF |
175 | } |
176 | ||
95a260a9 SG |
177 | #if defined(CONFIG_DM_GPIO) |
178 | /* | |
179 | * TODO([email protected]): For now we must fit into the existing GPIO | |
180 | * framework, so we look up the name here and convert it to a GPIO number. | |
181 | * Once all GPIO drivers are converted to driver model, we can change the | |
182 | * code here to use the GPIO uclass interface instead of the numbered | |
183 | * GPIO compatibility layer. | |
184 | */ | |
185 | ret = gpio_lookup_name(str_gpio, NULL, NULL, &gpio); | |
66280e82 SG |
186 | if (ret) { |
187 | printf("GPIO: '%s' not found\n", str_gpio); | |
95a260a9 | 188 | return cmd_process_error(cmdtp, ret); |
66280e82 | 189 | } |
95a260a9 | 190 | #else |
a972b8d7 MF |
191 | /* turn the gpio name into a gpio number */ |
192 | gpio = name_to_gpio(str_gpio); | |
193 | if (gpio < 0) | |
194 | goto show_usage; | |
95a260a9 | 195 | #endif |
a972b8d7 | 196 | /* grab the pin before we tweak it */ |
9165e842 SG |
197 | ret = gpio_request(gpio, "cmd_gpio"); |
198 | if (ret && ret != -EBUSY) { | |
6801201e MF |
199 | printf("gpio: requesting pin %u failed\n", gpio); |
200 | return -1; | |
201 | } | |
a972b8d7 MF |
202 | |
203 | /* finally, let's do it: set direction and exec command */ | |
66f657d1 | 204 | if (sub_cmd == GPIOC_INPUT) { |
a972b8d7 MF |
205 | gpio_direction_input(gpio); |
206 | value = gpio_get_value(gpio); | |
207 | } else { | |
208 | switch (sub_cmd) { | |
66f657d1 | 209 | case GPIOC_SET: |
b71bea71 SG |
210 | value = 1; |
211 | break; | |
66f657d1 | 212 | case GPIOC_CLEAR: |
b71bea71 SG |
213 | value = 0; |
214 | break; | |
66f657d1 | 215 | case GPIOC_TOGGLE: |
b71bea71 SG |
216 | value = gpio_get_value(gpio); |
217 | if (!IS_ERR_VALUE(value)) | |
218 | value = !value; | |
219 | break; | |
220 | default: | |
221 | goto show_usage; | |
a972b8d7 MF |
222 | } |
223 | gpio_direction_output(gpio, value); | |
224 | } | |
b1970013 | 225 | printf("gpio: pin %s (gpio %u) value is ", str_gpio, gpio); |
b71bea71 SG |
226 | if (IS_ERR_VALUE(value)) |
227 | printf("unknown (ret=%d)\n", value); | |
228 | else | |
229 | printf("%d\n", value); | |
66f657d1 | 230 | if (sub_cmd != GPIOC_INPUT && !IS_ERR_VALUE(value)) { |
b71bea71 SG |
231 | int nval = gpio_get_value(gpio); |
232 | ||
233 | if (IS_ERR_VALUE(nval)) | |
234 | printf(" Warning: no access to GPIO output value\n"); | |
235 | else if (nval != value) | |
236 | printf(" Warning: value of pin is still %d\n", nval); | |
237 | } | |
a972b8d7 | 238 | |
9165e842 SG |
239 | if (ret != -EBUSY) |
240 | gpio_free(gpio); | |
a972b8d7 MF |
241 | |
242 | return value; | |
243 | } | |
244 | ||
89e64054 SG |
245 | U_BOOT_CMD(gpio, 4, 0, do_gpio, |
246 | "query and control gpio pins", | |
247 | "<input|set|clear|toggle> <pin>\n" | |
248 | " - input/set/clear/toggle the specified pin\n" | |
249 | "gpio status [-a] [<bank> | <pin>] - show [all/claimed] GPIOs"); |