Merge git://git.kernel.org/pub/scm/linux/kernel/git/hskinnemoen/avr32-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/hskinnemoen/avr32-2.6: (31 commits)
  avr32: Fix typo of IFSR in a comment in the PIO header file
  avr32: Power Management support ("standby" and "mem" modes)
  avr32: Add system device for the internal interrupt controller (intc)
  avr32: Add simple SRAM allocator
  avr32: Enable SDRAMC clock at startup
  rtc-at32ap700x: Enable wakeup
  macb: Basic suspend/resume support
  atmel_serial: Drain console TX shifter before suspending
  atmel_serial: Fix build on avr32 with CONFIG_PM enabled
  avr32: Use a quicklist for PTE allocation as well
  avr32: Use a quicklist for PGD allocation
  avr32: Cover the kernel page tables in the user PGDs
  avr32: Store virtual addresses in the PGD
  avr32: Remove useless zeroing of swapper_pg_dir at startup
  avr32: Clean up and optimize the TLB operations
  avr32: Rename at32ap.c -> pdc.c
  avr32: Move setup_platform() into chip-specific file
  avr32: Kill special exception handler sections
  avr32: Kill unneeded #include <asm/pgalloc.h> from asm/mmu_context.h
  avr32: Clean up time.c #includes
  ...
diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig
index 09ad799..45d63c9 100644
--- a/arch/avr32/Kconfig
+++ b/arch/avr32/Kconfig
@@ -88,6 +88,7 @@
 	select MMU
 	select PERFORMANCE_COUNTERS
 	select HAVE_GPIO_LIB
+	select GENERIC_ALLOCATOR
 
 #
 # CPU types
@@ -147,6 +148,9 @@
 
 source "kernel/Kconfig.preempt"
 
+config QUICKLIST
+	def_bool y
+
 config HAVE_ARCH_BOOTMEM_NODE
 	def_bool n
 
@@ -201,6 +205,11 @@
 
 menu "Power management options"
 
+source "kernel/power/Kconfig"
+
+config ARCH_SUSPEND_POSSIBLE
+	def_bool y
+
 menu "CPU Frequency scaling"
 
 source "drivers/cpufreq/Kconfig"
diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c
index a398be2..a51bb9f 100644
--- a/arch/avr32/boards/atngw100/setup.c
+++ b/arch/avr32/boards/atngw100/setup.c
@@ -9,6 +9,8 @@
  */
 #include <linux/clk.h>
 #include <linux/etherdevice.h>
+#include <linux/irq.h>
+#include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
 #include <linux/init.h>
 #include <linux/linkage.h>
@@ -25,6 +27,13 @@
 #include <asm/arch/init.h>
 #include <asm/arch/portmux.h>
 
+/* Oscillator frequencies. These are board-specific */
+unsigned long at32_board_osc_rates[3] = {
+	[0] = 32768,	/* 32.768 kHz on RTC osc */
+	[1] = 20000000,	/* 20 MHz on osc0 */
+	[2] = 12000000,	/* 12 MHz on osc1 */
+};
+
 /* Initialized by bootloader-specific startup code. */
 struct tag *bootloader_tags __initdata;
 
@@ -140,6 +149,10 @@
 	},
 };
 
+static struct i2c_board_info __initdata i2c_info[] = {
+	/* NOTE:  original ATtiny24 firmware is at address 0x0b */
+};
+
 static int __init atngw100_init(void)
 {
 	unsigned	i;
@@ -165,12 +178,28 @@
 	}
 	platform_device_register(&ngw_gpio_leds);
 
+	/* all these i2c/smbus pins should have external pullups for
+	 * open-drain sharing among all I2C devices.  SDA and SCL do;
+	 * 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_gpio(i2c_gpio_data.sda_pin,
 		AT32_GPIOF_MULTIDRV | AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
 	at32_select_gpio(i2c_gpio_data.scl_pin,
 		AT32_GPIOF_MULTIDRV | AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
 	platform_device_register(&i2c_gpio_device);
+	i2c_register_board_info(0, i2c_info, ARRAY_SIZE(i2c_info));
 
 	return 0;
 }
 postcore_initcall(atngw100_init);
+
+static int __init atngw100_arch_init(void)
+{
+	/* set_irq_type() after the arch_initcall for EIC has run, and
+	 * before the I2C subsystem could try using this IRQ.
+	 */
+	return set_irq_type(AT32_EXTINT(3), IRQ_TYPE_EDGE_FALLING);
+}
+arch_initcall(atngw100_arch_init);
diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c
index 000eb42..86b363c 100644
--- a/arch/avr32/boards/atstk1000/atstk1002.c
+++ b/arch/avr32/boards/atstk1000/atstk1002.c
@@ -28,6 +28,12 @@
 
 #include "atstk1000.h"
 
+/* Oscillator frequencies. These are board specific */
+unsigned long at32_board_osc_rates[3] = {
+	[0] = 32768,	/* 32.768 kHz on RTC osc */
+	[1] = 20000000,	/* 20 MHz on osc0 */
+	[2] = 12000000,	/* 12 MHz on osc1 */
+};
 
 struct eth_addr {
 	u8 addr[6];
@@ -232,7 +238,7 @@
 	set_hw_addr(at32_add_device_eth(1, &eth_data[1]));
 #else
 	at32_add_device_lcdc(0, &atstk1000_lcdc_data,
-			     fbmem_start, fbmem_size);
+			     fbmem_start, fbmem_size, 0);
 #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 a0b223d..ea109f4 100644
--- a/arch/avr32/boards/atstk1000/atstk1003.c
+++ b/arch/avr32/boards/atstk1000/atstk1003.c
@@ -27,6 +27,13 @@
 
 #include "atstk1000.h"
 
+/* Oscillator frequencies. These are board specific */
+unsigned long at32_board_osc_rates[3] = {
+	[0] = 32768,	/* 32.768 kHz on RTC osc */
+	[1] = 20000000,	/* 20 MHz on osc0 */
+	[2] = 12000000,	/* 12 MHz on osc1 */
+};
+
 #ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
 static struct at73c213_board_info at73c213_data = {
 	.ssc_id		= 0,
diff --git a/arch/avr32/boards/atstk1000/atstk1004.c b/arch/avr32/boards/atstk1000/atstk1004.c
index e765a86..c7236df 100644
--- a/arch/avr32/boards/atstk1000/atstk1004.c
+++ b/arch/avr32/boards/atstk1000/atstk1004.c
@@ -29,6 +29,13 @@
 
 #include "atstk1000.h"
 
+/* Oscillator frequencies. These are board specific */
+unsigned long at32_board_osc_rates[3] = {
+	[0] = 32768,	/* 32.768 kHz on RTC osc */
+	[1] = 20000000,	/* 20 MHz on osc0 */
+	[2] = 12000000,	/* 12 MHz on osc1 */
+};
+
 #ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
 static struct at73c213_board_info at73c213_data = {
 	.ssc_id		= 0,
@@ -133,7 +140,7 @@
 	at32_add_device_mci(0);
 #endif
 	at32_add_device_lcdc(0, &atstk1000_lcdc_data,
-			     fbmem_start, fbmem_size);
+			     fbmem_start, fbmem_size, 0);
 	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/kernel/entry-avr32b.S b/arch/avr32/kernel/entry-avr32b.S
index 5f31702..2b398ca 100644
--- a/arch/avr32/kernel/entry-avr32b.S
+++ b/arch/avr32/kernel/entry-avr32b.S
@@ -74,50 +74,41 @@
 	.align	2
 	bral	do_dtlb_modified
 
-	/*
-	 * r0 :	PGD/PT/PTE
-	 * r1 : Offending address
-	 * r2 : Scratch register
-	 * r3 : Cause (5, 12 or 13)
-	 */
 #define	tlbmiss_save	pushm	r0-r3
 #define tlbmiss_restore	popm	r0-r3
 
-	.section .tlbx.ex.text,"ax",@progbits
+	.org	0x50
 	.global	itlb_miss
 itlb_miss:
 	tlbmiss_save
 	rjmp	tlb_miss_common
 
-	.section .tlbr.ex.text,"ax",@progbits
+	.org	0x60
 dtlb_miss_read:
 	tlbmiss_save
 	rjmp	tlb_miss_common
 
-	.section .tlbw.ex.text,"ax",@progbits
+	.org	0x70
 dtlb_miss_write:
 	tlbmiss_save
 
 	.global	tlb_miss_common
+	.align	2
 tlb_miss_common:
 	mfsr	r0, SYSREG_TLBEAR
 	mfsr	r1, SYSREG_PTBR
 
-	/* Is it the vmalloc space? */
-	bld	r0, 31
-	brcs	handle_vmalloc_miss
-
-	/* First level lookup */
+	/*
+	 * First level lookup: The PGD contains virtual pointers to
+	 * the second-level page tables, but they may be NULL if not
+	 * present.
+	 */
 pgtbl_lookup:
 	lsr	r2, r0, PGDIR_SHIFT
 	ld.w	r3, r1[r2 << 2]
 	bfextu	r1, r0, PAGE_SHIFT, PGDIR_SHIFT - PAGE_SHIFT
-	bld	r3, _PAGE_BIT_PRESENT
-	brcc	page_table_not_present
-
-	/* Translate to virtual address in P1. */
-	andl	r3, 0xf000
-	sbr	r3, 31
+	cp.w	r3, 0
+	breq	page_table_not_present
 
 	/* Second level lookup */
 	ld.w	r2, r3[r1 << 2]
@@ -148,16 +139,55 @@
 	tlbmiss_restore
 	rete
 
-handle_vmalloc_miss:
-	/* Simply do the lookup in init's page table */
+	/* The slow path of the TLB miss handler */
+	.align	2
+page_table_not_present:
+	/* Do we need to synchronize with swapper_pg_dir? */
+	bld	r0, 31
+	brcs	sync_with_swapper_pg_dir
+
+page_not_present:
+	tlbmiss_restore
+	sub	sp, 4
+	stmts	--sp, r0-lr
+	rcall	save_full_context_ex
+	mfsr	r12, SYSREG_ECR
+	mov	r11, sp
+	rcall	do_page_fault
+	rjmp	ret_from_exception
+
+	.align	2
+sync_with_swapper_pg_dir:
+	/*
+	 * If swapper_pg_dir contains a non-NULL second-level page
+	 * table pointer, copy it into the current PGD. If not, we
+	 * must handle it as a full-blown page fault.
+	 *
+	 * Jumping back to pgtbl_lookup causes an unnecessary lookup,
+	 * but it is guaranteed to be a cache hit, it won't happen
+	 * very often, and we absolutely do not want to sacrifice any
+	 * performance in the fast path in order to improve this.
+	 */
 	mov	r1, lo(swapper_pg_dir)
 	orh	r1, hi(swapper_pg_dir)
+	ld.w	r3, r1[r2 << 2]
+	cp.w	r3, 0
+	breq	page_not_present
+	mfsr	r1, SYSREG_PTBR
+	st.w	r1[r2 << 2], r3
 	rjmp	pgtbl_lookup
 
+	/*
+	 * We currently have two bytes left at this point until we
+	 * crash into the system call handler...
+	 *
+	 * Don't worry, the assembler will let us know.
+	 */
+
 
 	/* ---                    System Call                    --- */
 
-	.section .scall.text,"ax",@progbits
+	.org	0x100
 system_call:
 #ifdef CONFIG_PREEMPT
 	mask_interrupts
@@ -266,18 +296,6 @@
 	brcc	syscall_exit_cont
 	rjmp	enter_monitor_mode
 
-	/* The slow path of the TLB miss handler */
-page_table_not_present:
-page_not_present:
-	tlbmiss_restore
-	sub	sp, 4
-	stmts	--sp, r0-lr
-	rcall	save_full_context_ex
-	mfsr	r12, SYSREG_ECR
-	mov	r11, sp
-	rcall	do_page_fault
-	rjmp	ret_from_exception
-
 	/* This function expects to find offending PC in SYSREG_RAR_EX */
 	.type	save_full_context_ex, @function
 	.align	2
diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c
index 5616a00..c5b11f9 100644
--- a/arch/avr32/kernel/signal.c
+++ b/arch/avr32/kernel/signal.c
@@ -93,6 +93,9 @@
 	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
 		goto badframe;
 
+	if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT)
+		goto badframe;
+
 	pr_debug("Context restored: pc = %08lx, lr = %08lx, sp = %08lx\n",
 		 regs->pc, regs->lr, regs->sp);
 
diff --git a/arch/avr32/kernel/time.c b/arch/avr32/kernel/time.c
index 00a9862..abd954f 100644
--- a/arch/avr32/kernel/time.c
+++ b/arch/avr32/kernel/time.c
@@ -7,21 +7,13 @@
  */
 #include <linux/clk.h>
 #include <linux/clockchips.h>
-#include <linux/time.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
-#include <linux/kernel_stat.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/profile.h>
-#include <linux/sysdev.h>
-#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
 
-#include <asm/div64.h>
 #include <asm/sysreg.h>
-#include <asm/io.h>
-#include <asm/sections.h>
 
 #include <asm/arch/pm.h>
 
diff --git a/arch/avr32/kernel/vmlinux.lds.S b/arch/avr32/kernel/vmlinux.lds.S
index 481cfd4..5d25d8e 100644
--- a/arch/avr32/kernel/vmlinux.lds.S
+++ b/arch/avr32/kernel/vmlinux.lds.S
@@ -68,14 +68,6 @@
 		_evba = .;
 		_text = .;
 		*(.ex.text)
-		. = 0x50;
-		*(.tlbx.ex.text)
-		. = 0x60;
-		*(.tlbr.ex.text)
-		. = 0x70;
-		*(.tlbw.ex.text)
-		. = 0x100;
-		*(.scall.text)
 		*(.irq.text)
 		KPROBES_TEXT
 		TEXT_TEXT
@@ -107,6 +99,10 @@
 		 */
 		*(.data.init_task)
 
+		/* Then, the page-aligned data */
+		. = ALIGN(PAGE_SIZE);
+		*(.data.page_aligned)
+
 		/* Then, the cacheline aligned data */
 		. = ALIGN(L1_CACHE_BYTES);
 		*(.data.cacheline_aligned)
diff --git a/arch/avr32/lib/io-readsb.S b/arch/avr32/lib/io-readsb.S
index 2be5da7..cb2d869 100644
--- a/arch/avr32/lib/io-readsb.S
+++ b/arch/avr32/lib/io-readsb.S
@@ -41,7 +41,7 @@
 2:	sub	r10, -4
 	reteq	r12
 
-3:	ld.uh	r8, r12[0]
+3:	ld.ub	r8, r12[0]
 	sub	r10, 1
 	st.b	r11++, r8
 	brne	3b
diff --git a/arch/avr32/mach-at32ap/Makefile b/arch/avr32/mach-at32ap/Makefile
index e890094..d5018e2 100644
--- a/arch/avr32/mach-at32ap/Makefile
+++ b/arch/avr32/mach-at32ap/Makefile
@@ -1,3 +1,8 @@
-obj-y				+= at32ap.o clock.o intc.o extint.o pio.o hsmc.o
+obj-y				+= pdc.o clock.o intc.o extint.o pio.o hsmc.o
 obj-$(CONFIG_CPU_AT32AP700X)	+= at32ap700x.o pm-at32ap700x.o
 obj-$(CONFIG_CPU_FREQ_AT32AP)	+= cpufreq.o
+obj-$(CONFIG_PM)		+= pm.o
+
+ifeq ($(CONFIG_PM_DEBUG),y)
+CFLAGS_pm.o	+= -DDEBUG
+endif
diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
index 0f24b4f8..07b21b1 100644
--- a/arch/avr32/mach-at32ap/at32ap700x.c
+++ b/arch/avr32/mach-at32ap/at32ap700x.c
@@ -20,6 +20,7 @@
 #include <asm/arch/at32ap700x.h>
 #include <asm/arch/board.h>
 #include <asm/arch/portmux.h>
+#include <asm/arch/sram.h>
 
 #include <video/atmel_lcdc.h>
 
@@ -93,19 +94,12 @@
 
 static DEFINE_SPINLOCK(pm_lock);
 
-unsigned long at32ap7000_osc_rates[3] = {
-	[0] = 32768,
-	/* FIXME: these are ATSTK1002-specific */
-	[1] = 20000000,
-	[2] = 12000000,
-};
-
 static struct clk osc0;
 static struct clk osc1;
 
 static unsigned long osc_get_rate(struct clk *clk)
 {
-	return at32ap7000_osc_rates[clk->index];
+	return at32_board_osc_rates[clk->index];
 }
 
 static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
@@ -682,6 +676,14 @@
 	.users		= 1,
 	.index		= 3,
 };
+static struct clk sdramc_clk = {
+	.name		= "sdramc_clk",
+	.parent		= &pbb_clk,
+	.mode		= pbb_clk_mode,
+	.get_rate	= pbb_clk_get_rate,
+	.users		= 1,
+	.index		= 14,
+};
 
 static struct resource smc0_resource[] = {
 	PBMEM(0xfff03400),
@@ -841,6 +843,81 @@
 }
 
 /* --------------------------------------------------------------------
+ *  PSIF
+ * -------------------------------------------------------------------- */
+static struct resource atmel_psif0_resource[] __initdata = {
+	{
+		.start	= 0xffe03c00,
+		.end	= 0xffe03cff,
+		.flags	= IORESOURCE_MEM,
+	},
+	IRQ(18),
+};
+static struct clk atmel_psif0_pclk = {
+	.name		= "pclk",
+	.parent		= &pba_clk,
+	.mode		= pba_clk_mode,
+	.get_rate	= pba_clk_get_rate,
+	.index		= 15,
+};
+
+static struct resource atmel_psif1_resource[] __initdata = {
+	{
+		.start	= 0xffe03d00,
+		.end	= 0xffe03dff,
+		.flags	= IORESOURCE_MEM,
+	},
+	IRQ(18),
+};
+static struct clk atmel_psif1_pclk = {
+	.name		= "pclk",
+	.parent		= &pba_clk,
+	.mode		= pba_clk_mode,
+	.get_rate	= pba_clk_get_rate,
+	.index		= 15,
+};
+
+struct platform_device *__init at32_add_device_psif(unsigned int id)
+{
+	struct platform_device *pdev;
+
+	if (!(id == 0 || id == 1))
+		return NULL;
+
+	pdev = platform_device_alloc("atmel_psif", id);
+	if (!pdev)
+		return NULL;
+
+	switch (id) {
+	case 0:
+		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  */
+		break;
+	case 1:
+		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  */
+		break;
+	default:
+		return NULL;
+	}
+
+	platform_device_add(pdev);
+	return pdev;
+
+err_add_resources:
+	platform_device_put(pdev);
+	return NULL;
+}
+
+/* --------------------------------------------------------------------
  *  USART
  * -------------------------------------------------------------------- */
 
@@ -1113,7 +1190,8 @@
 	switch (id) {
 	case 0:
 		pdev = &atmel_spi0_device;
-		select_peripheral(PA(0),  PERIPH_A, 0);	/* MISO	 */
+		/* 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	 */
 		at32_spi_setup_slaves(0, b, n, spi0_pins);
@@ -1121,7 +1199,8 @@
 
 	case 1:
 		pdev = &atmel_spi1_device;
-		select_peripheral(PB(0),  PERIPH_B, 0);	/* MISO  */
+		/* 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   */
 		at32_spi_setup_slaves(1, b, n, spi1_pins);
@@ -1264,7 +1343,8 @@
 
 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 long fbmem_start, unsigned long fbmem_len,
+		     unsigned int pin_config)
 {
 	struct platform_device *pdev;
 	struct atmel_lcdfb_info *info;
@@ -1291,37 +1371,77 @@
 	switch (id) {
 	case 0:
 		pdev = &atmel_lcdfb0_device;
-		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 */
+
+		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;
+		}
 
 		clk_set_parent(&atmel_lcdfb0_pixclk, &pll0);
 		clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0));
@@ -1360,7 +1480,7 @@
 	IRQ(24),
 };
 static struct clk atmel_pwm0_mck = {
-	.name		= "mck",
+	.name		= "pwm_clk",
 	.parent		= &pbb_clk,
 	.mode		= pbb_clk_mode,
 	.get_rate	= pbb_clk_get_rate,
@@ -1887,6 +2007,7 @@
 	&hmatrix_clk,
 	&ebi_clk,
 	&hramc_clk,
+	&sdramc_clk,
 	&smc0_pclk,
 	&smc0_mck,
 	&pdc_hclk,
@@ -1900,6 +2021,8 @@
 	&pio4_mck,
 	&at32_tcb0_t0_clk,
 	&at32_tcb1_t0_clk,
+	&atmel_psif0_pclk,
+	&atmel_psif1_pclk,
 	&atmel_usart0_usart,
 	&atmel_usart1_usart,
 	&atmel_usart2_usart,
@@ -1935,16 +2058,7 @@
 };
 unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
 
-void __init at32_portmux_init(void)
-{
-	at32_init_pio(&pio0_device);
-	at32_init_pio(&pio1_device);
-	at32_init_pio(&pio2_device);
-	at32_init_pio(&pio3_device);
-	at32_init_pio(&pio4_device);
-}
-
-void __init at32_clock_init(void)
+void __init setup_platform(void)
 {
 	u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0;
 	int i;
@@ -1999,4 +2113,36 @@
 	pm_writel(HSB_MASK, hsb_mask);
 	pm_writel(PBA_MASK, pba_mask);
 	pm_writel(PBB_MASK, pbb_mask);
+
+	/* Initialize the port muxes */
+	at32_init_pio(&pio0_device);
+	at32_init_pio(&pio1_device);
+	at32_init_pio(&pio2_device);
+	at32_init_pio(&pio3_device);
+	at32_init_pio(&pio4_device);
 }
+
+struct gen_pool *sram_pool;
+
+static int __init sram_init(void)
+{
+	struct gen_pool *pool;
+
+	/* 1KiB granularity */
+	pool = gen_pool_create(10, -1);
+	if (!pool)
+		goto fail;
+
+	if (gen_pool_add(pool, 0x24000000, 0x8000, -1))
+		goto err_pool_add;
+
+	sram_pool = pool;
+	return 0;
+
+err_pool_add:
+	gen_pool_destroy(pool);
+fail:
+	pr_err("Failed to create SRAM pool\n");
+	return -ENOMEM;
+}
+core_initcall(sram_init);
diff --git a/arch/avr32/mach-at32ap/intc.c b/arch/avr32/mach-at32ap/intc.c
index 097cf4e..994c4545 100644
--- a/arch/avr32/mach-at32ap/intc.c
+++ b/arch/avr32/mach-at32ap/intc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 Atmel Corporation
+ * Copyright (C) 2006, 2008 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
@@ -12,14 +12,20 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/platform_device.h>
+#include <linux/sysdev.h>
 
 #include <asm/io.h>
 
 #include "intc.h"
 
 struct intc {
-	void __iomem	*regs;
-	struct irq_chip	chip;
+	void __iomem		*regs;
+	struct irq_chip		chip;
+	struct sys_device	sysdev;
+#ifdef CONFIG_PM
+	unsigned long		suspend_ipr;
+	unsigned long		saved_ipr[64];
+#endif
 };
 
 extern struct platform_device at32_intc0_device;
@@ -136,6 +142,74 @@
 	panic("Interrupt controller initialization failed!\n");
 }
 
+#ifdef CONFIG_PM
+void intc_set_suspend_handler(unsigned long offset)
+{
+	intc0.suspend_ipr = offset;
+}
+
+static int intc_suspend(struct sys_device *sdev, pm_message_t state)
+{
+	struct intc *intc = container_of(sdev, struct intc, sysdev);
+	int i;
+
+	if (unlikely(!irqs_disabled())) {
+		pr_err("intc_suspend: called with interrupts enabled\n");
+		return -EINVAL;
+	}
+
+	if (unlikely(!intc->suspend_ipr)) {
+		pr_err("intc_suspend: suspend_ipr not initialized\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < 64; i++) {
+		intc->saved_ipr[i] = intc_readl(intc, INTPR0 + 4 * i);
+		intc_writel(intc, INTPR0 + 4 * i, intc->suspend_ipr);
+	}
+
+	return 0;
+}
+
+static int intc_resume(struct sys_device *sdev)
+{
+	struct intc *intc = container_of(sdev, struct intc, sysdev);
+	int i;
+
+	WARN_ON(!irqs_disabled());
+
+	for (i = 0; i < 64; i++)
+		intc_writel(intc, INTPR0 + 4 * i, intc->saved_ipr[i]);
+
+	return 0;
+}
+#else
+#define intc_suspend	NULL
+#define intc_resume	NULL
+#endif
+
+static struct sysdev_class intc_class = {
+	.name		= "intc",
+	.suspend	= intc_suspend,
+	.resume		= intc_resume,
+};
+
+static int __init intc_init_sysdev(void)
+{
+	int ret;
+
+	ret = sysdev_class_register(&intc_class);
+	if (ret)
+		return ret;
+
+	intc0.sysdev.id = 0;
+	intc0.sysdev.cls = &intc_class;
+	ret = sysdev_register(&intc0.sysdev);
+
+	return ret;
+}
+device_initcall(intc_init_sysdev);
+
 unsigned long intc_get_pending(unsigned int group)
 {
 	return intc_readl(&intc0, INTREQ0 + 4 * group);
diff --git a/arch/avr32/mach-at32ap/at32ap.c b/arch/avr32/mach-at32ap/pdc.c
similarity index 90%
rename from arch/avr32/mach-at32ap/at32ap.c
rename to arch/avr32/mach-at32ap/pdc.c
index 7c4987f..1040bda 100644
--- a/arch/avr32/mach-at32ap/at32ap.c
+++ b/arch/avr32/mach-at32ap/pdc.c
@@ -11,14 +11,6 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 
-#include <asm/arch/init.h>
-
-void __init setup_platform(void)
-{
-	at32_clock_init();
-	at32_portmux_init();
-}
-
 static int __init pdc_probe(struct platform_device *pdev)
 {
 	struct clk *pclk, *hclk;
diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c
index 38a8fa3..60da03b 100644
--- a/arch/avr32/mach-at32ap/pio.c
+++ b/arch/avr32/mach-at32ap/pio.c
@@ -318,6 +318,8 @@
 		const char *label;
 
 		label = gpiochip_is_requested(chip, i);
+		if (!label && (imr & mask))
+			label = "[irq]";
 		if (!label)
 			continue;
 
diff --git a/arch/avr32/mach-at32ap/pio.h b/arch/avr32/mach-at32ap/pio.h
index 7795116..9484dfc 100644
--- a/arch/avr32/mach-at32ap/pio.h
+++ b/arch/avr32/mach-at32ap/pio.h
@@ -57,7 +57,7 @@
 
 /* Bitfields in IFDR */
 
-/* Bitfields in ISFR */
+/* Bitfields in IFSR */
 
 /* Bitfields in SODR */
 
diff --git a/arch/avr32/mach-at32ap/pm-at32ap700x.S b/arch/avr32/mach-at32ap/pm-at32ap700x.S
index 949e248..0a53ad3 100644
--- a/arch/avr32/mach-at32ap/pm-at32ap700x.S
+++ b/arch/avr32/mach-at32ap/pm-at32ap700x.S
@@ -12,6 +12,12 @@
 #include <asm/thread_info.h>
 #include <asm/arch/pm.h>
 
+#include "pm.h"
+#include "sdramc.h"
+
+/* Same as 0xfff00000 but fits in a 21 bit signed immediate */
+#define PM_BASE	-0x100000
+
 	.section .bss, "wa", @nobits
 	.global	disable_idle_sleep
 	.type	disable_idle_sleep, @object
@@ -64,3 +70,105 @@
 	unmask_interrupts
 	retal	r12
 	.size	cpu_idle_skip_sleep, . - cpu_idle_skip_sleep
+
+#ifdef CONFIG_PM
+	.section .init.text, "ax", @progbits
+
+	.global	pm_exception
+	.type	pm_exception, @function
+pm_exception:
+	/*
+	 * Exceptions are masked when we switch to this handler, so
+	 * we'll only get "unrecoverable" exceptions (offset 0.)
+	 */
+	sub	r12, pc, . - .Lpanic_msg
+	lddpc	pc, .Lpanic_addr
+
+	.align	2
+.Lpanic_addr:
+	.long	panic
+.Lpanic_msg:
+	.asciz	"Unrecoverable exception during suspend\n"
+	.size	pm_exception, . - pm_exception
+
+	.global	pm_irq0
+	.type	pm_irq0, @function
+pm_irq0:
+	/* Disable interrupts and return after the sleep instruction */
+	mfsr	r9, SYSREG_RSR_INT0
+	mtsr	SYSREG_RAR_INT0, r8
+	sbr	r9, SYSREG_GM_OFFSET
+	mtsr	SYSREG_RSR_INT0, r9
+	rete
+
+	/*
+	 * void cpu_enter_standby(unsigned long sdramc_base)
+	 *
+	 * Enter PM_SUSPEND_STANDBY mode. At this point, all drivers
+	 * are suspended and interrupts are disabled. Interrupts
+	 * marked as 'wakeup' event sources may still come along and
+	 * get us out of here.
+	 *
+	 * The SDRAM will be put into self-refresh mode (which does
+	 * not require a clock from the CPU), and the CPU will be put
+	 * into "frozen" mode (HSB bus stopped). The SDRAM controller
+	 * will automatically bring the SDRAM into normal mode on the
+	 * first access, and the power manager will automatically
+	 * start the HSB and CPU clocks upon a wakeup event.
+	 *
+	 * This code uses the same "skip sleep" technique as above.
+	 * It is very important that we jump directly to
+	 * cpu_after_sleep after the sleep instruction since that's
+	 * where we'll end up if the interrupt handler decides that we
+	 * need to skip the sleep instruction.
+	 */
+	.global	pm_standby
+	.type	pm_standby, @function
+pm_standby:
+	/*
+	 * interrupts are already masked at this point, and EVBA
+	 * points to pm_exception above.
+	 */
+	ld.w	r10, r12[SDRAMC_LPR]
+	sub	r8, pc, . - 1f		/* return address for irq handler */
+	mov	r11, SDRAMC_LPR_LPCB_SELF_RFR
+	bfins	r10, r11, 0, 2		/* LPCB <- self Refresh */
+	sync	0			/* flush write buffer */
+	st.w	r12[SDRAMC_LPR], r11	/* put SDRAM in self-refresh mode */
+	ld.w	r11, r12[SDRAMC_LPR]
+	unmask_interrupts
+	sleep	CPU_SLEEP_FROZEN
+1:	mask_interrupts
+	retal	r12
+	.size	pm_standby, . - pm_standby
+
+	.global	pm_suspend_to_ram
+	.type	pm_suspend_to_ram, @function
+pm_suspend_to_ram:
+	/*
+	 * interrupts are already masked at this point, and EVBA
+	 * points to pm_exception above.
+	 */
+	mov	r11, 0
+	cache	r11[2], 8		/* clean all dcache lines */
+	sync	0			/* flush write buffer */
+	ld.w	r10, r12[SDRAMC_LPR]
+	sub	r8, pc, . - 1f		/* return address for irq handler */
+	mov	r11, SDRAMC_LPR_LPCB_SELF_RFR
+	bfins	r10, r11, 0, 2		/* LPCB <- self refresh */
+	st.w	r12[SDRAMC_LPR], r10	/* put SDRAM in self-refresh mode */
+	ld.w	r11, r12[SDRAMC_LPR]
+
+	unmask_interrupts
+	sleep	CPU_SLEEP_STOP
+1:	mask_interrupts
+
+	retal	r12
+	.size	pm_suspend_to_ram, . - pm_suspend_to_ram
+
+	.global	pm_sram_end
+	.type	pm_sram_end, @function
+pm_sram_end:
+	.size	pm_sram_end, 0
+
+#endif /* CONFIG_PM */
diff --git a/arch/avr32/mach-at32ap/pm.c b/arch/avr32/mach-at32ap/pm.c
new file mode 100644
index 0000000..0b76432
--- /dev/null
+++ b/arch/avr32/mach-at32ap/pm.c
@@ -0,0 +1,245 @@
+/*
+ * AVR32 AP Power Management
+ *
+ * Copyright (C) 2008 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.
+ */
+#include <linux/io.h>
+#include <linux/suspend.h>
+#include <linux/vmalloc.h>
+
+#include <asm/cacheflush.h>
+#include <asm/sysreg.h>
+
+#include <asm/arch/pm.h>
+#include <asm/arch/sram.h>
+
+/* FIXME: This is only valid for AP7000 */
+#define SDRAMC_BASE	0xfff03800
+
+#include "sdramc.h"
+
+#define SRAM_PAGE_FLAGS	(SYSREG_BIT(TLBELO_D) | SYSREG_BF(SZ, 1)	\
+				| SYSREG_BF(AP, 3) | SYSREG_BIT(G))
+
+
+static unsigned long	pm_sram_start;
+static size_t		pm_sram_size;
+static struct vm_struct	*pm_sram_area;
+
+static void (*avr32_pm_enter_standby)(unsigned long sdramc_base);
+static void (*avr32_pm_enter_str)(unsigned long sdramc_base);
+
+/*
+ * Must be called with interrupts disabled. Exceptions will be masked
+ * on return (i.e. all exceptions will be "unrecoverable".)
+ */
+static void *avr32_pm_map_sram(void)
+{
+	unsigned long	vaddr;
+	unsigned long	page_addr;
+	u32		tlbehi;
+	u32		mmucr;
+
+	vaddr = (unsigned long)pm_sram_area->addr;
+	page_addr = pm_sram_start & PAGE_MASK;
+
+	/*
+	 * Mask exceptions and grab the first TLB entry. We won't be
+	 * needing it while sleeping.
+	 */
+	asm volatile("ssrf	%0" : : "i"(SYSREG_EM_OFFSET) : "memory");
+
+	mmucr = sysreg_read(MMUCR);
+	tlbehi = sysreg_read(TLBEHI);
+	sysreg_write(MMUCR, SYSREG_BFINS(DRP, 0, mmucr));
+
+	tlbehi = SYSREG_BF(ASID, SYSREG_BFEXT(ASID, tlbehi));
+	tlbehi |= vaddr & PAGE_MASK;
+	tlbehi |= SYSREG_BIT(TLBEHI_V);
+
+	sysreg_write(TLBELO, page_addr | SRAM_PAGE_FLAGS);
+	sysreg_write(TLBEHI, tlbehi);
+	__builtin_tlbw();
+
+	return (void *)(vaddr + pm_sram_start - page_addr);
+}
+
+/*
+ * Must be called with interrupts disabled. Exceptions will be
+ * unmasked on return.
+ */
+static void avr32_pm_unmap_sram(void)
+{
+	u32	mmucr;
+	u32	tlbehi;
+	u32	tlbarlo;
+
+	/* Going to update TLB entry at index 0 */
+	mmucr = sysreg_read(MMUCR);
+	tlbehi = sysreg_read(TLBEHI);
+	sysreg_write(MMUCR, SYSREG_BFINS(DRP, 0, mmucr));
+
+	/* Clear the "valid" bit */
+	tlbehi = SYSREG_BF(ASID, SYSREG_BFEXT(ASID, tlbehi));
+	sysreg_write(TLBEHI, tlbehi);
+
+	/* Mark it as "not accessed" */
+	tlbarlo = sysreg_read(TLBARLO);
+	sysreg_write(TLBARLO, tlbarlo | 0x80000000U);
+
+	/* Update the TLB */
+	__builtin_tlbw();
+
+	/* Unmask exceptions */
+	asm volatile("csrf	%0" : : "i"(SYSREG_EM_OFFSET) : "memory");
+}
+
+static int avr32_pm_valid_state(suspend_state_t state)
+{
+	switch (state) {
+	case PM_SUSPEND_ON:
+	case PM_SUSPEND_STANDBY:
+	case PM_SUSPEND_MEM:
+		return 1;
+
+	default:
+		return 0;
+	}
+}
+
+static int avr32_pm_enter(suspend_state_t state)
+{
+	u32		lpr_saved;
+	u32		evba_saved;
+	void		*sram;
+
+	switch (state) {
+	case PM_SUSPEND_STANDBY:
+		sram = avr32_pm_map_sram();
+
+		/* Switch to in-sram exception handlers */
+		evba_saved = sysreg_read(EVBA);
+		sysreg_write(EVBA, (unsigned long)sram);
+
+		/*
+		 * Save the LPR register so that we can re-enable
+		 * SDRAM Low Power mode on resume.
+		 */
+		lpr_saved = sdramc_readl(LPR);
+		pr_debug("%s: Entering standby...\n", __func__);
+		avr32_pm_enter_standby(SDRAMC_BASE);
+		sdramc_writel(LPR, lpr_saved);
+
+		/* Switch back to regular exception handlers */
+		sysreg_write(EVBA, evba_saved);
+
+		avr32_pm_unmap_sram();
+		break;
+
+	case PM_SUSPEND_MEM:
+		sram = avr32_pm_map_sram();
+
+		/* Switch to in-sram exception handlers */
+		evba_saved = sysreg_read(EVBA);
+		sysreg_write(EVBA, (unsigned long)sram);
+
+		/*
+		 * Save the LPR register so that we can re-enable
+		 * SDRAM Low Power mode on resume.
+		 */
+		lpr_saved = sdramc_readl(LPR);
+		pr_debug("%s: Entering suspend-to-ram...\n", __func__);
+		avr32_pm_enter_str(SDRAMC_BASE);
+		sdramc_writel(LPR, lpr_saved);
+
+		/* Switch back to regular exception handlers */
+		sysreg_write(EVBA, evba_saved);
+
+		avr32_pm_unmap_sram();
+		break;
+
+	case PM_SUSPEND_ON:
+		pr_debug("%s: Entering idle...\n", __func__);
+		cpu_enter_idle();
+		break;
+
+	default:
+		pr_debug("%s: Invalid suspend state %d\n", __func__, state);
+		goto out;
+	}
+
+	pr_debug("%s: wakeup\n", __func__);
+
+out:
+	return 0;
+}
+
+static struct platform_suspend_ops avr32_pm_ops = {
+	.valid	= avr32_pm_valid_state,
+	.enter	= avr32_pm_enter,
+};
+
+static unsigned long avr32_pm_offset(void *symbol)
+{
+	extern u8 pm_exception[];
+
+	return (unsigned long)symbol - (unsigned long)pm_exception;
+}
+
+static int __init avr32_pm_init(void)
+{
+	extern u8 pm_exception[];
+	extern u8 pm_irq0[];
+	extern u8 pm_standby[];
+	extern u8 pm_suspend_to_ram[];
+	extern u8 pm_sram_end[];
+	void *dst;
+
+	/*
+	 * To keep things simple, we depend on not needing more than a
+	 * single page.
+	 */
+	pm_sram_size = avr32_pm_offset(pm_sram_end);
+	if (pm_sram_size > PAGE_SIZE)
+		goto err;
+
+	pm_sram_start = sram_alloc(pm_sram_size);
+	if (!pm_sram_start)
+		goto err_alloc_sram;
+
+	/* Grab a virtual area we can use later on. */
+	pm_sram_area = get_vm_area(pm_sram_size, VM_IOREMAP);
+	if (!pm_sram_area)
+		goto err_vm_area;
+	pm_sram_area->phys_addr = pm_sram_start;
+
+	local_irq_disable();
+	dst = avr32_pm_map_sram();
+	memcpy(dst, pm_exception, pm_sram_size);
+	flush_dcache_region(dst, pm_sram_size);
+	invalidate_icache_region(dst, pm_sram_size);
+	avr32_pm_unmap_sram();
+	local_irq_enable();
+
+	avr32_pm_enter_standby = dst + avr32_pm_offset(pm_standby);
+	avr32_pm_enter_str = dst + avr32_pm_offset(pm_suspend_to_ram);
+	intc_set_suspend_handler(avr32_pm_offset(pm_irq0));
+
+	suspend_set_ops(&avr32_pm_ops);
+
+	printk("AVR32 AP Power Management enabled\n");
+
+	return 0;
+
+err_vm_area:
+	sram_free(pm_sram_start, pm_sram_size);
+err_alloc_sram:
+err:
+	pr_err("AVR32 Power Management initialization failed\n");
+	return -ENOMEM;
+}
+arch_initcall(avr32_pm_init);
diff --git a/arch/avr32/mach-at32ap/sdramc.h b/arch/avr32/mach-at32ap/sdramc.h
new file mode 100644
index 0000000..66eeaed
--- /dev/null
+++ b/arch/avr32/mach-at32ap/sdramc.h
@@ -0,0 +1,76 @@
+/*
+ * Register definitions for the AT32AP SDRAM Controller
+ *
+ * Copyright (C) 2008 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.
+ */
+
+/* Register offsets */
+#define SDRAMC_MR			0x0000
+#define SDRAMC_TR			0x0004
+#define SDRAMC_CR			0x0008
+#define SDRAMC_HSR			0x000c
+#define SDRAMC_LPR			0x0010
+#define SDRAMC_IER			0x0014
+#define SDRAMC_IDR			0x0018
+#define SDRAMC_IMR			0x001c
+#define SDRAMC_ISR			0x0020
+#define SDRAMC_MDR			0x0024
+
+/* MR - Mode Register */
+#define SDRAMC_MR_MODE_NORMAL		(  0 <<  0)
+#define SDRAMC_MR_MODE_NOP		(  1 <<  0)
+#define SDRAMC_MR_MODE_BANKS_PRECHARGE	(  2 <<  0)
+#define SDRAMC_MR_MODE_LOAD_MODE	(  3 <<  0)
+#define SDRAMC_MR_MODE_AUTO_REFRESH	(  4 <<  0)
+#define SDRAMC_MR_MODE_EXT_LOAD_MODE	(  5 <<  0)
+#define SDRAMC_MR_MODE_POWER_DOWN	(  6 <<  0)
+
+/* CR - Configuration Register */
+#define SDRAMC_CR_NC_8_BITS		(  0 <<  0)
+#define SDRAMC_CR_NC_9_BITS		(  1 <<  0)
+#define SDRAMC_CR_NC_10_BITS		(  2 <<  0)
+#define SDRAMC_CR_NC_11_BITS		(  3 <<  0)
+#define SDRAMC_CR_NR_11_BITS		(  0 <<  2)
+#define SDRAMC_CR_NR_12_BITS		(  1 <<  2)
+#define SDRAMC_CR_NR_13_BITS		(  2 <<  2)
+#define SDRAMC_CR_NB_2_BANKS		(  0 <<  4)
+#define SDRAMC_CR_NB_4_BANKS		(  1 <<  4)
+#define SDRAMC_CR_CAS(x)		((x) <<  5)
+#define SDRAMC_CR_DBW_32_BITS		(  0 <<  7)
+#define SDRAMC_CR_DBW_16_BITS		(  1 <<  7)
+#define SDRAMC_CR_TWR(x)		((x) <<  8)
+#define SDRAMC_CR_TRC(x)		((x) << 12)
+#define SDRAMC_CR_TRP(x)		((x) << 16)
+#define SDRAMC_CR_TRCD(x)		((x) << 20)
+#define SDRAMC_CR_TRAS(x)		((x) << 24)
+#define SDRAMC_CR_TXSR(x)		((x) << 28)
+
+/* HSR - High Speed Register */
+#define SDRAMC_HSR_DA			(  1 <<  0)
+
+/* LPR - Low Power Register */
+#define SDRAMC_LPR_LPCB_INHIBIT		(  0 <<  0)
+#define SDRAMC_LPR_LPCB_SELF_RFR	(  1 <<  0)
+#define SDRAMC_LPR_LPCB_PDOWN		(  2 <<  0)
+#define SDRAMC_LPR_LPCB_DEEP_PDOWN	(  3 <<  0)
+#define SDRAMC_LPR_PASR(x)		((x) <<  4)
+#define SDRAMC_LPR_TCSR(x)		((x) <<  8)
+#define SDRAMC_LPR_DS(x)		((x) << 10)
+#define SDRAMC_LPR_TIMEOUT(x)		((x) << 12)
+
+/* IER/IDR/IMR/ISR - Interrupt Enable/Disable/Mask/Status Register */
+#define SDRAMC_ISR_RES			(  1 <<  0)
+
+/* MDR - Memory Device Register */
+#define SDRAMC_MDR_MD_SDRAM		(  0 <<  0)
+#define SDRAMC_MDR_MD_LOW_PWR_SDRAM	(  1 <<  0)
+
+/* Register access macros */
+#define sdramc_readl(reg) \
+	__raw_readl((void __iomem __force *)SDRAMC_BASE + SDRAMC_##reg)
+#define sdramc_writel(reg, value) \
+	__raw_writel(value, (void __iomem __force *)SDRAMC_BASE + SDRAMC_##reg)
diff --git a/arch/avr32/mm/init.c b/arch/avr32/mm/init.c
index 0e64ddc..3f90a87 100644
--- a/arch/avr32/mm/init.c
+++ b/arch/avr32/mm/init.c
@@ -11,6 +11,7 @@
 #include <linux/swap.h>
 #include <linux/init.h>
 #include <linux/mmzone.h>
+#include <linux/module.h>
 #include <linux/bootmem.h>
 #include <linux/pagemap.h>
 #include <linux/nodemask.h>
@@ -23,11 +24,14 @@
 #include <asm/setup.h>
 #include <asm/sections.h>
 
+#define __page_aligned	__attribute__((section(".data.page_aligned")))
+
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
-pgd_t swapper_pg_dir[PTRS_PER_PGD];
+pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned;
 
 struct page *empty_zero_page;
+EXPORT_SYMBOL(empty_zero_page);
 
 /*
  * Cache of MMU context last used.
@@ -106,19 +110,9 @@
 	zero_page = alloc_bootmem_low_pages_node(NODE_DATA(0),
 						 PAGE_SIZE);
 
-	{
-		pgd_t *pg_dir;
-		int i;
-
-		pg_dir = swapper_pg_dir;
-		sysreg_write(PTBR, (unsigned long)pg_dir);
-
-		for (i = 0; i < PTRS_PER_PGD; i++)
-			pgd_val(pg_dir[i]) = 0;
-
-		enable_mmu();
-		printk ("CPU: Paging enabled\n");
-	}
+	sysreg_write(PTBR, (unsigned long)swapper_pg_dir);
+	enable_mmu();
+	printk ("CPU: Paging enabled\n");
 
 	for_each_online_node(nid) {
 		pg_data_t *pgdat = NODE_DATA(nid);
diff --git a/arch/avr32/mm/tlb.c b/arch/avr32/mm/tlb.c
index cd12edb..06677be 100644
--- a/arch/avr32/mm/tlb.c
+++ b/arch/avr32/mm/tlb.c
@@ -11,21 +11,21 @@
 
 #include <asm/mmu_context.h>
 
-#define _TLBEHI_I	0x100
+/* TODO: Get the correct number from the CONFIG1 system register */
+#define NR_TLB_ENTRIES 32
 
-void show_dtlb_entry(unsigned int index)
+static void show_dtlb_entry(unsigned int index)
 {
-	unsigned int tlbehi, tlbehi_save, tlbelo, mmucr, mmucr_save;
+	u32 tlbehi, tlbehi_save, tlbelo, mmucr, mmucr_save;
 	unsigned long flags;
 
 	local_irq_save(flags);
 	mmucr_save = sysreg_read(MMUCR);
 	tlbehi_save = sysreg_read(TLBEHI);
-	mmucr = mmucr_save & 0x13;
-	mmucr |= index << 14;
+	mmucr = SYSREG_BFINS(DRP, index, mmucr_save);
 	sysreg_write(MMUCR, mmucr);
 
-	asm volatile("tlbr" : : : "memory");
+	__builtin_tlbr();
 	cpu_sync_pipeline();
 
 	tlbehi = sysreg_read(TLBEHI);
@@ -33,15 +33,17 @@
 
 	printk("%2u: %c %c %02x   %05x %05x %o  %o  %c %c %c %c\n",
 	       index,
-	       (tlbehi & 0x200)?'1':'0',
-	       (tlbelo & 0x100)?'1':'0',
-	       (tlbehi & 0xff),
-	       (tlbehi >> 12), (tlbelo >> 12),
-	       (tlbelo >> 4) & 7, (tlbelo >> 2) & 3,
-	       (tlbelo & 0x200)?'1':'0',
-	       (tlbelo & 0x080)?'1':'0',
-	       (tlbelo & 0x001)?'1':'0',
-	       (tlbelo & 0x002)?'1':'0');
+	       SYSREG_BFEXT(TLBEHI_V, tlbehi) ? '1' : '0',
+	       SYSREG_BFEXT(G, tlbelo) ? '1' : '0',
+	       SYSREG_BFEXT(ASID, tlbehi),
+	       SYSREG_BFEXT(VPN, tlbehi) >> 2,
+	       SYSREG_BFEXT(PFN, tlbelo) >> 2,
+	       SYSREG_BFEXT(AP, tlbelo),
+	       SYSREG_BFEXT(SZ, tlbelo),
+	       SYSREG_BFEXT(TLBELO_C, tlbelo) ? 'C' : ' ',
+	       SYSREG_BFEXT(B, tlbelo) ? 'B' : ' ',
+	       SYSREG_BFEXT(W, tlbelo) ? 'W' : ' ',
+	       SYSREG_BFEXT(TLBELO_D, tlbelo) ? 'D' : ' ');
 
 	sysreg_write(MMUCR, mmucr_save);
 	sysreg_write(TLBEHI, tlbehi_save);
@@ -54,29 +56,33 @@
 	unsigned int i;
 
 	printk("ID  V G ASID VPN   PFN   AP SZ C B W D\n");
-	for (i = 0; i < 32; i++)
+	for (i = 0; i < NR_TLB_ENTRIES; i++)
 		show_dtlb_entry(i);
 }
 
-static unsigned long last_mmucr;
-
-static inline void set_replacement_pointer(unsigned shift)
+static void update_dtlb(unsigned long address, pte_t pte)
 {
-	unsigned long mmucr, mmucr_save;
+	u32 tlbehi;
+	u32 mmucr;
 
-	mmucr = mmucr_save = sysreg_read(MMUCR);
+	/*
+	 * We're not changing the ASID here, so no need to flush the
+	 * pipeline.
+	 */
+	tlbehi = sysreg_read(TLBEHI);
+	tlbehi = SYSREG_BF(ASID, SYSREG_BFEXT(ASID, tlbehi));
+	tlbehi |= address & MMU_VPN_MASK;
+	tlbehi |= SYSREG_BIT(TLBEHI_V);
+	sysreg_write(TLBEHI, tlbehi);
 
 	/* Does this mapping already exist? */
-	__asm__ __volatile__(
-		"	tlbs\n"
-		"	mfsr %0, %1"
-		: "=r"(mmucr)
-		: "i"(SYSREG_MMUCR));
+	__builtin_tlbs();
+	mmucr = sysreg_read(MMUCR);
 
 	if (mmucr & SYSREG_BIT(MMUCR_N)) {
 		/* Not found -- pick a not-recently-accessed entry */
-		unsigned long rp;
-		unsigned long tlbar = sysreg_read(TLBARLO);
+		unsigned int rp;
+		u32 tlbar = sysreg_read(TLBARLO);
 
 		rp = 32 - fls(tlbar);
 		if (rp == 32) {
@@ -84,30 +90,14 @@
 			sysreg_write(TLBARLO, -1L);
 		}
 
-		mmucr &= 0x13;
-		mmucr |= (rp << shift);
-
+		mmucr = SYSREG_BFINS(DRP, rp, mmucr);
 		sysreg_write(MMUCR, mmucr);
 	}
 
-	last_mmucr = mmucr;
-}
-
-static void update_dtlb(unsigned long address, pte_t pte, unsigned long asid)
-{
-	unsigned long vpn;
-
-	vpn = (address & MMU_VPN_MASK) | _TLBEHI_VALID | asid;
-	sysreg_write(TLBEHI, vpn);
-	cpu_sync_pipeline();
-
-	set_replacement_pointer(14);
-
 	sysreg_write(TLBELO, pte_val(pte) & _PAGE_FLAGS_HARDWARE_MASK);
 
 	/* Let's go */
-	asm volatile("nop\n\ttlbw" : : : "memory");
-	cpu_sync_pipeline();
+	__builtin_tlbw();
 }
 
 void update_mmu_cache(struct vm_area_struct *vma,
@@ -120,39 +110,40 @@
 		return;
 
 	local_irq_save(flags);
-	update_dtlb(address, pte, get_asid());
+	update_dtlb(address, pte);
 	local_irq_restore(flags);
 }
 
-void __flush_tlb_page(unsigned long asid, unsigned long page)
+static void __flush_tlb_page(unsigned long asid, unsigned long page)
 {
-	unsigned long mmucr, tlbehi;
+	u32 mmucr, tlbehi;
 
-	page |= asid;
-	sysreg_write(TLBEHI, page);
-	cpu_sync_pipeline();
-	asm volatile("tlbs");
+	/*
+	 * Caller is responsible for masking out non-PFN bits in page
+	 * and changing the current ASID if necessary. This means that
+	 * we don't need to flush the pipeline after writing TLBEHI.
+	 */
+	tlbehi = page | asid;
+	sysreg_write(TLBEHI, tlbehi);
+
+	__builtin_tlbs();
 	mmucr = sysreg_read(MMUCR);
 
 	if (!(mmucr & SYSREG_BIT(MMUCR_N))) {
-		unsigned long tlbarlo;
-		unsigned long entry;
+		unsigned int entry;
+		u32 tlbarlo;
 
 		/* Clear the "valid" bit */
-		tlbehi = sysreg_read(TLBEHI);
-		tlbehi &= ~_TLBEHI_VALID;
 		sysreg_write(TLBEHI, tlbehi);
-		cpu_sync_pipeline();
 
 		/* mark the entry as "not accessed" */
-		entry = (mmucr >> 14) & 0x3f;
+		entry = SYSREG_BFEXT(DRP, mmucr);
 		tlbarlo = sysreg_read(TLBARLO);
-		tlbarlo |= (0x80000000 >> entry);
+		tlbarlo |= (0x80000000UL >> entry);
 		sysreg_write(TLBARLO, tlbarlo);
 
 		/* update the entry with valid bit clear */
-		asm volatile("tlbw");
-		cpu_sync_pipeline();
+		__builtin_tlbw();
 	}
 }
 
@@ -190,17 +181,22 @@
 
 		local_irq_save(flags);
 		size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+
 		if (size > (MMU_DTLB_ENTRIES / 4)) { /* Too many entries to flush */
 			mm->context = NO_CONTEXT;
 			if (mm == current->mm)
 				activate_context(mm);
 		} else {
-			unsigned long asid = mm->context & MMU_CONTEXT_ASID_MASK;
-			unsigned long saved_asid = MMU_NO_ASID;
+			unsigned long asid;
+			unsigned long saved_asid;
+
+			asid = mm->context & MMU_CONTEXT_ASID_MASK;
+			saved_asid = MMU_NO_ASID;
 
 			start &= PAGE_MASK;
 			end += (PAGE_SIZE - 1);
 			end &= PAGE_MASK;
+
 			if (mm != current->mm) {
 				saved_asid = get_asid();
 				set_asid(asid);
@@ -218,33 +214,34 @@
 }
 
 /*
- * TODO: If this is only called for addresses > TASK_SIZE, we can probably
- * skip the ASID stuff and just use the Global bit...
+ * This function depends on the pages to be flushed having the G
+ * (global) bit set in their pte. This is true for all
+ * PAGE_KERNEL(_RO) pages.
  */
 void flush_tlb_kernel_range(unsigned long start, unsigned long end)
 {
 	unsigned long flags;
 	int size;
 
-	local_irq_save(flags);
 	size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
 	if (size > (MMU_DTLB_ENTRIES / 4)) { /* Too many entries to flush */
 		flush_tlb_all();
 	} else {
-		unsigned long asid = init_mm.context & MMU_CONTEXT_ASID_MASK;
-		unsigned long saved_asid = get_asid();
+		unsigned long asid;
+
+		local_irq_save(flags);
+		asid = get_asid();
 
 		start &= PAGE_MASK;
 		end += (PAGE_SIZE - 1);
 		end &= PAGE_MASK;
-		set_asid(asid);
+
 		while (start < end) {
 			__flush_tlb_page(asid, start);
 			start += PAGE_SIZE;
 		}
-		set_asid(saved_asid);
+		local_irq_restore(flags);
 	}
-	local_irq_restore(flags);
 }
 
 void flush_tlb_mm(struct mm_struct *mm)
@@ -280,7 +277,7 @@
 {
 	static unsigned long tlb_index;
 
-	if (*pos >= 32)
+	if (*pos >= NR_TLB_ENTRIES)
 		return NULL;
 
 	tlb_index = 0;
@@ -291,7 +288,7 @@
 {
 	unsigned long *index = v;
 
-	if (*index >= 31)
+	if (*index >= NR_TLB_ENTRIES - 1)
 		return NULL;
 
 	++*pos;
@@ -313,16 +310,16 @@
 	if (*index == 0)
 		seq_puts(tlb, "ID  V G ASID VPN   PFN   AP SZ C B W D\n");
 
-	BUG_ON(*index >= 32);
+	BUG_ON(*index >= NR_TLB_ENTRIES);
 
 	local_irq_save(flags);
 	mmucr_save = sysreg_read(MMUCR);
 	tlbehi_save = sysreg_read(TLBEHI);
-	mmucr = mmucr_save & 0x13;
-	mmucr |= *index << 14;
+	mmucr = SYSREG_BFINS(DRP, *index, mmucr_save);
 	sysreg_write(MMUCR, mmucr);
 
-	asm volatile("tlbr" : : : "memory");
+	/* TLBR might change the ASID */
+	__builtin_tlbr();
 	cpu_sync_pipeline();
 
 	tlbehi = sysreg_read(TLBEHI);
@@ -334,16 +331,18 @@
 	local_irq_restore(flags);
 
 	seq_printf(tlb, "%2lu: %c %c %02x   %05x %05x %o  %o  %c %c %c %c\n",
-	       *index,
-	       (tlbehi & 0x200)?'1':'0',
-	       (tlbelo & 0x100)?'1':'0',
-	       (tlbehi & 0xff),
-	       (tlbehi >> 12), (tlbelo >> 12),
-	       (tlbelo >> 4) & 7, (tlbelo >> 2) & 3,
-	       (tlbelo & 0x200)?'1':'0',
-	       (tlbelo & 0x080)?'1':'0',
-	       (tlbelo & 0x001)?'1':'0',
-	       (tlbelo & 0x002)?'1':'0');
+		   *index,
+		   SYSREG_BFEXT(TLBEHI_V, tlbehi) ? '1' : '0',
+		   SYSREG_BFEXT(G, tlbelo) ? '1' : '0',
+		   SYSREG_BFEXT(ASID, tlbehi),
+		   SYSREG_BFEXT(VPN, tlbehi) >> 2,
+		   SYSREG_BFEXT(PFN, tlbelo) >> 2,
+		   SYSREG_BFEXT(AP, tlbelo),
+		   SYSREG_BFEXT(SZ, tlbelo),
+		   SYSREG_BFEXT(TLBELO_C, tlbelo) ? '1' : '0',
+		   SYSREG_BFEXT(B, tlbelo) ? '1' : '0',
+		   SYSREG_BFEXT(W, tlbelo) ? '1' : '0',
+		   SYSREG_BFEXT(TLBELO_D, tlbelo) ? '1' : '0');
 
 	return 0;
 }
diff --git a/drivers/misc/atmel_pwm.c b/drivers/misc/atmel_pwm.c
index 0d5ce03..5b5a14d 100644
--- a/drivers/misc/atmel_pwm.c
+++ b/drivers/misc/atmel_pwm.c
@@ -332,7 +332,7 @@
 	p->base = ioremap(r->start, r->end - r->start + 1);
 	if (!p->base)
 		goto fail;
-	p->clk = clk_get(&pdev->dev, "mck");
+	p->clk = clk_get(&pdev->dev, "pwm_clk");
 	if (IS_ERR(p->clk)) {
 		status = PTR_ERR(p->clk);
 		p->clk = NULL;
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 92dccd4..0a5745a 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -1277,8 +1277,45 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM
+static int macb_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct net_device *netdev = platform_get_drvdata(pdev);
+	struct macb *bp = netdev_priv(netdev);
+
+	netif_device_detach(netdev);
+
+#ifndef CONFIG_ARCH_AT91
+	clk_disable(bp->hclk);
+#endif
+	clk_disable(bp->pclk);
+
+	return 0;
+}
+
+static int macb_resume(struct platform_device *pdev)
+{
+	struct net_device *netdev = platform_get_drvdata(pdev);
+	struct macb *bp = netdev_priv(netdev);
+
+	clk_enable(bp->pclk);
+#ifndef CONFIG_ARCH_AT91
+	clk_enable(bp->hclk);
+#endif
+
+	netif_device_attach(netdev);
+
+	return 0;
+}
+#else
+#define macb_suspend	NULL
+#define macb_resume	NULL
+#endif
+
 static struct platform_driver macb_driver = {
 	.remove		= __exit_p(macb_remove),
+	.suspend	= macb_suspend,
+	.resume		= macb_resume,
 	.driver		= {
 		.name		= "macb",
 		.owner	= THIS_MODULE,
diff --git a/drivers/rtc/rtc-at32ap700x.c b/drivers/rtc/rtc-at32ap700x.c
index 2ef8cdf..90b9a65 100644
--- a/drivers/rtc/rtc-at32ap700x.c
+++ b/drivers/rtc/rtc-at32ap700x.c
@@ -265,6 +265,7 @@
 	}
 
 	platform_set_drvdata(pdev, rtc);
+	device_init_wakeup(&pdev->dev, 1);
 
 	dev_info(&pdev->dev, "Atmel RTC for AT32AP700x at %08lx irq %ld\n",
 			(unsigned long)rtc->regs, rtc->irq);
@@ -284,6 +285,8 @@
 {
 	struct rtc_at32ap700x *rtc = platform_get_drvdata(pdev);
 
+	device_init_wakeup(&pdev->dev, 0);
+
 	free_irq(rtc->irq, rtc);
 	iounmap(rtc->regs);
 	rtc_device_unregister(rtc->rtc);
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
index 42be8b01..6aeef22b 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/serial/atmel_serial.c
@@ -1439,14 +1439,29 @@
 };
 
 #ifdef CONFIG_PM
+static bool atmel_serial_clk_will_stop(void)
+{
+#ifdef CONFIG_ARCH_AT91
+	return at91_suspend_entering_slow_clock();
+#else
+	return false;
+#endif
+}
+
 static int atmel_serial_suspend(struct platform_device *pdev,
 				pm_message_t state)
 {
 	struct uart_port *port = platform_get_drvdata(pdev);
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
+	if (atmel_is_console_port(port) && console_suspend_enabled) {
+		/* Drain the TX shifter */
+		while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY))
+			cpu_relax();
+	}
+
 	if (device_may_wakeup(&pdev->dev)
-	    && !at91_suspend_entering_slow_clock())
+	    && !atmel_serial_clk_will_stop())
 		enable_irq_wake(port->irq);
 	else {
 		uart_suspend_port(&atmel_uart, port);
diff --git a/include/asm-avr32/arch-at32ap/board.h b/include/asm-avr32/arch-at32ap/board.h
index a4e2d28..b4cddfa 100644
--- a/include/asm-avr32/arch-at32ap/board.h
+++ b/include/asm-avr32/arch-at32ap/board.h
@@ -8,6 +8,12 @@
 
 #define GPIO_PIN_NONE	(-1)
 
+/*
+ * Clock rates for various on-board oscillators. The number of entries
+ * in this array is chip-dependent.
+ */
+extern unsigned long at32_board_osc_rates[];
+  
 /* Add basic devices: system manager, interrupt controller, portmuxes, etc. */
 void at32_add_system_devices(void);
 
@@ -36,7 +42,8 @@
 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 long fbmem_start, unsigned long fbmem_len,
+		     unsigned int pin_config);
 
 struct usba_platform_data;
 struct platform_device *
@@ -73,6 +80,7 @@
 struct platform_device *at32_add_device_mci(unsigned int id);
 struct platform_device *at32_add_device_ac97c(unsigned int id);
 struct platform_device *at32_add_device_abdac(unsigned int id);
+struct platform_device *at32_add_device_psif(unsigned int id);
 
 struct cf_platform_data {
 	int	detect_pin;
diff --git a/include/asm-avr32/arch-at32ap/init.h b/include/asm-avr32/arch-at32ap/init.h
index 5e75d85..bc40e3d 100644
--- a/include/asm-avr32/arch-at32ap/init.h
+++ b/include/asm-avr32/arch-at32ap/init.h
@@ -13,10 +13,6 @@
 void setup_platform(void);
 void setup_board(void);
 
-/* Called by setup_platform */
-void at32_clock_init(void);
-void at32_portmux_init(void);
-
 void at32_setup_serial_console(unsigned int usart_id);
 
 #endif /* __ASM_AVR32_AT32AP_INIT_H__ */
diff --git a/include/asm-avr32/arch-at32ap/pm.h b/include/asm-avr32/arch-at32ap/pm.h
index 356e430..979b355 100644
--- a/include/asm-avr32/arch-at32ap/pm.h
+++ b/include/asm-avr32/arch-at32ap/pm.h
@@ -19,6 +19,7 @@
 
 #ifndef __ASSEMBLY__
 extern void cpu_enter_idle(void);
+extern void cpu_enter_standby(unsigned long sdramc_base);
 
 extern bool disable_idle_sleep;
 
@@ -43,6 +44,8 @@
 	else
 		cpu_enter_idle();
 }
+
+void intc_set_suspend_handler(unsigned long offset);
 #endif
 
 #endif /* __ASM_AVR32_ARCH_PM_H */
diff --git a/include/asm-avr32/arch-at32ap/sram.h b/include/asm-avr32/arch-at32ap/sram.h
new file mode 100644
index 0000000..4838dae
--- /dev/null
+++ b/include/asm-avr32/arch-at32ap/sram.h
@@ -0,0 +1,30 @@
+/*
+ * Simple SRAM allocator
+ *
+ * Copyright (C) 2008 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_ARCH_SRAM_H
+#define __ASM_AVR32_ARCH_SRAM_H
+
+#include <linux/genalloc.h>
+
+extern struct gen_pool *sram_pool;
+
+static inline unsigned long sram_alloc(size_t len)
+{
+	if (!sram_pool)
+		return 0UL;
+
+	return gen_pool_alloc(sram_pool, len);
+}
+
+static inline void sram_free(unsigned long addr, size_t len)
+{
+	return gen_pool_free(sram_pool, addr, len);
+}
+
+#endif /* __ASM_AVR32_ARCH_SRAM_H */
diff --git a/include/asm-avr32/mmu_context.h b/include/asm-avr32/mmu_context.h
index c37c391..27ff234 100644
--- a/include/asm-avr32/mmu_context.h
+++ b/include/asm-avr32/mmu_context.h
@@ -13,7 +13,6 @@
 #define __ASM_AVR32_MMU_CONTEXT_H
 
 #include <asm/tlbflush.h>
-#include <asm/pgalloc.h>
 #include <asm/sysreg.h>
 #include <asm-generic/mm_hooks.h>
 
diff --git a/include/asm-avr32/pci.h b/include/asm-avr32/pci.h
index 0f5f134..a32a023 100644
--- a/include/asm-avr32/pci.h
+++ b/include/asm-avr32/pci.h
@@ -5,4 +5,6 @@
 
 #define PCI_DMA_BUS_IS_PHYS	(1)
 
+#include <asm-generic/pci-dma-compat.h>
+
 #endif /* __ASM_AVR32_PCI_H__ */
diff --git a/include/asm-avr32/pgalloc.h b/include/asm-avr32/pgalloc.h
index 51fc1f6..6408213 100644
--- a/include/asm-avr32/pgalloc.h
+++ b/include/asm-avr32/pgalloc.h
@@ -8,65 +8,79 @@
 #ifndef __ASM_AVR32_PGALLOC_H
 #define __ASM_AVR32_PGALLOC_H
 
-#include <asm/processor.h>
-#include <linux/threads.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
+#include <linux/quicklist.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
 
-#define pmd_populate_kernel(mm, pmd, pte) \
-	set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)))
+#define QUICK_PGD	0	/* Preserve kernel mappings over free */
+#define QUICK_PT	1	/* Zero on free */
 
-static __inline__ void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
+static inline void pmd_populate_kernel(struct mm_struct *mm,
+				       pmd_t *pmd, pte_t *pte)
+{
+	set_pmd(pmd, __pmd((unsigned long)pte));
+}
+
+static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
 				    pgtable_t pte)
 {
-	set_pmd(pmd, __pmd(_PAGE_TABLE + page_to_phys(pte)));
+	set_pmd(pmd, __pmd((unsigned long)page_address(pte)));
 }
 #define pmd_pgtable(pmd) pmd_page(pmd)
 
+static inline void pgd_ctor(void *x)
+{
+	pgd_t *pgd = x;
+
+	memcpy(pgd + USER_PTRS_PER_PGD,
+		swapper_pg_dir + USER_PTRS_PER_PGD,
+		(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+}
+
 /*
  * Allocate and free page tables
  */
-static __inline__ pgd_t *pgd_alloc(struct mm_struct *mm)
+static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 {
-	return kcalloc(USER_PTRS_PER_PGD, sizeof(pgd_t), GFP_KERNEL);
+	return quicklist_alloc(QUICK_PGD, GFP_KERNEL | __GFP_REPEAT, pgd_ctor);
 }
 
 static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
-	kfree(pgd);
+	quicklist_free(QUICK_PGD, NULL, pgd);
 }
 
 static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
 					  unsigned long address)
 {
-	pte_t *pte;
-
-	pte = (pte_t *)get_zeroed_page(GFP_KERNEL | __GFP_REPEAT);
-
-	return pte;
+	return quicklist_alloc(QUICK_PT, GFP_KERNEL | __GFP_REPEAT, NULL);
 }
 
-static inline struct page *pte_alloc_one(struct mm_struct *mm,
+static inline pgtable_t pte_alloc_one(struct mm_struct *mm,
 					 unsigned long address)
 {
-	struct page *pte;
+	struct page *page;
+	void *pg;
 
-	pte = alloc_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
-	if (!pte)
+	pg = quicklist_alloc(QUICK_PT, GFP_KERNEL | __GFP_REPEAT, NULL);
+	if (!pg)
 		return NULL;
-	pgtable_page_ctor(pte);
-	return pte;
+
+	page = virt_to_page(pg);
+	pgtable_page_ctor(page);
+
+	return page;
 }
 
 static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 {
-	free_page((unsigned long)pte);
+	quicklist_free(QUICK_PT, NULL, pte);
 }
 
 static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
 {
 	pgtable_page_dtor(pte);
-	__free_page(pte);
+	quicklist_free_page(QUICK_PT, NULL, pte);
 }
 
 #define __pte_free_tlb(tlb,pte)				\
@@ -75,6 +89,10 @@
 	tlb_remove_page((tlb), pte);			\
 } while (0)
 
-#define check_pgt_cache() do { } while(0)
+static inline void check_pgt_cache(void)
+{
+	quicklist_trim(QUICK_PGD, NULL, 25, 16);
+	quicklist_trim(QUICK_PT, NULL, 25, 16);
+}
 
 #endif /* __ASM_AVR32_PGALLOC_H */
diff --git a/include/asm-avr32/pgtable.h b/include/asm-avr32/pgtable.h
index c0e5e29..fecdda1 100644
--- a/include/asm-avr32/pgtable.h
+++ b/include/asm-avr32/pgtable.h
@@ -129,13 +129,6 @@
 
 #define _PAGE_FLAGS_CACHE_MASK	(_PAGE_CACHABLE | _PAGE_BUFFER | _PAGE_WT)
 
-/* TODO: Check for saneness */
-/* User-mode page table flags (to be set in a pgd or pmd entry) */
-#define _PAGE_TABLE		(_PAGE_PRESENT | _PAGE_TYPE_SMALL | _PAGE_RW \
-				 | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
-/* Kernel-mode page table flags */
-#define _KERNPG_TABLE		(_PAGE_PRESENT | _PAGE_TYPE_SMALL | _PAGE_RW \
-				 | _PAGE_ACCESSED | _PAGE_DIRTY)
 /* Flags that may be modified by software */
 #define _PAGE_CHG_MASK		(PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY \
 				 | _PAGE_FLAGS_CACHE_MASK)
@@ -262,10 +255,14 @@
 }
 
 #define pmd_none(x)	(!pmd_val(x))
-#define pmd_present(x)	(pmd_val(x) & _PAGE_PRESENT)
-#define pmd_clear(xp)	do { set_pmd(xp, __pmd(0)); } while (0)
-#define	pmd_bad(x)	((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER))	\
-			 != _KERNPG_TABLE)
+#define pmd_present(x)	(pmd_val(x))
+
+static inline void pmd_clear(pmd_t *pmdp)
+{
+	set_pmd(pmdp, __pmd(0));
+}
+
+#define	pmd_bad(x)	(pmd_val(x) & ~PAGE_MASK)
 
 /*
  * Permanent address of a page. We don't support highmem, so this is
@@ -303,19 +300,16 @@
 
 #define page_pte(page)	page_pte_prot(page, __pgprot(0))
 
-#define pmd_page_vaddr(pmd)					\
-	((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
-
-#define pmd_page(pmd)	(phys_to_page(pmd_val(pmd)))
+#define pmd_page_vaddr(pmd)	pmd_val(pmd)
+#define pmd_page(pmd)		(virt_to_page(pmd_val(pmd)))
 
 /* to find an entry in a page-table-directory. */
-#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
-#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
-#define pgd_offset_current(address)				\
-	((pgd_t *)__mfsr(SYSREG_PTBR) + pgd_index(address))
+#define pgd_index(address)	(((address) >> PGDIR_SHIFT)	\
+				 & (PTRS_PER_PGD - 1))
+#define pgd_offset(mm, address)	((mm)->pgd + pgd_index(address))
 
 /* to find an entry in a kernel page-table-directory */
-#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+#define pgd_offset_k(address)	pgd_offset(&init_mm, address)
 
 /* Find an entry in the third-level page table.. */
 #define pte_index(address)				\
diff --git a/include/asm-avr32/thread_info.h b/include/asm-avr32/thread_info.h
index 07049f6..df68631 100644
--- a/include/asm-avr32/thread_info.h
+++ b/include/asm-avr32/thread_info.h
@@ -88,6 +88,7 @@
 #define TIF_MEMDIE		6
 #define TIF_RESTORE_SIGMASK	7	/* restore signal mask in do_signal */
 #define TIF_CPU_GOING_TO_SLEEP	8	/* CPU is entering sleep 0 mode */
+#define TIF_FREEZE		29
 #define TIF_DEBUG		30	/* debugging enabled */
 #define TIF_USERSPACE		31      /* true if FS sets userspace */
 
diff --git a/include/asm-avr32/tlbflush.h b/include/asm-avr32/tlbflush.h
index 5bc7c88..bf90a78 100644
--- a/include/asm-avr32/tlbflush.h
+++ b/include/asm-avr32/tlbflush.h
@@ -26,7 +26,6 @@
 extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 			    unsigned long end);
 extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
-extern void __flush_tlb_page(unsigned long asid, unsigned long page);
 
 extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
 
diff --git a/mm/Kconfig b/mm/Kconfig
index 4242743..c4de852 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -199,7 +199,7 @@
 config NR_QUICK
 	int
 	depends on QUICKLIST
-	default "2" if SUPERH
+	default "2" if SUPERH || AVR32
 	default "1"
 
 config VIRT_TO_BUS