ARM: OMAP: Use gpiolib

Update OMAP to use the new GPIO implementation framework.  This is just a
quick'n'dirty update ... more code could now be removed, ideally as part
of cleaning up the entire OMAP GPIO infrastructure ...

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Tony Lindgren <tony@atomide.com>



diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c
index 8c78e4e..56889fd 100644
--- a/arch/arm/plat-omap/gpio.c
+++ b/arch/arm/plat-omap/gpio.c
@@ -136,7 +136,6 @@
 	u16 irq;
 	u16 virtual_irq_start;
 	int method;
-	u32 reserved_map;
 #if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
 	u32 suspend_wakeup;
 	u32 saved_wakeup;
@@ -150,6 +149,7 @@
 	u32 saved_risingdetect;
 #endif
 	spinlock_t lock;
+	struct gpio_chip chip;
 };
 
 #define METHOD_MPUIO		0
@@ -903,19 +903,17 @@
 {
 	struct gpio_bank *bank;
 	unsigned long flags;
+	int status;
 
 	if (check_gpio(gpio) < 0)
 		return -EINVAL;
 
+	status = gpio_request(gpio, NULL);
+	if (status < 0)
+		return status;
+
 	bank = get_gpio_bank(gpio);
 	spin_lock_irqsave(&bank->lock, flags);
-	if (unlikely(bank->reserved_map & (1 << get_gpio_index(gpio)))) {
-		printk(KERN_ERR "omap-gpio: GPIO %d is already reserved!\n", gpio);
-		dump_stack();
-		spin_unlock_irqrestore(&bank->lock, flags);
-		return -1;
-	}
-	bank->reserved_map |= (1 << get_gpio_index(gpio));
 
 	/* Set trigger to none. You need to enable the desired trigger with
 	 * request_irq() or set_irq_type().
@@ -945,10 +943,11 @@
 		return;
 	bank = get_gpio_bank(gpio);
 	spin_lock_irqsave(&bank->lock, flags);
-	if (unlikely(!(bank->reserved_map & (1 << get_gpio_index(gpio))))) {
+	if (unlikely(!gpiochip_is_requested(&bank->chip,
+				get_gpio_index(gpio)))) {
+		spin_unlock_irqrestore(&bank->lock, flags);
 		printk(KERN_ERR "omap-gpio: GPIO %d wasn't reserved!\n", gpio);
 		dump_stack();
-		spin_unlock_irqrestore(&bank->lock, flags);
 		return;
 	}
 #ifdef CONFIG_ARCH_OMAP16XX
@@ -965,9 +964,9 @@
 		__raw_writel(1 << get_gpio_index(gpio), reg);
 	}
 #endif
-	bank->reserved_map &= ~(1 << get_gpio_index(gpio));
 	_reset_gpio(bank, gpio);
 	spin_unlock_irqrestore(&bank->lock, flags);
+	gpio_free(gpio);
 }
 
 /*
@@ -1266,6 +1265,53 @@
 
 /*---------------------------------------------------------------------*/
 
+/* REVISIT these are stupid implementations!  replace by ones that
+ * don't switch on METHOD_* and which mostly avoid spinlocks
+ */
+
+static int gpio_input(struct gpio_chip *chip, unsigned offset)
+{
+	struct gpio_bank *bank;
+	unsigned long flags;
+
+	bank = container_of(chip, struct gpio_bank, chip);
+	spin_lock_irqsave(&bank->lock, flags);
+	_set_gpio_direction(bank, offset, 1);
+	spin_unlock_irqrestore(&bank->lock, flags);
+	return 0;
+}
+
+static int gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	return omap_get_gpio_datain(chip->base + offset);
+}
+
+static int gpio_output(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct gpio_bank *bank;
+	unsigned long flags;
+
+	bank = container_of(chip, struct gpio_bank, chip);
+	spin_lock_irqsave(&bank->lock, flags);
+	_set_gpio_dataout(bank, offset, value);
+	_set_gpio_direction(bank, offset, 0);
+	spin_unlock_irqrestore(&bank->lock, flags);
+	return 0;
+}
+
+static void gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct gpio_bank *bank;
+	unsigned long flags;
+
+	bank = container_of(chip, struct gpio_bank, chip);
+	spin_lock_irqsave(&bank->lock, flags);
+	_set_gpio_dataout(bank, offset, value);
+	spin_unlock_irqrestore(&bank->lock, flags);
+}
+
+/*---------------------------------------------------------------------*/
+
 static int initialized;
 #if !defined(CONFIG_ARCH_OMAP3)
 static struct clk * gpio_ick;
@@ -1293,6 +1339,7 @@
 static int __init _omap_gpio_init(void)
 {
 	int i;
+	int gpio = 0;
 	struct gpio_bank *bank;
 #if defined(CONFIG_ARCH_OMAP3)
 	char clk_name[11];
@@ -1423,7 +1470,6 @@
 		int j, gpio_count = 16;
 
 		bank = &gpio_bank[i];
-		bank->reserved_map = 0;
 		bank->base = IO_ADDRESS(bank->base);
 		spin_lock_init(&bank->lock);
 		if (bank_is_mpuio(bank))
@@ -1461,6 +1507,26 @@
 			gpio_count = 32;
 		}
 #endif
+
+		/* REVISIT eventually switch from OMAP-specific gpio structs
+		 * over to the generic ones
+		 */
+		bank->chip.direction_input = gpio_input;
+		bank->chip.get = gpio_get;
+		bank->chip.direction_output = gpio_output;
+		bank->chip.set = gpio_set;
+		if (bank_is_mpuio(bank)) {
+			bank->chip.label = "mpuio";
+			bank->chip.base = OMAP_MPUIO(0);
+		} else {
+			bank->chip.label = "gpio";
+			bank->chip.base = gpio;
+			gpio += gpio_count;
+		}
+		bank->chip.ngpio = gpio_count;
+
+		gpiochip_add(&bank->chip);
+
 		for (j = bank->virtual_irq_start;
 		     j < bank->virtual_irq_start + gpio_count; j++) {
 			lockdep_set_class(&irq_desc[j].lock, &gpio_lock_class);
@@ -1757,8 +1823,10 @@
 
 		for (j = 0; j < bankwidth; j++, gpio++, mask <<= 1) {
 			unsigned	irq, value, is_in, irqstat;
+			const char	*label;
 
-			if (!(bank->reserved_map & mask))
+			label = gpiochip_is_requested(&bank->chip, j);
+			if (!label)
 				continue;
 
 			irq = bank->virtual_irq_start + j;
@@ -1766,13 +1834,16 @@
 			is_in = gpio_is_input(bank, mask);
 
 			if (bank_is_mpuio(bank))
-				seq_printf(s, "MPUIO %2d: ", j);
+				seq_printf(s, "MPUIO %2d ", j);
 			else
-				seq_printf(s, "GPIO %3d: ", gpio);
-			seq_printf(s, "%s %s",
+				seq_printf(s, "GPIO %3d ", gpio);
+			seq_printf(s, "(%10s): %s %s",
+					label,
 					is_in ? "in " : "out",
 					value ? "hi"  : "lo");
 
+/* FIXME for at least omap2, show pullup/pulldown state */
+
 			irqstat = irq_desc[irq].status;
 			if (is_in && ((bank->suspend_wakeup & mask)
 					|| irqstat & IRQ_TYPE_SENSE_MASK)) {
@@ -1795,10 +1866,10 @@
 					trigger = "high";
 					break;
 				case IRQ_TYPE_NONE:
-					trigger = "(unspecified)";
+					trigger = "(?)";
 					break;
 				}
-				seq_printf(s, ", irq-%d %s%s",
+				seq_printf(s, ", irq-%d %-8s%s",
 						irq, trigger,
 						(bank->suspend_wakeup & mask)
 							? " wakeup" : "");