diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c
index f3085208959f13e01162d138dd50fbf496869ab2..6c54580a66df77bdcba2d1e889c95ba9b6524291 100644
--- a/arch/avr32/boards/atngw100/setup.c
+++ b/arch/avr32/boards/atngw100/setup.c
@@ -9,6 +9,7 @@
  */
 #include <linux/clk.h>
 #include <linux/etherdevice.h>
+#include <linux/gpio.h>
 #include <linux/irq.h>
 #include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
@@ -193,7 +194,7 @@ static int __init atngw100_init(void)
 	 * PB28/EXTINT3 doesn't; it should be SMBALERT# (for PMBus),
 	 * but it's not available off-board.
 	 */
-	at32_select_periph(GPIO_PIN_PB(28), 0, AT32_GPIOF_PULLUP);
+	at32_select_periph(GPIO_PIOB_BASE, 1 << 28, 0, AT32_GPIOF_PULLUP);
 	at32_select_gpio(i2c_gpio_data.sda_pin,
 		AT32_GPIOF_MULTIDRV | AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
 	at32_select_gpio(i2c_gpio_data.scl_pin,
@@ -207,6 +208,15 @@ postcore_initcall(atngw100_init);
 
 static int __init atngw100_arch_init(void)
 {
+	/* PB30 is the otherwise unused jumper on the mainboard, with an
+	 * external pullup; the jumper grounds it.  Use it however you
+	 * like, including letting U-Boot or Linux tweak boot sequences.
+	 */
+	at32_select_gpio(GPIO_PIN_PB(30), 0);
+	gpio_request(GPIO_PIN_PB(30), "j15");
+	gpio_direction_input(GPIO_PIN_PB(30));
+	gpio_export(GPIO_PIN_PB(30), false);
+
 	/* set_irq_type() after the arch_initcall for EIC has run, and
 	 * before the I2C subsystem could try using this IRQ.
 	 */
diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c
index 4fedbc4488de645a88f9c62157067ceb872276df..29e5b51a7fd2b8801a23655e17edcff41ade6ab2 100644
--- a/arch/avr32/boards/atstk1000/atstk1002.c
+++ b/arch/avr32/boards/atstk1000/atstk1002.c
@@ -232,7 +232,7 @@ static void __init atstk1002_setup_extdac(void)
 		goto err_set_clk;
 	}
 
-	at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
+	at32_select_periph(GPIO_PIOA_BASE, (1 << 30), GPIO_PERIPH_A, 0);
 	at73c213_data.dac_clk = gclk;
 
 err_set_clk:
@@ -330,13 +330,14 @@ static int __init atstk1002_init(void)
 	at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
 #endif
 #ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
-	at32_add_device_mci(0, &mci0_pdata);
+	at32_add_device_mci(0, &mci0_data);
 #endif
 #ifdef CONFIG_BOARD_ATSTK1002_SW5_CUSTOM
 	set_hw_addr(at32_add_device_eth(1, &eth_data[1]));
 #else
 	at32_add_device_lcdc(0, &atstk1000_lcdc_data,
-			     fbmem_start, fbmem_size, 0);
+			     fbmem_start, fbmem_size,
+			     ATMEL_LCDC_PRI_24BIT | ATMEL_LCDC_PRI_CONTROL);
 #endif
 	at32_add_device_usba(0, NULL);
 #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
diff --git a/arch/avr32/boards/atstk1000/atstk1003.c b/arch/avr32/boards/atstk1000/atstk1003.c
index acc61235b89587d939f724122bbb1914db8c06cc..be089d7f37ebf1b0fe955475417fce4fb66e86f9 100644
--- a/arch/avr32/boards/atstk1000/atstk1003.c
+++ b/arch/avr32/boards/atstk1000/atstk1003.c
@@ -19,6 +19,7 @@
 #include <linux/spi/spi.h>
 
 #include <asm/setup.h>
+#include <asm/atmel-mci.h>
 
 #include <mach/at32ap700x.h>
 #include <mach/board.h>
@@ -94,7 +95,7 @@ static void __init atstk1003_setup_extdac(void)
 		goto err_set_clk;
 	}
 
-	at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
+	at32_select_periph(GPIO_PIOA_BASE, (1 << 30), GPIO_PERIPH_A, 0);
 	at73c213_data.dac_clk = gclk;
 
 err_set_clk:
diff --git a/arch/avr32/boards/atstk1000/atstk1004.c b/arch/avr32/boards/atstk1000/atstk1004.c
index d6a2d02f03291e51b98953b76a9bfc0efe969027..248ef237c167b95283c30dec20ca0080c97e6feb 100644
--- a/arch/avr32/boards/atstk1000/atstk1004.c
+++ b/arch/avr32/boards/atstk1000/atstk1004.c
@@ -21,6 +21,7 @@
 #include <video/atmel_lcdc.h>
 
 #include <asm/setup.h>
+#include <asm/atmel-mci.h>
 
 #include <mach/at32ap700x.h>
 #include <mach/board.h>
@@ -99,7 +100,7 @@ static void __init atstk1004_setup_extdac(void)
 		goto err_set_clk;
 	}
 
-	at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
+	at32_select_periph(GPIO_PIOA_BASE, (1 << 30), GPIO_PERIPH_A, 0);
 	at73c213_data.dac_clk = gclk;
 
 err_set_clk:
@@ -150,7 +151,8 @@ static int __init atstk1004_init(void)
 	at32_add_device_mci(0, &mci0_data);
 #endif
 	at32_add_device_lcdc(0, &atstk1000_lcdc_data,
-			     fbmem_start, fbmem_size, 0);
+			     fbmem_start, fbmem_size,
+			     ATMEL_LCDC_PRI_24BIT | ATMEL_LCDC_PRI_CONTROL);
 	at32_add_device_usba(0, NULL);
 #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
 	at32_add_device_ssc(0, ATMEL_SSC_TX);
diff --git a/arch/avr32/include/asm/byteorder.h b/arch/avr32/include/asm/byteorder.h
index d77b48ba73387ba57ac932e5a6676d43b1c6a584..8e3af02076dd59d8eedcf2cec413392ee867f68d 100644
--- a/arch/avr32/include/asm/byteorder.h
+++ b/arch/avr32/include/asm/byteorder.h
@@ -7,6 +7,9 @@
 #include <asm/types.h>
 #include <linux/compiler.h>
 
+#define __BIG_ENDIAN
+#define __SWAB_64_THRU_32__
+
 #ifdef __CHECKER__
 extern unsigned long __builtin_bswap_32(unsigned long x);
 extern unsigned short __builtin_bswap_16(unsigned short x);
@@ -17,15 +20,18 @@ extern unsigned short __builtin_bswap_16(unsigned short x);
  * the result.
  */
 #if !(__GNUC__ == 4 && __GNUC_MINOR__ < 2)
-#define __arch__swab32(x) __builtin_bswap_32(x)
-#define __arch__swab16(x) __builtin_bswap_16(x)
-#endif
+static inline __attribute_const__ __u16 __arch_swab16(__u16 val)
+{
+	return __builtin_bswap_16(val);
+}
+#define __arch_swab16 __arch_swab16
 
-#if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
-# define __BYTEORDER_HAS_U64__
-# define __SWAB_64_THRU_32__
+static inline __attribute_const__ __u32 __arch_swab32(__u32 val)
+{
+	return __builtin_bswap_32(val);
+}
+#define __arch_swab32 __arch_swab32
 #endif
 
-#include <linux/byteorder/big_endian.h>
-
+#include <linux/byteorder.h>
 #endif /* __ASM_AVR32_BYTEORDER_H */
diff --git a/arch/avr32/include/asm/io.h b/arch/avr32/include/asm/io.h
index a520f77ead96e62d02ee2197d85c2a76fa46c9e2..22c97ef92201bff82b5a7bc7a6fe139147c014a4 100644
--- a/arch/avr32/include/asm/io.h
+++ b/arch/avr32/include/asm/io.h
@@ -160,6 +160,14 @@ BUILDIO_IOPORT(l, u32)
 #define readw_relaxed			readw
 #define readl_relaxed			readl
 
+#define readb_be			__raw_readb
+#define readw_be			__raw_readw
+#define readl_be			__raw_readl
+
+#define writeb_be			__raw_writeb
+#define writew_be			__raw_writew
+#define writel_be			__raw_writel
+
 #define __BUILD_MEMORY_STRING(bwl, type)				\
 static inline void writes##bwl(volatile void __iomem *addr,		\
 			       const void *data, unsigned int count)	\
diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c
index 2c08ac992ac3d8435c2284224cbbd5a0691ac085..134d5302b6dd21fda7f676a9bdfa3923b19e5998 100644
--- a/arch/avr32/kernel/process.c
+++ b/arch/avr32/kernel/process.c
@@ -9,6 +9,7 @@
 #include <linux/module.h>
 #include <linux/kallsyms.h>
 #include <linux/fs.h>
+#include <linux/pm.h>
 #include <linux/ptrace.h>
 #include <linux/reboot.h>
 #include <linux/tick.h>
@@ -20,7 +21,7 @@
 
 #include <mach/pm.h>
 
-void (*pm_power_off)(void) = NULL;
+void (*pm_power_off)(void);
 EXPORT_SYMBOL(pm_power_off);
 
 /*
diff --git a/arch/avr32/kernel/setup.c b/arch/avr32/kernel/setup.c
index d8e623c426c1f324c37369eca13cf358e3b85ab1..5c7083916c33c14792728da5a08295476daebc17 100644
--- a/arch/avr32/kernel/setup.c
+++ b/arch/avr32/kernel/setup.c
@@ -283,6 +283,25 @@ static int __init early_parse_fbmem(char *p)
 }
 early_param("fbmem", early_parse_fbmem);
 
+/*
+ * Pick out the memory size.  We look for mem=size@start,
+ * where start and size are "size[KkMmGg]"
+ */
+static int __init early_mem(char *p)
+{
+	resource_size_t size, start;
+
+	start = system_ram->start;
+	size  = memparse(p, &p);
+	if (*p == '@')
+		start = memparse(p + 1, &p);
+
+	system_ram->start = start;
+	system_ram->end = system_ram->start + size - 1;
+	return 0;
+}
+early_param("mem", early_mem);
+
 static int __init parse_tag_core(struct tag *tag)
 {
 	if (tag->hdr.size > 2) {
diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
index f1b9a3ac27336fe92c9c15cbe114212b5f98d4f5..813b6844cdf67a1ec485ccc4f3839baa42c2682d 100644
--- a/arch/avr32/mach-at32ap/at32ap700x.c
+++ b/arch/avr32/mach-at32ap/at32ap700x.c
@@ -82,8 +82,9 @@ static struct platform_device _name##_id##_device = {		\
 	.num_resources	= ARRAY_SIZE(_name##_id##_resource),	\
 }
 
-#define select_peripheral(pin, periph, flags)			\
-	at32_select_periph(GPIO_PIN_##pin, GPIO_##periph, flags)
+#define select_peripheral(port, pin_mask, periph, flags)	\
+	at32_select_periph(GPIO_##port##_BASE, pin_mask,	\
+			   GPIO_##periph, flags)
 
 #define DEV_CLK(_name, devname, bus, _index)			\
 static struct clk devname##_##_name = {				\
@@ -871,6 +872,7 @@ static struct clk atmel_psif1_pclk = {
 struct platform_device *__init at32_add_device_psif(unsigned int id)
 {
 	struct platform_device *pdev;
+	u32 pin_mask;
 
 	if (!(id == 0 || id == 1))
 		return NULL;
@@ -881,20 +883,22 @@ struct platform_device *__init at32_add_device_psif(unsigned int id)
 
 	switch (id) {
 	case 0:
+		pin_mask  = (1 << 8) | (1 << 9); /* CLOCK & DATA */
+
 		if (platform_device_add_resources(pdev, atmel_psif0_resource,
 					ARRAY_SIZE(atmel_psif0_resource)))
 			goto err_add_resources;
 		atmel_psif0_pclk.dev = &pdev->dev;
-		select_peripheral(PA(8), PERIPH_A, 0); /* CLOCK */
-		select_peripheral(PA(9), PERIPH_A, 0); /* DATA  */
+		select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
 		break;
 	case 1:
+		pin_mask  = (1 << 11) | (1 << 12); /* CLOCK & DATA */
+
 		if (platform_device_add_resources(pdev, atmel_psif1_resource,
 					ARRAY_SIZE(atmel_psif1_resource)))
 			goto err_add_resources;
 		atmel_psif1_pclk.dev = &pdev->dev;
-		select_peripheral(PB(11), PERIPH_A, 0); /* CLOCK */
-		select_peripheral(PB(12), PERIPH_A, 0); /* DATA  */
+		select_peripheral(PIOB, pin_mask, PERIPH_A, 0);
 		break;
 	default:
 		return NULL;
@@ -958,26 +962,30 @@ DEV_CLK(usart, atmel_usart3, pba, 6);
 
 static inline void configure_usart0_pins(void)
 {
-	select_peripheral(PA(8),  PERIPH_B, 0);	/* RXD	*/
-	select_peripheral(PA(9),  PERIPH_B, 0);	/* TXD	*/
+	u32 pin_mask = (1 << 8) | (1 << 9); /* RXD & TXD */
+
+	select_peripheral(PIOA, pin_mask, PERIPH_B, 0);
 }
 
 static inline void configure_usart1_pins(void)
 {
-	select_peripheral(PA(17), PERIPH_A, 0);	/* RXD	*/
-	select_peripheral(PA(18), PERIPH_A, 0);	/* TXD	*/
+	u32 pin_mask = (1 << 17) | (1 << 18); /* RXD & TXD */
+
+	select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
 }
 
 static inline void configure_usart2_pins(void)
 {
-	select_peripheral(PB(26), PERIPH_B, 0);	/* RXD	*/
-	select_peripheral(PB(27), PERIPH_B, 0);	/* TXD	*/
+	u32 pin_mask = (1 << 26) | (1 << 27); /* RXD & TXD */
+
+	select_peripheral(PIOB, pin_mask, PERIPH_B, 0);
 }
 
 static inline void configure_usart3_pins(void)
 {
-	select_peripheral(PB(18), PERIPH_B, 0);	/* RXD	*/
-	select_peripheral(PB(17), PERIPH_B, 0);	/* TXD	*/
+	u32 pin_mask = (1 << 18) | (1 << 17); /* RXD & TXD */
+
+	select_peripheral(PIOB, pin_mask, PERIPH_B, 0);
 }
 
 static struct platform_device *__initdata at32_usarts[4];
@@ -1057,59 +1065,69 @@ struct platform_device *__init
 at32_add_device_eth(unsigned int id, struct eth_platform_data *data)
 {
 	struct platform_device *pdev;
+	u32 pin_mask;
 
 	switch (id) {
 	case 0:
 		pdev = &macb0_device;
 
-		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	*/
+		pin_mask  = (1 << 3);	/* TXD0 */
+		pin_mask |= (1 << 4);	/* TXD1 */
+		pin_mask |= (1 << 7);	/* TXEN */
+		pin_mask |= (1 << 8);	/* TXCK */
+		pin_mask |= (1 << 9);	/* RXD0 */
+		pin_mask |= (1 << 10);	/* RXD1 */
+		pin_mask |= (1 << 13);	/* RXER */
+		pin_mask |= (1 << 15);	/* RXDV */
+		pin_mask |= (1 << 16);	/* MDC  */
+		pin_mask |= (1 << 17);	/* MDIO */
 
 		if (!data->is_rmii) {
-			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	*/
+			pin_mask |= (1 << 0);	/* COL  */
+			pin_mask |= (1 << 1);	/* CRS  */
+			pin_mask |= (1 << 2);	/* TXER */
+			pin_mask |= (1 << 5);	/* TXD2 */
+			pin_mask |= (1 << 6);	/* TXD3 */
+			pin_mask |= (1 << 11);	/* RXD2 */
+			pin_mask |= (1 << 12);	/* RXD3 */
+			pin_mask |= (1 << 14);	/* RXCK */
+			pin_mask |= (1 << 18);	/* SPD  */
 		}
+
+		select_peripheral(PIOC, pin_mask, PERIPH_A, 0);
+
 		break;
 
 	case 1:
 		pdev = &macb1_device;
 
-		select_peripheral(PD(13), PERIPH_B, 0);		/* TXD0	*/
-		select_peripheral(PD(14), PERIPH_B, 0);		/* TXD1	*/
-		select_peripheral(PD(11), PERIPH_B, 0);		/* TXEN	*/
-		select_peripheral(PD(12), PERIPH_B, 0);		/* TXCK */
-		select_peripheral(PD(10), PERIPH_B, 0);		/* RXD0	*/
-		select_peripheral(PD(6),  PERIPH_B, 0);		/* RXD1	*/
-		select_peripheral(PD(5),  PERIPH_B, 0);		/* RXER	*/
-		select_peripheral(PD(4),  PERIPH_B, 0);		/* RXDV	*/
-		select_peripheral(PD(3),  PERIPH_B, 0);		/* MDC	*/
-		select_peripheral(PD(2),  PERIPH_B, 0);		/* MDIO	*/
+		pin_mask  = (1 << 13);	/* TXD0 */
+		pin_mask |= (1 << 14);	/* TXD1 */
+		pin_mask |= (1 << 11);	/* TXEN */
+		pin_mask |= (1 << 12);	/* TXCK */
+		pin_mask |= (1 << 10);	/* RXD0 */
+		pin_mask |= (1 << 6);	/* RXD1 */
+		pin_mask |= (1 << 5);	/* RXER */
+		pin_mask |= (1 << 4);	/* RXDV */
+		pin_mask |= (1 << 3);	/* MDC  */
+		pin_mask |= (1 << 2);	/* MDIO */
+
+		if (!data->is_rmii)
+			pin_mask |= (1 << 15);	/* SPD  */
+
+		select_peripheral(PIOD, pin_mask, PERIPH_B, 0);
 
 		if (!data->is_rmii) {
-			select_peripheral(PC(19), PERIPH_B, 0);	/* COL	*/
-			select_peripheral(PC(23), PERIPH_B, 0);	/* CRS	*/
-			select_peripheral(PC(26), PERIPH_B, 0);	/* TXER	*/
-			select_peripheral(PC(27), PERIPH_B, 0);	/* TXD2	*/
-			select_peripheral(PC(28), PERIPH_B, 0);	/* TXD3 */
-			select_peripheral(PC(29), PERIPH_B, 0);	/* RXD2	*/
-			select_peripheral(PC(30), PERIPH_B, 0);	/* RXD3	*/
-			select_peripheral(PC(24), PERIPH_B, 0);	/* RXCK	*/
-			select_peripheral(PD(15), PERIPH_B, 0);	/* SPD	*/
+			pin_mask  = (1 << 19);	/* COL  */
+			pin_mask |= (1 << 23);	/* CRS  */
+			pin_mask |= (1 << 26);	/* TXER */
+			pin_mask |= (1 << 27);	/* TXD2 */
+			pin_mask |= (1 << 28);	/* TXD3 */
+			pin_mask |= (1 << 29);	/* RXD2 */
+			pin_mask |= (1 << 30);	/* RXD3 */
+			pin_mask |= (1 << 24);	/* RXCK */
+
+			select_peripheral(PIOC, pin_mask, PERIPH_B, 0);
 		}
 		break;
 
@@ -1177,23 +1195,28 @@ at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
 		{ GPIO_PIN_PB(2), GPIO_PIN_PB(3),
 		  GPIO_PIN_PB(4), GPIO_PIN_PA(27), };
 	struct platform_device *pdev;
+	u32 pin_mask;
 
 	switch (id) {
 	case 0:
 		pdev = &atmel_spi0_device;
+		pin_mask  = (1 << 1) | (1 << 2);	/* MOSI & SCK */
+
 		/* pullup MISO so a level is always defined */
-		select_peripheral(PA(0),  PERIPH_A, AT32_GPIOF_PULLUP);
-		select_peripheral(PA(1),  PERIPH_A, 0);	/* MOSI	 */
-		select_peripheral(PA(2),  PERIPH_A, 0);	/* SCK	 */
+		select_peripheral(PIOA, (1 << 0), PERIPH_A, AT32_GPIOF_PULLUP);
+		select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
+
 		at32_spi_setup_slaves(0, b, n, spi0_pins);
 		break;
 
 	case 1:
 		pdev = &atmel_spi1_device;
+		pin_mask  = (1 << 1) | (1 << 5);	/* MOSI */
+
 		/* pullup MISO so a level is always defined */
-		select_peripheral(PB(0),  PERIPH_B, AT32_GPIOF_PULLUP);
-		select_peripheral(PB(1),  PERIPH_B, 0);	/* MOSI  */
-		select_peripheral(PB(5),  PERIPH_B, 0);	/* SCK   */
+		select_peripheral(PIOB, (1 << 0), PERIPH_B, AT32_GPIOF_PULLUP);
+		select_peripheral(PIOB, pin_mask, PERIPH_B, 0);
+
 		at32_spi_setup_slaves(1, b, n, spi1_pins);
 		break;
 
@@ -1226,6 +1249,7 @@ struct platform_device *__init at32_add_device_twi(unsigned int id,
 						    unsigned int n)
 {
 	struct platform_device *pdev;
+	u32 pin_mask;
 
 	if (id != 0)
 		return NULL;
@@ -1238,8 +1262,9 @@ struct platform_device *__init at32_add_device_twi(unsigned int id,
 				ARRAY_SIZE(atmel_twi0_resource)))
 		goto err_add_resources;
 
-	select_peripheral(PA(6),  PERIPH_A, 0);	/* SDA	*/
-	select_peripheral(PA(7),  PERIPH_A, 0);	/* SDL	*/
+	pin_mask  = (1 << 6) | (1 << 7);	/* SDA & SDL */
+
+	select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
 
 	atmel_twi0_pclk.dev = &pdev->dev;
 
@@ -1274,6 +1299,8 @@ at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
 {
 	struct platform_device		*pdev;
 	struct dw_dma_slave		*dws;
+	u32				pioa_mask;
+	u32				piob_mask;
 
 	if (id != 0 || !data)
 		return NULL;
@@ -1311,17 +1338,17 @@ at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
 		goto fail;
 
 	/* CLK line is common to both slots */
-	select_peripheral(PA(10), PERIPH_A, 0);
+	pioa_mask = 1 << 10;
 
 	switch (data->slot[0].bus_width) {
 	case 4:
-		select_peripheral(PA(13), PERIPH_A, 0);	/* DATA1 */
-		select_peripheral(PA(14), PERIPH_A, 0);	/* DATA2 */
-		select_peripheral(PA(15), PERIPH_A, 0);	/* DATA3 */
+		pioa_mask |= 1 << 13;		/* DATA1 */
+		pioa_mask |= 1 << 14;		/* DATA2 */
+		pioa_mask |= 1 << 15;		/* DATA3 */
 		/* fall through */
 	case 1:
-		select_peripheral(PA(11), PERIPH_A, 0);	/* CMD	 */
-		select_peripheral(PA(12), PERIPH_A, 0);	/* DATA0 */
+		pioa_mask |= 1 << 11;		/* CMD	 */
+		pioa_mask |= 1 << 12;		/* DATA0 */
 
 		if (gpio_is_valid(data->slot[0].detect_pin))
 			at32_select_gpio(data->slot[0].detect_pin, 0);
@@ -1335,15 +1362,19 @@ at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
 		goto fail;
 	}
 
+	select_peripheral(PIOA, pioa_mask, PERIPH_A, 0);
+	piob_mask = 0;
+
 	switch (data->slot[1].bus_width) {
 	case 4:
-		select_peripheral(PB(8),  PERIPH_B, 0);	/* DATA1 */
-		select_peripheral(PB(9),  PERIPH_B, 0);	/* DATA2 */
-		select_peripheral(PB(10), PERIPH_B, 0);	/* DATA3 */
+		piob_mask |= 1 <<  8;		/* DATA1 */
+		piob_mask |= 1 <<  9;		/* DATA2 */
+		piob_mask |= 1 << 10;		/* DATA3 */
 		/* fall through */
 	case 1:
-		select_peripheral(PB(6),  PERIPH_B, 0); /* CMD	 */
-		select_peripheral(PB(7),  PERIPH_B, 0); /* DATA0 */
+		piob_mask |= 1 <<  6;		/* CMD	 */
+		piob_mask |= 1 <<  7;		/* DATA0 */
+		select_peripheral(PIOB, piob_mask, PERIPH_B, 0);
 
 		if (gpio_is_valid(data->slot[1].detect_pin))
 			at32_select_gpio(data->slot[1].detect_pin, 0);
@@ -1405,13 +1436,14 @@ static struct clk atmel_lcdfb0_pixclk = {
 struct platform_device *__init
 at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
 		     unsigned long fbmem_start, unsigned long fbmem_len,
-		     unsigned int pin_config)
+		     u64 pin_mask)
 {
 	struct platform_device *pdev;
 	struct atmel_lcdfb_info *info;
 	struct fb_monspecs *monspecs;
 	struct fb_videomode *modedb;
 	unsigned int modedb_size;
+	u32 portc_mask, portd_mask, porte_mask;
 
 	/*
 	 * Do a deep copy of the fb data, monspecs and modedb. Make
@@ -1433,76 +1465,21 @@ at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
 	case 0:
 		pdev = &atmel_lcdfb0_device;
 
-		switch (pin_config) {
-		case 0:
-			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 */
-			break;
-		case 1:
-			select_peripheral(PE(0),  PERIPH_B, 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(PE(1),  PERIPH_B, 0);	/* DVAL	  */
-			select_peripheral(PE(2),  PERIPH_B, 0);	/* MODE	  */
-			select_peripheral(PC(25), PERIPH_A, 0);	/* PWR	  */
-			select_peripheral(PE(3),  PERIPH_B, 0);	/* DATA0  */
-			select_peripheral(PE(4),  PERIPH_B, 0);	/* DATA1  */
-			select_peripheral(PE(5),  PERIPH_B, 0);	/* DATA2  */
-			select_peripheral(PE(6),  PERIPH_B, 0);	/* DATA3  */
-			select_peripheral(PE(7),  PERIPH_B, 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(PE(8),  PERIPH_B, 0);	/* DATA8  */
-			select_peripheral(PE(9),  PERIPH_B, 0);	/* DATA9  */
-			select_peripheral(PE(10), PERIPH_B, 0);	/* DATA10 */
-			select_peripheral(PE(11), PERIPH_B, 0);	/* DATA11 */
-			select_peripheral(PE(12), PERIPH_B, 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(PE(13), PERIPH_B, 0);	/* DATA16 */
-			select_peripheral(PE(14), PERIPH_B, 0);	/* DATA17 */
-			select_peripheral(PE(15), PERIPH_B, 0);	/* DATA18 */
-			select_peripheral(PE(16), PERIPH_B, 0);	/* DATA19 */
-			select_peripheral(PE(17), PERIPH_B, 0);	/* DATA20 */
-			select_peripheral(PE(18), PERIPH_B, 0);	/* DATA21 */
-			select_peripheral(PD(16), PERIPH_A, 0);	/* DATA22 */
-			select_peripheral(PD(17), PERIPH_A, 0);	/* DATA23 */
-			break;
-		default:
-			goto err_invalid_id;
-		}
+		if (pin_mask == 0ULL)
+			/* Default to "full" lcdc control signals and 24bit */
+			pin_mask = ATMEL_LCDC_PRI_24BIT | ATMEL_LCDC_PRI_CONTROL;
+
+		/* LCDC on port C */
+		portc_mask = (pin_mask & 0xfff80000) >> 19;
+		select_peripheral(PIOC, portc_mask, PERIPH_A, 0);
+
+		/* LCDC on port D */
+		portd_mask = pin_mask & 0x0003ffff;
+		select_peripheral(PIOD, portd_mask, PERIPH_A, 0);
+
+		/* LCDC on port E */
+		porte_mask = (pin_mask >> 32) & 0x0007ffff;
+		select_peripheral(PIOE, porte_mask, PERIPH_B, 0);
 
 		clk_set_parent(&atmel_lcdfb0_pixclk, &pll0);
 		clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0));
@@ -1551,6 +1528,7 @@ static struct clk atmel_pwm0_mck = {
 struct platform_device *__init at32_add_device_pwm(u32 mask)
 {
 	struct platform_device *pdev;
+	u32 pin_mask;
 
 	if (!mask)
 		return NULL;
@@ -1566,14 +1544,21 @@ struct platform_device *__init at32_add_device_pwm(u32 mask)
 	if (platform_device_add_data(pdev, &mask, sizeof(mask)))
 		goto out_free_pdev;
 
+	pin_mask = 0;
 	if (mask & (1 << 0))
-		select_peripheral(PA(28), PERIPH_A, 0);
+		pin_mask |= (1 << 28);
 	if (mask & (1 << 1))
-		select_peripheral(PA(29), PERIPH_A, 0);
+		pin_mask |= (1 << 29);
+	if (pin_mask > 0)
+		select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
+
+	pin_mask = 0;
 	if (mask & (1 << 2))
-		select_peripheral(PA(21), PERIPH_B, 0);
+		pin_mask |= (1 << 21);
 	if (mask & (1 << 3))
-		select_peripheral(PA(22), PERIPH_B, 0);
+		pin_mask |= (1 << 22);
+	if (pin_mask > 0)
+		select_peripheral(PIOA, pin_mask, PERIPH_B, 0);
 
 	atmel_pwm0_mck.dev = &pdev->dev;
 
@@ -1614,52 +1599,65 @@ struct platform_device *__init
 at32_add_device_ssc(unsigned int id, unsigned int flags)
 {
 	struct platform_device *pdev;
+	u32 pin_mask = 0;
 
 	switch (id) {
 	case 0:
 		pdev = &ssc0_device;
 		if (flags & ATMEL_SSC_RF)
-			select_peripheral(PA(21), PERIPH_A, 0);	/* RF */
+			pin_mask |= (1 << 21);	/* RF */
 		if (flags & ATMEL_SSC_RK)
-			select_peripheral(PA(22), PERIPH_A, 0);	/* RK */
+			pin_mask |= (1 << 22);	/* RK */
 		if (flags & ATMEL_SSC_TK)
-			select_peripheral(PA(23), PERIPH_A, 0);	/* TK */
+			pin_mask |= (1 << 23);	/* TK */
 		if (flags & ATMEL_SSC_TF)
-			select_peripheral(PA(24), PERIPH_A, 0);	/* TF */
+			pin_mask |= (1 << 24);	/* TF */
 		if (flags & ATMEL_SSC_TD)
-			select_peripheral(PA(25), PERIPH_A, 0);	/* TD */
+			pin_mask |= (1 << 25);	/* TD */
 		if (flags & ATMEL_SSC_RD)
-			select_peripheral(PA(26), PERIPH_A, 0);	/* RD */
+			pin_mask |= (1 << 26);	/* RD */
+
+		if (pin_mask > 0)
+			select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
+
 		break;
 	case 1:
 		pdev = &ssc1_device;
 		if (flags & ATMEL_SSC_RF)
-			select_peripheral(PA(0), PERIPH_B, 0);	/* RF */
+			pin_mask |= (1 << 0);	/* RF */
 		if (flags & ATMEL_SSC_RK)
-			select_peripheral(PA(1), PERIPH_B, 0);	/* RK */
+			pin_mask |= (1 << 1);	/* RK */
 		if (flags & ATMEL_SSC_TK)
-			select_peripheral(PA(2), PERIPH_B, 0);	/* TK */
+			pin_mask |= (1 << 2);	/* TK */
 		if (flags & ATMEL_SSC_TF)
-			select_peripheral(PA(3), PERIPH_B, 0);	/* TF */
+			pin_mask |= (1 << 3);	/* TF */
 		if (flags & ATMEL_SSC_TD)
-			select_peripheral(PA(4), PERIPH_B, 0);	/* TD */
+			pin_mask |= (1 << 4);	/* TD */
 		if (flags & ATMEL_SSC_RD)
-			select_peripheral(PA(5), PERIPH_B, 0);	/* RD */
+			pin_mask |= (1 << 5);	/* RD */
+
+		if (pin_mask > 0)
+			select_peripheral(PIOA, pin_mask, PERIPH_B, 0);
+
 		break;
 	case 2:
 		pdev = &ssc2_device;
 		if (flags & ATMEL_SSC_TD)
-			select_peripheral(PB(13), PERIPH_A, 0);	/* TD */
+			pin_mask |= (1 << 13);	/* TD */
 		if (flags & ATMEL_SSC_RD)
-			select_peripheral(PB(14), PERIPH_A, 0);	/* RD */
+			pin_mask |= (1 << 14);	/* RD */
 		if (flags & ATMEL_SSC_TK)
-			select_peripheral(PB(15), PERIPH_A, 0);	/* TK */
+			pin_mask |= (1 << 15);	/* TK */
 		if (flags & ATMEL_SSC_TF)
-			select_peripheral(PB(16), PERIPH_A, 0);	/* TF */
+			pin_mask |= (1 << 16);	/* TF */
 		if (flags & ATMEL_SSC_RF)
-			select_peripheral(PB(17), PERIPH_A, 0);	/* RF */
+			pin_mask |= (1 << 17);	/* RF */
 		if (flags & ATMEL_SSC_RK)
-			select_peripheral(PB(18), PERIPH_A, 0);	/* RK */
+			pin_mask |= (1 << 18);	/* RK */
+
+		if (pin_mask > 0)
+			select_peripheral(PIOB, pin_mask, PERIPH_A, 0);
+
 		break;
 	default:
 		return NULL;
@@ -1797,14 +1795,15 @@ static int __init at32_init_ide_or_cf(struct platform_device *pdev,
 		unsigned int cs, unsigned int extint)
 {
 	static unsigned int extint_pin_map[4] __initdata = {
-		GPIO_PIN_PB(25),
-		GPIO_PIN_PB(26),
-		GPIO_PIN_PB(27),
-		GPIO_PIN_PB(28),
+		(1 << 25),
+		(1 << 26),
+		(1 << 27),
+		(1 << 28),
 	};
 	static bool common_pins_initialized __initdata = false;
 	unsigned int extint_pin;
 	int ret;
+	u32 pin_mask;
 
 	if (extint >= ARRAY_SIZE(extint_pin_map))
 		return -EINVAL;
@@ -1818,7 +1817,8 @@ static int __init at32_init_ide_or_cf(struct platform_device *pdev,
 		if (ret)
 			return ret;
 
-		select_peripheral(PE(21), PERIPH_A, 0); /* NCS4   -> OE_N  */
+		/* NCS4   -> OE_N  */
+		select_peripheral(PIOE, (1 << 21), PERIPH_A, 0);
 		hmatrix_sfr_set_bits(HMATRIX_SLAVE_EBI, HMATRIX_EBI_CF0_ENABLE);
 		break;
 	case 5:
@@ -1828,7 +1828,8 @@ static int __init at32_init_ide_or_cf(struct platform_device *pdev,
 		if (ret)
 			return ret;
 
-		select_peripheral(PE(22), PERIPH_A, 0); /* NCS5   -> OE_N  */
+		/* NCS5   -> OE_N  */
+		select_peripheral(PIOE, (1 << 22), PERIPH_A, 0);
 		hmatrix_sfr_set_bits(HMATRIX_SLAVE_EBI, HMATRIX_EBI_CF1_ENABLE);
 		break;
 	default:
@@ -1836,14 +1837,17 @@ static int __init at32_init_ide_or_cf(struct platform_device *pdev,
 	}
 
 	if (!common_pins_initialized) {
-		select_peripheral(PE(19), PERIPH_A, 0);	/* CFCE1  -> CS0_N */
-		select_peripheral(PE(20), PERIPH_A, 0);	/* CFCE2  -> CS1_N */
-		select_peripheral(PE(23), PERIPH_A, 0); /* CFRNW  -> DIR   */
-		select_peripheral(PE(24), PERIPH_A, 0); /* NWAIT  <- IORDY */
+		pin_mask  = (1 << 19);	/* CFCE1  -> CS0_N */
+		pin_mask |= (1 << 20);	/* CFCE2  -> CS1_N */
+		pin_mask |= (1 << 23);	/* CFRNW  -> DIR   */
+		pin_mask |= (1 << 24);	/* NWAIT  <- IORDY */
+
+		select_peripheral(PIOE, pin_mask, PERIPH_A, 0);
+
 		common_pins_initialized = true;
 	}
 
-	at32_select_periph(extint_pin, GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH);
+	select_peripheral(PIOB, extint_pin, PERIPH_A, AT32_GPIOF_DEGLITCH);
 
 	pdev->resource[1].start = EIM_IRQ_BASE + extint;
 	pdev->resource[1].end = pdev->resource[1].start;
@@ -1982,6 +1986,7 @@ at32_add_device_ac97c(unsigned int id, struct ac97c_platform_data *data)
 {
 	struct platform_device *pdev;
 	struct ac97c_platform_data _data;
+	u32 pin_mask;
 
 	if (id != 0)
 		return NULL;
@@ -2008,10 +2013,10 @@ at32_add_device_ac97c(unsigned int id, struct ac97c_platform_data *data)
 				sizeof(struct ac97c_platform_data)))
 		goto fail;
 
-	select_peripheral(PB(20), PERIPH_B, 0);	/* SDO	*/
-	select_peripheral(PB(21), PERIPH_B, 0);	/* SYNC	*/
-	select_peripheral(PB(22), PERIPH_B, 0);	/* SCLK	*/
-	select_peripheral(PB(23), PERIPH_B, 0);	/* SDI	*/
+	pin_mask  = (1 << 20) | (1 << 21);	/* SDO & SYNC */
+	pin_mask |= (1 << 22) | (1 << 23);	/* SCLK & SDI */
+
+	select_peripheral(PIOB, pin_mask, PERIPH_B, 0);
 
 	/* TODO: gpio_is_valid(data->reset_pin) with kernel 2.6.26. */
 	if (data->reset_pin != GPIO_PIN_NONE)
@@ -2053,6 +2058,7 @@ static struct clk abdac0_sample_clk = {
 struct platform_device *__init at32_add_device_abdac(unsigned int id)
 {
 	struct platform_device *pdev;
+	u32 pin_mask;
 
 	if (id != 0)
 		return NULL;
@@ -2065,10 +2071,10 @@ struct platform_device *__init at32_add_device_abdac(unsigned int id)
 				ARRAY_SIZE(abdac0_resource)))
 		goto err_add_resources;
 
-	select_peripheral(PB(20), PERIPH_A, 0);	/* DATA1	*/
-	select_peripheral(PB(21), PERIPH_A, 0);	/* DATA0	*/
-	select_peripheral(PB(22), PERIPH_A, 0);	/* DATAN1	*/
-	select_peripheral(PB(23), PERIPH_A, 0);	/* DATAN0	*/
+	pin_mask  = (1 << 20) | (1 << 22);	/* DATA1 & DATAN1 */
+	pin_mask |= (1 << 21) | (1 << 23);	/* DATA0 & DATAN0 */
+
+	select_peripheral(PIOB, pin_mask, PERIPH_A, 0);
 
 	abdac0_pclk.dev = &pdev->dev;
 	abdac0_sample_clk.dev = &pdev->dev;
@@ -2125,7 +2131,7 @@ static struct clk gclk4 = {
 	.index		= 4,
 };
 
-struct clk *at32_clock_list[] = {
+static __initdata struct clk *init_clocks[] = {
 	&osc32k,
 	&osc0,
 	&osc1,
@@ -2189,7 +2195,6 @@ struct clk *at32_clock_list[] = {
 	&gclk3,
 	&gclk4,
 };
-unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
 
 void __init setup_platform(void)
 {
@@ -2220,14 +2225,19 @@ void __init setup_platform(void)
 	genclk_init_parent(&abdac0_sample_clk);
 
 	/*
-	 * Turn on all clocks that have at least one user already, and
-	 * turn off everything else. We only do this for module
-	 * clocks, and even though it isn't particularly pretty to
-	 * check the address of the mode function, it should do the
-	 * trick...
+	 * Build initial dynamic clock list by registering all clocks
+	 * from the array.
+	 * At the same time, turn on all clocks that have at least one
+	 * user already, and turn off everything else. We only do this
+	 * for module clocks, and even though it isn't particularly
+	 * pretty to  check the address of the mode function, it should
+	 * do the trick...
 	 */
-	for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) {
-		struct clk *clk = at32_clock_list[i];
+	for (i = 0; i < ARRAY_SIZE(init_clocks); i++) {
+		struct clk *clk = init_clocks[i];
+
+		/* first, register clock */
+		at32_clk_register(clk);
 
 		if (clk->users == 0)
 			continue;
diff --git a/arch/avr32/mach-at32ap/clock.c b/arch/avr32/mach-at32ap/clock.c
index 6c27ddac5adf10c6870c1c4679f8f6ab93411dc8..138a00a2a2d0c5c833723a0a6610e8baf6d42a5c 100644
--- a/arch/avr32/mach-at32ap/clock.c
+++ b/arch/avr32/mach-at32ap/clock.c
@@ -15,24 +15,40 @@
 #include <linux/err.h>
 #include <linux/device.h>
 #include <linux/string.h>
+#include <linux/list.h>
 
 #include <mach/chip.h>
 
 #include "clock.h"
 
+/* at32 clock list */
+static LIST_HEAD(at32_clock_list);
+
 static DEFINE_SPINLOCK(clk_lock);
+static DEFINE_SPINLOCK(clk_list_lock);
+
+void at32_clk_register(struct clk *clk)
+{
+	spin_lock(&clk_list_lock);
+	/* add the new item to the end of the list */
+	list_add_tail(&clk->list, &at32_clock_list);
+	spin_unlock(&clk_list_lock);
+}
 
 struct clk *clk_get(struct device *dev, const char *id)
 {
-	int i;
+	struct clk *clk;
 
-	for (i = 0; i < at32_nr_clocks; i++) {
-		struct clk *clk = at32_clock_list[i];
+	spin_lock(&clk_list_lock);
 
-		if (clk->dev == dev && strcmp(id, clk->name) == 0)
+	list_for_each_entry(clk, &at32_clock_list, list) {
+		if (clk->dev == dev && strcmp(id, clk->name) == 0) {
+			spin_unlock(&clk_list_lock);
 			return clk;
+		}
 	}
 
+	spin_unlock(&clk_list_lock);
 	return ERR_PTR(-ENOENT);
 }
 EXPORT_SYMBOL(clk_get);
@@ -203,8 +219,8 @@ dump_clock(struct clk *parent, struct clkinf *r)
 
 	/* cost of this scan is small, but not linear... */
 	r->nest = nest + NEST_DELTA;
-	for (i = 3; i < at32_nr_clocks; i++) {
-		clk = at32_clock_list[i];
+
+	list_for_each_entry(clk, &at32_clock_list, list) {
 		if (clk->parent == parent)
 			dump_clock(clk, r);
 	}
@@ -215,6 +231,7 @@ static int clk_show(struct seq_file *s, void *unused)
 {
 	struct clkinf	r;
 	int		i;
+	struct clk 	*clk;
 
 	/* show all the power manager registers */
 	seq_printf(s, "MCCTRL  = %8x\n", pm_readl(MCCTRL));
@@ -234,14 +251,25 @@ static int clk_show(struct seq_file *s, void *unused)
 
 	seq_printf(s, "\n");
 
-	/* show clock tree as derived from the three oscillators
-	 * we "know" are at the head of the list
-	 */
 	r.s = s;
 	r.nest = 0;
-	dump_clock(at32_clock_list[0], &r);
-	dump_clock(at32_clock_list[1], &r);
-	dump_clock(at32_clock_list[2], &r);
+	/* protected from changes on the list while dumping */
+	spin_lock(&clk_list_lock);
+
+	/* show clock tree as derived from the three oscillators */
+	clk = clk_get(NULL, "osc32k");
+	dump_clock(clk, &r);
+	clk_put(clk);
+
+	clk = clk_get(NULL, "osc0");
+	dump_clock(clk, &r);
+	clk_put(clk);
+
+	clk = clk_get(NULL, "osc1");
+	dump_clock(clk, &r);
+	clk_put(clk);
+
+	spin_unlock(&clk_list_lock);
 
 	return 0;
 }
diff --git a/arch/avr32/mach-at32ap/clock.h b/arch/avr32/mach-at32ap/clock.h
index bb8e1f295835e95fa306c42071a6d5c55fe4fe3b..623bf0e9a1e7a843ff66c02ed0aa4961dc3b784d 100644
--- a/arch/avr32/mach-at32ap/clock.h
+++ b/arch/avr32/mach-at32ap/clock.h
@@ -12,8 +12,13 @@
  * published by the Free Software Foundation.
  */
 #include <linux/clk.h>
+#include <linux/list.h>
+
+
+void at32_clk_register(struct clk *clk);
 
 struct clk {
+	struct list_head list;		/* linking element */
 	const char	*name;		/* Clock name/function */
 	struct device	*dev;		/* Device the clock is used by */
 	struct clk	*parent;	/* Parent clock, if any */
@@ -25,6 +30,3 @@ struct clk {
 	u16		users;		/* Enabled if non-zero */
 	u16		index;		/* Sibling index */
 };
-
-extern struct clk *at32_clock_list[];
-extern unsigned int at32_nr_clocks;
diff --git a/arch/avr32/mach-at32ap/include/mach/at32ap700x.h b/arch/avr32/mach-at32ap/include/mach/at32ap700x.h
index 1e9852d65ccaf04256dc96df8968984c772e692a..a77d372f6f3ea8660ffeec96cc31b52381a04b77 100644
--- a/arch/avr32/mach-at32ap/include/mach/at32ap700x.h
+++ b/arch/avr32/mach-at32ap/include/mach/at32ap700x.h
@@ -83,4 +83,132 @@
 #define HMATRIX_BASE	0xfff00800
 #define SDRAMC_BASE	0xfff03800
 
+/* LCDC on port C */
+#define ATMEL_LCDC_PC_CC	(1ULL << 19)
+#define ATMEL_LCDC_PC_HSYNC	(1ULL << 20)
+#define ATMEL_LCDC_PC_PCLK	(1ULL << 21)
+#define ATMEL_LCDC_PC_VSYNC	(1ULL << 22)
+#define ATMEL_LCDC_PC_DVAL	(1ULL << 23)
+#define ATMEL_LCDC_PC_MODE	(1ULL << 24)
+#define ATMEL_LCDC_PC_PWR	(1ULL << 25)
+#define ATMEL_LCDC_PC_DATA0	(1ULL << 26)
+#define ATMEL_LCDC_PC_DATA1	(1ULL << 27)
+#define ATMEL_LCDC_PC_DATA2	(1ULL << 28)
+#define ATMEL_LCDC_PC_DATA3	(1ULL << 29)
+#define ATMEL_LCDC_PC_DATA4	(1ULL << 30)
+#define ATMEL_LCDC_PC_DATA5	(1ULL << 31)
+
+/* LCDC on port D */
+#define ATMEL_LCDC_PD_DATA6	(1ULL << 0)
+#define ATMEL_LCDC_PD_DATA7	(1ULL << 1)
+#define ATMEL_LCDC_PD_DATA8	(1ULL << 2)
+#define ATMEL_LCDC_PD_DATA9	(1ULL << 3)
+#define ATMEL_LCDC_PD_DATA10	(1ULL << 4)
+#define ATMEL_LCDC_PD_DATA11	(1ULL << 5)
+#define ATMEL_LCDC_PD_DATA12	(1ULL << 6)
+#define ATMEL_LCDC_PD_DATA13	(1ULL << 7)
+#define ATMEL_LCDC_PD_DATA14	(1ULL << 8)
+#define ATMEL_LCDC_PD_DATA15	(1ULL << 9)
+#define ATMEL_LCDC_PD_DATA16	(1ULL << 10)
+#define ATMEL_LCDC_PD_DATA17	(1ULL << 11)
+#define ATMEL_LCDC_PD_DATA18	(1ULL << 12)
+#define ATMEL_LCDC_PD_DATA19	(1ULL << 13)
+#define ATMEL_LCDC_PD_DATA20	(1ULL << 14)
+#define ATMEL_LCDC_PD_DATA21	(1ULL << 15)
+#define ATMEL_LCDC_PD_DATA22	(1ULL << 16)
+#define ATMEL_LCDC_PD_DATA23	(1ULL << 17)
+
+/* LCDC on port E */
+#define ATMEL_LCDC_PE_CC	(1ULL << (32 + 0))
+#define ATMEL_LCDC_PE_DVAL	(1ULL << (32 + 1))
+#define ATMEL_LCDC_PE_MODE	(1ULL << (32 + 2))
+#define ATMEL_LCDC_PE_DATA0	(1ULL << (32 + 3))
+#define ATMEL_LCDC_PE_DATA1	(1ULL << (32 + 4))
+#define ATMEL_LCDC_PE_DATA2	(1ULL << (32 + 5))
+#define ATMEL_LCDC_PE_DATA3	(1ULL << (32 + 6))
+#define ATMEL_LCDC_PE_DATA4	(1ULL << (32 + 7))
+#define ATMEL_LCDC_PE_DATA8	(1ULL << (32 + 8))
+#define ATMEL_LCDC_PE_DATA9	(1ULL << (32 + 9))
+#define ATMEL_LCDC_PE_DATA10	(1ULL << (32 + 10))
+#define ATMEL_LCDC_PE_DATA11	(1ULL << (32 + 11))
+#define ATMEL_LCDC_PE_DATA12	(1ULL << (32 + 12))
+#define ATMEL_LCDC_PE_DATA16	(1ULL << (32 + 13))
+#define ATMEL_LCDC_PE_DATA17	(1ULL << (32 + 14))
+#define ATMEL_LCDC_PE_DATA18	(1ULL << (32 + 15))
+#define ATMEL_LCDC_PE_DATA19	(1ULL << (32 + 16))
+#define ATMEL_LCDC_PE_DATA20	(1ULL << (32 + 17))
+#define ATMEL_LCDC_PE_DATA21	(1ULL << (32 + 18))
+
+
+#define ATMEL_LCDC(PORT, PIN)	(ATMEL_LCDC_##PORT##_##PIN)
+
+
+#define ATMEL_LCDC_PRI_24B_DATA	(					\
+		ATMEL_LCDC(PC, DATA0)  | ATMEL_LCDC(PC, DATA1)  |	\
+		ATMEL_LCDC(PC, DATA2)  | ATMEL_LCDC(PC, DATA3)  |	\
+		ATMEL_LCDC(PC, DATA4)  | ATMEL_LCDC(PC, DATA5)  |	\
+		ATMEL_LCDC(PD, DATA6)  | ATMEL_LCDC(PD, DATA7)  |	\
+		ATMEL_LCDC(PD, DATA8)  | ATMEL_LCDC(PD, DATA9)  |	\
+		ATMEL_LCDC(PD, DATA10) | ATMEL_LCDC(PD, DATA11) |	\
+		ATMEL_LCDC(PD, DATA12) | ATMEL_LCDC(PD, DATA13) |	\
+		ATMEL_LCDC(PD, DATA14) | ATMEL_LCDC(PD, DATA15) |	\
+		ATMEL_LCDC(PD, DATA16) | ATMEL_LCDC(PD, DATA17) |	\
+		ATMEL_LCDC(PD, DATA18) | ATMEL_LCDC(PD, DATA19) |	\
+		ATMEL_LCDC(PD, DATA20) | ATMEL_LCDC(PD, DATA21) |	\
+		ATMEL_LCDC(PD, DATA22) | ATMEL_LCDC(PD, DATA23))
+
+#define ATMEL_LCDC_ALT_24B_DATA (					\
+		ATMEL_LCDC(PE, DATA0)  | ATMEL_LCDC(PE, DATA1)  |	\
+		ATMEL_LCDC(PE, DATA2)  | ATMEL_LCDC(PE, DATA3)  |	\
+		ATMEL_LCDC(PE, DATA4)  | ATMEL_LCDC(PC, DATA5)  |	\
+		ATMEL_LCDC(PD, DATA6)  | ATMEL_LCDC(PD, DATA7)  |	\
+		ATMEL_LCDC(PE, DATA8)  | ATMEL_LCDC(PE, DATA9)  |	\
+		ATMEL_LCDC(PE, DATA10) | ATMEL_LCDC(PE, DATA11) |	\
+		ATMEL_LCDC(PE, DATA12) | ATMEL_LCDC(PD, DATA13) |	\
+		ATMEL_LCDC(PD, DATA14) | ATMEL_LCDC(PD, DATA15) |	\
+		ATMEL_LCDC(PE, DATA16) | ATMEL_LCDC(PE, DATA17) |	\
+		ATMEL_LCDC(PE, DATA18) | ATMEL_LCDC(PE, DATA19) |	\
+		ATMEL_LCDC(PE, DATA20) | ATMEL_LCDC(PE, DATA21) |	\
+		ATMEL_LCDC(PD, DATA22) | ATMEL_LCDC(PD, DATA23))
+
+#define ATMEL_LCDC_PRI_15B_DATA (					\
+		ATMEL_LCDC(PC, DATA0)  | ATMEL_LCDC(PC, DATA1)  |	\
+		ATMEL_LCDC(PC, DATA2)  | ATMEL_LCDC(PC, DATA3)  |	\
+		ATMEL_LCDC(PC, DATA4)  | ATMEL_LCDC(PC, DATA5)  |	\
+		ATMEL_LCDC(PD, DATA8)  | ATMEL_LCDC(PD, DATA9)  |	\
+		ATMEL_LCDC(PD, DATA10) | ATMEL_LCDC(PD, DATA11) |	\
+		ATMEL_LCDC(PD, DATA12) | ATMEL_LCDC(PD, DATA16) |	\
+		ATMEL_LCDC(PD, DATA17) | ATMEL_LCDC(PD, DATA18) |	\
+		ATMEL_LCDC(PD, DATA19) | ATMEL_LCDC(PD, DATA20))
+
+#define ATMEL_LCDC_ALT_15B_DATA	(					\
+		ATMEL_LCDC(PE, DATA0)  | ATMEL_LCDC(PE, DATA1)  |	\
+		ATMEL_LCDC(PE, DATA2)  | ATMEL_LCDC(PE, DATA3)  |	\
+		ATMEL_LCDC(PE, DATA4)  | ATMEL_LCDC(PC, DATA5)  |	\
+		ATMEL_LCDC(PE, DATA8)  | ATMEL_LCDC(PE, DATA9)  |	\
+		ATMEL_LCDC(PE, DATA10) | ATMEL_LCDC(PE, DATA11) |	\
+		ATMEL_LCDC(PE, DATA12) | ATMEL_LCDC(PE, DATA16) |	\
+		ATMEL_LCDC(PE, DATA17) | ATMEL_LCDC(PE, DATA18) |	\
+		ATMEL_LCDC(PE, DATA19) | ATMEL_LCDC(PE, DATA20))
+
+#define ATMEL_LCDC_PRI_CONTROL (					\
+		ATMEL_LCDC(PC, CC)   | ATMEL_LCDC(PC, DVAL) |		\
+		ATMEL_LCDC(PC, MODE) | ATMEL_LCDC(PC, PWR))
+
+#define ATMEL_LCDC_ALT_CONTROL (					\
+		ATMEL_LCDC(PE, CC)   | ATMEL_LCDC(PE, DVAL) |		\
+		ATMEL_LCDC(PE, MODE) | ATMEL_LCDC(PC, PWR))
+
+#define ATMEL_LCDC_CONTROL (						\
+		ATMEL_LCDC(PC, HSYNC) | ATMEL_LCDC(PC, VSYNC) |		\
+		ATMEL_LCDC(PC, PCLK))
+
+#define ATMEL_LCDC_PRI_24BIT	(ATMEL_LCDC_CONTROL | ATMEL_LCDC_PRI_24B_DATA)
+
+#define ATMEL_LCDC_ALT_24BIT	(ATMEL_LCDC_CONTROL | ATMEL_LCDC_ALT_24B_DATA)
+
+#define ATMEL_LCDC_PRI_15BIT	(ATMEL_LCDC_CONTROL | ATMEL_LCDC_PRI_15B_DATA)
+
+#define ATMEL_LCDC_ALT_15BIT	(ATMEL_LCDC_CONTROL | ATMEL_LCDC_ALT_15B_DATA)
+
 #endif /* __ASM_ARCH_AT32AP700X_H__ */
diff --git a/arch/avr32/mach-at32ap/include/mach/board.h b/arch/avr32/mach-at32ap/include/mach/board.h
index e60e9076544d08ace7891dbe1d1ffbf31df4f45f..c48386d66bc38f9fb0c1e287748b6de16a8ac903 100644
--- a/arch/avr32/mach-at32ap/include/mach/board.h
+++ b/arch/avr32/mach-at32ap/include/mach/board.h
@@ -43,7 +43,7 @@ struct atmel_lcdfb_info;
 struct platform_device *
 at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
 		     unsigned long fbmem_start, unsigned long fbmem_len,
-		     unsigned int pin_config);
+		     u64 pin_mask);
 
 struct usba_platform_data;
 struct platform_device *
diff --git a/arch/avr32/mach-at32ap/include/mach/io.h b/arch/avr32/mach-at32ap/include/mach/io.h
index 4ec6abc68ea38084fae0a1d269f5fd53ebe34589..22ea79b740528b62dcd0bc9c4a211e2236bde564 100644
--- a/arch/avr32/mach-at32ap/include/mach/io.h
+++ b/arch/avr32/mach-at32ap/include/mach/io.h
@@ -1,8 +1,7 @@
 #ifndef __ASM_AVR32_ARCH_AT32AP_IO_H
 #define __ASM_AVR32_ARCH_AT32AP_IO_H
 
-/* For "bizarre" halfword swapping */
-#include <linux/byteorder/swabb.h>
+#include <linux/swab.h>
 
 #if defined(CONFIG_AP700X_32_BIT_SMC)
 # define __swizzle_addr_b(addr)	(addr ^ 3UL)
diff --git a/arch/avr32/mach-at32ap/include/mach/portmux.h b/arch/avr32/mach-at32ap/include/mach/portmux.h
index b1abe6b4e4efef469f8098dd2d1ebb04873d937d..21c79373b53f04dae129e8a3907638f180577b7e 100644
--- a/arch/avr32/mach-at32ap/include/mach/portmux.h
+++ b/arch/avr32/mach-at32ap/include/mach/portmux.h
@@ -21,9 +21,10 @@
 #define AT32_GPIOF_DEGLITCH	0x00000008	/* (IN) Filter glitches */
 #define AT32_GPIOF_MULTIDRV	0x00000010	/* Enable multidriver option */
 
-void at32_select_periph(unsigned int pin, unsigned int periph,
-			unsigned long flags);
+void at32_select_periph(unsigned int port, unsigned int pin,
+			unsigned int periph, unsigned long flags);
 void at32_select_gpio(unsigned int pin, unsigned long flags);
+void at32_deselect_pin(unsigned int pin);
 void at32_reserve_pin(unsigned int pin);
 
 #endif /* __ASM_ARCH_PORTMUX_H__ */
diff --git a/arch/avr32/mach-at32ap/pdc.c b/arch/avr32/mach-at32ap/pdc.c
index 1040bda4fda7c843ea0d4955129f17cc94ab79bd..61ab15aae97008e798f5b89d6a225d195ca1b578 100644
--- a/arch/avr32/mach-at32ap/pdc.c
+++ b/arch/avr32/mach-at32ap/pdc.c
@@ -35,7 +35,6 @@ static int __init pdc_probe(struct platform_device *pdev)
 }
 
 static struct platform_driver pdc_driver = {
-	.probe		= pdc_probe,
 	.driver		= {
 		.name	= "pdc",
 	},
@@ -43,6 +42,6 @@ static struct platform_driver pdc_driver = {
 
 static int __init pdc_init(void)
 {
-	return platform_driver_register(&pdc_driver);
+	return platform_driver_probe(&pdc_driver, pdc_probe);
 }
 arch_initcall(pdc_init);
diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c
index 405ee6bad4ce59dd888448b100daba698cf12b0c..ed81a8bcb22d44ffa733beed2b43119caca29036 100644
--- a/arch/avr32/mach-at32ap/pio.c
+++ b/arch/avr32/mach-at32ap/pio.c
@@ -50,35 +50,48 @@ static struct pio_device *gpio_to_pio(unsigned int gpio)
 }
 
 /* Pin multiplexing API */
+static DEFINE_SPINLOCK(pio_lock);
 
-void __init at32_select_periph(unsigned int pin, unsigned int periph,
-			       unsigned long flags)
+void __init at32_select_periph(unsigned int port, u32 pin_mask,
+			       unsigned int periph, unsigned long flags)
 {
 	struct pio_device *pio;
-	unsigned int pin_index = pin & 0x1f;
-	u32 mask = 1 << pin_index;
 
-	pio = gpio_to_pio(pin);
+	/* assign and verify pio */
+	pio = gpio_to_pio(port);
 	if (unlikely(!pio)) {
-		printk("pio: invalid pin %u\n", pin);
+		printk(KERN_WARNING "pio: invalid port %u\n", port);
 		goto fail;
 	}
 
-	if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask)
-			 || gpiochip_is_requested(&pio->chip, pin_index))) {
-		printk("%s: pin %u is busy\n", pio->name, pin_index);
+	/* Test if any of the requested pins is already muxed */
+	spin_lock(&pio_lock);
+	if (unlikely(pio->pinmux_mask & pin_mask)) {
+		printk(KERN_WARNING "%s: pin(s) busy (requested 0x%x, busy 0x%x)\n",
+		       pio->name, pin_mask, pio->pinmux_mask & pin_mask);
+		spin_unlock(&pio_lock);
 		goto fail;
 	}
 
-	pio_writel(pio, PUER, mask);
+	pio->pinmux_mask |= pin_mask;
+
+	/* enable pull ups */
+	pio_writel(pio, PUER, pin_mask);
+
+	/* select either peripheral A or B */
 	if (periph)
-		pio_writel(pio, BSR, mask);
+		pio_writel(pio, BSR, pin_mask);
 	else
-		pio_writel(pio, ASR, mask);
+		pio_writel(pio, ASR, pin_mask);
+
+	/* enable peripheral control */
+	pio_writel(pio, PDR, pin_mask);
 
-	pio_writel(pio, PDR, mask);
+	/* Disable pull ups if not requested. */
 	if (!(flags & AT32_GPIOF_PULLUP))
-		pio_writel(pio, PUDR, mask);
+		pio_writel(pio, PUDR, pin_mask);
+
+	spin_unlock(&pio_lock);
 
 	return;
 
@@ -134,6 +147,25 @@ void __init at32_select_gpio(unsigned int pin, unsigned long flags)
 	dump_stack();
 }
 
+/*
+ * Undo a previous pin reservation. Will not affect the hardware
+ * configuration.
+ */
+void at32_deselect_pin(unsigned int pin)
+{
+	struct pio_device *pio;
+	unsigned int pin_index = pin & 0x1f;
+
+	pio = gpio_to_pio(pin);
+	if (unlikely(!pio)) {
+		printk("pio: invalid pin %u\n", pin);
+		dump_stack();
+		return;
+	}
+
+	clear_bit(pin_index, &pio->pinmux_mask);
+}
+
 /* Reserve a pin, preventing anyone else from changing its configuration. */
 void __init at32_reserve_pin(unsigned int pin)
 {
@@ -382,7 +414,6 @@ static int __init pio_probe(struct platform_device *pdev)
 }
 
 static struct platform_driver pio_driver = {
-	.probe		= pio_probe,
 	.driver		= {
 		.name		= "pio",
 	},
@@ -390,7 +421,7 @@ static struct platform_driver pio_driver = {
 
 static int __init pio_init(void)
 {
-	return platform_driver_register(&pio_driver);
+	return platform_driver_probe(&pio_driver, pio_probe);
 }
 postcore_initcall(pio_init);
 
diff --git a/arch/avr32/oprofile/Makefile b/arch/avr32/oprofile/Makefile
index 1fe81c3c1e86921cedd64597ce3f3fb515007f0b..e0eb520e02872e01cec8fdb69c61439c27cc13fc 100644
--- a/arch/avr32/oprofile/Makefile
+++ b/arch/avr32/oprofile/Makefile
@@ -5,4 +5,4 @@ oprofile-y		:= $(addprefix ../../../drivers/oprofile/,	\
 				event_buffer.o oprofile_files.o		\
 				oprofilefs.o oprofile_stats.o		\
 				timer_int.o)
-oprofile-y		+= op_model_avr32.o
+oprofile-y		+= op_model_avr32.o backtrace.o
diff --git a/arch/avr32/oprofile/backtrace.c b/arch/avr32/oprofile/backtrace.c
new file mode 100644
index 0000000000000000000000000000000000000000..75d9ad6f99cf56e8071eff21157ed3da0dfef4b7
--- /dev/null
+++ b/arch/avr32/oprofile/backtrace.c
@@ -0,0 +1,81 @@
+/*
+ * AVR32 specific backtracing code for oprofile
+ *
+ * Copyright 2008 Weinmann GmbH
+ *
+ * Author: Nikolaus Voss <n.voss@weinmann.de>
+ *
+ * Based on i386 oprofile backtrace code by John Levon and David Smith
+ *
+ * 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.
+ *
+ */
+
+#include <linux/oprofile.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+
+/* The first two words of each frame on the stack look like this if we have
+ * frame pointers */
+struct frame_head {
+	unsigned long lr;
+	struct frame_head *fp;
+};
+
+/* copied from arch/avr32/kernel/process.c */
+static inline int valid_stack_ptr(struct thread_info *tinfo, unsigned long p)
+{
+	return (p > (unsigned long)tinfo)
+		&& (p < (unsigned long)tinfo + THREAD_SIZE - 3);
+}
+
+/* copied from arch/x86/oprofile/backtrace.c */
+static struct frame_head *dump_user_backtrace(struct frame_head *head)
+{
+	struct frame_head bufhead[2];
+
+	/* Also check accessibility of one struct frame_head beyond */
+	if (!access_ok(VERIFY_READ, head, sizeof(bufhead)))
+		return NULL;
+	if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead)))
+		return NULL;
+
+	oprofile_add_trace(bufhead[0].lr);
+
+	/* frame pointers should strictly progress back up the stack
+	 * (towards higher addresses) */
+	if (bufhead[0].fp <= head)
+		return NULL;
+
+	return bufhead[0].fp;
+}
+
+void avr32_backtrace(struct pt_regs * const regs, unsigned int depth)
+{
+	/* Get first frame pointer */
+	struct frame_head *head = (struct frame_head *)(regs->r7);
+
+	if (!user_mode(regs)) {
+#ifdef CONFIG_FRAME_POINTER
+		/*
+		 * Traverse the kernel stack from frame to frame up to
+		 * "depth" steps.
+		 */
+		while (depth-- && valid_stack_ptr(task_thread_info(current),
+						  (unsigned long)head)) {
+			oprofile_add_trace(head->lr);
+			if (head->fp <= head)
+				break;
+			head = head->fp;
+		}
+#endif
+	} else {
+		/* Assume we have frame pointers in user mode process */
+		while (depth-- && head)
+			head = dump_user_backtrace(head);
+	}
+}
+
+
diff --git a/arch/avr32/oprofile/op_model_avr32.c b/arch/avr32/oprofile/op_model_avr32.c
index df42325c7f81da49e882c23c535a8eafd7a2356c..a3e9b3c4845a50f0fc53bf164923a084650f5c17 100644
--- a/arch/avr32/oprofile/op_model_avr32.c
+++ b/arch/avr32/oprofile/op_model_avr32.c
@@ -22,6 +22,8 @@
 #define AVR32_PERFCTR_IRQ_GROUP	0
 #define AVR32_PERFCTR_IRQ_LINE	1
 
+void avr32_backtrace(struct pt_regs * const regs, unsigned int depth);
+
 enum { PCCNT, PCNT0, PCNT1, NR_counter };
 
 struct avr32_perf_counter {
@@ -223,6 +225,8 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
 	memcpy(ops, &avr32_perf_counter_ops,
 			sizeof(struct oprofile_operations));
 
+	ops->backtrace = avr32_backtrace;
+
 	printk(KERN_INFO "oprofile: using AVR32 performance monitoring.\n");
 
 	return 0;