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
27enum 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() */
40enum {
41	FLAG_SHOW_ALL		= 1 << 0,
42	FLAG_SHOW_BANK		= 1 << 1,
43	FLAG_SHOW_NEWLINE	= 1 << 2,
44};
45
46static 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;
72err:
73	if (ret != -ENOENT)
74		printf("Error %d\n", ret);
75}
76
77static 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
136static 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(sjg@chromium.org): 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
304err:
305	if (ret != -EBUSY)
306		gpio_free(gpio);
307	return CMD_RET_FAILURE;
308}
309
310U_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");
319