gpio: generalize for all generic gpio providers

The Blackfin gpio command isn't terribly Blackfin-specific.  So generalize
the few pieces into two new optional helpers:
	name_to_gpio() - turn a string name into a GPIO #
	gpio_status() - display current pin bindings (think /proc/gpio)

Once these pieces are pulled out, we can relocate the cmd_gpio.c into the
common directory.

Signed-off-by: Mike Frysinger <vapier@gentoo.org>
diff --git a/common/Makefile b/common/Makefile
index 26380c6..432a9de 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -98,6 +98,7 @@
 ifdef CONFIG_FPGA
 COBJS-$(CONFIG_CMD_FPGA) += cmd_fpga.o
 endif
+COBJS-$(CONFIG_CMD_GPIO) += cmd_gpio.o
 COBJS-$(CONFIG_CMD_I2C) += cmd_i2c.o
 COBJS-$(CONFIG_CMD_IDE) += cmd_ide.o
 COBJS-$(CONFIG_CMD_IMMAP) += cmd_immap.o
diff --git a/common/cmd_gpio.c b/common/cmd_gpio.c
new file mode 100644
index 0000000..9c9de28
--- /dev/null
+++ b/common/cmd_gpio.c
@@ -0,0 +1,86 @@
+/*
+ * Control GPIO pins on the fly
+ *
+ * Copyright (c) 2008-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+#include <command.h>
+
+#include <asm/gpio.h>
+
+#ifndef name_to_gpio
+#define name_to_gpio(name) simple_strtoul(name, NULL, 10)
+#endif
+
+enum gpio_cmd {
+	GPIO_INPUT,
+	GPIO_SET,
+	GPIO_CLEAR,
+	GPIO_TOGGLE,
+};
+
+static int do_gpio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	int gpio;
+	enum gpio_cmd sub_cmd;
+	ulong value;
+	const char *str_cmd, *str_gpio;
+
+#ifdef gpio_status
+	if (argc == 2 && !strcmp(argv[1], "status")) {
+		gpio_status();
+		return 0;
+	}
+#endif
+
+	if (argc != 3)
+ show_usage:
+		return cmd_usage(cmdtp);
+	str_cmd = argv[1];
+	str_gpio = argv[2];
+
+	/* parse the behavior */
+	switch (*str_cmd) {
+		case 'i': sub_cmd = GPIO_INPUT;  break;
+		case 's': sub_cmd = GPIO_SET;    break;
+		case 'c': sub_cmd = GPIO_CLEAR;  break;
+		case 't': sub_cmd = GPIO_TOGGLE; break;
+		default:  goto show_usage;
+	}
+
+	/* turn the gpio name into a gpio number */
+	gpio = name_to_gpio(str_gpio);
+	if (gpio < 0)
+		goto show_usage;
+
+	/* grab the pin before we tweak it */
+	gpio_request(gpio, "cmd_gpio");
+
+	/* finally, let's do it: set direction and exec command */
+	if (sub_cmd == GPIO_INPUT) {
+		gpio_direction_input(gpio);
+		value = gpio_get_value(gpio);
+	} else {
+		switch (sub_cmd) {
+			case GPIO_SET:    value = 1; break;
+			case GPIO_CLEAR:  value = 0; break;
+			case GPIO_TOGGLE: value = !gpio_get_value(gpio); break;
+			default:          goto show_usage;
+		}
+		gpio_direction_output(gpio, value);
+	}
+	printf("gpio: pin %s (gpio %i) value is %lu\n",
+		str_gpio, gpio, value);
+
+	gpio_free(gpio);
+
+	return value;
+}
+
+U_BOOT_CMD(gpio, 3, 0, do_gpio,
+	"input/set/clear/toggle gpio pins",
+	"<input|set|clear|toggle> <pin>\n"
+	"    - input/set/clear/toggle the specified pin");