Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hskinnemoen/avr32-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hskinnemoen/avr32-2.6:
  [AVR32] Initialize phy_mask for both macb devices
  [AVR32] Fix atomic_add_unless() and atomic_sub_unless()
  [AVR32] Correct misspelled CONFIG_BLK_DEV_INITRD variable.
  [AVR32] Fix build error in parse_tag_rdimg()
  [AVR32] Don't wire up macb0 unless SW6 is in default position
  [AVR32] Wire up SSC platform device 0 as TX on ATSTK1000 board
  [AVR32] Add Atmel SSC driver platform device to AT32AP architecture
  [AVR32] Remove optimization of unaligned word loads
  [AVR32] Make STK1000 mux settings configurable
  [AVR32] CPU frequency scaling for AT32AP
  [AVR32] Split SM device into PM, RTC, WDT and EIC
  [AVR32] faster avr32 unaligned access
diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig
index 3ec7658..d12346a 100644
--- a/arch/avr32/Kconfig
+++ b/arch/avr32/Kconfig
@@ -113,6 +113,10 @@
 	bool "ATNGW100 Network Gateway"
 endchoice
 
+if BOARD_ATSTK1000
+source "arch/avr32/boards/atstk1000/Kconfig"
+endif
+
 choice
 	prompt "Boot loader type"
 	default LOADER_U_BOOT
@@ -185,6 +189,27 @@
 
 endmenu
 
+menu "Power managment options"
+
+menu "CPU Frequency scaling"
+
+source "drivers/cpufreq/Kconfig"
+
+config CPU_FREQ_AT32AP
+	bool "CPU frequency driver for AT32AP"
+	depends on CPU_FREQ && PLATFORM_AT32AP
+	default n
+	help
+	  This enables the CPU frequency driver for AT32AP processors.
+
+	  For details, take a look in <file:Documentation/cpu-freq>.
+
+	  If in doubt, say N.
+
+endmenu
+
+endmenu
+
 menu "Bus options"
 
 config PCI
diff --git a/arch/avr32/boards/atstk1000/Kconfig b/arch/avr32/boards/atstk1000/Kconfig
new file mode 100644
index 0000000..71bc7d3
--- /dev/null
+++ b/arch/avr32/boards/atstk1000/Kconfig
@@ -0,0 +1,53 @@
+# STK1000 customization
+
+if BOARD_ATSTK1002
+
+config BOARD_ATSTK1002_CUSTOM
+	bool "Non-default STK-1002 jumper settings"
+	help
+	  You will normally leave the jumpers on the CPU card at their
+	  default settings.  If you need to use certain peripherals,
+	  you will need to change some of those jumpers.
+
+if BOARD_ATSTK1002_CUSTOM
+
+config BOARD_ATSTK1002_SW1_CUSTOM
+	bool "SW1: use SSC1 (not SPI0)"
+	help
+	  This also prevents using the external DAC as an audio interface,
+	  and means you can't initialize the on-board QVGA display.
+
+config BOARD_ATSTK1002_SW2_CUSTOM
+	bool "SW2: use IRDA or TIMER0 (not UART-A, MMC/SD, and PS2-A)"
+	help
+	  If you change this you'll want an updated boot loader putting
+	  the console on UART-C not UART-A.
+
+config BOARD_ATSTK1002_SW3_CUSTOM
+	bool "SW3: use TIMER1 (not SSC0 and GCLK)"
+	help
+	  This also prevents using the external DAC as an audio interface.
+
+config BOARD_ATSTK1002_SW4_CUSTOM
+	bool "SW4: use ISI/Camera (not GPIOs, SPI1, and PS2-B)"
+	help
+	  To use the camera interface you'll need a custom card (on the
+	  PCI-format connector) connect a video sensor.
+
+config BOARD_ATSTK1002_SW5_CUSTOM
+	bool "SW5: use MACB1 (not LCDC)"
+
+config BOARD_ATSTK1002_SW6_CUSTOM
+	bool "SW6: more GPIOs (not MACB0)"
+
+endif	# custom
+
+config BOARD_ATSTK1002_SPI1
+	bool "Configure SPI1 controller"
+	depends on !BOARD_ATSTK1002_SW4_CUSTOM
+	help
+	  All the signals for the second SPI controller are available on
+	  GPIO lines and accessed through the J1 jumper block.  Say "y"
+	  here to configure that SPI controller.
+
+endif	# stk 1002
diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c
index e253e86..cb93eab 100644
--- a/arch/avr32/boards/atstk1000/atstk1002.c
+++ b/arch/avr32/boards/atstk1000/atstk1002.c
@@ -27,15 +27,27 @@
 
 #include "atstk1000.h"
 
-#define	SW2_DEFAULT		/* MMCI and UART_A available */
 
 struct eth_addr {
 	u8 addr[6];
 };
 
 static struct eth_addr __initdata hw_addr[2];
-static struct eth_platform_data __initdata eth_data[2];
+static struct eth_platform_data __initdata eth_data[2] = {
+	{
+		/*
+		 * The MDIO pullups on STK1000 are a bit too weak for
+		 * the autodetection to work properly, so we have to
+		 * mask out everything but the correct address.
+		 */
+		.phy_mask	= ~(1U << 16),
+	},
+	{
+		.phy_mask	= ~(1U << 17),
+	},
+};
 
+#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
 static struct spi_board_info spi0_board_info[] __initdata = {
 	{
 		/* QVGA display */
@@ -45,6 +57,13 @@
 		.mode		= SPI_MODE_3,
 	},
 };
+#endif
+
+#ifdef CONFIG_BOARD_ATSTK1002_SPI1
+static struct spi_board_info spi1_board_info[] __initdata = { {
+	/* patch in custom entries here */
+} };
+#endif
 
 /*
  * The next two functions should go away as the boot loader is
@@ -103,10 +122,10 @@
 
 void __init setup_board(void)
 {
-#ifdef	SW2_DEFAULT
-	at32_map_usart(1, 0);	/* USART 1/A: /dev/ttyS0, DB9 */
-#else
+#ifdef	CONFIG_BOARD_ATSTK1002_SW2_CUSTOM
 	at32_map_usart(0, 1);	/* USART 0/B: /dev/ttyS1, IRDA */
+#else
+	at32_map_usart(1, 0);	/* USART 1/A: /dev/ttyS0, DB9 */
 #endif
 	/* USART 2/unused: expansion connector */
 	at32_map_usart(3, 2);	/* USART 3/C: /dev/ttyS2, DB9 */
@@ -140,18 +159,31 @@
 
 	at32_add_system_devices();
 
-#ifdef	SW2_DEFAULT
-	at32_add_device_usart(0);
-#else
+#ifdef	CONFIG_BOARD_ATSTK1002_SW2_CUSTOM
 	at32_add_device_usart(1);
+#else
+	at32_add_device_usart(0);
 #endif
 	at32_add_device_usart(2);
 
+#ifndef CONFIG_BOARD_ATSTK1002_SW6_CUSTOM
 	set_hw_addr(at32_add_device_eth(0, &eth_data[0]));
-
+#endif
+#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
 	at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
+#endif
+#ifdef CONFIG_BOARD_ATSTK1002_SPI1
+	at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
+#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);
+#endif
+#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
+	at32_add_device_ssc(0, ATMEL_SSC_TX);
+#endif
 
 	return 0;
 }
diff --git a/arch/avr32/kernel/setup.c b/arch/avr32/kernel/setup.c
index b279d66..d08b0bc 100644
--- a/arch/avr32/kernel/setup.c
+++ b/arch/avr32/kernel/setup.c
@@ -313,7 +313,7 @@
 
 static int __init parse_tag_rdimg(struct tag *tag)
 {
-#ifdef CONFIG_INITRD
+#ifdef CONFIG_BLK_DEV_INITRD
 	struct tag_mem_range *mem = &tag->u.mem_range;
 	int ret;
 
@@ -323,7 +323,7 @@
 		return 0;
 	}
 
-	ret = add_reserved_region(mem->start, mem->start + mem->size - 1,
+	ret = add_reserved_region(mem->addr, mem->addr + mem->size - 1,
 				  "initrd");
 	if (ret) {
 		printk(KERN_WARNING
diff --git a/arch/avr32/mach-at32ap/Makefile b/arch/avr32/mach-at32ap/Makefile
index f1d3957..a8b4450 100644
--- a/arch/avr32/mach-at32ap/Makefile
+++ b/arch/avr32/mach-at32ap/Makefile
@@ -1,3 +1,4 @@
 obj-y				+= at32ap.o clock.o intc.o extint.o pio.o hsmc.o
 obj-$(CONFIG_CPU_AT32AP7000)	+= at32ap7000.o
 obj-$(CONFIG_CPU_AT32AP7000)	+= time-tc.o
+obj-$(CONFIG_CPU_FREQ_AT32AP)	+= cpufreq.o
diff --git a/arch/avr32/mach-at32ap/at32ap.c b/arch/avr32/mach-at32ap/at32ap.c
index 90f207e..7c4987f 100644
--- a/arch/avr32/mach-at32ap/at32ap.c
+++ b/arch/avr32/mach-at32ap/at32ap.c
@@ -11,41 +11,10 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 
-#include <asm/io.h>
-
 #include <asm/arch/init.h>
-#include <asm/arch/sm.h>
-
-struct at32_sm system_manager;
-
-static int __init at32_sm_init(void)
-{
-	struct resource *regs;
-	struct at32_sm *sm = &system_manager;
-	int ret = -ENXIO;
-
-	regs = platform_get_resource(&at32_sm_device, IORESOURCE_MEM, 0);
-	if (!regs)
-		goto fail;
-
-	spin_lock_init(&sm->lock);
-	sm->pdev = &at32_sm_device;
-
-	ret = -ENOMEM;
-	sm->regs = ioremap(regs->start, regs->end - regs->start + 1);
-	if (!sm->regs)
-		goto fail;
-
-	return 0;
-
-fail:
-	printk(KERN_ERR "Failed to initialize System Manager: %d\n", ret);
-	return ret;
-}
 
 void __init setup_platform(void)
 {
-	at32_sm_init();
 	at32_clock_init();
 	at32_portmux_init();
 }
diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c
index 4dda42d..64cc558 100644
--- a/arch/avr32/mach-at32ap/at32ap7000.c
+++ b/arch/avr32/mach-at32ap/at32ap7000.c
@@ -17,14 +17,20 @@
 #include <asm/arch/at32ap7000.h>
 #include <asm/arch/board.h>
 #include <asm/arch/portmux.h>
-#include <asm/arch/sm.h>
 
 #include <video/atmel_lcdc.h>
 
 #include "clock.h"
 #include "hmatrix.h"
 #include "pio.h"
-#include "sm.h"
+#include "pm.h"
+
+/*
+ * We can reduce the code size a bit by using a constant here. Since
+ * this file is completely chip-specific, it's safe to not use
+ * ioremap. Generic drivers should of course never do this.
+ */
+#define AT32_PM_BASE	0xfff00000
 
 #define PBMEM(base)					\
 	{						\
@@ -88,6 +94,8 @@
 	.index		= _index,				\
 }
 
+static DEFINE_SPINLOCK(pm_lock);
+
 unsigned long at32ap7000_osc_rates[3] = {
 	[0] = 32768,
 	/* FIXME: these are ATSTK1002-specific */
@@ -104,11 +112,11 @@
 {
 	unsigned long div, mul, rate;
 
-	if (!(control & SM_BIT(PLLEN)))
+	if (!(control & PM_BIT(PLLEN)))
 		return 0;
 
-	div = SM_BFEXT(PLLDIV, control) + 1;
-	mul = SM_BFEXT(PLLMUL, control) + 1;
+	div = PM_BFEXT(PLLDIV, control) + 1;
+	mul = PM_BFEXT(PLLMUL, control) + 1;
 
 	rate = clk->parent->get_rate(clk->parent);
 	rate = (rate + div / 2) / div;
@@ -121,7 +129,7 @@
 {
 	u32 control;
 
-	control = sm_readl(&system_manager, PM_PLL0);
+	control = pm_readl(PLL0);
 
 	return pll_get_rate(clk, control);
 }
@@ -130,7 +138,7 @@
 {
 	u32 control;
 
-	control = sm_readl(&system_manager, PM_PLL1);
+	control = pm_readl(PLL1);
 
 	return pll_get_rate(clk, control);
 }
@@ -187,108 +195,139 @@
 
 static void cpu_clk_mode(struct clk *clk, int enabled)
 {
-	struct at32_sm *sm = &system_manager;
 	unsigned long flags;
 	u32 mask;
 
-	spin_lock_irqsave(&sm->lock, flags);
-	mask = sm_readl(sm, PM_CPU_MASK);
+	spin_lock_irqsave(&pm_lock, flags);
+	mask = pm_readl(CPU_MASK);
 	if (enabled)
 		mask |= 1 << clk->index;
 	else
 		mask &= ~(1 << clk->index);
-	sm_writel(sm, PM_CPU_MASK, mask);
-	spin_unlock_irqrestore(&sm->lock, flags);
+	pm_writel(CPU_MASK, mask);
+	spin_unlock_irqrestore(&pm_lock, flags);
 }
 
 static unsigned long cpu_clk_get_rate(struct clk *clk)
 {
 	unsigned long cksel, shift = 0;
 
-	cksel = sm_readl(&system_manager, PM_CKSEL);
-	if (cksel & SM_BIT(CPUDIV))
-		shift = SM_BFEXT(CPUSEL, cksel) + 1;
+	cksel = pm_readl(CKSEL);
+	if (cksel & PM_BIT(CPUDIV))
+		shift = PM_BFEXT(CPUSEL, cksel) + 1;
 
 	return bus_clk_get_rate(clk, shift);
 }
 
+static long cpu_clk_set_rate(struct clk *clk, unsigned long rate, int apply)
+{
+	u32 control;
+	unsigned long parent_rate, child_div, actual_rate, div;
+
+	parent_rate = clk->parent->get_rate(clk->parent);
+	control = pm_readl(CKSEL);
+
+	if (control & PM_BIT(HSBDIV))
+		child_div = 1 << (PM_BFEXT(HSBSEL, control) + 1);
+	else
+		child_div = 1;
+
+	if (rate > 3 * (parent_rate / 4) || child_div == 1) {
+		actual_rate = parent_rate;
+		control &= ~PM_BIT(CPUDIV);
+	} else {
+		unsigned int cpusel;
+		div = (parent_rate + rate / 2) / rate;
+		if (div > child_div)
+			div = child_div;
+		cpusel = (div > 1) ? (fls(div) - 2) : 0;
+		control = PM_BIT(CPUDIV) | PM_BFINS(CPUSEL, cpusel, control);
+		actual_rate = parent_rate / (1 << (cpusel + 1));
+	}
+
+	pr_debug("clk %s: new rate %lu (actual rate %lu)\n",
+			clk->name, rate, actual_rate);
+
+	if (apply)
+		pm_writel(CKSEL, control);
+
+	return actual_rate;
+}
+
 static void hsb_clk_mode(struct clk *clk, int enabled)
 {
-	struct at32_sm *sm = &system_manager;
 	unsigned long flags;
 	u32 mask;
 
-	spin_lock_irqsave(&sm->lock, flags);
-	mask = sm_readl(sm, PM_HSB_MASK);
+	spin_lock_irqsave(&pm_lock, flags);
+	mask = pm_readl(HSB_MASK);
 	if (enabled)
 		mask |= 1 << clk->index;
 	else
 		mask &= ~(1 << clk->index);
-	sm_writel(sm, PM_HSB_MASK, mask);
-	spin_unlock_irqrestore(&sm->lock, flags);
+	pm_writel(HSB_MASK, mask);
+	spin_unlock_irqrestore(&pm_lock, flags);
 }
 
 static unsigned long hsb_clk_get_rate(struct clk *clk)
 {
 	unsigned long cksel, shift = 0;
 
-	cksel = sm_readl(&system_manager, PM_CKSEL);
-	if (cksel & SM_BIT(HSBDIV))
-		shift = SM_BFEXT(HSBSEL, cksel) + 1;
+	cksel = pm_readl(CKSEL);
+	if (cksel & PM_BIT(HSBDIV))
+		shift = PM_BFEXT(HSBSEL, cksel) + 1;
 
 	return bus_clk_get_rate(clk, shift);
 }
 
 static void pba_clk_mode(struct clk *clk, int enabled)
 {
-	struct at32_sm *sm = &system_manager;
 	unsigned long flags;
 	u32 mask;
 
-	spin_lock_irqsave(&sm->lock, flags);
-	mask = sm_readl(sm, PM_PBA_MASK);
+	spin_lock_irqsave(&pm_lock, flags);
+	mask = pm_readl(PBA_MASK);
 	if (enabled)
 		mask |= 1 << clk->index;
 	else
 		mask &= ~(1 << clk->index);
-	sm_writel(sm, PM_PBA_MASK, mask);
-	spin_unlock_irqrestore(&sm->lock, flags);
+	pm_writel(PBA_MASK, mask);
+	spin_unlock_irqrestore(&pm_lock, flags);
 }
 
 static unsigned long pba_clk_get_rate(struct clk *clk)
 {
 	unsigned long cksel, shift = 0;
 
-	cksel = sm_readl(&system_manager, PM_CKSEL);
-	if (cksel & SM_BIT(PBADIV))
-		shift = SM_BFEXT(PBASEL, cksel) + 1;
+	cksel = pm_readl(CKSEL);
+	if (cksel & PM_BIT(PBADIV))
+		shift = PM_BFEXT(PBASEL, cksel) + 1;
 
 	return bus_clk_get_rate(clk, shift);
 }
 
 static void pbb_clk_mode(struct clk *clk, int enabled)
 {
-	struct at32_sm *sm = &system_manager;
 	unsigned long flags;
 	u32 mask;
 
-	spin_lock_irqsave(&sm->lock, flags);
-	mask = sm_readl(sm, PM_PBB_MASK);
+	spin_lock_irqsave(&pm_lock, flags);
+	mask = pm_readl(PBB_MASK);
 	if (enabled)
 		mask |= 1 << clk->index;
 	else
 		mask &= ~(1 << clk->index);
-	sm_writel(sm, PM_PBB_MASK, mask);
-	spin_unlock_irqrestore(&sm->lock, flags);
+	pm_writel(PBB_MASK, mask);
+	spin_unlock_irqrestore(&pm_lock, flags);
 }
 
 static unsigned long pbb_clk_get_rate(struct clk *clk)
 {
 	unsigned long cksel, shift = 0;
 
-	cksel = sm_readl(&system_manager, PM_CKSEL);
-	if (cksel & SM_BIT(PBBDIV))
-		shift = SM_BFEXT(PBBSEL, cksel) + 1;
+	cksel = pm_readl(CKSEL);
+	if (cksel & PM_BIT(PBBDIV))
+		shift = PM_BFEXT(PBBSEL, cksel) + 1;
 
 	return bus_clk_get_rate(clk, shift);
 }
@@ -296,6 +335,7 @@
 static struct clk cpu_clk = {
 	.name		= "cpu",
 	.get_rate	= cpu_clk_get_rate,
+	.set_rate	= cpu_clk_set_rate,
 	.users		= 1,
 };
 static struct clk hsb_clk = {
@@ -327,12 +367,12 @@
 {
 	u32 control;
 
-	control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
+	control = pm_readl(GCCTRL(clk->index));
 	if (enabled)
-		control |= SM_BIT(CEN);
+		control |= PM_BIT(CEN);
 	else
-		control &= ~SM_BIT(CEN);
-	sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index, control);
+		control &= ~PM_BIT(CEN);
+	pm_writel(GCCTRL(clk->index), control);
 }
 
 static unsigned long genclk_get_rate(struct clk *clk)
@@ -340,9 +380,9 @@
 	u32 control;
 	unsigned long div = 1;
 
-	control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
-	if (control & SM_BIT(DIVEN))
-		div = 2 * (SM_BFEXT(DIV, control) + 1);
+	control = pm_readl(GCCTRL(clk->index));
+	if (control & PM_BIT(DIVEN))
+		div = 2 * (PM_BFEXT(DIV, control) + 1);
 
 	return clk->parent->get_rate(clk->parent) / div;
 }
@@ -353,23 +393,22 @@
 	unsigned long parent_rate, actual_rate, div;
 
 	parent_rate = clk->parent->get_rate(clk->parent);
-	control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
+	control = pm_readl(GCCTRL(clk->index));
 
 	if (rate > 3 * parent_rate / 4) {
 		actual_rate = parent_rate;
-		control &= ~SM_BIT(DIVEN);
+		control &= ~PM_BIT(DIVEN);
 	} else {
 		div = (parent_rate + rate) / (2 * rate) - 1;
-		control = SM_BFINS(DIV, div, control) | SM_BIT(DIVEN);
+		control = PM_BFINS(DIV, div, control) | PM_BIT(DIVEN);
 		actual_rate = parent_rate / (2 * (div + 1));
 	}
 
-	printk("clk %s: new rate %lu (actual rate %lu)\n",
-	       clk->name, rate, actual_rate);
+	dev_dbg(clk->dev, "clk %s: new rate %lu (actual rate %lu)\n",
+		clk->name, rate, actual_rate);
 
 	if (apply)
-		sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index,
-			  control);
+		pm_writel(GCCTRL(clk->index), control);
 
 	return actual_rate;
 }
@@ -378,24 +417,24 @@
 {
 	u32 control;
 
-	printk("clk %s: new parent %s (was %s)\n",
-	       clk->name, parent->name, clk->parent->name);
+	dev_dbg(clk->dev, "clk %s: new parent %s (was %s)\n",
+		clk->name, parent->name, clk->parent->name);
 
-	control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
+	control = pm_readl(GCCTRL(clk->index));
 
 	if (parent == &osc1 || parent == &pll1)
-		control |= SM_BIT(OSCSEL);
+		control |= PM_BIT(OSCSEL);
 	else if (parent == &osc0 || parent == &pll0)
-		control &= ~SM_BIT(OSCSEL);
+		control &= ~PM_BIT(OSCSEL);
 	else
 		return -EINVAL;
 
 	if (parent == &pll0 || parent == &pll1)
-		control |= SM_BIT(PLLSEL);
+		control |= PM_BIT(PLLSEL);
 	else
-		control &= ~SM_BIT(PLLSEL);
+		control &= ~PM_BIT(PLLSEL);
 
-	sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index, control);
+	pm_writel(GCCTRL(clk->index), control);
 	clk->parent = parent;
 
 	return 0;
@@ -408,11 +447,11 @@
 
 	BUG_ON(clk->index > 7);
 
-	control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
-	if (control & SM_BIT(OSCSEL))
-		parent = (control & SM_BIT(PLLSEL)) ? &pll1 : &osc1;
+	control = pm_readl(GCCTRL(clk->index));
+	if (control & PM_BIT(OSCSEL))
+		parent = (control & PM_BIT(PLLSEL)) ? &pll1 : &osc1;
 	else
-		parent = (control & SM_BIT(PLLSEL)) ? &pll0 : &osc0;
+		parent = (control & PM_BIT(PLLSEL)) ? &pll0 : &osc0;
 
 	clk->parent = parent;
 }
@@ -420,21 +459,53 @@
 /* --------------------------------------------------------------------
  *  System peripherals
  * -------------------------------------------------------------------- */
-static struct resource sm_resource[] = {
-	PBMEM(0xfff00000),
-	NAMED_IRQ(19, "eim"),
-	NAMED_IRQ(20, "pm"),
-	NAMED_IRQ(21, "rtc"),
+static struct resource at32_pm0_resource[] = {
+	{
+		.start	= 0xfff00000,
+		.end	= 0xfff0007f,
+		.flags	= IORESOURCE_MEM,
+	},
+	IRQ(20),
 };
-struct platform_device at32_sm_device = {
-	.name		= "sm",
-	.id		= 0,
-	.resource	= sm_resource,
-	.num_resources	= ARRAY_SIZE(sm_resource),
+
+static struct resource at32ap700x_rtc0_resource[] = {
+	{
+		.start	= 0xfff00080,
+		.end	= 0xfff000af,
+		.flags	= IORESOURCE_MEM,
+	},
+	IRQ(21),
 };
-static struct clk at32_sm_pclk = {
+
+static struct resource at32_wdt0_resource[] = {
+	{
+		.start	= 0xfff000b0,
+		.end	= 0xfff000bf,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct resource at32_eic0_resource[] = {
+	{
+		.start	= 0xfff00100,
+		.end	= 0xfff0013f,
+		.flags	= IORESOURCE_MEM,
+	},
+	IRQ(19),
+};
+
+DEFINE_DEV(at32_pm, 0);
+DEFINE_DEV(at32ap700x_rtc, 0);
+DEFINE_DEV(at32_wdt, 0);
+DEFINE_DEV(at32_eic, 0);
+
+/*
+ * Peripheral clock for PM, RTC, WDT and EIC. PM will ensure that this
+ * is always running.
+ */
+static struct clk at32_pm_pclk = {
 	.name		= "pclk",
-	.dev		= &at32_sm_device.dev,
+	.dev		= &at32_pm0_device.dev,
 	.parent		= &pbb_clk,
 	.mode		= pbb_clk_mode,
 	.get_rate	= pbb_clk_get_rate,
@@ -583,10 +654,11 @@
 
 void __init at32_add_system_devices(void)
 {
-	system_manager.eim_first_irq = EIM_IRQ_BASE;
-
-	platform_device_register(&at32_sm_device);
+	platform_device_register(&at32_pm0_device);
 	platform_device_register(&at32_intc0_device);
+	platform_device_register(&at32ap700x_rtc0_device);
+	platform_device_register(&at32_wdt0_device);
+	platform_device_register(&at32_eic0_device);
 	platform_device_register(&smc0_device);
 	platform_device_register(&pdc_device);
 
@@ -1013,6 +1085,89 @@
 }
 
 /* --------------------------------------------------------------------
+ *  SSC
+ * -------------------------------------------------------------------- */
+static struct resource ssc0_resource[] = {
+	PBMEM(0xffe01c00),
+	IRQ(10),
+};
+DEFINE_DEV(ssc, 0);
+DEV_CLK(pclk, ssc0, pba, 7);
+
+static struct resource ssc1_resource[] = {
+	PBMEM(0xffe02000),
+	IRQ(11),
+};
+DEFINE_DEV(ssc, 1);
+DEV_CLK(pclk, ssc1, pba, 8);
+
+static struct resource ssc2_resource[] = {
+	PBMEM(0xffe02400),
+	IRQ(12),
+};
+DEFINE_DEV(ssc, 2);
+DEV_CLK(pclk, ssc2, pba, 9);
+
+struct platform_device *__init
+at32_add_device_ssc(unsigned int id, unsigned int flags)
+{
+	struct platform_device *pdev;
+
+	switch (id) {
+	case 0:
+		pdev = &ssc0_device;
+		if (flags & ATMEL_SSC_RF)
+			select_peripheral(PA(21), PERIPH_A, 0);	/* RF */
+		if (flags & ATMEL_SSC_RK)
+			select_peripheral(PA(22), PERIPH_A, 0);	/* RK */
+		if (flags & ATMEL_SSC_TK)
+			select_peripheral(PA(23), PERIPH_A, 0);	/* TK */
+		if (flags & ATMEL_SSC_TF)
+			select_peripheral(PA(24), PERIPH_A, 0);	/* TF */
+		if (flags & ATMEL_SSC_TD)
+			select_peripheral(PA(25), PERIPH_A, 0);	/* TD */
+		if (flags & ATMEL_SSC_RD)
+			select_peripheral(PA(26), PERIPH_A, 0);	/* RD */
+		break;
+	case 1:
+		pdev = &ssc1_device;
+		if (flags & ATMEL_SSC_RF)
+			select_peripheral(PA(0), PERIPH_B, 0);	/* RF */
+		if (flags & ATMEL_SSC_RK)
+			select_peripheral(PA(1), PERIPH_B, 0);	/* RK */
+		if (flags & ATMEL_SSC_TK)
+			select_peripheral(PA(2), PERIPH_B, 0);	/* TK */
+		if (flags & ATMEL_SSC_TF)
+			select_peripheral(PA(3), PERIPH_B, 0);	/* TF */
+		if (flags & ATMEL_SSC_TD)
+			select_peripheral(PA(4), PERIPH_B, 0);	/* TD */
+		if (flags & ATMEL_SSC_RD)
+			select_peripheral(PA(5), PERIPH_B, 0);	/* RD */
+		break;
+	case 2:
+		pdev = &ssc2_device;
+		if (flags & ATMEL_SSC_TD)
+			select_peripheral(PB(13), PERIPH_A, 0);	/* TD */
+		if (flags & ATMEL_SSC_RD)
+			select_peripheral(PB(14), PERIPH_A, 0);	/* RD */
+		if (flags & ATMEL_SSC_TK)
+			select_peripheral(PB(15), PERIPH_A, 0);	/* TK */
+		if (flags & ATMEL_SSC_TF)
+			select_peripheral(PB(16), PERIPH_A, 0);	/* TF */
+		if (flags & ATMEL_SSC_RF)
+			select_peripheral(PB(17), PERIPH_A, 0);	/* RF */
+		if (flags & ATMEL_SSC_RK)
+			select_peripheral(PB(18), PERIPH_A, 0);	/* RK */
+		break;
+	default:
+		return NULL;
+	}
+
+	platform_device_register(pdev);
+	return pdev;
+}
+
+/* --------------------------------------------------------------------
  *  GCLK
  * -------------------------------------------------------------------- */
 static struct clk gclk0 = {
@@ -1066,7 +1221,7 @@
 	&hsb_clk,
 	&pba_clk,
 	&pbb_clk,
-	&at32_sm_pclk,
+	&at32_pm_pclk,
 	&at32_intc0_pclk,
 	&hmatrix_clk,
 	&ebi_clk,
@@ -1094,6 +1249,9 @@
 	&atmel_spi1_spi_clk,
 	&atmel_lcdfb0_hck1,
 	&atmel_lcdfb0_pixclk,
+	&ssc0_pclk,
+	&ssc1_pclk,
+	&ssc2_pclk,
 	&gclk0,
 	&gclk1,
 	&gclk2,
@@ -1113,18 +1271,20 @@
 
 void __init at32_clock_init(void)
 {
-	struct at32_sm *sm = &system_manager;
 	u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0;
 	int i;
 
-	if (sm_readl(sm, PM_MCCTRL) & SM_BIT(PLLSEL))
+	if (pm_readl(MCCTRL) & PM_BIT(PLLSEL)) {
 		main_clock = &pll0;
-	else
+		cpu_clk.parent = &pll0;
+	} else {
 		main_clock = &osc0;
+		cpu_clk.parent = &osc0;
+	}
 
-	if (sm_readl(sm, PM_PLL0) & SM_BIT(PLLOSC))
+	if (pm_readl(PLL0) & PM_BIT(PLLOSC))
 		pll0.parent = &osc1;
-	if (sm_readl(sm, PM_PLL1) & SM_BIT(PLLOSC))
+	if (pm_readl(PLL1) & PM_BIT(PLLOSC))
 		pll1.parent = &osc1;
 
 	genclk_init_parent(&gclk0);
@@ -1157,8 +1317,8 @@
 			pbb_mask |= 1 << clk->index;
 	}
 
-	sm_writel(sm, PM_CPU_MASK, cpu_mask);
-	sm_writel(sm, PM_HSB_MASK, hsb_mask);
-	sm_writel(sm, PM_PBA_MASK, pba_mask);
-	sm_writel(sm, PM_PBB_MASK, pbb_mask);
+	pm_writel(CPU_MASK, cpu_mask);
+	pm_writel(HSB_MASK, hsb_mask);
+	pm_writel(PBA_MASK, pba_mask);
+	pm_writel(PBB_MASK, pbb_mask);
 }
diff --git a/arch/avr32/mach-at32ap/cpufreq.c b/arch/avr32/mach-at32ap/cpufreq.c
new file mode 100644
index 0000000..235524b
--- /dev/null
+++ b/arch/avr32/mach-at32ap/cpufreq.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2004-2007 Atmel Corporation
+ *
+ * Based on MIPS implementation arch/mips/kernel/time.c
+ *   Copyright 2001 MontaVista Software Inc.
+ *
+ * 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.
+ */
+
+/*#define DEBUG*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <asm/system.h>
+
+static struct clk *cpuclk;
+
+static int at32_verify_speed(struct cpufreq_policy *policy)
+{
+	if (policy->cpu != 0)
+		return -EINVAL;
+
+	cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+			policy->cpuinfo.max_freq);
+	return 0;
+}
+
+static unsigned int at32_get_speed(unsigned int cpu)
+{
+	/* No SMP support */
+	if (cpu)
+		return 0;
+	return (unsigned int)((clk_get_rate(cpuclk) + 500) / 1000);
+}
+
+static int at32_set_target(struct cpufreq_policy *policy,
+			  unsigned int target_freq,
+			  unsigned int relation)
+{
+	struct cpufreq_freqs freqs;
+	long freq;
+
+	/* Convert target_freq from kHz to Hz */
+	freq = clk_round_rate(cpuclk, target_freq * 1000);
+
+	/* Check if policy->min <= new_freq <= policy->max */
+	if(freq < (policy->min * 1000) || freq > (policy->max * 1000))
+		return -EINVAL;
+
+	pr_debug("cpufreq: requested frequency %u Hz\n", target_freq * 1000);
+
+	freqs.old = at32_get_speed(0);
+	freqs.new = (freq + 500) / 1000;
+	freqs.cpu = 0;
+	freqs.flags = 0;
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	clk_set_rate(cpuclk, freq);
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+	pr_debug("cpufreq: set frequency %lu Hz\n", freq);
+
+	return 0;
+}
+
+static int __init at32_cpufreq_driver_init(struct cpufreq_policy *policy)
+{
+	if (policy->cpu != 0)
+		return -EINVAL;
+
+	cpuclk = clk_get(NULL, "cpu");
+	if (IS_ERR(cpuclk)) {
+		pr_debug("cpufreq: could not get CPU clk\n");
+		return PTR_ERR(cpuclk);
+	}
+
+	policy->cpuinfo.min_freq = (clk_round_rate(cpuclk, 1) + 500) / 1000;
+	policy->cpuinfo.max_freq = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
+	policy->cpuinfo.transition_latency = 0;
+	policy->cur = at32_get_speed(0);
+	policy->min = policy->cpuinfo.min_freq;
+	policy->max = policy->cpuinfo.max_freq;
+	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+	printk("cpufreq: AT32AP CPU frequency driver\n");
+
+	return 0;
+}
+
+static struct cpufreq_driver at32_driver = {
+	.name		= "at32ap",
+	.owner		= THIS_MODULE,
+	.init		= at32_cpufreq_driver_init,
+	.verify		= at32_verify_speed,
+	.target		= at32_set_target,
+	.get		= at32_get_speed,
+	.flags		= CPUFREQ_STICKY,
+};
+
+static int __init at32_cpufreq_init(void)
+{
+	return cpufreq_register_driver(&at32_driver);
+}
+
+arch_initcall(at32_cpufreq_init);
diff --git a/arch/avr32/mach-at32ap/extint.c b/arch/avr32/mach-at32ap/extint.c
index 4a60ecc..8acd0109 100644
--- a/arch/avr32/mach-at32ap/extint.c
+++ b/arch/avr32/mach-at32ap/extint.c
@@ -17,42 +17,83 @@
 
 #include <asm/io.h>
 
-#include <asm/arch/sm.h>
+/* EIC register offsets */
+#define EIC_IER					0x0000
+#define EIC_IDR					0x0004
+#define EIC_IMR					0x0008
+#define EIC_ISR					0x000c
+#define EIC_ICR					0x0010
+#define EIC_MODE				0x0014
+#define EIC_EDGE				0x0018
+#define EIC_LEVEL				0x001c
+#define EIC_TEST				0x0020
+#define EIC_NMIC				0x0024
 
-#include "sm.h"
+/* Bitfields in TEST */
+#define EIC_TESTEN_OFFSET			31
+#define EIC_TESTEN_SIZE				1
 
-static void eim_ack_irq(unsigned int irq)
+/* Bitfields in NMIC */
+#define EIC_EN_OFFSET				0
+#define EIC_EN_SIZE				1
+
+/* Bit manipulation macros */
+#define EIC_BIT(name)					\
+	(1 << EIC_##name##_OFFSET)
+#define EIC_BF(name,value)				\
+	(((value) & ((1 << EIC_##name##_SIZE) - 1))	\
+	 << EIC_##name##_OFFSET)
+#define EIC_BFEXT(name,value)				\
+	(((value) >> EIC_##name##_OFFSET)		\
+	 & ((1 << EIC_##name##_SIZE) - 1))
+#define EIC_BFINS(name,value,old)			\
+	(((old) & ~(((1 << EIC_##name##_SIZE) - 1)	\
+		    << EIC_##name##_OFFSET))		\
+	 | EIC_BF(name,value))
+
+/* Register access macros */
+#define eic_readl(port,reg)				\
+	__raw_readl((port)->regs + EIC_##reg)
+#define eic_writel(port,reg,value)			\
+	__raw_writel((value), (port)->regs + EIC_##reg)
+
+struct eic {
+	void __iomem *regs;
+	struct irq_chip *chip;
+	unsigned int first_irq;
+};
+
+static void eic_ack_irq(unsigned int irq)
 {
-	struct at32_sm *sm = get_irq_chip_data(irq);
-	sm_writel(sm, EIM_ICR, 1 << (irq - sm->eim_first_irq));
+	struct eic *eic = get_irq_chip_data(irq);
+	eic_writel(eic, ICR, 1 << (irq - eic->first_irq));
 }
 
-static void eim_mask_irq(unsigned int irq)
+static void eic_mask_irq(unsigned int irq)
 {
-	struct at32_sm *sm = get_irq_chip_data(irq);
-	sm_writel(sm, EIM_IDR, 1 << (irq - sm->eim_first_irq));
+	struct eic *eic = get_irq_chip_data(irq);
+	eic_writel(eic, IDR, 1 << (irq - eic->first_irq));
 }
 
-static void eim_mask_ack_irq(unsigned int irq)
+static void eic_mask_ack_irq(unsigned int irq)
 {
-	struct at32_sm *sm = get_irq_chip_data(irq);
-	sm_writel(sm, EIM_ICR, 1 << (irq - sm->eim_first_irq));
-	sm_writel(sm, EIM_IDR, 1 << (irq - sm->eim_first_irq));
+	struct eic *eic = get_irq_chip_data(irq);
+	eic_writel(eic, ICR, 1 << (irq - eic->first_irq));
+	eic_writel(eic, IDR, 1 << (irq - eic->first_irq));
 }
 
-static void eim_unmask_irq(unsigned int irq)
+static void eic_unmask_irq(unsigned int irq)
 {
-	struct at32_sm *sm = get_irq_chip_data(irq);
-	sm_writel(sm, EIM_IER, 1 << (irq - sm->eim_first_irq));
+	struct eic *eic = get_irq_chip_data(irq);
+	eic_writel(eic, IER, 1 << (irq - eic->first_irq));
 }
 
-static int eim_set_irq_type(unsigned int irq, unsigned int flow_type)
+static int eic_set_irq_type(unsigned int irq, unsigned int flow_type)
 {
-	struct at32_sm *sm = get_irq_chip_data(irq);
+	struct eic *eic = get_irq_chip_data(irq);
 	struct irq_desc *desc;
-	unsigned int i = irq - sm->eim_first_irq;
+	unsigned int i = irq - eic->first_irq;
 	u32 mode, edge, level;
-	unsigned long flags;
 	int ret = 0;
 
 	flow_type &= IRQ_TYPE_SENSE_MASK;
@@ -60,11 +101,10 @@
 		flow_type = IRQ_TYPE_LEVEL_LOW;
 
 	desc = &irq_desc[irq];
-	spin_lock_irqsave(&sm->lock, flags);
 
-	mode = sm_readl(sm, EIM_MODE);
-	edge = sm_readl(sm, EIM_EDGE);
-	level = sm_readl(sm, EIM_LEVEL);
+	mode = eic_readl(eic, MODE);
+	edge = eic_readl(eic, EDGE);
+	level = eic_readl(eic, LEVEL);
 
 	switch (flow_type) {
 	case IRQ_TYPE_LEVEL_LOW:
@@ -89,9 +129,9 @@
 	}
 
 	if (ret == 0) {
-		sm_writel(sm, EIM_MODE, mode);
-		sm_writel(sm, EIM_EDGE, edge);
-		sm_writel(sm, EIM_LEVEL, level);
+		eic_writel(eic, MODE, mode);
+		eic_writel(eic, EDGE, edge);
+		eic_writel(eic, LEVEL, level);
 
 		if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
 			flow_type |= IRQ_LEVEL;
@@ -99,35 +139,33 @@
 		desc->status |= flow_type;
 	}
 
-	spin_unlock_irqrestore(&sm->lock, flags);
-
 	return ret;
 }
 
-struct irq_chip eim_chip = {
-	.name		= "eim",
-	.ack		= eim_ack_irq,
-	.mask		= eim_mask_irq,
-	.mask_ack	= eim_mask_ack_irq,
-	.unmask		= eim_unmask_irq,
-	.set_type	= eim_set_irq_type,
+struct irq_chip eic_chip = {
+	.name		= "eic",
+	.ack		= eic_ack_irq,
+	.mask		= eic_mask_irq,
+	.mask_ack	= eic_mask_ack_irq,
+	.unmask		= eic_unmask_irq,
+	.set_type	= eic_set_irq_type,
 };
 
-static void demux_eim_irq(unsigned int irq, struct irq_desc *desc)
+static void demux_eic_irq(unsigned int irq, struct irq_desc *desc)
 {
-	struct at32_sm *sm = desc->handler_data;
+	struct eic *eic = desc->handler_data;
 	struct irq_desc *ext_desc;
 	unsigned long status, pending;
 	unsigned int i, ext_irq;
 
-	status = sm_readl(sm, EIM_ISR);
-	pending = status & sm_readl(sm, EIM_IMR);
+	status = eic_readl(eic, ISR);
+	pending = status & eic_readl(eic, IMR);
 
 	while (pending) {
 		i = fls(pending) - 1;
 		pending &= ~(1 << i);
 
-		ext_irq = i + sm->eim_first_irq;
+		ext_irq = i + eic->first_irq;
 		ext_desc = irq_desc + ext_irq;
 		if (ext_desc->status & IRQ_LEVEL)
 			handle_level_irq(ext_irq, ext_desc);
@@ -136,51 +174,85 @@
 	}
 }
 
-static int __init eim_init(void)
+static int __init eic_probe(struct platform_device *pdev)
 {
-	struct at32_sm *sm = &system_manager;
+	struct eic *eic;
+	struct resource *regs;
 	unsigned int i;
 	unsigned int nr_irqs;
 	unsigned int int_irq;
+	int ret;
 	u32 pattern;
 
-	/*
-	 * The EIM is really the same module as SM, so register
-	 * mapping, etc. has been taken care of already.
-	 */
+	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	int_irq = platform_get_irq(pdev, 0);
+	if (!regs || !int_irq) {
+		dev_dbg(&pdev->dev, "missing regs and/or irq resource\n");
+		return -ENXIO;
+	}
+
+	ret = -ENOMEM;
+	eic = kzalloc(sizeof(struct eic), GFP_KERNEL);
+	if (!eic) {
+		dev_dbg(&pdev->dev, "no memory for eic structure\n");
+		goto err_kzalloc;
+	}
+
+	eic->first_irq = EIM_IRQ_BASE + 32 * pdev->id;
+	eic->regs = ioremap(regs->start, regs->end - regs->start + 1);
+	if (!eic->regs) {
+		dev_dbg(&pdev->dev, "failed to map regs\n");
+		goto err_ioremap;
+	}
 
 	/*
 	 * Find out how many interrupt lines that are actually
 	 * implemented in hardware.
 	 */
-	sm_writel(sm, EIM_IDR, ~0UL);
-	sm_writel(sm, EIM_MODE, ~0UL);
-	pattern = sm_readl(sm, EIM_MODE);
+	eic_writel(eic, IDR, ~0UL);
+	eic_writel(eic, MODE, ~0UL);
+	pattern = eic_readl(eic, MODE);
 	nr_irqs = fls(pattern);
 
 	/* Trigger on falling edge unless overridden by driver */
-	sm_writel(sm, EIM_MODE, 0UL);
-	sm_writel(sm, EIM_EDGE, 0UL);
+	eic_writel(eic, MODE, 0UL);
+	eic_writel(eic, EDGE, 0UL);
 
-	sm->eim_chip = &eim_chip;
+	eic->chip = &eic_chip;
 
 	for (i = 0; i < nr_irqs; i++) {
 		/* NOTE the handler we set here is ignored by the demux */
-		set_irq_chip_and_handler(sm->eim_first_irq + i, &eim_chip,
+		set_irq_chip_and_handler(eic->first_irq + i, &eic_chip,
 					 handle_level_irq);
-		set_irq_chip_data(sm->eim_first_irq + i, sm);
+		set_irq_chip_data(eic->first_irq + i, eic);
 	}
 
-	int_irq = platform_get_irq_byname(sm->pdev, "eim");
+	set_irq_chained_handler(int_irq, demux_eic_irq);
+	set_irq_data(int_irq, eic);
 
-	set_irq_chained_handler(int_irq, demux_eim_irq);
-	set_irq_data(int_irq, sm);
-
-	printk("EIM: External Interrupt Module at 0x%p, IRQ %u\n",
-	       sm->regs, int_irq);
-	printk("EIM: Handling %u external IRQs, starting with IRQ %u\n",
-	       nr_irqs, sm->eim_first_irq);
+	dev_info(&pdev->dev,
+		 "External Interrupt Controller at 0x%p, IRQ %u\n",
+		 eic->regs, int_irq);
+	dev_info(&pdev->dev,
+		 "Handling %u external IRQs, starting with IRQ %u\n",
+		 nr_irqs, eic->first_irq);
 
 	return 0;
+
+err_ioremap:
+	kfree(eic);
+err_kzalloc:
+	return ret;
 }
-arch_initcall(eim_init);
+
+static struct platform_driver eic_driver = {
+	.driver = {
+		.name = "at32_eic",
+	},
+};
+
+static int __init eic_init(void)
+{
+	return platform_driver_probe(&eic_driver, eic_probe);
+}
+arch_initcall(eic_init);
diff --git a/arch/avr32/mach-at32ap/pm.h b/arch/avr32/mach-at32ap/pm.h
new file mode 100644
index 0000000..a1f8ace
--- /dev/null
+++ b/arch/avr32/mach-at32ap/pm.h
@@ -0,0 +1,112 @@
+/*
+ * Register definitions for the Power Manager (PM)
+ */
+#ifndef __ARCH_AVR32_MACH_AT32AP_PM_H__
+#define __ARCH_AVR32_MACH_AT32AP_PM_H__
+
+/* PM register offsets */
+#define PM_MCCTRL				0x0000
+#define PM_CKSEL				0x0004
+#define PM_CPU_MASK				0x0008
+#define PM_HSB_MASK				0x000c
+#define PM_PBA_MASK				0x0010
+#define PM_PBB_MASK				0x0014
+#define PM_PLL0					0x0020
+#define PM_PLL1					0x0024
+#define PM_IER					0x0040
+#define PM_IDR					0x0044
+#define PM_IMR					0x0048
+#define PM_ISR					0x004c
+#define PM_ICR					0x0050
+#define PM_GCCTRL(x)				(0x0060 + 4 * (x))
+#define PM_RCAUSE				0x00c0
+
+/* Bitfields in CKSEL */
+#define PM_CPUSEL_OFFSET			0
+#define PM_CPUSEL_SIZE				3
+#define PM_CPUDIV_OFFSET			7
+#define PM_CPUDIV_SIZE				1
+#define PM_HSBSEL_OFFSET			8
+#define PM_HSBSEL_SIZE				3
+#define PM_HSBDIV_OFFSET			15
+#define PM_HSBDIV_SIZE				1
+#define PM_PBASEL_OFFSET			16
+#define PM_PBASEL_SIZE				3
+#define PM_PBADIV_OFFSET			23
+#define PM_PBADIV_SIZE				1
+#define PM_PBBSEL_OFFSET			24
+#define PM_PBBSEL_SIZE				3
+#define PM_PBBDIV_OFFSET			31
+#define PM_PBBDIV_SIZE				1
+
+/* Bitfields in PLL0 */
+#define PM_PLLEN_OFFSET				0
+#define PM_PLLEN_SIZE				1
+#define PM_PLLOSC_OFFSET			1
+#define PM_PLLOSC_SIZE				1
+#define PM_PLLOPT_OFFSET			2
+#define PM_PLLOPT_SIZE				3
+#define PM_PLLDIV_OFFSET			8
+#define PM_PLLDIV_SIZE				8
+#define PM_PLLMUL_OFFSET			16
+#define PM_PLLMUL_SIZE				8
+#define PM_PLLCOUNT_OFFSET			24
+#define PM_PLLCOUNT_SIZE			6
+#define PM_PLLTEST_OFFSET			31
+#define PM_PLLTEST_SIZE				1
+
+/* Bitfields in ICR */
+#define PM_LOCK0_OFFSET				0
+#define PM_LOCK0_SIZE				1
+#define PM_LOCK1_OFFSET				1
+#define PM_LOCK1_SIZE				1
+#define PM_WAKE_OFFSET				2
+#define PM_WAKE_SIZE				1
+#define PM_CKRDY_OFFSET				5
+#define PM_CKRDY_SIZE				1
+#define PM_MSKRDY_OFFSET			6
+#define PM_MSKRDY_SIZE				1
+
+/* Bitfields in GCCTRL0 */
+#define PM_OSCSEL_OFFSET			0
+#define PM_OSCSEL_SIZE				1
+#define PM_PLLSEL_OFFSET			1
+#define PM_PLLSEL_SIZE				1
+#define PM_CEN_OFFSET				2
+#define PM_CEN_SIZE				1
+#define PM_DIVEN_OFFSET				4
+#define PM_DIVEN_SIZE				1
+#define PM_DIV_OFFSET				8
+#define PM_DIV_SIZE				8
+
+/* Bitfields in RCAUSE */
+#define PM_POR_OFFSET				0
+#define PM_POR_SIZE				1
+#define PM_EXT_OFFSET				2
+#define PM_EXT_SIZE				1
+#define PM_WDT_OFFSET				3
+#define PM_WDT_SIZE				1
+#define PM_NTAE_OFFSET				4
+#define PM_NTAE_SIZE				1
+
+/* Bit manipulation macros */
+#define PM_BIT(name)					\
+	(1 << PM_##name##_OFFSET)
+#define PM_BF(name,value)				\
+	(((value) & ((1 << PM_##name##_SIZE) - 1))	\
+	 << PM_##name##_OFFSET)
+#define PM_BFEXT(name,value)				\
+	(((value) >> PM_##name##_OFFSET)		\
+	 & ((1 << PM_##name##_SIZE) - 1))
+#define PM_BFINS(name,value,old)\
+	(((old) & ~(((1 << PM_##name##_SIZE) - 1)	\
+		    << PM_##name##_OFFSET))		\
+	 | PM_BF(name,value))
+
+/* Register access macros */
+#define pm_readl(reg)							\
+	__raw_readl((void __iomem *)AT32_PM_BASE + PM_##reg)
+#define pm_writel(reg,value)						\
+	__raw_writel((value), (void __iomem *)AT32_PM_BASE + PM_##reg)
+
+#endif /* __ARCH_AVR32_MACH_AT32AP_PM_H__ */
diff --git a/arch/avr32/mach-at32ap/sm.h b/arch/avr32/mach-at32ap/sm.h
deleted file mode 100644
index cad02b5..0000000
--- a/arch/avr32/mach-at32ap/sm.h
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Register definitions for SM
- *
- * System Manager
- */
-#ifndef __ASM_AVR32_SM_H__
-#define __ASM_AVR32_SM_H__
-
-/* SM register offsets */
-#define SM_PM_MCCTRL                            0x0000
-#define SM_PM_CKSEL                             0x0004
-#define SM_PM_CPU_MASK                          0x0008
-#define SM_PM_HSB_MASK                          0x000c
-#define SM_PM_PBA_MASK                         0x0010
-#define SM_PM_PBB_MASK                         0x0014
-#define SM_PM_PLL0                              0x0020
-#define SM_PM_PLL1                              0x0024
-#define SM_PM_VCTRL                             0x0030
-#define SM_PM_VMREF                             0x0034
-#define SM_PM_VMV                               0x0038
-#define SM_PM_IER                               0x0040
-#define SM_PM_IDR                               0x0044
-#define SM_PM_IMR                               0x0048
-#define SM_PM_ISR                               0x004c
-#define SM_PM_ICR                               0x0050
-#define SM_PM_GCCTRL                            0x0060
-#define SM_RTC_CTRL                             0x0080
-#define SM_RTC_VAL                              0x0084
-#define SM_RTC_TOP                              0x0088
-#define SM_RTC_IER                              0x0090
-#define SM_RTC_IDR                              0x0094
-#define SM_RTC_IMR                              0x0098
-#define SM_RTC_ISR                              0x009c
-#define SM_RTC_ICR                              0x00a0
-#define SM_WDT_CTRL                             0x00b0
-#define SM_WDT_CLR                              0x00b4
-#define SM_WDT_EXT                              0x00b8
-#define SM_RC_RCAUSE                            0x00c0
-#define SM_EIM_IER                              0x0100
-#define SM_EIM_IDR                              0x0104
-#define SM_EIM_IMR                              0x0108
-#define SM_EIM_ISR                              0x010c
-#define SM_EIM_ICR                              0x0110
-#define SM_EIM_MODE                             0x0114
-#define SM_EIM_EDGE                             0x0118
-#define SM_EIM_LEVEL                            0x011c
-#define SM_EIM_TEST                             0x0120
-#define SM_EIM_NMIC                             0x0124
-
-/* Bitfields in PM_MCCTRL */
-
-/* Bitfields in PM_CKSEL */
-#define SM_CPUSEL_OFFSET                        0
-#define SM_CPUSEL_SIZE                          3
-#define SM_CPUDIV_OFFSET                        7
-#define SM_CPUDIV_SIZE                          1
-#define SM_HSBSEL_OFFSET                        8
-#define SM_HSBSEL_SIZE                          3
-#define SM_HSBDIV_OFFSET                        15
-#define SM_HSBDIV_SIZE                          1
-#define SM_PBASEL_OFFSET                       16
-#define SM_PBASEL_SIZE                         3
-#define SM_PBADIV_OFFSET                       23
-#define SM_PBADIV_SIZE                         1
-#define SM_PBBSEL_OFFSET                       24
-#define SM_PBBSEL_SIZE                         3
-#define SM_PBBDIV_OFFSET                       31
-#define SM_PBBDIV_SIZE                         1
-
-/* Bitfields in PM_CPU_MASK */
-
-/* Bitfields in PM_HSB_MASK */
-
-/* Bitfields in PM_PBA_MASK */
-
-/* Bitfields in PM_PBB_MASK */
-
-/* Bitfields in PM_PLL0 */
-#define SM_PLLEN_OFFSET                         0
-#define SM_PLLEN_SIZE                           1
-#define SM_PLLOSC_OFFSET                        1
-#define SM_PLLOSC_SIZE                          1
-#define SM_PLLOPT_OFFSET                        2
-#define SM_PLLOPT_SIZE                          3
-#define SM_PLLDIV_OFFSET                        8
-#define SM_PLLDIV_SIZE                          8
-#define SM_PLLMUL_OFFSET                        16
-#define SM_PLLMUL_SIZE                          8
-#define SM_PLLCOUNT_OFFSET                      24
-#define SM_PLLCOUNT_SIZE                        6
-#define SM_PLLTEST_OFFSET                       31
-#define SM_PLLTEST_SIZE                         1
-
-/* Bitfields in PM_PLL1 */
-
-/* Bitfields in PM_VCTRL */
-#define SM_VAUTO_OFFSET                         0
-#define SM_VAUTO_SIZE                           1
-#define SM_PM_VCTRL_VAL_OFFSET                  8
-#define SM_PM_VCTRL_VAL_SIZE                    7
-
-/* Bitfields in PM_VMREF */
-#define SM_REFSEL_OFFSET                        0
-#define SM_REFSEL_SIZE                          4
-
-/* Bitfields in PM_VMV */
-#define SM_PM_VMV_VAL_OFFSET                    0
-#define SM_PM_VMV_VAL_SIZE                      8
-
-/* Bitfields in PM_IER */
-
-/* Bitfields in PM_IDR */
-
-/* Bitfields in PM_IMR */
-
-/* Bitfields in PM_ISR */
-
-/* Bitfields in PM_ICR */
-#define SM_LOCK0_OFFSET                         0
-#define SM_LOCK0_SIZE                           1
-#define SM_LOCK1_OFFSET                         1
-#define SM_LOCK1_SIZE                           1
-#define SM_WAKE_OFFSET                          2
-#define SM_WAKE_SIZE                            1
-#define SM_VOK_OFFSET                           3
-#define SM_VOK_SIZE                             1
-#define SM_VMRDY_OFFSET                         4
-#define SM_VMRDY_SIZE                           1
-#define SM_CKRDY_OFFSET                         5
-#define SM_CKRDY_SIZE                           1
-
-/* Bitfields in PM_GCCTRL */
-#define SM_OSCSEL_OFFSET                        0
-#define SM_OSCSEL_SIZE                          1
-#define SM_PLLSEL_OFFSET                        1
-#define SM_PLLSEL_SIZE                          1
-#define SM_CEN_OFFSET                           2
-#define SM_CEN_SIZE                             1
-#define SM_CPC_OFFSET                           3
-#define SM_CPC_SIZE                             1
-#define SM_DIVEN_OFFSET                         4
-#define SM_DIVEN_SIZE                           1
-#define SM_DIV_OFFSET                           8
-#define SM_DIV_SIZE                             8
-
-/* Bitfields in RTC_CTRL */
-#define SM_PCLR_OFFSET                          1
-#define SM_PCLR_SIZE                            1
-#define SM_TOPEN_OFFSET                         2
-#define SM_TOPEN_SIZE                           1
-#define SM_CLKEN_OFFSET                         3
-#define SM_CLKEN_SIZE                           1
-#define SM_PSEL_OFFSET                          8
-#define SM_PSEL_SIZE                            16
-
-/* Bitfields in RTC_VAL */
-#define SM_RTC_VAL_VAL_OFFSET                   0
-#define SM_RTC_VAL_VAL_SIZE                     31
-
-/* Bitfields in RTC_TOP */
-#define SM_RTC_TOP_VAL_OFFSET                   0
-#define SM_RTC_TOP_VAL_SIZE                     32
-
-/* Bitfields in RTC_IER */
-
-/* Bitfields in RTC_IDR */
-
-/* Bitfields in RTC_IMR */
-
-/* Bitfields in RTC_ISR */
-
-/* Bitfields in RTC_ICR */
-#define SM_TOPI_OFFSET                          0
-#define SM_TOPI_SIZE                            1
-
-/* Bitfields in WDT_CTRL */
-#define SM_KEY_OFFSET                           24
-#define SM_KEY_SIZE                             8
-
-/* Bitfields in WDT_CLR */
-
-/* Bitfields in WDT_EXT */
-
-/* Bitfields in RC_RCAUSE */
-#define SM_POR_OFFSET                           0
-#define SM_POR_SIZE                             1
-#define SM_BOD_OFFSET                           1
-#define SM_BOD_SIZE                             1
-#define SM_EXT_OFFSET                           2
-#define SM_EXT_SIZE                             1
-#define SM_WDT_OFFSET                           3
-#define SM_WDT_SIZE                             1
-#define SM_NTAE_OFFSET                          4
-#define SM_NTAE_SIZE                            1
-#define SM_SERP_OFFSET                          5
-#define SM_SERP_SIZE                            1
-
-/* Bitfields in EIM_IER */
-
-/* Bitfields in EIM_IDR */
-
-/* Bitfields in EIM_IMR */
-
-/* Bitfields in EIM_ISR */
-
-/* Bitfields in EIM_ICR */
-
-/* Bitfields in EIM_MODE */
-
-/* Bitfields in EIM_EDGE */
-#define SM_INT0_OFFSET                          0
-#define SM_INT0_SIZE                            1
-#define SM_INT1_OFFSET                          1
-#define SM_INT1_SIZE                            1
-#define SM_INT2_OFFSET                          2
-#define SM_INT2_SIZE                            1
-#define SM_INT3_OFFSET                          3
-#define SM_INT3_SIZE                            1
-
-/* Bitfields in EIM_LEVEL */
-
-/* Bitfields in EIM_TEST */
-#define SM_TESTEN_OFFSET                        31
-#define SM_TESTEN_SIZE                          1
-
-/* Bitfields in EIM_NMIC */
-#define SM_EN_OFFSET                            0
-#define SM_EN_SIZE                              1
-
-/* Bit manipulation macros */
-#define SM_BIT(name)                            (1 << SM_##name##_OFFSET)
-#define SM_BF(name,value)                       (((value) & ((1 << SM_##name##_SIZE) - 1)) << SM_##name##_OFFSET)
-#define SM_BFEXT(name,value)                    (((value) >> SM_##name##_OFFSET) & ((1 << SM_##name##_SIZE) - 1))
-#define SM_BFINS(name,value,old)                (((old) & ~(((1 << SM_##name##_SIZE) - 1) << SM_##name##_OFFSET)) | SM_BF(name,value))
-
-/* Register access macros */
-#define sm_readl(port,reg)					\
-	__raw_readl((port)->regs + SM_##reg)
-#define sm_writel(port,reg,value)				\
-	__raw_writel((value), (port)->regs + SM_##reg)
-
-#endif /* __ASM_AVR32_SM_H__ */
diff --git a/include/asm-avr32/arch-at32ap/board.h b/include/asm-avr32/arch-at32ap/board.h
index 9744804..0215965 100644
--- a/include/asm-avr32/arch-at32ap/board.h
+++ b/include/asm-avr32/arch-at32ap/board.h
@@ -36,4 +36,18 @@
 at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
 		     unsigned long fbmem_start, unsigned long fbmem_len);
 
+/* depending on what's hooked up, not all SSC pins will be used */
+#define	ATMEL_SSC_TK		0x01
+#define	ATMEL_SSC_TF		0x02
+#define	ATMEL_SSC_TD		0x04
+#define	ATMEL_SSC_TX		(ATMEL_SSC_TK | ATMEL_SSC_TF | ATMEL_SSC_TD)
+
+#define	ATMEL_SSC_RK		0x10
+#define	ATMEL_SSC_RF		0x20
+#define	ATMEL_SSC_RD		0x40
+#define	ATMEL_SSC_RX		(ATMEL_SSC_RK | ATMEL_SSC_RF | ATMEL_SSC_RD)
+
+struct platform_device *
+at32_add_device_ssc(unsigned int id, unsigned int flags);
+
 #endif /* __ASM_ARCH_BOARD_H */
diff --git a/include/asm-avr32/arch-at32ap/sm.h b/include/asm-avr32/arch-at32ap/sm.h
deleted file mode 100644
index 265a9ea..0000000
--- a/include/asm-avr32/arch-at32ap/sm.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * AT32 System Manager interface.
- *
- * Copyright (C) 2006 Atmel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#ifndef __ASM_AVR32_AT32_SM_H__
-#define __ASM_AVR32_AT32_SM_H__
-
-struct irq_chip;
-struct platform_device;
-
-struct at32_sm {
-	spinlock_t lock;
-	void __iomem *regs;
-	struct irq_chip *eim_chip;
-	unsigned int eim_first_irq;
-	struct platform_device *pdev;
-};
-
-extern struct platform_device at32_sm_device;
-extern struct at32_sm system_manager;
-
-#endif /* __ASM_AVR32_AT32_SM_H__ */
diff --git a/include/asm-avr32/atomic.h b/include/asm-avr32/atomic.h
index b9c2548..7ef3862 100644
--- a/include/asm-avr32/atomic.h
+++ b/include/asm-avr32/atomic.h
@@ -101,7 +101,7 @@
 		"	mov	%1, 1\n"
 		"1:"
 		: "=&r"(tmp), "=&r"(result), "=o"(v->counter)
-		: "m"(v->counter), "rKs21"(a), "rKs21"(u)
+		: "m"(v->counter), "rKs21"(a), "rKs21"(u), "1"(result)
 		: "cc", "memory");
 
 	return result;
@@ -137,7 +137,7 @@
 			"	mov	%1, 1\n"
 			"1:"
 			: "=&r"(tmp), "=&r"(result), "=o"(v->counter)
-			: "m"(v->counter), "r"(a), "ir"(u)
+			: "m"(v->counter), "r"(a), "ir"(u), "1"(result)
 			: "cc", "memory");
 	}
 
diff --git a/include/asm-avr32/unaligned.h b/include/asm-avr32/unaligned.h
index 3042723..36f5fd4 100644
--- a/include/asm-avr32/unaligned.h
+++ b/include/asm-avr32/unaligned.h
@@ -7,19 +7,10 @@
  * words, but halfwords must be halfword-aligned, and doublewords must
  * be word-aligned.
  *
- * TODO: Make all this CPU-specific and optimize.
+ * However, swapped word loads must be word-aligned so we can't
+ * optimize word loads in general.
  */
 
-#include <linux/string.h>
-
-/* Use memmove here, so gcc does not insert a __builtin_memcpy. */
-
-#define get_unaligned(ptr) \
-  ({ __typeof__(*(ptr)) __tmp; memmove(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })
-
-#define put_unaligned(val, ptr)				\
-  ({ __typeof__(*(ptr)) __tmp = (val);			\
-     memmove((ptr), &__tmp, sizeof(*(ptr)));		\
-     (void)0; })
+#include <asm-generic/unaligned.h>
 
 #endif /* __ASM_AVR32_UNALIGNED_H */