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