From 05ac6cbfecf9e9b0ab46ba5f30eec8ea91b2987c Mon Sep 17 00:00:00 2001
From: Haavard Skinnemoen <hskinnemoen@atmel.com>
Date: Mon, 13 Nov 2006 10:23:15 +0100
Subject: [AVR32] Implement arch-neutral GPIO API

AVR32 implementation of the arch-neutral GPIO API described by
Documentation/gpio.txt.

This also contains a few related changes to the irq handling and
pin configuration code, to make this actually usable.

Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
---
 arch/avr32/mach-at32ap/at32ap7000.c        |  144 ++++++++++------------
 arch/avr32/mach-at32ap/pio.c               |  186 +++++++++++++++++++++++++++--
 include/asm-avr32/arch-at32ap/at32ap7000.h |   26 ++++
 include/asm-avr32/arch-at32ap/gpio.h       |   39 ++++++
 include/asm-avr32/arch-at32ap/irq.h        |   11 +
 include/asm-avr32/arch-at32ap/portmux.h    |   16 --
 include/asm-avr32/gpio.h                   |    6 
 include/asm-avr32/irq.h                    |    8 -
 8 files changed, 333 insertions(+), 103 deletions(-)

Index: linux-2.6.18-avr32/arch/avr32/mach-at32ap/at32ap7000.c
===================================================================
--- linux-2.6.18-avr32.orig/arch/avr32/mach-at32ap/at32ap7000.c	2006-11-29 16:21:12.000000000 +0100
+++ linux-2.6.18-avr32/arch/avr32/mach-at32ap/at32ap7000.c	2006-11-29 16:22:14.000000000 +0100
@@ -11,8 +11,9 @@
 
 #include <asm/io.h>
 
+#include <asm/arch/at32ap7000.h>
 #include <asm/arch/board.h>
-#include <asm/arch/portmux.h>
+#include <asm/arch/gpio.h>
 #include <asm/arch/sm.h>
 
 #include "clock.h"
@@ -67,17 +68,8 @@ static struct clk devname##_##_name = {	
 	.index		= _index,				\
 }
 
-enum {
-	PIOA,
-	PIOB,
-	PIOC,
-	PIOD,
-};
-
-enum {
-	FUNC_A,
-	FUNC_B,
-};
+#define select_peripheral(pin, periph, pullup)				\
+	at32_select_periph(GPIO_PIN_##pin, GPIO_##periph, pullup)
 
 unsigned long at32ap7000_osc_rates[3] = {
 	[0] = 32768,
@@ -553,26 +545,26 @@ DEV_CLK(usart, usart3, pba, 6);
 
 static inline void configure_usart0_pins(void)
 {
-	portmux_set_func(PIOA,  8, FUNC_B);	/* RXD	*/
-	portmux_set_func(PIOA,  9, FUNC_B);	/* TXD	*/
+	select_peripheral(PA(8), PERIPH_B, 0);	/* RXD	*/
+	select_peripheral(PA(9), PERIPH_B, 0);	/* TXD	*/
 }
 
 static inline void configure_usart1_pins(void)
 {
-	portmux_set_func(PIOA, 17, FUNC_A);	/* RXD	*/
-	portmux_set_func(PIOA, 18, FUNC_A);	/* TXD	*/
+	select_peripheral(PA(17), PERIPH_A, 0);	/* RXD	*/
+	select_peripheral(PA(18), PERIPH_A, 0);	/* TXD	*/
 }
 
 static inline void configure_usart2_pins(void)
 {
-	portmux_set_func(PIOB, 26, FUNC_B);	/* RXD	*/
-	portmux_set_func(PIOB, 27, FUNC_B);	/* TXD	*/
+	select_peripheral(PB(26), PERIPH_B, 0);	/* RXD	*/
+	select_peripheral(PB(27), PERIPH_B, 0);	/* TXD	*/
 }
 
 static inline void configure_usart3_pins(void)
 {
-	portmux_set_func(PIOB, 18, FUNC_B);	/* RXD	*/
-	portmux_set_func(PIOB, 17, FUNC_B);	/* TXD	*/
+	select_peripheral(PB(18), PERIPH_B, 0);	/* RXD	*/
+	select_peripheral(PB(17), PERIPH_B, 0);	/* TXD	*/
 }
 
 static struct platform_device *setup_usart(unsigned int id)
@@ -644,27 +636,27 @@ at32_add_device_eth(unsigned int id, str
 	case 0:
 		pdev = &macb0_device;
 
-		portmux_set_func(PIOC,  3, FUNC_A);	/* TXD0	*/
-		portmux_set_func(PIOC,  4, FUNC_A);	/* TXD1	*/
-		portmux_set_func(PIOC,  7, FUNC_A);	/* TXEN	*/
-		portmux_set_func(PIOC,  8, FUNC_A);	/* TXCK */
-		portmux_set_func(PIOC,  9, FUNC_A);	/* RXD0	*/
-		portmux_set_func(PIOC, 10, FUNC_A);	/* RXD1	*/
-		portmux_set_func(PIOC, 13, FUNC_A);	/* RXER	*/
-		portmux_set_func(PIOC, 15, FUNC_A);	/* RXDV	*/
-		portmux_set_func(PIOC, 16, FUNC_A);	/* MDC	*/
-		portmux_set_func(PIOC, 17, FUNC_A);	/* MDIO	*/
+		select_peripheral(PC(3), PERIPH_A, 0);		/* TXD0	*/
+		select_peripheral(PC(4), PERIPH_A, 0);		/* TXD1	*/
+		select_peripheral(PC(7), PERIPH_A, 0);		/* TXEN	*/
+		select_peripheral(PC(8), PERIPH_A, 0);		/* TXCK */
+		select_peripheral(PC(9), PERIPH_A, 0);		/* RXD0	*/
+		select_peripheral(PC(10), PERIPH_A, 0);		/* RXD1	*/
+		select_peripheral(PC(13), PERIPH_A, 0);		/* RXER	*/
+		select_peripheral(PC(15), PERIPH_A, 0);		/* RXDV	*/
+		select_peripheral(PC(16), PERIPH_A, 0);		/* MDC	*/
+		select_peripheral(PC(17), PERIPH_A, 0);		/* MDIO	*/
 
 		if (!data->is_rmii) {
-			portmux_set_func(PIOC,  0, FUNC_A);	/* COL	*/
-			portmux_set_func(PIOC,  1, FUNC_A);	/* CRS	*/
-			portmux_set_func(PIOC,  2, FUNC_A);	/* TXER	*/
-			portmux_set_func(PIOC,  5, FUNC_A);	/* TXD2	*/
-			portmux_set_func(PIOC,  6, FUNC_A);	/* TXD3 */
-			portmux_set_func(PIOC, 11, FUNC_A);	/* RXD2	*/
-			portmux_set_func(PIOC, 12, FUNC_A);	/* RXD3	*/
-			portmux_set_func(PIOC, 14, FUNC_A);	/* RXCK	*/
-			portmux_set_func(PIOC, 18, FUNC_A);	/* SPD	*/
+			select_peripheral(PC(0), PERIPH_A, 0);	/* COL	*/
+			select_peripheral(PC(1), PERIPH_A, 0);	/* CRS	*/
+			select_peripheral(PC(2), PERIPH_A, 0);	/* TXER	*/
+			select_peripheral(PC(5), PERIPH_A, 0);	/* TXD2	*/
+			select_peripheral(PC(6), PERIPH_A, 0);	/* TXD3 */
+			select_peripheral(PC(11), PERIPH_A, 0);	/* RXD2	*/
+			select_peripheral(PC(12), PERIPH_A, 0);	/* RXD3	*/
+			select_peripheral(PC(14), PERIPH_A, 0);	/* RXCK	*/
+			select_peripheral(PC(18), PERIPH_A, 0);	/* SPD	*/
 		}
 		break;
 
@@ -695,12 +687,12 @@ struct platform_device *__init at32_add_
 	switch (id) {
 	case 0:
 		pdev = &spi0_device;
-		portmux_set_func(PIOA,  0, FUNC_A);	/* MISO	 */
-		portmux_set_func(PIOA,  1, FUNC_A);	/* MOSI	 */
-		portmux_set_func(PIOA,  2, FUNC_A);	/* SCK	 */
-		portmux_set_func(PIOA,  3, FUNC_A);	/* NPCS0 */
-		portmux_set_func(PIOA,  4, FUNC_A);	/* NPCS1 */
-		portmux_set_func(PIOA,  5, FUNC_A);	/* NPCS2 */
+		select_peripheral(PA(0), PERIPH_A, 0);	/* MISO	 */
+		select_peripheral(PA(1), PERIPH_A, 0);	/* MOSI	 */
+		select_peripheral(PA(2), PERIPH_A, 0);	/* SCK	 */
+		select_peripheral(PA(3), PERIPH_A, 0);	/* NPCS0 */
+		select_peripheral(PA(4), PERIPH_A, 0);	/* NPCS1 */
+		select_peripheral(PA(5), PERIPH_A, 0);	/* NPCS2 */
 		break;
 
 	default:
@@ -743,37 +735,37 @@ at32_add_device_lcdc(unsigned int id, st
 	switch (id) {
 	case 0:
 		pdev = &lcdc0_device;
-		portmux_set_func(PIOC, 19, FUNC_A);	/* CC	  */
-		portmux_set_func(PIOC, 20, FUNC_A);	/* HSYNC  */
-		portmux_set_func(PIOC, 21, FUNC_A);	/* PCLK	  */
-		portmux_set_func(PIOC, 22, FUNC_A);	/* VSYNC  */
-		portmux_set_func(PIOC, 23, FUNC_A);	/* DVAL	  */
-		portmux_set_func(PIOC, 24, FUNC_A);	/* MODE	  */
-		portmux_set_func(PIOC, 25, FUNC_A);	/* PWR	  */
-		portmux_set_func(PIOC, 26, FUNC_A);	/* DATA0  */
-		portmux_set_func(PIOC, 27, FUNC_A);	/* DATA1  */
-		portmux_set_func(PIOC, 28, FUNC_A);	/* DATA2  */
-		portmux_set_func(PIOC, 29, FUNC_A);	/* DATA3  */
-		portmux_set_func(PIOC, 30, FUNC_A);	/* DATA4  */
-		portmux_set_func(PIOC, 31, FUNC_A);	/* DATA5  */
-		portmux_set_func(PIOD,  0, FUNC_A);	/* DATA6  */
-		portmux_set_func(PIOD,  1, FUNC_A);	/* DATA7  */
-		portmux_set_func(PIOD,  2, FUNC_A);	/* DATA8  */
-		portmux_set_func(PIOD,  3, FUNC_A);	/* DATA9  */
-		portmux_set_func(PIOD,  4, FUNC_A);	/* DATA10 */
-		portmux_set_func(PIOD,  5, FUNC_A);	/* DATA11 */
-		portmux_set_func(PIOD,  6, FUNC_A);	/* DATA12 */
-		portmux_set_func(PIOD,  7, FUNC_A);	/* DATA13 */
-		portmux_set_func(PIOD,  8, FUNC_A);	/* DATA14 */
-		portmux_set_func(PIOD,  9, FUNC_A);	/* DATA15 */
-		portmux_set_func(PIOD, 10, FUNC_A);	/* DATA16 */
-		portmux_set_func(PIOD, 11, FUNC_A);	/* DATA17 */
-		portmux_set_func(PIOD, 12, FUNC_A);	/* DATA18 */
-		portmux_set_func(PIOD, 13, FUNC_A);	/* DATA19 */
-		portmux_set_func(PIOD, 14, FUNC_A);	/* DATA20 */
-		portmux_set_func(PIOD, 15, FUNC_A);	/* DATA21 */
-		portmux_set_func(PIOD, 16, FUNC_A);	/* DATA22 */
-		portmux_set_func(PIOD, 17, FUNC_A);	/* DATA23 */
+		select_peripheral(PC(19), PERIPH_A, 0);	/* CC	  */
+		select_peripheral(PC(20), PERIPH_A, 0);	/* HSYNC  */
+		select_peripheral(PC(21), PERIPH_A, 0);	/* PCLK	  */
+		select_peripheral(PC(22), PERIPH_A, 0);	/* VSYNC  */
+		select_peripheral(PC(23), PERIPH_A, 0);	/* DVAL	  */
+		select_peripheral(PC(24), PERIPH_A, 0);	/* MODE	  */
+		select_peripheral(PC(25), PERIPH_A, 0);	/* PWR	  */
+		select_peripheral(PC(26), PERIPH_A, 0);	/* DATA0  */
+		select_peripheral(PC(27), PERIPH_A, 0);	/* DATA1  */
+		select_peripheral(PC(28), PERIPH_A, 0);	/* DATA2  */
+		select_peripheral(PC(29), PERIPH_A, 0);	/* DATA3  */
+		select_peripheral(PC(30), PERIPH_A, 0);	/* DATA4  */
+		select_peripheral(PC(31), PERIPH_A, 0);	/* DATA5  */
+		select_peripheral(PD(0), PERIPH_A, 0);	/* DATA6  */
+		select_peripheral(PD(1), PERIPH_A, 0);	/* DATA7  */
+		select_peripheral(PD(2), PERIPH_A, 0);	/* DATA8  */
+		select_peripheral(PD(3), PERIPH_A, 0);	/* DATA9  */
+		select_peripheral(PD(4), PERIPH_A, 0);	/* DATA10 */
+		select_peripheral(PD(5), PERIPH_A, 0);	/* DATA11 */
+		select_peripheral(PD(6), PERIPH_A, 0);	/* DATA12 */
+		select_peripheral(PD(7), PERIPH_A, 0);	/* DATA13 */
+		select_peripheral(PD(8), PERIPH_A, 0);	/* DATA14 */
+		select_peripheral(PD(9), PERIPH_A, 0);	/* DATA15 */
+		select_peripheral(PD(10), PERIPH_A, 0);	/* DATA16 */
+		select_peripheral(PD(11), PERIPH_A, 0);	/* DATA17 */
+		select_peripheral(PD(12), PERIPH_A, 0);	/* DATA18 */
+		select_peripheral(PD(13), PERIPH_A, 0);	/* DATA19 */
+		select_peripheral(PD(14), PERIPH_A, 0);	/* DATA20 */
+		select_peripheral(PD(15), PERIPH_A, 0);	/* DATA21 */
+		select_peripheral(PD(16), PERIPH_A, 0);	/* DATA22 */
+		select_peripheral(PD(17), PERIPH_A, 0);	/* DATA23 */
 
 		clk_set_parent(&lcdc0_pixclk, &pll0);
 		clk_set_rate(&lcdc0_pixclk, clk_get_rate(&pll0));
Index: linux-2.6.18-avr32/arch/avr32/mach-at32ap/pio.c
===================================================================
--- linux-2.6.18-avr32.orig/arch/avr32/mach-at32ap/pio.c	2006-11-29 16:21:12.000000000 +0100
+++ linux-2.6.18-avr32/arch/avr32/mach-at32ap/pio.c	2006-11-29 16:22:14.000000000 +0100
@@ -13,10 +13,9 @@
 #include <linux/fs.h>
 #include <linux/platform_device.h>
 
+#include <asm/gpio.h>
 #include <asm/io.h>
 
-#include <asm/arch/portmux.h>
-
 #include "pio.h"
 
 #define MAX_NR_PIO_DEVICES		8
@@ -25,28 +24,191 @@ struct pio_device {
 	void __iomem *regs;
 	const struct platform_device *pdev;
 	struct clk *clk;
-	u32 alloc_mask;
+	u32 pinmux_mask;
+	u32 gpio_mask;
 	char name[32];
 };
 
 static struct pio_device pio_dev[MAX_NR_PIO_DEVICES];
 
-void portmux_set_func(unsigned int portmux_id, unsigned int pin_id,
-		      unsigned int function_id)
+static struct pio_device *gpio_to_pio(unsigned int gpio)
 {
 	struct pio_device *pio;
-	u32 mask = 1 << pin_id;
+	unsigned int index;
+
+	index = gpio >> 5;
+	if (index >= MAX_NR_PIO_DEVICES)
+		return NULL;
+	pio = &pio_dev[index];
+	if (!pio->regs)
+		return NULL;
+
+	return pio;
+}
+
+/* Pin multiplexing API */
 
-	BUG_ON(portmux_id >= MAX_NR_PIO_DEVICES);
+void __init at32_select_periph(unsigned int pin, unsigned int periph,
+			       int use_pullup)
+{
+	struct pio_device *pio;
+	unsigned int pin_index = pin & 0x1f;
+	u32 mask = 1 << pin_index;
+
+	pio = gpio_to_pio(pin);
+	if (unlikely(!pio)) {
+		printk("pio: invalid pin %u\n", pin);
+		goto fail;
+	}
 
-	pio = &pio_dev[portmux_id];
+	if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask))) {
+		printk("%s: pin %u is busy\n", pio->name, pin_index);
+		goto fail;
+	}
 
-	if (function_id)
+	pio_writel(pio, PUER, mask);
+	if (periph)
 		pio_writel(pio, BSR, mask);
 	else
 		pio_writel(pio, ASR, mask);
+
 	pio_writel(pio, PDR, mask);
+	if (!use_pullup)
+		pio_writel(pio, PUDR, mask);
+
+	return;
+
+fail:
+	dump_stack();
+}
+
+void __init at32_select_gpio(unsigned int pin, int enable_output,
+			     int use_pullup)
+{
+	struct pio_device *pio;
+	unsigned int pin_index = pin & 0x1f;
+	u32 mask = 1 << pin_index;
+
+	pio = gpio_to_pio(pin);
+	if (unlikely(!pio)) {
+		printk("pio: invalid pin %u\n", pin);
+		goto fail;
+	}
+
+	if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask))) {
+		printk("%s: pin %u is busy\n", pio->name, pin_index);
+		goto fail;
+	}
+
+	pio_writel(pio, PUER, mask);
+	if (enable_output)
+		pio_writel(pio, OER, mask);
+	else
+		pio_writel(pio, ODR, mask);
+
+	pio_writel(pio, PER, mask);
+	if (!use_pullup)
+		pio_writel(pio, PUDR, mask);
+
+	/* It's now allowed to use request_gpio on this pin */
+	clear_bit(pin_index, &pio->gpio_mask);
+
+	return;
+
+fail:
+	dump_stack();
+}
+
+/* GPIO API */
+
+int gpio_request(unsigned int gpio, const char *label)
+{
+	struct pio_device *pio;
+	unsigned int pin;
+
+	pio = gpio_to_pio(gpio);
+	if (!pio)
+		return -ENODEV;
+
+	pin = gpio & 0x1f;
+	if (test_and_set_bit(pin, &pio->gpio_mask))
+		return -EBUSY;
+
+	return 0;
 }
+EXPORT_SYMBOL(gpio_request);
+
+void gpio_free(unsigned int gpio)
+{
+	struct pio_device *pio;
+	unsigned int pin;
+
+	pio = gpio_to_pio(gpio);
+	if (!pio) {
+		printk(KERN_ERR
+		       "gpio: attempted to free invalid pin %u\n", gpio);
+		return;
+	}
+
+	pin = gpio & 0x1f;
+	if (!test_and_clear_bit(pin, &pio->gpio_mask))
+		printk(KERN_ERR "gpio: freeing already-free pin %s[%u]\n",
+		       pio->name, pin);
+}
+EXPORT_SYMBOL(gpio_free);
+
+int gpio_direction_input(unsigned int gpio)
+{
+	struct pio_device *pio;
+	unsigned int pin;
+
+	pio = gpio_to_pio(gpio);
+	if (!pio)
+		return -ENODEV;
+
+	pin = gpio & 0x1f;
+	pio_writel(pio, ODR, 1 << pin);
+
+	return 0;
+}
+EXPORT_SYMBOL(gpio_direction_input);
+
+int gpio_direction_output(unsigned int gpio)
+{
+	struct pio_device *pio;
+	unsigned int pin;
+
+	pio = gpio_to_pio(gpio);
+	if (!pio)
+		return -ENODEV;
+
+	pin = gpio & 0x1f;
+	pio_writel(pio, OER, 1 << pin);
+
+	return 0;
+}
+EXPORT_SYMBOL(gpio_direction_output);
+
+int gpio_get_value(unsigned int gpio)
+{
+	struct pio_device *pio = &pio_dev[gpio >> 5];
+
+	return (pio_readl(pio, PDSR) >> (gpio & 0x1f)) & 1;
+}
+EXPORT_SYMBOL(gpio_get_value);
+
+void gpio_set_value(unsigned int gpio, int value)
+{
+	struct pio_device *pio = &pio_dev[gpio >> 5];
+	u32 mask;
+
+	mask = 1 << (gpio & 0x1f);
+	if (value)
+		pio_writel(pio, SODR, mask);
+	else
+		pio_writel(pio, CODR, mask);
+}
+EXPORT_SYMBOL(gpio_set_value);
 
 static int __init pio_probe(struct platform_device *pdev)
 {
@@ -113,6 +275,12 @@ void __init at32_init_pio(struct platfor
 	pio->pdev = pdev;
 	pio->regs = ioremap(regs->start, regs->end - regs->start + 1);
 
+	/*
+	 * request_gpio() is only valid for pins that have been
+	 * configured as GPIO.
+	 */
+	pio->gpio_mask = ~0UL;
+
 	pio_writel(pio, ODR, ~0UL);
 	pio_writel(pio, PER, ~0UL);
 }
Index: linux-2.6.18-avr32/include/asm-avr32/arch-at32ap/at32ap7000.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.18-avr32/include/asm-avr32/arch-at32ap/at32ap7000.h	2006-11-29 16:22:14.000000000 +0100
@@ -0,0 +1,26 @@
+#ifndef __ASM_ARCH_AT32AP7000_H
+#define __ASM_ARCH_AT32AP7000_H
+
+#define GPIO_PERIPH_A	0
+#define GPIO_PERIPH_B	1
+
+#define NR_GPIO_CONTROLLERS	4
+
+/*
+ * Pin numbers identifying specific GPIO pins on the chip. They can
+ * also be converted to IRQ numbers by passing them through
+ * gpio_to_irq().
+ */
+#define GPIO_PIOA_BASE	(0)
+#define GPIO_PIOB_BASE	(GPIO_PIOA_BASE + 32)
+#define GPIO_PIOC_BASE	(GPIO_PIOB_BASE + 32)
+#define GPIO_PIOD_BASE	(GPIO_PIOC_BASE + 32)
+#define GPIO_PIOE_BASE	(GPIO_PIOD_BASE + 32)
+
+#define GPIO_PIN_PA(N)	(GPIO_PIOA_BASE + (N))
+#define GPIO_PIN_PB(N)	(GPIO_PIOB_BASE + (N))
+#define GPIO_PIN_PC(N)	(GPIO_PIOC_BASE + (N))
+#define GPIO_PIN_PD(N)	(GPIO_PIOD_BASE + (N))
+#define GPIO_PIN_PE(N)	(GPIO_PIOE_BASE + (N))
+
+#endif /* __ASM_ARCH_AT32AP7000_H */
Index: linux-2.6.18-avr32/include/asm-avr32/arch-at32ap/gpio.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.18-avr32/include/asm-avr32/arch-at32ap/gpio.h	2006-11-29 16:22:14.000000000 +0100
@@ -0,0 +1,39 @@
+#ifndef __ASM_AVR32_GPIO_H
+#define __ASM_AVR32_GPIO_H
+
+#include <linux/compiler.h>
+#include <asm/irq.h>
+
+/*
+ * Set up pin multiplexing, called from board init only.
+ *
+ * The following flags determine the initial state of the pin.
+ */
+#define AT32_GPIOF_PULLUP	0x00000001	/* Enable pull-up */
+#define AT32_GPIOF_OUTPUT	0x00000002	/* Enable output driver */
+#define AT32_GPIOF_HIGH		0x00000004	/* Set output high */
+
+void at32_select_periph(unsigned int pin, unsigned int periph,
+			unsigned long flags);
+void at32_select_gpio(unsigned int pin, unsigned long flags);
+
+/* Arch-neutral GPIO API */
+int __must_check gpio_request(unsigned int gpio, const char *label);
+void gpio_free(unsigned int gpio);
+
+int gpio_direction_input(unsigned int gpio);
+int gpio_direction_output(unsigned int gpio);
+int gpio_get_value(unsigned int gpio);
+void gpio_set_value(unsigned int gpio, int value);
+
+static inline int gpio_to_irq(unsigned int gpio)
+{
+	return gpio + GPIO_IRQ_BASE;
+}
+
+static inline int irq_to_gpio(unsigned int irq)
+{
+	return irq - GPIO_IRQ_BASE;
+}
+
+#endif /* __ASM_AVR32_GPIO_H */
Index: linux-2.6.18-avr32/include/asm-avr32/arch-at32ap/irq.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.18-avr32/include/asm-avr32/arch-at32ap/irq.h	2006-11-29 16:22:14.000000000 +0100
@@ -0,0 +1,11 @@
+#ifndef __ASM_AVR32_ARCH_IRQ_H
+#define __ASM_AVR32_ARCH_IRQ_H
+
+#define EIM_IRQ_BASE	NR_INTERNAL_IRQS
+#define NR_EIM_IRQS	32
+#define GPIO_IRQ_BASE	(EIM_IRQ_BASE + NR_EIM_IRQS)
+#define NR_GPIO_IRQS	(4 * 32)
+
+#define NR_IRQS		(GPIO_IRQ_BASE + NR_GPIO_IRQS)
+
+#endif /* __ASM_AVR32_ARCH_IRQ_H */
Index: linux-2.6.18-avr32/include/asm-avr32/arch-at32ap/portmux.h
===================================================================
--- linux-2.6.18-avr32.orig/include/asm-avr32/arch-at32ap/portmux.h	2006-11-29 16:21:12.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,16 +0,0 @@
-/*
- * AT32 portmux interface.
- *
- * Copyright (C) 2006 Atmel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#ifndef __ASM_AVR32_AT32_PORTMUX_H__
-#define __ASM_AVR32_AT32_PORTMUX_H__
-
-void portmux_set_func(unsigned int portmux_id, unsigned int pin_id,
-		      unsigned int function_id);
-
-#endif /* __ASM_AVR32_AT32_PORTMUX_H__ */
Index: linux-2.6.18-avr32/include/asm-avr32/gpio.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.18-avr32/include/asm-avr32/gpio.h	2006-11-29 16:22:14.000000000 +0100
@@ -0,0 +1,6 @@
+#ifndef __ASM_AVR32_GPIO_H
+#define __ASM_AVR32_GPIO_H
+
+#include <asm/arch/gpio.h>
+
+#endif /* __ASM_AVR32_GPIO_H */
Index: linux-2.6.18-avr32/include/asm-avr32/irq.h
===================================================================
--- linux-2.6.18-avr32.orig/include/asm-avr32/irq.h	2006-11-29 16:21:12.000000000 +0100
+++ linux-2.6.18-avr32/include/asm-avr32/irq.h	2006-11-29 16:22:14.000000000 +0100
@@ -2,8 +2,12 @@
 #define __ASM_AVR32_IRQ_H
 
 #define NR_INTERNAL_IRQS	64
-#define NR_EXTERNAL_IRQS	64
-#define NR_IRQS			(NR_INTERNAL_IRQS + NR_EXTERNAL_IRQS)
+
+#include <asm/arch/irq.h>
+
+#ifndef NR_IRQS
+#define NR_IRQS			(NR_INTERNAL_IRQS)
+#endif
 
 #define irq_canonicalize(i)	(i)