[ARM] 5373/2: Add gpiolib support to AT91

Add support for gpiolib, including debugfs output, to the AT91 family.
The at91_get/set_gpio_value calls still exist since they are used by the
atmel serial driver.

Signed-off-by: Ryan Mallon <ryan@bluewatersys.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c
index 9b0447c..028e4f7 100644
--- a/arch/arm/mach-at91/gpio.c
+++ b/arch/arm/mach-at91/gpio.c
@@ -24,19 +24,59 @@
 #include <mach/at91_pio.h>
 #include <mach/gpio.h>
 
+#include <asm/gpio.h>
+
 #include "generic.h"
 
+struct at91_gpio_chip {
+	struct gpio_chip	chip;
+	struct at91_gpio_chip	*next;		/* Bank sharing same clock */
+	struct at91_gpio_bank	*bank;		/* Bank definition */
+	void __iomem		*regbase;	/* Base of register bank */
+};
 
-static struct at91_gpio_bank *gpio;
+#define to_at91_gpio_chip(c) container_of(c, struct at91_gpio_chip, chip)
+
+static void at91_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip);
+static void at91_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val);
+static int at91_gpiolib_get(struct gpio_chip *chip, unsigned offset);
+static int at91_gpiolib_direction_output(struct gpio_chip *chip,
+					 unsigned offset, int val);
+static int at91_gpiolib_direction_input(struct gpio_chip *chip,
+					unsigned offset);
+static int at91_gpiolib_request(struct gpio_chip *chip, unsigned offset);
+
+#define AT91_GPIO_CHIP(name, base_gpio, nr_gpio)			\
+	{								\
+		.chip = {						\
+			.label		  = name,			\
+			.request	  = at91_gpiolib_request,	\
+			.direction_input  = at91_gpiolib_direction_input, \
+			.direction_output = at91_gpiolib_direction_output, \
+			.get		  = at91_gpiolib_get,		\
+			.set		  = at91_gpiolib_set,		\
+			.dbg_show	  = at91_gpiolib_dbg_show,	\
+			.base		  = base_gpio,			\
+			.ngpio		  = nr_gpio,			\
+		},							\
+	}
+
+static struct at91_gpio_chip gpio_chip[] = {
+	AT91_GPIO_CHIP("A", 0x00 + PIN_BASE, 32),
+	AT91_GPIO_CHIP("B", 0x20 + PIN_BASE, 32),
+	AT91_GPIO_CHIP("C", 0x40 + PIN_BASE, 32),
+	AT91_GPIO_CHIP("D", 0x60 + PIN_BASE, 32),
+	AT91_GPIO_CHIP("E", 0x80 + PIN_BASE, 32),
+};
+
 static int gpio_banks;
 
-
 static inline void __iomem *pin_to_controller(unsigned pin)
 {
 	pin -= PIN_BASE;
 	pin /= 32;
 	if (likely(pin < gpio_banks))
-		return gpio[pin].regbase;
+		return gpio_chip[pin].regbase;
 
 	return NULL;
 }
@@ -197,39 +237,6 @@
 }
 EXPORT_SYMBOL(at91_set_multi_drive);
 
-/*--------------------------------------------------------------------------*/
-
-/* new-style GPIO calls; these expect at91_set_GPIO_periph to have been
- * called, and maybe at91_set_multi_drive() for putout pins.
- */
-
-int gpio_direction_input(unsigned pin)
-{
-	void __iomem	*pio = pin_to_controller(pin);
-	unsigned	mask = pin_to_mask(pin);
-
-	if (!pio || !(__raw_readl(pio + PIO_PSR) & mask))
-		return -EINVAL;
-	__raw_writel(mask, pio + PIO_ODR);
-	return 0;
-}
-EXPORT_SYMBOL(gpio_direction_input);
-
-int gpio_direction_output(unsigned pin, int value)
-{
-	void __iomem	*pio = pin_to_controller(pin);
-	unsigned	mask = pin_to_mask(pin);
-
-	if (!pio || !(__raw_readl(pio + PIO_PSR) & mask))
-		return -EINVAL;
-	__raw_writel(mask, pio + (value ? PIO_SODR : PIO_CODR));
-	__raw_writel(mask, pio + PIO_OER);
-	return 0;
-}
-EXPORT_SYMBOL(gpio_direction_output);
-
-/*--------------------------------------------------------------------------*/
-
 /*
  * assuming the pin is muxed as a gpio output, set its value.
  */
@@ -282,7 +289,7 @@
 	else
 		wakeups[bank] &= ~mask;
 
-	set_irq_wake(gpio[bank].id, state);
+	set_irq_wake(gpio_chip[bank].bank->id, state);
 
 	return 0;
 }
@@ -292,14 +299,14 @@
 	int i;
 
 	for (i = 0; i < gpio_banks; i++) {
-		void __iomem	*pio = gpio[i].regbase;
+		void __iomem	*pio = gpio_chip[i].regbase;
 
 		backups[i] = __raw_readl(pio + PIO_IMR);
 		__raw_writel(backups[i], pio + PIO_IDR);
 		__raw_writel(wakeups[i], pio + PIO_IER);
 
 		if (!wakeups[i])
-			clk_disable(gpio[i].clock);
+			clk_disable(gpio_chip[i].bank->clock);
 		else {
 #ifdef CONFIG_PM_DEBUG
 			printk(KERN_DEBUG "GPIO-%c may wake for %08x\n", 'A'+i, wakeups[i]);
@@ -313,10 +320,10 @@
 	int i;
 
 	for (i = 0; i < gpio_banks; i++) {
-		void __iomem	*pio = gpio[i].regbase;
+		void __iomem	*pio = gpio_chip[i].regbase;
 
 		if (!wakeups[i])
-			clk_enable(gpio[i].clock);
+			clk_enable(gpio_chip[i].bank->clock);
 
 		__raw_writel(wakeups[i], pio + PIO_IDR);
 		__raw_writel(backups[i], pio + PIO_IER);
@@ -380,12 +387,12 @@
 {
 	unsigned	pin;
 	struct irq_desc	*gpio;
-	struct at91_gpio_bank *bank;
+	struct at91_gpio_chip *at91_gpio;
 	void __iomem	*pio;
 	u32		isr;
 
-	bank = get_irq_chip_data(irq);
-	pio = bank->regbase;
+	at91_gpio = get_irq_chip_data(irq);
+	pio = at91_gpio->regbase;
 
 	/* temporarily mask (level sensitive) parent IRQ */
 	desc->chip->ack(irq);
@@ -396,14 +403,14 @@
 		 */
 		isr = __raw_readl(pio + PIO_ISR) & __raw_readl(pio + PIO_IMR);
 		if (!isr) {
-			if (!bank->next)
+			if (!at91_gpio->next)
 				break;
-			bank = bank->next;
-			pio = bank->regbase;
+			at91_gpio = at91_gpio->next;
+			pio = at91_gpio->regbase;
 			continue;
 		}
 
-		pin = bank->chipbase;
+		pin = at91_gpio->chip.base;
 		gpio = &irq_desc[pin];
 
 		while (isr) {
@@ -430,66 +437,6 @@
 
 /*--------------------------------------------------------------------------*/
 
-#ifdef CONFIG_DEBUG_FS
-
-static int at91_gpio_show(struct seq_file *s, void *unused)
-{
-	int bank, j;
-
-	/* print heading */
-	seq_printf(s, "Pin\t");
-	for (bank = 0; bank < gpio_banks; bank++) {
-		seq_printf(s, "PIO%c\t", 'A' + bank);
-	};
-	seq_printf(s, "\n\n");
-
-	/* print pin status */
-	for (j = 0; j < 32; j++) {
-		seq_printf(s, "%i:\t", j);
-
-		for (bank = 0; bank < gpio_banks; bank++) {
-			unsigned	pin  = PIN_BASE + (32 * bank) + j;
-			void __iomem	*pio = pin_to_controller(pin);
-			unsigned	mask = pin_to_mask(pin);
-
-			if (__raw_readl(pio + PIO_PSR) & mask)
-				seq_printf(s, "GPIO:%s", __raw_readl(pio + PIO_PDSR) & mask ? "1" : "0");
-			else
-				seq_printf(s, "%s", __raw_readl(pio + PIO_ABSR) & mask ? "B" : "A");
-
-			seq_printf(s, "\t");
-		}
-
-		seq_printf(s, "\n");
-	}
-
-	return 0;
-}
-
-static int at91_gpio_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, at91_gpio_show, NULL);
-}
-
-static const struct file_operations at91_gpio_operations = {
-	.open		= at91_gpio_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-static int __init at91_gpio_debugfs_init(void)
-{
-	/* /sys/kernel/debug/at91_gpio */
-	(void) debugfs_create_file("at91_gpio", S_IFREG | S_IRUGO, NULL, NULL, &at91_gpio_operations);
-	return 0;
-}
-postcore_initcall(at91_gpio_debugfs_init);
-
-#endif
-
-/*--------------------------------------------------------------------------*/
-
 /* This lock class tells lockdep that GPIO irqs are in a different
  * category than their parents, so it won't report false recursion.
  */
@@ -501,20 +448,20 @@
 void __init at91_gpio_irq_setup(void)
 {
 	unsigned		pioc, pin;
-	struct at91_gpio_bank	*this, *prev;
+	struct at91_gpio_chip	*this, *prev;
 
-	for (pioc = 0, pin = PIN_BASE, this = gpio, prev = NULL;
+	for (pioc = 0, pin = PIN_BASE, this = gpio_chip, prev = NULL;
 			pioc++ < gpio_banks;
 			prev = this, this++) {
-		unsigned	id = this->id;
+		unsigned	id = this->bank->id;
 		unsigned	i;
 
 		/* enable PIO controller's clock */
-		clk_enable(this->clock);
+		clk_enable(this->bank->clock);
 
 		__raw_writel(~0, this->regbase + PIO_IDR);
 
-		for (i = 0, pin = this->chipbase; i < 32; i++, pin++) {
+		for (i = 0, pin = this->chip.base; i < 32; i++, pin++) {
 			lockdep_set_class(&irq_desc[pin].lock, &gpio_lock_class);
 
 			/*
@@ -539,25 +486,114 @@
 	pr_info("AT91: %d gpio irqs in %d banks\n", pin - PIN_BASE, gpio_banks);
 }
 
+/* gpiolib support */
+static int at91_gpiolib_direction_input(struct gpio_chip *chip,
+					unsigned offset)
+{
+	struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+	void __iomem *pio = at91_gpio->regbase;
+	unsigned mask = 1 << offset;
+
+	__raw_writel(mask, pio + PIO_ODR);
+	return 0;
+}
+
+static int at91_gpiolib_direction_output(struct gpio_chip *chip,
+					 unsigned offset, int val)
+{
+	struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+	void __iomem *pio = at91_gpio->regbase;
+	unsigned mask = 1 << offset;
+
+	__raw_writel(mask, pio + (val ? PIO_SODR : PIO_CODR));
+	__raw_writel(mask, pio + PIO_OER);
+	return 0;
+}
+
+static int at91_gpiolib_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+	void __iomem *pio = at91_gpio->regbase;
+	unsigned mask = 1 << offset;
+	u32 pdsr;
+
+	pdsr = __raw_readl(pio + PIO_PDSR);
+	return (pdsr & mask) != 0;
+}
+
+static void at91_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val)
+{
+	struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+	void __iomem *pio = at91_gpio->regbase;
+	unsigned mask = 1 << offset;
+
+	__raw_writel(mask, pio + (val ? PIO_SODR : PIO_CODR));
+}
+
+static int at91_gpiolib_request(struct gpio_chip *chip, unsigned offset)
+{
+	unsigned pin = chip->base + offset;
+	void __iomem *pio = pin_to_controller(pin);
+	unsigned mask = pin_to_mask(pin);
+
+	/* Cannot request GPIOs that are in alternate function mode */
+	if (!(__raw_readl(pio + PIO_PSR) & mask))
+		return -EPERM;
+
+	return 0;
+}
+
+static void at91_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+	int i;
+
+	for (i = 0; i < chip->ngpio; i++) {
+		unsigned pin = chip->base + i;
+		void __iomem *pio = pin_to_controller(pin);
+		unsigned mask = pin_to_mask(pin);
+		const char *gpio_label;
+
+		gpio_label = gpiochip_is_requested(chip, i);
+		if (gpio_label) {
+			seq_printf(s, "[%s] GPIO%s%d: ",
+				   gpio_label, chip->label, i);
+			if (__raw_readl(pio + PIO_PSR) & mask)
+				seq_printf(s, "[gpio] %s\n",
+					   at91_get_gpio_value(pin) ?
+					   "set" : "clear");
+			else
+				seq_printf(s, "[periph %s]\n",
+					   __raw_readl(pio + PIO_ABSR) &
+					   mask ? "B" : "A");
+		}
+	}
+}
+
 /*
  * Called from the processor-specific init to enable GPIO pin support.
  */
 void __init at91_gpio_init(struct at91_gpio_bank *data, int nr_banks)
 {
 	unsigned		i;
-	struct at91_gpio_bank	*last;
+	struct at91_gpio_chip *at91_gpio, *last = NULL;
 
 	BUG_ON(nr_banks > MAX_GPIO_BANKS);
 
-	gpio = data;
 	gpio_banks = nr_banks;
 
-	for (i = 0, last = NULL; i < nr_banks; i++, last = data, data++) {
-		data->chipbase = PIN_BASE + i * 32;
-		data->regbase = data->offset + (void __iomem *)AT91_VA_BASE_SYS;
+	for (i = 0; i < nr_banks; i++) {
+		at91_gpio = &gpio_chip[i];
+
+		at91_gpio->bank = &data[i];
+		at91_gpio->chip.base = PIN_BASE + i * 32;
+		at91_gpio->regbase = at91_gpio->bank->offset +
+			(void __iomem *)AT91_VA_BASE_SYS;
 
 		/* AT91SAM9263_ID_PIOCDE groups PIOC, PIOD, PIOE */
-		if (last && last->id == data->id)
-			last->next = data;
+		if (last && last->bank->id == at91_gpio->bank->id)
+			last->next = at91_gpio;
+		last = at91_gpio;
+
+		gpiochip_add(&at91_gpio->chip);
 	}
 }