diff --git a/MAINTAINERS b/MAINTAINERS
index 277877a..a5bdfa6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1434,6 +1434,11 @@ L:	linux-scsi@vger.kernel.org
 W:	http://www.icp-vortex.com/
 S:	Supported
 
+GENERIC GPIO I2C DRIVER
+P:	Haavard Skinnemoen
+M:	hskinnemoen@atmel.com
+S:	Supported
+
 GENERIC HDLC DRIVER, N2, C101, PCI200SYN and WANXL DRIVERS
 P:	Krzysztof Halasa
 M:	khc@pm.waw.pl
diff --git a/Makefile b/Makefile
index 7980f39..388b666 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 21
-EXTRAVERSION = .3
+EXTRAVERSION = .3.atmel.1
 NAME = Nocturnal Monster Puppy
 
 # *DOCUMENTATION*
diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig
index ce4013a..3956118 100644
--- a/arch/avr32/Kconfig
+++ b/arch/avr32/Kconfig
@@ -57,9 +57,6 @@ config ARCH_HAS_ILOG2_U64
 	bool
 	default n
 
-config GENERIC_BUST_SPINLOCK
-	bool
-
 config GENERIC_HWEIGHT
 	bool
 	default y
@@ -68,6 +65,11 @@ config GENERIC_CALIBRATE_DELAY
 	bool
 	default y
 
+config GENERIC_BUG
+	bool
+	default y
+	depends on BUG
+
 source "init/Kconfig"
 
 menu "System Type and features"
@@ -106,6 +108,9 @@ choice
 config BOARD_ATSTK1000
 	bool "ATSTK1000 evaluation board"
 	select BOARD_ATSTK1002 if CPU_AT32AP7000
+
+config BOARD_ATNGW100
+	bool "ATNGW100 Network Gateway"
 endchoice
 
 choice
@@ -116,6 +121,8 @@ config	LOADER_U_BOOT
 	bool "U-Boot (or similar) bootloader"
 endchoice
 
+source "arch/avr32/mach-at32ap/Kconfig"
+
 config LOAD_ADDRESS
 	hex
 	default 0x10000000 if LOADER_U_BOOT=y && CPU_AT32AP7000=y
@@ -164,6 +171,10 @@ config OWNERSHIP_TRACE
 	  enabling Nexus-compliant debuggers to keep track of the PID of the
 	  currently executing task.
 
+config DW_DMAC
+	tristate "Synopsys DesignWare DMA Controller support"
+	default y if CPU_AT32AP7000
+
 # FPU emulation goes here
 
 source "kernel/Kconfig.hz"
diff --git a/arch/avr32/Makefile b/arch/avr32/Makefile
index 7b842e9..eb72198 100644
--- a/arch/avr32/Makefile
+++ b/arch/avr32/Makefile
@@ -16,7 +16,7 @@ AFLAGS		+= -mrelax -mno-pic
 CFLAGS_MODULE	+= -mno-relax
 LDFLAGS_vmlinux	+= --relax
 
-cpuflags-$(CONFIG_CPU_AP7000)	+= -mcpu=ap7000
+cpuflags-$(CONFIG_CPU_AT32AP7000)	+= -mcpu=ap7000
 
 CFLAGS		+= $(cpuflags-y)
 AFLAGS		+= $(cpuflags-y)
@@ -27,9 +27,11 @@ head-$(CONFIG_LOADER_U_BOOT)		+= arch/avr32/boot/u-boot/head.o
 head-y					+= arch/avr32/kernel/head.o
 core-$(CONFIG_PLATFORM_AT32AP)		+= arch/avr32/mach-at32ap/
 core-$(CONFIG_BOARD_ATSTK1000)		+= arch/avr32/boards/atstk1000/
+core-$(CONFIG_BOARD_ATNGW100)		+= arch/avr32/boards/atngw100/
 core-$(CONFIG_LOADER_U_BOOT)		+= arch/avr32/boot/u-boot/
 core-y					+= arch/avr32/kernel/
 core-y					+= arch/avr32/mm/
+drivers-y				+= arch/avr32/drivers/
 libs-y					+= arch/avr32/lib/
 
 archincdir-$(CONFIG_PLATFORM_AT32AP)	:= arch-at32ap
diff --git a/arch/avr32/boards/atngw100/Makefile b/arch/avr32/boards/atngw100/Makefile
new file mode 100644
index 0000000..c740aa1
--- /dev/null
+++ b/arch/avr32/boards/atngw100/Makefile
@@ -0,0 +1 @@
+obj-y				+= setup.o flash.o
diff --git a/arch/avr32/boards/atngw100/flash.c b/arch/avr32/boards/atngw100/flash.c
new file mode 100644
index 0000000..f9b32a8
--- /dev/null
+++ b/arch/avr32/boards/atngw100/flash.c
@@ -0,0 +1,95 @@
+/*
+ * ATNGW100 board-specific flash initialization
+ *
+ * Copyright (C) 2005-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.
+ */
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+
+#include <asm/arch/smc.h>
+
+static struct smc_config flash_config __initdata = {
+	.ncs_read_setup		= 0,
+	.nrd_setup		= 40,
+	.ncs_write_setup	= 0,
+	.nwe_setup		= 10,
+
+	.ncs_read_pulse		= 80,
+	.nrd_pulse		= 40,
+	.ncs_write_pulse	= 65,
+	.nwe_pulse		= 55,
+
+	.read_cycle		= 120,
+	.write_cycle		= 120,
+
+	.bus_width		= 2,
+	.nrd_controlled		= 1,
+	.nwe_controlled		= 1,
+	.byte_write		= 1,
+};
+
+static struct mtd_partition flash_parts[] = {
+	{
+		.name           = "u-boot",
+		.offset         = 0x00000000,
+		.size           = 0x00020000,           /* 128 KiB */
+		.mask_flags     = MTD_WRITEABLE,
+	},
+	{
+		.name           = "root",
+		.offset         = 0x00020000,
+		.size           = 0x007d0000,
+	},
+	{
+		.name           = "env",
+		.offset         = 0x007f0000,
+		.size           = 0x00010000,
+		.mask_flags     = MTD_WRITEABLE,
+	},
+};
+
+static struct physmap_flash_data flash_data = {
+	.width		= 2,
+	.nr_parts	= ARRAY_SIZE(flash_parts),
+	.parts		= flash_parts,
+};
+
+static struct resource flash_resource = {
+	.start		= 0x00000000,
+	.end		= 0x007fffff,
+	.flags		= IORESOURCE_MEM,
+};
+
+static struct platform_device flash_device = {
+	.name		= "physmap-flash",
+	.id		= 0,
+	.resource	= &flash_resource,
+	.num_resources	= 1,
+	.dev		= {
+		.platform_data = &flash_data,
+	},
+};
+
+/* This needs to be called after the SMC has been initialized */
+static int __init atngw100_flash_init(void)
+{
+	int ret;
+
+	ret = smc_set_configuration(0, &flash_config);
+	if (ret < 0) {
+		printk(KERN_ERR "atngw100: failed to set NOR flash timing\n");
+		return ret;
+	}
+
+	platform_device_register(&flash_device);
+
+	return 0;
+}
+device_initcall(atngw100_flash_init);
diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c
new file mode 100644
index 0000000..3cbdc2d
--- /dev/null
+++ b/arch/avr32/boards/atngw100/setup.c
@@ -0,0 +1,131 @@
+/*
+ * Board-specific setup code for the ATNGW100 Network Gateway
+ *
+ * Copyright (C) 2005-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.
+ */
+#include <linux/clk.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/spi/spi.h>
+
+#include <asm/io.h>
+#include <asm/setup.h>
+
+#include <asm/arch/at32ap7000.h>
+#include <asm/arch/board.h>
+#include <asm/arch/init.h>
+
+/* Initialized by bootloader-specific startup code. */
+struct tag *bootloader_tags __initdata;
+
+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 spi_board_info spi0_board_info[] __initdata = {
+	{
+		.modalias	= "mtd_dataflash",
+		.max_speed_hz	= 10000000,
+		.chip_select	= 0,
+	},
+};
+
+static struct mci_platform_data __initdata mci0_data = {
+	.detect_pin	= GPIO_PIN_PC(25),
+	.wp_pin		= GPIO_PIN_PE(0),
+};
+
+/*
+ * The next two functions should go away as the boot loader is
+ * supposed to initialize the macb address registers with a valid
+ * ethernet address. But we need to keep it around for a while until
+ * we can be reasonably sure the boot loader does this.
+ *
+ * The phy_id is ignored as the driver will probe for it.
+ */
+static int __init parse_tag_ethernet(struct tag *tag)
+{
+	int i;
+
+	i = tag->u.ethernet.mac_index;
+	if (i < ARRAY_SIZE(hw_addr))
+		memcpy(hw_addr[i].addr, tag->u.ethernet.hw_address,
+		       sizeof(hw_addr[i].addr));
+
+	return 0;
+}
+__tagtable(ATAG_ETHERNET, parse_tag_ethernet);
+
+static void __init set_hw_addr(struct platform_device *pdev)
+{
+	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	const u8 *addr;
+	void __iomem *regs;
+	struct clk *pclk;
+
+	if (!res)
+		return;
+	if (pdev->id >= ARRAY_SIZE(hw_addr))
+		return;
+
+	addr = hw_addr[pdev->id].addr;
+	if (!is_valid_ether_addr(addr))
+		return;
+
+	/*
+	 * Since this is board-specific code, we'll cheat and use the
+	 * physical address directly as we happen to know that it's
+	 * the same as the virtual address.
+	 */
+	regs = (void __iomem __force *)res->start;
+	pclk = clk_get(&pdev->dev, "pclk");
+	if (!pclk)
+		return;
+
+	clk_enable(pclk);
+	__raw_writel((addr[3] << 24) | (addr[2] << 16)
+		     | (addr[1] << 8) | addr[0], regs + 0x98);
+	__raw_writel((addr[5] << 8) | addr[4], regs + 0x9c);
+	clk_disable(pclk);
+	clk_put(pclk);
+}
+
+struct platform_device *at32_usart_map[1];
+unsigned int at32_nr_usarts = 1;
+
+void __init setup_board(void)
+{
+	at32_map_usart(1, 0);	/* USART 1: /dev/ttyS0, DB9 */
+	at32_setup_serial_console(0);
+}
+
+static int __init atngw100_init(void)
+{
+	/*
+	 * ATNGW100 uses 16-bit SDRAM interface, so we don't need to
+	 * reserve any pins for it.
+	 */
+
+	at32_add_system_devices();
+
+	at32_add_device_usart(0);
+
+	set_hw_addr(at32_add_device_eth(0, &eth_data[0]));
+	set_hw_addr(at32_add_device_eth(1, &eth_data[1]));
+
+	at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
+	at32_add_device_mci(0, &mci0_data);
+	at32_add_device_usba(0);
+
+	return 0;
+}
+postcore_initcall(atngw100_init);
diff --git a/arch/avr32/boards/atstk1000/atstk1000.h b/arch/avr32/boards/atstk1000/atstk1000.h
new file mode 100644
index 0000000..9a49ed0
--- /dev/null
+++ b/arch/avr32/boards/atstk1000/atstk1000.h
@@ -0,0 +1,15 @@
+/*
+ * ATSTK1000 setup code: Daughterboard interface
+ *
+ * Copyright (C) 2007 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 __ARCH_AVR32_BOARDS_ATSTK1000_ATSTK1000_H
+#define __ARCH_AVR32_BOARDS_ATSTK1000_ATSTK1000_H
+
+extern struct atmel_lcdfb_info atstk1000_lcdc_data;
+
+#endif /* __ARCH_AVR32_BOARDS_ATSTK1000_ATSTK1000_H */
diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c
index 5974768..84c22b2 100644
--- a/arch/avr32/boards/atstk1000/atstk1002.c
+++ b/arch/avr32/boards/atstk1000/atstk1002.c
@@ -14,7 +14,12 @@
 #include <linux/platform_device.h>
 #include <linux/string.h>
 #include <linux/types.h>
+
 #include <linux/spi/spi.h>
+#include <linux/spi/at73c213.h>
+#include <linux/gpio_mouse.h>
+
+#include <video/atmel_lcdc.h>
 
 #include <asm/io.h>
 #include <asm/setup.h>
@@ -23,6 +28,7 @@
 #include <asm/arch/init.h>
 #include <asm/arch/portmux.h>
 
+#include "atstk1000.h"
 
 #define	SW2_DEFAULT		/* MMCI and UART_A available */
 
@@ -31,19 +37,82 @@ struct eth_addr {
 };
 
 static struct eth_addr __initdata hw_addr[2];
-
 static struct eth_platform_data __initdata eth_data[2];
-extern struct lcdc_platform_data atstk1000_fb0_data;
+
+static struct at73c213_board_info at73c213_data = {
+	.dac_clk	= "gclk0",
+	.i2s_dev	= 0,
+	.shortname	= "AVR32 STK1000 external DAC",
+};
+
+static struct cf_platform_data __initdata cf0_data = {
+	.detect_pin	= GPIO_PIN_PB(15),
+	.reset_pin	= GPIO_PIN_PB(30),
+};
 
 static struct spi_board_info spi0_board_info[] __initdata = {
 	{
+		/* AT73C213 */
+		.modalias	= "at73c213",
+		.max_speed_hz	= 200000,
+		.chip_select	= 0,
+		.mode		= SPI_MODE_1,
+		.platform_data	= &at73c213_data,
+	},
+	{
 		/* QVGA display */
 		.modalias	= "ltv350qv",
 		.max_speed_hz	= 16000000,
 		.chip_select	= 1,
+		.mode		= SPI_MODE_3,
 	},
 };
 
+static struct mci_platform_data __initdata mci0_data = {
+	.detect_pin	= GPIO_PIN_NONE,
+	.wp_pin		= GPIO_PIN_NONE,
+};
+
+/* The next two structs and functions are for adding gpio_mouse
+ * support to the board
+ */
+static struct gpio_mouse_platform_data gpio_mouse0_data = {
+	.polarity	= GPIO_MOUSE_POLARITY_ACT_LOW,
+	.up		= GPIO_PIN_PB(2),
+	.down		= GPIO_PIN_PB(1),
+	.left		= GPIO_PIN_PB(3),
+	.right		= GPIO_PIN_PB(0),
+	.bleft		= GPIO_PIN_PB(7),
+	.bmiddle	= GPIO_PIN_PB(6),
+	.bright		= GPIO_PIN_PB(5),
+	.scan_ms	= 10,
+};
+
+static struct platform_device gpio_mouse0_device = {
+	.name		= "gpio_mouse",
+	.id		= 0,
+	.dev		= {
+		.platform_data = &gpio_mouse0_data,
+	},
+};
+
+static void __init add_device_gpio_mouse0(void)
+{
+	struct platform_device *pdev = &gpio_mouse0_device;
+	struct gpio_mouse_platform_data *data = pdev->dev.platform_data;
+
+	at32_select_gpio(data->up, 0);
+	at32_select_gpio(data->down, 0);
+	at32_select_gpio(data->left, 0);
+	at32_select_gpio(data->right, 0);
+
+	at32_select_gpio(data->bleft, 0);
+	at32_select_gpio(data->bmiddle, 0);
+	at32_select_gpio(data->bright, 0);
+
+	platform_device_register(pdev);
+}
+
 /*
  * The next two functions should go away as the boot loader is
  * supposed to initialize the macb address registers with a valid
@@ -99,6 +168,29 @@ static void __init set_hw_addr(struct platform_device *pdev)
 	clk_put(pclk);
 }
 
+static void __init set_at73c213_init_gclk(struct at73c213_board_info *info)
+{
+	struct clk *gclk = clk_get(NULL, info->dac_clk);
+	struct clk *pll = clk_get(NULL, "pll0");
+
+	if (!IS_ERR(gclk) && !IS_ERR(pll)) {
+		if(clk_set_parent(gclk, pll) != 0)
+			goto cleanup;
+	} else {
+		goto cleanup;
+	}
+
+	at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
+	return;
+
+cleanup:
+	if(!IS_ERR(gclk))
+		clk_put(gclk);
+	if(!IS_ERR(pll))
+		clk_put(pll);
+	return;
+}
+
 void __init setup_board(void)
 {
 #ifdef	SW2_DEFAULT
@@ -148,7 +240,18 @@ static int __init atstk1002_init(void)
 	set_hw_addr(at32_add_device_eth(0, &eth_data[0]));
 
 	at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
-	at32_add_device_lcdc(0, &atstk1000_fb0_data);
+	at32_add_device_twi(0);
+	at32_add_device_mci(0, &mci0_data);
+	at32_add_device_lcdc(0, &atstk1000_lcdc_data,
+			     fbmem_start, fbmem_size);
+	at32_add_device_usba(0);
+	at32_add_device_ssc(0, ATMEL_SSC_TX);
+	at32_add_device_abdac(0);
+	at32_add_device_cf(0, 3, &cf0_data);
+
+	set_at73c213_init_gclk(&at73c213_data);
+
+	add_device_gpio_mouse0();
 
 	return 0;
 }
diff --git a/arch/avr32/boards/atstk1000/setup.c b/arch/avr32/boards/atstk1000/setup.c
index 272c011..c9af409 100644
--- a/arch/avr32/boards/atstk1000/setup.c
+++ b/arch/avr32/boards/atstk1000/setup.c
@@ -8,43 +8,56 @@
  * published by the Free Software Foundation.
  */
 #include <linux/bootmem.h>
+#include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/linkage.h>
 
-#include <asm/setup.h>
+#include <video/atmel_lcdc.h>
 
+#include <asm/setup.h>
 #include <asm/arch/board.h>
 
+#include "atstk1000.h"
+
 /* Initialized by bootloader-specific startup code. */
 struct tag *bootloader_tags __initdata;
 
-struct lcdc_platform_data __initdata atstk1000_fb0_data;
-
-void __init board_setup_fbmem(unsigned long fbmem_start,
-			      unsigned long fbmem_size)
-{
-	if (!fbmem_size)
-		return;
-
-	if (!fbmem_start) {
-		void *fbmem;
-
-		fbmem = alloc_bootmem_low_pages(fbmem_size);
-		fbmem_start = __pa(fbmem);
-	} else {
-		pg_data_t *pgdat;
-
-		for_each_online_pgdat(pgdat) {
-			if (fbmem_start >= pgdat->bdata->node_boot_start
-			    && fbmem_start <= pgdat->bdata->node_low_pfn)
-				reserve_bootmem_node(pgdat, fbmem_start,
-						     fbmem_size);
-		}
-	}
-
-	printk("%luKiB framebuffer memory at address 0x%08lx\n",
-	       fbmem_size >> 10, fbmem_start);
-	atstk1000_fb0_data.fbmem_start = fbmem_start;
-	atstk1000_fb0_data.fbmem_size = fbmem_size;
-}
+static struct fb_videomode __initdata ltv350qv_modes[] = {
+	{
+		.name		= "320x240 @ 75",
+		.refresh	= 75,
+		.xres		= 320,		.yres		= 240,
+		.pixclock	= KHZ2PICOS(6891),
+
+		.left_margin	= 17,		.right_margin	= 33,
+		.upper_margin	= 10,		.lower_margin	= 10,
+		.hsync_len	= 16,		.vsync_len	= 1,
+
+		.sync		= 0,
+		.vmode		= FB_VMODE_NONINTERLACED,
+	},
+};
+
+static struct fb_monspecs __initdata atstk1000_default_monspecs = {
+	.manufacturer		= "SNG",
+	.monitor		= "LTV350QV",
+	.modedb			= ltv350qv_modes,
+	.modedb_len		= ARRAY_SIZE(ltv350qv_modes),
+	.hfmin			= 14820,
+	.hfmax			= 22230,
+	.vfmin			= 60,
+	.vfmax			= 90,
+	.dclkmax		= 30000000,
+};
+
+struct atmel_lcdfb_info __initdata atstk1000_lcdc_data = {
+	.default_bpp		= 24,
+	.default_dmacon		= ATMEL_LCDC_DMAEN | ATMEL_LCDC_DMA2DEN,
+	.default_lcdcon2	= (ATMEL_LCDC_DISTYPE_TFT
+				   | ATMEL_LCDC_INVCLK
+				   | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE
+				   | ATMEL_LCDC_MEMOR_BIG),
+	.default_monspecs	= &atstk1000_default_monspecs,
+	.guard_time		= 2,
+};
diff --git a/arch/avr32/configs/atngw100_defconfig b/arch/avr32/configs/atngw100_defconfig
new file mode 100644
index 0000000..c254ffc
--- /dev/null
+++ b/arch/avr32/configs/atngw100_defconfig
@@ -0,0 +1,1085 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21-rc6
+# Thu Apr 12 16:35:07 2007
+#
+CONFIG_AVR32=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_TIME=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+# CONFIG_BASE_FULL is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=1
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+
+#
+# System Type and features
+#
+CONFIG_SUBARCH_AVR32B=y
+CONFIG_MMU=y
+CONFIG_PERFORMANCE_COUNTERS=y
+CONFIG_PLATFORM_AT32AP=y
+CONFIG_CPU_AT32AP7000=y
+# CONFIG_BOARD_ATSTK1000 is not set
+CONFIG_BOARD_ATNGW100=y
+CONFIG_LOADER_U_BOOT=y
+
+#
+# Atmel AVR32 AP options
+#
+# CONFIG_AP7000_32_BIT_SMC is not set
+CONFIG_AP7000_16_BIT_SMC=y
+# CONFIG_AP7000_8_BIT_SMC is not set
+CONFIG_LOAD_ADDRESS=0x10000000
+CONFIG_ENTRY_ADDRESS=0x90000000
+CONFIG_PHYS_OFFSET=0x10000000
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_HAVE_ARCH_BOOTMEM_NODE is not set
+# CONFIG_ARCH_HAVE_MEMORY_PRESENT is not set
+# CONFIG_NEED_NODE_MEMMAP_SIZE is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+# CONFIG_ARCH_SPARSEMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+# CONFIG_OWNERSHIP_TRACE is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_CMDLINE=""
+
+#
+# Bus options
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_MULTIPLE_TABLES is not set
+# CONFIG_IP_ROUTE_MULTIPATH is not set
+# CONFIG_IP_ROUTE_VERBOSE is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+# CONFIG_IP_PIMSM_V2 is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+CONFIG_INET_XFRM_TUNNEL=y
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+# CONFIG_IPV6_MIP6 is not set
+CONFIG_INET6_XFRM_TUNNEL=y
+CONFIG_INET6_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+CONFIG_NF_CONNTRACK_ENABLED=m
+CONFIG_NF_CONNTRACK_SUPPORT=y
+# CONFIG_IP_NF_CONNTRACK_SUPPORT is not set
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CT_ACCT=y
+CONFIG_NF_CONNTRACK_MARK=y
+# CONFIG_NF_CONNTRACK_EVENTS is not set
+CONFIG_NF_CT_PROTO_GRE=m
+# CONFIG_NF_CT_PROTO_SCTP is not set
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NETFILTER_XTABLES=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+# CONFIG_IP_NF_TARGET_ULOG is not set
+CONFIG_NF_NAT=m
+CONFIG_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_NF_NAT_SNMP_BASIC=m
+CONFIG_NF_NAT_PROTO_GRE=m
+CONFIG_NF_NAT_FTP=m
+CONFIG_NF_NAT_IRC=m
+CONFIG_NF_NAT_TFTP=m
+CONFIG_NF_NAT_AMANDA=m
+CONFIG_NF_NAT_PPTP=m
+CONFIG_NF_NAT_H323=m
+CONFIG_NF_NAT_SIP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_RAW=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+CONFIG_VLAN_8021Q=m
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+CONFIG_NET_CLS_ROUTE=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0x80000000
+CONFIG_MTD_PHYSMAP_LEN=0x0
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+CONFIG_MTD_DATAFLASH=y
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=m
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_MACB=y
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+# CONFIG_SLIP is not set
+CONFIG_SLHC=m
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_ATMEL=y
+# CONFIG_SPI_BITBANG is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=850
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+CONFIG_CONFIGFS_FS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=y
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=y
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_FORCED_INLINING is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_KPROBES is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=y
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+CONFIG_CRYPTO_ARC4=m
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
diff --git a/arch/avr32/drivers/Makefile b/arch/avr32/drivers/Makefile
new file mode 100644
index 0000000..b429b75
--- /dev/null
+++ b/arch/avr32/drivers/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_DW_DMAC)			+= dw-dmac.o
diff --git a/arch/avr32/drivers/dw-dmac.c b/arch/avr32/drivers/dw-dmac.c
new file mode 100644
index 0000000..9c1d27a
--- /dev/null
+++ b/arch/avr32/drivers/dw-dmac.c
@@ -0,0 +1,761 @@
+/*
+ * Driver for the Synopsys DesignWare DMA Controller
+ *
+ * Copyright (C) 2005-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.
+ */
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/dma-controller.h>
+#include <asm/io.h>
+
+#include "dw-dmac.h"
+
+#define DMAC_NR_CHANNELS 3
+#define DMAC_MAX_BLOCKSIZE 4095
+
+enum {
+	CH_STATE_FREE = 0,
+	CH_STATE_ALLOCATED,
+	CH_STATE_BUSY,
+};
+
+struct dw_dma_lli {
+	dma_addr_t	sar;
+	dma_addr_t	dar;
+	dma_addr_t	llp;
+	u32		ctllo;
+	u32		ctlhi;
+	u32		sstat;
+	u32		dstat;
+};
+
+struct dw_dma_block {
+	struct dw_dma_lli *lli_vaddr;
+	dma_addr_t lli_dma_addr;
+};
+
+struct dw_dma_channel {
+	unsigned int state;
+        int is_cyclic;
+	struct dma_request_sg *req_sg;
+	struct dma_request_cyclic *req_cyclic;
+	unsigned int nr_blocks;
+	int direction;
+	struct dw_dma_block *block;
+};
+
+struct dw_dma_controller {
+	spinlock_t lock;
+	void * __iomem	regs;
+	struct dma_pool *lli_pool;
+	struct clk *hclk;
+	struct dma_controller dma;
+	struct dw_dma_channel channel[DMAC_NR_CHANNELS];
+};
+#define to_dw_dmac(dmac) container_of(dmac, struct dw_dma_controller, dma)
+
+#define dmac_writel_hi(dmac, reg, value) \
+	__raw_writel((value), (dmac)->regs + DW_DMAC_##reg + 4)
+#define dmac_readl_hi(dmac, reg) \
+	__raw_readl((dmac)->regs + DW_DMAC_##reg + 4)
+#define dmac_writel_lo(dmac, reg, value) \
+	__raw_writel((value), (dmac)->regs + DW_DMAC_##reg)
+#define dmac_readl_lo(dmac, reg) \
+	__raw_readl((dmac)->regs + DW_DMAC_##reg)
+#define dmac_chan_writel_hi(dmac, chan, reg, value) \
+	__raw_writel((value), ((dmac)->regs + 0x58 * (chan) \
+			       + DW_DMAC_CHAN_##reg + 4))
+#define dmac_chan_readl_hi(dmac, chan, reg) \
+	__raw_readl((dmac)->regs + 0x58 * (chan) + DW_DMAC_CHAN_##reg + 4)
+#define dmac_chan_writel_lo(dmac, chan, reg, value) \
+	__raw_writel((value), (dmac)->regs + 0x58 * (chan) + DW_DMAC_CHAN_##reg)
+#define dmac_chan_readl_lo(dmac, chan, reg) \
+	__raw_readl((dmac)->regs + 0x58 * (chan) + DW_DMAC_CHAN_##reg)
+#define set_channel_bit(dmac, reg, chan) \
+	dmac_writel_lo(dmac, reg, (1 << (chan)) | (1 << ((chan) + 8)))
+#define clear_channel_bit(dmac, reg, chan) \
+	dmac_writel_lo(dmac, reg, (0 << (chan)) | (1 << ((chan) + 8)))
+
+static int dmac_alloc_channel(struct dma_controller *_dmac)
+{
+	struct dw_dma_controller *dmac = to_dw_dmac(_dmac);
+	struct dw_dma_channel *chan;
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&dmac->lock, flags);
+	for (i = 0; i < DMAC_NR_CHANNELS; i++)
+		if (dmac->channel[i].state == CH_STATE_FREE)
+			break;
+
+	if (i < DMAC_NR_CHANNELS) {
+		chan = &dmac->channel[i];
+		chan->state = CH_STATE_ALLOCATED;
+	} else {
+		i = -EBUSY;
+	}
+
+	spin_unlock_irqrestore(&dmac->lock, flags);
+
+	return i;
+}
+
+static void dmac_release_channel(struct dma_controller *_dmac, int channel)
+{
+	struct dw_dma_controller *dmac = to_dw_dmac(_dmac);
+
+	BUG_ON(channel >= DMAC_NR_CHANNELS
+	       || dmac->channel[channel].state != CH_STATE_ALLOCATED);
+
+	dmac->channel[channel].state = CH_STATE_FREE;
+}
+
+static struct dw_dma_block *allocate_blocks(struct dw_dma_controller *dmac,
+					    unsigned int nr_blocks)
+{
+	struct dw_dma_block *block;
+	void *p;
+	unsigned int i;
+
+	block = kmalloc(nr_blocks * sizeof(*block),
+			GFP_KERNEL);
+	if (unlikely(!block))
+		return NULL;
+
+	for (i = 0; i < nr_blocks; i++) {
+		p = dma_pool_alloc(dmac->lli_pool, GFP_KERNEL,
+				   &block[i].lli_dma_addr);
+		block[i].lli_vaddr = p;
+		if (unlikely(!p))
+			goto fail;
+	}
+
+	return block;
+
+fail:
+	for (i = 0; i < nr_blocks; i++) {
+		if (!block[i].lli_vaddr)
+			break;
+		dma_pool_free(dmac->lli_pool, block[i].lli_vaddr,
+			      block[i].lli_dma_addr);
+	}
+	kfree(block);
+	return NULL;
+}
+
+static void cleanup_channel(struct dw_dma_controller *dmac,
+			    struct dw_dma_channel *chan)
+{
+	unsigned int i;
+
+	if (chan->nr_blocks > 1) {
+		for (i = 0; i < chan->nr_blocks; i++)
+			dma_pool_free(dmac->lli_pool, chan->block[i].lli_vaddr,
+				      chan->block[i].lli_dma_addr);
+		kfree(chan->block);
+	}
+
+	chan->state = CH_STATE_ALLOCATED;
+}
+
+static int dmac_prepare_request_sg(struct dma_controller *_dmac,
+				   struct dma_request_sg *req)
+{
+	struct dw_dma_controller *dmac = to_dw_dmac(_dmac);
+	struct dw_dma_channel *chan;
+	unsigned long ctlhi, ctllo, cfghi, cfglo;
+	unsigned long block_size;
+	unsigned int nr_blocks;
+	int ret, i, direction;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dmac->lock, flags);
+
+	ret = -EINVAL;
+	if (req->req.channel >= DMAC_NR_CHANNELS
+	    || dmac->channel[req->req.channel].state != CH_STATE_ALLOCATED
+	    || req->block_size > DMAC_MAX_BLOCKSIZE) {
+		spin_unlock_irqrestore(&dmac->lock, flags);
+		return -EINVAL;
+	}
+
+	chan = &dmac->channel[req->req.channel];
+	chan->state = CH_STATE_BUSY;
+	chan->req_sg = req;
+	chan->is_cyclic = 0;
+
+	/*
+	 * We have marked the channel as busy, so no need to keep the
+	 * lock as long as we only touch the channel-specific
+	 * registers
+	 */
+	spin_unlock_irqrestore(&dmac->lock, flags);
+
+	/*
+	 * There may be limitations in the driver and/or the DMA
+	 * controller that prevents us from sending a whole
+	 * scatterlist item in one go.  Taking this into account,
+	 * calculate the number of block transfers we need to set up.
+	 *
+	 * FIXME: Let the peripheral driver know about the maximum
+	 * block size we support. We really don't want to use a
+	 * different block size than what was suggested by the
+	 * peripheral.
+	 *
+	 * Each block will get its own Linked List Item (LLI) below.
+	 */
+	block_size = req->block_size;
+	nr_blocks = req->nr_blocks;
+	pr_debug("block_size %lu, nr_blocks %u nr_sg = %u\n",
+		 block_size, nr_blocks, req->nr_sg);
+
+	BUG_ON(nr_blocks == 0);
+	chan->nr_blocks = nr_blocks;
+
+	ret = -EINVAL;
+	cfglo = cfghi = 0;
+	switch (req->direction) {
+	case DMA_DIR_MEM_TO_PERIPH:
+		direction = DMA_TO_DEVICE;
+		cfghi = req->periph_id << (43 - 32);
+		break;
+
+	case DMA_DIR_PERIPH_TO_MEM:
+		direction = DMA_FROM_DEVICE;
+		cfghi = req->periph_id << (39 - 32);
+		break;
+	default:
+		goto out_unclaim_channel;
+	}
+
+        chan->direction = direction;
+
+	dmac_chan_writel_hi(dmac, req->req.channel, CFG, cfghi);
+	dmac_chan_writel_lo(dmac, req->req.channel, CFG, cfglo);
+
+	ctlhi = block_size >> req->width;
+	ctllo = ((req->direction << 20)
+		 // | (1 << 14) | (1 << 11) // source/dest burst trans len
+		 | (req->width << 4) | (req->width << 1)
+		 | (1 << 0));		 // interrupt enable
+
+	if (nr_blocks == 1) {
+		/* Only one block: No need to use block chaining */
+		if (direction == DMA_TO_DEVICE) {
+			dmac_chan_writel_lo(dmac, req->req.channel, SAR,
+					    req->sg->dma_address);
+			dmac_chan_writel_lo(dmac, req->req.channel, DAR,
+					    req->data_reg);
+			ctllo |= 2 << 7; // no dst increment
+		} else {
+			dmac_chan_writel_lo(dmac, req->req.channel, SAR,
+					    req->data_reg);
+			dmac_chan_writel_lo(dmac, req->req.channel, DAR,
+					    req->sg->dma_address);
+			ctllo |= 2 << 9; // no src increment
+		}
+		dmac_chan_writel_lo(dmac, req->req.channel, CTL, ctllo);
+		dmac_chan_writel_hi(dmac, req->req.channel, CTL, ctlhi);
+		pr_debug("ctl hi:lo 0x%lx:%lx\n", ctlhi, ctllo);
+	} else {
+		struct dw_dma_lli *lli, *lli_prev = NULL;
+		int j = 0, offset = 0;
+
+		ret = -ENOMEM;
+		chan->block = allocate_blocks(dmac, nr_blocks);
+		if (!chan->block)
+			goto out_unclaim_channel;
+
+		if (direction == DMA_TO_DEVICE)
+			ctllo |= 1 << 28 | 1 << 27 | 2 << 7;
+		else
+			ctllo |= 1 << 28 | 1 << 27 | 2 << 9;
+
+		/*
+		 * Map scatterlist items to blocks. One scatterlist
+		 * item may need more than one block for the reasons
+		 * mentioned above.
+		 */
+		for (i = 0; i < nr_blocks; i++) {
+			lli = chan->block[i].lli_vaddr;
+			if (lli_prev) {
+				lli_prev->llp = chan->block[i].lli_dma_addr;
+				pr_debug("lli[%d] (0x%p/0x%x): 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+					 i - 1, chan->block[i - 1].lli_vaddr,
+					 chan->block[i - 1].lli_dma_addr,
+					 lli_prev->sar, lli_prev->dar, lli_prev->llp,
+					 lli_prev->ctllo, lli_prev->ctlhi);
+			}
+			lli->llp = 0;
+			lli->ctllo = ctllo;
+			lli->ctlhi = ctlhi;
+			if (direction == DMA_TO_DEVICE) {
+				lli->sar = req->sg[j].dma_address + offset;
+				lli->dar = req->data_reg;
+			} else {
+				lli->sar = req->data_reg;
+				lli->dar = req->sg[j].dma_address + offset;
+			}
+			lli_prev = lli;
+
+			offset += block_size;
+			if (offset > req->sg[j].length) {
+				j++;
+				offset = 0;
+			}
+		}
+
+		pr_debug("lli[%d] (0x%p/0x%x): 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+			 i - 1, chan->block[i - 1].lli_vaddr,
+			 chan->block[i - 1].lli_dma_addr, lli_prev->sar,
+			 lli_prev->dar, lli_prev->llp,
+			 lli_prev->ctllo, lli_prev->ctlhi);
+
+		/*
+		 * SAR, DAR and CTL are initialized from the LLI. We
+		 * only have to enable the LLI bits in CTL.
+		 */
+		dmac_chan_writel_hi(dmac, req->req.channel, CTL, 0);
+		dmac_chan_writel_lo(dmac, req->req.channel, LLP,
+				    chan->block[0].lli_dma_addr);
+		dmac_chan_writel_lo(dmac, req->req.channel, CTL, 1 << 28 | 1 << 27);
+	}
+
+	set_channel_bit(dmac, MASK_XFER, req->req.channel);
+	set_channel_bit(dmac, MASK_ERROR, req->req.channel);
+	if (req->req.block_complete)
+		set_channel_bit(dmac, MASK_BLOCK, req->req.channel);
+	else
+		clear_channel_bit(dmac, MASK_BLOCK, req->req.channel);
+
+	return 0;
+
+out_unclaim_channel:
+	chan->state = CH_STATE_ALLOCATED;
+	return ret;
+}
+
+static int dmac_prepare_request_cyclic(struct dma_controller *_dmac,
+                                       struct dma_request_cyclic *req)
+{
+	struct dw_dma_controller *dmac = to_dw_dmac(_dmac);
+	struct dw_dma_channel *chan;
+	unsigned long ctlhi, ctllo, cfghi, cfglo;
+	unsigned long block_size;
+	int ret, i, direction;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dmac->lock, flags);
+
+        block_size = (req->buffer_size/req->periods) >> req->width;
+
+	ret = -EINVAL;
+	if (req->req.channel >= DMAC_NR_CHANNELS
+	    || dmac->channel[req->req.channel].state != CH_STATE_ALLOCATED
+            || (req->periods == 0)
+	    || block_size > DMAC_MAX_BLOCKSIZE) {
+		spin_unlock_irqrestore(&dmac->lock, flags);
+		return -EINVAL;
+	}
+
+	chan = &dmac->channel[req->req.channel];
+	chan->state = CH_STATE_BUSY;
+	chan->is_cyclic = 1;
+        chan->req_cyclic = req;
+
+	/*
+	 * We have marked the channel as busy, so no need to keep the
+	 * lock as long as we only touch the channel-specific
+	 * registers
+	 */
+	spin_unlock_irqrestore(&dmac->lock, flags);
+
+	/*
+          Setup
+	 */
+	BUG_ON(req->buffer_size % req->periods);
+	/* printk(KERN_INFO "block_size = %lu, periods = %u\n", block_size, req->periods); */
+
+	chan->nr_blocks = req->periods;
+
+	ret = -EINVAL;
+	cfglo = cfghi = 0;
+	switch (req->direction) {
+	case DMA_DIR_MEM_TO_PERIPH:
+		direction = DMA_TO_DEVICE;
+		cfghi = req->periph_id << (43 - 32);
+		break;
+
+	case DMA_DIR_PERIPH_TO_MEM:
+		direction = DMA_FROM_DEVICE;
+		cfghi = req->periph_id << (39 - 32);
+		break;
+	default:
+		goto out_unclaim_channel;
+	}
+
+        chan->direction = direction;
+
+	dmac_chan_writel_hi(dmac, req->req.channel, CFG, cfghi);
+	dmac_chan_writel_lo(dmac, req->req.channel, CFG, cfglo);
+
+	ctlhi = block_size;
+	ctllo = ((req->direction << 20)
+		 | (req->width << 4) | (req->width << 1)
+		 | (1 << 0));		 // interrupt enable
+
+        {
+		struct dw_dma_lli *lli = NULL, *lli_prev = NULL;
+
+		ret = -ENOMEM;
+		chan->block = allocate_blocks(dmac, req->periods);
+		if (!chan->block)
+			goto out_unclaim_channel;
+
+		if (direction == DMA_TO_DEVICE)
+			ctllo |= 1 << 28 | 1 << 27 | 2 << 7;
+		else
+			ctllo |= 1 << 28 | 1 << 27 | 2 << 9;
+
+		/*
+		 * Set up a linked list items where each period gets
+		 * an item. The linked list item for the last period
+		 * points back to the star of the buffer making a
+		 * cyclic buffer.
+		 */
+		for (i = 0; i < req->periods; i++) {
+			lli = chan->block[i].lli_vaddr;
+			if (lli_prev) {
+				lli_prev->llp = chan->block[i].lli_dma_addr;
+				/* printk(KERN_INFO "lli[%d] (0x%p/0x%x): 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+				   i - 1, chan->block[i - 1].lli_vaddr,
+				   chan->block[i - 1].lli_dma_addr,
+				   lli_prev->sar, lli_prev->dar, lli_prev->llp,
+				   lli_prev->ctllo, lli_prev->ctlhi);*/
+			}
+			lli->llp = 0;
+			lli->ctllo = ctllo;
+			lli->ctlhi = ctlhi;
+			if (direction == DMA_TO_DEVICE) {
+				lli->sar = req->buffer_start + i*(block_size << req->width);
+				lli->dar = req->data_reg;
+			} else {
+				lli->sar = req->data_reg;
+				lli->dar = req->buffer_start + i*(block_size << req->width);
+			}
+			lli_prev = lli;
+		}
+		lli->llp = chan->block[0].lli_dma_addr;
+
+		/*printk(KERN_INFO "lli[%d] (0x%p/0x%x): 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+		  i - 1, chan->block[i - 1].lli_vaddr,
+		  chan->block[i - 1].lli_dma_addr, lli_prev->sar,
+		  lli_prev->dar, lli_prev->llp,
+		  lli_prev->ctllo, lli_prev->ctlhi); */
+
+		/*
+		 * SAR, DAR and CTL are initialized from the LLI. We
+		 * only have to enable the LLI bits in CTL.
+		 */
+		dmac_chan_writel_lo(dmac, req->req.channel, LLP,
+				    chan->block[0].lli_dma_addr);
+		dmac_chan_writel_lo(dmac, req->req.channel, CTL, 1 << 28 | 1 << 27);
+	}
+
+	clear_channel_bit(dmac, MASK_XFER, req->req.channel);
+	set_channel_bit(dmac, MASK_ERROR, req->req.channel);
+	if (req->req.block_complete)
+		set_channel_bit(dmac, MASK_BLOCK, req->req.channel);
+	else
+		clear_channel_bit(dmac, MASK_BLOCK, req->req.channel);
+
+	return 0;
+
+out_unclaim_channel:
+	chan->state = CH_STATE_ALLOCATED;
+	return ret;
+}
+
+static int dmac_start_request(struct dma_controller *_dmac,
+			      unsigned int channel)
+{
+	struct dw_dma_controller *dmac = to_dw_dmac(_dmac);
+
+	BUG_ON(channel >= DMAC_NR_CHANNELS);
+
+	set_channel_bit(dmac, CH_EN, channel);
+
+	return 0;
+}
+
+static dma_addr_t dmac_get_current_pos(struct dma_controller *_dmac,
+                                       unsigned int channel)
+{
+	struct dw_dma_controller *dmac = to_dw_dmac(_dmac);
+	struct dw_dma_channel *chan;
+        dma_addr_t current_pos;
+
+	BUG_ON(channel >= DMAC_NR_CHANNELS);
+
+        chan = &dmac->channel[channel];
+
+	switch (chan->direction) {
+	case DMA_TO_DEVICE:
+		current_pos = dmac_chan_readl_lo(dmac, channel, SAR);
+		break;
+	case DMA_FROM_DEVICE:
+		current_pos = dmac_chan_readl_lo(dmac, channel, DAR);
+		break;
+	default:
+		return 0;
+	}
+
+
+        if (!current_pos) {
+		if (chan->is_cyclic) {
+			current_pos = chan->req_cyclic->buffer_start;
+		} else {
+			current_pos = chan->req_sg->sg->dma_address;
+		}
+	}
+
+	return current_pos;
+}
+
+
+static int dmac_stop_request(struct dma_controller *_dmac,
+                             unsigned int channel)
+{
+	struct dw_dma_controller *dmac = to_dw_dmac(_dmac);
+	struct dw_dma_channel *chan;
+
+	BUG_ON(channel >= DMAC_NR_CHANNELS);
+
+	chan = &dmac->channel[channel];
+	pr_debug("stop: st%u s%08x d%08x l%08x ctl0x%08x:0x%08x\n",
+		 chan->state, dmac_chan_readl_lo(dmac, channel, SAR),
+		 dmac_chan_readl_lo(dmac, channel, DAR),
+		 dmac_chan_readl_lo(dmac, channel, LLP),
+		 dmac_chan_readl_hi(dmac, channel, CTL),
+		 dmac_chan_readl_lo(dmac, channel, CTL));
+
+	if (chan->state == CH_STATE_BUSY) {
+		clear_channel_bit(dmac, CH_EN, channel);
+		cleanup_channel(dmac, &dmac->channel[channel]);
+	}
+
+	return 0;
+}
+
+
+static void dmac_block_complete(struct dw_dma_controller *dmac)
+{
+	struct dw_dma_channel *chan;
+	unsigned long status, chanid;
+
+	status = dmac_readl_lo(dmac, STATUS_BLOCK);
+
+	while (status) {
+		struct dma_request *req;
+		chanid = __ffs(status);
+		chan = &dmac->channel[chanid];
+
+                if (chan->is_cyclic) {
+			BUG_ON(!chan->req_cyclic
+			       || !chan->req_cyclic->req.block_complete);
+			req = &chan->req_cyclic->req;
+                } else {
+			BUG_ON(!chan->req_sg || !chan->req_sg->req.block_complete);
+			req = &chan->req_sg->req;
+                }
+		dmac_writel_lo(dmac, CLEAR_BLOCK, 1 << chanid);
+		req->block_complete(req);
+		status = dmac_readl_lo(dmac, STATUS_BLOCK);
+	}
+}
+
+static void dmac_xfer_complete(struct dw_dma_controller *dmac)
+{
+	struct dw_dma_channel *chan;
+	struct dma_request *req;
+	unsigned long status, chanid;
+
+	status = dmac_readl_lo(dmac, STATUS_XFER);
+
+	while (status) {
+		chanid = __ffs(status);
+		chan = &dmac->channel[chanid];
+
+		dmac_writel_lo(dmac, CLEAR_XFER, 1 << chanid);
+
+                req = &chan->req_sg->req;
+                BUG_ON(!req);
+                cleanup_channel(dmac, chan);
+                if (req->xfer_complete)
+			req->xfer_complete(req);
+
+		status = dmac_readl_lo(dmac, STATUS_XFER);
+	}
+}
+
+static void dmac_error(struct dw_dma_controller *dmac)
+{
+	struct dw_dma_channel *chan;
+	unsigned long status, chanid;
+
+	status = dmac_readl_lo(dmac, STATUS_ERROR);
+
+	while (status) {
+		struct dma_request *req;
+
+		chanid = __ffs(status);
+		chan = &dmac->channel[chanid];
+
+		dmac_writel_lo(dmac, CLEAR_ERROR, 1 << chanid);
+		clear_channel_bit(dmac, CH_EN, chanid);
+
+                if (chan->is_cyclic) {
+			BUG_ON(!chan->req_cyclic);
+			req = &chan->req_cyclic->req;
+                } else {
+			BUG_ON(!chan->req_sg);
+			req = &chan->req_sg->req;
+                }
+
+		cleanup_channel(dmac, chan);
+		if (req->error)
+			req->error(req);
+
+		status = dmac_readl_lo(dmac, STATUS_XFER);
+	}
+}
+
+static irqreturn_t dmac_interrupt(int irq, void *dev_id)
+{
+	struct dw_dma_controller *dmac = dev_id;
+	unsigned long status;
+	int ret = IRQ_NONE;
+
+	spin_lock(&dmac->lock);
+
+	status = dmac_readl_lo(dmac, STATUS_INT);
+
+	while (status) {
+		ret = IRQ_HANDLED;
+		if (status & 0x10)
+			dmac_error(dmac);
+		if (status & 0x02)
+			dmac_block_complete(dmac);
+		if (status & 0x01)
+			dmac_xfer_complete(dmac);
+
+		status = dmac_readl_lo(dmac, STATUS_INT);
+	}
+
+	spin_unlock(&dmac->lock);
+	return ret;
+}
+
+static int __devinit dmac_probe(struct platform_device *pdev)
+{
+	struct dw_dma_controller *dmac;
+	struct resource *regs;
+	int ret;
+
+	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!regs)
+		return -ENXIO;
+
+	dmac = kmalloc(sizeof(*dmac), GFP_KERNEL);
+	if (!dmac)
+		return -ENOMEM;
+	memset(dmac, 0, sizeof(*dmac));
+
+	dmac->hclk = clk_get(&pdev->dev, "hclk");
+	if (IS_ERR(dmac->hclk)) {
+		ret = PTR_ERR(dmac->hclk);
+		goto out_free_dmac;
+	}
+	clk_enable(dmac->hclk);
+
+	ret = -ENOMEM;
+	dmac->lli_pool = dma_pool_create("dmac", &pdev->dev,
+					 sizeof(struct dw_dma_lli), 4, 0);
+	if (!dmac->lli_pool)
+		goto out_disable_clk;
+
+	spin_lock_init(&dmac->lock);
+	dmac->dma.dev = &pdev->dev;
+	dmac->dma.alloc_channel = dmac_alloc_channel;
+	dmac->dma.release_channel = dmac_release_channel;
+	dmac->dma.prepare_request_sg = dmac_prepare_request_sg;
+	dmac->dma.prepare_request_cyclic = dmac_prepare_request_cyclic;
+	dmac->dma.start_request = dmac_start_request;
+	dmac->dma.stop_request = dmac_stop_request;
+	dmac->dma.get_current_pos = dmac_get_current_pos;
+
+	dmac->regs = ioremap(regs->start, regs->end - regs->start + 1);
+	if (!dmac->regs)
+		goto out_free_pool;
+
+	ret = request_irq(platform_get_irq(pdev, 0), dmac_interrupt,
+			  SA_SAMPLE_RANDOM, pdev->name, dmac);
+	if (ret)
+		goto out_unmap_regs;
+
+	/* Enable the DMA controller */
+	dmac_writel_lo(dmac, CFG, 1);
+
+	register_dma_controller(&dmac->dma);
+
+	printk(KERN_INFO
+	       "dmac%d: DesignWare DMA controller at 0x%p irq %d\n",
+	       dmac->dma.id, dmac->regs, platform_get_irq(pdev, 0));
+
+	return 0;
+
+out_unmap_regs:
+	iounmap(dmac->regs);
+out_free_pool:
+	dma_pool_destroy(dmac->lli_pool);
+out_disable_clk:
+	clk_disable(dmac->hclk);
+	clk_put(dmac->hclk);
+out_free_dmac:
+	kfree(dmac);
+	return ret;
+}
+
+static struct platform_driver dmac_driver = {
+	.probe		= dmac_probe,
+	.driver		= {
+		.name		= "dmaca",
+	},
+};
+
+static int __init dmac_init(void)
+{
+	return platform_driver_register(&dmac_driver);
+}
+subsys_initcall(dmac_init);
+
+static void __exit dmac_exit(void)
+{
+	platform_driver_unregister(&dmac_driver);
+}
+module_exit(dmac_exit);
+
+MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller driver");
+MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
+MODULE_LICENSE("GPL");
diff --git a/arch/avr32/drivers/dw-dmac.h b/arch/avr32/drivers/dw-dmac.h
new file mode 100644
index 0000000..1f67921
--- /dev/null
+++ b/arch/avr32/drivers/dw-dmac.h
@@ -0,0 +1,42 @@
+/*
+ * Driver for the Synopsys DesignWare DMA Controller
+ *
+ * Copyright (C) 2005-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 __AVR32_DW_DMAC_H__
+#define __AVR32_DW_DMAC_H__
+
+#define DW_DMAC_CFG		0x398
+#define DW_DMAC_CH_EN		0x3a0
+
+#define DW_DMAC_STATUS_XFER	0x2e8
+#define DW_DMAC_STATUS_BLOCK	0x2f0
+#define DW_DMAC_STATUS_ERROR	0x308
+
+#define DW_DMAC_MASK_XFER	0x310
+#define DW_DMAC_MASK_BLOCK	0x318
+#define DW_DMAC_MASK_ERROR	0x330
+
+#define DW_DMAC_CLEAR_XFER	0x338
+#define DW_DMAC_CLEAR_BLOCK	0x340
+#define DW_DMAC_CLEAR_ERROR	0x358
+
+#define DW_DMAC_STATUS_INT	0x360
+
+#define DW_DMAC_CHAN_SAR	0x000
+#define DW_DMAC_CHAN_DAR	0x008
+#define DW_DMAC_CHAN_LLP	0x010
+#define DW_DMAC_CHAN_CTL	0x018
+#define DW_DMAC_CHAN_SSTAT	0x020
+#define DW_DMAC_CHAN_DSTAT	0x028
+#define DW_DMAC_CHAN_SSTATAR	0x030
+#define DW_DMAC_CHAN_DSTATAR	0x038
+#define DW_DMAC_CHAN_CFG	0x040
+#define DW_DMAC_CHAN_SGR	0x048
+#define DW_DMAC_CHAN_DSR	0x050
+
+#endif /* __AVR32_DW_DMAC_H__ */
diff --git a/arch/avr32/kernel/Makefile b/arch/avr32/kernel/Makefile
index 90e5aff..b6afc0c 100644
--- a/arch/avr32/kernel/Makefile
+++ b/arch/avr32/kernel/Makefile
@@ -9,6 +9,7 @@ obj-y				+= syscall_table.o syscall-stubs.o irq.o
 obj-y				+= setup.o traps.o semaphore.o ptrace.o
 obj-y				+= signal.o sys_avr32.o process.o time.o
 obj-y				+= init_task.o switch_to.o cpu.o
+obj-y				+= dma-controller.o
 obj-$(CONFIG_MODULES)		+= module.o avr32_ksyms.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o
 
diff --git a/arch/avr32/kernel/cpu.c b/arch/avr32/kernel/cpu.c
index 2e72fd2..2714cf6 100644
--- a/arch/avr32/kernel/cpu.c
+++ b/arch/avr32/kernel/cpu.c
@@ -209,16 +209,17 @@ static const char *mmu_types[] = {
 void __init setup_processor(void)
 {
 	unsigned long config0, config1;
+	unsigned long features;
 	unsigned cpu_id, cpu_rev, arch_id, arch_rev, mmu_type;
 	unsigned tmp;
 
-	config0 = sysreg_read(CONFIG0); /* 0x0000013e; */
-	config1 = sysreg_read(CONFIG1); /* 0x01f689a2; */
-	cpu_id = config0 >> 24;
-	cpu_rev = (config0 >> 16) & 0xff;
-	arch_id = (config0 >> 13) & 0x07;
-	arch_rev = (config0 >> 10) & 0x07;
-	mmu_type = (config0 >> 7) & 0x03;
+	config0 = sysreg_read(CONFIG0);
+	config1 = sysreg_read(CONFIG1);
+	cpu_id = SYSREG_BFEXT(PROCESSORID, config0);
+	cpu_rev = SYSREG_BFEXT(PROCESSORREVISION, config0);
+	arch_id = SYSREG_BFEXT(AT, config0);
+	arch_rev = SYSREG_BFEXT(AR, config0);
+	mmu_type = SYSREG_BFEXT(MMUT, config0);
 
 	boot_cpu_data.arch_type = arch_id;
 	boot_cpu_data.cpu_type = cpu_id;
@@ -226,16 +227,16 @@ void __init setup_processor(void)
 	boot_cpu_data.cpu_revision = cpu_rev;
 	boot_cpu_data.tlb_config = mmu_type;
 
-	tmp = (config1 >> 13) & 0x07;
+	tmp = SYSREG_BFEXT(ILSZ, config1);
 	if (tmp) {
-		boot_cpu_data.icache.ways = 1 << ((config1 >> 10) & 0x07);
-		boot_cpu_data.icache.sets = 1 << ((config1 >> 16) & 0x0f);
+		boot_cpu_data.icache.ways = 1 << SYSREG_BFEXT(IASS, config1);
+		boot_cpu_data.icache.sets = 1 << SYSREG_BFEXT(ISET, config1);
 		boot_cpu_data.icache.linesz = 1 << (tmp + 1);
 	}
-	tmp = (config1 >> 3) & 0x07;
+	tmp = SYSREG_BFEXT(DLSZ, config1);
 	if (tmp) {
-		boot_cpu_data.dcache.ways = 1 << (config1 & 0x07);
-		boot_cpu_data.dcache.sets = 1 << ((config1 >> 6) & 0x0f);
+		boot_cpu_data.dcache.ways = 1 << SYSREG_BFEXT(DASS, config1);
+		boot_cpu_data.dcache.sets = 1 << SYSREG_BFEXT(DSET, config1);
 		boot_cpu_data.dcache.linesz = 1 << (tmp + 1);
 	}
 
@@ -250,16 +251,39 @@ void __init setup_processor(void)
 		cpu_names[cpu_id], cpu_id, cpu_rev,
 		arch_names[arch_id], arch_rev);
 	printk ("CPU: MMU configuration: %s\n", mmu_types[mmu_type]);
+
 	printk ("CPU: features:");
-	if (config0 & (1 << 6))
-		printk(" fpu");
-	if (config0 & (1 << 5))
-		printk(" java");
-	if (config0 & (1 << 4))
-		printk(" perfctr");
-	if (config0 & (1 << 3))
+	features = 0;
+	if (config0 & SYSREG_BIT(CONFIG0_R)) {
+		features |= AVR32_FEATURE_RMW;
+		printk(" rmw");
+	}
+	if (config0 & SYSREG_BIT(CONFIG0_D)) {
+		features |= AVR32_FEATURE_DSP;
+		printk(" dsp");
+	}
+	if (config0 & SYSREG_BIT(CONFIG0_S)) {
+		features |= AVR32_FEATURE_SIMD;
+		printk(" simd");
+	}
+	if (config0 & SYSREG_BIT(CONFIG0_O)) {
+		features |= AVR32_FEATURE_OCD;
 		printk(" ocd");
+	}
+	if (config0 & SYSREG_BIT(CONFIG0_P)) {
+		features |= AVR32_FEATURE_PCTR;
+		printk(" perfctr");
+	}
+	if (config0 & SYSREG_BIT(CONFIG0_J)) {
+		features |= AVR32_FEATURE_JAVA;
+		printk(" java");
+	}
+	if (config0 & SYSREG_BIT(CONFIG0_F)) {
+		features |= AVR32_FEATURE_FPU;
+		printk(" fpu");
+	}
 	printk("\n");
+	boot_cpu_data.features = features;
 }
 
 #ifdef CONFIG_PROC_FS
diff --git a/arch/avr32/kernel/dma-controller.c b/arch/avr32/kernel/dma-controller.c
new file mode 100644
index 0000000..fb654b3
--- /dev/null
+++ b/arch/avr32/kernel/dma-controller.c
@@ -0,0 +1,34 @@
+/*
+ * Preliminary DMA controller framework for AVR32
+ *
+ * Copyright (C) 2005-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.
+ */
+#include <asm/dma-controller.h>
+
+static LIST_HEAD(controllers);
+
+int register_dma_controller(struct dma_controller *dmac)
+{
+	static int next_id;
+
+	dmac->id = next_id++;
+	list_add_tail(&dmac->list, &controllers);
+
+	return 0;
+}
+EXPORT_SYMBOL(register_dma_controller);
+
+struct dma_controller *find_dma_controller(int id)
+{
+	struct dma_controller *dmac;
+
+	list_for_each_entry(dmac, &controllers, list)
+		if (dmac->id == id)
+			return dmac;
+	return NULL;
+}
+EXPORT_SYMBOL(find_dma_controller);
diff --git a/arch/avr32/kernel/entry-avr32b.S b/arch/avr32/kernel/entry-avr32b.S
index eeb6679..42657f1 100644
--- a/arch/avr32/kernel/entry-avr32b.S
+++ b/arch/avr32/kernel/entry-avr32b.S
@@ -100,55 +100,49 @@ dtlb_miss_write:
 
 	.global	tlb_miss_common
 tlb_miss_common:
-	mfsr	r0, SYSREG_PTBR
-	mfsr	r1, SYSREG_TLBEAR
+	mfsr	r0, SYSREG_TLBEAR
+	mfsr	r1, SYSREG_PTBR
 
 	/* Is it the vmalloc space? */
-	bld	r1, 31
+	bld	r0, 31
 	brcs	handle_vmalloc_miss
 
 	/* First level lookup */
 pgtbl_lookup:
-	lsr	r2, r1, PGDIR_SHIFT
-	ld.w	r0, r0[r2 << 2]
-	bld	r0, _PAGE_BIT_PRESENT
+	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
 
-	/* TODO: Check access rights on page table if necessary */
-
 	/* Translate to virtual address in P1. */
-	andl	r0, 0xf000
-	sbr	r0, 31
+	andl	r3, 0xf000
+	sbr	r3, 31
 
 	/* Second level lookup */
-	lsl	r1, (32 - PGDIR_SHIFT)
-	lsr	r1, (32 - PGDIR_SHIFT) + PAGE_SHIFT
-	add	r2, r0, r1 << 2
-	ld.w	r1, r2[0]
-	bld	r1, _PAGE_BIT_PRESENT
+	ld.w	r2, r3[r1 << 2]
+	mfsr	r0, SYSREG_TLBARLO
+	bld	r2, _PAGE_BIT_PRESENT
 	brcc	page_not_present
 
 	/* Mark the page as accessed */
-	sbr	r1, _PAGE_BIT_ACCESSED
-	st.w	r2[0], r1
+	sbr	r2, _PAGE_BIT_ACCESSED
+	st.w	r3[r1 << 2], r2
 
 	/* Drop software flags */
-	andl	r1, _PAGE_FLAGS_HARDWARE_MASK & 0xffff
-	mtsr	SYSREG_TLBELO, r1
+	andl	r2, _PAGE_FLAGS_HARDWARE_MASK & 0xffff
+	mtsr	SYSREG_TLBELO, r2
 
 	/* Figure out which entry we want to replace */
-	mfsr	r0, SYSREG_TLBARLO
+	mfsr	r1, SYSREG_MMUCR
 	clz	r2, r0
 	brcc	1f
-	mov	r1, -1			/* All entries have been accessed, */
-	mtsr	SYSREG_TLBARLO, r1	/* so reset TLBAR */
-	mov	r2, 0			/* and start at 0 */
-1:	mfsr	r1, SYSREG_MMUCR
-	lsl	r2, 14
-	andl	r1, 0x3fff, COH
-	or	r1, r2
-	mtsr	SYSREG_MMUCR, r1
+	mov	r3, -1			/* All entries have been accessed, */
+	mov	r2, 0			/* so start at 0 */
+	mtsr	SYSREG_TLBARLO, r3	/* and reset TLBAR */
 
+1:	bfins	r1, r2, SYSREG_DRP_OFFSET, SYSREG_DRP_SIZE
+	mtsr	SYSREG_MMUCR, r1
 	tlbw
 
 	tlbmiss_restore
@@ -156,8 +150,8 @@ pgtbl_lookup:
 
 handle_vmalloc_miss:
 	/* Simply do the lookup in init's page table */
-	mov	r0, lo(swapper_pg_dir)
-	orh	r0, hi(swapper_pg_dir)
+	mov	r1, lo(swapper_pg_dir)
+	orh	r1, hi(swapper_pg_dir)
 	rjmp	pgtbl_lookup
 
 
@@ -340,12 +334,34 @@ do_bus_error_read:
 do_nmi_ll:
 	sub	sp, 4
 	stmts	--sp, r0-lr
-	/* FIXME: Make sure RAR_NMI and RSR_NMI are pushed instead of *_EX */
-	rcall	save_full_context_ex
+	mfsr	r9, SYSREG_RSR_NMI
+	mfsr	r8, SYSREG_RAR_NMI
+	bfextu	r0, r9, MODE_SHIFT, 3
+	brne	2f
+
+1:	pushm	r8, r9	/* PC and SR */
 	mfsr	r12, SYSREG_ECR
 	mov	r11, sp
 	rcall	do_nmi
-	rjmp	bad_return
+	popm	r8-r9
+	mtsr	SYSREG_RAR_NMI, r8
+	tst	r0, r0
+	mtsr	SYSREG_RSR_NMI, r9
+	brne	3f
+
+	ldmts	sp++, r0-lr
+	sub	sp, -4		/* skip r12_orig */
+	rete
+
+2:	sub	r10, sp, -(FRAME_SIZE_FULL - REG_LR)
+	stdsp	sp[4], r10	/* replace saved SP */
+	rjmp	1b
+
+3:	popm	lr
+	sub	sp, -4		/* skip sp */
+	popm	r0-r12
+	sub	sp, -4		/* skip r12_orig */
+	rete
 
 handle_address_fault:
 	sub	sp, 4
@@ -630,9 +646,12 @@ irq_level\level:
 	rcall	do_IRQ
 
 	lddsp	r4, sp[REG_SR]
-	andh	r4, (MODE_MASK >> 16), COH
+	bfextu	r4, r4, SYSREG_M0_OFFSET, 3
+	cp.w	r4, MODE_SUPERVISOR >> SYSREG_M0_OFFSET
+	breq	2f
+	cp.w	r4, MODE_USER >> SYSREG_M0_OFFSET
 #ifdef CONFIG_PREEMPT
-	brne	2f
+	brne	3f
 #else
 	brne	1f
 #endif
@@ -649,9 +668,18 @@ irq_level\level:
 	sub	sp, -4		/* ignore r12_orig */
 	rete
 
+2:	get_thread_info	r0
+	ld.w	r1, r0[TI_flags]
+	bld	r1, TIF_CPU_GOING_TO_SLEEP
 #ifdef CONFIG_PREEMPT
-2:
-	get_thread_info	r0
+	brcc	3f
+#else
+	brcc	1b
+#endif
+	sub	r1, pc, . - cpu_idle_skip_sleep
+	stdsp	sp[REG_PC], r1
+#ifdef CONFIG_PREEMPT
+3:	get_thread_info r0
 	ld.w	r2, r0[TI_preempt_count]
 	cp.w	r2, 0
 	brne	1b
@@ -662,12 +690,32 @@ irq_level\level:
 	bld	r4, SYSREG_GM_OFFSET
 	brcs	1b
 	rcall	preempt_schedule_irq
-	rjmp	1b
 #endif
+	rjmp	1b
 	.endm
 
 	.section .irq.text,"ax",@progbits
 
+.global cpu_idle_sleep
+cpu_idle_sleep:
+	mask_interrupts
+	get_thread_info r8
+	ld.w	r9, r8[TI_flags]
+	bld	r9, TIF_NEED_RESCHED
+	brcs	cpu_idle_enable_int_and_exit
+	sbr	r9, TIF_CPU_GOING_TO_SLEEP
+	st.w	r8[TI_flags], r9
+	unmask_interrupts
+	sleep 0
+cpu_idle_skip_sleep:
+	mask_interrupts
+	ld.w	r9, r8[TI_flags]
+	cbr	r9, TIF_CPU_GOING_TO_SLEEP
+	st.w	r8[TI_flags], r9
+cpu_idle_enable_int_and_exit:
+	unmask_interrupts
+	retal	r12
+
 	.global	irq_level0
 	.global	irq_level1
 	.global	irq_level2
diff --git a/arch/avr32/kernel/irq.c b/arch/avr32/kernel/irq.c
index fd31124..61f2de2 100644
--- a/arch/avr32/kernel/irq.c
+++ b/arch/avr32/kernel/irq.c
@@ -7,15 +7,6 @@
  * 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.
- *
- * This file contains the code used by various IRQ handling routines:
- * asking for different IRQ's should be done through these routines
- * instead of just grabbing them. Thus setups with different IRQ numbers
- * shouldn't result in any weird surprises, and installing new handlers
- * should be easier.
- *
- * IRQ's are in fact implemented a bit like signal handlers for the kernel.
- * Naturally it's not a 1:1 relation, but there are similarities.
  */
 
 #include <linux/interrupt.h>
diff --git a/arch/avr32/kernel/kprobes.c b/arch/avr32/kernel/kprobes.c
index d0abbca..037d7bd 100644
--- a/arch/avr32/kernel/kprobes.c
+++ b/arch/avr32/kernel/kprobes.c
@@ -179,7 +179,7 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs)
 	return 1;
 }
 
-static int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
 {
 	struct kprobe *cur = kprobe_running();
 
@@ -216,11 +216,6 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
 		if (post_kprobe_handler(args->regs))
 			ret = NOTIFY_STOP;
 		break;
-	case DIE_FAULT:
-		if (kprobe_running()
-		    && kprobe_fault_handler(args->regs, args->trapnr))
-			ret = NOTIFY_STOP;
-		break;
 	default:
 		break;
 	}
diff --git a/arch/avr32/kernel/module.c b/arch/avr32/kernel/module.c
index b599eae..1167fe9 100644
--- a/arch/avr32/kernel/module.c
+++ b/arch/avr32/kernel/module.c
@@ -12,10 +12,11 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/moduleloader.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
+#include <linux/bug.h>
 #include <linux/elf.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleloader.h>
 #include <linux/vmalloc.h>
 
 void *module_alloc(unsigned long size)
@@ -315,10 +316,10 @@ int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
 	vfree(module->arch.syminfo);
 	module->arch.syminfo = NULL;
 
-	return 0;
+	return module_bug_finalize(hdr, sechdrs, module);
 }
 
 void module_arch_cleanup(struct module *module)
 {
-
+	module_bug_cleanup(module);
 }
diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c
index 0b43259..4e4181e 100644
--- a/arch/avr32/kernel/process.c
+++ b/arch/avr32/kernel/process.c
@@ -11,6 +11,7 @@
 #include <linux/fs.h>
 #include <linux/ptrace.h>
 #include <linux/reboot.h>
+#include <linux/uaccess.h>
 #include <linux/unistd.h>
 
 #include <asm/sysreg.h>
@@ -19,6 +20,8 @@
 void (*pm_power_off)(void) = NULL;
 EXPORT_SYMBOL(pm_power_off);
 
+extern void cpu_idle_sleep(void);
+
 /*
  * This file handles the architecture-dependent parts of process handling..
  */
@@ -27,9 +30,8 @@ void cpu_idle(void)
 {
 	/* endless idle loop with no priority at all */
 	while (1) {
-		/* TODO: Enter sleep mode */
 		while (!need_resched())
-			cpu_relax();
+			cpu_idle_sleep();
 		preempt_enable_no_resched();
 		schedule();
 		preempt_disable();
@@ -114,39 +116,178 @@ void release_thread(struct task_struct *dead_task)
 	/* do nothing */
 }
 
+static void dump_mem(const char *str, const char *log_lvl,
+		     unsigned long bottom, unsigned long top)
+{
+	unsigned long p;
+	int i;
+
+	printk("%s%s(0x%08lx to 0x%08lx)\n", log_lvl, str, bottom, top);
+
+	for (p = bottom & ~31; p < top; ) {
+		printk("%s%04lx: ", log_lvl, p & 0xffff);
+
+		for (i = 0; i < 8; i++, p += 4) {
+			unsigned int val;
+
+			if (p < bottom || p >= top)
+				printk("         ");
+			else {
+				if (__get_user(val, (unsigned int __user *)p)) {
+					printk("\n");
+					goto out;
+				}
+				printk("%08x ", val);
+			}
+		}
+		printk("\n");
+	}
+
+out:
+	return;
+}
+
+static inline int valid_stack_ptr(struct thread_info *tinfo, unsigned long p)
+{
+	return (p > (unsigned long)tinfo)
+		&& (p < (unsigned long)tinfo + THREAD_SIZE - 3);
+}
+
+#ifdef CONFIG_FRAME_POINTER
+static void show_trace_log_lvl(struct task_struct *tsk, unsigned long *sp,
+			       struct pt_regs *regs, const char *log_lvl)
+{
+	unsigned long lr, fp;
+	struct thread_info *tinfo;
+
+	if (regs)
+		fp = regs->r7;
+	else if (tsk == current)
+		asm("mov %0, r7" : "=r"(fp));
+	else
+		fp = tsk->thread.cpu_context.r7;
+
+	/*
+	 * Walk the stack as long as the frame pointer (a) is within
+	 * the kernel stack of the task, and (b) it doesn't move
+	 * downwards.
+	 */
+	tinfo = task_thread_info(tsk);
+	printk("%sCall trace:\n", log_lvl);
+	while (valid_stack_ptr(tinfo, fp)) {
+		unsigned long new_fp;
+
+		lr = *(unsigned long *)fp;
+#ifdef CONFIG_KALLSYMS
+		printk("%s [<%08lx>] ", log_lvl, lr);
+#else
+		printk(" [<%08lx>] ", lr);
+#endif
+		print_symbol("%s\n", lr);
+
+		new_fp = *(unsigned long *)(fp + 4);
+		if (new_fp <= fp)
+			break;
+		fp = new_fp;
+	}
+	printk("\n");
+}
+#else
+static void show_trace_log_lvl(struct task_struct *tsk, unsigned long *sp,
+			       struct pt_regs *regs, const char *log_lvl)
+{
+	unsigned long addr;
+
+	printk("%sCall trace:\n", log_lvl);
+
+	while (!kstack_end(sp)) {
+		addr = *sp++;
+		if (kernel_text_address(addr)) {
+#ifdef CONFIG_KALLSYMS
+			printk("%s [<%08lx>] ", log_lvl, addr);
+#else
+			printk(" [<%08lx>] ", addr);
+#endif
+			print_symbol("%s\n", addr);
+		}
+	}
+	printk("\n");
+}
+#endif
+
+void show_stack_log_lvl(struct task_struct *tsk, unsigned long sp,
+			struct pt_regs *regs, const char *log_lvl)
+{
+	struct thread_info *tinfo;
+
+	if (sp == 0) {
+		if (tsk)
+			sp = tsk->thread.cpu_context.ksp;
+		else
+			sp = (unsigned long)&tinfo;
+	}
+	if (!tsk)
+		tsk = current;
+
+	tinfo = task_thread_info(tsk);
+
+	if (valid_stack_ptr(tinfo, sp)) {
+		dump_mem("Stack: ", log_lvl, sp,
+			 THREAD_SIZE + (unsigned long)tinfo);
+		show_trace_log_lvl(tsk, (unsigned long *)sp, regs, log_lvl);
+	}
+}
+
+void show_stack(struct task_struct *tsk, unsigned long *stack)
+{
+	show_stack_log_lvl(tsk, (unsigned long)stack, NULL, "");
+}
+
+void dump_stack(void)
+{
+	unsigned long stack;
+
+	show_trace_log_lvl(current, &stack, NULL, "");
+}
+EXPORT_SYMBOL(dump_stack);
+
 static const char *cpu_modes[] = {
 	"Application", "Supervisor", "Interrupt level 0", "Interrupt level 1",
 	"Interrupt level 2", "Interrupt level 3", "Exception", "NMI"
 };
 
-void show_regs(struct pt_regs *regs)
+void show_regs_log_lvl(struct pt_regs *regs, const char *log_lvl)
 {
 	unsigned long sp = regs->sp;
 	unsigned long lr = regs->lr;
 	unsigned long mode = (regs->sr & MODE_MASK) >> MODE_SHIFT;
 
-	if (!user_mode(regs))
+	if (!user_mode(regs)) {
 		sp = (unsigned long)regs + FRAME_SIZE_FULL;
 
-	print_symbol("PC is at %s\n", instruction_pointer(regs));
-	print_symbol("LR is at %s\n", lr);
-	printk("pc : [<%08lx>]    lr : [<%08lx>]    %s\n"
-	       "sp : %08lx  r12: %08lx  r11: %08lx\n",
-	       instruction_pointer(regs),
-	       lr, print_tainted(), sp, regs->r12, regs->r11);
-	printk("r10: %08lx  r9 : %08lx  r8 : %08lx\n",
-	       regs->r10, regs->r9, regs->r8);
-	printk("r7 : %08lx  r6 : %08lx  r5 : %08lx  r4 : %08lx\n",
-	       regs->r7, regs->r6, regs->r5, regs->r4);
-	printk("r3 : %08lx  r2 : %08lx  r1 : %08lx  r0 : %08lx\n",
-	       regs->r3, regs->r2, regs->r1, regs->r0);
-	printk("Flags: %c%c%c%c%c\n",
+		printk("%s", log_lvl);
+		print_symbol("PC is at %s\n", instruction_pointer(regs));
+		printk("%s", log_lvl);
+		print_symbol("LR is at %s\n", lr);
+	}
+
+	printk("%spc : [<%08lx>]    lr : [<%08lx>]    %s\n"
+	       "%ssp : %08lx  r12: %08lx  r11: %08lx\n",
+	       log_lvl, instruction_pointer(regs), lr, print_tainted(),
+	       log_lvl, sp, regs->r12, regs->r11);
+	printk("%sr10: %08lx  r9 : %08lx  r8 : %08lx\n",
+	       log_lvl, regs->r10, regs->r9, regs->r8);
+	printk("%sr7 : %08lx  r6 : %08lx  r5 : %08lx  r4 : %08lx\n",
+	       log_lvl, regs->r7, regs->r6, regs->r5, regs->r4);
+	printk("%sr3 : %08lx  r2 : %08lx  r1 : %08lx  r0 : %08lx\n",
+	       log_lvl, regs->r3, regs->r2, regs->r1, regs->r0);
+	printk("%sFlags: %c%c%c%c%c\n", log_lvl,
 	       regs->sr & SR_Q ? 'Q' : 'q',
 	       regs->sr & SR_V ? 'V' : 'v',
 	       regs->sr & SR_N ? 'N' : 'n',
 	       regs->sr & SR_Z ? 'Z' : 'z',
 	       regs->sr & SR_C ? 'C' : 'c');
-	printk("Mode bits: %c%c%c%c%c%c%c%c%c\n",
+	printk("%sMode bits: %c%c%c%c%c%c%c%c%c\n", log_lvl,
 	       regs->sr & SR_H ? 'H' : 'h',
 	       regs->sr & SR_R ? 'R' : 'r',
 	       regs->sr & SR_J ? 'J' : 'j',
@@ -156,9 +297,21 @@ void show_regs(struct pt_regs *regs)
 	       regs->sr & SR_I1M ? '1' : '.',
 	       regs->sr & SR_I0M ? '0' : '.',
 	       regs->sr & SR_GM ? 'G' : 'g');
-	printk("CPU Mode: %s\n", cpu_modes[mode]);
+	printk("%sCPU Mode: %s\n", log_lvl, cpu_modes[mode]);
+	printk("%sProcess: %s [%d] (task: %p thread: %p)\n",
+	       log_lvl, current->comm, current->pid, current,
+	       task_thread_info(current));
+}
+
+void show_regs(struct pt_regs *regs)
+{
+	unsigned long sp = regs->sp;
+
+	if (!user_mode(regs))
+		sp = (unsigned long)regs + FRAME_SIZE_FULL;
 
-	show_trace(NULL, (unsigned long *)sp, regs);
+	show_regs_log_lvl(regs, "");
+	show_trace_log_lvl(current, (unsigned long *)sp, regs, "");
 }
 EXPORT_SYMBOL(show_regs);
 
diff --git a/arch/avr32/kernel/setup.c b/arch/avr32/kernel/setup.c
index a1a7c3c..b279d66 100644
--- a/arch/avr32/kernel/setup.c
+++ b/arch/avr32/kernel/setup.c
@@ -8,12 +8,14 @@
 
 #include <linux/clk.h>
 #include <linux/init.h>
+#include <linux/initrd.h>
 #include <linux/sched.h>
 #include <linux/console.h>
 #include <linux/ioport.h>
 #include <linux/bootmem.h>
 #include <linux/fs.h>
 #include <linux/module.h>
+#include <linux/pfn.h>
 #include <linux/root_dev.h>
 #include <linux/cpu.h>
 #include <linux/kernel.h>
@@ -30,13 +32,6 @@
 extern int root_mountflags;
 
 /*
- * Bootloader-provided information about physical memory
- */
-struct tag_mem_range *mem_phys;
-struct tag_mem_range *mem_reserved;
-struct tag_mem_range *mem_ramdisk;
-
-/*
  * Initialize loops_per_jiffy as 5000000 (500MIPS).
  * Better make it too large than too small...
  */
@@ -48,48 +43,193 @@ EXPORT_SYMBOL(boot_cpu_data);
 static char __initdata command_line[COMMAND_LINE_SIZE];
 
 /*
- * Should be more than enough, but if you have a _really_ complex
- * setup, you might need to increase the size of this...
+ * Standard memory resources
  */
-static struct tag_mem_range __initdata mem_range_cache[32];
-static unsigned mem_range_next_free;
+static struct resource __initdata kernel_data = {
+	.name	= "Kernel data",
+	.start	= 0,
+	.end	= 0,
+	.flags	= IORESOURCE_MEM,
+};
+static struct resource __initdata kernel_code = {
+	.name	= "Kernel code",
+	.start	= 0,
+	.end	= 0,
+	.flags	= IORESOURCE_MEM,
+	.sibling = &kernel_data,
+};
 
 /*
- * Standard memory resources
+ * Available system RAM and reserved regions as singly linked
+ * lists. These lists are traversed using the sibling pointer in
+ * struct resource and are kept sorted at all times.
  */
-static struct resource mem_res[] = {
-	{
-		.name	= "Kernel code",
-		.start	= 0,
-		.end	= 0,
-		.flags	= IORESOURCE_MEM
-	},
-	{
-		.name	= "Kernel data",
-		.start	= 0,
-		.end	= 0,
-		.flags	= IORESOURCE_MEM,
-	},
-};
+static struct resource *__initdata system_ram;
+static struct resource *__initdata reserved = &kernel_code;
+
+/*
+ * We need to allocate these before the bootmem allocator is up and
+ * running, so we need this "cache". 32 entries are probably enough
+ * for all but the most insanely complex systems.
+ */
+static struct resource __initdata res_cache[32];
+static unsigned int __initdata res_cache_next_free;
+
+static void __init resource_init(void)
+{
+	struct resource *mem, *res;
+	struct resource *new;
+
+	kernel_code.start = __pa(init_mm.start_code);
+
+	for (mem = system_ram; mem; mem = mem->sibling) {
+		new = alloc_bootmem_low(sizeof(struct resource));
+		memcpy(new, mem, sizeof(struct resource));
+
+		new->sibling = NULL;
+		if (request_resource(&iomem_resource, new))
+			printk(KERN_WARNING "Bad RAM resource %08x-%08x\n",
+			       mem->start, mem->end);
+	}
+
+	for (res = reserved; res; res = res->sibling) {
+		new = alloc_bootmem_low(sizeof(struct resource));
+		memcpy(new, res, sizeof(struct resource));
+
+		new->sibling = NULL;
+		if (insert_resource(&iomem_resource, new))
+			printk(KERN_WARNING
+			       "Bad reserved resource %s (%08x-%08x)\n",
+			       res->name, res->start, res->end);
+	}
+}
+
+static void __init
+add_physical_memory(resource_size_t start, resource_size_t end)
+{
+	struct resource *new, *next, **pprev;
+
+	for (pprev = &system_ram, next = system_ram; next;
+	     pprev = &next->sibling, next = next->sibling) {
+		if (end < next->start)
+			break;
+		if (start <= next->end) {
+			printk(KERN_WARNING
+			       "Warning: Physical memory map is broken\n");
+			printk(KERN_WARNING
+			       "Warning: %08x-%08x overlaps %08x-%08x\n",
+			       start, end, next->start, next->end);
+			return;
+		}
+	}
+
+	if (res_cache_next_free >= ARRAY_SIZE(res_cache)) {
+		printk(KERN_WARNING
+		       "Warning: Failed to add physical memory %08x-%08x\n",
+		       start, end);
+		return;
+	}
+
+	new = &res_cache[res_cache_next_free++];
+	new->start = start;
+	new->end = end;
+	new->name = "System RAM";
+	new->flags = IORESOURCE_MEM;
+
+	*pprev = new;
+}
+
+static int __init
+add_reserved_region(resource_size_t start, resource_size_t end,
+		    const char *name)
+{
+	struct resource *new, *next, **pprev;
+
+	if (end < start)
+		return -EINVAL;
+
+	if (res_cache_next_free >= ARRAY_SIZE(res_cache))
+		return -ENOMEM;
+
+	for (pprev = &reserved, next = reserved; next;
+	     pprev = &next->sibling, next = next->sibling) {
+		if (end < next->start)
+			break;
+		if (start <= next->end)
+			return -EBUSY;
+	}
+
+	new = &res_cache[res_cache_next_free++];
+	new->start = start;
+	new->end = end;
+	new->name = name;
+	new->flags = IORESOURCE_MEM;
+
+	*pprev = new;
+
+	return 0;
+}
+
+static unsigned long __init
+find_free_region(const struct resource *mem, resource_size_t size,
+		 resource_size_t align)
+{
+	struct resource *res;
+	unsigned long target;
+
+	target = ALIGN(mem->start, align);
+	for (res = reserved; res; res = res->sibling) {
+		if ((target + size) <= res->start)
+			break;
+		if (target <= res->end)
+			target = ALIGN(res->end + 1, align);
+	}
+
+	if ((target + size) > (mem->end + 1))
+		return mem->end + 1;
+
+	return target;
+}
+
+static int __init
+alloc_reserved_region(resource_size_t *start, resource_size_t size,
+		      resource_size_t align, const char *name)
+{
+	struct resource *mem;
+	resource_size_t target;
+	int ret;
+
+	for (mem = system_ram; mem; mem = mem->sibling) {
+		target = find_free_region(mem, size, align);
+		if (target <= mem->end) {
+			ret = add_reserved_region(target, target + size - 1,
+						  name);
+			if (!ret)
+				*start = target;
+			return ret;
+		}
+	}
 
-#define kernel_code	mem_res[0]
-#define kernel_data	mem_res[1]
+	return -ENOMEM;
+}
 
 /*
  * Early framebuffer allocation. Works as follows:
  *   - If fbmem_size is zero, nothing will be allocated or reserved.
  *   - If fbmem_start is zero when setup_bootmem() is called,
- *     fbmem_size bytes will be allocated from the bootmem allocator.
+ *     a block of fbmem_size bytes will be reserved before bootmem
+ *     initialization. It will be aligned to the largest page size
+ *     that fbmem_size is a multiple of.
  *   - If fbmem_start is nonzero, an area of size fbmem_size will be
- *     reserved at the physical address fbmem_start if necessary. If
- *     the area isn't in a memory region known to the kernel, it will
- *     be left alone.
+ *     reserved at the physical address fbmem_start if possible. If
+ *     it collides with other reserved memory, a different block of
+ *     same size will be allocated, just as if fbmem_start was zero.
  *
  * Board-specific code may use these variables to set up platform data
  * for the framebuffer driver if fbmem_size is nonzero.
  */
-static unsigned long __initdata fbmem_start;
-static unsigned long __initdata fbmem_size;
+resource_size_t __initdata fbmem_start;
+resource_size_t __initdata fbmem_size;
 
 /*
  * "fbmem=xxx[kKmM]" allocates the specified amount of boot memory for
@@ -103,48 +243,42 @@ static unsigned long __initdata fbmem_size;
  */
 static int __init early_parse_fbmem(char *p)
 {
+	int ret;
+	unsigned long align;
+
 	fbmem_size = memparse(p, &p);
-	if (*p == '@')
+	if (*p == '@') {
 		fbmem_start = memparse(p, &p);
-	return 0;
-}
-early_param("fbmem", early_parse_fbmem);
-
-static inline void __init resource_init(void)
-{
-	struct tag_mem_range *region;
-
-	kernel_code.start = __pa(init_mm.start_code);
-	kernel_code.end = __pa(init_mm.end_code - 1);
-	kernel_data.start = __pa(init_mm.end_code);
-	kernel_data.end = __pa(init_mm.brk - 1);
-
-	for (region = mem_phys; region; region = region->next) {
-		struct resource *res;
-		unsigned long phys_start, phys_end;
-
-		if (region->size == 0)
-			continue;
-
-		phys_start = region->addr;
-		phys_end = phys_start + region->size - 1;
-
-		res = alloc_bootmem_low(sizeof(*res));
-		res->name = "System RAM";
-		res->start = phys_start;
-		res->end = phys_end;
-		res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-
-		request_resource (&iomem_resource, res);
+		ret = add_reserved_region(fbmem_start,
+					  fbmem_start + fbmem_size - 1,
+					  "Framebuffer");
+		if (ret) {
+			printk(KERN_WARNING
+			       "Failed to reserve framebuffer memory\n");
+			fbmem_start = 0;
+		}
+	}
 
-		if (kernel_code.start >= res->start &&
-		    kernel_code.end <= res->end)
-			request_resource (res, &kernel_code);
-		if (kernel_data.start >= res->start &&
-		    kernel_data.end <= res->end)
-			request_resource (res, &kernel_data);
+	if (!fbmem_start) {
+		if ((fbmem_size & 0x000fffffUL) == 0)
+			align = 0x100000;	/* 1 MiB */
+		else if ((fbmem_size & 0x0000ffffUL) == 0)
+			align = 0x10000;	/* 64 KiB */
+		else
+			align = 0x1000;		/* 4 KiB */
+
+		ret = alloc_reserved_region(&fbmem_start, fbmem_size,
+					    align, "Framebuffer");
+		if (ret) {
+			printk(KERN_WARNING
+			       "Failed to allocate framebuffer memory\n");
+			fbmem_size = 0;
+		}
 	}
+
+	return 0;
 }
+early_param("fbmem", early_parse_fbmem);
 
 static int __init parse_tag_core(struct tag *tag)
 {
@@ -157,11 +291,9 @@ static int __init parse_tag_core(struct tag *tag)
 }
 __tagtable(ATAG_CORE, parse_tag_core);
 
-static int __init parse_tag_mem_range(struct tag *tag,
-				      struct tag_mem_range **root)
+static int __init parse_tag_mem(struct tag *tag)
 {
-	struct tag_mem_range *cur, **pprev;
-	struct tag_mem_range *new;
+	unsigned long start, end;
 
 	/*
 	 * Ignore zero-sized entries. If we're running standalone, the
@@ -171,34 +303,53 @@ static int __init parse_tag_mem_range(struct tag *tag,
 	if (tag->u.mem_range.size == 0)
 		return 0;
 
-	/*
-	 * Copy the data so the bootmem init code doesn't need to care
-	 * about it.
-	 */
-	if (mem_range_next_free >= ARRAY_SIZE(mem_range_cache))
-		panic("Physical memory map too complex!\n");
+	start = tag->u.mem_range.addr;
+	end = tag->u.mem_range.addr + tag->u.mem_range.size - 1;
+
+	add_physical_memory(start, end);
+	return 0;
+}
+__tagtable(ATAG_MEM, parse_tag_mem);
+
+static int __init parse_tag_rdimg(struct tag *tag)
+{
+#ifdef CONFIG_INITRD
+	struct tag_mem_range *mem = &tag->u.mem_range;
+	int ret;
 
-	new = &mem_range_cache[mem_range_next_free++];
-	*new = tag->u.mem_range;
+	if (initrd_start) {
+		printk(KERN_WARNING
+		       "Warning: Only the first initrd image will be used\n");
+		return 0;
+	}
 
-	pprev = root;
-	cur = *root;
-	while (cur) {
-		pprev = &cur->next;
-		cur = cur->next;
+	ret = add_reserved_region(mem->start, mem->start + mem->size - 1,
+				  "initrd");
+	if (ret) {
+		printk(KERN_WARNING
+		       "Warning: Failed to reserve initrd memory\n");
+		return ret;
 	}
 
-	*pprev = new;
-	new->next = NULL;
+	initrd_start = (unsigned long)__va(mem->addr);
+	initrd_end = initrd_start + mem->size;
+#else
+	printk(KERN_WARNING "RAM disk image present, but "
+	       "no initrd support in kernel, ignoring\n");
+#endif
 
 	return 0;
 }
+__tagtable(ATAG_RDIMG, parse_tag_rdimg);
 
-static int __init parse_tag_mem(struct tag *tag)
+static int __init parse_tag_rsvd_mem(struct tag *tag)
 {
-	return parse_tag_mem_range(tag, &mem_phys);
+	struct tag_mem_range *mem = &tag->u.mem_range;
+
+	return add_reserved_region(mem->addr, mem->addr + mem->size - 1,
+				   "Reserved");
 }
-__tagtable(ATAG_MEM, parse_tag_mem);
+__tagtable(ATAG_RSVD_MEM, parse_tag_rsvd_mem);
 
 static int __init parse_tag_cmdline(struct tag *tag)
 {
@@ -207,12 +358,6 @@ static int __init parse_tag_cmdline(struct tag *tag)
 }
 __tagtable(ATAG_CMDLINE, parse_tag_cmdline);
 
-static int __init parse_tag_rdimg(struct tag *tag)
-{
-	return parse_tag_mem_range(tag, &mem_ramdisk);
-}
-__tagtable(ATAG_RDIMG, parse_tag_rdimg);
-
 static int __init parse_tag_clock(struct tag *tag)
 {
 	/*
@@ -223,12 +368,6 @@ static int __init parse_tag_clock(struct tag *tag)
 }
 __tagtable(ATAG_CLOCK, parse_tag_clock);
 
-static int __init parse_tag_rsvd_mem(struct tag *tag)
-{
-	return parse_tag_mem_range(tag, &mem_reserved);
-}
-__tagtable(ATAG_RSVD_MEM, parse_tag_rsvd_mem);
-
 /*
  * Scan the tag table for this tag, and call its parse function. The
  * tag table is built by the linker from all the __tagtable
@@ -260,10 +399,137 @@ static void __init parse_tags(struct tag *t)
 			       t->hdr.tag);
 }
 
+/*
+ * Find a free memory region large enough for storing the
+ * bootmem bitmap.
+ */
+static unsigned long __init
+find_bootmap_pfn(const struct resource *mem)
+{
+	unsigned long bootmap_pages, bootmap_len;
+	unsigned long node_pages = PFN_UP(mem->end - mem->start + 1);
+	unsigned long bootmap_start;
+
+	bootmap_pages = bootmem_bootmap_pages(node_pages);
+	bootmap_len = bootmap_pages << PAGE_SHIFT;
+
+	/*
+	 * Find a large enough region without reserved pages for
+	 * storing the bootmem bitmap. We can take advantage of the
+	 * fact that all lists have been sorted.
+	 *
+	 * We have to check that we don't collide with any reserved
+	 * regions, which includes the kernel image and any RAMDISK
+	 * images.
+	 */
+	bootmap_start = find_free_region(mem, bootmap_len, PAGE_SIZE);
+
+	return bootmap_start >> PAGE_SHIFT;
+}
+
+#define MAX_LOWMEM	HIGHMEM_START
+#define MAX_LOWMEM_PFN	PFN_DOWN(MAX_LOWMEM)
+
+static void __init setup_bootmem(void)
+{
+	unsigned bootmap_size;
+	unsigned long first_pfn, bootmap_pfn, pages;
+	unsigned long max_pfn, max_low_pfn;
+	unsigned node = 0;
+	struct resource *res;
+
+	printk(KERN_INFO "Physical memory:\n");
+	for (res = system_ram; res; res = res->sibling)
+		printk("  %08x-%08x\n", res->start, res->end);
+	printk(KERN_INFO "Reserved memory:\n");
+	for (res = reserved; res; res = res->sibling)
+		printk("  %08x-%08x: %s\n",
+		       res->start, res->end, res->name);
+
+	nodes_clear(node_online_map);
+
+	if (system_ram->sibling)
+		printk(KERN_WARNING "Only using first memory bank\n");
+
+	for (res = system_ram; res; res = NULL) {
+		first_pfn = PFN_UP(res->start);
+		max_low_pfn = max_pfn = PFN_DOWN(res->end + 1);
+		bootmap_pfn = find_bootmap_pfn(res);
+		if (bootmap_pfn > max_pfn)
+			panic("No space for bootmem bitmap!\n");
+
+		if (max_low_pfn > MAX_LOWMEM_PFN) {
+			max_low_pfn = MAX_LOWMEM_PFN;
+#ifndef CONFIG_HIGHMEM
+			/*
+			 * Lowmem is memory that can be addressed
+			 * directly through P1/P2
+			 */
+			printk(KERN_WARNING
+			       "Node %u: Only %ld MiB of memory will be used.\n",
+			       node, MAX_LOWMEM >> 20);
+			printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n");
+#else
+#error HIGHMEM is not supported by AVR32 yet
+#endif
+		}
+
+		/* Initialize the boot-time allocator with low memory only. */
+		bootmap_size = init_bootmem_node(NODE_DATA(node), bootmap_pfn,
+						 first_pfn, max_low_pfn);
+
+		/*
+		 * Register fully available RAM pages with the bootmem
+		 * allocator.
+		 */
+		pages = max_low_pfn - first_pfn;
+		free_bootmem_node (NODE_DATA(node), PFN_PHYS(first_pfn),
+				   PFN_PHYS(pages));
+
+		/* Reserve space for the bootmem bitmap... */
+		reserve_bootmem_node(NODE_DATA(node),
+				     PFN_PHYS(bootmap_pfn),
+				     bootmap_size);
+
+		/* ...and any other reserved regions. */
+		for (res = reserved; res; res = res->sibling) {
+			if (res->start > PFN_PHYS(max_pfn))
+				break;
+
+			/*
+			 * resource_init will complain about partial
+			 * overlaps, so we'll just ignore such
+			 * resources for now.
+			 */
+			if (res->start >= PFN_PHYS(first_pfn)
+			    && res->end < PFN_PHYS(max_pfn))
+				reserve_bootmem_node(
+					NODE_DATA(node), res->start,
+					res->end - res->start + 1);
+		}
+
+		node_set_online(node);
+	}
+}
+
 void __init setup_arch (char **cmdline_p)
 {
 	struct clk *cpu_clk;
 
+	init_mm.start_code = (unsigned long)_text;
+	init_mm.end_code = (unsigned long)_etext;
+	init_mm.end_data = (unsigned long)_edata;
+	init_mm.brk = (unsigned long)_end;
+
+	/*
+	 * Include .init section to make allocations easier. It will
+	 * be removed before the resource is actually requested.
+	 */
+	kernel_code.start = __pa(__init_begin);
+	kernel_code.end = __pa(init_mm.end_code - 1);
+	kernel_data.start = __pa(init_mm.end_code);
+	kernel_data.end = __pa(init_mm.brk - 1);
+
 	parse_tags(bootloader_tags);
 
 	setup_processor();
@@ -289,24 +555,16 @@ void __init setup_arch (char **cmdline_p)
 		       ((cpu_hz + 500) / 1000) % 1000);
 	}
 
-	init_mm.start_code = (unsigned long) &_text;
-	init_mm.end_code = (unsigned long) &_etext;
-	init_mm.end_data = (unsigned long) &_edata;
-	init_mm.brk = (unsigned long) &_end;
-
 	strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
 	*cmdline_p = command_line;
 	parse_early_param();
 
 	setup_bootmem();
 
-	board_setup_fbmem(fbmem_start, fbmem_size);
-
 #ifdef CONFIG_VT
 	conswitchp = &dummy_con;
 #endif
 
 	paging_init();
-
 	resource_init();
 }
diff --git a/arch/avr32/kernel/time.c b/arch/avr32/kernel/time.c
index c10833f..7014a35 100644
--- a/arch/avr32/kernel/time.c
+++ b/arch/avr32/kernel/time.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004-2006 Atmel Corporation
+ * Copyright (C) 2004-2007 Atmel Corporation
  *
  * Based on MIPS implementation arch/mips/kernel/time.c
  *   Copyright 2001 MontaVista Software Inc.
@@ -20,18 +20,25 @@
 #include <linux/init.h>
 #include <linux/profile.h>
 #include <linux/sysdev.h>
+#include <linux/err.h>
 
 #include <asm/div64.h>
 #include <asm/sysreg.h>
 #include <asm/io.h>
 #include <asm/sections.h>
 
-static cycle_t read_cycle_count(void)
+/* how many counter cycles in a jiffy? */
+static u32 cycles_per_jiffy;
+
+/* the count value for the next timer interrupt */
+static u32 expirelo;
+
+cycle_t __weak read_cycle_count(void)
 {
 	return (cycle_t)sysreg_read(COUNT);
 }
 
-static struct clocksource clocksource_avr32 = {
+struct clocksource __weak clocksource_avr32 = {
 	.name		= "avr32",
 	.rating		= 350,
 	.read		= read_cycle_count,
@@ -40,12 +47,20 @@ static struct clocksource clocksource_avr32 = {
 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
+irqreturn_t __weak timer_interrupt(int irq, void *dev_id);
+
+struct irqaction timer_irqaction = {
+	.handler	= timer_interrupt,
+	.flags		= IRQF_DISABLED,
+	.name		= "timer",
+};
+
 /*
  * By default we provide the null RTC ops
  */
 static unsigned long null_rtc_get_time(void)
 {
-	return mktime(2004, 1, 1, 0, 0, 0);
+	return mktime(2007, 1, 1, 0, 0, 0);
 }
 
 static int null_rtc_set_time(unsigned long sec)
@@ -56,23 +71,14 @@ static int null_rtc_set_time(unsigned long sec)
 static unsigned long (*rtc_get_time)(void) = null_rtc_get_time;
 static int (*rtc_set_time)(unsigned long) = null_rtc_set_time;
 
-/* how many counter cycles in a jiffy? */
-static unsigned long cycles_per_jiffy;
-
-/* cycle counter value at the previous timer interrupt */
-static unsigned int timerhi, timerlo;
-
-/* the count value for the next timer interrupt */
-static unsigned int expirelo;
-
 static void avr32_timer_ack(void)
 {
-	unsigned int count;
+	u32 count;
 
 	/* Ack this timer interrupt and set the next one */
 	expirelo += cycles_per_jiffy;
+	/* setting COMPARE to 0 stops the COUNT-COMPARE */
 	if (expirelo == 0) {
-		printk(KERN_DEBUG "expirelo == 0\n");
 		sysreg_write(COMPARE, expirelo + 1);
 	} else {
 		sysreg_write(COMPARE, expirelo);
@@ -86,27 +92,56 @@ static void avr32_timer_ack(void)
 	}
 }
 
-static unsigned int avr32_hpt_read(void)
+int __weak avr32_hpt_init(void)
 {
-	return sysreg_read(COUNT);
+	int ret;
+	unsigned long mult, shift, count_hz;
+
+	count_hz = clk_get_rate(boot_cpu_data.clk);
+	shift = clocksource_avr32.shift;
+	mult = clocksource_hz2mult(count_hz, shift);
+	clocksource_avr32.mult = mult;
+
+	{
+		u64 tmp;
+
+		tmp = TICK_NSEC;
+		tmp <<= shift;
+		tmp += mult / 2;
+		do_div(tmp, mult);
+
+		cycles_per_jiffy = tmp;
+	}
+
+	ret = setup_irq(0, &timer_irqaction);
+	if (ret) {
+		pr_debug("timer: could not request IRQ 0: %d\n", ret);
+		return -ENODEV;
+	}
+
+	printk(KERN_INFO "timer: AT32AP COUNT-COMPARE at irq 0, "
+			"%lu.%03lu MHz\n",
+			((count_hz + 500) / 1000) / 1000,
+			((count_hz + 500) / 1000) % 1000);
+
+	return 0;
 }
 
 /*
  * Taken from MIPS c0_hpt_timer_init().
  *
- * Why is it so complicated, and what is "count"?  My assumption is
- * that `count' specifies the "reference cycle", i.e. the cycle since
- * reset that should mean "zero". The reason COUNT is written twice is
- * probably to make sure we don't get any timer interrupts while we
- * are messing with the counter.
+ * The reason COUNT is written twice is probably to make sure we don't get any
+ * timer interrupts while we are messing with the counter.
  */
-static void avr32_hpt_init(unsigned int count)
+int __weak avr32_hpt_start(void)
 {
-	count = sysreg_read(COUNT) - count;
+	u32 count = sysreg_read(COUNT);
 	expirelo = (count / cycles_per_jiffy + 1) * cycles_per_jiffy;
 	sysreg_write(COUNT, expirelo - cycles_per_jiffy);
 	sysreg_write(COMPARE, expirelo);
 	sysreg_write(COUNT, count);
+
+	return 0;
 }
 
 /*
@@ -115,26 +150,18 @@ static void avr32_hpt_init(unsigned int count)
  *
  * In UP mode, it is invoked from the (global) timer_interrupt.
  */
-static void local_timer_interrupt(int irq, void *dev_id)
+void local_timer_interrupt(int irq, void *dev_id)
 {
 	if (current->pid)
 		profile_tick(CPU_PROFILING);
 	update_process_times(user_mode(get_irq_regs()));
 }
 
-static irqreturn_t
-timer_interrupt(int irq, void *dev_id)
+irqreturn_t __weak timer_interrupt(int irq, void *dev_id)
 {
-	unsigned int count;
-
 	/* ack timer interrupt and try to set next interrupt */
-	count = avr32_hpt_read();
 	avr32_timer_ack();
 
-	/* Update timerhi/timerlo for intra-jiffy calibration */
-	timerhi += count < timerlo;	/* Wrap around */
-	timerlo = count;
-
 	/*
 	 * Call the generic timer interrupt handler
 	 */
@@ -153,60 +180,37 @@ timer_interrupt(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-static struct irqaction timer_irqaction = {
-	.handler	= timer_interrupt,
-	.flags		= IRQF_DISABLED,
-	.name		= "timer",
-};
-
 void __init time_init(void)
 {
-	unsigned long mult, shift, count_hz;
 	int ret;
 
+	/*
+	 * Make sure we don't get any COMPARE interrupts before we can
+	 * handle them.
+	 */
+	sysreg_write(COMPARE, 0);
+
 	xtime.tv_sec = rtc_get_time();
 	xtime.tv_nsec = 0;
 
 	set_normalized_timespec(&wall_to_monotonic,
 				-xtime.tv_sec, -xtime.tv_nsec);
 
-	printk("Before time_init: count=%08lx, compare=%08lx\n",
-	       (unsigned long)sysreg_read(COUNT),
-	       (unsigned long)sysreg_read(COMPARE));
-
-	count_hz = clk_get_rate(boot_cpu_data.clk);
-	shift = clocksource_avr32.shift;
-	mult = clocksource_hz2mult(count_hz, shift);
-	clocksource_avr32.mult = mult;
-
-	printk("Cycle counter: mult=%lu, shift=%lu\n", mult, shift);
-
-	{
-		u64 tmp;
-
-		tmp = TICK_NSEC;
-		tmp <<= shift;
-		tmp += mult / 2;
-		do_div(tmp, mult);
-
-		cycles_per_jiffy = tmp;
+	ret = avr32_hpt_init();
+	if (ret) {
+		pr_debug("timer: failed setup: %d\n", ret);
+		return;
 	}
 
-	/* This sets up the high precision timer for the first interrupt. */
-	avr32_hpt_init(avr32_hpt_read());
-
-	printk("After time_init: count=%08lx, compare=%08lx\n",
-	       (unsigned long)sysreg_read(COUNT),
-	       (unsigned long)sysreg_read(COMPARE));
-
 	ret = clocksource_register(&clocksource_avr32);
 	if (ret)
-		printk(KERN_ERR
-		       "timer: could not register clocksource: %d\n", ret);
+		pr_debug("timer: could not register clocksource: %d\n", ret);
 
-	ret = setup_irq(0, &timer_irqaction);
-	if (ret)
-		printk("timer: could not request IRQ 0: %d\n", ret);
+	ret = avr32_hpt_start();
+	if (ret) {
+		pr_debug("timer: failed starting: %d\n", ret);
+		return;
+	}
 }
 
 static struct sysdev_class timer_class = {
diff --git a/arch/avr32/kernel/traps.c b/arch/avr32/kernel/traps.c
index adc01a1..4d7ae14 100644
--- a/arch/avr32/kernel/traps.c
+++ b/arch/avr32/kernel/traps.c
@@ -5,158 +5,25 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#undef DEBUG
-#include <linux/sched.h>
+
+#include <linux/bug.h>
 #include <linux/init.h>
-#include <linux/module.h>
 #include <linux/kallsyms.h>
+#include <linux/module.h>
 #include <linux/notifier.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
 
-#include <asm/traps.h>
-#include <asm/sysreg.h>
 #include <asm/addrspace.h>
-#include <asm/ocd.h>
 #include <asm/mmu_context.h>
-#include <asm/uaccess.h>
-
-static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
-{
-	unsigned long p;
-	int i;
-
-	printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
-
-	for (p = bottom & ~31; p < top; ) {
-		printk("%04lx: ", p & 0xffff);
-
-		for (i = 0; i < 8; i++, p += 4) {
-			unsigned int val;
-
-			if (p < bottom || p >= top)
-				printk("         ");
-			else {
-				if (__get_user(val, (unsigned int __user *)p)) {
-					printk("\n");
-					goto out;
-				}
-				printk("%08x ", val);
-			}
-		}
-		printk("\n");
-	}
-
-out:
-	return;
-}
-
-static inline int valid_stack_ptr(struct thread_info *tinfo, unsigned long p)
-{
-	return (p > (unsigned long)tinfo)
-		&& (p < (unsigned long)tinfo + THREAD_SIZE - 3);
-}
-
-#ifdef CONFIG_FRAME_POINTER
-static inline void __show_trace(struct task_struct *tsk, unsigned long *sp,
-				struct pt_regs *regs)
-{
-	unsigned long lr, fp;
-	struct thread_info *tinfo;
-
-	tinfo = (struct thread_info *)
-		((unsigned long)sp & ~(THREAD_SIZE - 1));
-
-	if (regs)
-		fp = regs->r7;
-	else if (tsk == current)
-		asm("mov %0, r7" : "=r"(fp));
-	else
-		fp = tsk->thread.cpu_context.r7;
-
-	/*
-	 * Walk the stack as long as the frame pointer (a) is within
-	 * the kernel stack of the task, and (b) it doesn't move
-	 * downwards.
-	 */
-	while (valid_stack_ptr(tinfo, fp)) {
-		unsigned long new_fp;
-
-		lr = *(unsigned long *)fp;
-		printk(" [<%08lx>] ", lr);
-		print_symbol("%s\n", lr);
-
-		new_fp = *(unsigned long *)(fp + 4);
-		if (new_fp <= fp)
-			break;
-		fp = new_fp;
-	}
-	printk("\n");
-}
-#else
-static inline void __show_trace(struct task_struct *tsk, unsigned long *sp,
-				struct pt_regs *regs)
-{
-	unsigned long addr;
-
-	while (!kstack_end(sp)) {
-		addr = *sp++;
-		if (kernel_text_address(addr)) {
-			printk(" [<%08lx>] ", addr);
-			print_symbol("%s\n", addr);
-		}
-	}
-}
-#endif
-
-void show_trace(struct task_struct *tsk, unsigned long *sp,
-		       struct pt_regs *regs)
-{
-	if (regs &&
-	    (((regs->sr & MODE_MASK) == MODE_EXCEPTION) ||
-	     ((regs->sr & MODE_MASK) == MODE_USER)))
-		return;
-
-	printk ("Call trace:");
-#ifdef CONFIG_KALLSYMS
-	printk("\n");
-#endif
-
-	__show_trace(tsk, sp, regs);
-	printk("\n");
-}
-
-void show_stack(struct task_struct *tsk, unsigned long *sp)
-{
-	unsigned long stack;
-
-	if (!tsk)
-		tsk = current;
-	if (sp == 0) {
-		if (tsk == current) {
-			register unsigned long *real_sp __asm__("sp");
-			sp = real_sp;
-		} else {
-			sp = (unsigned long *)tsk->thread.cpu_context.ksp;
-		}
-	}
-
-	stack = (unsigned long)sp;
-	dump_mem("Stack: ", stack,
-		 THREAD_SIZE + (unsigned long)tsk->thread_info);
-	show_trace(tsk, sp, NULL);
-}
-
-void dump_stack(void)
-{
-	show_stack(NULL, NULL);
-}
-EXPORT_SYMBOL(dump_stack);
+#include <asm/ocd.h>
+#include <asm/sysreg.h>
+#include <asm/traps.h>
 
 ATOMIC_NOTIFIER_HEAD(avr32_die_chain);
 
 int register_die_notifier(struct notifier_block *nb)
 {
-	pr_debug("register_die_notifier: %p\n", nb);
-
 	return atomic_notifier_chain_register(&avr32_die_chain, nb);
 }
 EXPORT_SYMBOL(register_die_notifier);
@@ -169,98 +36,108 @@ EXPORT_SYMBOL(unregister_die_notifier);
 
 static DEFINE_SPINLOCK(die_lock);
 
-void __die(const char *str, struct pt_regs *regs, unsigned long err,
-	   const char *file, const char *func, unsigned long line)
+void NORET_TYPE die(const char *str, struct pt_regs *regs, long err)
 {
-	struct task_struct *tsk = current;
 	static int die_counter;
 
 	console_verbose();
 	spin_lock_irq(&die_lock);
 	bust_spinlocks(1);
 
-	printk(KERN_ALERT "%s", str);
-	if (file && func)
-		printk(" in %s:%s, line %ld", file, func, line);
-	printk("[#%d]:\n", ++die_counter);
-	print_modules();
-	show_regs(regs);
-	printk("Process %s (pid: %d, stack limit = 0x%p)\n",
-	       tsk->comm, tsk->pid, tsk->thread_info + 1);
-
-	if (!user_mode(regs) || in_interrupt()) {
-		dump_mem("Stack: ", regs->sp,
-			 THREAD_SIZE + (unsigned long)tsk->thread_info);
+	printk(KERN_ALERT "Oops: %s, sig: %ld [#%d]\n" KERN_EMERG,
+	       str, err, ++die_counter);
+#ifdef CONFIG_PREEMPT
+	printk("PREEMPT ");
+#endif
+#ifdef CONFIG_FRAME_POINTER
+	printk("FRAME_POINTER ");
+#endif
+	if (current_cpu_data.features & AVR32_FEATURE_OCD) {
+		unsigned long did = __mfdr(DBGREG_DID);
+		printk("chip: 0x%03lx:0x%04lx rev %lu\n",
+		       (did >> 1) & 0x7ff,
+		       (did >> 12) & 0x7fff,
+		       (did >> 28) & 0xf);
+	} else {
+		printk("cpu: arch %u r%u / core %u r%u\n",
+		       current_cpu_data.arch_type,
+		       current_cpu_data.arch_revision,
+		       current_cpu_data.cpu_type,
+		       current_cpu_data.cpu_revision);
 	}
 
+	print_modules();
+	show_regs_log_lvl(regs, KERN_EMERG);
+	show_stack_log_lvl(current, regs->sp, regs, KERN_EMERG);
 	bust_spinlocks(0);
 	spin_unlock_irq(&die_lock);
-	do_exit(SIGSEGV);
+
+	if (in_interrupt())
+		panic("Fatal exception in interrupt");
+
+	if (panic_on_oops)
+		panic("Fatal exception");
+
+	do_exit(err);
 }
 
-void __die_if_kernel(const char *str, struct pt_regs *regs, unsigned long err,
-		     const char *file, const char *func, unsigned long line)
+void _exception(long signr, struct pt_regs *regs, int code,
+		unsigned long addr)
 {
+	siginfo_t info;
+
 	if (!user_mode(regs))
-		__die(str, regs, err, file, func, line);
-}
+		die("Unhandled exception in kernel mode", regs, signr);
+
+	memset(&info, 0, sizeof(info));
+	info.si_signo = signr;
+	info.si_code = code;
+	info.si_addr = (void __user *)addr;
+	force_sig_info(signr, &info, current);
 
-asmlinkage void do_nmi(unsigned long ecr, struct pt_regs *regs)
-{
-#ifdef CONFIG_SUBARCH_AVR32B
 	/*
-	 * The exception entry always saves RSR_EX. For NMI, this is
-	 * wrong; it should be RSR_NMI
+	 * Init gets no signals that it doesn't have a handler for.
+	 * That's all very well, but if it has caused a synchronous
+	 * exception and we ignore the resulting signal, it will just
+	 * generate the same exception over and over again and we get
+	 * nowhere.  Better to kill it and let the kernel panic.
 	 */
-	regs->sr = sysreg_read(RSR_NMI);
-#endif
+	if (is_init(current)) {
+		__sighandler_t handler;
+
+		spin_lock_irq(&current->sighand->siglock);
+		handler = current->sighand->action[signr-1].sa.sa_handler;
+		spin_unlock_irq(&current->sighand->siglock);
+		if (handler == SIG_DFL) {
+			/* init has generated a synchronous exception
+			   and it doesn't have a handler for the signal */
+			printk(KERN_CRIT "init has generated signal %ld "
+			       "but has no handler for it\n", signr);
+			do_exit(signr);
+		}
+	}
+}
 
-	printk("NMI taken!!!!\n");
-	die("NMI", regs, ecr);
-	BUG();
+asmlinkage void do_nmi(unsigned long ecr, struct pt_regs *regs)
+{
+	printk(KERN_ALERT "Got Non-Maskable Interrupt, dumping regs\n");
+	show_regs_log_lvl(regs, KERN_ALERT);
+	show_stack_log_lvl(current, regs->sp, regs, KERN_ALERT);
 }
 
 asmlinkage void do_critical_exception(unsigned long ecr, struct pt_regs *regs)
 {
-	printk("Unable to handle critical exception %lu at pc = %08lx!\n",
-	       ecr, regs->pc);
-	die("Oops", regs, ecr);
-	BUG();
+	die("Critical exception", regs, SIGKILL);
 }
 
 asmlinkage void do_address_exception(unsigned long ecr, struct pt_regs *regs)
 {
-	siginfo_t info;
-
-	die_if_kernel("Oops: Address exception in kernel mode", regs, ecr);
-
-#ifdef DEBUG
-	if (ecr == ECR_ADDR_ALIGN_X)
-		pr_debug("Instruction Address Exception at pc = %08lx\n",
-			 regs->pc);
-	else if (ecr == ECR_ADDR_ALIGN_R)
-		pr_debug("Data Address Exception (Read) at pc = %08lx\n",
-			 regs->pc);
-	else if (ecr == ECR_ADDR_ALIGN_W)
-		pr_debug("Data Address Exception (Write) at pc = %08lx\n",
-			 regs->pc);
-	else
-		BUG();
-
-	show_regs(regs);
-#endif
-
-	info.si_signo = SIGBUS;
-	info.si_errno = 0;
-	info.si_code = BUS_ADRALN;
-	info.si_addr = (void __user *)regs->pc;
-
-	force_sig_info(SIGBUS, &info, current);
+	_exception(SIGBUS, regs, BUS_ADRALN, regs->pc);
 }
 
 /* This way of handling undefined instructions is stolen from ARM */
 static LIST_HEAD(undef_hook);
-static spinlock_t undef_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(undef_lock);
 
 void register_undef_hook(struct undef_hook *hook)
 {
@@ -280,7 +157,8 @@ static int do_cop_absent(u32 insn)
 {
 	int cop_nr;
 	u32 cpucr;
-	if ( (insn & 0xfdf00000) == 0xf1900000 )
+
+	if ((insn & 0xfdf00000) == 0xf1900000)
 		/* LDC0 */
 		cop_nr = 0;
 	else
@@ -292,136 +170,91 @@ static int do_cop_absent(u32 insn)
 	sysreg_write(CPUCR, cpucr);
 
 	cpucr = sysreg_read(CPUCR);
-	if ( !(cpucr & (1 << (24 + cop_nr))) ){
-		printk("Coprocessor #%i not found!\n", cop_nr);
-		return -1;
-	}
+	if (!(cpucr & (1 << (24 + cop_nr))))
+		return -ENODEV;
 
 	return 0;
 }
 
-#ifdef CONFIG_BUG
-#ifdef CONFIG_DEBUG_BUGVERBOSE
-static inline void do_bug_verbose(struct pt_regs *regs, u32 insn)
-{
-	char *file;
-	u16 line;
-	char c;
-
-	if (__get_user(line, (u16 __user *)(regs->pc + 2)))
-		return;
-	if (__get_user(file, (char * __user *)(regs->pc + 4))
-	    || (unsigned long)file < PAGE_OFFSET
-	    || __get_user(c, file))
-		file = "<bad filename>";
-
-	printk(KERN_ALERT "kernel BUG at %s:%d!\n", file, line);
-}
-#else
-static inline void do_bug_verbose(struct pt_regs *regs, u32 insn)
+int is_valid_bugaddr(unsigned long pc)
 {
+	unsigned short opcode;
+
+	if (pc < PAGE_OFFSET)
+		return 0;
+	if (probe_kernel_address((u16 *)pc, opcode))
+		return 0;
 
+	return opcode == AVR32_BUG_OPCODE;
 }
-#endif
-#endif
 
 asmlinkage void do_illegal_opcode(unsigned long ecr, struct pt_regs *regs)
 {
 	u32 insn;
 	struct undef_hook *hook;
-	siginfo_t info;
 	void __user *pc;
+	long code;
 
-	if (!user_mode(regs))
-		goto kernel_trap;
+	if (!user_mode(regs) && (ecr == ECR_ILLEGAL_OPCODE)) {
+		enum bug_trap_type type;
+
+		type = report_bug(regs->pc);
+		switch (type) {
+		case BUG_TRAP_TYPE_NONE:
+			break;
+		case BUG_TRAP_TYPE_WARN:
+			regs->pc += 2;
+			return;
+		case BUG_TRAP_TYPE_BUG:
+			die("Kernel BUG", regs, SIGKILL);
+		}
+	}
 
 	local_irq_enable();
 
-	pc = (void __user *)instruction_pointer(regs);
-	if (__get_user(insn, (u32 __user *)pc))
-		goto invalid_area;
+	if (user_mode(regs)) {
+		pc = (void __user *)instruction_pointer(regs);
+		if (get_user(insn, (u32 __user *)pc))
+			goto invalid_area;
 
-        if (ecr == ECR_COPROC_ABSENT) {
-		if (do_cop_absent(insn) == 0)
+		if (ecr == ECR_COPROC_ABSENT && !do_cop_absent(insn))
 			return;
-        }
 
-	spin_lock_irq(&undef_lock);
-	list_for_each_entry(hook, &undef_hook, node) {
-		if ((insn & hook->insn_mask) == hook->insn_val) {
-			if (hook->fn(regs, insn) == 0) {
-				spin_unlock_irq(&undef_lock);
-				return;
+		spin_lock_irq(&undef_lock);
+		list_for_each_entry(hook, &undef_hook, node) {
+			if ((insn & hook->insn_mask) == hook->insn_val) {
+				if (hook->fn(regs, insn) == 0) {
+					spin_unlock_irq(&undef_lock);
+					return;
+				}
 			}
 		}
+		spin_unlock_irq(&undef_lock);
 	}
-	spin_unlock_irq(&undef_lock);
-
-invalid_area:
 
-#ifdef DEBUG
-	printk("Illegal instruction at pc = %08lx\n", regs->pc);
-	if (regs->pc < TASK_SIZE) {
-		unsigned long ptbr, pgd, pte, *p;
-
-		ptbr = sysreg_read(PTBR);
-		p = (unsigned long *)ptbr;
-		pgd = p[regs->pc >> 22];
-		p = (unsigned long *)((pgd & 0x1ffff000) | 0x80000000);
-		pte = p[(regs->pc >> 12) & 0x3ff];
-		printk("page table: 0x%08lx -> 0x%08lx -> 0x%08lx\n", ptbr, pgd, pte);
-	}
-#endif
-
-	info.si_signo = SIGILL;
-	info.si_errno = 0;
-	info.si_addr = (void __user *)regs->pc;
 	switch (ecr) {
-	case ECR_ILLEGAL_OPCODE:
-	case ECR_UNIMPL_INSTRUCTION:
-		info.si_code = ILL_ILLOPC;
-		break;
 	case ECR_PRIVILEGE_VIOLATION:
-		info.si_code = ILL_PRVOPC;
+		code = ILL_PRVOPC;
 		break;
 	case ECR_COPROC_ABSENT:
-		info.si_code = ILL_COPROC;
+		code = ILL_COPROC;
 		break;
 	default:
-		BUG();
+		code = ILL_ILLOPC;
+		break;
 	}
 
-	force_sig_info(SIGILL, &info, current);
+	_exception(SIGILL, regs, code, regs->pc);
 	return;
 
-kernel_trap:
-#ifdef CONFIG_BUG
-	if (__kernel_text_address(instruction_pointer(regs))) {
-		insn = *(u16 *)instruction_pointer(regs);
-		if (insn == AVR32_BUG_OPCODE) {
-			do_bug_verbose(regs, insn);
-			die("Kernel BUG", regs, 0);
-			return;
-		}
-	}
-#endif
-
-	die("Oops: Illegal instruction in kernel code", regs, ecr);
+invalid_area:
+	_exception(SIGSEGV, regs, SEGV_MAPERR, regs->pc);
 }
 
 asmlinkage void do_fpe(unsigned long ecr, struct pt_regs *regs)
 {
-	siginfo_t info;
-
-	printk("Floating-point exception at pc = %08lx\n", regs->pc);
-
-	/* We have no FPU... */
-	info.si_signo = SIGILL;
-	info.si_errno = 0;
-	info.si_addr = (void __user *)regs->pc;
-	info.si_code = ILL_COPROC;
-
-	force_sig_info(SIGILL, &info, current);
+	/* We have no FPU yet */
+	_exception(SIGILL, regs, ILL_COPROC, regs->pc);
 }
 
 
diff --git a/arch/avr32/kernel/vmlinux.lds.c b/arch/avr32/kernel/vmlinux.lds.c
index ef13b7c..e7f72c9 100644
--- a/arch/avr32/kernel/vmlinux.lds.c
+++ b/arch/avr32/kernel/vmlinux.lds.c
@@ -26,10 +26,16 @@ SECTIONS
 			_sinittext = .;
 			*(.text.reset)
 			*(.init.text)
+			/*
+			 * .exit.text is discarded at runtime, not
+			 * link time, to deal with references from
+			 * __bug_table
+			 */
+			*(.exit.text)
 			_einittext = .;
 		. = ALIGN(4);
 		__tagtable_begin = .;
-			*(.taglist)
+			*(.taglist.init)
 		__tagtable_end = .;
 			*(.init.data)
 		. = ALIGN(16);
@@ -86,6 +92,8 @@ SECTIONS
 		__stop___ex_table = .;
 	}
 
+	BUG_TABLE
+
 	RODATA
 
 	. = ALIGN(8192);
@@ -126,7 +134,6 @@ SECTIONS
 	 * thrown away, as cleanup code is never called unless it's a module.
 	 */
 	/DISCARD/       	: {
-		*(.exit.text)
 		*(.exit.data)
 		*(.exitcall.exit)
 	}
diff --git a/arch/avr32/mach-at32ap/Kconfig b/arch/avr32/mach-at32ap/Kconfig
new file mode 100644
index 0000000..eb30783
--- /dev/null
+++ b/arch/avr32/mach-at32ap/Kconfig
@@ -0,0 +1,31 @@
+if PLATFORM_AT32AP
+
+menu "Atmel AVR32 AP options"
+
+choice
+	prompt "AT32AP7000 static memory bus width"
+	depends on CPU_AT32AP7000
+	default AP7000_16_BIT_SMC
+	help
+	  Define the width of the AP7000 external static memory interface.
+	  This is used to determine how to mangle the address and/or data
+	  when doing little-endian port access.
+
+	  The current code can only support a single external memory bus
+	  width for all chip selects, excluding the flash (which is using
+	  raw access and is thus not affected by any of this.)
+
+config AP7000_32_BIT_SMC
+	bool "32 bit"
+
+config AP7000_16_BIT_SMC
+	bool "16 bit"
+
+config AP7000_8_BIT_SMC
+	bool "8 bit"
+
+endchoice
+
+endmenu
+
+endif # PLATFORM_AT32AP
diff --git a/arch/avr32/mach-at32ap/Makefile b/arch/avr32/mach-at32ap/Makefile
index b21bea9..f1d3957 100644
--- a/arch/avr32/mach-at32ap/Makefile
+++ b/arch/avr32/mach-at32ap/Makefile
@@ -1,2 +1,3 @@
 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
diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c
index 472703f..028883f 100644
--- a/arch/avr32/mach-at32ap/at32ap7000.c
+++ b/arch/avr32/mach-at32ap/at32ap7000.c
@@ -6,6 +6,7 @@
  * published by the Free Software Foundation.
  */
 #include <linux/clk.h>
+#include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
@@ -17,7 +18,10 @@
 #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"
 
@@ -407,8 +411,6 @@ static void __init genclk_init_parent(struct clk *clk)
 static struct resource sm_resource[] = {
 	PBMEM(0xfff00000),
 	NAMED_IRQ(19, "eim"),
-	NAMED_IRQ(20, "pm"),
-	NAMED_IRQ(21, "rtc"),
 };
 struct platform_device at32_sm_device = {
 	.name		= "sm",
@@ -416,7 +418,55 @@ struct platform_device at32_sm_device = {
 	.resource	= sm_resource,
 	.num_resources	= ARRAY_SIZE(sm_resource),
 };
-DEV_CLK(pclk, at32_sm, pbb, 0);
+static struct clk at32_sm_pclk = {
+	.name		= "pclk",
+	.dev		= &at32_sm_device.dev,
+	.parent		= &pbb_clk,
+	.mode		= pbb_clk_mode,
+	.get_rate	= pbb_clk_get_rate,
+	.users		= 1,
+	.index		= 0,
+};
+
+static struct resource pm_resource[] = {
+	PBMEM(0xfff00000),
+	IRQ(20),
+};
+struct platform_device at32_pm_device = {
+	.name		= "pm",
+	.id		= 0,
+	.resource	= pm_resource,
+	.num_resources	= ARRAY_SIZE(pm_resource),
+};
+
+static struct resource rtc_resource[] = {
+	{
+		.start	= 0xfff00080,
+		.end	= 0xfff000a3,
+		.flags	= IORESOURCE_MEM,
+	},
+	IRQ(21),
+};
+struct platform_device at32_rtc_device = {
+	.name		= "rtc",
+	.id		= 0,
+	.resource	= rtc_resource,
+	.num_resources	= ARRAY_SIZE(rtc_resource),
+};
+
+static struct resource wdt_resource[] = {
+	{
+		.start	= 0xfff000b0,
+		.end	= 0xfff000b7,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+struct platform_device at32_wdt_device = {
+	.name		= "wdt",
+	.id		= 0,
+	.resource	= wdt_resource,
+	.num_resources	= ARRAY_SIZE(wdt_resource),
+};
 
 static struct resource intc0_resource[] = {
 	PBMEM(0xfff00400),
@@ -442,6 +492,7 @@ static struct clk hramc_clk = {
 	.mode		= hsb_clk_mode,
 	.get_rate	= hsb_clk_get_rate,
 	.users		= 1,
+	.index		= 3,
 };
 
 static struct resource smc0_resource[] = {
@@ -466,6 +517,68 @@ static struct clk pico_clk = {
 	.users		= 1,
 };
 
+static struct resource dmaca0_resource[] = {
+	{
+		.start	= 0xff200000,
+		.end	= 0xff20ffff,
+		.flags	= IORESOURCE_MEM,
+	},
+	IRQ(2),
+};
+DEFINE_DEV(dmaca, 0);
+DEV_CLK(hclk, dmaca0, hsb, 10);
+
+/* --------------------------------------------------------------------
+ * HMATRIX
+ * -------------------------------------------------------------------- */
+
+static struct clk hmatrix_clk = {
+	.name		= "hmatrix_clk",
+	.parent		= &pbb_clk,
+	.mode		= pbb_clk_mode,
+	.get_rate	= pbb_clk_get_rate,
+	.index		= 2,
+	.users		= 1,
+};
+#define HMATRIX_BASE	((void __iomem *)0xfff00800)
+
+#define hmatrix_readl(reg)					\
+	__raw_readl((HMATRIX_BASE) + HMATRIX_##reg)
+#define hmatrix_writel(reg,value)				\
+	__raw_writel((value), (HMATRIX_BASE) + HMATRIX_##reg)
+
+/*
+ * Set bits in the HMATRIX Special Function Register (SFR) used by the
+ * External Bus Interface (EBI). This can be used to enable special
+ * features like CompactFlash support, NAND Flash support, etc. on
+ * certain chipselects.
+ */
+static inline void set_ebi_sfr_bits(u32 mask)
+{
+	u32 sfr;
+
+	clk_enable(&hmatrix_clk);
+	sfr = hmatrix_readl(SFR4);
+	sfr |= mask;
+	hmatrix_writel(SFR4, sfr);
+	clk_disable(&hmatrix_clk);
+}
+
+/* --------------------------------------------------------------------
+ *  System Timer/Counter (TC)
+ * -------------------------------------------------------------------- */
+static struct resource at32_systc0_resource[] = {
+	PBMEM(0xfff00c00),
+	IRQ(22),
+};
+struct platform_device at32_systc0_device = {
+	.name		= "systc",
+	.id		= 0,
+	.resource	= at32_systc0_resource,
+	.num_resources	= ARRAY_SIZE(at32_systc0_resource),
+};
+DEV_CLK(pclk, at32_systc0, pbb, 3);
+
 /* --------------------------------------------------------------------
  *  PIO
  * -------------------------------------------------------------------- */
@@ -510,9 +623,15 @@ 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_pm_device);
+	platform_device_register(&at32_rtc_device);
+	platform_device_register(&at32_wdt_device);
 	platform_device_register(&at32_intc0_device);
 	platform_device_register(&smc0_device);
 	platform_device_register(&pdc_device);
+	platform_device_register(&dmaca0_device);
+
+	platform_device_register(&at32_systc0_device);
 
 	platform_device_register(&pio0_device);
 	platform_device_register(&pio1_device);
@@ -816,22 +935,105 @@ at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
 }
 
 /* --------------------------------------------------------------------
+ *  TWI
+ * -------------------------------------------------------------------- */
+
+static struct resource atmel_twi0_resource[] = {
+	PBMEM(0xffe00800),
+	IRQ(5),
+};
+DEFINE_DEV(atmel_twi, 0);
+DEV_CLK(pclk,atmel_twi0,pba,2);
+
+struct platform_device *__init
+at32_add_device_twi(unsigned int id)
+{
+	struct platform_device *pdev;
+
+	switch (id) {
+	case 0:
+		pdev = &atmel_twi0_device;
+		select_peripheral(PA(6),  PERIPH_A, 0);	/* SDA	*/
+		select_peripheral(PA(7),  PERIPH_A, 0);	/* SCL	*/
+		break;
+
+	default:
+		return NULL;
+	}
+
+	platform_device_register(pdev);
+	return pdev;
+}
+
+/* --------------------------------------------------------------------
+ * MMC
+ * -------------------------------------------------------------------- */
+static struct mci_platform_data atmel_mci0_data = {
+	.detect_pin	= GPIO_PIN_NONE,
+	.wp_pin		= GPIO_PIN_NONE,
+};
+static struct resource atmel_mci0_resource[] = {
+	PBMEM(0xfff02400),
+	IRQ(28),
+};
+DEFINE_DEV_DATA(atmel_mci, 0);
+DEV_CLK(mci_clk, atmel_mci0, pbb, 9);
+
+struct platform_device *__init
+at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
+{
+	struct platform_device *pdev;
+
+	switch (id) {
+	case 0:
+		pdev = &atmel_mci0_device;
+		select_peripheral(PA(10), PERIPH_A, 0);	/* CLK	 */
+		select_peripheral(PA(11), PERIPH_A, 0);	/* CMD	 */
+		select_peripheral(PA(12), PERIPH_A, 0);	/* DATA0 */
+		select_peripheral(PA(13), PERIPH_A, 0);	/* DATA1 */
+		select_peripheral(PA(14), PERIPH_A, 0);	/* DATA2 */
+		select_peripheral(PA(15), PERIPH_A, 0);	/* DATA3 */
+		break;
+	default:
+		return NULL;
+	}
+
+	if (data) {
+		if (data->detect_pin != GPIO_PIN_NONE)
+			at32_select_gpio(data->detect_pin, 0);
+		if (data->wp_pin != GPIO_PIN_NONE)
+			at32_select_gpio(data->wp_pin, 0);
+		memcpy(pdev->dev.platform_data, data,
+		       sizeof(struct mci_platform_data));
+	}
+
+	platform_device_register(pdev);
+	return pdev;
+}
+
+/* --------------------------------------------------------------------
  *  LCDC
  * -------------------------------------------------------------------- */
-static struct lcdc_platform_data lcdc0_data;
-static struct resource lcdc0_resource[] = {
+static struct atmel_lcdfb_info atmel_lcdfb0_data;
+static struct resource atmel_lcdfb0_resource[] = {
 	{
 		.start		= 0xff000000,
 		.end		= 0xff000fff,
 		.flags		= IORESOURCE_MEM,
 	},
 	IRQ(1),
+	{
+		/* Placeholder for pre-allocated fb memory */
+		.start		= 0x00000000,
+		.end		= 0x00000000,
+		.flags		= 0,
+	},
 };
-DEFINE_DEV_DATA(lcdc, 0);
-DEV_CLK(hclk, lcdc0, hsb, 7);
-static struct clk lcdc0_pixclk = {
-	.name		= "pixclk",
-	.dev		= &lcdc0_device.dev,
+DEFINE_DEV_DATA(atmel_lcdfb, 0);
+DEV_CLK(hck1, atmel_lcdfb0, hsb, 7);
+static struct clk atmel_lcdfb0_pixclk = {
+	.name		= "lcdc_clk",
+	.dev		= &atmel_lcdfb0_device.dev,
 	.mode		= genclk_mode,
 	.get_rate	= genclk_get_rate,
 	.set_rate	= genclk_set_rate,
@@ -840,13 +1042,34 @@ static struct clk lcdc0_pixclk = {
 };
 
 struct platform_device *__init
-at32_add_device_lcdc(unsigned int id, struct lcdc_platform_data *data)
+at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
+		     unsigned long fbmem_start, unsigned long fbmem_len)
 {
 	struct platform_device *pdev;
+	struct atmel_lcdfb_info *info;
+	struct fb_monspecs *monspecs;
+	struct fb_videomode *modedb;
+	unsigned int modedb_size;
+
+	/*
+	 * Do a deep copy of the fb data, monspecs and modedb. Make
+	 * sure all allocations are done before setting up the
+	 * portmux.
+	 */
+	monspecs = kmemdup(data->default_monspecs,
+			   sizeof(struct fb_monspecs), GFP_KERNEL);
+	if (!monspecs)
+		return NULL;
+
+	modedb_size = sizeof(struct fb_videomode) * monspecs->modedb_len;
+	modedb = kmemdup(monspecs->modedb, modedb_size, GFP_KERNEL);
+	if (!modedb)
+		goto err_dup_modedb;
+	monspecs->modedb = modedb;
 
 	switch (id) {
 	case 0:
-		pdev = &lcdc0_device;
+		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	  */
@@ -879,16 +1102,287 @@ at32_add_device_lcdc(unsigned int id, struct lcdc_platform_data *data)
 		select_peripheral(PD(16), PERIPH_A, 0);	/* DATA22 */
 		select_peripheral(PD(17), PERIPH_A, 0);	/* DATA23 */
 
-		clk_set_parent(&lcdc0_pixclk, &pll0);
-		clk_set_rate(&lcdc0_pixclk, clk_get_rate(&pll0));
+		clk_set_parent(&atmel_lcdfb0_pixclk, &pll0);
+		clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0));
+		break;
+
+	default:
+		goto err_invalid_id;
+	}
+
+	if (fbmem_len) {
+		pdev->resource[2].start = fbmem_start;
+		pdev->resource[2].end = fbmem_start + fbmem_len - 1;
+		pdev->resource[2].flags = IORESOURCE_MEM;
+	}
+
+	info = pdev->dev.platform_data;
+	memcpy(info, data, sizeof(struct atmel_lcdfb_info));
+	info->default_monspecs = monspecs;
+
+	platform_device_register(pdev);
+	return pdev;
+
+err_invalid_id:
+	kfree(modedb);
+err_dup_modedb:
+	kfree(monspecs);
+	return NULL;
+}
+
+/* --------------------------------------------------------------------
+ *  USB Device Controller
+ * -------------------------------------------------------------------- */
+static struct resource usba0_resource[] = {
+	{
+		.start		= 0xff300000,
+		.end		= 0xff3fffff,
+		.flags		= IORESOURCE_MEM,
+	},
+	PBMEM(0xfff03000),
+	IRQ(31),
+};
+DEFINE_DEV(usba, 0);
+DEV_CLK(pclk, usba0, pbb, 12);
+DEV_CLK(hclk, usba0, hsb, 6);
+
+struct platform_device *__init at32_add_device_usba(unsigned int id)
+{
+	struct platform_device *pdev;
+
+	switch (id) {
+	case 0:
+		pdev = &usba0_device;
+		/* USB pads are not multiplexed */
 		break;
+	default:
+		return NULL;
+	}
 
+	platform_device_register(pdev);
+	return pdev;
+}
+
+/* --------------------------------------------------------------------
+ *  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;
+}
+
+/* --------------------------------------------------------------------
+ *  AC97C
+ * -------------------------------------------------------------------- */
+static struct resource atmel_ac97c0_resource[] = {
+	PBMEM(0xfff02800),
+	IRQ(29),
+};
+DEFINE_DEV(atmel_ac97c, 0);
+DEV_CLK(pclk, atmel_ac97c0, pbb, 10);
+
+struct platform_device *__init
+at32_add_device_ac97c(unsigned int id)
+{
+	struct platform_device *pdev;
+
+	switch (id) {
+	case 0:
+		pdev = &atmel_ac97c0_device;
+		select_peripheral(PB(20), PERIPH_B, 0);	/* SYNC	*/
+		select_peripheral(PB(21), PERIPH_B, 0);	/* SDO	*/
+		select_peripheral(PB(22), PERIPH_B, 0);	/* SDI	*/
+		select_peripheral(PB(23), PERIPH_B, 0);	/* SCLK	*/
+		break;
 	default:
 		return NULL;
 	}
 
+	platform_device_register(pdev);
+	return pdev;
+}
+
+/* --------------------------------------------------------------------
+ *  DAC
+ * -------------------------------------------------------------------- */
+static struct resource abdac0_resource[] = {
+	PBMEM(0xfff02000),
+	IRQ(27),
+};
+DEFINE_DEV(abdac, 0);
+DEV_CLK(pclk, abdac0, pbb, 8);
+static struct clk abdac0_sample_clk = {
+	.name           = "sample_clk",
+	.dev            = &abdac0_device.dev,
+	.mode           = genclk_mode,
+	.get_rate       = genclk_get_rate,
+	.set_rate       = genclk_set_rate,
+	.set_parent     = genclk_set_parent,
+	.index          = 6,
+};
+
+struct platform_device *__init
+at32_add_device_abdac(unsigned int id)
+{
+	struct platform_device *pdev;
+
+	switch (id) {
+	case 0:
+		pdev = &abdac0_device;
+		select_peripheral(PB(20), PERIPH_A, 0);	/* DATA1	*/
+		select_peripheral(PB(21), PERIPH_A, 0);	/* DATA0	*/
+		select_peripheral(PB(22), PERIPH_A, 0);	/* DATAN1	*/
+		select_peripheral(PB(23), PERIPH_A, 0);	/* DATAN0	*/
+		break;
+	default:
+		return NULL;
+	}
+
+	platform_device_register(pdev);
+	return pdev;
+}
+
+/* --------------------------------------------------------------------
+ * CompactFlash
+ * -------------------------------------------------------------------- */
+static struct cf_platform_data at32_cf0_data;
+static struct resource at32_cf0_resource[] = {
+	{
+		.start	= 0x04000000,
+		.end	= 0x07ffffff,
+		.flags	= IORESOURCE_MEM,
+	},
+	IRQ(~0UL),
+};
+DEFINE_DEV_DATA(at32_cf, 0);
+
+struct platform_device *__init
+at32_add_device_cf(unsigned int id, unsigned int extint,
+		   struct cf_platform_data *data)
+{
+	struct platform_device *pdev;
+	unsigned int extint_pin;
+
+	switch (extint) {
+	case 0:
+		extint_pin = GPIO_PIN_PB(25);
+		break;
+	case 1:
+		extint_pin = GPIO_PIN_PB(26);
+		break;
+	case 2:
+		extint_pin = GPIO_PIN_PB(27);
+		break;
+	case 3:
+		extint_pin = GPIO_PIN_PB(28);
+		break;
+	default:
+		return NULL;
+	}
+
+	switch (id) {
+	case 0:
+		pdev = &at32_cf0_device;
+		select_peripheral(PE(19), PERIPH_A, 0);	/* CFCE1 */
+		select_peripheral(PE(20), PERIPH_A, 0);	/* CFCE2 */
+		select_peripheral(PE(21), PERIPH_A, 0);	/* NCS4  */
+		select_peripheral(PE(23), PERIPH_A, 0);	/* CFNRW */
+		select_peripheral(PE(24), PERIPH_A, 0);	/* NWAIT */
+		set_ebi_sfr_bits(HMATRIX_BIT(CS4A));
+		data->cs = 4;
+		break;
+	default:
+		return NULL;
+	}
+
+	if (data->detect_pin)
+		at32_select_gpio(data->detect_pin, AT32_GPIOF_DEGLITCH);
+	if (data->reset_pin)
+		at32_select_gpio(data->reset_pin, 0);
+	if (data->vcc_pin)
+		at32_select_gpio(data->vcc_pin, 0);
+
+	at32_select_periph(extint_pin, GPIO_PERIPH_A, AT32_GPIOF_PULLUP);
+	pdev->resource[1].start = system_manager.eim_first_irq + extint;
+	pdev->resource[1].end = pdev->resource[1].start;
+
 	memcpy(pdev->dev.platform_data, data,
-	       sizeof(struct lcdc_platform_data));
+	       sizeof(struct cf_platform_data));
 
 	platform_device_register(pdev);
 	return pdev;
@@ -950,18 +1444,21 @@ struct clk *at32_clock_list[] = {
 	&pbb_clk,
 	&at32_sm_pclk,
 	&at32_intc0_pclk,
+	&hmatrix_clk,
 	&ebi_clk,
 	&hramc_clk,
 	&smc0_pclk,
 	&smc0_mck,
 	&pdc_hclk,
 	&pdc_pclk,
+	&dmaca0_hclk,
 	&pico_clk,
 	&pio0_mck,
 	&pio1_mck,
 	&pio2_mck,
 	&pio3_mck,
 	&pio4_mck,
+	&at32_systc0_pclk,
 	&atmel_usart0_usart,
 	&atmel_usart1_usart,
 	&atmel_usart2_usart,
@@ -972,8 +1469,18 @@ struct clk *at32_clock_list[] = {
 	&macb1_pclk,
 	&atmel_spi0_spi_clk,
 	&atmel_spi1_spi_clk,
-	&lcdc0_hclk,
-	&lcdc0_pixclk,
+	&atmel_twi0_pclk,
+	&atmel_mci0_mci_clk,
+	&atmel_lcdfb0_hck1,
+	&atmel_lcdfb0_pixclk,
+	&usba0_pclk,
+	&usba0_hclk,
+	&ssc0_pclk,
+	&ssc1_pclk,
+	&ssc2_pclk,
+	&atmel_ac97c0_pclk,
+	&abdac0_pclk,
+	&abdac0_sample_clk,
 	&gclk0,
 	&gclk1,
 	&gclk2,
@@ -1012,7 +1519,8 @@ void __init at32_clock_init(void)
 	genclk_init_parent(&gclk2);
 	genclk_init_parent(&gclk3);
 	genclk_init_parent(&gclk4);
-	genclk_init_parent(&lcdc0_pixclk);
+	genclk_init_parent(&atmel_lcdfb0_pixclk);
+	genclk_init_parent(&abdac0_sample_clk);
 
 	/*
 	 * Turn on all clocks that have at least one user already, and
@@ -1024,6 +1532,9 @@ void __init at32_clock_init(void)
 	for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) {
 		struct clk *clk = at32_clock_list[i];
 
+		if (clk->users == 0)
+			continue;
+
 		if (clk->mode == &cpu_clk_mode)
 			cpu_mask |= 1 << clk->index;
 		else if (clk->mode == &hsb_clk_mode)
diff --git a/arch/avr32/mach-at32ap/clock.c b/arch/avr32/mach-at32ap/clock.c
index 00c4354..e8a12a3 100644
--- a/arch/avr32/mach-at32ap/clock.c
+++ b/arch/avr32/mach-at32ap/clock.c
@@ -18,7 +18,7 @@
 
 #include "clock.h"
 
-static spinlock_t clk_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(clk_lock);
 
 struct clk *clk_get(struct device *dev, const char *id)
 {
@@ -125,7 +125,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
 	ret = clk->set_rate(clk, rate, 1);
 	spin_unlock_irqrestore(&clk_lock, flags);
 
-	return (ret < 0) ? ret : 0;
+	return (ret > 0) ? ret : 0;
 }
 EXPORT_SYMBOL(clk_set_rate);
 
diff --git a/arch/avr32/mach-at32ap/hmatrix.h b/arch/avr32/mach-at32ap/hmatrix.h
new file mode 100644
index 0000000..d10bfb6
--- /dev/null
+++ b/arch/avr32/mach-at32ap/hmatrix.h
@@ -0,0 +1,182 @@
+/*
+ * Register definitions for High-Speed Bus Matrix
+ */
+#ifndef __HMATRIX_H
+#define __HMATRIX_H
+
+/* HMATRIX register offsets */
+#define HMATRIX_MCFG0				0x0000
+#define HMATRIX_MCFG1				0x0004
+#define HMATRIX_MCFG2				0x0008
+#define HMATRIX_MCFG3				0x000c
+#define HMATRIX_MCFG4				0x0010
+#define HMATRIX_MCFG5				0x0014
+#define HMATRIX_MCFG6				0x0018
+#define HMATRIX_MCFG7				0x001c
+#define HMATRIX_MCFG8				0x0020
+#define HMATRIX_MCFG9				0x0024
+#define HMATRIX_MCFG10				0x0028
+#define HMATRIX_MCFG11				0x002c
+#define HMATRIX_MCFG12				0x0030
+#define HMATRIX_MCFG13				0x0034
+#define HMATRIX_MCFG14				0x0038
+#define HMATRIX_MCFG15				0x003c
+#define HMATRIX_SCFG0				0x0040
+#define HMATRIX_SCFG1				0x0044
+#define HMATRIX_SCFG2				0x0048
+#define HMATRIX_SCFG3				0x004c
+#define HMATRIX_SCFG4				0x0050
+#define HMATRIX_SCFG5				0x0054
+#define HMATRIX_SCFG6				0x0058
+#define HMATRIX_SCFG7				0x005c
+#define HMATRIX_SCFG8				0x0060
+#define HMATRIX_SCFG9				0x0064
+#define HMATRIX_SCFG10				0x0068
+#define HMATRIX_SCFG11				0x006c
+#define HMATRIX_SCFG12				0x0070
+#define HMATRIX_SCFG13				0x0074
+#define HMATRIX_SCFG14				0x0078
+#define HMATRIX_SCFG15				0x007c
+#define HMATRIX_PRAS0				0x0080
+#define HMATRIX_PRBS0				0x0084
+#define HMATRIX_PRAS1				0x0088
+#define HMATRIX_PRBS1				0x008c
+#define HMATRIX_PRAS2				0x0090
+#define HMATRIX_PRBS2				0x0094
+#define HMATRIX_PRAS3				0x0098
+#define HMATRIX_PRBS3				0x009c
+#define HMATRIX_PRAS4				0x00a0
+#define HMATRIX_PRBS4				0x00a4
+#define HMATRIX_PRAS5				0x00a8
+#define HMATRIX_PRBS5				0x00ac
+#define HMATRIX_PRAS6				0x00b0
+#define HMATRIX_PRBS6				0x00b4
+#define HMATRIX_PRAS7				0x00b8
+#define HMATRIX_PRBS7				0x00bc
+#define HMATRIX_PRAS8				0x00c0
+#define HMATRIX_PRBS8				0x00c4
+#define HMATRIX_PRAS9				0x00c8
+#define HMATRIX_PRBS9				0x00cc
+#define HMATRIX_PRAS10				0x00d0
+#define HMATRIX_PRBS10				0x00d4
+#define HMATRIX_PRAS11				0x00d8
+#define HMATRIX_PRBS11				0x00dc
+#define HMATRIX_PRAS12				0x00e0
+#define HMATRIX_PRBS12				0x00e4
+#define HMATRIX_PRAS13				0x00e8
+#define HMATRIX_PRBS13				0x00ec
+#define HMATRIX_PRAS14				0x00f0
+#define HMATRIX_PRBS14				0x00f4
+#define HMATRIX_PRAS15				0x00f8
+#define HMATRIX_PRBS15				0x00fc
+#define HMATRIX_MRCR				0x0100
+#define HMATRIX_SFR0				0x0110
+#define HMATRIX_SFR1				0x0114
+#define HMATRIX_SFR2				0x0118
+#define HMATRIX_SFR3				0x011c
+#define HMATRIX_SFR4				0x0120
+#define HMATRIX_SFR5				0x0124
+#define HMATRIX_SFR6				0x0128
+#define HMATRIX_SFR7				0x012c
+#define HMATRIX_SFR8				0x0130
+#define HMATRIX_SFR9				0x0134
+#define HMATRIX_SFR10				0x0138
+#define HMATRIX_SFR11				0x013c
+#define HMATRIX_SFR12				0x0140
+#define HMATRIX_SFR13				0x0144
+#define HMATRIX_SFR14				0x0148
+#define HMATRIX_SFR15				0x014c
+
+/* Bitfields in MCFGx */
+#define HMATRIX_ULBT_OFFSET			0
+#define HMATRIX_ULBT_SIZE			3
+
+/* Bitfields in SCFGx */
+#define HMATRIX_SLOT_CYCLE_OFFSET		0
+#define HMATRIX_SLOT_CYCLE_SIZE			8
+#define HMATRIX_DEFMSTR_TYPE_OFFSET		16
+#define HMATRIX_DEFMSTR_TYPE_SIZE		2
+#define HMATRIX_FIXED_DEFMSTR_OFFSET		18
+#define HMATRIX_FIXED_DEFMSTR_SIZE		4
+#define HMATRIX_ARBT_OFFSET			24
+#define HMATRIX_ARBT_SIZE			2
+
+/* Bitfields in PRASx */
+#define HMATRIX_M0PR_OFFSET			0
+#define HMATRIX_M0PR_SIZE			4
+#define HMATRIX_M1PR_OFFSET			4
+#define HMATRIX_M1PR_SIZE			4
+#define HMATRIX_M2PR_OFFSET			8
+#define HMATRIX_M2PR_SIZE			4
+#define HMATRIX_M3PR_OFFSET			12
+#define HMATRIX_M3PR_SIZE			4
+#define HMATRIX_M4PR_OFFSET			16
+#define HMATRIX_M4PR_SIZE			4
+#define HMATRIX_M5PR_OFFSET			20
+#define HMATRIX_M5PR_SIZE			4
+#define HMATRIX_M6PR_OFFSET			24
+#define HMATRIX_M6PR_SIZE			4
+#define HMATRIX_M7PR_OFFSET			28
+#define HMATRIX_M7PR_SIZE			4
+
+/* Bitfields in PRBSx */
+#define HMATRIX_M8PR_OFFSET			0
+#define HMATRIX_M8PR_SIZE			4
+#define HMATRIX_M9PR_OFFSET			4
+#define HMATRIX_M9PR_SIZE			4
+#define HMATRIX_M10PR_OFFSET			8
+#define HMATRIX_M10PR_SIZE			4
+#define HMATRIX_M11PR_OFFSET			12
+#define HMATRIX_M11PR_SIZE			4
+#define HMATRIX_M12PR_OFFSET			16
+#define HMATRIX_M12PR_SIZE			4
+#define HMATRIX_M13PR_OFFSET			20
+#define HMATRIX_M13PR_SIZE			4
+#define HMATRIX_M14PR_OFFSET			24
+#define HMATRIX_M14PR_SIZE			4
+#define HMATRIX_M15PR_OFFSET			28
+#define HMATRIX_M15PR_SIZE			4
+
+/* Bitfields in SFR4 */
+#define HMATRIX_CS1A_OFFSET			1
+#define HMATRIX_CS1A_SIZE			1
+#define HMATRIX_CS3A_OFFSET			3
+#define HMATRIX_CS3A_SIZE			1
+#define HMATRIX_CS4A_OFFSET			4
+#define HMATRIX_CS4A_SIZE			1
+#define HMATRIX_CS5A_OFFSET			5
+#define HMATRIX_CS5A_SIZE			1
+#define HMATRIX_DBPUC_OFFSET			8
+#define HMATRIX_DBPUC_SIZE			1
+
+/* Constants for ULBT */
+#define HMATRIX_ULBT_INFINITE			0
+#define HMATRIX_ULBT_SINGLE			1
+#define HMATRIX_ULBT_FOUR_BEAT			2
+#define HMATRIX_ULBT_EIGHT_BEAT			3
+#define HMATRIX_ULBT_SIXTEEN_BEAT		4
+
+/* Constants for DEFMSTR_TYPE */
+#define HMATRIX_DEFMSTR_TYPE_NO_DEFAULT		0
+#define HMATRIX_DEFMSTR_TYPE_LAST_DEFAULT	1
+#define HMATRIX_DEFMSTR_TYPE_FIXED_DEFAULT	2
+
+/* Constants for ARBT */
+#define HMATRIX_ARBT_ROUND_ROBIN		0
+#define HMATRIX_ARBT_FIXED_PRIORITY		1
+
+/* Bit manipulation macros */
+#define HMATRIX_BIT(name)					\
+	(1 << HMATRIX_##name##_OFFSET)
+#define HMATRIX_BF(name,value)					\
+	(((value) & ((1 << HMATRIX_##name##_SIZE) - 1))		\
+	 << HMATRIX_##name##_OFFSET)
+#define HMATRIX_BFEXT(name,value)				\
+	(((value) >> HMATRIX_##name##_OFFSET)			\
+	 & ((1 << HMATRIX_##name##_SIZE) - 1))
+#define HMATRIX_BFINS(name,value,old)				\
+	(((old) & ~(((1 << HMATRIX_##name##_SIZE) - 1)		\
+		    << HMATRIX_##name##_OFFSET))		\
+	 | HMATRIX_BF(name,value))
+
+#endif /* __HMATRIX_H */
diff --git a/arch/avr32/mach-at32ap/hsmc.c b/arch/avr32/mach-at32ap/hsmc.c
index 7691721..5e22a75 100644
--- a/arch/avr32/mach-at32ap/hsmc.c
+++ b/arch/avr32/mach-at32ap/hsmc.c
@@ -75,12 +75,35 @@ int smc_set_configuration(int cs, const struct smc_config *config)
 		return -EINVAL;
 	}
 
+	switch (config->nwait_mode) {
+	case 0:
+		mode |= HSMC_BF(EXNW_MODE, HSMC_EXNW_MODE_DISABLED);
+		break;
+	case 1:
+		mode |= HSMC_BF(EXNW_MODE, HSMC_EXNW_MODE_RESERVED);
+		break;
+	case 2:
+		mode |= HSMC_BF(EXNW_MODE, HSMC_EXNW_MODE_FROZEN);
+		break;
+	case 3:
+		mode |= HSMC_BF(EXNW_MODE, HSMC_EXNW_MODE_READY);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (config->tdf_cycles) {
+		mode |= HSMC_BF(TDF_CYCLES, config->tdf_cycles);
+	}
+
 	if (config->nrd_controlled)
 		mode |= HSMC_BIT(READ_MODE);
 	if (config->nwe_controlled)
 		mode |= HSMC_BIT(WRITE_MODE);
 	if (config->byte_write)
 		mode |= HSMC_BIT(BAT);
+	if (config->tdf_mode)
+		mode |= HSMC_BIT(TDF_MODE);
 
 	pr_debug("smc cs%d: setup/%08x pulse/%08x cycle/%08x mode/%08x\n",
 		 cs, setup, pulse, cycle, mode);
diff --git a/arch/avr32/mach-at32ap/time-tc.c b/arch/avr32/mach-at32ap/time-tc.c
new file mode 100644
index 0000000..e3070bd
--- /dev/null
+++ b/arch/avr32/mach-at32ap/time-tc.c
@@ -0,0 +1,218 @@
+/*
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/clocksource.h>
+#include <linux/time.h>
+#include <linux/module.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 <asm/div64.h>
+#include <asm/sysreg.h>
+#include <asm/io.h>
+#include <asm/sections.h>
+
+#include <asm/arch/time.h>
+
+/* how many counter cycles in a jiffy? */
+static u32 cycles_per_jiffy;
+
+/* the count value for the next timer interrupt */
+static u32 expirelo;
+
+/* the I/O registers of the TC module */
+static void __iomem *ioregs;
+
+cycle_t read_cycle_count(void)
+{
+	return (cycle_t)timer_read(ioregs, 0, CV);
+}
+
+struct clocksource clocksource_avr32 = {
+	.name		= "avr32",
+	.rating		= 342,
+	.read		= read_cycle_count,
+	.mask		= CLOCKSOURCE_MASK(16),
+	.shift		= 16,
+	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static void avr32_timer_ack(void)
+{
+	u16 count = expirelo;
+
+	/* Ack this timer interrupt and set the next one, use a u16
+	 * variable so it will wrap around correctly */
+	count += cycles_per_jiffy;
+	expirelo = count;
+	timer_write(ioregs, 0, RC, expirelo);
+
+	/* Check to see if we have missed any timer interrupts */
+	count = timer_read(ioregs, 0, CV);
+	if ((count - expirelo) < 0x7fff) {
+		expirelo = count + cycles_per_jiffy;
+		timer_write(ioregs, 0, RC, expirelo);
+	}
+}
+
+u32 avr32_hpt_read(void)
+{
+	return timer_read(ioregs, 0, CV);
+}
+
+static int avr32_timer_calc_div_and_set_jiffies(struct clk *pclk)
+{
+	unsigned int cycles_max = (clocksource_avr32.mask + 1) / 2;
+	unsigned int divs[] = { 4, 8, 16, 32 };
+	int divs_size = sizeof(divs) / sizeof(*divs);
+	int i = 0;
+	unsigned long count_hz;
+	unsigned long shift;
+	unsigned long mult;
+	int clock_div = -1;
+	u64 tmp;
+
+	shift = clocksource_avr32.shift;
+
+	do {
+		count_hz = clk_get_rate(pclk) / divs[i];
+		mult = clocksource_hz2mult(count_hz, shift);
+		clocksource_avr32.mult = mult;
+
+		tmp = TICK_NSEC;
+		tmp <<= shift;
+		tmp += mult / 2;
+		do_div(tmp, mult);
+
+		cycles_per_jiffy = tmp;
+	} while (cycles_per_jiffy > cycles_max && ++i < divs_size);
+
+	clock_div = i + 1;
+
+	if (clock_div > divs_size) {
+		pr_debug("timer: could not calculate clock divider\n");
+		return -EFAULT;
+	}
+
+	/* Set the clock divider */
+	timer_write(ioregs, 0, CMR, TIMER_BF(CMR_TCCLKS, clock_div));
+
+	return 0;
+}
+
+int avr32_hpt_init(unsigned int count)
+{
+	struct resource *regs;
+	struct clk *pclk;
+	int irq = -1;
+	int ret = 0;
+
+	ret = -ENXIO;
+
+	irq = platform_get_irq(&at32_systc0_device, 0);
+	if (irq < 0) {
+		pr_debug("timer: could not get irq\n");
+		goto out_error;
+	}
+
+	pclk = clk_get(&at32_systc0_device.dev, "pclk");
+	if (IS_ERR(pclk)) {
+		pr_debug("timer: could not get clk: %ld\n", PTR_ERR(pclk));
+		goto out_error;
+	}
+	clk_enable(pclk);
+
+	regs = platform_get_resource(&at32_systc0_device, IORESOURCE_MEM, 0);
+	if (!regs) {
+		pr_debug("timer: could not get resource\n");
+		goto out_error_clk;
+	}
+
+	ioregs = ioremap(regs->start, regs->end - regs->start + 1);
+	if (!ioregs) {
+		pr_debug("timer: could not get ioregs\n");
+		goto out_error_clk;
+	}
+
+	ret = avr32_timer_calc_div_and_set_jiffies(pclk);
+	if (ret)
+		goto out_error_io;
+
+	ret = setup_irq(irq, &timer_irqaction);
+	if (ret) {
+		pr_debug("timer: could not request irq %d: %d\n",
+				irq, ret);
+		goto out_error_io;
+	}
+
+	expirelo = (timer_read(ioregs, 0, CV) / cycles_per_jiffy + 1)
+		* cycles_per_jiffy;
+
+	/* Enable clock and interrupts on RC compare */
+	timer_write(ioregs, 0, CCR, TIMER_BIT(CCR_CLKEN));
+	timer_write(ioregs, 0, IER, TIMER_BIT(IER_CPCS));
+	/* Set cycles to first interrupt */
+	timer_write(ioregs, 0,  RC, expirelo);
+
+	printk(KERN_INFO "timer: AT32AP system timer/counter at 0x%p irq %d\n",
+			ioregs, irq);
+
+	return 0;
+
+out_error_io:
+	iounmap(ioregs);
+out_error_clk:
+	clk_put(pclk);
+out_error:
+	return ret;
+}
+
+int avr32_hpt_start(void)
+{
+	timer_write(ioregs, 0, CCR, TIMER_BIT(CCR_SWTRG));
+	return 0;
+}
+
+irqreturn_t timer_interrupt(int irq, void *dev_id)
+{
+	unsigned int sr = timer_read(ioregs, 0, SR);
+
+	if (sr & TIMER_BIT(SR_CPCS)) {
+		/* ack timer interrupt and try to set next interrupt */
+		avr32_timer_ack();
+
+		/*
+		 * Call the generic timer interrupt handler
+		 */
+		write_seqlock(&xtime_lock);
+		do_timer(1);
+		write_sequnlock(&xtime_lock);
+
+		/*
+		 * In UP mode, we call local_timer_interrupt() to do profiling
+		 * and process accounting.
+		 *
+		 * SMP is not supported yet.
+		 */
+		local_timer_interrupt(irq, dev_id);
+
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
diff --git a/arch/avr32/mm/dma-coherent.c b/arch/avr32/mm/dma-coherent.c
index b68d669..099212d 100644
--- a/arch/avr32/mm/dma-coherent.c
+++ b/arch/avr32/mm/dma-coherent.c
@@ -112,16 +112,21 @@ void dma_free_coherent(struct device *dev, size_t size,
 }
 EXPORT_SYMBOL(dma_free_coherent);
 
-#if 0
 void *dma_alloc_writecombine(struct device *dev, size_t size,
 			     dma_addr_t *handle, gfp_t gfp)
 {
 	struct page *page;
+	dma_addr_t phys;
 
 	page = __dma_alloc(dev, size, handle, gfp);
+	if (!page)
+		return NULL;
+
+	phys = page_to_phys(page);
+	*handle = phys;
 
 	/* Now, map the page into P3 with write-combining turned on */
-	return __ioremap(page_to_phys(page), size, _PAGE_BUFFER);
+	return __ioremap(phys, size, _PAGE_BUFFER);
 }
 EXPORT_SYMBOL(dma_alloc_writecombine);
 
@@ -132,8 +137,7 @@ void dma_free_writecombine(struct device *dev, size_t size,
 
 	iounmap(cpu_addr);
 
-	page = bus_to_page(handle);
+	page = phys_to_page(handle);
 	__dma_free(dev, size, page, handle);
 }
 EXPORT_SYMBOL(dma_free_writecombine);
-#endif
diff --git a/arch/avr32/mm/fault.c b/arch/avr32/mm/fault.c
index 6785572..11941d8 100644
--- a/arch/avr32/mm/fault.c
+++ b/arch/avr32/mm/fault.c
@@ -12,73 +12,46 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/pagemap.h>
+#include <linux/kprobes.h>
 
 #include <asm/kdebug.h>
 #include <asm/mmu_context.h>
 #include <asm/sysreg.h>
-#include <asm/uaccess.h>
 #include <asm/tlb.h>
-
-#ifdef DEBUG
-static void dump_code(unsigned long pc)
-{
-	char *p = (char *)pc;
-	char val;
-	int i;
-
-
-	printk(KERN_DEBUG "Code:");
-	for (i = 0; i < 16; i++) {
-		if (__get_user(val, p + i))
-			break;
-		printk(" %02x", val);
-	}
-	printk("\n");
-}
-#endif
+#include <asm/uaccess.h>
 
 #ifdef CONFIG_KPROBES
-ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
-
-/* Hook to register for page fault notifications */
-int register_page_fault_notifier(struct notifier_block *nb)
+static inline int notify_page_fault(struct pt_regs *regs, int trap)
 {
-	return atomic_notifier_chain_register(&notify_page_fault_chain, nb);
-}
+	int ret = 0;
 
-int unregister_page_fault_notifier(struct notifier_block *nb)
-{
-	return atomic_notifier_chain_unregister(&notify_page_fault_chain, nb);
-}
+	if (!user_mode(regs)) {
+		if (kprobe_running() && kprobe_fault_handler(regs, trap))
+			ret = 1;
+	}
 
-static inline int notify_page_fault(enum die_val val, struct pt_regs *regs,
-				    int trap, int sig)
-{
-	struct die_args args = {
-		.regs = regs,
-		.trapnr = trap,
-	};
-	return atomic_notifier_call_chain(&notify_page_fault_chain, val, &args);
+	return ret;
 }
 #else
-static inline int notify_page_fault(enum die_val val, struct pt_regs *regs,
-				    int trap, int sig)
+static inline int notify_page_fault(struct pt_regs *regs, int trap)
 {
-	return NOTIFY_DONE;
+	return 0;
 }
 #endif
 
+int exception_trace = 1;
+
 /*
  * This routine handles page faults. It determines the address and the
  * problem, and then passes it off to one of the appropriate routines.
  *
  * ecr is the Exception Cause Register. Possible values are:
- *   5:  Page not found (instruction access)
  *   6:  Protection fault (instruction access)
- *   12: Page not found (read access)
- *   13: Page not found (write access)
- *   14: Protection fault (read access)
- *   15: Protection fault (write access)
+ *   15: Protection fault (read access)
+ *   16: Protection fault (write access)
+ *   20: Page not found (instruction access)
+ *   24: Page not found (read access)
+ *   28: Page not found (write access)
  */
 asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs)
 {
@@ -88,10 +61,11 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs)
 	const struct exception_table_entry *fixup;
 	unsigned long address;
 	unsigned long page;
-	int writeaccess = 0;
+	int writeaccess;
+	long signr;
+	int code;
 
-	if (notify_page_fault(DIE_PAGE_FAULT, regs,
-			      ecr, SIGSEGV) == NOTIFY_STOP)
+	if (notify_page_fault(regs, ecr))
 		return;
 
 	address = sysreg_read(TLBEAR);
@@ -99,6 +73,9 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs)
 	tsk = current;
 	mm = tsk->mm;
 
+	signr = SIGSEGV;
+	code = SEGV_MAPERR;
+
 	/*
 	 * If we're in an interrupt or have no user context, we must
 	 * not take the fault...
@@ -125,7 +102,9 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs)
 	 * can handle it...
 	 */
 good_area:
-	//pr_debug("good area: vm_flags = 0x%lx\n", vma->vm_flags);
+	code = SEGV_ACCERR;
+	writeaccess = 0;
+
 	switch (ecr) {
 	case ECR_PROTECTION_X:
 	case ECR_TLB_MISS_X:
@@ -176,46 +155,24 @@ survive:
 	 * map. Fix it, but check if it's kernel or user first...
 	 */
 bad_area:
-	pr_debug("Bad area [%s:%u]: addr %08lx, ecr %lu\n",
-		 tsk->comm, tsk->pid, address, ecr);
-
 	up_read(&mm->mmap_sem);
 
 	if (user_mode(regs)) {
-		/* Hmm...we have to pass address and ecr somehow... */
-		/* tsk->thread.address = address;
-		   tsk->thread.error_code = ecr; */
-#ifdef DEBUG
-		show_regs(regs);
-		dump_code(regs->pc);
-
-		page = sysreg_read(PTBR);
-		printk("ptbr = %08lx", page);
-		if (page) {
-			page = ((unsigned long *)page)[address >> 22];
-			printk(" pgd = %08lx", page);
-			if (page & _PAGE_PRESENT) {
-				page &= PAGE_MASK;
-				address &= 0x003ff000;
-				page = ((unsigned long *)__va(page))[address >> PAGE_SHIFT];
-				printk(" pte = %08lx\n", page);
-			}
-		}
-#endif
-		pr_debug("Sending SIGSEGV to PID %d...\n",
-			tsk->pid);
-		force_sig(SIGSEGV, tsk);
+		if (exception_trace && printk_ratelimit())
+			printk("%s%s[%d]: segfault at %08lx pc %08lx "
+			       "sp %08lx ecr %lu\n",
+			       is_init(tsk) ? KERN_EMERG : KERN_INFO,
+			       tsk->comm, tsk->pid, address, regs->pc,
+			       regs->sp, ecr);
+		_exception(SIGSEGV, regs, code, address);
 		return;
 	}
 
 no_context:
-	pr_debug("No context\n");
-
 	/* Are we prepared to handle this kernel fault? */
 	fixup = search_exception_tables(regs->pc);
 	if (fixup) {
 		regs->pc = fixup->fixup;
-		pr_debug("Found fixup at %08lx\n", fixup->fixup);
 		return;
 	}
 
@@ -230,7 +187,6 @@ no_context:
 		printk(KERN_ALERT
 		       "Unable to handle kernel paging request");
 	printk(" at virtual address %08lx\n", address);
-	printk(KERN_ALERT "pc = %08lx\n", regs->pc);
 
 	page = sysreg_read(PTBR);
 	printk(KERN_ALERT "ptbr = %08lx", page);
@@ -241,20 +197,20 @@ no_context:
 			page &= PAGE_MASK;
 			address &= 0x003ff000;
 			page = ((unsigned long *)__va(page))[address >> PAGE_SHIFT];
-			printk(" pte = %08lx\n", page);
+			printk(" pte = %08lx", page);
 		}
 	}
-	die("\nOops", regs, ecr);
-	do_exit(SIGKILL);
+	printk("\n");
+	die("Kernel access of bad area", regs, signr);
+	return;
 
 	/*
 	 * We ran out of memory, or some other thing happened to us
 	 * that made us unable to handle the page fault gracefully.
 	 */
 out_of_memory:
-	printk("Out of memory\n");
 	up_read(&mm->mmap_sem);
-	if (current->pid == 1) {
+	if (is_init(current)) {
 		yield();
 		down_read(&mm->mmap_sem);
 		goto survive;
@@ -267,21 +223,20 @@ out_of_memory:
 do_sigbus:
 	up_read(&mm->mmap_sem);
 
-	/*
-	 * Send a sigbus, regardless of whether we were in kernel or
-	 * user mode.
-	 */
-	/* address, error_code, trap_no, ... */
-#ifdef DEBUG
-	show_regs(regs);
-	dump_code(regs->pc);
-#endif
-	pr_debug("Sending SIGBUS to PID %d...\n", tsk->pid);
-	force_sig(SIGBUS, tsk);
-
 	/* Kernel mode? Handle exceptions or die */
+	signr = SIGBUS;
+	code = BUS_ADRERR;
 	if (!user_mode(regs))
 		goto no_context;
+
+	if (exception_trace)
+		printk("%s%s[%d]: bus error at %08lx pc %08lx "
+		       "sp %08lx ecr %lu\n",
+		       is_init(tsk) ? KERN_EMERG : KERN_INFO,
+		       tsk->comm, tsk->pid, address, regs->pc,
+		       regs->sp, ecr);
+
+	_exception(SIGBUS, regs, BUS_ADRERR, address);
 }
 
 asmlinkage void do_bus_error(unsigned long addr, int write_access,
@@ -292,8 +247,7 @@ asmlinkage void do_bus_error(unsigned long addr, int write_access,
 	       addr, write_access ? "write" : "read");
 	printk(KERN_INFO "DTLB dump:\n");
 	dump_dtlb();
-	die("Bus Error", regs, write_access);
-	do_exit(SIGKILL);
+	die("Bus Error", regs, SIGKILL);
 }
 
 /*
diff --git a/arch/avr32/mm/init.c b/arch/avr32/mm/init.c
index 70da689..82cf708 100644
--- a/arch/avr32/mm/init.c
+++ b/arch/avr32/mm/init.c
@@ -10,11 +10,9 @@
 #include <linux/mm.h>
 #include <linux/swap.h>
 #include <linux/init.h>
-#include <linux/initrd.h>
 #include <linux/mmzone.h>
 #include <linux/bootmem.h>
 #include <linux/pagemap.h>
-#include <linux/pfn.h>
 #include <linux/nodemask.h>
 
 #include <asm/page.h>
@@ -78,242 +76,6 @@ void show_mem(void)
 	printk ("%d pages swap cached\n", cached);
 }
 
-static void __init print_memory_map(const char *what,
-				    struct tag_mem_range *mem)
-{
-	printk ("%s:\n", what);
-	for (; mem; mem = mem->next) {
-		printk ("  %08lx - %08lx\n",
-			(unsigned long)mem->addr,
-			(unsigned long)(mem->addr + mem->size));
-	}
-}
-
-#define MAX_LOWMEM	HIGHMEM_START
-#define MAX_LOWMEM_PFN	PFN_DOWN(MAX_LOWMEM)
-
-/*
- * Sort a list of memory regions in-place by ascending address.
- *
- * We're using bubble sort because we only have singly linked lists
- * with few elements.
- */
-static void __init sort_mem_list(struct tag_mem_range **pmem)
-{
-	int done;
-	struct tag_mem_range **a, **b;
-
-	if (!*pmem)
-		return;
-
-	do {
-		done = 1;
-		a = pmem, b = &(*pmem)->next;
-		while (*b) {
-			if ((*a)->addr > (*b)->addr) {
-				struct tag_mem_range *tmp;
-				tmp = (*b)->next;
-				(*b)->next = *a;
-				*a = *b;
-				*b = tmp;
-				done = 0;
-			}
-			a = &(*a)->next;
-			b = &(*a)->next;
-		}
-	} while (!done);
-}
-
-/*
- * Find a free memory region large enough for storing the
- * bootmem bitmap.
- */
-static unsigned long __init
-find_bootmap_pfn(const struct tag_mem_range *mem)
-{
-	unsigned long bootmap_pages, bootmap_len;
-	unsigned long node_pages = PFN_UP(mem->size);
-	unsigned long bootmap_addr = mem->addr;
-	struct tag_mem_range *reserved = mem_reserved;
-	struct tag_mem_range *ramdisk = mem_ramdisk;
-	unsigned long kern_start = virt_to_phys(_stext);
-	unsigned long kern_end = virt_to_phys(_end);
-
-	bootmap_pages = bootmem_bootmap_pages(node_pages);
-	bootmap_len = bootmap_pages << PAGE_SHIFT;
-
-	/*
-	 * Find a large enough region without reserved pages for
-	 * storing the bootmem bitmap. We can take advantage of the
-	 * fact that all lists have been sorted.
-	 *
-	 * We have to check explicitly reserved regions as well as the
-	 * kernel image and any RAMDISK images...
-	 *
-	 * Oh, and we have to make sure we don't overwrite the taglist
-	 * since we're going to use it until the bootmem allocator is
-	 * fully up and running.
-	 */
-	while (1) {
-		if ((bootmap_addr < kern_end) &&
-		    ((bootmap_addr + bootmap_len) > kern_start))
-			bootmap_addr = kern_end;
-
-		while (reserved &&
-		       (bootmap_addr >= (reserved->addr + reserved->size)))
-			reserved = reserved->next;
-
-		if (reserved &&
-		    ((bootmap_addr + bootmap_len) >= reserved->addr)) {
-			bootmap_addr = reserved->addr + reserved->size;
-			continue;
-		}
-
-		while (ramdisk &&
-		       (bootmap_addr >= (ramdisk->addr + ramdisk->size)))
-			ramdisk = ramdisk->next;
-
-		if (!ramdisk ||
-		    ((bootmap_addr + bootmap_len) < ramdisk->addr))
-			break;
-
-		bootmap_addr = ramdisk->addr + ramdisk->size;
-	}
-
-	if ((PFN_UP(bootmap_addr) + bootmap_len) >= (mem->addr + mem->size))
-		return ~0UL;
-
-	return PFN_UP(bootmap_addr);
-}
-
-void __init setup_bootmem(void)
-{
-	unsigned bootmap_size;
-	unsigned long first_pfn, bootmap_pfn, pages;
-	unsigned long max_pfn, max_low_pfn;
-	unsigned long kern_start = virt_to_phys(_stext);
-	unsigned long kern_end = virt_to_phys(_end);
-	unsigned node = 0;
-	struct tag_mem_range *bank, *res;
-
-	sort_mem_list(&mem_phys);
-	sort_mem_list(&mem_reserved);
-
-	print_memory_map("Physical memory", mem_phys);
-	print_memory_map("Reserved memory", mem_reserved);
-
-	nodes_clear(node_online_map);
-
-	if (mem_ramdisk) {
-#ifdef CONFIG_BLK_DEV_INITRD
-		initrd_start = (unsigned long)__va(mem_ramdisk->addr);
-		initrd_end = initrd_start + mem_ramdisk->size;
-
-		print_memory_map("RAMDISK images", mem_ramdisk);
-		if (mem_ramdisk->next)
-			printk(KERN_WARNING
-			       "Warning: Only the first RAMDISK image "
-			       "will be used\n");
-		sort_mem_list(&mem_ramdisk);
-#else
-		printk(KERN_WARNING "RAM disk image present, but "
-		       "no initrd support in kernel!\n");
-#endif
-	}
-
-	if (mem_phys->next)
-		printk(KERN_WARNING "Only using first memory bank\n");
-
-	for (bank = mem_phys; bank; bank = NULL) {
-		first_pfn = PFN_UP(bank->addr);
-		max_low_pfn = max_pfn = PFN_DOWN(bank->addr + bank->size);
-		bootmap_pfn = find_bootmap_pfn(bank);
-		if (bootmap_pfn > max_pfn)
-			panic("No space for bootmem bitmap!\n");
-
-		if (max_low_pfn > MAX_LOWMEM_PFN) {
-			max_low_pfn = MAX_LOWMEM_PFN;
-#ifndef CONFIG_HIGHMEM
-			/*
-			 * Lowmem is memory that can be addressed
-			 * directly through P1/P2
-			 */
-			printk(KERN_WARNING
-			       "Node %u: Only %ld MiB of memory will be used.\n",
-			       node, MAX_LOWMEM >> 20);
-			printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n");
-#else
-#error HIGHMEM is not supported by AVR32 yet
-#endif
-		}
-
-		/* Initialize the boot-time allocator with low memory only. */
-		bootmap_size = init_bootmem_node(NODE_DATA(node), bootmap_pfn,
-						 first_pfn, max_low_pfn);
-
-		printk("Node %u: bdata = %p, bdata->node_bootmem_map = %p\n",
-		       node, NODE_DATA(node)->bdata,
-		       NODE_DATA(node)->bdata->node_bootmem_map);
-
-		/*
-		 * Register fully available RAM pages with the bootmem
-		 * allocator.
-		 */
-		pages = max_low_pfn - first_pfn;
-		free_bootmem_node (NODE_DATA(node), PFN_PHYS(first_pfn),
-				   PFN_PHYS(pages));
-
-		/*
-		 * Reserve space for the kernel image (if present in
-		 * this node)...
-		 */
-		if ((kern_start >= PFN_PHYS(first_pfn)) &&
-		    (kern_start < PFN_PHYS(max_pfn))) {
-			printk("Node %u: Kernel image %08lx - %08lx\n",
-			       node, kern_start, kern_end);
-			reserve_bootmem_node(NODE_DATA(node), kern_start,
-					     kern_end - kern_start);
-		}
-
-		/* ...the bootmem bitmap... */
-		reserve_bootmem_node(NODE_DATA(node),
-				     PFN_PHYS(bootmap_pfn),
-				     bootmap_size);
-
-		/* ...any RAMDISK images... */
-		for (res = mem_ramdisk; res; res = res->next) {
-			if (res->addr > PFN_PHYS(max_pfn))
-				break;
-
-			if (res->addr >= PFN_PHYS(first_pfn)) {
-				printk("Node %u: RAMDISK %08lx - %08lx\n",
-				       node,
-				       (unsigned long)res->addr,
-				       (unsigned long)(res->addr + res->size));
-				reserve_bootmem_node(NODE_DATA(node),
-						     res->addr, res->size);
-			}
-		}
-
-		/* ...and any other reserved regions. */
-		for (res = mem_reserved; res; res = res->next) {
-			if (res->addr > PFN_PHYS(max_pfn))
-				break;
-
-			if (res->addr >= PFN_PHYS(first_pfn)) {
-				printk("Node %u: Reserved %08lx - %08lx\n",
-				       node,
-				       (unsigned long)res->addr,
-				       (unsigned long)(res->addr + res->size));
-				reserve_bootmem_node(NODE_DATA(node),
-						     res->addr, res->size);
-			}
-		}
-
-		node_set_online(node);
-	}
-}
-
 /*
  * paging_init() sets up the page tables
  *
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index e812aa1..84d9847 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -183,6 +183,26 @@ config PNX4008_WATCHDOG
 
 	  Say N if you are unsure.
 
+# AVR32 Architecture
+
+config AT32AP700X_WDT
+	tristate "AT32AP700x watchdog"
+	depends on WATCHDOG && CPU_AT32AP7000
+	help
+	  Watchdog timer embedded into AT32AP700x devices. This will reboot
+	  your system when the timeout is reached.
+
+config AT32AP700X_WDT_TIMEOUT
+	int "Timeout value for AT32AP700x watchdog"
+	depends on AT32AP700X_WDT
+	default "2"
+	range 1 2
+	help
+	  Sets the timeout value for the watchdog in AT32AP700x devices.
+	  Limited by hardware to be 1 or 2 seconds.
+
+	  Set to 2 seconds by default.
+
 # X86 (i386 + ia64 + x86_64) Architecture
 
 config ACQUIRE_WDT
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile
index 2cd8ff8..8b2a530 100644
--- a/drivers/char/watchdog/Makefile
+++ b/drivers/char/watchdog/Makefile
@@ -35,6 +35,9 @@ obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
 obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
 obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
 
+# AVR32 Architecture
+obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
+
 # X86 (i386 + ia64 + x86_64) Architecture
 obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
 obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
diff --git a/drivers/char/watchdog/at32ap700x_wdt.c b/drivers/char/watchdog/at32ap700x_wdt.c
new file mode 100644
index 0000000..789456d
--- /dev/null
+++ b/drivers/char/watchdog/at32ap700x_wdt.c
@@ -0,0 +1,312 @@
+/*
+ * Watchdog driver for Atmel AT32AP700X devices
+ *
+ * Copyright (C) 2005-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.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#define TIMEOUT_MIN		1
+#define TIMEOUT_DEFAULT		CONFIG_AT32AP700X_WDT_TIMEOUT
+#define TIMEOUT_MAX		2
+
+/* Watchdog registers and write/read macro */
+#define	WDT_CTRL		0x00
+#define WDT_CTRL_EN		   0
+#define WDT_CTRL_PSEL		   8
+#define WDT_CTRL_KEY		  24
+
+#define WDT_CLR			0x04
+
+#define WDT_BIT(name)		(1 << WDT_##name)
+#define WDT_BF(name,value)	((value) << WDT_##name)
+
+#define wdt_readl(dev,reg)				\
+	__raw_readl((dev)->regs + WDT_##reg)
+#define wdt_writel(dev,reg,value)			\
+	__raw_writel((value), (dev)->regs + WDT_##reg)
+
+struct wdt_at32ap700x {
+	void __iomem	*regs;
+	int		timeout;
+	int		users;
+};
+
+static struct wdt_at32ap700x *wdt;
+
+/*
+ * Disable the watchdog.
+ */
+static void inline at32_wdt_stop(void)
+{
+	unsigned long psel = wdt_readl(wdt, CTRL) & WDT_BF(CTRL_PSEL, 0x0f);
+	wdt_writel(wdt, CTRL, psel | WDT_BF(CTRL_KEY, 0x55));
+	wdt_writel(wdt, CTRL, psel | WDT_BF(CTRL_KEY, 0xaa));
+}
+
+/*
+ * Enable and reset the watchdog.
+ */
+static void inline at32_wdt_start(void)
+{
+	/* 0xf is 2^16 divider = 2 sec, 0xe is 2^15 divider = 1 sec */
+	unsigned long psel = (wdt->timeout > 1) ? 0xf : 0xe;
+
+	wdt_writel(wdt, CTRL, WDT_BIT(CTRL_EN)
+			| WDT_BF(CTRL_PSEL, psel)
+			| WDT_BF(CTRL_KEY, 0x55));
+	wdt_writel(wdt, CTRL, WDT_BIT(CTRL_EN)
+			| WDT_BF(CTRL_PSEL, psel)
+			| WDT_BF(CTRL_KEY, 0xaa));
+}
+
+/*
+ * Pat the watchdog timer.
+ */
+static void inline at32_wdt_pat(void)
+{
+	wdt_writel(wdt, CLR, 0x42);
+}
+
+/*
+ * Watchdog device is opened, and watchdog starts running.
+ */
+static int at32_wdt_open(struct inode *inode, struct file *file)
+{
+	if (test_and_set_bit(1, &wdt->users))
+		return -EBUSY;
+
+	at32_wdt_start();
+	return nonseekable_open(inode, file);
+}
+
+/*
+ * Close the watchdog device. If CONFIG_WATCHDOG_NOWAYOUT is _not_ defined then
+ * the watchdog is also disabled.
+ */
+static int at32_wdt_close(struct inode *inode, struct file *file)
+{
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+	at32_wdt_stop();
+#endif
+	clear_bit(1, &wdt->users);
+	return 0;
+}
+
+/*
+ * Change the watchdog time interval.
+ */
+static int at32_wdt_settimeout(int time)
+{
+	/*
+	 * All counting occurs at 1 / SLOW_CLOCK (32 kHz) and max prescaler is
+	 * 2 ^ 16 allowing up to 2 seconds timeout.
+	 */
+	if ((time < TIMEOUT_MIN) || (time > TIMEOUT_MAX))
+		return -EINVAL;
+
+	/* Set new watchdog time. It will be used when at32_wdt_start() is called. */
+	wdt->timeout = time;
+	return 0;
+}
+
+static struct watchdog_info at32_wdt_info = {
+	.identity	= "at32ap700x watchdog",
+	.options	= WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+};
+
+/*
+ * Handle commands from user-space.
+ */
+static int at32_wdt_ioctl(struct inode *inode, struct file *file,
+		unsigned int cmd, unsigned long arg)
+{
+	int ret = -ENOTTY;
+	int time;
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+
+	switch(cmd) {
+	case WDIOC_KEEPALIVE:
+		at32_wdt_pat();
+		ret = 0;
+		break;
+	case WDIOC_GETSUPPORT:
+		ret = copy_to_user(argp, &at32_wdt_info,
+				sizeof(at32_wdt_info)) ? -EFAULT : 0;
+		break;
+	case WDIOC_SETTIMEOUT:
+		ret = get_user(time, p);
+		if (ret)
+			break;
+		ret = at32_wdt_settimeout(time);
+		if (ret)
+			break;
+		/* Enable new time value */
+		at32_wdt_start();
+		/* fall through */
+	case WDIOC_GETTIMEOUT:
+		ret = put_user(wdt->timeout, p);
+		break;
+	case WDIOC_GETSTATUS: /* fall through */
+	case WDIOC_GETBOOTSTATUS:
+		ret = put_user(0, p);
+		break;
+	case WDIOC_SETOPTIONS:
+		ret = get_user(time, p);
+		if (ret)
+			break;
+		if (time & WDIOS_DISABLECARD)
+			at32_wdt_stop();
+		if (time & WDIOS_ENABLECARD)
+			at32_wdt_start();
+		ret = 0;
+		break;
+	}
+
+	return ret;
+}
+
+static ssize_t at32_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+{
+	at32_wdt_pat();
+	return len;
+}
+
+static const struct file_operations at32_wdt_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.ioctl		= at32_wdt_ioctl,
+	.open		= at32_wdt_open,
+	.release	= at32_wdt_close,
+	.write		= at32_wdt_write,
+};
+
+static struct miscdevice at32_wdt_miscdev = {
+	.minor		= WATCHDOG_MINOR,
+	.name		= "watchdog",
+	.fops		= &at32_wdt_fops,
+};
+
+static int __init at32_wdt_probe(struct platform_device *pdev)
+{
+	struct resource	*regs;
+	int ret;
+
+	wdt = kmalloc(sizeof(struct wdt_at32ap700x), GFP_KERNEL);
+	if (!wdt) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!regs) {
+		pr_debug(KERN_ERR "wdt: no mmio resource defined for WDT\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	wdt->regs = ioremap(regs->start, regs->end - regs->start + 1);
+	wdt->users = 0;
+
+	if (at32_wdt_settimeout(TIMEOUT_DEFAULT)) {
+		at32_wdt_settimeout(TIMEOUT_MAX);
+		pr_info("at32_wdt: timeout invalid, set to %d sec.\n",
+				TIMEOUT_MAX);
+	}
+
+	if (at32_wdt_miscdev.parent)
+		return -EBUSY;
+	at32_wdt_miscdev.parent = &pdev->dev;
+
+	ret = misc_register(&at32_wdt_miscdev);
+	if (ret)
+		return ret;
+
+	printk(KERN_INFO "Atmel WDT for AT32AP700X at %08lx\n",
+			(unsigned long)wdt->regs);
+	return 0;
+
+out:
+	if (wdt)
+		kfree(wdt);
+	return ret;
+}
+
+static int __exit at32_wdt_remove(struct platform_device *pdev)
+{
+	int ret;
+
+	ret = misc_deregister(&at32_wdt_miscdev);
+	if (!ret)
+		at32_wdt_miscdev.parent = NULL;
+
+	if (wdt)
+		kfree(wdt);
+
+	return ret;
+}
+
+static void at32_wdt_shutdown(struct platform_device *pdev)
+{
+	at32_wdt_stop();
+}
+
+#ifdef CONFIG_PM
+static int at32_wdt_suspend(struct platform_device *pdev, pm_message_t message)
+{
+	at32_wdt_stop();
+	return 0;
+}
+
+static int at32_wdt_resume(struct platform_device *pdev)
+{
+	if (wdt->users)
+		at32_wdt_start();
+	return 0;
+}
+#endif
+
+static struct platform_driver at32_wdt_driver = {
+	.remove		= __exit_p(at32_wdt_remove),
+#ifdef CONFIG_PM
+	.suspend	= at32_wdt_suspend,
+	.resume		= at32_wdt_resume,
+#endif
+	.driver		= {
+		.name	= "wdt",
+		.owner	= THIS_MODULE,
+	},
+	.shutdown	= at32_wdt_shutdown,
+};
+
+static int __init at32_wdt_init(void)
+{
+	return platform_driver_probe(&at32_wdt_driver, at32_wdt_probe);
+}
+module_init(at32_wdt_init);
+
+static void __exit at32_wdt_exit(void)
+{
+	platform_driver_unregister(&at32_wdt_driver);
+}
+module_exit(at32_wdt_exit);
+
+MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
+MODULE_DESCRIPTION("Watchdog driver for Atmel AT32AP700X");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index ece31d2..a77c24b 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -5,6 +5,26 @@
 menu "I2C Hardware Bus support"
 	depends on I2C
 
+config I2C_ATMELTWI
+	tristate "Atmel TWI/I2C"
+	depends on I2C
+	help
+	  Atmel on-chip TWI controller. Say Y if you have an AT32 or
+	  AT91-based device and want to use its built-in TWI
+	  functionality. Atmel's TWI is compatible with Philips' I2C
+	  protocol. If in doubt, say NO
+
+config I2C_ATMELTWI_BAUDRATE
+	prompt "Atmel TWI baudrate"
+	depends on I2C_ATMELTWI
+	int
+	default 100000
+	help
+	  Set the TWI/I2C baudrate. This will alter the default value. A
+	  different baudrate can be set by using a module parameter as well. If
+	  no parameter is provided when loading, this is the value that will be
+	  used.
+
 config I2C_ALI1535
 	tristate "ALI 1535"
 	depends on I2C && PCI
@@ -102,6 +122,14 @@ config I2C_ELEKTOR
 	  This support is also available as a module.  If so, the module 
 	  will be called i2c-elektor.
 
+config I2C_GPIO
+	tristate "GPIO-based bitbanging I2C"
+	depends on GENERIC_GPIO
+	select I2C_ALGOBIT
+	help
+	  This is a very simple bitbanging I2C driver utilizing the
+	  arch-neutral GPIO API to control the SCL and SDA lines.
+
 config I2C_HYDRA
 	tristate "CHRP Apple Hydra Mac I/O I2C interface"
 	depends on I2C && PCI && PPC_CHRP && EXPERIMENTAL
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 290b540..604fe49 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_I2C_AMD8111)	+= i2c-amd8111.o
 obj-$(CONFIG_I2C_AT91)		+= i2c-at91.o
 obj-$(CONFIG_I2C_AU1550)	+= i2c-au1550.o
 obj-$(CONFIG_I2C_ELEKTOR)	+= i2c-elektor.o
+obj-$(CONFIG_I2C_GPIO)		+= i2c-gpio.o
 obj-$(CONFIG_I2C_HYDRA)		+= i2c-hydra.o
 obj-$(CONFIG_I2C_I801)		+= i2c-i801.o
 obj-$(CONFIG_I2C_I810)		+= i2c-i810.o
@@ -48,6 +49,7 @@ obj-$(CONFIG_I2C_VIAPRO)	+= i2c-viapro.o
 obj-$(CONFIG_I2C_VOODOO3)	+= i2c-voodoo3.o
 obj-$(CONFIG_SCx200_ACB)	+= scx200_acb.o
 obj-$(CONFIG_SCx200_I2C)	+= scx200_i2c.o
+obj-$(CONFIG_I2C_ATMELTWI)	+= i2c-atmeltwi.o
 
 ifeq ($(CONFIG_I2C_DEBUG_BUS),y)
 EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/i2c/busses/atmeltwi.h b/drivers/i2c/busses/atmeltwi.h
new file mode 100644
index 0000000..8502ea6
--- /dev/null
+++ b/drivers/i2c/busses/atmeltwi.h
@@ -0,0 +1,117 @@
+/*
+ * Register definitions for the Atmel Two-Wire Interface
+ */
+
+#ifndef __ASM_AVR32_TWI_H__
+#define __ASM_AVR32_TWI_H__
+
+/* TWI register offsets */
+#define TWI_CR					0x0000
+#define TWI_MMR					0x0004
+#define TWI_SMR					0x0008
+#define TWI_IADR				0x000c
+#define TWI_CWGR				0x0010
+#define TWI_SR					0x0020
+#define TWI_IER					0x0024
+#define TWI_IDR					0x0028
+#define TWI_IMR					0x002c
+#define TWI_RHR					0x0030
+#define TWI_THR					0x0034
+
+/* Bitfields in CR */
+#define TWI_START_OFFSET			0
+#define TWI_START_SIZE				1
+#define TWI_STOP_OFFSET				1
+#define TWI_STOP_SIZE				1
+#define TWI_MSEN_OFFSET				2
+#define TWI_MSEN_SIZE				1
+#define TWI_MSDIS_OFFSET			3
+#define TWI_MSDIS_SIZE				1
+#define TWI_SVEN_OFFSET				4
+#define TWI_SVEN_SIZE				1
+#define TWI_SVDIS_OFFSET			5
+#define TWI_SVDIS_SIZE				1
+#define TWI_SWRST_OFFSET			7
+#define TWI_SWRST_SIZE				1
+
+/* Bitfields in MMR */
+#define TWI_IADRSZ_OFFSET			8
+#define TWI_IADRSZ_SIZE				2
+#define TWI_MREAD_OFFSET			12
+#define TWI_MREAD_SIZE				1
+#define TWI_DADR_OFFSET				16
+#define TWI_DADR_SIZE				7
+
+/* Bitfields in SMR */
+#define TWI_SADR_OFFSET				16
+#define TWI_SADR_SIZE				7
+
+/* Bitfields in IADR */
+#define TWI_IADR_OFFSET				0
+#define TWI_IADR_SIZE				24
+
+/* Bitfields in CWGR */
+#define TWI_CLDIV_OFFSET			0
+#define TWI_CLDIV_SIZE				8
+#define TWI_CHDIV_OFFSET			8
+#define TWI_CHDIV_SIZE				8
+#define TWI_CKDIV_OFFSET			16
+#define TWI_CKDIV_SIZE				3
+
+/* Bitfields in SR */
+#define TWI_TXCOMP_OFFSET			0
+#define TWI_TXCOMP_SIZE				1
+#define TWI_RXRDY_OFFSET			1
+#define TWI_RXRDY_SIZE				1
+#define TWI_TXRDY_OFFSET			2
+#define TWI_TXRDY_SIZE				1
+#define TWI_SVDIR_OFFSET			3
+#define TWI_SVDIR_SIZE				1
+#define TWI_SVACC_OFFSET			4
+#define TWI_SVACC_SIZE				1
+#define TWI_GCACC_OFFSET			5
+#define TWI_GCACC_SIZE				1
+#define TWI_OVRE_OFFSET				6
+#define TWI_OVRE_SIZE				1
+#define TWI_UNRE_OFFSET				7
+#define TWI_UNRE_SIZE				1
+#define TWI_NACK_OFFSET				8
+#define TWI_NACK_SIZE				1
+#define TWI_ARBLST_OFFSET			9
+#define TWI_ARBLST_SIZE				1
+
+/* Bitfields in RHR */
+#define TWI_RXDATA_OFFSET			0
+#define TWI_RXDATA_SIZE				8
+
+/* Bitfields in THR */
+#define TWI_TXDATA_OFFSET			0
+#define TWI_TXDATA_SIZE				8
+
+/* Constants for IADRSZ */
+#define TWI_IADRSZ_NO_ADDR			0
+#define TWI_IADRSZ_ONE_BYTE			1
+#define TWI_IADRSZ_TWO_BYTES			2
+#define TWI_IADRSZ_THREE_BYTES			3
+
+/* Bit manipulation macros */
+#define TWI_BIT(name)					\
+	(1 << TWI_##name##_OFFSET)
+#define TWI_BF(name,value)				\
+	(((value) & ((1 << TWI_##name##_SIZE) - 1))	\
+	 << TWI_##name##_OFFSET)
+#define TWI_BFEXT(name,value)				\
+	(((value) >> TWI_##name##_OFFSET)		\
+	 & ((1 << TWI_##name##_SIZE) - 1))
+#define TWI_BFINS(name,value,old)			\
+	(((old) & ~(((1 << TWI_##name##_SIZE) - 1)	\
+		    << TWI_##name##_OFFSET))		\
+	 | TWI_BF(name,value))
+
+/* Register access macros */
+#define twi_readl(port,reg)				\
+	__raw_readl((port)->regs + TWI_##reg)
+#define twi_writel(port,reg,value)			\
+	__raw_writel((value), (port)->regs + TWI_##reg)
+
+#endif /* __ASM_AVR32_TWI_H__ */
diff --git a/drivers/i2c/busses/i2c-atmeltwi.c b/drivers/i2c/busses/i2c-atmeltwi.c
new file mode 100644
index 0000000..3418465
--- /dev/null
+++ b/drivers/i2c/busses/i2c-atmeltwi.c
@@ -0,0 +1,348 @@
+/*
+ * i2c Support for Atmel's Two-Wire Interface (TWI)
+ *
+ * Based on the work of Copyright (C) 2004 Rick Bronson
+ * Converted to 2.6 by Andrew Victor <andrew at sanpeople.com>
+ * Ported to AVR32 and heavily modified by Espen Krangnes <ekrangnes at atmel.com>
+ *
+ * Copyright (C) 2006 Atmel Corporation
+ *
+ * Borrowed heavily from the original work by:
+ * Copyright (C) 2000 Philip Edelbrock <phil at stimpy.netroedge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+#include <asm/io.h>
+#include <linux/time.h>
+#include "atmeltwi.h"
+
+static unsigned int baudrate = CONFIG_I2C_ATMELTWI_BAUDRATE;
+module_param(baudrate, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+MODULE_PARM_DESC(baudrate, "The TWI baudrate");
+
+
+struct atmel_twi {
+	void __iomem *regs;
+	struct i2c_adapter adapter;
+	struct clk *pclk;
+	spinlock_t lock;
+	struct completion comp;
+	u32 intmask;
+	u8 *buf;
+	u8 len;
+	u8 acks_left;
+	unsigned int irq;
+
+};
+#define to_atmel_twi(adap) container_of(adap, struct atmel_twi, adapter)
+
+/*
+ * Initialize the TWI hardware registers.
+ */
+static int __devinit twi_hwinit(struct atmel_twi *twi)
+{
+	unsigned long cdiv, ckdiv=0;
+
+	twi_writel(twi, IDR, ~0UL);
+	twi_writel(twi, CR, TWI_BIT(SWRST));	/*Reset peripheral*/
+	twi_readl(twi, SR);
+
+	cdiv = (clk_get_rate(twi->pclk) / (2 * baudrate)) - 4;
+
+	while (cdiv > 255) {
+		ckdiv++;
+		cdiv = cdiv >> 1;
+	}
+
+	if (ckdiv > 7)
+		return -EINVAL;
+	else
+		twi_writel(twi, CWGR, (TWI_BF(CKDIV, ckdiv)
+			       | TWI_BF(CHDIV, cdiv)
+			       | TWI_BF(CLDIV, cdiv)));
+	return 0;
+}
+
+/*
+ * Waits for the i2c status register to set the specified bitmask
+ * Returns 0 if timed out (~100ms).
+ */
+static short twi_wait_for_completion(struct atmel_twi *twi,
+		u32 mask)
+{
+	int timeout = msecs_to_jiffies(100);
+
+	twi->intmask = mask;
+	init_completion(&twi->comp);
+
+	twi_writel(twi, IER, mask);
+
+	if(!wait_for_completion_timeout(&twi->comp, timeout))
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+/*
+ * Generic i2c master transfer entrypoint.
+ */
+static int twi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+	struct atmel_twi *twi = to_atmel_twi(adap);
+	struct i2c_msg *pmsg;
+	int i;
+
+	/* get first message */
+	pmsg = msgs;
+
+	dev_dbg(&adap->dev, "twi_xfer: processing %d messages:\n", num);
+
+	for (i = 0; i < num; i++, pmsg++) {
+
+		twi->len = pmsg->len;
+		twi->buf = pmsg->buf;
+		twi->acks_left = pmsg->len;
+		twi_writel(twi, MMR, TWI_BF(DADR, pmsg->addr) |
+			(pmsg->flags & I2C_M_RD ? TWI_BIT(MREAD) : 0));
+		twi_writel(twi, IADR, TWI_BF(IADR, pmsg->addr));
+
+		dev_dbg(&adap->dev,"#%d: internal addr %d %s byte%s %s 0x%02x\n",
+			i,pmsg->len, pmsg->flags & I2C_M_RD ? "reading" : "writing",
+			pmsg->len > 1 ? "s" : "",
+			pmsg->flags & I2C_M_RD ? "from" : "to", pmsg->addr);
+
+		/* enable */
+		twi_writel(twi, CR, TWI_BIT(MSEN));
+
+		if (pmsg->flags & I2C_M_RD) {
+			twi_writel(twi, CR, TWI_BIT(START));
+			if ( twi_wait_for_completion(twi,TWI_BIT(RXRDY))==-ETIMEDOUT ) {
+				dev_dbg(&adap->dev, "RXRDY timeout. Stopped with %d bytes left\n",
+					twi->acks_left);
+				return -ETIMEDOUT;
+			}
+
+			/* Send Stop, and Wait until transfer is finished */
+			if ( twi_wait_for_completion(twi,TWI_BIT(TXCOMP))==-ETIMEDOUT ) {
+				dev_dbg(&adap->dev, "TXCOMP timeout\n");
+				return -ETIMEDOUT;
+			}
+
+		} else {
+			twi_writel(twi, THR, twi->buf[0]);
+			if ( twi_wait_for_completion(twi,TWI_BIT(TXRDY))==-ETIMEDOUT ) {
+				dev_dbg(&adap->dev, "TXRDY timeout. Stopped with %d bytes left\n",
+				twi->acks_left);
+				return -ETIMEDOUT;
+			}
+		}
+
+		/* Disable TWI interface */
+		twi_writel(twi, CR, TWI_BIT(MSDIS));
+
+	} /* end cur msg */
+
+	return i;
+}
+
+
+static irqreturn_t twi_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct atmel_twi *twi = dev_id;
+	int status = twi_readl(twi, SR);
+
+	if (twi->intmask & status){
+		if (twi->intmask & TWI_BIT(NACK)) {
+			goto nack;
+		} else if (twi->intmask & TWI_BIT(RXRDY)){
+			twi->buf[twi->len - twi->acks_left] = twi_readl(twi,RHR);
+			if(--twi->acks_left==1)
+				twi_writel(twi, CR, TWI_BIT(STOP));
+			if (twi->acks_left==0)
+				goto complete;
+		} else if (twi->intmask & TWI_BIT(TXRDY)) {
+			twi->acks_left--;
+			if (twi->acks_left==0) {
+				twi->intmask = TWI_BIT(TXCOMP);
+				twi_writel(twi, IER, TWI_BIT(TXCOMP));
+			} else
+				twi_writel(twi, THR, twi->buf[twi->len - twi->acks_left]);
+		} else if (twi->intmask & TWI_BIT(TXCOMP)) {
+			goto complete;
+		}
+	}
+
+	return IRQ_HANDLED;
+
+nack:
+	printk(KERN_INFO "NACK received!\n");
+
+complete:
+	twi_writel(twi, IDR, ~0UL);
+	complete(&twi->comp);
+
+	return IRQ_HANDLED;
+
+}
+
+
+/*
+ * Return list of supported functionality.
+ */
+static u32 twi_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+/* For now, we only handle combined mode (smbus) */
+static struct i2c_algorithm twi_algorithm = {
+	.master_xfer	= twi_xfer,
+	.functionality	= twi_func,
+};
+
+/*
+ * Main initialization routine.
+ */
+static int __devinit twi_probe(struct platform_device *pdev)
+{
+	struct atmel_twi *twi;
+	struct resource *regs;
+	struct clk *pclk;
+	struct i2c_adapter *adapter;
+	int rc, irq;
+
+	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!regs)
+		return -ENXIO;
+
+	pclk = clk_get(&pdev->dev, "pclk");
+	if (IS_ERR(pclk))
+		return PTR_ERR(pclk);
+	clk_enable(pclk);
+
+	rc = -ENOMEM;
+	twi = kzalloc(sizeof(struct atmel_twi), GFP_KERNEL);
+	if (!twi) {
+		dev_err(&pdev->dev, "can't allocate interface!\n");
+		goto err_alloc_twi;
+	}
+
+	twi->pclk = pclk;
+	twi->regs = ioremap(regs->start, regs->end - regs->start + 1);
+	if (!twi->regs)
+		goto err_ioremap;
+
+	irq = platform_get_irq(pdev,0);
+	rc = request_irq(irq, twi_interrupt, 0, "twi", twi);
+	if (rc) {
+		dev_err(&pdev->dev, "can't bind irq!\n");
+		goto err_irq;
+	}
+	twi->irq = irq;
+
+	rc = twi_hwinit(twi);
+	if (rc) {
+		dev_err(&pdev->dev, "Unable to set baudrate\n");
+		goto err_hw_init;
+	}
+
+	adapter = &twi->adapter;
+	sprintf(adapter->name, "TWI");
+	adapter->algo = &twi_algorithm;
+	adapter->class = I2C_CLASS_HWMON;
+	adapter->dev.parent = &pdev->dev;
+
+	platform_set_drvdata(pdev, twi);
+
+	rc = i2c_add_adapter(adapter);
+	if (rc) {
+		dev_err(&pdev->dev, "Adapter %s registration failed\n",
+			adapter->name);
+		goto err_register;
+	}
+
+	dev_info(&pdev->dev, "Atmel TWI i2c bus device (baudrate %dk) at 0x%08lx.\n",
+		 baudrate/1000, (unsigned long)regs->start);
+
+	return 0;
+
+
+err_register:
+	platform_set_drvdata(pdev, NULL);
+
+err_hw_init:
+	free_irq(irq, twi);
+
+err_irq:
+	iounmap(twi->regs);
+
+err_ioremap:
+	kfree(twi);
+
+err_alloc_twi:
+	clk_disable(pclk);
+	clk_put(pclk);
+
+	return rc;
+}
+
+static int __devexit twi_remove(struct platform_device *pdev)
+{
+	struct atmel_twi *twi = platform_get_drvdata(pdev);
+	int res;
+
+	platform_set_drvdata(pdev, NULL);
+	res = i2c_del_adapter(&twi->adapter);
+	twi_writel(twi, CR, TWI_BIT(MSDIS));
+	iounmap(twi->regs);
+	clk_disable(twi->pclk);
+	clk_put(twi->pclk);
+	free_irq(twi->irq, twi);
+	kfree(twi);
+
+	return res;
+}
+
+static struct platform_driver twi_driver = {
+	.probe		= twi_probe,
+	.remove		= __devexit_p(twi_remove),
+	.driver		= {
+		.name	= "atmel_twi",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init atmel_twi_init(void)
+{
+	return platform_driver_register(&twi_driver);
+}
+
+static void __exit atmel_twi_exit(void)
+{
+	platform_driver_unregister(&twi_driver);
+}
+
+module_init(atmel_twi_init);
+module_exit(atmel_twi_exit);
+
+MODULE_AUTHOR("Espen Krangnes");
+MODULE_DESCRIPTION("I2C driver for Atmel TWI");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
new file mode 100644
index 0000000..a7dd546
--- /dev/null
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -0,0 +1,215 @@
+/*
+ * Bitbanging I2C bus driver using the GPIO API
+ *
+ * Copyright (C) 2007 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/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/i2c-gpio.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/gpio.h>
+
+/* Toggle SDA by changing the direction of the pin */
+static void i2c_gpio_setsda_dir(void *data, int state)
+{
+	struct i2c_gpio_platform_data *pdata = data;
+
+	if (state)
+		gpio_direction_input(pdata->sda_pin);
+	else
+		gpio_direction_output(pdata->sda_pin, 0);
+}
+
+/*
+ * Toggle SDA by changing the output value of the pin. This is only
+ * valid for pins configured as open drain (i.e. setting the value
+ * high effectively turns off the output driver.)
+ */
+static void i2c_gpio_setsda_val(void *data, int state)
+{
+	struct i2c_gpio_platform_data *pdata = data;
+
+	gpio_set_value(pdata->sda_pin, state);
+}
+
+/* Toggle SCL by changing the direction of the pin. */
+static void i2c_gpio_setscl_dir(void *data, int state)
+{
+	struct i2c_gpio_platform_data *pdata = data;
+
+	if (state)
+		gpio_direction_input(pdata->scl_pin);
+	else
+		gpio_direction_output(pdata->scl_pin, 0);
+}
+
+/*
+ * Toggle SCL by changing the output value of the pin. This is used
+ * for pins that are configured as open drain and for output-only
+ * pins. The latter case will break the i2c protocol, but it will
+ * often work in practice.
+ */
+static void i2c_gpio_setscl_val(void *data, int state)
+{
+	struct i2c_gpio_platform_data *pdata = data;
+
+	gpio_set_value(pdata->scl_pin, state);
+}
+
+int i2c_gpio_getsda(void *data)
+{
+	struct i2c_gpio_platform_data *pdata = data;
+
+	return gpio_get_value(pdata->sda_pin);
+}
+
+int i2c_gpio_getscl(void *data)
+{
+	struct i2c_gpio_platform_data *pdata = data;
+
+	return gpio_get_value(pdata->scl_pin);
+}
+
+static int __init i2c_gpio_probe(struct platform_device *pdev)
+{
+	struct i2c_gpio_platform_data *pdata;
+	struct i2c_algo_bit_data *bit_data;
+	struct i2c_adapter *adap;
+	int ret;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata)
+		return -ENXIO;
+
+	ret = -ENOMEM;
+	adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+	if (!adap)
+		goto err_alloc_adap;
+	bit_data = kzalloc(sizeof(struct i2c_algo_bit_data), GFP_KERNEL);
+	if (!bit_data)
+		goto err_alloc_bit_data;
+
+	ret = gpio_request(pdata->sda_pin, "sda");
+	if (ret)
+		goto err_request_sda;
+	ret = gpio_request(pdata->scl_pin, "scl");
+	if (ret)
+		goto err_request_scl;
+
+	if (pdata->sda_is_open_drain) {
+		gpio_direction_output(pdata->sda_pin, 1);
+		bit_data->setsda = i2c_gpio_setsda_val;
+	} else {
+		gpio_direction_input(pdata->sda_pin);
+		bit_data->setsda = i2c_gpio_setsda_dir;
+	}
+
+	if (pdata->scl_is_open_drain || pdata->scl_is_output_only) {
+		gpio_direction_output(pdata->scl_pin, 1);
+		bit_data->setscl = i2c_gpio_setscl_val;
+	} else {
+		gpio_direction_input(pdata->scl_pin);
+		bit_data->setscl = i2c_gpio_setscl_dir;
+	}
+
+	if (!pdata->scl_is_output_only)
+		bit_data->getscl = i2c_gpio_getscl;
+	bit_data->getsda = i2c_gpio_getsda;
+
+	if (pdata->udelay)
+		bit_data->udelay = pdata->udelay;
+	else if (pdata->scl_is_output_only)
+		bit_data->udelay = 50;			/* 10 kHz */
+	else
+		bit_data->udelay = 5;			/* 100 kHz */
+
+	if (pdata->timeout)
+		bit_data->timeout = pdata->timeout;
+	else
+		bit_data->timeout = HZ / 10;		/* 100 ms */
+
+	bit_data->data = pdata;
+
+	adap->owner = THIS_MODULE;
+	snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id);
+	adap->algo_data = bit_data;
+	adap->dev.parent = &pdev->dev;
+
+	ret = i2c_bit_add_bus(adap);
+	if (ret)
+		goto err_add_bus;
+
+	platform_set_drvdata(pdev, adap);
+
+	dev_info(&pdev->dev, "using pins %u (SDA) and %u (SCL%s)\n",
+		 pdata->sda_pin, pdata->scl_pin,
+		 pdata->scl_is_output_only
+		 ? ", no clock stretching" : "");
+
+	return 0;
+
+err_add_bus:
+	gpio_free(pdata->scl_pin);
+err_request_scl:
+	gpio_free(pdata->sda_pin);
+err_request_sda:
+	kfree(bit_data);
+err_alloc_bit_data:
+	kfree(adap);
+err_alloc_adap:
+	return ret;
+}
+
+static int __exit i2c_gpio_remove(struct platform_device *pdev)
+{
+	struct i2c_gpio_platform_data *pdata;
+	struct i2c_adapter *adap;
+
+	adap = platform_get_drvdata(pdev);
+	pdata = pdev->dev.platform_data;
+
+	i2c_del_adapter(adap);
+	gpio_free(pdata->scl_pin);
+	gpio_free(pdata->sda_pin);
+	kfree(adap->algo_data);
+	kfree(adap);
+
+	return 0;
+}
+
+static struct platform_driver i2c_gpio_driver = {
+	.driver		= {
+		.name	= "i2c-gpio",
+		.owner	= THIS_MODULE,
+	},
+	.remove		= __exit_p(i2c_gpio_remove),
+};
+
+static int __init i2c_gpio_init(void)
+{
+	int ret;
+
+	ret = platform_driver_probe(&i2c_gpio_driver, i2c_gpio_probe);
+	if (ret)
+		printk(KERN_ERR "i2c-gpio: probe failed: %d\n", ret);
+
+	return ret;
+}
+module_init(i2c_gpio_init);
+
+static void __exit i2c_gpio_exit(void)
+{
+	platform_driver_unregister(&i2c_gpio_driver);
+}
+module_exit(i2c_gpio_exit);
+
+MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
+MODULE_DESCRIPTION("Platform-independent bitbanging I2C driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index 35d998c..a3c7057 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -125,4 +125,19 @@ config MOUSE_HIL
 	help
 	  Say Y here to support HIL pointers.
 
+config MOUSE_GPIO
+	tristate "GPIO mouse"
+	depends on GENERIC_GPIO
+	help
+	  This driver simulates a mouse on GPIO lines of various CPUs (and some
+	  other chips).
+
+	  Say Y here if your device has buttons or a simple joystick connected
+	  directly to GPIO lines. Your board-specific setup logic must also
+	  provide a platform device and platform data saying which GPIOs are
+	  used.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gpio_mouse.
+
 endif
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index 21a1de6..5d0fc43 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -13,5 +13,6 @@ obj-$(CONFIG_MOUSE_PS2)		+= psmouse.o
 obj-$(CONFIG_MOUSE_SERIAL)	+= sermouse.o
 obj-$(CONFIG_MOUSE_HIL)		+= hil_ptr.o
 obj-$(CONFIG_MOUSE_VSXXXAA)	+= vsxxxaa.o
+obj-$(CONFIG_MOUSE_GPIO)	+= gpio_mouse.o
 
 psmouse-objs  := psmouse-base.o alps.o logips2pp.o synaptics.o lifebook.o trackpoint.o
diff --git a/drivers/input/mouse/gpio_mouse.c b/drivers/input/mouse/gpio_mouse.c
new file mode 100644
index 0000000..b7c438e
--- /dev/null
+++ b/drivers/input/mouse/gpio_mouse.c
@@ -0,0 +1,305 @@
+/*
+ * Driver for simulating a mouse on GPIO lines.
+ *
+ * Copyright (C) 2007 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/init.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/gpio_mouse.h>
+
+#include <asm/gpio.h>
+
+struct gpio_mouse {
+	struct input_dev *input;
+	struct gpio_mouse_platform_data *gpio;
+	struct timer_list timer;
+};
+
+/*
+ * Timer function which is run every scan_ms ms when the device is opened. The
+ * dev input varaible is set to the the input_dev pointer.
+ */
+static void gpio_mouse_scan(unsigned long _dev)
+{
+	struct input_dev *input = (struct input_dev *)_dev;
+	struct gpio_mouse *gmouse = input->private;
+	struct gpio_mouse_platform_data *gpio = gmouse->gpio;
+	int x, y;
+
+	if (gpio->bleft >= 0)
+		input_report_key(input, BTN_LEFT,
+				gpio_get_value(gpio->bleft) ^ gpio->polarity);
+	if (gpio->bmiddle >= 0)
+		input_report_key(input, BTN_MIDDLE,
+				gpio_get_value(gpio->bmiddle) ^ gpio->polarity);
+	if (gpio->bright >= 0)
+		input_report_key(input, BTN_RIGHT,
+				gpio_get_value(gpio->bright) ^ gpio->polarity);
+
+	x = (gpio_get_value(gpio->right) ^ gpio->polarity)
+		- (gpio_get_value(gpio->left) ^ gpio->polarity);
+	y = (gpio_get_value(gpio->down) ^ gpio->polarity)
+		- (gpio_get_value(gpio->up) ^ gpio->polarity);
+
+	input_report_rel(input, REL_X, x);
+	input_report_rel(input, REL_Y, y);
+	input_sync(input);
+
+	mod_timer(&gmouse->timer, jiffies + msecs_to_jiffies(gpio->scan_ms));
+}
+
+/* Only start the timer when the device is actually in use, i.e. opened. */
+static int gpio_mouse_open(struct input_dev *input)
+{
+	struct gpio_mouse *gmouse = input->private;
+	struct gpio_mouse_platform_data *gpio = gmouse->gpio;
+	gmouse->timer.expires = jiffies + msecs_to_jiffies(gpio->scan_ms);
+	gmouse->timer.data = (unsigned long)input;
+	add_timer(&gmouse->timer);
+	return 0;
+}
+
+static void gpio_mouse_close(struct input_dev *input)
+{
+	struct gpio_mouse *gmouse = input->private;
+	del_timer_sync(&gmouse->timer);
+}
+
+static int __init gpio_mouse_probe(struct platform_device *pdev)
+{
+	struct gpio_mouse_platform_data *pdata = pdev->dev.platform_data;
+	struct gpio_mouse *gmouse;
+	struct input_dev *input;
+	int ret;
+
+	if (!pdata) {
+		dev_dbg(&pdev->dev, "no platform data\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	if (pdata->up < 0 || pdata->down < 0 || pdata->right < 0
+			|| pdata->left < 0) {
+		dev_dbg(&pdev->dev, "missing GPIO for directions\n");
+		ret = -EINVAL;
+		goto out;
+	}
+	if (pdata->scan_ms < 0) {
+		dev_dbg(&pdev->dev, "invalid scan time\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	gmouse = kzalloc(sizeof(struct gpio_mouse), GFP_KERNEL);
+	if (!gmouse) {
+		dev_dbg(&pdev->dev, "not enought memory for gpio_mouse\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	/* Mouse direction, required. */
+	ret = gpio_request(pdata->up, "gpio_mouse_up");
+	if (ret) {
+		dev_dbg(&pdev->dev, "fail up pin\n");
+		goto out_gpio_up;
+	}
+	ret = gpio_request(pdata->down, "gpio_mouse_down");
+	if (ret) {
+		dev_dbg(&pdev->dev, "fail down pin\n");
+		goto out_gpio_down;
+	}
+	ret = gpio_request(pdata->left, "gpio_mouse_left");
+	if (ret) {
+		dev_dbg(&pdev->dev, "fail left pin\n");
+		goto out_gpio_left;
+	}
+	ret = gpio_request(pdata->right, "gpio_mouse_right");
+	if (ret) {
+		dev_dbg(&pdev->dev, "fail right pin\n");
+		goto out_gpio_right;
+	}
+
+	gpio_direction_input(pdata->up);
+	gpio_direction_input(pdata->down);
+	gpio_direction_input(pdata->left);
+	gpio_direction_input(pdata->right);
+
+	/* Mouse buttons, not required, but should at least have bleft. */
+	if (pdata->bleft >= 0) {
+		ret = gpio_request(pdata->bleft, "gpio_mouse_bleft");
+		if (ret) {
+			dev_dbg(&pdev->dev, "fail bleft pin\n");
+			goto out_gpio_bleft;
+		}
+		gpio_direction_input(pdata->bleft);
+	} else {
+		dev_dbg(&pdev->dev, "no left button defined\n");
+	}
+	if (pdata->bmiddle >= 0) {
+		ret = gpio_request(pdata->bmiddle, "gpio_mouse_bmiddle");
+		if (ret) {
+			dev_dbg(&pdev->dev, "fail bmiddle pin\n");
+			goto out_gpio_bmiddle;
+		}
+		gpio_direction_input(pdata->bmiddle);
+	}
+	if (pdata->bright >= 0) {
+		ret = gpio_request(pdata->bright, "gpio_mouse_bright");
+		if (ret) {
+			dev_dbg(&pdev->dev, "fail bright pin\n");
+			goto out_gpio_bright;
+		}
+		gpio_direction_input(pdata->bright);
+	}
+
+	input = input_allocate_device();
+	if (!input) {
+		dev_dbg(&pdev->dev, "not enough memory for input device\n");
+		ret = -ENOMEM;
+		goto out_input_allocate;
+	}
+
+	platform_set_drvdata(pdev, input);
+
+	input->name = pdev->name;
+	/* TODO: change to "input->dev.parent = &pdev->dev;" in the future */
+	input->cdev.dev = &pdev->dev;
+	input->private = gmouse;
+
+	input->id.bustype = BUS_HOST;
+	input->id.vendor = 0;
+	input->id.product = 0;
+	input->id.version = 0;
+
+	input->evbit[0] = BIT(EV_REL);
+	if (pdata->bleft >= 0 || pdata->bmiddle >= 0 || pdata->bright >= 0) {
+		input->evbit[0] |= BIT(EV_KEY);
+
+		if (pdata->bleft >= 0)
+			input->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT);
+		if (pdata->bmiddle >= 0)
+			input->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_MIDDLE);
+		if (pdata->bright >= 0)
+			input->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT);
+	}
+	input->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+
+	input->open = gpio_mouse_open;
+	input->close = gpio_mouse_close;
+
+	gmouse->gpio = pdata;
+	gmouse->input = input;
+
+	/* Init the scan timer. TODO: rewrite to use input-polldev in the future */
+	init_timer(&gmouse->timer);
+	gmouse->timer.function = gpio_mouse_scan;
+
+	ret = input_register_device(input);
+	if (ret) {
+		dev_dbg(&pdev->dev, "could not register input device\n");
+		goto out_reg_dev;
+	}
+
+	dev_dbg(&pdev->dev, "%d ms scan time, buttons: %s%s%s\n",
+			pdata->scan_ms,
+			pdata->bleft < 0 ? "" : "left ",
+			pdata->bmiddle < 0 ? "" : "middle ",
+			pdata->bright < 0 ? "" : "right");
+
+	return 0;
+
+out_reg_dev:
+	input_free_device(input);
+	platform_set_drvdata(pdev, NULL);
+out_input_allocate:
+	if (pdata->bright >= 0)
+		gpio_free(pdata->bright);
+out_gpio_bright:
+	if (pdata->bmiddle >= 0)
+		gpio_free(pdata->bmiddle);
+out_gpio_bmiddle:
+	if (pdata->bleft >= 0)
+		gpio_free(pdata->bleft);
+out_gpio_bleft:
+	if (pdata->right >= 0)
+		gpio_free(pdata->right);
+out_gpio_right:
+	if (pdata->left >= 0)
+		gpio_free(pdata->left);
+out_gpio_left:
+	if (pdata->down >= 0)
+		gpio_free(pdata->down);
+out_gpio_down:
+	if (pdata->up >= 0)
+		gpio_free(pdata->up);
+out_gpio_up:
+	kfree(gmouse);
+out:
+	return ret;
+}
+
+static int __exit gpio_mouse_remove(struct platform_device *pdev)
+{
+	struct input_dev *input = platform_get_drvdata(pdev);
+	struct gpio_mouse_platform_data *pdata = pdev->dev.platform_data;
+	struct gpio_mouse *gmouse = input->private;
+
+	if (input)
+		input_unregister_device(input);
+
+	if (pdata->up >= 0)
+		gpio_free(pdata->up);
+	if (pdata->down >= 0)
+		gpio_free(pdata->down);
+	if (pdata->left >= 0)
+		gpio_free(pdata->left);
+	if (pdata->right >= 0)
+		gpio_free(pdata->right);
+	if (pdata->bleft >= 0)
+		gpio_free(pdata->bleft);
+	if (pdata->bmiddle >= 0)
+		gpio_free(pdata->bmiddle);
+	if (pdata->bright >= 0)
+		gpio_free(pdata->bright);
+
+	if (gmouse)
+		kfree(gmouse);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+struct platform_driver gpio_mouse_device_driver = {
+	.remove		= __exit_p(gpio_mouse_remove),
+	.driver		= {
+		.name	= "gpio_mouse",
+	}
+};
+
+static int __init gpio_mouse_init(void)
+{
+	return platform_driver_probe(&gpio_mouse_device_driver,
+			gpio_mouse_probe);
+}
+module_init(gpio_mouse_init);
+
+static void __exit gpio_mouse_exit(void)
+{
+	platform_driver_unregister(&gpio_mouse_device_driver);
+}
+module_exit(gpio_mouse_exit);
+
+MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
+MODULE_DESCRIPTION("GPIO mouse driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 80b199f..b6fb03b 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -122,4 +122,16 @@ config SONY_LAPTOP
 
 	  Read <file:Documentation/sony-laptop.txt> for more information.
 
+config ATMEL_SSC
+	tristate "Device driver for Atmel SSC peripheral"
+	depends on AVR32 || ARCH_AT91
+	---help---
+	  This option enables device driver support for Atmel Syncronized
+	  Serial Communication peripheral (SSC).
+
+	  The SSC peripheral supports a wide variety of serial frame based
+	  communications, i.e. I2S, SPI, etc.
+
+	  If unsure, say N.
+
 endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 7793ccd..03bb556 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_TIFM_CORE)       	+= tifm_core.o
 obj-$(CONFIG_TIFM_7XX1)       	+= tifm_7xx1.o
 obj-$(CONFIG_SGI_IOC4)		+= ioc4.o
 obj-$(CONFIG_SONY_LAPTOP)	+= sony-laptop.o
+obj-$(CONFIG_ATMEL_SSC)		+= atmel-ssc/
diff --git a/drivers/misc/atmel-ssc/Makefile b/drivers/misc/atmel-ssc/Makefile
new file mode 100644
index 0000000..8c45446
--- /dev/null
+++ b/drivers/misc/atmel-ssc/Makefile
@@ -0,0 +1,3 @@
+
+obj-$(CONFIG_ATMEL_SSC) := ssc.o
+
diff --git a/drivers/misc/atmel-ssc/ssc.c b/drivers/misc/atmel-ssc/ssc.c
new file mode 100644
index 0000000..a13bd6f
--- /dev/null
+++ b/drivers/misc/atmel-ssc/ssc.c
@@ -0,0 +1,471 @@
+/*
+ * Atmel SSC support
+ *
+ * Copyright (C) 2007 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/clk.h>
+#include <linux/ssc.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+#include <asm/io.h>
+
+#define MAX_NR_SSC_DEVICES	4
+
+DEFINE_MUTEX(user_mutex);
+
+static struct ssc_device ssc_dev[MAX_NR_SSC_DEVICES];
+
+/* SSC API */
+
+struct ssc_device* ssc_request(unsigned int ssc_num)
+{
+	struct ssc_device *ssc;
+
+	ssc = &ssc_dev[ssc_num];
+	if (!ssc)
+		return ERR_PTR(-ENODEV);
+
+	/* Lock, check if we are taken and return BUSY if taken */
+	mutex_lock(&user_mutex);
+	if (ssc->user) {
+		mutex_unlock(&user_mutex);
+		printk(KERN_ERR
+		       "%s: attempted to request taken ssc%u module\n",
+		       ssc->name, ssc_num);
+		return ERR_PTR(-EBUSY);
+	}
+	ssc->user++;
+	mutex_unlock(&user_mutex);
+
+	/* turn on the module */
+	clk_enable(ssc->clk);
+
+	return ssc;
+}
+EXPORT_SYMBOL(ssc_request);
+
+void ssc_free(struct ssc_device *ssc)
+{
+	mutex_lock(&user_mutex);
+	if (ssc->user) {
+		ssc->user--;
+		/* turn off the module */
+		clk_disable(ssc->clk);
+	} else {
+		printk(KERN_WARNING
+		       "%s: attempted to free already free ssc module\n",
+		       ssc->name);
+	}
+	mutex_unlock(&user_mutex);
+}
+EXPORT_SYMBOL(ssc_free);
+
+int ssc_set_mode(struct ssc_device *ssc, struct ssc_mode *mode)
+{
+	ssc_writel(ssc, CR, SSC_BIT(CR_SWRST));
+
+	if (!mode)
+		return -EINVAL;
+	if (mode->bauddiv % 2)
+		return -EINVAL; /* not power of 2 */
+
+	switch (mode->mode) {
+	case ATMEL_SSC_MODE_I2S_MASTER:
+		if (mode->data_length % 2)
+			return -EINVAL; /* not power of 2 */
+
+		ssc_writel(ssc, CMR, (mode->bauddiv / 2));
+
+		/* Continous clock output
+		 * Starts on falling TF
+		 * Delay 1 cycle (1 bit)
+		 */
+		ssc_writel(ssc, TCMR, SSC_BF(TCMR_CKO, 1)
+				| SSC_BF(TCMR_START, 4)
+				| SSC_BF(TCMR_STTDLY, 1)
+				| SSC_BF(TCMR_PERIOD,
+					(mode->data_length-1)));
+		/* Transmitt MSB first
+		 * Transmit 2 words each transfer
+		 * Frame starts on negative pulse
+		 */
+		ssc_writel(ssc, TFMR,
+				SSC_BF(TFMR_DATLEN,
+					(mode->data_length-1))
+				| SSC_BIT(TFMR_MSBF)
+				| SSC_BF(TFMR_DATNB, 1)
+				| SSC_BF(TFMR_FSLEN,
+					(mode->data_length-1))
+				| SSC_BF(TFMR_FSOS, 1));
+		/* Use transmitter clock
+		 * Invert clock
+		 * Start on any edge on RF
+		 * Delay 1 cycle (1 bit)
+		 */
+		ssc_writel(ssc, RCMR, SSC_BF(RCMR_CKS, 1)
+				| SSC_BIT(RCMR_CKI)
+				| SSC_BF(RCMR_START, 7)
+				| SSC_BF(RCMR_STTDLY, 1));
+		/* Receive MSB first */
+		ssc_writel(ssc, RFMR,
+				SSC_BF(RFMR_DATLEN, (mode->data_length-1))
+				| SSC_BIT(RFMR_MSBF));
+		break;
+	case ATMEL_SSC_MODE_I2S_SLAVE:
+		if (mode->data_length % 2)
+			return -EINVAL; /* not power of 2 */
+
+		ssc_writel(ssc, CMR, 0);
+
+		/* Continous clock input on TK
+		 * Starts on any TF edge
+		 * Delay 1 cycle (1 bit)
+		 */
+		ssc_writel(ssc, TCMR, SSC_BF(TCMR_CKS, 2)
+				| SSC_BF(TCMR_START, 7)
+				| SSC_BF(TCMR_STTDLY, 1));
+		/* Transmitt MSB first
+		 * Transmit 2 words each transfer
+		 * Frame starts on negative pulse
+		 */
+		ssc_writel(ssc, TFMR,
+				SSC_BF(TFMR_DATLEN,
+					(mode->data_length-1))
+				| SSC_BIT(TFMR_MSBF)
+				| SSC_BF(TFMR_DATNB, 1)
+				| SSC_BF(TFMR_FSLEN,
+					(mode->data_length-1))
+				| SSC_BF(TFMR_FSOS, 1));
+		/* Continous clock input on RK
+		 * Start on any RF edge
+		 * Delay 1 cycle (1 bit)
+		 */
+		ssc_writel(ssc, RCMR, SSC_BF(RCMR_CKS, 2)
+				| SSC_BF(RCMR_START, 7)
+				| SSC_BF(RCMR_STTDLY, 1));
+		/* Receive MSB first */
+		ssc_writel(ssc, RFMR,
+				SSC_BF(RFMR_DATLEN, (mode->data_length-1))
+				| SSC_BIT(RFMR_MSBF));
+		break;
+	case ATMEL_SSC_MODE_SPI_MASTER:
+		if (mode->data_length < 8 || mode->data_length > 16)
+			return -EINVAL;
+
+		ssc_writel(ssc, CMR, (mode->bauddiv / 2));
+
+		/* Clock during xfer
+		 * Invert depending on SPI mode
+		 * Continous clock gating
+		 */
+		ssc_writel(ssc, TCMR, SSC_BF(TCMR_CKO, 2)
+				| SSC_BF(TCMR_CKI, (mode->spi_mode % 2) ? 0 : 1)
+				| SSC_BF(TCMR_CKG, 1));
+		/* Transmitt MSB first
+		 * Frame starts on negative edge
+		 */
+		ssc_writel(ssc, TFMR,
+				SSC_BF(TFMR_DATLEN, (mode->data_length-1))
+				| SSC_BIT(TFMR_MSBF)
+				| SSC_BF(TFMR_FSOS, 3));
+		/* Invert depending on SPI mode
+		 * Start receive on transmitt
+		 */
+		ssc_writel(ssc, RCMR,
+				SSC_BF(RCMR_CKI, (mode->spi_mode % 2) ? 0 : 1)
+				| SSC_BF(RCMR_START, 1));
+		/* Reveice MSB first */
+		ssc_writel(ssc, RFMR,
+				SSC_BF(RFMR_DATLEN, (mode->data_length-1))
+				| SSC_BIT(RFMR_MSBF));
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(ssc_set_mode);
+
+int ssc_set_rx_buffers(struct ssc_device *ssc, struct ssc_xfer_info *xfer)
+{
+	if (xfer->data) {
+		ssc_writel(ssc, PDC_RPR, xfer->data);
+		ssc_writel(ssc, PDC_RCR, xfer->len);
+	}
+	if (xfer->next_data) {
+		ssc_writel(ssc, PDC_RNPR, xfer->next_data);
+		ssc_writel(ssc, PDC_RNCR, xfer->next_len);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(ssc_set_rx_buffers);
+
+int ssc_get_rx_buffers(struct ssc_device *ssc, struct ssc_xfer_info *xfer)
+{
+	xfer->data	= ssc_readl(ssc, PDC_RPR);
+	xfer->len	= ssc_readl(ssc, PDC_RCR);
+	xfer->next_data	= ssc_readl(ssc, PDC_RNPR);
+	xfer->next_len	= ssc_readl(ssc, PDC_RNCR);
+
+	return 0;
+}
+EXPORT_SYMBOL(ssc_get_rx_buffers);
+
+int ssc_set_tx_buffers(struct ssc_device *ssc, struct ssc_xfer_info *xfer)
+{
+	if (xfer->data) {
+		ssc_writel(ssc, PDC_TPR, xfer->data);
+		ssc_writel(ssc, PDC_TCR, xfer->len);
+	}
+	if (xfer->next_data) {
+		ssc_writel(ssc, PDC_TNPR, xfer->next_data);
+		ssc_writel(ssc, PDC_TNCR, xfer->next_len);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(ssc_set_tx_buffers);
+
+int ssc_get_tx_buffers(struct ssc_device *ssc, struct ssc_xfer_info *xfer)
+{
+	xfer->data	= ssc_readl(ssc, PDC_TPR);
+	xfer->len	= ssc_readl(ssc, PDC_TCR);
+	xfer->next_data	= ssc_readl(ssc, PDC_TNPR);
+	xfer->next_len	= ssc_readl(ssc, PDC_TNCR);
+
+	return 0;
+}
+EXPORT_SYMBOL(ssc_get_tx_buffers);
+
+int ssc_enable(struct ssc_device *ssc, char tx, char rx)
+{
+	if (tx && rx) {
+		ssc_writel(ssc, CR, SSC_BIT(CR_TXEN)|SSC_BIT(CR_RXEN));
+	}
+	else if (tx) {
+		ssc_writel(ssc, CR, SSC_BIT(CR_TXEN));
+	}
+	else if (rx) {
+		ssc_writel(ssc, CR, SSC_BIT(CR_RXEN));
+	}
+	return 0;
+}
+EXPORT_SYMBOL(ssc_enable);
+
+int ssc_enable_xfer(struct ssc_device *ssc, char tx, char rx)
+{
+	if (tx && rx) {
+		ssc_writel(ssc, PDC_PTCR, SSC_BIT(PDC_PTCR_TXTEN)|SSC_BIT(PDC_PTCR_RXTEN));
+	}
+	else if (tx) {
+		ssc_writel(ssc, PDC_PTCR, SSC_BIT(PDC_PTCR_TXTEN));
+	}
+	else if (rx) {
+		ssc_writel(ssc, PDC_PTCR, SSC_BIT(PDC_PTCR_RXTEN));
+	}
+	return 0;
+}
+EXPORT_SYMBOL(ssc_enable_xfer);
+
+int ssc_disable(struct ssc_device *ssc, char tx, char rx)
+{
+	if (tx && rx) {
+		ssc_writel(ssc, CR, SSC_BIT(CR_TXDIS)|SSC_BIT(CR_RXDIS));
+	}
+	else if (tx) {
+		ssc_writel(ssc, CR, SSC_BIT(CR_TXDIS));
+	}
+	else if (rx) {
+		ssc_writel(ssc, CR, SSC_BIT(CR_RXDIS));
+	}
+	return 0;
+}
+EXPORT_SYMBOL(ssc_disable);
+
+int ssc_disable_xfer(struct ssc_device *ssc, char tx, char rx)
+{
+	if (tx && rx) {
+		ssc_writel(ssc, PDC_PTCR, SSC_BIT(PDC_PTCR_TXTDIS)|SSC_BIT(PDC_PTCR_RXTDIS));
+	}
+	else if (tx) {
+		ssc_writel(ssc, PDC_PTCR, SSC_BIT(PDC_PTCR_TXTDIS));
+	}
+	else if (rx) {
+		ssc_writel(ssc, PDC_PTCR, SSC_BIT(PDC_PTCR_RXTDIS));
+	}
+	return 0;
+}
+EXPORT_SYMBOL(ssc_disable_xfer);
+
+int ssc_enable_int(struct ssc_device *ssc, unsigned int mask)
+{
+	long status;
+
+	ssc_writel(ssc, IER, mask);
+
+	status = ssc_readl(ssc, IMR);
+
+	if (!(status & mask))
+		return -EFAULT;
+
+	return 0;
+}
+EXPORT_SYMBOL(ssc_enable_int);
+
+int ssc_disable_int(struct ssc_device *ssc, unsigned int mask)
+{
+	long status;
+
+	ssc_writel(ssc, IDR, mask);
+
+	status = ssc_readl(ssc, IMR);
+
+	if (status ^ ~mask)
+		return -EFAULT;
+
+	return 0;
+}
+EXPORT_SYMBOL(ssc_disable_int);
+
+int ssc_get_int_mask(struct ssc_device *ssc, unsigned int *mask)
+{
+	*mask = ssc_readl(ssc, IMR);
+	return 0;
+}
+EXPORT_SYMBOL(ssc_get_int_mask);
+
+int ssc_clk_get_rate(struct ssc_device *ssc)
+{
+	return clk_get_rate(ssc->clk);
+}
+EXPORT_SYMBOL(ssc_clk_get_rate);
+
+int ssc_to_irq(struct ssc_device *ssc)
+{
+	return ssc->irq;
+}
+EXPORT_SYMBOL(ssc_to_irq);
+
+struct ssc_device* irq_to_ssc(unsigned int irq)
+{
+	int i;
+	struct ssc_device *ssc;
+
+	for (i = 0; i < MAX_NR_SSC_DEVICES; i++) {
+		ssc = &ssc_dev[i];
+		if (ssc && ssc->irq == irq)
+			return ssc;
+	}
+
+	return ERR_PTR(-ENXIO);
+}
+EXPORT_SYMBOL(irq_to_ssc);
+
+/* End SSC API */
+
+static int __init ssc_probe(struct platform_device *pdev)
+{
+	int retval = 0;
+	struct resource *regs;
+	struct ssc_device *ssc = NULL;
+
+	if (pdev->id > MAX_NR_SSC_DEVICES) {
+		dev_err(&pdev->dev, "only %d SSC devices supported\n",
+				MAX_NR_SSC_DEVICES);
+		retval = -ENODEV;
+		goto out;
+	}
+
+	ssc = &ssc_dev[pdev->id];
+	ssc->user = 0;
+	snprintf(ssc->name, sizeof(ssc->name), "ssc%d", pdev->id);
+
+	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!regs) {
+		dev_err(&pdev->dev, "no mmio resource defined for %s\n",
+				ssc->name);
+		retval = -ENXIO;
+		goto out;
+	}
+
+	ssc->clk = clk_get(&pdev->dev, "pclk");
+	if (IS_ERR(ssc->clk)) {
+		dev_err(&pdev->dev, "no pclk clock defined for %s\n",
+				ssc->name);
+		retval = -ENXIO;
+		goto out;
+	}
+
+	ssc->pdev = pdev;
+	ssc->regs = ioremap(regs->start, regs->end - regs->start + 1);
+
+	mutex_init(&user_mutex);
+
+	/* disable all interrupts */
+	ssc_writel(ssc, IDR, ~0UL);
+	ssc_readl(ssc, SR);
+
+	ssc->irq = platform_get_irq(pdev, 0);
+	if (!ssc->irq) {
+		printk(KERN_ERR "%s: no interrupt for module\n", ssc->name);
+		retval = -ENXIO;
+		goto out_unmap;
+	}
+
+	platform_set_drvdata(pdev, ssc);
+
+	printk(KERN_INFO "%s: Atmel SSC module at 0x%08lx (irq %d)\n",
+			ssc->name, (unsigned long)ssc->regs, ssc->irq);
+
+	goto out;
+
+out_unmap:
+	iounmap(ssc->regs);
+out:
+	return retval;
+}
+
+static int __devexit ssc_remove(struct platform_device *pdev)
+{
+	struct ssc_device *ssc = platform_get_drvdata(pdev);
+
+	if (ssc && ssc->regs)
+		iounmap(ssc->regs);
+	if (ssc && ssc->clk)
+		clk_put(ssc->clk);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver ssc_driver = {
+	.remove		= __devexit_p(ssc_remove),
+	.driver		= {
+		.name		= "ssc",
+	},
+};
+
+static int __init ssc_init(void)
+{
+	return platform_driver_probe(&ssc_driver, ssc_probe);
+}
+
+static void __exit ssc_exit(void)
+{
+	platform_driver_unregister(&ssc_driver);
+}
+
+MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
+MODULE_DESCRIPTION("SSC driver for AVR32 capable of I2S and SPI master (todo)");
+MODULE_LICENSE("GPL");
+
+module_init(ssc_init);
+module_exit(ssc_exit);
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 12af9c7..6514159 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -71,6 +71,16 @@ config MMC_OMAP
 
 	  If unsure, say N.
 
+config MMC_ATMELMCI
+	tristate "Atmel Multimedia Card Interface support"
+	depends on AVR32 && MMC
+	help
+	  This selects the Atmel Multimedia Card Interface. If you have
+	  a AT91 (ARM) or AT32 (AVR32) platform with a Multimedia Card
+	  slot, say Y or M here.
+
+	  If unsure, say N.
+
 config MMC_WBSD
 	tristate "Winbond W83L51xD SD/MMC Card Interface support"
 	depends on MMC && ISA_DMA_API
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 83ffb93..caf30e0 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_MMC_WBSD)		+= wbsd.o
 obj-$(CONFIG_MMC_AU1X)		+= au1xmmc.o
 obj-$(CONFIG_MMC_OMAP)		+= omap.o
 obj-$(CONFIG_MMC_AT91)		+= at91_mci.o
+obj-$(CONFIG_MMC_ATMELMCI)	+= atmel-mci.o
 obj-$(CONFIG_MMC_TIFM_SD)	+= tifm_sd.o
 
 mmc_core-y := mmc.o mmc_sysfs.o
diff --git a/drivers/mmc/atmel-mci.c b/drivers/mmc/atmel-mci.c
new file mode 100644
index 0000000..ebeab32
--- /dev/null
+++ b/drivers/mmc/atmel-mci.c
@@ -0,0 +1,1218 @@
+/*
+ * Atmel MultiMedia Card Interface driver
+ *
+ * Copyright (C) 2004-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.
+ */
+#include <linux/blkdev.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/protocol.h>
+
+#include <asm/dma-controller.h>
+#include <asm/io.h>
+#include <asm/arch/board.h>
+#include <asm/arch/gpio.h>
+
+#include "atmel-mci.h"
+
+#define DRIVER_NAME "atmel_mci"
+
+#define MCI_CMD_ERROR_FLAGS	(MCI_BIT(RINDE)	| MCI_BIT(RDIRE) |	\
+				 MCI_BIT(RCRCE) | MCI_BIT(RENDE) |	\
+				 MCI_BIT(RTOE))
+#define MCI_DATA_ERROR_FLAGS	(MCI_BIT(DCRCE) | MCI_BIT(DTOE) |	\
+				 MCI_BIT(OVRE) | MCI_BIT(UNRE))
+
+enum {
+	EVENT_CMD_COMPLETE = 0,
+	EVENT_CMD_ERROR,
+	EVENT_DATA_COMPLETE,
+	EVENT_DATA_ERROR,
+	EVENT_STOP_SENT,
+	EVENT_STOP_COMPLETE,
+	EVENT_STOP_ERROR,
+	EVENT_DMA_ERROR,
+	EVENT_CARD_DETECT,
+};
+
+struct atmel_mci_dma {
+	struct dma_request_sg	req;
+	unsigned short		rx_periph_id;
+	unsigned short		tx_periph_id;
+};
+
+struct atmel_mci {
+	struct mmc_host		*mmc;
+	void __iomem		*regs;
+	struct atmel_mci_dma	dma;
+
+	struct mmc_request	*mrq;
+	struct mmc_command	*cmd;
+	struct mmc_data		*data;
+
+	u32			stop_cmdr;
+	u32			stop_iflags;
+
+	struct tasklet_struct	tasklet;
+	unsigned long		pending_events;
+	unsigned long		completed_events;
+	u32			error_status;
+
+	int			present;
+	int			detect_pin;
+	int			wp_pin;
+
+	unsigned long		bus_hz;
+	unsigned long		mapbase;
+	struct clk		*mck;
+	struct platform_device	*pdev;
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry		*debugfs_root;
+	struct dentry		*debugfs_regs;
+	struct dentry		*debugfs_req;
+	struct dentry		*debugfs_pending_events;
+	struct dentry		*debugfs_completed_events;
+#endif
+};
+
+/* Those printks take an awful lot of time... */
+#ifndef DEBUG
+static unsigned int fmax = 15000000U;
+#else
+static unsigned int fmax = 1000000U;
+#endif
+module_param(fmax, uint, 0444);
+MODULE_PARM_DESC(fmax, "Max frequency in Hz of the MMC bus clock");
+
+/* Test bit macros for completed events */
+#define mci_cmd_is_complete(host)			\
+	test_bit(EVENT_CMD_COMPLETE, &host->completed_events)
+#define mci_cmd_error_is_complete(host)			\
+	test_bit(EVENT_CMD_ERROR, &host->completed_events)
+#define mci_data_is_complete(host)			\
+	test_bit(EVENT_DATA_COMPLETE, &host->completed_events)
+#define mci_data_error_is_complete(host)		\
+	test_bit(EVENT_DATA_ERROR, &host->completed_events)
+#define mci_stop_sent_is_complete(host)			\
+	test_bit(EVENT_STOP_SENT, &host->completed_events)
+#define mci_stop_is_complete(host)			\
+	test_bit(EVENT_STOP_COMPLETE, &host->completed_events)
+#define mci_stop_error_is_complete(host)		\
+	test_bit(EVENT_STOP_ERROR, &host->completed_events)
+#define mci_dma_error_is_complete(host)			\
+	test_bit(EVENT_DMA_ERROR, &host->completed_events)
+#define mci_card_detect_is_complete(host)			\
+	test_bit(EVENT_CARD_DETECT, &host->completed_events)
+
+/* Test and clear bit macros for pending events */
+#define mci_clear_cmd_is_pending(host)			\
+	test_and_clear_bit(EVENT_CMD_COMPLETE, &host->pending_events)
+#define mci_clear_cmd_error_is_pending(host)		\
+	test_and_clear_bit(EVENT_CMD_ERROR, &host->pending_events)
+#define mci_clear_data_is_pending(host)			\
+	test_and_clear_bit(EVENT_DATA_COMPLETE, &host->pending_events)
+#define mci_clear_data_error_is_pending(host)		\
+	test_and_clear_bit(EVENT_DATA_ERROR, &host->pending_events)
+#define mci_clear_stop_sent_is_pending(host)		\
+	test_and_clear_bit(EVENT_STOP_SENT, &host->pending_events)
+#define mci_clear_stop_is_pending(host)			\
+	test_and_clear_bit(EVENT_STOP_COMPLETE, &host->pending_events)
+#define mci_clear_stop_error_is_pending(host)		\
+	test_and_clear_bit(EVENT_STOP_ERROR, &host->pending_events)
+#define mci_clear_dma_error_is_pending(host)		\
+	test_and_clear_bit(EVENT_DMA_ERROR, &host->pending_events)
+#define mci_clear_card_detect_is_pending(host)		\
+	test_and_clear_bit(EVENT_CARD_DETECT, &host->pending_events)
+
+/* Test and set bit macros for completed events */
+#define mci_set_cmd_is_completed(host)			\
+	test_and_set_bit(EVENT_CMD_COMPLETE, &host->completed_events)
+#define mci_set_cmd_error_is_completed(host)		\
+	test_and_set_bit(EVENT_CMD_ERROR, &host->completed_events)
+#define mci_set_data_is_completed(host)			\
+	test_and_set_bit(EVENT_DATA_COMPLETE, &host->completed_events)
+#define mci_set_data_error_is_completed(host)		\
+	test_and_set_bit(EVENT_DATA_ERROR, &host->completed_events)
+#define mci_set_stop_sent_is_completed(host)		\
+	test_and_set_bit(EVENT_STOP_SENT, &host->completed_events)
+#define mci_set_stop_is_completed(host)			\
+	test_and_set_bit(EVENT_STOP_COMPLETE, &host->completed_events)
+#define mci_set_stop_error_is_completed(host)		\
+	test_and_set_bit(EVENT_STOP_ERROR, &host->completed_events)
+#define mci_set_dma_error_is_completed(host)		\
+	test_and_set_bit(EVENT_DMA_ERROR, &host->completed_events)
+#define mci_set_card_detect_is_completed(host)		\
+	test_and_set_bit(EVENT_CARD_DETECT, &host->completed_events)
+
+/* Set bit macros for completed events */
+#define mci_set_cmd_complete(host)			\
+	set_bit(EVENT_CMD_COMPLETE, &host->completed_events)
+#define mci_set_cmd_error_complete(host)		\
+	set_bit(EVENT_CMD_ERROR, &host->completed_events)
+#define mci_set_data_complete(host)			\
+	set_bit(EVENT_DATA_COMPLETE, &host->completed_events)
+#define mci_set_data_error_complete(host)		\
+	set_bit(EVENT_DATA_ERROR, &host->completed_events)
+#define mci_set_stop_sent_complete(host)		\
+	set_bit(EVENT_STOP_SENT, &host->completed_events)
+#define mci_set_stop_complete(host)			\
+	set_bit(EVENT_STOP_COMPLETE, &host->completed_events)
+#define mci_set_stop_error_complete(host)		\
+	set_bit(EVENT_STOP_ERROR, &host->completed_events)
+#define mci_set_dma_error_complete(host)		\
+	set_bit(EVENT_DMA_ERROR, &host->completed_events)
+#define mci_set_card_detect_complete(host)		\
+	set_bit(EVENT_CARD_DETECT, &host->completed_events)
+
+/* Set bit macros for pending events */
+#define mci_set_cmd_pending(host)			\
+	set_bit(EVENT_CMD_COMPLETE, &host->pending_events)
+#define mci_set_cmd_error_pending(host)			\
+	set_bit(EVENT_CMD_ERROR, &host->pending_events)
+#define mci_set_data_pending(host)			\
+	set_bit(EVENT_DATA_COMPLETE, &host->pending_events)
+#define mci_set_data_error_pending(host)		\
+	set_bit(EVENT_DATA_ERROR, &host->pending_events)
+#define mci_set_stop_sent_pending(host)			\
+	set_bit(EVENT_STOP_SENT, &host->pending_events)
+#define mci_set_stop_pending(host)			\
+	set_bit(EVENT_STOP_COMPLETE, &host->pending_events)
+#define mci_set_stop_error_pending(host)		\
+	set_bit(EVENT_STOP_ERROR, &host->pending_events)
+#define mci_set_dma_error_pending(host)			\
+	set_bit(EVENT_DMA_ERROR, &host->pending_events)
+#define mci_set_card_detect_pending(host)		\
+	set_bit(EVENT_CARD_DETECT, &host->pending_events)
+
+/* Clear bit macros for pending events */
+#define mci_clear_cmd_pending(host)			\
+	clear_bit(EVENT_CMD_COMPLETE, &host->pending_events)
+#define mci_clear_cmd_error_pending(host)		\
+	clear_bit(EVENT_CMD_ERROR, &host->pending_events)
+#define mci_clear_data_pending(host)			\
+	clear_bit(EVENT_DATA_COMPLETE, &host->pending_events)
+#define mci_clear_data_error_pending(host)		\
+	clear_bit(EVENT_DATA_ERROR, &host->pending_events)
+#define mci_clear_stop_sent_pending(host)		\
+	clear_bit(EVENT_STOP_SENT, &host->pending_events)
+#define mci_clear_stop_pending(host)			\
+	clear_bit(EVENT_STOP_COMPLETE, &host->pending_events)
+#define mci_clear_stop_error_pending(host)		\
+	clear_bit(EVENT_STOP_ERROR, &host->pending_events)
+#define mci_clear_dma_error_pending(host)		\
+	clear_bit(EVENT_DMA_ERROR, &host->pending_events)
+#define mci_clear_card_detect_pending(host)		\
+	clear_bit(EVENT_CARD_DETECT, &host->pending_events)
+
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+
+#define DBG_REQ_BUF_SIZE	(4096 - sizeof(unsigned int))
+
+struct req_dbg_data {
+	unsigned int nbytes;
+	char str[DBG_REQ_BUF_SIZE];
+};
+
+static int req_dbg_open(struct inode *inode, struct file *file)
+{
+	struct atmel_mci *host;
+	struct mmc_request *mrq;
+	struct mmc_command *cmd, *stop;
+	struct mmc_data *data;
+	struct req_dbg_data *priv;
+	char *str;
+	unsigned long n = 0;
+
+	priv = kzalloc(DBG_REQ_BUF_SIZE, GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	str = priv->str;
+
+	mutex_lock(&inode->i_mutex);
+	host = inode->i_private;
+
+	spin_lock_irq(&host->mmc->lock);
+	mrq = host->mrq;
+	if (mrq) {
+		cmd = mrq->cmd;
+		data = mrq->data;
+		stop = mrq->stop;
+		n = snprintf(str, DBG_REQ_BUF_SIZE,
+			     "CMD%u(0x%x) %x %x %x %x %x (err %u)\n",
+			     cmd->opcode, cmd->arg, cmd->flags,
+			     cmd->resp[0], cmd->resp[1], cmd->resp[2],
+			     cmd->resp[3], cmd->error);
+		if (n < DBG_REQ_BUF_SIZE && data)
+			n += snprintf(str + n, DBG_REQ_BUF_SIZE - n,
+				      "DATA %u * %u (%u) %x (err %u)\n",
+				      data->blocks, data->blksz,
+				      data->bytes_xfered, data->flags,
+				      data->error);
+		if (n < DBG_REQ_BUF_SIZE && stop)
+			n += snprintf(str + n, DBG_REQ_BUF_SIZE - n,
+				      "CMD%u(0x%x) %x %x %x %x %x (err %u)\n",
+				      stop->opcode, stop->arg, stop->flags,
+				      stop->resp[0], stop->resp[1],
+				      stop->resp[2], stop->resp[3],
+				      stop->error);
+	}
+	spin_unlock_irq(&host->mmc->lock);
+	mutex_unlock(&inode->i_mutex);
+
+	priv->nbytes = min(n, DBG_REQ_BUF_SIZE);
+	file->private_data = priv;
+
+	return 0;
+}
+
+static ssize_t req_dbg_read(struct file *file, char __user *buf,
+			    size_t nbytes, loff_t *ppos)
+{
+	struct req_dbg_data *priv = file->private_data;
+
+	return simple_read_from_buffer(buf, nbytes, ppos,
+				       priv->str, priv->nbytes);
+}
+
+static int req_dbg_release(struct inode *inode, struct file *file)
+{
+	kfree(file->private_data);
+	return 0;
+}
+
+static const struct file_operations req_dbg_fops = {
+	.owner		= THIS_MODULE,
+	.open		= req_dbg_open,
+	.llseek		= no_llseek,
+	.read		= req_dbg_read,
+	.release	= req_dbg_release,
+};
+
+static int regs_dbg_open(struct inode *inode, struct file *file)
+{
+	struct atmel_mci *host;
+	unsigned int i;
+	u32 *data;
+	int ret = -ENOMEM;
+
+	mutex_lock(&inode->i_mutex);
+	host = inode->i_private;
+	data = kmalloc(inode->i_size, GFP_KERNEL);
+	if (!data)
+		goto out;
+
+	spin_lock_irq(&host->mmc->lock);
+	for (i = 0; i < inode->i_size / 4; i++)
+		data[i] = __raw_readl(host->regs + i * 4);
+	spin_unlock_irq(&host->mmc->lock);
+
+	file->private_data = data;
+	ret = 0;
+
+out:
+	mutex_unlock(&inode->i_mutex);
+
+	return ret;
+}
+
+static ssize_t regs_dbg_read(struct file *file, char __user *buf,
+			     size_t nbytes, loff_t *ppos)
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	int ret;
+
+	mutex_lock(&inode->i_mutex);
+	ret = simple_read_from_buffer(buf, nbytes, ppos,
+				      file->private_data,
+				      file->f_dentry->d_inode->i_size);
+	mutex_unlock(&inode->i_mutex);
+
+	return ret;
+}
+
+static int regs_dbg_release(struct inode *inode, struct file *file)
+{
+	kfree(file->private_data);
+	return 0;
+}
+
+static const struct file_operations regs_dbg_fops = {
+	.owner		= THIS_MODULE,
+	.open		= regs_dbg_open,
+	.llseek		= generic_file_llseek,
+	.read		= regs_dbg_read,
+	.release	= regs_dbg_release,
+};
+
+static void atmci_init_debugfs(struct atmel_mci *host)
+{
+	struct mmc_host *mmc;
+	struct dentry *root, *regs;
+	struct resource *res;
+
+	mmc = host->mmc;
+	root = debugfs_create_dir(mmc_hostname(mmc), NULL);
+	if (IS_ERR(root) || !root)
+		goto err_root;
+	host->debugfs_root = root;
+
+	regs = debugfs_create_file("regs", 0400, root, host, &regs_dbg_fops);
+	if (!regs)
+		goto err_regs;
+
+	res = platform_get_resource(host->pdev, IORESOURCE_MEM, 0);
+	regs->d_inode->i_size = res->end - res->start + 1;
+	host->debugfs_regs = regs;
+
+	host->debugfs_req = debugfs_create_file("req", 0400, root,
+						host, &req_dbg_fops);
+	if (!host->debugfs_req)
+		goto err_req;
+
+	host->debugfs_pending_events
+		= debugfs_create_u32("pending_events", 0400, root,
+				     (u32 *)&host->pending_events);
+	if (!host->debugfs_pending_events)
+		goto err_pending_events;
+
+	host->debugfs_completed_events
+		= debugfs_create_u32("completed_events", 0400, root,
+				     (u32 *)&host->completed_events);
+	if (!host->debugfs_completed_events)
+		goto err_completed_events;
+
+	return;
+
+err_completed_events:
+	debugfs_remove(host->debugfs_pending_events);
+err_pending_events:
+	debugfs_remove(host->debugfs_req);
+err_req:
+	debugfs_remove(host->debugfs_regs);
+err_regs:
+	debugfs_remove(host->debugfs_root);
+err_root:
+	host->debugfs_root = NULL;
+	dev_err(&host->pdev->dev,
+		"failed to initialize debugfs for %s\n",
+		mmc_hostname(mmc));
+}
+
+static void atmci_cleanup_debugfs(struct atmel_mci *host)
+{
+	if (host->debugfs_root) {
+		debugfs_remove(host->debugfs_completed_events);
+		debugfs_remove(host->debugfs_pending_events);
+		debugfs_remove(host->debugfs_req);
+		debugfs_remove(host->debugfs_regs);
+		debugfs_remove(host->debugfs_root);
+		host->debugfs_root = NULL;
+	}
+}
+#else
+static inline void atmci_init_debugfs(struct atmel_mci *host)
+{
+
+}
+
+static inline void atmci_cleanup_debugfs(struct atmel_mci *host)
+{
+
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static inline unsigned int ns_to_clocks(struct atmel_mci *host,
+					unsigned int ns)
+{
+	return (ns * (host->bus_hz / 1000000) + 999) / 1000;
+}
+
+static void atmci_set_timeout(struct atmel_mci *host,
+			      struct mmc_data *data)
+{
+	static unsigned dtomul_to_shift[] = {
+		0, 4, 7, 8, 10, 12, 16, 20
+	};
+	unsigned timeout;
+	unsigned dtocyc, dtomul;
+
+	timeout = ns_to_clocks(host, data->timeout_ns) + data->timeout_clks;
+
+	for (dtomul = 0; dtomul < 8; dtomul++) {
+		unsigned shift = dtomul_to_shift[dtomul];
+		dtocyc = (timeout + (1 << shift) - 1) >> shift;
+		if (dtocyc < 15)
+			break;
+	}
+
+	if (dtomul >= 8) {
+		dtomul = 7;
+		dtocyc = 15;
+	}
+
+	pr_debug("%s: setting timeout to %u cycles\n",
+		 mmc_hostname(host->mmc),
+		 dtocyc << dtomul_to_shift[dtomul]);
+	mci_writel(host, DTOR, (MCI_BF(DTOMUL, dtomul)
+				| MCI_BF(DTOCYC, dtocyc)));
+}
+
+/*
+ * Return mask with interrupt flags to be handled for this command.
+ */
+static u32 atmci_prepare_command(struct mmc_host *mmc,
+				 struct mmc_command *cmd,
+				 u32 *cmd_flags)
+{
+	u32 cmdr;
+	u32 iflags;
+
+	cmd->error = MMC_ERR_NONE;
+
+	cmdr = 0;
+	BUG_ON(MCI_BFEXT(CMDNB, cmdr) != 0);
+	cmdr = MCI_BFINS(CMDNB, cmd->opcode, cmdr);
+
+	if (cmd->flags & MMC_RSP_PRESENT) {
+		if (cmd->flags & MMC_RSP_136)
+			cmdr |= MCI_BF(RSPTYP, MCI_RSPTYP_136_BIT);
+		else
+			cmdr |= MCI_BF(RSPTYP, MCI_RSPTYP_48_BIT);
+	}
+
+	/*
+	 * This should really be MAXLAT_5 for CMD2 and ACMD41, but
+	 * it's too difficult to determine whether this is an ACMD or
+	 * not. Better make it 64.
+	 */
+	cmdr |= MCI_BIT(MAXLAT);
+
+	if (mmc->ios.bus_mode == MMC_BUSMODE_OPENDRAIN)
+		cmdr |= MCI_BIT(OPDCMD);
+
+	iflags = MCI_BIT(CMDRDY) | MCI_CMD_ERROR_FLAGS;
+	if (!(cmd->flags & MMC_RSP_CRC))
+		iflags &= ~MCI_BIT(RCRCE);
+
+	pr_debug("%s: cmd: op %02x arg %08x flags %08x, cmdflags %08lx\n",
+		 mmc_hostname(mmc), cmd->opcode, cmd->arg, cmd->flags,
+		 (unsigned long)cmdr);
+
+	*cmd_flags = cmdr;
+	return iflags;
+}
+
+static void atmci_start_command(struct atmel_mci *host,
+				struct mmc_command *cmd,
+				u32 cmd_flags)
+{
+	WARN_ON(host->cmd);
+	host->cmd = cmd;
+
+	mci_writel(host, ARGR, cmd->arg);
+	mci_writel(host, CMDR, cmd_flags);
+
+	if (cmd->data)
+		dma_start_request(host->dma.req.req.dmac,
+				  host->dma.req.req.channel);
+}
+
+/*
+ * Returns a mask of flags to be set in the command register when the
+ * command to start the transfer is to be sent.
+ */
+static u32 atmci_prepare_data(struct mmc_host *mmc, struct mmc_data *data)
+{
+	struct atmel_mci *host = mmc_priv(mmc);
+	u32 cmd_flags;
+
+	WARN_ON(host->data);
+	host->data = data;
+
+	atmci_set_timeout(host, data);
+	mci_writel(host, BLKR, (MCI_BF(BCNT, data->blocks)
+				| MCI_BF(BLKLEN, data->blksz)));
+	host->dma.req.block_size = data->blksz;
+	host->dma.req.nr_blocks = data->blocks;
+
+	cmd_flags = MCI_BF(TRCMD, MCI_TRCMD_START_TRANS);
+	if (data->flags & MMC_DATA_STREAM)
+		cmd_flags |= MCI_BF(TRTYP, MCI_TRTYP_STREAM);
+	else if (data->blocks > 1)
+		cmd_flags |= MCI_BF(TRTYP, MCI_TRTYP_MULTI_BLOCK);
+	else
+		cmd_flags |= MCI_BF(TRTYP, MCI_TRTYP_BLOCK);
+
+	if (data->flags & MMC_DATA_READ) {
+		cmd_flags |= MCI_BIT(TRDIR);
+		host->dma.req.nr_sg
+			= dma_map_sg(&host->pdev->dev, data->sg,
+				     data->sg_len, DMA_FROM_DEVICE);
+		host->dma.req.periph_id = host->dma.rx_periph_id;
+		host->dma.req.direction = DMA_DIR_PERIPH_TO_MEM;
+		host->dma.req.data_reg = host->mapbase + MCI_RDR;
+	} else {
+		host->dma.req.nr_sg
+			= dma_map_sg(&host->pdev->dev, data->sg,
+				     data->sg_len, DMA_TO_DEVICE);
+		host->dma.req.periph_id = host->dma.tx_periph_id;
+		host->dma.req.direction = DMA_DIR_MEM_TO_PERIPH;
+		host->dma.req.data_reg = host->mapbase + MCI_TDR;
+	}
+	host->dma.req.sg = data->sg;
+
+	dma_prepare_request_sg(host->dma.req.req.dmac, &host->dma.req);
+
+	return cmd_flags;
+}
+
+static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct atmel_mci *host = mmc_priv(mmc);
+	struct mmc_data *data = mrq->data;
+	u32 iflags;
+	u32 cmdflags = 0;
+
+	iflags = mci_readl(host, IMR);
+	if (iflags)
+		printk("WARNING: IMR=0x%08x\n", mci_readl(host, IMR));
+
+	WARN_ON(host->mrq != NULL);
+	host->mrq = mrq;
+	host->pending_events = 0;
+	host->completed_events = 0;
+
+	iflags = atmci_prepare_command(mmc, mrq->cmd, &cmdflags);
+
+	if (mrq->stop) {
+		BUG_ON(!data);
+
+		host->stop_iflags = atmci_prepare_command(mmc, mrq->stop,
+							  &host->stop_cmdr);
+		host->stop_cmdr |= MCI_BF(TRCMD, MCI_TRCMD_STOP_TRANS);
+		if (!(data->flags & MMC_DATA_WRITE))
+			host->stop_cmdr |= MCI_BIT(TRDIR);
+		if (data->flags & MMC_DATA_STREAM)
+			host->stop_cmdr |= MCI_BF(TRTYP, MCI_TRTYP_STREAM);
+		else
+			host->stop_cmdr |= MCI_BF(TRTYP, MCI_TRTYP_MULTI_BLOCK);
+	}
+	if (data) {
+		cmdflags |= atmci_prepare_data(mmc, data);
+		iflags |= MCI_DATA_ERROR_FLAGS;
+	}
+
+	atmci_start_command(host, mrq->cmd, cmdflags);
+	mci_writel(host, IER, iflags);
+}
+
+static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct atmel_mci *host = mmc_priv(mmc);
+
+	if (ios->clock) {
+		u32 clkdiv;
+
+		clkdiv = host->bus_hz / (2 * ios->clock) - 1;
+		if (clkdiv > 255)
+			clkdiv = 255;
+		mci_writel(host, MR, (clkdiv
+				      | MCI_BIT(WRPROOF)
+				      | MCI_BIT(RDPROOF)));
+	}
+
+	switch (ios->bus_width) {
+	case MMC_BUS_WIDTH_1:
+		mci_writel(host, SDCR, 0);
+		break;
+	case MMC_BUS_WIDTH_4:
+		mci_writel(host, SDCR, MCI_BIT(SDCBUS));
+		break;
+	}
+
+	switch (ios->power_mode) {
+	case MMC_POWER_OFF:
+		mci_writel(host, CR, MCI_BIT(MCIDIS));
+		break;
+	case MMC_POWER_UP:
+		mci_writel(host, CR, MCI_BIT(SWRST));
+		break;
+	case MMC_POWER_ON:
+		mci_writel(host, CR, MCI_BIT(MCIEN));
+		break;
+	}
+}
+
+static int atmci_get_ro(struct mmc_host *mmc)
+{
+	int read_only = 0;
+	struct atmel_mci *host = mmc_priv(mmc);
+
+	if (host->wp_pin >= 0) {
+		read_only = gpio_get_value(host->wp_pin);
+		pr_debug("%s: card is %s\n", mmc_hostname(mmc),
+			 read_only ? "read-only" : "read-write");
+	} else {
+		pr_debug("%s: no pin for checking read-only switch."
+			 " Assuming write-enable.\n", mmc_hostname(mmc));
+	}
+
+	return read_only;
+}
+
+static struct mmc_host_ops atmci_ops = {
+	.request	= atmci_request,
+	.set_ios	= atmci_set_ios,
+	.get_ro		= atmci_get_ro,
+};
+
+static void atmci_request_end(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct atmel_mci *host = mmc_priv(mmc);
+
+	WARN_ON(host->cmd || host->data);
+	host->mrq = NULL;
+
+	mmc_request_done(mmc, mrq);
+}
+
+static void send_stop_cmd(struct mmc_host *mmc, struct mmc_data *data,
+			  u32 flags)
+{
+	struct atmel_mci *host = mmc_priv(mmc);
+
+	atmci_start_command(host, data->stop, host->stop_cmdr | flags);
+	mci_writel(host, IER, host->stop_iflags);
+}
+
+static void atmci_data_complete(struct atmel_mci *host, struct mmc_data *data)
+{
+	host->data = NULL;
+	dma_unmap_sg(&host->pdev->dev, data->sg, host->dma.req.nr_sg,
+		     ((data->flags & MMC_DATA_WRITE)
+		      ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
+
+	/*
+	 * Data might complete before command for very short transfers
+	 * (like READ_SCR)
+	 */
+	if (mci_cmd_is_complete(host)
+	    && (!data->stop || mci_stop_is_complete(host)))
+		atmci_request_end(host->mmc, data->mrq);
+}
+
+static void atmci_command_error(struct mmc_host *mmc,
+				struct mmc_command *cmd,
+				u32 status)
+{
+	pr_debug("%s: command error: status=0x%08x\n",
+		 mmc_hostname(mmc), status);
+
+	if (status & MCI_BIT(RTOE))
+		cmd->error = MMC_ERR_TIMEOUT;
+	else if (status & MCI_BIT(RCRCE))
+		cmd->error = MMC_ERR_BADCRC;
+	else
+		cmd->error = MMC_ERR_FAILED;
+}
+
+static void atmci_tasklet_func(unsigned long priv)
+{
+	struct mmc_host *mmc = (struct mmc_host *)priv;
+	struct atmel_mci *host = mmc_priv(mmc);
+	struct mmc_request *mrq = host->mrq;
+	struct mmc_data *data = host->data;
+
+	pr_debug("atmci_tasklet: pending/completed/mask %lx/%lx/%x\n",
+		 host->pending_events, host->completed_events,
+		 mci_readl(host, IMR));
+
+	if (mci_clear_cmd_error_is_pending(host)) {
+		struct mmc_command *cmd;
+
+		mci_set_cmd_error_complete(host);
+		mci_clear_cmd_pending(host);
+		cmd = host->mrq->cmd;
+
+		if (cmd->data) {
+			dma_stop_request(host->dma.req.req.dmac,
+					 host->dma.req.req.channel);
+			host->data = NULL;
+		}
+
+		atmci_command_error(mmc, cmd, host->error_status);
+		atmci_request_end(mmc, cmd->mrq);
+	}
+	if (mci_clear_stop_error_is_pending(host)) {
+		mci_set_stop_error_complete(host);
+		mci_clear_stop_pending(host);
+		atmci_command_error(mmc, host->mrq->stop,
+				    host->error_status);
+		if (!host->data)
+			atmci_request_end(mmc, host->mrq);
+	}
+	if (mci_clear_cmd_is_pending(host)) {
+		mci_set_cmd_complete(host);
+		if (!mrq->data || mci_data_is_complete(host)
+		    || mci_data_error_is_complete(host))
+			atmci_request_end(mmc, mrq);
+	}
+	if (mci_clear_stop_is_pending(host)) {
+		mci_set_stop_complete(host);
+		if (mci_data_is_complete(host)
+		    || mci_data_error_is_complete(host))
+			atmci_request_end(mmc, mrq);
+	}
+	if (mci_clear_dma_error_is_pending(host)) {
+		mci_set_dma_error_complete(host);
+		mci_clear_data_pending(host);
+
+		/* DMA controller got bus error => invalid address */
+		data->error = MMC_ERR_INVALID;
+
+		printk(KERN_DEBUG "%s: dma error after %u bytes xfered\n",
+		       mmc_hostname(mmc), host->data->bytes_xfered);
+
+		if (data->stop
+		    && !mci_set_stop_sent_is_completed(host))
+			/* TODO: Check if card is still present */
+			send_stop_cmd(host->mmc, data, 0);
+
+		atmci_data_complete(host, data);
+	}
+	if (mci_clear_data_error_is_pending(host)) {
+		u32 status = host->error_status;
+
+		mci_set_data_error_complete(host);
+		mci_clear_data_pending(host);
+
+		dma_stop_request(host->dma.req.req.dmac,
+				 host->dma.req.req.channel);
+
+		printk(KERN_DEBUG "%s: data error: status=0x%08x\n",
+		       mmc_hostname(host->mmc), status);
+
+		if (status & MCI_BIT(DCRCE)) {
+			printk(KERN_DEBUG "%s: Data CRC error\n",
+			       mmc_hostname(host->mmc));
+			data->error = MMC_ERR_BADCRC;
+		} else if (status & MCI_BIT(DTOE)) {
+			printk(KERN_DEBUG "%s: Data Timeout error\n",
+			       mmc_hostname(host->mmc));
+			data->error = MMC_ERR_TIMEOUT;
+		} else {
+			printk(KERN_DEBUG "%s: Data FIFO error\n",
+			       mmc_hostname(host->mmc));
+			data->error = MMC_ERR_FIFO;
+		}
+		printk(KERN_DEBUG "%s: Bytes xfered: %u\n",
+		       mmc_hostname(host->mmc), data->bytes_xfered);
+
+		if (data->stop
+		    && !mci_set_stop_sent_is_completed(host))
+			/* TODO: Check if card is still present */
+			send_stop_cmd(host->mmc, data, 0);
+
+		atmci_data_complete(host, data);
+	}
+	if (mci_clear_data_is_pending(host)) {
+		mci_set_data_complete(host);
+		data->bytes_xfered = data->blocks * data->blksz;
+		atmci_data_complete(host, data);
+	}
+	if (mci_clear_card_detect_is_pending(host)) {
+		/* Reset controller if card is gone */
+		if (!host->present) {
+			mci_writel(host, CR, MCI_BIT(SWRST));
+			mci_writel(host, IDR, ~0UL);
+			mci_writel(host, CR, MCI_BIT(MCIEN));
+		}
+
+		/* Clean up queue if present */
+		if (mrq) {
+			if (!mci_cmd_is_complete(host)
+			    && !mci_cmd_error_is_complete(host)) {
+				mrq->cmd->error = MMC_ERR_TIMEOUT;
+			}
+			if (mrq->data && !mci_data_is_complete(host)
+			    && !mci_data_error_is_complete(host)) {
+				dma_stop_request(host->dma.req.req.dmac,
+						host->dma.req.req.channel);
+				host->data->error = MMC_ERR_TIMEOUT;
+				atmci_data_complete(host, data);
+			}
+			if (mrq->stop && !mci_stop_is_complete(host)
+			    && !mci_stop_error_is_complete(host)) {
+				mrq->stop->error = MMC_ERR_TIMEOUT;
+			}
+
+			host->cmd = NULL;
+			atmci_request_end(mmc, mrq);
+		}
+		mmc_detect_change(host->mmc, msecs_to_jiffies(100));
+	}
+}
+
+static void atmci_cmd_interrupt(struct mmc_host *mmc, u32 status)
+{
+	struct atmel_mci *host = mmc_priv(mmc);
+	struct mmc_command *cmd = host->cmd;
+
+	/*
+	 * Read the response now so that we're free to send a new
+	 * command immediately.
+	 */
+	cmd->resp[0] = mci_readl(host, RSPR);
+	cmd->resp[1] = mci_readl(host, RSPR);
+	cmd->resp[2] = mci_readl(host, RSPR);
+	cmd->resp[3] = mci_readl(host, RSPR);
+
+	mci_writel(host, IDR, MCI_BIT(CMDRDY) | MCI_CMD_ERROR_FLAGS);
+	host->cmd = NULL;
+
+	if (mci_stop_sent_is_complete(host))
+		mci_set_stop_pending(host);
+	else
+		mci_set_cmd_pending(host);
+
+	tasklet_schedule(&host->tasklet);
+}
+
+static void atmci_xfer_complete(struct dma_request *_req)
+{
+	struct dma_request_sg *req = to_dma_request_sg(_req);
+	struct atmel_mci_dma *dma;
+	struct atmel_mci *host;
+	struct mmc_data *data;
+
+	dma = container_of(req, struct atmel_mci_dma, req);
+	host = container_of(dma, struct atmel_mci, dma);
+	data = host->data;
+
+	if (data->stop && !mci_set_stop_sent_is_completed(host))
+		send_stop_cmd(host->mmc, data, 0);
+
+	if (data->flags & MMC_DATA_READ) {
+		mci_writel(host, IDR, MCI_DATA_ERROR_FLAGS);
+		mci_set_data_pending(host);
+		tasklet_schedule(&host->tasklet);
+	} else {
+		/*
+		 * For the WRITE case, wait for NOTBUSY. This function
+		 * is called when everything has been written to the
+		 * controller, not when the card is done programming.
+		 */
+		mci_writel(host, IER, MCI_BIT(NOTBUSY));
+	}
+}
+
+static void atmci_dma_error(struct dma_request *_req)
+{
+	struct dma_request_sg *req = to_dma_request_sg(_req);
+	struct atmel_mci_dma *dma;
+	struct atmel_mci *host;
+
+	dma = container_of(req, struct atmel_mci_dma, req);
+	host = container_of(dma, struct atmel_mci, dma);
+
+	mci_writel(host, IDR, (MCI_BIT(NOTBUSY)
+			       | MCI_DATA_ERROR_FLAGS));
+
+	mci_set_dma_error_pending(host);
+	tasklet_schedule(&host->tasklet);
+}
+
+static irqreturn_t atmci_interrupt(int irq, void *dev_id)
+{
+	struct mmc_host *mmc = dev_id;
+	struct atmel_mci *host = mmc_priv(mmc);
+	u32 status, mask, pending;
+
+	spin_lock(&mmc->lock);
+
+	status = mci_readl(host, SR);
+	mask = mci_readl(host, IMR);
+	pending = status & mask;
+
+	do {
+		if (pending & MCI_CMD_ERROR_FLAGS) {
+			mci_writel(host, IDR, (MCI_BIT(CMDRDY)
+					       | MCI_BIT(NOTBUSY)
+					       | MCI_CMD_ERROR_FLAGS
+					       | MCI_DATA_ERROR_FLAGS));
+			host->error_status = status;
+			host->cmd = NULL;
+			if (mci_stop_sent_is_complete(host))
+				mci_set_stop_error_pending(host);
+			else
+				mci_set_cmd_error_pending(host);
+			tasklet_schedule(&host->tasklet);
+			break;
+		}
+		if (pending & MCI_DATA_ERROR_FLAGS) {
+			mci_writel(host, IDR, (MCI_BIT(NOTBUSY)
+					       | MCI_DATA_ERROR_FLAGS));
+			host->error_status = status;
+			mci_set_data_error_pending(host);
+			tasklet_schedule(&host->tasklet);
+			break;
+		}
+		if (pending & MCI_BIT(CMDRDY))
+			atmci_cmd_interrupt(mmc, status);
+		if (pending & MCI_BIT(NOTBUSY)) {
+			mci_writel(host, IDR, (MCI_BIT(NOTBUSY)
+					       | MCI_DATA_ERROR_FLAGS));
+			mci_set_data_pending(host);
+			tasklet_schedule(&host->tasklet);
+		}
+
+		status = mci_readl(host, SR);
+		mask = mci_readl(host, IMR);
+		pending = status & mask;
+	} while (pending);
+
+	spin_unlock(&mmc->lock);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t atmci_detect_change(int irq, void *dev_id)
+{
+	struct mmc_host *mmc = dev_id;
+	struct atmel_mci *host = mmc_priv(mmc);
+
+	int present = !gpio_get_value(irq_to_gpio(irq));
+
+	if (present != host->present) {
+		pr_debug("%s: card %s\n", mmc_hostname(host->mmc),
+			 present ? "inserted" : "removed");
+		host->present = present;
+		mci_set_card_detect_pending(host);
+		tasklet_schedule(&host->tasklet);
+	}
+	return IRQ_HANDLED;
+}
+
+static int __devinit atmci_probe(struct platform_device *pdev)
+{
+	struct mci_platform_data *board;
+	struct atmel_mci *host;
+	struct mmc_host *mmc;
+	struct resource *regs;
+	int irq;
+	int ret;
+
+	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!regs)
+		return -ENXIO;
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	board = pdev->dev.platform_data;
+
+	mmc = mmc_alloc_host(sizeof(struct atmel_mci), &pdev->dev);
+	if (!mmc)
+		return -ENOMEM;
+
+	host = mmc_priv(mmc);
+	host->pdev = pdev;
+	host->mmc = mmc;
+	if (board) {
+		host->detect_pin = board->detect_pin;
+		host->wp_pin = board->wp_pin;
+	} else {
+		host->detect_pin = -1;
+		host->detect_pin = -1;
+	}
+
+	host->mck = clk_get(&pdev->dev, "mci_clk");
+	if (IS_ERR(host->mck)) {
+		ret = PTR_ERR(host->mck);
+		goto out_free_host;
+	}
+	clk_enable(host->mck);
+
+	ret = -ENOMEM;
+	host->regs = ioremap(regs->start, regs->end - regs->start + 1);
+	if (!host->regs)
+		goto out_disable_clk;
+
+	host->bus_hz = clk_get_rate(host->mck);
+	host->mapbase = regs->start;
+
+	mmc->ops = &atmci_ops;
+	mmc->f_min = (host->bus_hz + 511) / 512;
+	mmc->f_max = min((unsigned int)(host->bus_hz / 2), fmax);
+	mmc->ocr_avail	= 0x00100000;
+	mmc->caps |= MMC_CAP_4_BIT_DATA;
+
+	tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)mmc);
+
+	ret = request_irq(irq, atmci_interrupt, 0, "mmci", mmc);
+	if (ret)
+		goto out_unmap;
+
+	/* Assume card is present if we don't have a detect pin */
+	host->present = 1;
+	if (host->detect_pin >= 0) {
+		if (gpio_request(host->detect_pin, "mmc_detect")) {
+			printk(KERN_WARNING "%s: no detect pin available\n",
+			       mmc_hostname(host->mmc));
+			host->detect_pin = -1;
+		} else {
+			host->present = !gpio_get_value(host->detect_pin);
+		}
+	}
+	if (host->wp_pin >= 0) {
+		if (gpio_request(host->wp_pin, "mmc_wp")) {
+			printk(KERN_WARNING "%s: no WP pin available\n",
+			       mmc_hostname(host->mmc));
+			host->wp_pin = -1;
+		}
+	}
+
+	/* TODO: Get this information from platform data */
+	ret = -ENOMEM;
+	host->dma.req.req.dmac = find_dma_controller(0);
+	if (!host->dma.req.req.dmac) {
+		printk(KERN_ERR
+		       "mmci: No DMA controller available, aborting\n");
+		goto out_free_irq;
+	}
+	ret = dma_alloc_channel(host->dma.req.req.dmac);
+	if (ret < 0) {
+		printk(KERN_ERR
+		       "mmci: Unable to allocate DMA channel, aborting\n");
+		goto out_free_irq;
+	}
+	host->dma.req.req.channel = ret;
+	host->dma.req.width = DMA_WIDTH_32BIT;
+	host->dma.req.req.xfer_complete = atmci_xfer_complete;
+	host->dma.req.req.block_complete = NULL; // atmci_block_complete;
+	host->dma.req.req.error = atmci_dma_error;
+	host->dma.rx_periph_id = 0;
+	host->dma.tx_periph_id = 1;
+
+	mci_writel(host, CR, MCI_BIT(SWRST));
+	mci_writel(host, IDR, ~0UL);
+	mci_writel(host, CR, MCI_BIT(MCIEN));
+
+	platform_set_drvdata(pdev, host);
+
+	mmc_add_host(mmc);
+
+	if (host->detect_pin >= 0) {
+		ret = request_irq(gpio_to_irq(host->detect_pin),
+				  atmci_detect_change,
+				  IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+				  DRIVER_NAME, mmc);
+		if (ret) {
+			printk(KERN_ERR
+			       "%s: could not request IRQ %d for detect pin\n",
+			       mmc_hostname(mmc),
+			       gpio_to_irq(host->detect_pin));
+			gpio_free(host->detect_pin);
+			host->detect_pin = -1;
+		}
+	}
+
+	printk(KERN_INFO "%s: Atmel MCI controller at 0x%08lx irq %d\n",
+	       mmc_hostname(mmc), host->mapbase, irq);
+
+	atmci_init_debugfs(host);
+
+	return 0;
+
+out_free_irq:
+	if (host->detect_pin >= 0)
+		gpio_free(host->detect_pin);
+	if (host->wp_pin >= 0)
+		gpio_free(host->wp_pin);
+	free_irq(irq, mmc);
+out_unmap:
+	iounmap(host->regs);
+out_disable_clk:
+	clk_disable(host->mck);
+	clk_put(host->mck);
+out_free_host:
+	mmc_free_host(mmc);
+	return ret;
+}
+
+static int __devexit atmci_remove(struct platform_device *pdev)
+{
+	struct atmel_mci *host = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	if (host) {
+		atmci_cleanup_debugfs(host);
+
+		if (host->detect_pin >= 0) {
+			free_irq(gpio_to_irq(host->detect_pin), host->mmc);
+			cancel_delayed_work(&host->mmc->detect);
+			gpio_free(host->detect_pin);
+		}
+
+		mmc_remove_host(host->mmc);
+
+		mci_writel(host, IDR, ~0UL);
+		mci_writel(host, CR, MCI_BIT(MCIDIS));
+		mci_readl(host, SR);
+
+		dma_release_channel(host->dma.req.req.dmac,
+				    host->dma.req.req.channel);
+
+		if (host->wp_pin >= 0)
+			gpio_free(host->wp_pin);
+
+		free_irq(platform_get_irq(pdev, 0), host->mmc);
+		iounmap(host->regs);
+
+		clk_disable(host->mck);
+		clk_put(host->mck);
+
+		mmc_free_host(host->mmc);
+	}
+	return 0;
+}
+
+static struct platform_driver atmci_driver = {
+	.probe		= atmci_probe,
+	.remove		= __devexit_p(atmci_remove),
+	.driver		= {
+		.name		= DRIVER_NAME,
+	},
+};
+
+static int __init atmci_init(void)
+{
+	return platform_driver_register(&atmci_driver);
+}
+
+static void __exit atmci_exit(void)
+{
+	platform_driver_unregister(&atmci_driver);
+}
+
+module_init(atmci_init);
+module_exit(atmci_exit);
+
+MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/atmel-mci.h b/drivers/mmc/atmel-mci.h
new file mode 100644
index 0000000..60d15c4
--- /dev/null
+++ b/drivers/mmc/atmel-mci.h
@@ -0,0 +1,192 @@
+/*
+ * Atmel MultiMedia Card Interface driver
+ *
+ * Copyright (C) 2004-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 __DRIVERS_MMC_ATMEL_MCI_H__
+#define __DRIVERS_MMC_ATMEL_MCI_H__
+
+/* MCI register offsets */
+#define MCI_CR					0x0000
+#define MCI_MR					0x0004
+#define MCI_DTOR				0x0008
+#define MCI_SDCR				0x000c
+#define MCI_ARGR				0x0010
+#define MCI_CMDR				0x0014
+#define MCI_BLKR				0x0018
+#define MCI_RSPR				0x0020
+#define MCI_RSPR1				0x0024
+#define MCI_RSPR2				0x0028
+#define MCI_RSPR3				0x002c
+#define MCI_RDR					0x0030
+#define MCI_TDR					0x0034
+#define MCI_SR					0x0040
+#define MCI_IER					0x0044
+#define MCI_IDR					0x0048
+#define MCI_IMR					0x004c
+
+/* Bitfields in CR */
+#define MCI_MCIEN_OFFSET			0
+#define MCI_MCIEN_SIZE				1
+#define MCI_MCIDIS_OFFSET			1
+#define MCI_MCIDIS_SIZE				1
+#define MCI_PWSEN_OFFSET			2
+#define MCI_PWSEN_SIZE				1
+#define MCI_PWSDIS_OFFSET			3
+#define MCI_PWSDIS_SIZE				1
+#define MCI_SWRST_OFFSET			7
+#define MCI_SWRST_SIZE				1
+
+/* Bitfields in MR */
+#define MCI_CLKDIV_OFFSET			0
+#define MCI_CLKDIV_SIZE				8
+#define MCI_PWSDIV_OFFSET			8
+#define MCI_PWSDIV_SIZE				3
+#define MCI_RDPROOF_OFFSET			11
+#define MCI_RDPROOF_SIZE			1
+#define MCI_WRPROOF_OFFSET			12
+#define MCI_WRPROOF_SIZE			1
+#define MCI_DMAPADV_OFFSET			14
+#define MCI_DMAPADV_SIZE			1
+#define MCI_BLKLEN_OFFSET			16
+#define MCI_BLKLEN_SIZE				16
+
+/* Bitfields in DTOR */
+#define MCI_DTOCYC_OFFSET			0
+#define MCI_DTOCYC_SIZE				4
+#define MCI_DTOMUL_OFFSET			4
+#define MCI_DTOMUL_SIZE				3
+
+/* Bitfields in SDCR */
+#define MCI_SDCSEL_OFFSET			0
+#define MCI_SDCSEL_SIZE				4
+#define MCI_SDCBUS_OFFSET			7
+#define MCI_SDCBUS_SIZE				1
+
+/* Bitfields in ARGR */
+#define MCI_ARG_OFFSET				0
+#define MCI_ARG_SIZE				32
+
+/* Bitfields in CMDR */
+#define MCI_CMDNB_OFFSET			0
+#define MCI_CMDNB_SIZE				6
+#define MCI_RSPTYP_OFFSET			6
+#define MCI_RSPTYP_SIZE				2
+#define MCI_SPCMD_OFFSET			8
+#define MCI_SPCMD_SIZE				3
+#define MCI_OPDCMD_OFFSET			11
+#define MCI_OPDCMD_SIZE				1
+#define MCI_MAXLAT_OFFSET			12
+#define MCI_MAXLAT_SIZE				1
+#define MCI_TRCMD_OFFSET			16
+#define MCI_TRCMD_SIZE				2
+#define MCI_TRDIR_OFFSET			18
+#define MCI_TRDIR_SIZE				1
+#define MCI_TRTYP_OFFSET			19
+#define MCI_TRTYP_SIZE				2
+
+/* Bitfields in BLKR */
+#define MCI_BCNT_OFFSET				0
+#define MCI_BCNT_SIZE				16
+
+/* Bitfields in RSPRn */
+#define MCI_RSP_OFFSET				0
+#define MCI_RSP_SIZE				32
+
+/* Bitfields in SR/IER/IDR/IMR */
+#define MCI_CMDRDY_OFFSET			0
+#define MCI_CMDRDY_SIZE				1
+#define MCI_RXRDY_OFFSET			1
+#define MCI_RXRDY_SIZE				1
+#define MCI_TXRDY_OFFSET			2
+#define MCI_TXRDY_SIZE				1
+#define MCI_BLKE_OFFSET				3
+#define MCI_BLKE_SIZE				1
+#define MCI_DTIP_OFFSET				4
+#define MCI_DTIP_SIZE				1
+#define MCI_NOTBUSY_OFFSET			5
+#define MCI_NOTBUSY_SIZE			1
+#define MCI_ENDRX_OFFSET			6
+#define MCI_ENDRX_SIZE				1
+#define MCI_ENDTX_OFFSET			7
+#define MCI_ENDTX_SIZE				1
+#define MCI_RXBUFF_OFFSET			14
+#define MCI_RXBUFF_SIZE				1
+#define MCI_TXBUFE_OFFSET			15
+#define MCI_TXBUFE_SIZE				1
+#define MCI_RINDE_OFFSET			16
+#define MCI_RINDE_SIZE				1
+#define MCI_RDIRE_OFFSET			17
+#define MCI_RDIRE_SIZE				1
+#define MCI_RCRCE_OFFSET			18
+#define MCI_RCRCE_SIZE				1
+#define MCI_RENDE_OFFSET			19
+#define MCI_RENDE_SIZE				1
+#define MCI_RTOE_OFFSET				20
+#define MCI_RTOE_SIZE				1
+#define MCI_DCRCE_OFFSET			21
+#define MCI_DCRCE_SIZE				1
+#define MCI_DTOE_OFFSET				22
+#define MCI_DTOE_SIZE				1
+#define MCI_OVRE_OFFSET				30
+#define MCI_OVRE_SIZE				1
+#define MCI_UNRE_OFFSET				31
+#define MCI_UNRE_SIZE				1
+
+/* Constants for DTOMUL */
+#define MCI_DTOMUL_1_CYCLE			0
+#define MCI_DTOMUL_16_CYCLES			1
+#define MCI_DTOMUL_128_CYCLES			2
+#define MCI_DTOMUL_256_CYCLES			3
+#define MCI_DTOMUL_1024_CYCLES			4
+#define MCI_DTOMUL_4096_CYCLES			5
+#define MCI_DTOMUL_65536_CYCLES			6
+#define MCI_DTOMUL_1048576_CYCLES		7
+
+/* Constants for RSPTYP */
+#define MCI_RSPTYP_NO_RESP			0
+#define MCI_RSPTYP_48_BIT			1
+#define MCI_RSPTYP_136_BIT			2
+
+/* Constants for SPCMD */
+#define MCI_SPCMD_NO_SPEC_CMD			0
+#define MCI_SPCMD_INIT_CMD			1
+#define MCI_SPCMD_SYNC_CMD			2
+#define MCI_SPCMD_INT_CMD			4
+#define MCI_SPCMD_INT_RESP			5
+
+/* Constants for TRCMD */
+#define MCI_TRCMD_NO_TRANS			0
+#define MCI_TRCMD_START_TRANS			1
+#define MCI_TRCMD_STOP_TRANS			2
+
+/* Constants for TRTYP */
+#define MCI_TRTYP_BLOCK				0
+#define MCI_TRTYP_MULTI_BLOCK			1
+#define MCI_TRTYP_STREAM			2
+
+/* Bit manipulation macros */
+#define MCI_BIT(name)					\
+	(1 << MCI_##name##_OFFSET)
+#define MCI_BF(name,value)				\
+	(((value) & ((1 << MCI_##name##_SIZE) - 1))	\
+	 << MCI_##name##_OFFSET)
+#define MCI_BFEXT(name,value)				\
+	(((value) >> MCI_##name##_OFFSET)		\
+	 & ((1 << MCI_##name##_SIZE) - 1))
+#define MCI_BFINS(name,value,old)			\
+	(((old) & ~(((1 << MCI_##name##_SIZE) - 1)	\
+		    << MCI_##name##_OFFSET))		\
+	 | MCI_BF(name,value))
+
+/* Register access macros */
+#define mci_readl(port,reg)				\
+	__raw_readl((port)->regs + MCI_##reg)
+#define mci_writel(port,reg,value)			\
+	__raw_writel((value), (port)->regs + MCI_##reg)
+
+#endif /* __DRIVERS_MMC_ATMEL_MCI_H__ */
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index f334959..e2ef662 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -47,6 +47,7 @@
 #define I82802AC	0x00ac
 #define MANUFACTURER_ST         0x0020
 #define M50LPW080       0x002F
+#define AT49BV640D	0x02de
 
 static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
@@ -153,6 +154,47 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp)
 }
 #endif
 
+/* Atmel chips don't use the same PRI format as Intel chips */
+static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	struct cfi_pri_intelext *extp = cfi->cmdset_priv;
+	struct cfi_pri_atmel atmel_pri;
+	uint32_t features = 0;
+
+	/* Reverse byteswapping */
+	extp->FeatureSupport = cpu_to_le32(extp->FeatureSupport);
+	extp->BlkStatusRegMask = cpu_to_le16(extp->BlkStatusRegMask);
+	extp->ProtRegAddr = cpu_to_le16(extp->ProtRegAddr);
+
+	memcpy(&atmel_pri, extp, sizeof(atmel_pri));
+	memset((char *)extp + 5, 0, sizeof(*extp) - 5);
+
+	printk(KERN_ERR "atmel Features: %02x\n", atmel_pri.Features);
+
+	if (atmel_pri.Features & 0x01) /* chip erase supported */
+		features |= (1<<0);
+	if (atmel_pri.Features & 0x02) /* erase suspend supported */
+		features |= (1<<1);
+	if (atmel_pri.Features & 0x04) /* program suspend supported */
+		features |= (1<<2);
+	if (atmel_pri.Features & 0x08) /* simultaneous operations supported */
+		features |= (1<<9);
+	if (atmel_pri.Features & 0x20) /* page mode read supported */
+		features |= (1<<7);
+	if (atmel_pri.Features & 0x40) /* queued erase supported */
+		features |= (1<<4);
+	if (atmel_pri.Features & 0x80) /* Protection bits supported */
+		features |= (1<<6);
+
+	extp->FeatureSupport = features;
+
+	/* burst write mode not supported */
+	cfi->cfiq->BufWriteTimeoutTyp = 0;
+	cfi->cfiq->BufWriteTimeoutMax = 0;
+}
+
 #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
 /* Some Intel Strata Flash prior to FPO revision C has bugs in this area */
 static void fixup_intel_strataflash(struct mtd_info *mtd, void* param)
@@ -221,6 +263,7 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param)
 }
 
 static struct cfi_fixup cfi_fixup_table[] = {
+	{ CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL },
 #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
 	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL },
 #endif
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index 1f64458..205977b 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -185,6 +185,10 @@ static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param)
 		extp->TopBottom = 2;
 	else
 		extp->TopBottom = 3;
+
+	/* burst write mode not supported */
+	cfi->cfiq->BufWriteTimeoutTyp = 0;
+	cfi->cfiq->BufWriteTimeoutMax = 0;
 }
 
 static void fixup_use_secsi(struct mtd_info *mtd, void *param)
@@ -217,6 +221,7 @@ static void fixup_use_atmel_lock(struct mtd_info *mtd, void *param)
 }
 
 static struct cfi_fixup cfi_fixup_table[] = {
+	{ CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL },
 #ifdef AMD_BOOTLOC_BUG
 	{ CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock, NULL },
 #endif
@@ -229,7 +234,6 @@ static struct cfi_fixup cfi_fixup_table[] = {
 #if !FORCE_WORD_WRITE
 	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, },
 #endif
-	{ CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL },
 	{ 0, 0, NULL, NULL }
 };
 static struct cfi_fixup jedec_fixup_table[] = {
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index 35f8864..29388e1 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -270,6 +270,13 @@ config AT91_CF
 	  Say Y here to support the CompactFlash controller on AT91 chips.
 	  Or choose M to compile the driver as a module named "at91_cf".
 
+config AT32_CF
+	tristate "AT32AP CompactFlash Controller"
+	depends on PCMCIA && AVR32 && PLATFORM_AT32AP
+	help
+	  Say Y here to support the CompactFlash controller on AT32 chips.
+	  Or choose M to compile the driver as a module named "at32_cf".
+
 config PCCARD_NONSTATIC
 	tristate
 
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index 4276965..08d7ffa 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_PCMCIA_VRC4171)			+= vrc4171_card.o
 obj-$(CONFIG_PCMCIA_VRC4173)			+= vrc4173_cardu.o
 obj-$(CONFIG_OMAP_CF)				+= omap_cf.o
 obj-$(CONFIG_AT91_CF)				+= at91_cf.o
+obj-$(CONFIG_AT32_CF)				+= at32_cf.o
 
 sa11xx_core-y					+= soc_common.o sa11xx_base.o
 pxa2xx_core-y					+= soc_common.o pxa2xx_base.o
diff --git a/drivers/pcmcia/at32_cf.c b/drivers/pcmcia/at32_cf.c
new file mode 100644
index 0000000..7165c39
--- /dev/null
+++ b/drivers/pcmcia/at32_cf.c
@@ -0,0 +1,506 @@
+/*
+ * Driver for AVR32 Static Memory Controller: CompactFlash support
+ *
+ * Copyright (C) 2006 Atmel Norway
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this
+ * distribution in the file called COPYING.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+
+#include <pcmcia/ss.h>
+
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/arch/board.h>
+
+#include <asm/arch/smc.h>
+
+struct at32_cf_socket {
+	struct pcmcia_socket	socket;
+	int			detect_pin;
+	int			reset_pin;
+	int			vcc_pin;
+	struct resource		res_attr;
+	struct resource		res_mem;
+	struct resource		res_io;
+	struct smc_config	smc;
+	unsigned int		irq;
+	unsigned int		cf_cs;
+	socket_state_t		state;
+	unsigned		present:1;
+};
+#define to_at32_cf(sock) container_of(sock, struct at32_cf_socket, socket)
+
+/*
+ * We have the following memory layout relative to the base address:
+ *
+ *   Alt IDE Mode:      00e0 0000 -> 00ff ffff
+ *   True IDE Mode:     00c0 0000 -> 00df ffff
+ *   I/O memory:        0080 0000 -> 00bf ffff
+ *   Common memory:     0040 0000 -> 007f ffff
+ *   Attribute memory:  0000 0000 -> 003f ffff
+ */
+#define CF_ATTR_OFFSET	0x00000000
+#define CF_MEM_OFFSET	0x00400000
+#define CF_IO_OFFSET	0x00800000
+#define CF_RES_SIZE	2048
+
+#ifdef DEBUG
+
+static int pc_debug;
+module_param(pc_debug, int, 0644);
+
+static void at32_cf_debug(struct at32_cf_socket *cf, const char *func,
+			  int level, const char *fmt, ...)
+{
+	va_list args;
+
+	if (pc_debug > level) {
+		printk(KERN_DEBUG "at32_cf/%u: %s: ", cf->cf_cs, func);
+		va_start(args, fmt);
+		vprintk(fmt, args);
+		va_end(args);
+	}
+}
+
+#define debug(cf, lvl, fmt, arg...)			\
+	at32_cf_debug(cf, __func__, lvl, fmt, ##arg)
+
+#else
+#define debug(cf, lvl, fmt, arg...) do { } while (0)
+#endif
+
+static inline int at32_cf_present(struct at32_cf_socket *cf)
+{
+	int present = 1;
+
+	/* If we don't have a detect pin, assume the card is present */
+	if (cf->detect_pin >= 0)
+		present = !gpio_get_value(cf->detect_pin);
+
+	return present;
+}
+
+static irqreturn_t at32_cf_irq(int irq, void *dev_id)
+{
+	struct at32_cf_socket *cf = dev_id;
+	unsigned int present;
+
+	present = at32_cf_present(cf);
+	if (present != cf->present) {
+		cf->present = present;
+		debug(cf, 3, "card %s\n", present ? "present" : "gone");
+		pcmcia_parse_events(&cf->socket, SS_DETECT);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int at32_cf_get_status(struct pcmcia_socket *sock, u_int *value)
+{
+	struct at32_cf_socket *cf;
+	u_int status = 0;
+
+	cf = container_of(sock, struct at32_cf_socket, socket);
+
+	if (at32_cf_present(cf)) {
+		/* NOTE: gpio on AP7xxx is 3.3V */
+		status = SS_DETECT | SS_3VCARD | SS_READY;
+		if (cf->vcc_pin < 0 || gpio_get_value(cf->vcc_pin))
+			status |= SS_POWERON;
+	}
+
+	*value = status;
+	return 0;
+}
+
+static int at32_cf_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
+{
+	struct at32_cf_socket *cf = container_of(sock, struct at32_cf_socket, socket);
+
+	debug(cf, 2, "mask: %s%s%s%s%s%sflags: %s%s%s%s%s%sVcc %d Vpp %d irq %d\n",
+			(state->csc_mask==0)?"<NONE> ":"",
+			(state->csc_mask&SS_DETECT)?"DETECT ":"",
+			(state->csc_mask&SS_READY)?"READY ":"",
+			(state->csc_mask&SS_BATDEAD)?"BATDEAD ":"",
+			(state->csc_mask&SS_BATWARN)?"BATWARN ":"",
+			(state->csc_mask&SS_STSCHG)?"STSCHG ":"",
+			(state->flags==0)?"<NONE> ":"",
+			(state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"",
+			(state->flags&SS_IOCARD)?"IOCARD ":"",
+			(state->flags&SS_RESET)?"RESET ":"",
+			(state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"",
+			(state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"",
+			state->Vcc, state->Vpp, state->io_irq);
+
+	/*
+	 * TODO: Allow boards to override this in case they have level
+	 * converters.
+	 */
+	switch (state->Vcc) {
+	case 0:
+		if (cf->vcc_pin >= 0)
+			gpio_set_value(cf->vcc_pin, 0);
+		break;
+	case 33:
+		if (cf->vcc_pin >= 0)
+			gpio_set_value(cf->vcc_pin, 1);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (cf->reset_pin >= 0)
+		gpio_set_value(cf->reset_pin, state->flags & SS_RESET);
+
+	cf->state = *state;
+
+	return 0;
+}
+
+static int at32_cf_socket_init(struct pcmcia_socket *sock)
+{
+#ifdef DEBUG
+	struct at32_cf_socket *cf = to_at32_cf(sock);
+	debug(cf, 2, "called\n");
+#endif
+	return 0;
+}
+
+static int at32_cf_suspend(struct pcmcia_socket *sock)
+{
+#ifdef DEBUG
+	struct at32_cf_socket *cf = to_at32_cf(sock);
+	debug(cf, 2, "called\n");
+#endif
+	at32_cf_set_socket(sock, &dead_socket);
+
+	return 0;
+}
+
+static int at32_cf_set_io_map(struct pcmcia_socket *sock,
+			      struct pccard_io_map *map)
+{
+	struct at32_cf_socket *cf = container_of(sock, struct at32_cf_socket, socket);
+	int retval;
+
+	debug(cf, 2, "map %u  speed %u start 0x%08x stop 0x%08x\n",
+		map->map, map->speed, map->start, map->stop);
+	debug(cf, 2, "flags: %s%s%s%s%s%s%s%s\n",
+		(map->flags == 0) ? "<NONE>":"",
+		(map->flags & MAP_ACTIVE) ? "ACTIVE " : "",
+		(map->flags & MAP_16BIT) ? "16BIT " : "",
+		(map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "",
+		(map->flags & MAP_0WS) ? "0WS " : "",
+		(map->flags & MAP_WRPROT) ? "WRPROT " : "",
+		(map->flags & MAP_USE_WAIT) ? "USE_WAIT " : "",
+		(map->flags & MAP_PREFETCH) ? "PREFETCH " : "");
+
+	map->flags &= MAP_ACTIVE | MAP_16BIT | MAP_USE_WAIT;
+
+	if (map->flags & MAP_16BIT)
+		cf->smc.bus_width = 2;
+	else
+		cf->smc.bus_width = 1;
+
+	if (map->flags & MAP_USE_WAIT)
+		cf->smc.nwait_mode = 3;
+	else
+		cf->smc.nwait_mode = 0;
+
+	retval = smc_set_configuration(cf->cf_cs, &cf->smc);
+	if (retval) {
+		printk(KERN_ERR "at32_cf: could not set up SMC for I/O\n");
+		return retval;
+	}
+
+	map->start = cf->socket.io_offset;
+	map->stop = map->start + CF_RES_SIZE - 1;
+
+	return 0;
+}
+
+static int
+at32_cf_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *map)
+{
+	struct at32_cf_socket *cf;
+
+	cf = container_of(sock, struct at32_cf_socket, socket);
+
+	debug(cf, 2, "map %u speed %u card_start %08x\n",
+		map->map, map->speed, map->card_start);
+	debug(cf, 2, "flags: %s%s%s%s%s%s%s%s\n",
+		(map->flags==0)?"<NONE>":"",
+		(map->flags&MAP_ACTIVE)?"ACTIVE ":"",
+		(map->flags&MAP_16BIT)?"16BIT ":"",
+		(map->flags&MAP_AUTOSZ)?"AUTOSZ ":"",
+		(map->flags&MAP_0WS)?"0WS ":"",
+		(map->flags&MAP_WRPROT)?"WRPROT ":"",
+		(map->flags&MAP_ATTRIB)?"ATTRIB ":"",
+		(map->flags&MAP_USE_WAIT)?"USE_WAIT ":"");
+
+	if (map->card_start)
+		return -EINVAL;
+
+	map->flags &= MAP_ACTIVE | MAP_ATTRIB | MAP_16BIT;
+
+	if (map->flags & MAP_ATTRIB)
+		map->static_start = cf->res_attr.start;
+	else
+		map->static_start = cf->res_mem.start;
+
+	return 0;
+}
+
+static struct pccard_operations at32_cf_ops = {
+	.init			= at32_cf_socket_init,
+	.suspend		= at32_cf_suspend,
+	.get_status		= at32_cf_get_status,
+	.set_socket		= at32_cf_set_socket,
+	.set_io_map		= at32_cf_set_io_map,
+	.set_mem_map		= at32_cf_set_mem_map,
+};
+
+static int __init request_pin(struct platform_device *pdev,
+			      unsigned int pin, const char *name)
+{
+	if (gpio_request(pin, name)) {
+		dev_warn(&pdev->dev, "failed to request %s pin\n", name);
+		return -1;
+	}
+
+	return pin;
+}
+
+static int __init at32_cf_probe(struct platform_device *pdev)
+{
+	struct at32_cf_socket	*cf;
+	struct cf_platform_data	*board = pdev->dev.platform_data;
+	struct resource		*res_skt;
+	int			irq;
+	int			ret;
+
+	dev_dbg(&pdev->dev, "probe");
+
+	if (!board)
+		return -ENXIO;
+
+	res_skt = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res_skt)
+		return -ENXIO;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	cf = kzalloc(sizeof(struct at32_cf_socket), GFP_KERNEL);
+	if (!cf)
+		return -ENOMEM;
+
+	cf->detect_pin = -1;
+	cf->reset_pin = -1;
+	cf->vcc_pin = -1;
+	cf->cf_cs = board->cs;
+
+	if (board->detect_pin)
+		cf->detect_pin = request_pin(pdev, board->detect_pin,
+					     "cf_detect");
+	if (board->reset_pin)
+		cf->reset_pin = request_pin(pdev, board->reset_pin,
+					    "cf_reset");
+	if (board->vcc_pin)
+		cf->vcc_pin = request_pin(pdev, board->reset_pin,
+					  "cf_vcc");
+
+	debug(cf, 2, "pins: detect=%d reset=%d vcc=%d\n",
+	      cf->detect_pin, cf->reset_pin, cf->vcc_pin);
+
+	cf->socket.pci_irq = irq;
+	cf->socket.ops = &at32_cf_ops;
+	cf->socket.resource_ops = &pccard_static_ops;
+	cf->socket.dev.parent = &pdev->dev;
+	cf->socket.owner = THIS_MODULE;
+	cf->socket.features =
+		SS_CAP_MEM_ALIGN | SS_CAP_STATIC_MAP | SS_CAP_PCCARD;
+	cf->socket.map_size = CF_RES_SIZE;
+
+	cf->res_attr.start = res_skt->start + CF_ATTR_OFFSET;
+	cf->res_attr.end = cf->res_attr.start + CF_RES_SIZE - 1;
+	cf->res_attr.name = "attribute";
+	cf->res_attr.flags = IORESOURCE_MEM;
+	ret = request_resource(res_skt, &cf->res_attr);
+	if (ret)
+		goto err_request_res_attr;
+
+	cf->res_mem.start = res_skt->start + CF_MEM_OFFSET;
+	cf->res_mem.end = cf->res_mem.start + CF_RES_SIZE - 1;
+	cf->res_mem.name = "memory";
+	cf->res_mem.flags = IORESOURCE_MEM;
+	ret = request_resource(res_skt, &cf->res_mem);
+	if (ret)
+		goto err_request_res_mem;
+
+	cf->res_io.start = res_skt->start + CF_IO_OFFSET;
+	cf->res_io.end = cf->res_io.start + CF_RES_SIZE - 1;
+	cf->res_io.name = "io";
+	cf->res_io.flags = IORESOURCE_MEM;
+	ret = request_resource(res_skt, &cf->res_io);
+	if (ret)
+		goto err_request_res_io;
+
+	cf->socket.io_offset = cf->res_io.start;
+
+	if (cf->detect_pin >= 0) {
+		ret = request_irq(gpio_to_irq(cf->detect_pin), at32_cf_irq,
+				  IRQF_SHARED, "cf_detect", cf);
+		if (ret) {
+			debug(cf, 1,
+			      "failed to request cf_detect interrupt\n");
+			goto err_detect_irq;
+		}
+	}
+
+	/* Setup SMC timings */
+	cf->smc.ncs_read_setup = 30;
+	cf->smc.nrd_setup = 75;
+	cf->smc.ncs_write_setup = 30;
+	cf->smc.nwe_setup = 75;
+
+	cf->smc.ncs_read_pulse = 240;
+	cf->smc.nrd_pulse = 165;
+	cf->smc.ncs_write_pulse = 240;
+	cf->smc.nwe_pulse = 165;
+
+	cf->smc.read_cycle = 300;
+	cf->smc.write_cycle = 300;
+
+	cf->smc.bus_width = 2;
+	cf->smc.nrd_controlled = 1;
+	cf->smc.nwe_controlled = 1;
+	cf->smc.nwait_mode = 0;
+	cf->smc.byte_write = 0;
+	cf->smc.tdf_cycles = 1;
+	cf->smc.tdf_mode = 0;
+
+	ret = smc_set_configuration(cf->cf_cs, &cf->smc);
+	if (ret) {
+		debug(cf, 1, "failed to configure SMC\n", ret);
+		goto err_smc;
+	}
+
+	ret = pcmcia_register_socket(&cf->socket);
+	if (ret) {
+		debug(cf, 1, "failed to register socket: %d\n", ret);
+		goto err_register_socket;
+	}
+
+	if (cf->reset_pin >= 0) {
+		gpio_direction_output(cf->reset_pin, 0);
+	}
+
+	platform_set_drvdata(pdev, cf);
+
+	dev_info(&pdev->dev, "Atmel SMC CF interface at 0x%08lx\n",
+		 (unsigned long)res_skt->start);
+
+	return 0;
+
+err_register_socket:
+err_smc:
+	if (cf->detect_pin >= 0)
+		free_irq(gpio_to_irq(cf->detect_pin), cf);
+err_detect_irq:
+	release_resource(&cf->res_io);
+err_request_res_io:
+	release_resource(&cf->res_mem);
+err_request_res_mem:
+	release_resource(&cf->res_attr);
+err_request_res_attr:
+	if (cf->vcc_pin >= 0)
+		gpio_free(cf->vcc_pin);
+	if (cf->reset_pin >= 0)
+		gpio_free(cf->reset_pin);
+	if (cf->detect_pin >= 0)
+		gpio_free(cf->detect_pin);
+	kfree(cf);
+
+	return ret;
+}
+
+static int __exit at32_cf_remove(struct platform_device *pdev)
+{
+	struct at32_cf_socket *cf = platform_get_drvdata(pdev);
+
+	pcmcia_unregister_socket(&cf->socket);
+	if (cf->detect_pin >= 0) {
+		free_irq(gpio_to_irq(cf->detect_pin), cf);
+		gpio_free(cf->detect_pin);
+	}
+	if (cf->vcc_pin >= 0)
+		gpio_free(cf->vcc_pin);
+	if (cf->reset_pin >= 0)
+		gpio_free(cf->reset_pin);
+
+	release_resource(&cf->res_io);
+	release_resource(&cf->res_mem);
+	release_resource(&cf->res_attr);
+	kfree(cf);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver at32_cf_driver = {
+	.remove		= __exit_p(at32_cf_remove),
+	.driver		= {
+		.name	= "at32_cf",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init at32_cf_init(void)
+{
+	int ret;
+
+	ret = platform_driver_probe(&at32_cf_driver, at32_cf_probe);
+	if (ret)
+		printk(KERN_ERR "at32_cf: probe failed: %d\n", ret);
+	return ret;
+}
+
+static void __exit at32_cf_exit(void)
+{
+	platform_driver_unregister(&at32_cf_driver);
+}
+
+module_init(at32_cf_init);
+module_exit(at32_cf_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Driver for SMC PCMCIA interface");
+MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c
index d154dee..5a464ec 100644
--- a/drivers/pcmcia/cistpl.c
+++ b/drivers/pcmcia/cistpl.c
@@ -1091,7 +1091,7 @@ static int parse_cftable_entry(tuple_t *tuple,
 	break;
     case 0x20:
 	entry->mem.nwin = 1;
-	entry->mem.win[0].len = le16_to_cpu(*(__le16 *)p) << 8;
+	entry->mem.win[0].len = (p[0] << 8) | (p[1] << 16);
 	entry->mem.win[0].card_addr = 0;
 	entry->mem.win[0].host_addr = 0;
 	p += 2;
@@ -1099,9 +1099,8 @@ static int parse_cftable_entry(tuple_t *tuple,
 	break;
     case 0x40:
 	entry->mem.nwin = 1;
-	entry->mem.win[0].len = le16_to_cpu(*(__le16 *)p) << 8;
-	entry->mem.win[0].card_addr =
-	    le16_to_cpu(*(__le16 *)(p+2)) << 8;
+	entry->mem.win[0].len = (p[0] << 8) | (p[1] << 16);
+	entry->mem.win[0].card_addr = (p[2] << 8) | (p[3] << 16);
 	entry->mem.win[0].host_addr = 0;
 	p += 4;
 	if (p > q) return CS_BAD_TUPLE;
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 95826b9..ee96d77 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -313,6 +313,13 @@ config RTC_DRV_PL031
 	  To compile this driver as a module, choose M here: the
 	  module will be called rtc-pl031.
 
+config RTC_DRV_AT32AP700X
+	tristate "AT32AP700X series RTC"
+	depends on RTC_CLASS && PLATFORM_AT32AP
+	help
+	  Driver for the internal RTC (Realtime Clock) on Atmel AVR32
+	  AT32AP700x family processors.
+
 config RTC_DRV_AT91RM9200
 	tristate "AT91RM9200"
 	depends on RTC_CLASS && ARCH_AT91RM9200
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 92bfe1b..d36d987 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_RTC_DRV_CMOS)	+= rtc-cmos.o
 obj-$(CONFIG_RTC_DRV_X1205)	+= rtc-x1205.o
 obj-$(CONFIG_RTC_DRV_ISL1208)	+= rtc-isl1208.o
 obj-$(CONFIG_RTC_DRV_TEST)	+= rtc-test.o
+obj-$(CONFIG_RTC_DRV_AT32AP700X)	+= rtc-at32ap700x.o
 obj-$(CONFIG_RTC_DRV_DS1307)	+= rtc-ds1307.o
 obj-$(CONFIG_RTC_DRV_DS1672)	+= rtc-ds1672.o
 obj-$(CONFIG_RTC_DRV_DS1742)	+= rtc-ds1742.o
diff --git a/drivers/rtc/rtc-at32ap700x.c b/drivers/rtc/rtc-at32ap700x.c
new file mode 100644
index 0000000..a59b7c1
--- /dev/null
+++ b/drivers/rtc/rtc-at32ap700x.c
@@ -0,0 +1,319 @@
+/*
+ * An RTC driver for the AVR32 AT32AP700x processor series
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+
+#include <asm/io.h>
+
+/* This is a bare-bones RTC. It runs during most system sleep states, but has
+ * no battery backup and gets reset during system restart.  It must be
+ * initialized from an external clock (network, I2C, etc) before it can be of
+ * much use.
+ *
+ * The alarm functionality is limited by the hardware, not supporting periodic
+ * interrupts.
+ */
+
+#define RTC_CTRL		0x00
+#define RTC_CTRL_EN		   0
+#define RTC_CTRL_PCLR		   1
+#define RTC_CTRL_TOPEN		   2
+#define RTC_CTRL_PSEL		   8
+
+#define RTC_VAL			0x04
+
+#define RTC_TOP			0x08
+
+#define RTC_IER			0x10
+#define RTC_IER_TOPI		   0
+
+#define RTC_IDR			0x14
+#define RTC_IDR_TOPI		   0
+
+#define RTC_IMR			0x18
+#define RTC_IMR_TOPI		   0
+
+#define RTC_ISR			0x1c
+#define RTC_ISR_TOPI		   0
+
+#define RTC_ICR			0x20
+#define RTC_ICR_TOPI		   0
+
+#define RTC_BIT(name)		(1 << RTC_##name)
+#define RTC_BF(name,value)	((value) << RTC_##name)
+
+#define rtc_readl(dev,reg)				\
+	__raw_readl((dev)->regs + RTC_##reg)
+#define rtc_writel(dev,reg,value)			\
+	__raw_writel((value), (dev)->regs + RTC_##reg)
+
+struct rtc_at32ap700x {
+	struct rtc_device	*rtc;
+	void __iomem		*regs;
+	unsigned long		alarm_time;
+	unsigned long		irq;
+	spinlock_t		lock;
+};
+
+static int at32_rtc_readtime(struct device *dev, struct rtc_time *tm)
+{
+	struct rtc_at32ap700x *rtc = dev_get_drvdata(dev);
+	unsigned long now;
+
+	now = rtc_readl(rtc, VAL);
+	rtc_time_to_tm(now, tm);
+
+	return 0;
+}
+
+static int at32_rtc_settime(struct device *dev, struct rtc_time *tm)
+{
+	struct rtc_at32ap700x *rtc = dev_get_drvdata(dev);
+	unsigned long now;
+	int ret;
+
+	ret = rtc_tm_to_time(tm, &now);
+	if (ret == 0)
+		rtc_writel(rtc, VAL, now);
+
+	return ret;
+}
+
+static int at32_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct rtc_at32ap700x *rtc = dev_get_drvdata(dev);
+	struct rtc_time tm;
+
+	rtc_time_to_tm(rtc->alarm_time, &tm);
+	alrm->time = tm;
+	alrm->pending = rtc_readl(rtc, IMR) & RTC_BIT(IMR_TOPI) ? 1 : 0;
+
+	return 0;
+}
+
+static int at32_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct rtc_at32ap700x *rtc = dev_get_drvdata(dev);
+	struct rtc_time	tm;
+	unsigned long rtc_unix_time;
+	unsigned long alarm_unix_time;
+	int ret;
+
+	rtc_unix_time = rtc_readl(rtc, VAL);
+	rtc_time_to_tm(rtc_unix_time, &tm);
+
+	/* RTC does only support one alarm time, not periodic */
+	if (alrm->time.tm_mday < 1) {
+		alrm->time.tm_mday  = tm.tm_mday;
+		alrm->time.tm_mon   = tm.tm_mon;
+		alrm->time.tm_year  = tm.tm_year;
+		alrm->time.tm_wday  = tm.tm_wday;
+		alrm->time.tm_yday  = tm.tm_yday;
+	}
+
+	ret = rtc_tm_to_time(&alrm->time, &alarm_unix_time);
+	if (ret)
+		return ret;
+
+	if (alarm_unix_time < rtc_unix_time)
+		return -EINVAL;
+
+	spin_lock_irq(&rtc->lock);
+	rtc->alarm_time = alarm_unix_time;
+	rtc_writel(rtc, TOP, rtc->alarm_time);
+	if (alrm->pending)
+		rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL)
+				| RTC_BIT(CTRL_TOPEN));
+	else
+		rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL)
+				& ~RTC_BIT(CTRL_TOPEN));
+	spin_unlock_irq(&rtc->lock);
+
+	return ret;
+}
+
+static int at32_rtc_ioctl(struct device *dev, unsigned int cmd,
+			unsigned long arg)
+{
+	struct rtc_at32ap700x *rtc = dev_get_drvdata(dev);
+	int ret = 0;
+
+	switch (cmd) {
+	case RTC_AIE_ON:
+		spin_lock_irq(&rtc->lock);
+		if (rtc_readl(rtc, VAL) > rtc->alarm_time)
+			return -EINVAL;
+		rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL)
+				| RTC_BIT(CTRL_TOPEN));
+		rtc_writel(rtc, ICR, RTC_BIT(ICR_TOPI));
+		rtc_writel(rtc, IER, RTC_BIT(IER_TOPI));
+		spin_unlock_irq(&rtc->lock);
+		break;
+	case RTC_AIE_OFF:
+		spin_lock_irq(&rtc->lock);
+		rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL)
+				& ~RTC_BIT(CTRL_TOPEN));
+		rtc_writel(rtc, IDR, RTC_BIT(IDR_TOPI));
+		rtc_writel(rtc, ICR, RTC_BIT(ICR_TOPI));
+		spin_unlock_irq(&rtc->lock);
+		break;
+	default:
+		ret = -ENOIOCTLCMD;
+		break;
+	}
+
+	return ret;
+}
+
+static irqreturn_t at32_rtc_interrupt(int irq, void *dev_id)
+{
+	struct rtc_at32ap700x *rtc = (struct rtc_at32ap700x *)dev_id;
+	unsigned long isr = rtc_readl(rtc, ISR);
+	unsigned long events = 0;
+
+	spin_lock(&rtc->lock);
+
+	if (isr & RTC_BIT(ISR_TOPI)) {
+		rtc_writel(rtc, ICR, RTC_BIT(ICR_TOPI));
+		rtc_writel(rtc, IDR, RTC_BIT(IDR_TOPI));
+		rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL)
+				& ~RTC_BIT(CTRL_TOPEN));
+		rtc_writel(rtc, VAL, rtc->alarm_time);
+		events = RTC_AF | RTC_IRQF;
+		rtc_update_irq(&rtc->rtc->class_dev, 1, events);
+	}
+
+	spin_unlock(&rtc->lock);
+
+	return IRQ_HANDLED;
+}
+
+static struct rtc_class_ops at32_rtc_ops = {
+	.ioctl		= at32_rtc_ioctl,
+	.read_time	= at32_rtc_readtime,
+	.set_time	= at32_rtc_settime,
+	.read_alarm	= at32_rtc_readalarm,
+	.set_alarm	= at32_rtc_setalarm,
+};
+
+static int __devinit at32_rtc_probe(struct platform_device *pdev)
+{
+	struct resource	*regs;
+	struct rtc_at32ap700x *rtc;
+	int irq = -1;
+	int ret;
+
+	rtc = kmalloc(sizeof(struct rtc_at32ap700x), GFP_KERNEL);
+	if (!rtc) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!regs) {
+		printk(KERN_ERR "rtc: no mmio resource defined for RTC\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		printk(KERN_ERR "rtc: could not get irq\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	ret = request_irq(irq, at32_rtc_interrupt, IRQF_SHARED, "rtc", rtc);
+	if (ret) {
+		printk(KERN_ERR "rtc: could not request irq%d\n", irq);
+		goto out;
+	}
+
+	rtc->irq = irq;
+	rtc->alarm_time = 0;
+	rtc->regs = ioremap(regs->start, regs->end - regs->start + 1);
+	spin_lock_init(&rtc->lock);
+
+	/* Maybe init RTC: count from zero at 1 Hz, disable wrap irq */
+	/* Do not reset VAL register, as it can hold an old time
+	 * from last JTAG reset. */
+	if (!(rtc_readl(rtc, CTRL) & RTC_BIT(CTRL_EN))) {
+		rtc_writel(rtc, CTRL, RTC_BIT(CTRL_PCLR));
+		rtc_writel(rtc, IDR, RTC_BIT(IDR_TOPI));
+		rtc_writel(rtc, CTRL, RTC_BF(CTRL_PSEL, 0xe)
+				| RTC_BIT(CTRL_EN));
+	}
+
+	/* REVISIT init in arch code if wdt or rtc is enabled; this
+	 * affects both...
+	 */
+
+	rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
+				&at32_rtc_ops, THIS_MODULE);
+	if (IS_ERR(rtc->rtc)) {
+		ret = PTR_ERR(rtc->rtc);
+		goto out_free_irq;
+	}
+
+	platform_set_drvdata(pdev, rtc);
+
+	printk(KERN_INFO "Atmel RTC for AT32AP700x at %08lx irq %ld\n",
+			(unsigned long)rtc->regs, rtc->irq);
+
+	return 0;
+
+out_free_irq:
+	free_irq(irq, rtc);
+	iounmap(rtc->regs);
+out:
+	kfree(rtc);
+	return ret;
+}
+
+static int __devexit at32_rtc_remove(struct platform_device *pdev)
+{
+	struct rtc_at32ap700x *rtc = platform_get_drvdata(pdev);
+
+	if (rtc->irq >= 0)
+		free_irq(rtc->irq, rtc);
+	if (rtc->regs)
+		iounmap(rtc->regs);
+	rtc_device_unregister(rtc->rtc);
+	kfree(rtc);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver at32_rtc_driver = {
+	.remove		= __exit_p(at32_rtc_remove),
+	.driver		= {
+		.name	= "rtc",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init at32_rtc_init(void)
+{
+	return platform_driver_probe(&at32_rtc_driver, at32_rtc_probe);
+}
+
+static void __exit at32_rtc_exit(void)
+{
+	platform_driver_unregister(&at32_rtc_driver);
+}
+
+MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
+MODULE_DESCRIPTION("Real time counter for AVR32 AT32AP700x");
+MODULE_LICENSE("GPL");
+
+module_init(at32_rtc_init);
+module_exit(at32_rtc_exit);
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
index 935f48f..4d6b3c5 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/serial/atmel_serial.c
@@ -114,6 +114,7 @@ struct atmel_uart_port {
 	struct uart_port	uart;		/* uart */
 	struct clk		*clk;		/* uart clock */
 	unsigned short		suspended;	/* is port suspended? */
+	int			break_active;	/* break being received */
 };
 
 static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
@@ -252,6 +253,7 @@ static void atmel_break_ctl(struct uart_port *port, int break_state)
  */
 static void atmel_rx_chars(struct uart_port *port)
 {
+	struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
 	struct tty_struct *tty = port->info->tty;
 	unsigned int status, ch, flg;
 
@@ -267,13 +269,29 @@ static void atmel_rx_chars(struct uart_port *port)
 		 * note that the error handling code is
 		 * out of the main execution path
 		 */
-		if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME | ATMEL_US_OVRE | ATMEL_US_RXBRK))) {
+		if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME
+				       | ATMEL_US_OVRE | ATMEL_US_RXBRK)
+			     || atmel_port->break_active)) {
 			UART_PUT_CR(port, ATMEL_US_RSTSTA);	/* clear error */
-			if (status & ATMEL_US_RXBRK) {
+			if (status & ATMEL_US_RXBRK
+			    && !atmel_port->break_active) {
 				status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME);	/* ignore side-effect */
 				port->icount.brk++;
+				atmel_port->break_active = 1;
+				UART_PUT_IER(port, ATMEL_US_RXBRK);
 				if (uart_handle_break(port))
 					goto ignore_char;
+			} else {
+				/*
+				 * This is either the end-of-break
+				 * condition or we've received at
+				 * least one character without RXBRK
+				 * being set. In both cases, the next
+				 * RXBRK will indicate start-of-break.
+				 */
+				UART_PUT_IDR(port, ATMEL_US_RXBRK);
+				status &= ~ATMEL_US_RXBRK;
+				atmel_port->break_active = 0;
 			}
 			if (status & ATMEL_US_PARE)
 				port->icount.parity++;
@@ -352,6 +370,16 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
 		/* Interrupt receive */
 		if (pending & ATMEL_US_RXRDY)
 			atmel_rx_chars(port);
+		else if (pending & ATMEL_US_RXBRK) {
+			/*
+			 * End of break detected. If it came along
+			 * with a character, atmel_rx_chars will
+			 * handle it.
+			 */
+			UART_PUT_CR(port, ATMEL_US_RSTSTA);
+			UART_PUT_IDR(port, ATMEL_US_RXBRK);
+			atmel_port->break_active = 0;
+		}
 
 		// TODO: All reads to CSR will clear these interrupts!
 		if (pending & ATMEL_US_RIIC) port->icount.rng++;
@@ -484,11 +512,16 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios * termios,
 	unsigned long flags;
 	unsigned int mode, imr, quot, baud;
 
+	/* Get current mode register */
+	mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL | ATMEL_US_NBSTOP | ATMEL_US_PAR);
+
 	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
 	quot = uart_get_divisor(port, baud);
 
-	/* Get current mode register */
-	mode = UART_GET_MR(port) & ~(ATMEL_US_CHRL | ATMEL_US_NBSTOP | ATMEL_US_PAR);
+	if (quot > 65535) {		/* BRGR is 16-bit, so switch to slower clock */
+		quot /= 8;
+		mode |= ATMEL_US_USCLKS_MCK_DIV8;
+	}
 
 	/* byte size */
 	switch (termios->c_cflag & CSIZE) {
diff --git a/drivers/serial/atmel_serial.h b/drivers/serial/atmel_serial.h
index 11b4436..e014177 100644
--- a/drivers/serial/atmel_serial.h
+++ b/drivers/serial/atmel_serial.h
@@ -46,6 +46,9 @@
 #define			ATMEL_US_USMODE_ISO7816_T1	6
 #define			ATMEL_US_USMODE_IRDA		8
 #define		ATMEL_US_USCLKS		(3   <<  4)		/* Clock Selection */
+#define			ATMEL_US_USCLKS_MCK		(0 <<  4)
+#define			ATMEL_US_USCLKS_MCK_DIV8	(1 <<  4)
+#define			ATMEL_US_USCLKS_SCK		(3 <<  4)
 #define		ATMEL_US_CHRL		(3   <<  6)		/* Character Length */
 #define			ATMEL_US_CHRL_5			(0 <<  6)
 #define			ATMEL_US_CHRL_6			(1 <<  6)
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index 66e7bc9..8f5453f 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -22,10 +22,7 @@
 #include <asm/io.h>
 #include <asm/arch/board.h>
 #include <asm/arch/gpio.h>
-
-#ifdef CONFIG_ARCH_AT91
 #include <asm/arch/cpu.h>
-#endif
 
 #include "atmel_spi.h"
 
@@ -116,16 +113,16 @@ static void atmel_spi_next_xfer(struct spi_master *master,
 
 	len = as->remaining_bytes;
 
-	tx_dma = xfer->tx_dma;
-	rx_dma = xfer->rx_dma;
+	tx_dma = xfer->tx_dma + xfer->len - len;
+	rx_dma = xfer->rx_dma + xfer->len - len;
 
 	/* use scratch buffer only when rx or tx data is unspecified */
-	if (rx_dma == INVALID_DMA_ADDRESS) {
+	if (!xfer->rx_buf) {
 		rx_dma = as->buffer_dma;
 		if (len > BUFFER_SIZE)
 			len = BUFFER_SIZE;
 	}
-	if (tx_dma == INVALID_DMA_ADDRESS) {
+	if (!xfer->tx_buf) {
 		tx_dma = as->buffer_dma;
 		if (len > BUFFER_SIZE)
 			len = BUFFER_SIZE;
@@ -415,8 +412,8 @@ static int atmel_spi_setup(struct spi_device *spi)
 		csr |= SPI_BIT(NCPHA);
 
 	/* TODO: DLYBS and DLYBCT */
-	csr |= SPI_BF(DLYBS, 10);
-	csr |= SPI_BF(DLYBCT, 10);
+	csr |= SPI_BF(DLYBS, 0);
+	csr |= SPI_BF(DLYBCT, 0);
 
 	/* chipselect must have been muxed as GPIO (e.g. in board setup) */
 	npcs_pin = (unsigned int)spi->controller_data;
@@ -552,10 +549,8 @@ static int __init atmel_spi_probe(struct platform_device *pdev)
 		goto out_free_buffer;
 	as->irq = irq;
 	as->clk = clk;
-#ifdef CONFIG_ARCH_AT91
 	if (!cpu_is_at91rm9200())
 		as->new_1 = 1;
-#endif
 
 	ret = request_irq(irq, atmel_spi_interrupt, 0,
 			pdev->dev.bus_id, master);
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 8372ace..2fcbbd4 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -674,6 +674,22 @@ config FB_S1D13XXX
 	  working with S1D13806). Product specs at
 	  <http://www.erd.epson.com/vdc/html/legacy_13xxx.htm>
 
+config FB_ATMEL
+	tristate "AT91/AT32 LCD Controller support"
+	depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || AVR32)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	help
+	  This enables support for the AT91/AT32 LCD Controller.
+
+config FB_INTSRAM
+	bool "Frame Buffer in internal SRAM"
+	depends on FB_ATMEL && ARCH_AT91SAM9261
+	help
+	  Say Y if you want to map Frame Buffer in internal SRAM. Say N if you want
+	  to let frame buffer in external SDRAM.
+
 config FB_NVIDIA
 	tristate "nVidia Framebuffer Support"
 	depends on FB && PCI
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 760305c..17a09c6 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -75,6 +75,7 @@ obj-$(CONFIG_FB_G364)             += g364fb.o
 obj-$(CONFIG_FB_SA1100)           += sa1100fb.o
 obj-$(CONFIG_FB_HIT)              += hitfb.o
 obj-$(CONFIG_FB_EPSON1355)	  += epson1355fb.o
+obj-$(CONFIG_FB_ATMEL)		  += atmel_lcdfb.o
 obj-$(CONFIG_FB_PVR2)             += pvr2fb.o
 obj-$(CONFIG_FB_VOODOO1)          += sstfb.o
 obj-$(CONFIG_FB_ARMCLCD)	  += amba-clcd.o
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
new file mode 100644
index 0000000..e1d5bd0
--- /dev/null
+++ b/drivers/video/atmel_lcdfb.c
@@ -0,0 +1,752 @@
+/*
+ *  Driver for AT91/AT32 LCD Controller
+ *
+ *  Copyright (C) 2007 Atmel Corporation
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/gpio.h>
+
+#include <video/atmel_lcdc.h>
+
+#define lcdc_readl(sinfo, reg)		__raw_readl((sinfo)->mmio+(reg))
+#define lcdc_writel(sinfo, reg, val)	__raw_writel((val), (sinfo)->mmio+(reg))
+
+/* configurable parameters */
+#define ATMEL_LCDC_CVAL_DEFAULT		0xc8
+#define ATMEL_LCDC_DMA_BURST_LEN	8
+
+#if defined(CONFIG_ARCH_AT91SAM9263)
+#define ATMEL_LCDC_FIFO_SIZE		2048
+#else
+#define ATMEL_LCDC_FIFO_SIZE		512
+#endif
+
+#if defined(CONFIG_ARCH_AT91)
+#define	ATMEL_LCDFB_FBINFO_DEFAULT	FBINFO_DEFAULT
+
+static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
+					struct fb_var_screeninfo *var)
+{
+
+}
+#elif defined(CONFIG_AVR32)
+#define	ATMEL_LCDFB_FBINFO_DEFAULT	(FBINFO_DEFAULT \
+					| FBINFO_PARTIAL_PAN_OK \
+					| FBINFO_HWACCEL_XPAN \
+					| FBINFO_HWACCEL_YPAN)
+
+static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
+				     struct fb_var_screeninfo *var)
+{
+	u32 dma2dcfg;
+	u32 pixeloff;
+
+	pixeloff = (var->xoffset * var->bits_per_pixel) & 0x1f;
+
+	dma2dcfg = ((var->xres_virtual - var->xres) * var->bits_per_pixel) / 8;
+	dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET;
+	lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg);
+
+	/* Update configuration */
+	lcdc_writel(sinfo, ATMEL_LCDC_DMACON,
+		    lcdc_readl(sinfo, ATMEL_LCDC_DMACON)
+		    | ATMEL_LCDC_DMAUPDT);
+}
+#endif
+
+
+static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
+	.type		= FB_TYPE_PACKED_PIXELS,
+	.visual		= FB_VISUAL_TRUECOLOR,
+	.xpanstep	= 0,
+	.ypanstep	= 0,
+	.ywrapstep	= 0,
+	.accel		= FB_ACCEL_NONE,
+};
+
+
+static void atmel_lcdfb_update_dma(struct fb_info *info,
+			       struct fb_var_screeninfo *var)
+{
+	struct atmel_lcdfb_info *sinfo = info->par;
+	struct fb_fix_screeninfo *fix = &info->fix;
+	unsigned long dma_addr;
+
+	dma_addr = (fix->smem_start + var->yoffset * fix->line_length
+		    + var->xoffset * var->bits_per_pixel / 8);
+
+	dma_addr &= ~3UL;
+
+	/* Set framebuffer DMA base address and pixel offset */
+	lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
+
+	atmel_lcdfb_update_dma2d(sinfo, var);
+}
+
+static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
+{
+	struct fb_info *info = sinfo->info;
+
+	dma_free_writecombine(info->device, info->fix.smem_len,
+				info->screen_base, info->fix.smem_start);
+}
+
+/**
+ *	atmel_lcdfb_alloc_video_memory - Allocate framebuffer memory
+ *	@sinfo: the frame buffer to allocate memory for
+ */
+static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
+{
+	struct fb_info *info = sinfo->info;
+	struct fb_var_screeninfo *var = &info->var;
+
+	info->fix.smem_len = (var->xres_virtual * var->yres_virtual
+			    * ((var->bits_per_pixel + 7) / 8));
+
+	info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len,
+					(dma_addr_t *)&info->fix.smem_start, GFP_KERNEL);
+
+	if (!info->screen_base) {
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+/**
+ *      atmel_lcdfb_check_var - Validates a var passed in.
+ *      @var: frame buffer variable screen structure
+ *      @info: frame buffer structure that represents a single frame buffer
+ *
+ *	Checks to see if the hardware supports the state requested by
+ *	var passed in. This function does not alter the hardware
+ *	state!!!  This means the data stored in struct fb_info and
+ *	struct atmel_lcdfb_info do not change. This includes the var
+ *	inside of struct fb_info.  Do NOT change these. This function
+ *	can be called on its own if we intent to only test a mode and
+ *	not actually set it. The stuff in modedb.c is a example of
+ *	this. If the var passed in is slightly off by what the
+ *	hardware can support then we alter the var PASSED in to what
+ *	we can do. If the hardware doesn't support mode change a
+ *	-EINVAL will be returned by the upper layers. You don't need
+ *	to implement this function then. If you hardware doesn't
+ *	support changing the resolution then this function is not
+ *	needed. In this case the driver would just provide a var that
+ *	represents the static state the screen is in.
+ *
+ *	Returns negative errno on error, or zero on success.
+ */
+static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
+			     struct fb_info *info)
+{
+	struct device *dev = info->device;
+	struct atmel_lcdfb_info *sinfo = info->par;
+	unsigned long clk_value_khz;
+
+	clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+
+	dev_dbg(dev, "%s:\n", __func__);
+	dev_dbg(dev, "  resolution: %ux%u\n", var->xres, var->yres);
+	dev_dbg(dev, "  pixclk:     %lu KHz\n", PICOS2KHZ(var->pixclock));
+	dev_dbg(dev, "  bpp:        %u\n", var->bits_per_pixel);
+	dev_dbg(dev, "  clk:        %lu KHz\n", clk_value_khz);
+
+	if ((PICOS2KHZ(var->pixclock) * var->bits_per_pixel / 8) > clk_value_khz) {
+		dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(var->pixclock));
+		return -EINVAL;
+	}
+
+	/* Force same alignment for each line */
+	var->xres = (var->xres + 3) & ~3UL;
+	var->xres_virtual = (var->xres_virtual + 3) & ~3UL;
+
+	var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0;
+	var->transp.msb_right = 0;
+	var->transp.offset = var->transp.length = 0;
+	var->xoffset = var->yoffset = 0;
+
+	switch (var->bits_per_pixel) {
+	case 2:
+	case 4:
+	case 8:
+		var->red.offset = var->green.offset = var->blue.offset = 0;
+		var->red.length = var->green.length = var->blue.length
+			= var->bits_per_pixel;
+		break;
+	case 15:
+	case 16:
+		var->red.offset = 0;
+		var->green.offset = 5;
+		var->blue.offset = 10;
+		var->red.length = var->green.length = var->blue.length = 5;
+		break;
+	case 24:
+	case 32:
+		var->red.offset = 0;
+		var->green.offset = 8;
+		var->blue.offset = 16;
+		var->red.length = var->green.length = var->blue.length = 8;
+		break;
+	default:
+		dev_err(dev, "color depth %d not supported\n",
+					var->bits_per_pixel);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ *      atmel_lcdfb_set_par - Alters the hardware state.
+ *      @info: frame buffer structure that represents a single frame buffer
+ *
+ *	Using the fb_var_screeninfo in fb_info we set the resolution
+ *	of the this particular framebuffer. This function alters the
+ *	par AND the fb_fix_screeninfo stored in fb_info. It doesn't
+ *	not alter var in fb_info since we are using that data. This
+ *	means we depend on the data in var inside fb_info to be
+ *	supported by the hardware.  atmel_lcdfb_check_var is always called
+ *	before atmel_lcdfb_set_par to ensure this.  Again if you can't
+ *	change the resolution you don't need this function.
+ *
+ */
+static int atmel_lcdfb_set_par(struct fb_info *info)
+{
+	struct atmel_lcdfb_info *sinfo = info->par;
+	unsigned long value;
+	unsigned long clk_value_khz;
+
+	dev_dbg(info->device, "%s:\n", __func__);
+	dev_dbg(info->device, "  * resolution: %ux%u (%ux%u virtual)\n",
+		 info->var.xres, info->var.yres,
+		 info->var.xres_virtual, info->var.yres_virtual);
+
+	/* Turn off the LCD controller and the DMA controller */
+	lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
+
+	lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
+
+	if (info->var.bits_per_pixel <= 8)
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+	else
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+
+	info->fix.line_length = info->var.xres_virtual * (info->var.bits_per_pixel / 8);
+
+	/* Re-initialize the DMA engine... */
+	dev_dbg(info->device, "  * update DMA engine\n");
+	atmel_lcdfb_update_dma(info, &info->var);
+
+	/* ...set frame size and burst length = 8 words (?) */
+	value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32;
+	value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
+	lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
+
+	/* Now, the LCDC core... */
+
+	/* Set pixel clock */
+	clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+
+	value = clk_value_khz / PICOS2KHZ(info->var.pixclock);
+
+	if (clk_value_khz % PICOS2KHZ(info->var.pixclock))
+		value++;
+
+	value = (value / 2) - 1;
+
+	if (value <= 0) {
+		dev_notice(info->device, "Bypassing pixel clock divider\n");
+		lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
+	} else
+		lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, value << ATMEL_LCDC_CLKVAL_OFFSET);
+
+	/* Initialize control register 2 */
+	value = sinfo->default_lcdcon2;
+
+	if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
+		value |= ATMEL_LCDC_INVLINE_INVERTED;
+	if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
+		value |= ATMEL_LCDC_INVFRAME_INVERTED;
+
+	switch (info->var.bits_per_pixel) {
+		case 1:	value |= ATMEL_LCDC_PIXELSIZE_1; break;
+		case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break;
+		case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break;
+		case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break;
+		case 15: /* fall through */
+		case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break;
+		case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break;
+		case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break;
+		default: BUG(); break;
+	}
+	dev_dbg(info->device, "  * LCDCON2 = %08lx\n", value);
+	lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
+
+	/* Vertical timing */
+	value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
+	value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET;
+	value |= info->var.lower_margin;
+	dev_dbg(info->device, "  * LCDTIM1 = %08lx\n", value);
+	lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
+
+	/* Horizontal timing */
+	value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
+	value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
+	value |= (info->var.left_margin - 1);
+	dev_dbg(info->device, "  * LCDTIM2 = %08lx\n", value);
+	lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
+
+	/* Display size */
+	value = (info->var.xres - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
+	value |= info->var.yres - 1;
+	lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
+
+	/* FIFO Threshold: Use formula from data sheet */
+	value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
+	lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
+
+	/* Toggle LCD_MODE every frame */
+	lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
+
+	/* Disable all interrupts */
+	lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
+
+	/* Set contrast */
+	value = ATMEL_LCDC_PS_DIV8 | ATMEL_LCDC_POL_POSITIVE | ATMEL_LCDC_ENA_PWMENABLE;
+	lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, value);
+	lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
+	/* ...wait for DMA engine to become idle... */
+	while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
+		msleep(10);
+
+	dev_dbg(info->device, "  * re-enable DMA engine\n");
+	/* ...and enable it with updated configuration */
+	lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
+
+	dev_dbg(info->device, "  * re-enable LCDC core\n");
+	lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
+		(sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR);
+
+	dev_dbg(info->device, "  * DONE\n");
+
+	return 0;
+}
+
+static inline unsigned int chan_to_field(unsigned int chan, const struct fb_bitfield *bf)
+{
+	chan &= 0xffff;
+	chan >>= 16 - bf->length;
+	return chan << bf->offset;
+}
+
+/**
+ *  	atmel_lcdfb_setcolreg - Optional function. Sets a color register.
+ *      @regno: Which register in the CLUT we are programming
+ *      @red: The red value which can be up to 16 bits wide
+ *	@green: The green value which can be up to 16 bits wide
+ *	@blue:  The blue value which can be up to 16 bits wide.
+ *	@transp: If supported the alpha value which can be up to 16 bits wide.
+ *      @info: frame buffer info structure
+ *
+ *  	Set a single color register. The values supplied have a 16 bit
+ *  	magnitude which needs to be scaled in this function for the hardware.
+ *	Things to take into consideration are how many color registers, if
+ *	any, are supported with the current color visual. With truecolor mode
+ *	no color palettes are supported. Here a psuedo palette is created
+ *	which we store the value in pseudo_palette in struct fb_info. For
+ *	pseudocolor mode we have a limited color palette. To deal with this
+ *	we can program what color is displayed for a particular pixel value.
+ *	DirectColor is similar in that we can program each color field. If
+ *	we have a static colormap we don't need to implement this function.
+ *
+ *	Returns negative errno on error, or zero on success. In an
+ *	ideal world, this would have been the case, but as it turns
+ *	out, the other drivers return 1 on failure, so that's what
+ *	we're going to do.
+ */
+static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
+			     unsigned int green, unsigned int blue,
+			     unsigned int transp, struct fb_info *info)
+{
+	struct atmel_lcdfb_info *sinfo = info->par;
+	unsigned int val;
+	u32 *pal;
+	int ret = 1;
+
+	if (info->var.grayscale)
+		red = green = blue = (19595 * red + 38470 * green
+				      + 7471 * blue) >> 16;
+
+	switch (info->fix.visual) {
+	case FB_VISUAL_TRUECOLOR:
+		if (regno < 16) {
+			pal = info->pseudo_palette;
+
+			val  = chan_to_field(red, &info->var.red);
+			val |= chan_to_field(green, &info->var.green);
+			val |= chan_to_field(blue, &info->var.blue);
+
+			pal[regno] = val;
+			ret = 0;
+		}
+		break;
+
+	case FB_VISUAL_PSEUDOCOLOR:
+		if (regno < 256) {
+			val  = ((red   >> 11) & 0x001f);
+			val |= ((green >>  6) & 0x03e0);
+			val |= ((blue  >>  1) & 0x7c00);
+
+			/*
+			 * TODO: intensity bit. Maybe something like
+			 *   ~(red[10] ^ green[10] ^ blue[10]) & 1
+			 */
+
+			lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
+			ret = 0;
+		}
+		break;
+	}
+
+	return ret;
+}
+
+static int atmel_lcdfb_pan_display(struct fb_var_screeninfo *var,
+			       struct fb_info *info)
+{
+	dev_dbg(info->device, "%s\n", __func__);
+
+	atmel_lcdfb_update_dma(info, var);
+
+	return 0;
+}
+
+static struct fb_ops atmel_lcdfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= atmel_lcdfb_check_var,
+	.fb_set_par	= atmel_lcdfb_set_par,
+	.fb_setcolreg	= atmel_lcdfb_setcolreg,
+	.fb_pan_display	= atmel_lcdfb_pan_display,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+};
+
+static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
+{
+	struct fb_info *info = dev_id;
+	struct atmel_lcdfb_info *sinfo = info->par;
+	u32 status;
+
+	status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
+	lcdc_writel(sinfo, ATMEL_LCDC_IDR, status);
+	return IRQ_HANDLED;
+}
+
+static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo)
+{
+	struct fb_info *info = sinfo->info;
+	int ret = 0;
+
+	memset_io(info->screen_base, 0, info->fix.smem_len);
+	info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW;
+
+	dev_info(info->device,
+	       "%luKiB frame buffer at %08lx (mapped at %p)\n",
+	       (unsigned long)info->fix.smem_len / 1024,
+	       (unsigned long)info->fix.smem_start,
+	       info->screen_base);
+
+	/* Allocate colormap */
+	ret = fb_alloc_cmap(&info->cmap, 256, 0);
+	if (ret < 0)
+		dev_err(info->device, "Alloc color map failed\n");
+
+	return ret;
+}
+
+static void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo)
+{
+	if (sinfo->bus_clk)
+		clk_enable(sinfo->bus_clk);
+	clk_enable(sinfo->lcdc_clk);
+}
+
+static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo)
+{
+	if (sinfo->bus_clk)
+		clk_disable(sinfo->bus_clk);
+	clk_disable(sinfo->lcdc_clk);
+}
+
+
+static int __init atmel_lcdfb_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct fb_info *info;
+	struct atmel_lcdfb_info *sinfo;
+	struct atmel_lcdfb_info *pdata_sinfo;
+	struct resource *regs = NULL;
+	struct resource *map = NULL;
+	int ret;
+
+	dev_dbg(dev, "%s BEGIN\n", __func__);
+
+	ret = -ENOMEM;
+	info = framebuffer_alloc(sizeof(struct atmel_lcdfb_info), dev);
+	if (!info) {
+		dev_err(dev, "cannot allocate memory\n");
+		goto out;
+	}
+
+	sinfo = info->par;
+
+	if (dev->platform_data) {
+		pdata_sinfo = (struct atmel_lcdfb_info *)dev->platform_data;
+		sinfo->default_bpp = pdata_sinfo->default_bpp;
+		sinfo->default_dmacon = pdata_sinfo->default_dmacon;
+		sinfo->default_lcdcon2 = pdata_sinfo->default_lcdcon2;
+		sinfo->default_monspecs = pdata_sinfo->default_monspecs;
+		sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control;
+		sinfo->guard_time = pdata_sinfo->guard_time;
+	} else {
+		dev_err(dev, "cannot get default configuration\n");
+		goto free_info;
+	}
+	sinfo->info = info;
+	sinfo->pdev = pdev;
+
+	strcpy(info->fix.id, sinfo->pdev->name);
+	info->flags = ATMEL_LCDFB_FBINFO_DEFAULT;
+	info->pseudo_palette = sinfo->pseudo_palette;
+	info->fbops = &atmel_lcdfb_ops;
+
+	memcpy(&info->monspecs, sinfo->default_monspecs, sizeof(info->monspecs));
+	info->fix = atmel_lcdfb_fix;
+
+	/* Enable LCDC Clocks */
+	if (cpu_is_at91sam9261() || cpu_is_at32ap7000()) {
+		sinfo->bus_clk = clk_get(dev, "hck1");
+		if (IS_ERR(sinfo->bus_clk)) {
+			ret = PTR_ERR(sinfo->bus_clk);
+			goto free_info;
+		}
+	}
+	sinfo->lcdc_clk = clk_get(dev, "lcdc_clk");
+	if (IS_ERR(sinfo->lcdc_clk)) {
+		ret = PTR_ERR(sinfo->lcdc_clk);
+		goto put_bus_clk;
+	}
+	atmel_lcdfb_start_clock(sinfo);
+
+	ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb,
+			info->monspecs.modedb_len, info->monspecs.modedb,
+			sinfo->default_bpp);
+	if (!ret) {
+		dev_err(dev, "no suitable video mode found\n");
+		goto stop_clk;
+	}
+
+
+	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!regs) {
+		dev_err(dev, "resources unusable\n");
+		ret = -ENXIO;
+		goto stop_clk;
+	}
+
+	sinfo->irq_base = platform_get_irq(pdev, 0);
+	if (sinfo->irq_base < 0) {
+		dev_err(dev, "unable to get irq\n");
+		ret = sinfo->irq_base;
+		goto stop_clk;
+	}
+
+	/* Initialize video memory */
+	map = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (map) {
+		/* use a pre-allocated memory buffer */
+		info->fix.smem_start = map->start;
+		info->fix.smem_len = map->end - map->start + 1;
+		if (!request_mem_region(info->fix.smem_start,
+					info->fix.smem_len, pdev->name)) {
+			ret = -EBUSY;
+			goto stop_clk;
+		}
+
+		info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
+		if (!info->screen_base)
+			goto release_intmem;
+	} else {
+		/* alocate memory buffer */
+		ret = atmel_lcdfb_alloc_video_memory(sinfo);
+		if (ret < 0) {
+			dev_err(dev, "cannot allocate framebuffer: %d\n", ret);
+			goto stop_clk;
+		}
+	}
+
+	/* LCDC registers */
+	info->fix.mmio_start = regs->start;
+	info->fix.mmio_len = regs->end - regs->start + 1;
+
+	if (!request_mem_region(info->fix.mmio_start,
+				info->fix.mmio_len, pdev->name)) {
+		ret = -EBUSY;
+		goto free_fb;
+	}
+
+	sinfo->mmio = ioremap(info->fix.mmio_start, info->fix.mmio_len);
+	if (!sinfo->mmio) {
+		dev_err(dev, "cannot map LCDC registers\n");
+		goto release_mem;
+	}
+
+	/* interrupt */
+	ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info);
+	if (ret) {
+		dev_err(dev, "request_irq failed: %d\n", ret);
+		goto unmap_mmio;
+	}
+
+	ret = atmel_lcdfb_init_fbinfo(sinfo);
+	if (ret < 0) {
+		dev_err(dev, "init fbinfo failed: %d\n", ret);
+		goto unregister_irqs;
+	}
+
+	/*
+	 * This makes sure that our colour bitfield
+	 * descriptors are correctly initialised.
+	 */
+	atmel_lcdfb_check_var(&info->var, info);
+
+	ret = fb_set_var(info, &info->var);
+	if (ret) {
+		dev_warn(dev, "unable to set display parameters\n");
+		goto free_cmap;
+	}
+
+	dev_set_drvdata(dev, info);
+
+	/*
+	 * Tell the world that we're ready to go
+	 */
+	ret = register_framebuffer(info);
+	if (ret < 0) {
+		dev_err(dev, "failed to register framebuffer device: %d\n", ret);
+		goto free_cmap;
+	}
+
+	/* Power up the LCDC screen */
+	if (sinfo->atmel_lcdfb_power_control)
+		sinfo->atmel_lcdfb_power_control(1);
+
+	dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %lu\n",
+		       info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base);
+
+	return 0;
+
+
+free_cmap:
+	fb_dealloc_cmap(&info->cmap);
+unregister_irqs:
+	free_irq(sinfo->irq_base, info);
+unmap_mmio:
+	iounmap(sinfo->mmio);
+release_mem:
+ 	release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+free_fb:
+	if (map)
+		iounmap(info->screen_base);
+	else
+		atmel_lcdfb_free_video_memory(sinfo);
+
+release_intmem:
+	if (map)
+		release_mem_region(info->fix.smem_start, info->fix.smem_len);
+stop_clk:
+	atmel_lcdfb_stop_clock(sinfo);
+	clk_put(sinfo->lcdc_clk);
+put_bus_clk:
+	if (sinfo->bus_clk)
+		clk_put(sinfo->bus_clk);
+free_info:
+	framebuffer_release(info);
+out:
+	dev_dbg(dev, "%s FAILED\n", __func__);
+	return ret;
+}
+
+static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct fb_info *info = dev_get_drvdata(dev);
+	struct atmel_lcdfb_info *sinfo = info->par;
+
+	if (!sinfo)
+		return 0;
+
+	if (sinfo->atmel_lcdfb_power_control)
+		sinfo->atmel_lcdfb_power_control(0);
+	unregister_framebuffer(info);
+	atmel_lcdfb_stop_clock(sinfo);
+	clk_put(sinfo->lcdc_clk);
+	if (sinfo->bus_clk)
+		clk_put(sinfo->bus_clk);
+	fb_dealloc_cmap(&info->cmap);
+	free_irq(sinfo->irq_base, info);
+	iounmap(sinfo->mmio);
+ 	release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+	if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) {
+		iounmap(info->screen_base);
+		release_mem_region(info->fix.smem_start, info->fix.smem_len);
+	} else {
+		atmel_lcdfb_free_video_memory(sinfo);
+	}
+
+	dev_set_drvdata(dev, NULL);
+	framebuffer_release(info);
+
+	return 0;
+}
+
+static struct platform_driver atmel_lcdfb_driver = {
+	.remove		= __exit_p(atmel_lcdfb_remove),
+	.driver		= {
+		.name	= "atmel_lcdfb",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init atmel_lcdfb_init(void)
+{
+	return platform_driver_probe(&atmel_lcdfb_driver, atmel_lcdfb_probe);
+}
+
+static void __exit atmel_lcdfb_exit(void)
+{
+	platform_driver_unregister(&atmel_lcdfb_driver);
+}
+
+module_init(atmel_lcdfb_init);
+module_exit(atmel_lcdfb_exit);
+
+MODULE_DESCRIPTION("AT91/AT32 LCD Controller framebuffer driver");
+MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@rfo.atmel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 47d15b5..b59d5bb 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -8,26 +8,44 @@ menuconfig BACKLIGHT_LCD_SUPPORT
 	  Enable this to be able to choose the drivers for controlling the
 	  backlight and the LCD panel on some platforms, for example on PDAs.
 
-config BACKLIGHT_CLASS_DEVICE
-        tristate "Lowlevel Backlight controls"
+#
+# LCD
+#
+config LCD_CLASS_DEVICE
+        tristate "Lowlevel LCD controls"
 	depends on BACKLIGHT_LCD_SUPPORT
 	default m
 	help
-	  This framework adds support for low-level control of the LCD
-          backlight. This includes support for brightness and power.
+	  This framework adds support for low-level control of LCD.
+	  Some framebuffer devices connect to platform-specific LCD modules
+	  in order to have a platform-specific way to control the flat panel
+	  (contrast and applying power to the LCD (not to the backlight!)).
 
 	  To have support for your specific LCD panel you will have to
 	  select the proper drivers which depend on this option.
 
-config LCD_CLASS_DEVICE
-        tristate "Lowlevel LCD controls"
+config LCD_LTV350QV
+	tristate "Samsung LTV350QV LCD Panel"
+	depends on LCD_CLASS_DEVICE && SPI_MASTER
+	default n
+	help
+	  If you have a Samsung LTV350QV LCD panel, say y to include a
+	  power control driver for it.  The panel starts up in power
+	  off state, so you need this driver in order to see any
+	  output.
+
+	  The LTV350QV panel is present on all ATSTK1000 boards.
+
+#
+# Backlight
+#
+config BACKLIGHT_CLASS_DEVICE
+        tristate "Lowlevel Backlight controls"
 	depends on BACKLIGHT_LCD_SUPPORT
 	default m
 	help
-	  This framework adds support for low-level control of LCD.
-	  Some framebuffer devices connect to platform-specific LCD modules
-	  in order to have a platform-specific way to control the flat panel
-	  (contrast and applying power to the LCD (not to the backlight!)).
+	  This framework adds support for low-level control of the LCD
+          backlight. This includes support for brightness and power.
 
 	  To have support for your specific LCD panel you will have to
 	  select the proper drivers which depend on this option.
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 0c3ce46..526c54b 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -1,6 +1,8 @@
 # Backlight & LCD drivers
 
 obj-$(CONFIG_LCD_CLASS_DEVICE)     += lcd.o
+obj-$(CONFIG_LCD_LTV350QV)	+= ltv350qv.o
+
 obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
 obj-$(CONFIG_BACKLIGHT_CORGI)	+= corgi_bl.o
 obj-$(CONFIG_BACKLIGHT_HP680)	+= hp680_bl.o
diff --git a/drivers/video/backlight/ltv350qv.c b/drivers/video/backlight/ltv350qv.c
new file mode 100644
index 0000000..342b97a
--- /dev/null
+++ b/drivers/video/backlight/ltv350qv.c
@@ -0,0 +1,340 @@
+/*
+ * Power control for Samsung LTV350QV Quarter VGA LCD Panel
+ *
+ * Copyright (C) 2006, 2007 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/delay.h>
+#include <linux/err.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/lcd.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#include "ltv350qv.h"
+
+#define POWER_IS_ON(pwr)	((pwr) <= FB_BLANK_NORMAL)
+
+struct ltv350qv {
+	struct spi_device	*spi;
+	u8			*buffer;
+	int			power;
+	struct lcd_device	*ld;
+};
+
+/*
+ * The power-on and power-off sequences are taken from the
+ * LTV350QV-F04 data sheet from Samsung. The register definitions are
+ * taken from the S6F2002 command list also from Samsung. Both
+ * documents are distributed with the AVR32 Linux BSP CD from Atmel.
+ *
+ * There's still some voodoo going on here, but it's a lot better than
+ * in the first incarnation of the driver where all we had was the raw
+ * numbers from the initialization sequence.
+ */
+static int ltv350qv_write_reg(struct ltv350qv *lcd, u8 reg, u16 val)
+{
+	struct spi_message msg;
+	struct spi_transfer index_xfer = {
+		.len		= 3,
+		.cs_change	= 1,
+	};
+	struct spi_transfer value_xfer = {
+		.len		= 3,
+		.cs_change	= 1,
+	};
+
+	spi_message_init(&msg);
+
+	/* register index */
+	lcd->buffer[0] = LTV_OPC_INDEX;
+	lcd->buffer[1] = 0x00;
+	lcd->buffer[2] = reg & 0x7f;
+	index_xfer.tx_buf = lcd->buffer;
+	spi_message_add_tail(&index_xfer, &msg);
+
+	/* register value */
+	lcd->buffer[4] = LTV_OPC_DATA;
+	lcd->buffer[5] = val >> 8;
+	lcd->buffer[6] = val;
+	value_xfer.tx_buf = lcd->buffer + 4;
+	spi_message_add_tail(&value_xfer, &msg);
+
+	return spi_sync(lcd->spi, &msg);
+}
+
+/* The comments are taken straight from the data sheet */
+static int ltv350qv_power_on(struct ltv350qv *lcd)
+{
+	int ret;
+
+	/* Power On Reset Display off State */
+	if (ltv350qv_write_reg(lcd, LTV_PWRCTL1, 0x0000))
+		goto err;
+	msleep(15);
+
+	/* Power Setting Function 1 */
+	if (ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE))
+		goto err;
+	if (ltv350qv_write_reg(lcd, LTV_PWRCTL2, LTV_VCOML_ENABLE))
+		goto err_power1;
+
+	/* Power Setting Function 2 */
+	if (ltv350qv_write_reg(lcd, LTV_PWRCTL1,
+			       LTV_VCOM_DISABLE | LTV_DRIVE_CURRENT(5)
+			       | LTV_SUPPLY_CURRENT(5)))
+		goto err_power2;
+
+	msleep(55);
+
+	/* Instruction Setting */
+	ret = ltv350qv_write_reg(lcd, LTV_IFCTL,
+				 LTV_NMD | LTV_REV | LTV_NL(0x1d));
+	ret |= ltv350qv_write_reg(lcd, LTV_DATACTL,
+				  LTV_DS_SAME | LTV_CHS_480
+				  | LTV_DF_RGB | LTV_RGB_BGR);
+	ret |= ltv350qv_write_reg(lcd, LTV_ENTRY_MODE,
+				  LTV_VSPL_ACTIVE_LOW
+				  | LTV_HSPL_ACTIVE_LOW
+				  | LTV_DPL_SAMPLE_RISING
+				  | LTV_EPL_ACTIVE_LOW
+				  | LTV_SS_RIGHT_TO_LEFT);
+	ret |= ltv350qv_write_reg(lcd, LTV_GATECTL1, LTV_CLW(3));
+	ret |= ltv350qv_write_reg(lcd, LTV_GATECTL2,
+				  LTV_NW_INV_1LINE | LTV_FWI(3));
+	ret |= ltv350qv_write_reg(lcd, LTV_VBP, 0x000a);
+	ret |= ltv350qv_write_reg(lcd, LTV_HBP, 0x0021);
+	ret |= ltv350qv_write_reg(lcd, LTV_SOTCTL, LTV_SDT(3) | LTV_EQ(0));
+	ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(0), 0x0103);
+	ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(1), 0x0301);
+	ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(2), 0x1f0f);
+	ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(3), 0x1f0f);
+	ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(4), 0x0707);
+	ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(5), 0x0307);
+	ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(6), 0x0707);
+	ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(7), 0x0000);
+	ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(8), 0x0004);
+	ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(9), 0x0000);
+	if (ret)
+		goto err_settings;
+
+	/* Wait more than 2 frames */
+	msleep(20);
+
+	/* Display On Sequence */
+	ret = ltv350qv_write_reg(lcd, LTV_PWRCTL1,
+				 LTV_VCOM_DISABLE | LTV_VCOMOUT_ENABLE
+				 | LTV_POWER_ON | LTV_DRIVE_CURRENT(5)
+				 | LTV_SUPPLY_CURRENT(5));
+	ret |= ltv350qv_write_reg(lcd, LTV_GATECTL2,
+				  LTV_NW_INV_1LINE | LTV_DSC | LTV_FWI(3));
+	if (ret)
+		goto err_disp_on;
+
+	/* Display should now be ON. Phew. */
+	return 0;
+
+err_disp_on:
+	/*
+	 * Try to recover. Error handling probably isn't very useful
+	 * at this point, just make a best effort to switch the panel
+	 * off.
+	 */
+	ltv350qv_write_reg(lcd, LTV_PWRCTL1,
+			   LTV_VCOM_DISABLE | LTV_DRIVE_CURRENT(5)
+			   | LTV_SUPPLY_CURRENT(5));
+	ltv350qv_write_reg(lcd, LTV_GATECTL2,
+			   LTV_NW_INV_1LINE | LTV_FWI(3));
+err_settings:
+err_power2:
+err_power1:
+	ltv350qv_write_reg(lcd, LTV_PWRCTL2, 0x0000);
+	msleep(1);
+err:
+	ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE);
+	return -EIO;
+}
+
+static int ltv350qv_power_off(struct ltv350qv *lcd)
+{
+	int ret;
+
+	/* Display Off Sequence */
+	ret = ltv350qv_write_reg(lcd, LTV_PWRCTL1,
+				 LTV_VCOM_DISABLE
+				 | LTV_DRIVE_CURRENT(5)
+				 | LTV_SUPPLY_CURRENT(5));
+	ret |= ltv350qv_write_reg(lcd, LTV_GATECTL2,
+				  LTV_NW_INV_1LINE | LTV_FWI(3));
+
+	/* Power down setting 1 */
+	ret |= ltv350qv_write_reg(lcd, LTV_PWRCTL2, 0x0000);
+
+	/* Wait at least 1 ms */
+	msleep(1);
+
+	/* Power down setting 2 */
+	ret |= ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE);
+
+	/*
+	 * No point in trying to recover here. If we can't switch the
+	 * panel off, what are we supposed to do other than inform the
+	 * user about the failure?
+	 */
+	if (ret)
+		return -EIO;
+
+	/* Display power should now be OFF */
+	return 0;
+}
+
+static int ltv350qv_power(struct ltv350qv *lcd, int power)
+{
+	int ret = 0;
+
+	if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power))
+		ret = ltv350qv_power_on(lcd);
+	else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power))
+		ret = ltv350qv_power_off(lcd);
+
+	if (!ret)
+		lcd->power = power;
+
+	return ret;
+}
+
+static int ltv350qv_set_power(struct lcd_device *ld, int power)
+{
+	struct ltv350qv *lcd;
+
+	lcd = class_get_devdata(&ld->class_dev);
+	return ltv350qv_power(lcd, power);
+}
+
+static int ltv350qv_get_power(struct lcd_device *ld)
+{
+	struct ltv350qv *lcd;
+
+	lcd = class_get_devdata(&ld->class_dev);
+	return lcd->power;
+}
+
+static struct lcd_ops ltv_ops = {
+	.get_power	= ltv350qv_get_power,
+	.set_power	= ltv350qv_set_power,
+};
+
+static int __devinit ltv350qv_probe(struct spi_device *spi)
+{
+	struct ltv350qv *lcd;
+	struct lcd_device *ld;
+	int ret;
+
+	lcd = kzalloc(sizeof(struct ltv350qv), GFP_KERNEL);
+	if (!lcd)
+		return -ENOMEM;
+
+	lcd->spi = spi;
+	lcd->power = FB_BLANK_POWERDOWN;
+	lcd->buffer = kzalloc(8, GFP_KERNEL);
+
+	ld = lcd_device_register("ltv350qv", lcd, &ltv_ops);
+	if (IS_ERR(ld)) {
+		ret = PTR_ERR(ld);
+		goto out_free_lcd;
+	}
+	lcd->ld = ld;
+
+	ret = ltv350qv_power(lcd, FB_BLANK_UNBLANK);
+	if (ret)
+		goto out_unregister;
+
+	dev_set_drvdata(&spi->dev, lcd);
+
+	return 0;
+
+out_unregister:
+	lcd_device_unregister(ld);
+out_free_lcd:
+	kfree(lcd);
+	return ret;
+}
+
+static int __devexit ltv350qv_remove(struct spi_device *spi)
+{
+	struct ltv350qv *lcd = dev_get_drvdata(&spi->dev);
+
+	ltv350qv_power(lcd, FB_BLANK_POWERDOWN);
+	lcd_device_unregister(lcd->ld);
+	kfree(lcd);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int ltv350qv_suspend(struct spi_device *spi,
+			    pm_message_t state, u32 level)
+{
+	struct ltv350qv *lcd = dev_get_drvdata(&spi->dev);
+
+	if (level == SUSPEND_POWER_DOWN)
+		return ltv350qv_power(lcd, FB_BLANK_POWERDOWN);
+
+	return 0;
+}
+
+static int ltv350qv_resume(struct spi_device *spi, u32 level)
+{
+	struct ltv350qv *lcd = dev_get_drvdata(&spi->dev);
+
+	if (level == RESUME_POWER_ON)
+		return ltv350qv_power(lcd, FB_BLANK_UNBLANK);
+
+	return 0;
+}
+#else
+#define ltv350qv_suspend	NULL
+#define ltv350qv_resume		NULL
+#endif
+
+/* Power down all displays on reboot, poweroff or halt */
+static void ltv350qv_shutdown(struct spi_device *spi)
+{
+	struct ltv350qv *lcd = dev_get_drvdata(&spi->dev);
+
+	ltv350qv_power(lcd, FB_BLANK_POWERDOWN);
+}
+
+static struct spi_driver ltv350qv_driver = {
+	.driver = {
+		.name		= "ltv350qv",
+		.bus		= &spi_bus_type,
+		.owner		= THIS_MODULE,
+	},
+
+	.probe		= ltv350qv_probe,
+	.remove		= __devexit_p(ltv350qv_remove),
+	.shutdown	= ltv350qv_shutdown,
+	.suspend	= ltv350qv_suspend,
+	.resume		= ltv350qv_resume,
+};
+
+static int __init ltv350qv_init(void)
+{
+	return spi_register_driver(&ltv350qv_driver);
+}
+
+static void __exit ltv350qv_exit(void)
+{
+	spi_unregister_driver(&ltv350qv_driver);
+}
+module_init(ltv350qv_init);
+module_exit(ltv350qv_exit);
+
+MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
+MODULE_DESCRIPTION("Samsung LTV350QV LCD Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/backlight/ltv350qv.h b/drivers/video/backlight/ltv350qv.h
new file mode 100644
index 0000000..189112e
--- /dev/null
+++ b/drivers/video/backlight/ltv350qv.h
@@ -0,0 +1,95 @@
+/*
+ * Register definitions for Samsung LTV350QV Quarter VGA LCD Panel
+ *
+ * Copyright (C) 2006, 2007 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 __LTV350QV_H
+#define __LTV350QV_H
+
+#define LTV_OPC_INDEX	0x74
+#define LTV_OPC_DATA	0x76
+
+#define LTV_ID		0x00		/* ID Read */
+#define LTV_IFCTL	0x01		/* Display Interface Control */
+#define LTV_DATACTL	0x02		/* Display Data Control */
+#define LTV_ENTRY_MODE	0x03		/* Entry Mode */
+#define LTV_GATECTL1	0x04		/* Gate Control 1 */
+#define LTV_GATECTL2	0x05		/* Gate Control 2 */
+#define LTV_VBP		0x06		/* Vertical Back Porch */
+#define LTV_HBP		0x07		/* Horizontal Back Porch */
+#define LTV_SOTCTL	0x08		/* Source Output Timing Control */
+#define LTV_PWRCTL1	0x09		/* Power Control 1 */
+#define LTV_PWRCTL2	0x0a		/* Power Control 2 */
+#define LTV_GAMMA(x)	(0x10 + (x))	/* Gamma control */
+
+/* Bit definitions for LTV_IFCTL */
+#define LTV_IM			(1 << 15)
+#define LTV_NMD			(1 << 14)
+#define LTV_SSMD		(1 << 13)
+#define LTV_REV			(1 <<  7)
+#define LTV_NL(x)		(((x) & 0x001f) << 0)
+
+/* Bit definitions for LTV_DATACTL */
+#define LTV_DS_SAME		(0 << 12)
+#define LTV_DS_D_TO_S		(1 << 12)
+#define LTV_DS_S_TO_D		(2 << 12)
+#define LTV_CHS_384		(0 <<  9)
+#define LTV_CHS_480		(1 <<  9)
+#define LTV_CHS_492		(2 <<  9)
+#define LTV_DF_RGB		(0 <<  6)
+#define LTV_DF_RGBX		(1 <<  6)
+#define LTV_DF_XRGB		(2 <<  6)
+#define LTV_RGB_RGB		(0 <<  2)
+#define LTV_RGB_BGR		(1 <<  2)
+#define LTV_RGB_GRB		(2 <<  2)
+#define LTV_RGB_RBG		(3 <<  2)
+
+/* Bit definitions for LTV_ENTRY_MODE */
+#define LTV_VSPL_ACTIVE_LOW	(0 << 15)
+#define LTV_VSPL_ACTIVE_HIGH	(1 << 15)
+#define LTV_HSPL_ACTIVE_LOW	(0 << 14)
+#define LTV_HSPL_ACTIVE_HIGH	(1 << 14)
+#define LTV_DPL_SAMPLE_RISING	(0 << 13)
+#define LTV_DPL_SAMPLE_FALLING	(1 << 13)
+#define LTV_EPL_ACTIVE_LOW	(0 << 12)
+#define LTV_EPL_ACTIVE_HIGH	(1 << 12)
+#define LTV_SS_LEFT_TO_RIGHT	(0 <<  8)
+#define LTV_SS_RIGHT_TO_LEFT	(1 <<  8)
+#define LTV_STB			(1 <<  1)
+
+/* Bit definitions for LTV_GATECTL1 */
+#define LTV_CLW(x)		(((x) & 0x0007) << 12)
+#define LTV_GAON		(1 <<  5)
+#define LTV_SDR			(1 <<  3)
+
+/* Bit definitions for LTV_GATECTL2 */
+#define LTV_NW_INV_FRAME	(0 << 14)
+#define LTV_NW_INV_1LINE	(1 << 14)
+#define LTV_NW_INV_2LINE	(2 << 14)
+#define LTV_DSC			(1 << 12)
+#define LTV_GIF			(1 <<  8)
+#define LTV_FHN			(1 <<  7)
+#define LTV_FTI(x)		(((x) & 0x0003) << 4)
+#define LTV_FWI(x)		(((x) & 0x0003) << 0)
+
+/* Bit definitions for LTV_SOTCTL */
+#define LTV_SDT(x)		(((x) & 0x0007) << 10)
+#define LTV_EQ(x)		(((x) & 0x0007) <<  2)
+
+/* Bit definitions for LTV_PWRCTL1 */
+#define LTV_VCOM_DISABLE	(1 << 14)
+#define LTV_VCOMOUT_ENABLE	(1 << 11)
+#define LTV_POWER_ON		(1 <<  9)
+#define LTV_DRIVE_CURRENT(x)	(((x) & 0x0007) << 4)	/* 0=off, 5=max */
+#define LTV_SUPPLY_CURRENT(x)	(((x) & 0x0007) << 0)	/* 0=off, 5=max */
+
+/* Bit definitions for LTV_PWRCTL2 */
+#define LTV_VCOML_ENABLE	(1 << 13)
+#define LTV_VCOML_VOLTAGE(x)	(((x) & 0x001f) << 8)	/* 0=1V, 31=-1V */
+#define LTV_VCOMH_VOLTAGE(x)	(((x) & 0x001f) << 0)	/* 0=3V, 31=4.5V */
+
+#endif /* __LTV350QV_H */
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 2822526..babf8a9 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1198,6 +1198,10 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
 	pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
 #elif defined(__arm__) || defined(__sh__) || defined(__m32r__)
 	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+#elif defined(__avr32__)
+	vma->vm_page_prot = __pgprot((pgprot_val(vma->vm_page_prot)
+				      & ~_PAGE_CACHABLE)
+				     | (_PAGE_BUFFER | _PAGE_DIRTY));
 #elif defined(__ia64__)
 	if (efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start))
 		vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
diff --git a/include/asm-alpha/pgtable.h b/include/asm-alpha/pgtable.h
index 49ac9be..616d206 100644
--- a/include/asm-alpha/pgtable.h
+++ b/include/asm-alpha/pgtable.h
@@ -345,10 +345,6 @@ extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
 #define io_remap_pfn_range(vma, start, pfn, size, prot)	\
 		remap_pfn_range(vma, start, pfn, size, prot)
 
-#define MK_IOSPACE_PFN(space, pfn)	(pfn)
-#define GET_IOSPACE(pfn)		0
-#define GET_PFN(pfn)			(pfn)
-
 #define pte_ERROR(e) \
 	printk("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e))
 #define pmd_ERROR(e) \
diff --git a/include/asm-alpha/scatterlist.h b/include/asm-alpha/scatterlist.h
index 6afb8bd..9173654 100644
--- a/include/asm-alpha/scatterlist.h
+++ b/include/asm-alpha/scatterlist.h
@@ -2,6 +2,7 @@
 #define _ALPHA_SCATTERLIST_H
 
 #include <asm/page.h>
+#include <asm/types.h>
   
 struct scatterlist {
 	struct page *page;
diff --git a/include/asm-arm/arch-at91/cpu.h b/include/asm-arm/arch-at91/cpu.h
index d464ca5..7ef4eeb 100644
--- a/include/asm-arm/arch-at91/cpu.h
+++ b/include/asm-arm/arch-at91/cpu.h
@@ -68,4 +68,10 @@ static inline unsigned long at91_arch_identify(void)
 #define cpu_is_at91sam9263()	(0)
 #endif
 
+/*
+ * Since this is ARM, we will never run on any AVR32 CPU. But these
+ * definitions may reduce clutter in common drivers.
+ */
+#define cpu_is_at32ap7000()	(0)
+
 #endif
diff --git a/include/asm-arm/pgtable-nommu.h b/include/asm-arm/pgtable-nommu.h
index 7b1c9ac..0c8be19 100644
--- a/include/asm-arm/pgtable-nommu.h
+++ b/include/asm-arm/pgtable-nommu.h
@@ -83,10 +83,6 @@ extern int is_in_rom(unsigned long);
 #define io_remap_page_range	remap_page_range
 #define io_remap_pfn_range	remap_pfn_range
 
-#define MK_IOSPACE_PFN(space, pfn)	(pfn)
-#define GET_IOSPACE(pfn)		0
-#define GET_PFN(pfn)			(pfn)
-
 
 /*
  * All 32bit addresses are effectively valid for vmalloc...
diff --git a/include/asm-arm/pgtable.h b/include/asm-arm/pgtable.h
index 7b2bafc..21dec9f 100644
--- a/include/asm-arm/pgtable.h
+++ b/include/asm-arm/pgtable.h
@@ -395,10 +395,6 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 #define io_remap_pfn_range(vma,from,pfn,size,prot) \
 		remap_pfn_range(vma, from, pfn, size, prot)
 
-#define MK_IOSPACE_PFN(space, pfn)	(pfn)
-#define GET_IOSPACE(pfn)		0
-#define GET_PFN(pfn)			(pfn)
-
 #define pgtable_cache_init() do { } while (0)
 
 #endif /* !__ASSEMBLY__ */
diff --git a/include/asm-arm26/pgtable.h b/include/asm-arm26/pgtable.h
index 63a8881..2b20e9f 100644
--- a/include/asm-arm26/pgtable.h
+++ b/include/asm-arm26/pgtable.h
@@ -297,10 +297,6 @@ static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
 #define io_remap_pfn_range(vma,from,pfn,size,prot) \
 		remap_pfn_range(vma, from, pfn, size, prot)
 
-#define MK_IOSPACE_PFN(space, pfn)	(pfn)
-#define GET_IOSPACE(pfn)		0
-#define GET_PFN(pfn)			(pfn)
-
 #endif /* !__ASSEMBLY__ */
 
 #endif /* _ASMARM_PGTABLE_H */
diff --git a/include/asm-avr32/arch-at32ap/board.h b/include/asm-avr32/arch-at32ap/board.h
index 1a7b07d..2293ab0 100644
--- a/include/asm-avr32/arch-at32ap/board.h
+++ b/include/asm-avr32/arch-at32ap/board.h
@@ -6,6 +6,8 @@
 
 #include <linux/types.h>
 
+#define GPIO_PIN_NONE	(-1)
+
 /* Add basic devices: system manager, interrupt controller, portmuxes, etc. */
 void at32_add_system_devices(void);
 
@@ -30,11 +32,46 @@ struct spi_board_info;
 struct platform_device *
 at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n);
 
-struct lcdc_platform_data {
-	unsigned long fbmem_start;
-	unsigned long fbmem_size;
+struct platform_device *at32_add_device_twi(unsigned int id);
+
+struct mci_platform_data {
+	int detect_pin;
+	int wp_pin;
+};
+struct platform_device *
+at32_add_device_mci(unsigned int id, struct mci_platform_data *data);
+struct platform_device *at32_add_device_usba(unsigned int id);
+
+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);
+
+struct platform_device *at32_add_device_ac97c(unsigned int id);
+struct platform_device *at32_add_device_abdac(unsigned int id);
+
+struct cf_platform_data {
+	int	detect_pin;
+	int	reset_pin;
+	int	vcc_pin;
+	u8	cs;
 };
 struct platform_device *
-at32_add_device_lcdc(unsigned int id, struct lcdc_platform_data *data);
+at32_add_device_cf(unsigned int id, unsigned int extint,
+		   struct cf_platform_data *data);
+
+/* 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/cpu.h b/include/asm-avr32/arch-at32ap/cpu.h
new file mode 100644
index 0000000..2bdc5bd
--- /dev/null
+++ b/include/asm-avr32/arch-at32ap/cpu.h
@@ -0,0 +1,33 @@
+/*
+ * AVR32 and (fake) AT91 CPU identification
+ *
+ * Copyright (C) 2007 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_ARCH_CPU_H
+#define __ASM_ARCH_CPU_H
+
+/*
+ * Only AT32AP7000 is defined for now. We can identify the specific
+ * chip at runtime, but I'm not sure if it's really worth it.
+ */
+#ifdef CONFIG_CPU_AT32AP7000
+# define cpu_is_at32ap7000()	(1)
+#else
+# define cpu_is_at32ap7000()	(0)
+#endif
+
+/*
+ * Since this is AVR32, we will never run on any AT91 CPU. But these
+ * definitions may reduce clutter in common drivers.
+ */
+#define cpu_is_at91rm9200()	(0)
+#define cpu_is_at91sam9xe()	(0)
+#define cpu_is_at91sam9260()	(0)
+#define cpu_is_at91sam9261()	(0)
+#define cpu_is_at91sam9263()	(0)
+
+#endif /* __ASM_ARCH_CPU_H */
diff --git a/include/asm-avr32/arch-at32ap/gpio.h b/include/asm-avr32/arch-at32ap/gpio.h
index 80a21aa..af7f953 100644
--- a/include/asm-avr32/arch-at32ap/gpio.h
+++ b/include/asm-avr32/arch-at32ap/gpio.h
@@ -14,6 +14,8 @@ int gpio_direction_output(unsigned int gpio, int value);
 int gpio_get_value(unsigned int gpio);
 void gpio_set_value(unsigned int gpio, int value);
 
+#include <asm-generic/gpio.h>		/* cansleep wrappers */
+
 static inline int gpio_to_irq(unsigned int gpio)
 {
 	return gpio + GPIO_IRQ_BASE;
diff --git a/include/asm-avr32/arch-at32ap/io.h b/include/asm-avr32/arch-at32ap/io.h
new file mode 100644
index 0000000..ee59e40
--- /dev/null
+++ b/include/asm-avr32/arch-at32ap/io.h
@@ -0,0 +1,39 @@
+#ifndef __ASM_AVR32_ARCH_AT32AP_IO_H
+#define __ASM_AVR32_ARCH_AT32AP_IO_H
+
+/* For "bizarre" halfword swapping */
+#include <linux/byteorder/swabb.h>
+
+#if defined(CONFIG_AP7000_32_BIT_SMC)
+# define __swizzle_addr_b(addr)	(addr ^ 3UL)
+# define __swizzle_addr_w(addr)	(addr ^ 2UL)
+# define __swizzle_addr_l(addr)	(addr)
+# define ioswabb(a, x)		(x)
+# define ioswabw(a, x)		(x)
+# define ioswabl(a, x)		(x)
+# define __mem_ioswabb(a, x)	(x)
+# define __mem_ioswabw(a, x)	swab16(x)
+# define __mem_ioswabl(a, x)	swab32(x)
+#elif defined(CONFIG_AP7000_16_BIT_SMC)
+# define __swizzle_addr_b(addr)	(addr ^ 1UL)
+# define __swizzle_addr_w(addr)	(addr)
+# define __swizzle_addr_l(addr)	(addr)
+# define ioswabb(a, x)		(x)
+# define ioswabw(a, x)		(x)
+# define ioswabl(a, x)		swahw32(x)
+# define __mem_ioswabb(a, x)	(x)
+# define __mem_ioswabw(a, x)	swab16(x)
+# define __mem_ioswabl(a, x)	swahb32(x)
+#else
+# define __swizzle_addr_b(addr)	(addr)
+# define __swizzle_addr_w(addr)	(addr)
+# define __swizzle_addr_l(addr)	(addr)
+# define ioswabb(a, x)		(x)
+# define ioswabw(a, x)		swab16(x)
+# define ioswabl(a, x)		swab32(x)
+# define __mem_ioswabb(a, x)	(x)
+# define __mem_ioswabw(a, x)	(x)
+# define __mem_ioswabl(a, x)	(x)
+#endif
+
+#endif /* __ASM_AVR32_ARCH_AT32AP_IO_H */
diff --git a/include/asm-avr32/arch-at32ap/smc.h b/include/asm-avr32/arch-at32ap/smc.h
index 3732b32..07152b7 100644
--- a/include/asm-avr32/arch-at32ap/smc.h
+++ b/include/asm-avr32/arch-at32ap/smc.h
@@ -48,10 +48,32 @@ struct smc_config {
 	unsigned int	nwe_controlled:1;
 
 	/*
+	 * 0: NWAIT is disabled
+	 * 1: Reserved
+	 * 2: NWAIT is frozen mode
+	 * 3: NWAIT in ready mode
+	 */
+	unsigned int	nwait_mode:2;
+
+	/*
 	 * 0: Byte select access type
 	 * 1: Byte write access type
 	 */
 	unsigned int	byte_write:1;
+
+	/*
+	 * Number of clock cycles before data is released after
+	 * the rising edge of the read controlling signal
+	 *
+	 * Total cycles from SMC is tdf_cycles + 1
+	 */
+	unsigned int	tdf_cycles:4;
+
+	/*
+	 * 0: TDF optimization disabled
+	 * 1: TDF optimization enabled
+	 */
+	unsigned int	tdf_mode:1;
 };
 
 extern int smc_set_configuration(int cs, const struct smc_config *config);
diff --git a/include/asm-avr32/arch-at32ap/time.h b/include/asm-avr32/arch-at32ap/time.h
new file mode 100644
index 0000000..cc8a434
--- /dev/null
+++ b/include/asm-avr32/arch-at32ap/time.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2007 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_AT32AP_TIME_H
+#define _ASM_AVR32_ARCH_AT32AP_TIME_H
+
+#include <linux/platform_device.h>
+
+extern struct irqaction timer_irqaction;
+extern struct platform_device at32_systc0_device;
+extern void local_timer_interrupt(int irq, void *dev_id);
+
+#define TIMER_BCR					0x000000c0
+#define TIMER_BCR_SYNC						 0
+#define TIMER_BMR					0x000000c4
+#define TIMER_BMR_TC0XC0S					 0
+#define TIMER_BMR_TC1XC1S					 2
+#define TIMER_BMR_TC2XC2S					 4
+#define TIMER_CCR					0x00000000
+#define TIMER_CCR_CLKDIS					 1
+#define TIMER_CCR_CLKEN						 0
+#define TIMER_CCR_SWTRG						 2
+#define TIMER_CMR					0x00000004
+#define TIMER_CMR_ABETRG					10
+#define TIMER_CMR_ACPA						16
+#define TIMER_CMR_ACPC						18
+#define TIMER_CMR_AEEVT						20
+#define TIMER_CMR_ASWTRG					22
+#define TIMER_CMR_BCPB						24
+#define TIMER_CMR_BCPC						26
+#define TIMER_CMR_BEEVT						28
+#define TIMER_CMR_BSWTRG					30
+#define TIMER_CMR_BURST						 4
+#define TIMER_CMR_CLKI						 3
+#define TIMER_CMR_CPCDIS					 7
+#define TIMER_CMR_CPCSTOP					 6
+#define TIMER_CMR_CPCTRG					14
+#define TIMER_CMR_EEVT						10
+#define TIMER_CMR_EEVTEDG					 8
+#define TIMER_CMR_ENETRG					12
+#define TIMER_CMR_ETRGEDG					 8
+#define TIMER_CMR_LDBDIS					 7
+#define TIMER_CMR_LDBSTOP					 6
+#define TIMER_CMR_LDRA						16
+#define TIMER_CMR_LDRB						18
+#define TIMER_CMR_TCCLKS					 0
+#define TIMER_CMR_WAVE						15
+#define TIMER_CMR_WAVSEL					13
+#define TIMER_CV					0x00000010
+#define TIMER_CV_CV						 0
+#define TIMER_IDR					0x00000028
+#define TIMER_IDR_COVFS						 0
+#define TIMER_IDR_CPAS						 2
+#define TIMER_IDR_CPBS						 3
+#define TIMER_IDR_CPCS						 4
+#define TIMER_IDR_ETRGS						 7
+#define TIMER_IDR_LDRAS						 5
+#define TIMER_IDR_LDRBS						 6
+#define TIMER_IDR_LOVRS						 1
+#define TIMER_IER					0x00000024
+#define TIMER_IER_COVFS						 0
+#define TIMER_IER_CPAS						 2
+#define TIMER_IER_CPBS						 3
+#define TIMER_IER_CPCS						 4
+#define TIMER_IER_ETRGS						 7
+#define TIMER_IER_LDRAS						 5
+#define TIMER_IER_LDRBS						 6
+#define TIMER_IER_LOVRS						 1
+#define TIMER_IMR					0x0000002c
+#define TIMER_IMR_COVFS						 0
+#define TIMER_IMR_CPAS						 2
+#define TIMER_IMR_CPBS						 3
+#define TIMER_IMR_CPCS						 4
+#define TIMER_IMR_ETRGS						 7
+#define TIMER_IMR_LDRAS						 5
+#define TIMER_IMR_LDRBS						 6
+#define TIMER_IMR_LOVRS						 1
+#define TIMER_RA					0x00000014
+#define TIMER_RA_RA						 0
+#define TIMER_RB					0x00000018
+#define TIMER_RB_RB						 0
+#define TIMER_RC					0x0000001c
+#define TIMER_RC_RC						 0
+#define TIMER_SR					0x00000020
+#define TIMER_SR_CLKSTA						16
+#define TIMER_SR_COVFS						 0
+#define TIMER_SR_CPAS						 2
+#define TIMER_SR_CPBS						 3
+#define TIMER_SR_CPCS						 4
+#define TIMER_SR_ETRGS						 7
+#define TIMER_SR_LDRAS						 5
+#define TIMER_SR_LDRBS						 6
+#define TIMER_SR_LOVRS						 1
+#define TIMER_SR_MTIOA						17
+#define TIMER_SR_MTIOB						18
+
+/* Bit manipulation macros */
+#define TIMER_BIT(name)		(1 << TIMER_##name)
+#define TIMER_BF(name,value)	((value) << TIMER_##name)
+
+/* Register access macros */
+#define timer_read(port,instance,reg) \
+	__raw_readl(port + (0x40 * instance) + TIMER_##reg)
+#define timer_write(port,instance,reg,value) \
+	__raw_writel((value), port + (0x40 * instance) + TIMER_##reg)
+
+#endif /* _ASM_AVR32_ARCH_AT32AP_TIME_H */
diff --git a/include/asm-avr32/atomic.h b/include/asm-avr32/atomic.h
index c40b603..b9c2548 100644
--- a/include/asm-avr32/atomic.h
+++ b/include/asm-avr32/atomic.h
@@ -173,7 +173,7 @@ static inline int atomic_sub_if_positive(int i, atomic_t *v)
 }
 
 #define atomic_xchg(v, new)	(xchg(&((v)->counter), new))
-#define atomic_cmpxchg(v, o, n)	((int)cmpxchg(&((v)->counter), (o), (n)))
+#define atomic_cmpxchg(v, o, n)	(cmpxchg(&((v)->counter), (o), (n)))
 
 #define atomic_sub(i, v)	(void)atomic_sub_return(i, v)
 #define atomic_add(i, v)	(void)atomic_add_return(i, v)
diff --git a/include/asm-avr32/bug.h b/include/asm-avr32/bug.h
index 521766b..afdcd79 100644
--- a/include/asm-avr32/bug.h
+++ b/include/asm-avr32/bug.h
@@ -18,27 +18,53 @@
 
 #ifdef CONFIG_DEBUG_BUGVERBOSE
 
-#define BUG()								\
-	do {								\
-		asm volatile(".hword	%0\n\t"				\
-			     ".hword	%1\n\t"				\
-			     ".long	%2"				\
-			     :						\
-			     : "n"(AVR32_BUG_OPCODE),			\
-			       "i"(__LINE__), "X"(__FILE__));		\
-	} while (0)
+#define _BUG_OR_WARN(flags)						\
+	asm volatile(							\
+		"1:	.hword	%0\n"					\
+		"	.section __bug_table,\"a\",@progbits\n"		\
+		"2:	.long	1b\n"					\
+		"	.long	%1\n"					\
+		"	.short	%2\n"					\
+		"	.short	%3\n"					\
+		"	.org	2b + %4\n"				\
+		"	.previous"					\
+		:							\
+		: "i"(AVR32_BUG_OPCODE), "i"(__FILE__),			\
+		  "i"(__LINE__), "i"(flags),				\
+		  "i"(sizeof(struct bug_entry)))
 
 #else
 
+#define _BUG_OR_WARN(flags)						\
+	asm volatile(							\
+		"1:	.hword	%0\n"					\
+		"	.section __bug_table,\"a\",@progbits\n"		\
+		"2:	.long	1b\n"					\
+		"	.short	%1\n"					\
+		"	.org	2b + %2\n"				\
+		"	.previous"					\
+		:							\
+		: "i"(AVR32_BUG_OPCODE), "i"(flags),			\
+		  "i"(sizeof(struct bug_entry)))
+
+#endif /* CONFIG_DEBUG_BUGVERBOSE */
+
 #define BUG()								\
 	do {								\
-		asm volatile(".hword	%0\n\t"				\
-			     : : "n"(AVR32_BUG_OPCODE));		\
+		_BUG_OR_WARN(0);					\
+		for (;;);						\
 	} while (0)
 
-#endif /* CONFIG_DEBUG_BUGVERBOSE */
+#define WARN_ON(condition)							\
+	({								\
+		typeof(condition) __ret_warn_on = (condition);		\
+		if (unlikely(__ret_warn_on))				\
+			_BUG_OR_WARN(BUGFLAG_WARNING);			\
+		unlikely(__ret_warn_on);				\
+	})
 
 #define HAVE_ARCH_BUG
+#define HAVE_ARCH_WARN_ON
 
 #endif /* CONFIG_BUG */
 
diff --git a/include/asm-avr32/dma-controller.h b/include/asm-avr32/dma-controller.h
new file mode 100644
index 0000000..56a4965
--- /dev/null
+++ b/include/asm-avr32/dma-controller.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2005-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_DMA_CONTROLLER_H
+#define __ASM_AVR32_DMA_CONTROLLER_H
+
+#include <linux/device.h>
+
+#define DMA_DIR_MEM_TO_MEM		0x0000
+#define DMA_DIR_MEM_TO_PERIPH		0x0001
+#define DMA_DIR_PERIPH_TO_MEM		0x0002
+#define DMA_DIR_PERIPH_TO_PERIPH	0x0003
+
+#define DMA_WIDTH_8BIT			0
+#define DMA_WIDTH_16BIT			1
+#define DMA_WIDTH_32BIT			2
+
+struct dma_request {
+	struct dma_controller *dmac;
+	struct list_head list;
+
+	unsigned short channel;
+
+	void (*xfer_complete)(struct dma_request *req);
+	void (*block_complete)(struct dma_request *req);
+	void (*error)(struct dma_request *req);
+};
+
+struct dma_request_sg {
+	struct dma_request req;
+
+	int nr_sg;
+	struct scatterlist *sg;
+	unsigned long block_size;
+	unsigned int nr_blocks;
+
+	dma_addr_t data_reg;
+	unsigned short periph_id;
+
+	unsigned char direction;
+	unsigned char width;
+};
+#define to_dma_request_sg(_req)				\
+	container_of(_req, struct dma_request_sg, req)
+
+struct dma_request_cyclic {
+	struct dma_request req;
+
+        int periods;
+	unsigned long buffer_size;
+
+        dma_addr_t buffer_start;
+	dma_addr_t data_reg;
+
+	unsigned short periph_id;
+	unsigned char direction;
+	unsigned char width;
+
+        void *dev_id;
+};
+#define to_dma_request_cyclic(_req)				\
+	container_of(_req, struct dma_request_cyclic, req)
+
+struct dma_request_memcpy {
+	struct dma_request req;
+
+	dma_addr_t src_addr;
+	unsigned int src_width;
+	unsigned int src_stride;
+
+	dma_addr_t dst_addr;
+	unsigned int dst_width;
+	unsigned int dst_stride;
+
+	size_t length;
+
+	unsigned short src_reverse:1;
+	unsigned short dst_reverse:1;
+};
+#define to_dma_request_memcpy(_req)				\
+	container_of(_req, struct dma_request_memcpy, req)
+
+struct dma_controller {
+	struct list_head list;
+	int id;
+	struct device *dev;
+
+	int (*alloc_channel)(struct dma_controller *dmac);
+	void (*release_channel)(struct dma_controller *dmac,
+				int channel);
+	int (*prepare_request_sg)(struct dma_controller *dmac,
+				  struct dma_request_sg *req);
+        int (*prepare_request_cyclic)(struct dma_controller *dmac,
+				      struct dma_request_cyclic *req);
+	int (*prepare_request_memcpy)(struct dma_controller *dmac,
+				      struct dma_request_memcpy *req);
+	int (*start_request)(struct dma_controller *dmac,
+			     unsigned int channel);
+	int (*stop_request)(struct dma_controller *dmac,
+                            unsigned int channel);
+        dma_addr_t (*get_current_pos)(struct dma_controller *dmac,
+                                      unsigned int channel);
+};
+
+static inline int
+dma_alloc_channel(struct dma_controller *dmac)
+{
+	return dmac->alloc_channel(dmac);
+}
+
+static inline void
+dma_release_channel(struct dma_controller *dmac, int chan)
+{
+	dmac->release_channel(dmac, chan);
+}
+
+static inline int
+dma_prepare_request_sg(struct dma_controller *dmac,
+		       struct dma_request_sg *req)
+{
+	return dmac->prepare_request_sg(dmac, req);
+}
+
+static inline int
+dma_prepare_request_cyclic(struct dma_controller *dmac,
+			   struct dma_request_cyclic *req)
+{
+	return dmac->prepare_request_cyclic(dmac, req);
+}
+
+static inline int
+dma_prepare_request_memcpy(struct dma_controller *dmac,
+			   struct dma_request_memcpy *req)
+{
+	return dmac->prepare_request_memcpy(dmac, req);
+}
+
+static inline int
+dma_start_request(struct dma_controller *dmac,
+		  unsigned int channel)
+{
+	return dmac->start_request(dmac, channel);
+}
+
+static inline int
+dma_stop_request(struct dma_controller *dmac,
+                 unsigned int channel)
+{
+	return dmac->stop_request(dmac, channel);
+}
+
+static inline dma_addr_t
+dma_get_current_pos(struct dma_controller *dmac,
+                    unsigned int channel)
+{
+	return dmac->get_current_pos(dmac, channel);
+}
+
+extern int register_dma_controller(struct dma_controller *dmac);
+extern struct dma_controller *find_dma_controller(int id);
+
+#endif /* __ASM_AVR32_DMA_CONTROLLER_H */
diff --git a/include/asm-avr32/io.h b/include/asm-avr32/io.h
index c08e810..e30d4b3 100644
--- a/include/asm-avr32/io.h
+++ b/include/asm-avr32/io.h
@@ -1,13 +1,15 @@
 #ifndef __ASM_AVR32_IO_H
 #define __ASM_AVR32_IO_H
 
+#include <linux/kernel.h>
 #include <linux/string.h>
-
-#ifdef __KERNEL__
+#include <linux/types.h>
 
 #include <asm/addrspace.h>
 #include <asm/byteorder.h>
 
+#include <asm/arch/io.h>
+
 /* virt_to_phys will only work when address is in P1 or P2 */
 static __inline__ unsigned long virt_to_phys(volatile void *address)
 {
@@ -36,104 +38,215 @@ extern void __raw_readsb(const void __iomem *addr, void *data, int bytelen);
 extern void __raw_readsw(const void __iomem *addr, void *data, int wordlen);
 extern void __raw_readsl(const void __iomem *addr, void *data, int longlen);
 
-static inline void writeb(unsigned char b, volatile void __iomem *addr)
+static inline void __raw_writeb(u8 v, volatile void __iomem *addr)
 {
-	*(volatile unsigned char __force *)addr = b;
+	*(volatile u8 __force *)addr = v;
 }
-static inline void writew(unsigned short b, volatile void __iomem *addr)
+static inline void __raw_writew(u16 v, volatile void __iomem *addr)
 {
-	*(volatile unsigned short __force *)addr = b;
+	*(volatile u16 __force *)addr = v;
 }
-static inline void writel(unsigned int b, volatile void __iomem *addr)
+static inline void __raw_writel(u32 v, volatile void __iomem *addr)
 {
-	*(volatile unsigned int __force *)addr = b;
+	*(volatile u32 __force *)addr = v;
 }
-#define __raw_writeb writeb
-#define __raw_writew writew
-#define __raw_writel writel
 
-static inline unsigned char readb(const volatile void __iomem *addr)
+static inline u8 __raw_readb(const volatile void __iomem *addr)
 {
-	return *(const volatile unsigned char __force *)addr;
+	return *(const volatile u8 __force *)addr;
 }
-static inline unsigned short readw(const volatile void __iomem *addr)
+static inline u16 __raw_readw(const volatile void __iomem *addr)
 {
-	return *(const volatile unsigned short __force *)addr;
+	return *(const volatile u16 __force *)addr;
 }
-static inline unsigned int readl(const volatile void __iomem *addr)
+static inline u32 __raw_readl(const volatile void __iomem *addr)
 {
-	return *(const volatile unsigned int __force *)addr;
+	return *(const volatile u32 __force *)addr;
+}
+
+/* Convert I/O port address to virtual address */
+#ifndef __io
+# define __io(p)	((void *)phys_to_uncached(p))
+#endif
+
+/*
+ * Not really sure about the best way to slow down I/O on
+ * AVR32. Defining it as a no-op until we have an actual test case.
+ */
+#define SLOW_DOWN_IO	do { } while (0)
+
+#define __BUILD_MEMORY_SINGLE(pfx, bwl, type)				\
+static inline void							\
+pfx##write##bwl(type val, volatile void __iomem *addr)			\
+{									\
+	volatile type *__addr;						\
+	type __val;							\
+									\
+	__addr = (void *)__swizzle_addr_##bwl((unsigned long)(addr));	\
+	__val = pfx##ioswab##bwl(__addr, val);				\
+									\
+	BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long));		\
+									\
+	*__addr = __val;						\
+}									\
+									\
+static inline type pfx##read##bwl(const volatile void __iomem *addr)	\
+{									\
+	volatile type *__addr;						\
+	type __val;							\
+									\
+	__addr = (void *)__swizzle_addr_##bwl((unsigned long)(addr));	\
+									\
+	BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long));		\
+									\
+	__val = *__addr;						\
+	return pfx##ioswab##bwl(__addr, __val);				\
+}
+
+#define __BUILD_IOPORT_SINGLE(pfx, bwl, type, p, slow)			\
+static inline void pfx##out##bwl##p(type val, unsigned long port)	\
+{									\
+	volatile type *__addr;						\
+	type __val;							\
+									\
+	__addr = __io(__swizzle_addr_##bwl(port));			\
+	__val = pfx##ioswab##bwl(__addr, val);				\
+									\
+	BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long));		\
+									\
+	*__addr = __val;						\
+	slow;								\
+}									\
+									\
+static inline type pfx##in##bwl##p(unsigned long port)			\
+{									\
+	volatile type *__addr;						\
+	type __val;							\
+									\
+	__addr = __io(__swizzle_addr_##bwl(port));			\
+									\
+	BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long));		\
+									\
+	__val = *__addr;						\
+	slow;								\
+									\
+	return pfx##ioswab##bwl(__addr, __val);				\
+}
+
+#define __BUILD_MEMORY_PFX(bus, bwl, type)				\
+	__BUILD_MEMORY_SINGLE(bus, bwl, type)
+
+#define BUILDIO_MEM(bwl, type)						\
+	__BUILD_MEMORY_PFX(, bwl, type)					\
+	__BUILD_MEMORY_PFX(__mem_, bwl, type)
+
+#define __BUILD_IOPORT_PFX(bus, bwl, type)				\
+	__BUILD_IOPORT_SINGLE(bus, bwl, type, ,)			\
+	__BUILD_IOPORT_SINGLE(bus, bwl, type, _p, SLOW_DOWN_IO)
+
+#define BUILDIO_IOPORT(bwl, type)					\
+	__BUILD_IOPORT_PFX(, bwl, type)					\
+	__BUILD_IOPORT_PFX(__mem_, bwl, type)
+
+BUILDIO_MEM(b, u8)
+BUILDIO_MEM(w, u16)
+BUILDIO_MEM(l, u32)
+
+BUILDIO_IOPORT(b, u8)
+BUILDIO_IOPORT(w, u16)
+BUILDIO_IOPORT(l, u32)
+
+#define readb_relaxed			readb
+#define readw_relaxed			readw
+#define readl_relaxed			readl
+
+#define __BUILD_MEMORY_STRING(bwl, type)				\
+static inline void writes##bwl(volatile void __iomem *addr,		\
+			       const void *data, unsigned int count)	\
+{									\
+	const type *__data = data;					\
+									\
+	while (count--)							\
+		__mem_write##bwl(*__data++, addr);			\
+}									\
+									\
+static inline void reads##bwl(const volatile void __iomem *addr,	\
+			      void *data, unsigned int count)		\
+{									\
+	type *__data = data;						\
+									\
+	while (count--)							\
+		*__data++ = __mem_read##bwl(addr);			\
 }
-#define __raw_readb readb
-#define __raw_readw readw
-#define __raw_readl readl
 
-#define writesb(p, d, l)	__raw_writesb((unsigned int)p, d, l)
-#define writesw(p, d, l)	__raw_writesw((unsigned int)p, d, l)
-#define writesl(p, d, l)	__raw_writesl((unsigned int)p, d, l)
+#define __BUILD_IOPORT_STRING(bwl, type)				\
+static inline void outs##bwl(unsigned long port, const void *data,	\
+			     unsigned int count)			\
+{									\
+	const type *__data = data;					\
+									\
+	while (count--)							\
+		__mem_out##bwl(*__data++, port);			\
+}									\
+									\
+static inline void ins##bwl(unsigned long port, void *data,		\
+			   unsigned int count)				\
+{									\
+	type *__data = data;						\
+									\
+	while (count--)							\
+		*__data++ = __mem_in##bwl(port);			\
+}
 
-#define readsb(p, d, l)		__raw_readsb((unsigned int)p, d, l)
-#define readsw(p, d, l)		__raw_readsw((unsigned int)p, d, l)
-#define readsl(p, d, l)		__raw_readsl((unsigned int)p, d, l)
+#define BUILDSTRING(bwl, type)						\
+	__BUILD_MEMORY_STRING(bwl, type)				\
+	__BUILD_IOPORT_STRING(bwl, type)
 
+BUILDSTRING(b, u8)
+BUILDSTRING(w, u16)
+BUILDSTRING(l, u32)
 
 /*
  * io{read,write}{8,16,32} macros in both le (for PCI style consumers) and native be
  */
 #ifndef ioread8
 
-#define ioread8(p)	({ unsigned int __v = __raw_readb(p); __v; })
+#define ioread8(p)		((unsigned int)readb(p))
 
-#define ioread16(p)	({ unsigned int __v = le16_to_cpu(__raw_readw(p)); __v; })
-#define ioread16be(p)	({ unsigned int __v = be16_to_cpu(__raw_readw(p)); __v; })
+#define ioread16(p)		((unsigned int)readw(p))
+#define ioread16be(p)		((unsigned int)__raw_readw(p))
 
-#define ioread32(p)	({ unsigned int __v = le32_to_cpu(__raw_readl(p)); __v; })
-#define ioread32be(p)	({ unsigned int __v = be32_to_cpu(__raw_readl(p)); __v; })
+#define ioread32(p)		((unsigned int)readl(p))
+#define ioread32be(p)		((unsigned int)__raw_readl(p))
 
-#define iowrite8(v,p)	__raw_writeb(v, p)
+#define iowrite8(v,p)		writeb(v, p)
 
-#define iowrite16(v,p)	__raw_writew(cpu_to_le16(v), p)
-#define iowrite16be(v,p)	__raw_writew(cpu_to_be16(v), p)
+#define iowrite16(v,p)		writew(v, p)
+#define iowrite16be(v,p)	__raw_writew(v, p)
 
-#define iowrite32(v,p)	__raw_writel(cpu_to_le32(v), p)
-#define iowrite32be(v,p)	__raw_writel(cpu_to_be32(v), p)
+#define iowrite32(v,p)		writel(v, p)
+#define iowrite32be(v,p)	__raw_writel(v, p)
 
-#define ioread8_rep(p,d,c)	__raw_readsb(p,d,c)
-#define ioread16_rep(p,d,c)	__raw_readsw(p,d,c)
-#define ioread32_rep(p,d,c)	__raw_readsl(p,d,c)
+#define ioread8_rep(p,d,c)	readsb(p,d,c)
+#define ioread16_rep(p,d,c)	readsw(p,d,c)
+#define ioread32_rep(p,d,c)	readsl(p,d,c)
 
-#define iowrite8_rep(p,s,c)	__raw_writesb(p,s,c)
-#define iowrite16_rep(p,s,c)	__raw_writesw(p,s,c)
-#define iowrite32_rep(p,s,c)	__raw_writesl(p,s,c)
+#define iowrite8_rep(p,s,c)	writesb(p,s,c)
+#define iowrite16_rep(p,s,c)	writesw(p,s,c)
+#define iowrite32_rep(p,s,c)	writesl(p,s,c)
 
 #endif
 
-
-/*
- * These two are only here because ALSA _thinks_ it needs them...
- */
 static inline void memcpy_fromio(void * to, const volatile void __iomem *from,
 				 unsigned long count)
 {
-	char *p = to;
-	while (count) {
-		count--;
-		*p = readb(from);
-		p++;
-		from++;
-	}
+	memcpy(to, (const void __force *)from, count);
 }
 
 static inline void  memcpy_toio(volatile void __iomem *to, const void * from,
 				unsigned long count)
 {
-	const char *p = from;
-	while (count) {
-		count--;
-		writeb(*p, to);
-		p++;
-		to++;
-	}
+	memcpy((void __force *)to, from, count);
 }
 
 static inline void memset_io(volatile void __iomem *addr, unsigned char val,
@@ -142,99 +255,8 @@ static inline void memset_io(volatile void __iomem *addr, unsigned char val,
 	memset((void __force *)addr, val, count);
 }
 
-/*
- * Bad read/write accesses...
- */
-extern void __readwrite_bug(const char *fn);
-
 #define IO_SPACE_LIMIT	0xffffffff
 
-/* Convert I/O port address to virtual address */
-#define __io(p)		((void __iomem *)phys_to_uncached(p))
-
-/*
- *  IO port access primitives
- *  -------------------------
- *
- * The AVR32 doesn't have special IO access instructions; all IO is memory
- * mapped. Note that these are defined to perform little endian accesses
- * only. Their primary purpose is to access PCI and ISA peripherals.
- *
- * Note that for a big endian machine, this implies that the following
- * big endian mode connectivity is in place.
- *
- * The machine specific io.h include defines __io to translate an "IO"
- * address to a memory address.
- *
- * Note that we prevent GCC re-ordering or caching values in expressions
- * by introducing sequence points into the in*() definitions.  Note that
- * __raw_* do not guarantee this behaviour.
- *
- * The {in,out}[bwl] macros are for emulating x86-style PCI/ISA IO space.
- */
-#define outb(v, p)		__raw_writeb(v, __io(p))
-#define outw(v, p)		__raw_writew(cpu_to_le16(v), __io(p))
-#define outl(v, p)		__raw_writel(cpu_to_le32(v), __io(p))
-
-#define inb(p)			__raw_readb(__io(p))
-#define inw(p)			le16_to_cpu(__raw_readw(__io(p)))
-#define inl(p)			le32_to_cpu(__raw_readl(__io(p)))
-
-static inline void __outsb(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		outb(*(u8 *)addr, port);
-		addr++;
-	}
-}
-
-static inline void __insb(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		*(u8 *)addr = inb(port);
-		addr++;
-	}
-}
-
-static inline void __outsw(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		outw(*(u16 *)addr, port);
-		addr += 2;
-	}
-}
-
-static inline void __insw(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		*(u16 *)addr = inw(port);
-		addr += 2;
-	}
-}
-
-static inline void __outsl(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		outl(*(u32 *)addr, port);
-		addr += 4;
-	}
-}
-
-static inline void __insl(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		*(u32 *)addr = inl(port);
-		addr += 4;
-	}
-}
-
-#define outsb(port, addr, count)	__outsb(port, addr, count)
-#define insb(port, addr, count)		__insb(port, addr, count)
-#define outsw(port, addr, count)	__outsw(port, addr, count)
-#define insw(port, addr, count)		__insw(port, addr, count)
-#define outsl(port, addr, count)	__outsl(port, addr, count)
-#define insl(port, addr, count)		__insl(port, addr, count)
-
 extern void __iomem *__ioremap(unsigned long offset, size_t size,
 			       unsigned long flags);
 extern void __iounmap(void __iomem *addr);
@@ -292,6 +314,4 @@ extern void __iounmap(void __iomem *addr);
  */
 #define xlate_dev_kmem_ptr(p)   p
 
-#endif /* __KERNEL__ */
-
 #endif /* __ASM_AVR32_IO_H */
diff --git a/include/asm-avr32/kdebug.h b/include/asm-avr32/kdebug.h
index f583b64..a8c2f5e 100644
--- a/include/asm-avr32/kdebug.h
+++ b/include/asm-avr32/kdebug.h
@@ -12,16 +12,12 @@ struct die_args {
 
 int register_die_notifier(struct notifier_block *nb);
 int unregister_die_notifier(struct notifier_block *nb);
-int register_page_fault_notifier(struct notifier_block *nb);
-int unregister_page_fault_notifier(struct notifier_block *nb);
 extern struct atomic_notifier_head avr32_die_chain;
 
 /* Grossly misnamed. */
 enum die_val {
-	DIE_FAULT,
 	DIE_BREAKPOINT,
 	DIE_SSTEP,
-	DIE_PAGE_FAULT,
 };
 
 static inline int notify_die(enum die_val val, struct pt_regs *regs,
@@ -35,4 +31,18 @@ static inline int notify_die(enum die_val val, struct pt_regs *regs,
 	return atomic_notifier_call_chain(&avr32_die_chain, val, &args);
 }
 
+/*
+ * These are only here because kprobes.c wants them to implement a
+ * blatant layering violation.  Will hopefully go away soon once all
+ * architectures are updated.
+ */
+static inline int register_page_fault_notifier(struct notifier_block *nb)
+{
+	return 0;
+}
+static inline int unregister_page_fault_notifier(struct notifier_block *nb)
+{
+	return 0;
+}
+
 #endif /* __ASM_AVR32_KDEBUG_H */
diff --git a/include/asm-avr32/kprobes.h b/include/asm-avr32/kprobes.h
index 09a5cbe..190a637 100644
--- a/include/asm-avr32/kprobes.h
+++ b/include/asm-avr32/kprobes.h
@@ -26,6 +26,7 @@ struct arch_specific_insn {
 	kprobe_opcode_t	insn[MAX_INSN_SIZE];
 };
 
+extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
 extern int kprobe_exceptions_notify(struct notifier_block *self,
 				    unsigned long val, void *data);
 
diff --git a/include/asm-avr32/pgtable.h b/include/asm-avr32/pgtable.h
index 6b8ca9d..f6cc2b0 100644
--- a/include/asm-avr32/pgtable.h
+++ b/include/asm-avr32/pgtable.h
@@ -394,10 +394,6 @@ typedef pte_t *pte_addr_t;
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)	\
 	remap_pfn_range(vma, vaddr, pfn, size, prot)
 
-#define MK_IOSPACE_PFN(space, pfn)	(pfn)
-#define GET_IOSPACE(pfn)		0
-#define GET_PFN(pfn)			(pfn)
-
 /* No page table caches to initialize (?) */
 #define pgtable_cache_init()	do { } while(0)
 
diff --git a/include/asm-avr32/processor.h b/include/asm-avr32/processor.h
index f691377..6a64833 100644
--- a/include/asm-avr32/processor.h
+++ b/include/asm-avr32/processor.h
@@ -40,6 +40,14 @@ enum tlb_config {
 	TLB_INVALID
 };
 
+#define AVR32_FEATURE_RMW	(1 << 0)
+#define AVR32_FEATURE_DSP	(1 << 1)
+#define AVR32_FEATURE_SIMD	(1 << 2)
+#define AVR32_FEATURE_OCD	(1 << 3)
+#define AVR32_FEATURE_PCTR	(1 << 4)
+#define AVR32_FEATURE_JAVA	(1 << 5)
+#define AVR32_FEATURE_FPU	(1 << 6)
+
 struct avr32_cpuinfo {
 	struct clk *clk;
 	unsigned long loops_per_jiffy;
@@ -48,6 +56,7 @@ struct avr32_cpuinfo {
 	unsigned short arch_revision;
 	unsigned short cpu_revision;
 	enum tlb_config tlb_config;
+	unsigned long features;
 
 	struct cache_info icache;
 	struct cache_info dcache;
@@ -125,10 +134,10 @@ extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
 #define thread_saved_pc(tsk)    ((tsk)->thread.cpu_context.pc)
 
 struct pt_regs;
-void show_trace(struct task_struct *task, unsigned long *stack,
-		struct pt_regs *regs);
-
 extern unsigned long get_wchan(struct task_struct *p);
+extern void show_regs_log_lvl(struct pt_regs *regs, const char *log_lvl);
+extern void show_stack_log_lvl(struct task_struct *tsk, unsigned long sp,
+			       struct pt_regs *regs, const char *log_lvl);
 
 #define KSTK_EIP(tsk)	((tsk)->thread.cpu_context.pc)
 #define KSTK_ESP(tsk)	((tsk)->thread.cpu_context.ksp)
diff --git a/include/asm-avr32/scatterlist.h b/include/asm-avr32/scatterlist.h
index bfe7d75..c6d5ce3 100644
--- a/include/asm-avr32/scatterlist.h
+++ b/include/asm-avr32/scatterlist.h
@@ -1,6 +1,8 @@
 #ifndef __ASM_AVR32_SCATTERLIST_H
 #define __ASM_AVR32_SCATTERLIST_H
 
+#include <asm/types.h>
+
 struct scatterlist {
     struct page		*page;
     unsigned int	offset;
diff --git a/include/asm-avr32/setup.h b/include/asm-avr32/setup.h
index 0a52242..b0828d4 100644
--- a/include/asm-avr32/setup.h
+++ b/include/asm-avr32/setup.h
@@ -110,7 +110,7 @@ struct tagtable {
 	int	(*parse)(struct tag *);
 };
 
-#define __tag __attribute_used__ __attribute__((__section__(".taglist")))
+#define __tag __attribute_used__ __attribute__((__section__(".taglist.init")))
 #define __tagtable(tag, fn)						\
 	static struct tagtable __tagtable_##fn __tag = { tag, fn }
 
@@ -124,19 +124,12 @@ struct tagtable {
 #define for_each_tag(t,base)						\
 	for (t = base; t->hdr.size; t = tag_next(t))
 
-extern struct tag_mem_range *mem_phys;
-extern struct tag_mem_range *mem_reserved;
-extern struct tag_mem_range *mem_ramdisk;
-
 extern struct tag *bootloader_tags;
 
-extern void setup_bootmem(void);
-extern void setup_processor(void);
-extern void board_setup_fbmem(unsigned long fbmem_start,
-			      unsigned long fbmem_size);
+extern resource_size_t fbmem_start;
+extern resource_size_t fbmem_size;
 
-/* Chip-specific hook to enable the use of SDRAM */
-void chip_enable_sdram(void);
+void setup_processor(void);
 
 #endif /* !__ASSEMBLY__ */
 
diff --git a/include/asm-avr32/sysreg.h b/include/asm-avr32/sysreg.h
index f91975f..c02bc83 100644
--- a/include/asm-avr32/sysreg.h
+++ b/include/asm-avr32/sysreg.h
@@ -7,326 +7,281 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#ifndef __ASM_AVR32_SYSREG_H__
-#define __ASM_AVR32_SYSREG_H__
+#ifndef __ASM_AVR32_SYSREG_H
+#define __ASM_AVR32_SYSREG_H
 
 /* sysreg register offsets */
-#define SYSREG_SR                               0x0000
-#define SYSREG_EVBA                             0x0004
-#define SYSREG_ACBA                             0x0008
-#define SYSREG_CPUCR                            0x000c
-#define SYSREG_ECR                              0x0010
-#define SYSREG_RSR_SUP                          0x0014
-#define SYSREG_RSR_INT0                         0x0018
-#define SYSREG_RSR_INT1                         0x001c
-#define SYSREG_RSR_INT2                         0x0020
-#define SYSREG_RSR_INT3                         0x0024
-#define SYSREG_RSR_EX                           0x0028
-#define SYSREG_RSR_NMI                          0x002c
-#define SYSREG_RSR_DBG                          0x0030
-#define SYSREG_RAR_SUP                          0x0034
-#define SYSREG_RAR_INT0                         0x0038
-#define SYSREG_RAR_INT1                         0x003c
-#define SYSREG_RAR_INT2                         0x0040
-#define SYSREG_RAR_INT3                         0x0044
-#define SYSREG_RAR_EX                           0x0048
-#define SYSREG_RAR_NMI                          0x004c
-#define SYSREG_RAR_DBG                          0x0050
-#define SYSREG_JECR                             0x0054
-#define SYSREG_JOSP                             0x0058
-#define SYSREG_JAVA_LV0                         0x005c
-#define SYSREG_JAVA_LV1                         0x0060
-#define SYSREG_JAVA_LV2                         0x0064
-#define SYSREG_JAVA_LV3                         0x0068
-#define SYSREG_JAVA_LV4                         0x006c
-#define SYSREG_JAVA_LV5                         0x0070
-#define SYSREG_JAVA_LV6                         0x0074
-#define SYSREG_JAVA_LV7                         0x0078
-#define SYSREG_JTBA                             0x007c
-#define SYSREG_JBCR                             0x0080
-#define SYSREG_CONFIG0                          0x0100
-#define SYSREG_CONFIG1                          0x0104
-#define SYSREG_COUNT                            0x0108
-#define SYSREG_COMPARE                          0x010c
-#define SYSREG_TLBEHI                           0x0110
-#define SYSREG_TLBELO                           0x0114
-#define SYSREG_PTBR                             0x0118
-#define SYSREG_TLBEAR                           0x011c
-#define SYSREG_MMUCR                            0x0120
-#define SYSREG_TLBARLO                          0x0124
-#define SYSREG_TLBARHI                          0x0128
-#define SYSREG_PCCNT                            0x012c
-#define SYSREG_PCNT0                            0x0130
-#define SYSREG_PCNT1                            0x0134
-#define SYSREG_PCCR                             0x0138
-#define SYSREG_BEAR                             0x013c
+#define SYSREG_SR				0x0000
+#define SYSREG_EVBA				0x0004
+#define SYSREG_ACBA				0x0008
+#define SYSREG_CPUCR				0x000c
+#define SYSREG_ECR				0x0010
+#define SYSREG_RSR_SUP				0x0014
+#define SYSREG_RSR_INT0				0x0018
+#define SYSREG_RSR_INT1				0x001c
+#define SYSREG_RSR_INT2				0x0020
+#define SYSREG_RSR_INT3				0x0024
+#define SYSREG_RSR_EX				0x0028
+#define SYSREG_RSR_NMI				0x002c
+#define SYSREG_RSR_DBG				0x0030
+#define SYSREG_RAR_SUP				0x0034
+#define SYSREG_RAR_INT0				0x0038
+#define SYSREG_RAR_INT1				0x003c
+#define SYSREG_RAR_INT2				0x0040
+#define SYSREG_RAR_INT3				0x0044
+#define SYSREG_RAR_EX				0x0048
+#define SYSREG_RAR_NMI				0x004c
+#define SYSREG_RAR_DBG				0x0050
+#define SYSREG_JECR				0x0054
+#define SYSREG_JOSP				0x0058
+#define SYSREG_JAVA_LV0				0x005c
+#define SYSREG_JAVA_LV1				0x0060
+#define SYSREG_JAVA_LV2				0x0064
+#define SYSREG_JAVA_LV3				0x0068
+#define SYSREG_JAVA_LV4				0x006c
+#define SYSREG_JAVA_LV5				0x0070
+#define SYSREG_JAVA_LV6				0x0074
+#define SYSREG_JAVA_LV7				0x0078
+#define SYSREG_JTBA				0x007c
+#define SYSREG_JBCR				0x0080
+#define SYSREG_CONFIG0				0x0100
+#define SYSREG_CONFIG1				0x0104
+#define SYSREG_COUNT				0x0108
+#define SYSREG_COMPARE				0x010c
+#define SYSREG_TLBEHI				0x0110
+#define SYSREG_TLBELO				0x0114
+#define SYSREG_PTBR				0x0118
+#define SYSREG_TLBEAR				0x011c
+#define SYSREG_MMUCR				0x0120
+#define SYSREG_TLBARLO				0x0124
+#define SYSREG_TLBARHI				0x0128
+#define SYSREG_PCCNT				0x012c
+#define SYSREG_PCNT0				0x0130
+#define SYSREG_PCNT1				0x0134
+#define SYSREG_PCCR				0x0138
+#define SYSREG_BEAR				0x013c
+#define SYSREG_SABAL				0x0300
+#define SYSREG_SABAH				0x0304
+#define SYSREG_SABD				0x0308
 
 /* Bitfields in SR */
-#define SYSREG_SR_C_OFFSET                      0
-#define SYSREG_SR_C_SIZE                        1
-#define SYSREG_Z_OFFSET                         1
-#define SYSREG_Z_SIZE                           1
-#define SYSREG_SR_N_OFFSET                      2
-#define SYSREG_SR_N_SIZE                        1
-#define SYSREG_SR_V_OFFSET                      3
-#define SYSREG_SR_V_SIZE                        1
-#define SYSREG_Q_OFFSET                         4
-#define SYSREG_Q_SIZE                           1
-#define SYSREG_GM_OFFSET                        16
-#define SYSREG_GM_SIZE                          1
-#define SYSREG_I0M_OFFSET                       17
-#define SYSREG_I0M_SIZE                         1
-#define SYSREG_I1M_OFFSET                       18
-#define SYSREG_I1M_SIZE                         1
-#define SYSREG_I2M_OFFSET                       19
-#define SYSREG_I2M_SIZE                         1
-#define SYSREG_I3M_OFFSET                       20
-#define SYSREG_I3M_SIZE                         1
-#define SYSREG_EM_OFFSET                        21
-#define SYSREG_EM_SIZE                          1
-#define SYSREG_M0_OFFSET                        22
-#define SYSREG_M0_SIZE                          1
-#define SYSREG_M1_OFFSET                        23
-#define SYSREG_M1_SIZE                          1
-#define SYSREG_M2_OFFSET                        24
-#define SYSREG_M2_SIZE                          1
-#define SYSREG_SR_D_OFFSET                      26
-#define SYSREG_SR_D_SIZE                        1
-#define SYSREG_DM_OFFSET                        27
-#define SYSREG_DM_SIZE                          1
-#define SYSREG_SR_J_OFFSET                      28
-#define SYSREG_SR_J_SIZE                        1
-#define SYSREG_R_OFFSET                         29
-#define SYSREG_R_SIZE                           1
-#define SYSREG_H_OFFSET                         30
-#define SYSREG_H_SIZE                           1
-
-/* Bitfields in EVBA */
-
-/* Bitfields in ACBA */
+#define SYSREG_SR_C_OFFSET			0
+#define SYSREG_SR_C_SIZE			1
+#define SYSREG_Z_OFFSET				1
+#define SYSREG_Z_SIZE				1
+#define SYSREG_SR_N_OFFSET			2
+#define SYSREG_SR_N_SIZE			1
+#define SYSREG_SR_V_OFFSET			3
+#define SYSREG_SR_V_SIZE			1
+#define SYSREG_Q_OFFSET				4
+#define SYSREG_Q_SIZE				1
+#define SYSREG_L_OFFSET				5
+#define SYSREG_L_SIZE				1
+#define SYSREG_T_OFFSET				14
+#define SYSREG_T_SIZE				1
+#define SYSREG_SR_R_OFFSET			15
+#define SYSREG_SR_R_SIZE			1
+#define SYSREG_GM_OFFSET			16
+#define SYSREG_GM_SIZE				1
+#define SYSREG_I0M_OFFSET			17
+#define SYSREG_I0M_SIZE				1
+#define SYSREG_I1M_OFFSET			18
+#define SYSREG_I1M_SIZE				1
+#define SYSREG_I2M_OFFSET			19
+#define SYSREG_I2M_SIZE				1
+#define SYSREG_I3M_OFFSET			20
+#define SYSREG_I3M_SIZE				1
+#define SYSREG_EM_OFFSET			21
+#define SYSREG_EM_SIZE				1
+#define SYSREG_M0_OFFSET			22
+#define SYSREG_M0_SIZE				1
+#define SYSREG_M1_OFFSET			23
+#define SYSREG_M1_SIZE				1
+#define SYSREG_M2_OFFSET			24
+#define SYSREG_M2_SIZE				1
+#define SYSREG_SR_D_OFFSET			26
+#define SYSREG_SR_D_SIZE			1
+#define SYSREG_DM_OFFSET			27
+#define SYSREG_DM_SIZE				1
+#define SYSREG_SR_J_OFFSET			28
+#define SYSREG_SR_J_SIZE			1
+#define SYSREG_H_OFFSET				29
+#define SYSREG_H_SIZE				1
 
 /* Bitfields in CPUCR */
-#define SYSREG_BI_OFFSET                        0
-#define SYSREG_BI_SIZE                          1
-#define SYSREG_BE_OFFSET                        1
-#define SYSREG_BE_SIZE                          1
-#define SYSREG_FE_OFFSET                        2
-#define SYSREG_FE_SIZE                          1
-#define SYSREG_RE_OFFSET                        3
-#define SYSREG_RE_SIZE                          1
-#define SYSREG_IBE_OFFSET                       4
-#define SYSREG_IBE_SIZE                         1
-#define SYSREG_IEE_OFFSET                       5
-#define SYSREG_IEE_SIZE                         1
-
-/* Bitfields in ECR */
-#define SYSREG_ECR_OFFSET                       0
-#define SYSREG_ECR_SIZE                         32
-
-/* Bitfields in RSR_SUP */
-
-/* Bitfields in RSR_INT0 */
-
-/* Bitfields in RSR_INT1 */
-
-/* Bitfields in RSR_INT2 */
-
-/* Bitfields in RSR_INT3 */
-
-/* Bitfields in RSR_EX */
-
-/* Bitfields in RSR_NMI */
-
-/* Bitfields in RSR_DBG */
-
-/* Bitfields in RAR_SUP */
-
-/* Bitfields in RAR_INT0 */
-
-/* Bitfields in RAR_INT1 */
-
-/* Bitfields in RAR_INT2 */
-
-/* Bitfields in RAR_INT3 */
-
-/* Bitfields in RAR_EX */
-
-/* Bitfields in RAR_NMI */
-
-/* Bitfields in RAR_DBG */
-
-/* Bitfields in JECR */
-
-/* Bitfields in JOSP */
-
-/* Bitfields in JAVA_LV0 */
-
-/* Bitfields in JAVA_LV1 */
-
-/* Bitfields in JAVA_LV2 */
-
-/* Bitfields in JAVA_LV3 */
-
-/* Bitfields in JAVA_LV4 */
-
-/* Bitfields in JAVA_LV5 */
-
-/* Bitfields in JAVA_LV6 */
-
-/* Bitfields in JAVA_LV7 */
-
-/* Bitfields in JTBA */
-
-/* Bitfields in JBCR */
+#define SYSREG_BI_OFFSET			0
+#define SYSREG_BI_SIZE				1
+#define SYSREG_BE_OFFSET			1
+#define SYSREG_BE_SIZE				1
+#define SYSREG_FE_OFFSET			2
+#define SYSREG_FE_SIZE				1
+#define SYSREG_RE_OFFSET			3
+#define SYSREG_RE_SIZE				1
+#define SYSREG_IBE_OFFSET			4
+#define SYSREG_IBE_SIZE				1
+#define SYSREG_IEE_OFFSET			5
+#define SYSREG_IEE_SIZE				1
 
 /* Bitfields in CONFIG0 */
-#define SYSREG_CONFIG0_D_OFFSET                 1
-#define SYSREG_CONFIG0_D_SIZE                   1
-#define SYSREG_CONFIG0_S_OFFSET                 2
-#define SYSREG_CONFIG0_S_SIZE                   1
-#define SYSREG_O_OFFSET                         3
-#define SYSREG_O_SIZE                           1
-#define SYSREG_P_OFFSET                         4
-#define SYSREG_P_SIZE                           1
-#define SYSREG_CONFIG0_J_OFFSET                 5
-#define SYSREG_CONFIG0_J_SIZE                   1
-#define SYSREG_F_OFFSET                         6
-#define SYSREG_F_SIZE                           1
-#define SYSREG_MMUT_OFFSET                      7
-#define SYSREG_MMUT_SIZE                        3
-#define SYSREG_AR_OFFSET                        10
-#define SYSREG_AR_SIZE                          3
-#define SYSREG_AT_OFFSET                        13
-#define SYSREG_AT_SIZE                          3
-#define SYSREG_PROCESSORREVISION_OFFSET         16
-#define SYSREG_PROCESSORREVISION_SIZE           8
-#define SYSREG_PROCESSORID_OFFSET               24
-#define SYSREG_PROCESSORID_SIZE                 8
+#define SYSREG_CONFIG0_R_OFFSET			0
+#define SYSREG_CONFIG0_R_SIZE			1
+#define SYSREG_CONFIG0_D_OFFSET			1
+#define SYSREG_CONFIG0_D_SIZE			1
+#define SYSREG_CONFIG0_S_OFFSET			2
+#define SYSREG_CONFIG0_S_SIZE			1
+#define SYSREG_CONFIG0_O_OFFSET			3
+#define SYSREG_CONFIG0_O_SIZE			1
+#define SYSREG_CONFIG0_P_OFFSET			4
+#define SYSREG_CONFIG0_P_SIZE			1
+#define SYSREG_CONFIG0_J_OFFSET			5
+#define SYSREG_CONFIG0_J_SIZE			1
+#define SYSREG_CONFIG0_F_OFFSET			6
+#define SYSREG_CONFIG0_F_SIZE			1
+#define SYSREG_MMUT_OFFSET			7
+#define SYSREG_MMUT_SIZE			3
+#define SYSREG_AR_OFFSET			10
+#define SYSREG_AR_SIZE				3
+#define SYSREG_AT_OFFSET			13
+#define SYSREG_AT_SIZE				3
+#define SYSREG_PROCESSORREVISION_OFFSET		16
+#define SYSREG_PROCESSORREVISION_SIZE		8
+#define SYSREG_PROCESSORID_OFFSET		24
+#define SYSREG_PROCESSORID_SIZE			8
 
 /* Bitfields in CONFIG1 */
-#define SYSREG_DASS_OFFSET                      0
-#define SYSREG_DASS_SIZE                        3
-#define SYSREG_DLSZ_OFFSET                      3
-#define SYSREG_DLSZ_SIZE                        3
-#define SYSREG_DSET_OFFSET                      6
-#define SYSREG_DSET_SIZE                        4
-#define SYSREG_IASS_OFFSET                      10
-#define SYSREG_IASS_SIZE                        2
-#define SYSREG_ILSZ_OFFSET                      13
-#define SYSREG_ILSZ_SIZE                        3
-#define SYSREG_ISET_OFFSET                      16
-#define SYSREG_ISET_SIZE                        4
-#define SYSREG_DMMUSZ_OFFSET                    20
-#define SYSREG_DMMUSZ_SIZE                      6
-#define SYSREG_IMMUSZ_OFFSET                    26
-#define SYSREG_IMMUSZ_SIZE                      6
-
-/* Bitfields in COUNT */
-
-/* Bitfields in COMPARE */
+#define SYSREG_DASS_OFFSET			0
+#define SYSREG_DASS_SIZE			3
+#define SYSREG_DLSZ_OFFSET			3
+#define SYSREG_DLSZ_SIZE			3
+#define SYSREG_DSET_OFFSET			6
+#define SYSREG_DSET_SIZE			4
+#define SYSREG_IASS_OFFSET			10
+#define SYSREG_IASS_SIZE			3
+#define SYSREG_ILSZ_OFFSET			13
+#define SYSREG_ILSZ_SIZE			3
+#define SYSREG_ISET_OFFSET			16
+#define SYSREG_ISET_SIZE			4
+#define SYSREG_DMMUSZ_OFFSET			20
+#define SYSREG_DMMUSZ_SIZE			6
+#define SYSREG_IMMUSZ_OFFSET			26
+#define SYSREG_IMMUSZ_SIZE			6
 
 /* Bitfields in TLBEHI */
-#define SYSREG_ASID_OFFSET                      0
-#define SYSREG_ASID_SIZE                        8
-#define SYSREG_TLBEHI_I_OFFSET                  8
-#define SYSREG_TLBEHI_I_SIZE                    1
-#define SYSREG_TLBEHI_V_OFFSET                  9
-#define SYSREG_TLBEHI_V_SIZE                    1
-#define SYSREG_VPN_OFFSET                       10
-#define SYSREG_VPN_SIZE                         22
+#define SYSREG_ASID_OFFSET			0
+#define SYSREG_ASID_SIZE			8
+#define SYSREG_TLBEHI_I_OFFSET			8
+#define SYSREG_TLBEHI_I_SIZE			1
+#define SYSREG_TLBEHI_V_OFFSET			9
+#define SYSREG_TLBEHI_V_SIZE			1
+#define SYSREG_VPN_OFFSET			10
+#define SYSREG_VPN_SIZE				22
 
 /* Bitfields in TLBELO */
-#define SYSREG_W_OFFSET                         0
-#define SYSREG_W_SIZE                           1
-#define SYSREG_TLBELO_D_OFFSET                  1
-#define SYSREG_TLBELO_D_SIZE                    1
-#define SYSREG_SZ_OFFSET                        2
-#define SYSREG_SZ_SIZE                          2
-#define SYSREG_AP_OFFSET                        4
-#define SYSREG_AP_SIZE                          3
-#define SYSREG_B_OFFSET                         7
-#define SYSREG_B_SIZE                           1
-#define SYSREG_G_OFFSET                         8
-#define SYSREG_G_SIZE                           1
-#define SYSREG_TLBELO_C_OFFSET                  9
-#define SYSREG_TLBELO_C_SIZE                    1
-#define SYSREG_PFN_OFFSET                       10
-#define SYSREG_PFN_SIZE                         22
-
-/* Bitfields in PTBR */
-
-/* Bitfields in TLBEAR */
+#define SYSREG_W_OFFSET				0
+#define SYSREG_W_SIZE				1
+#define SYSREG_TLBELO_D_OFFSET			1
+#define SYSREG_TLBELO_D_SIZE			1
+#define SYSREG_SZ_OFFSET			2
+#define SYSREG_SZ_SIZE				2
+#define SYSREG_AP_OFFSET			4
+#define SYSREG_AP_SIZE				3
+#define SYSREG_B_OFFSET				7
+#define SYSREG_B_SIZE				1
+#define SYSREG_G_OFFSET				8
+#define SYSREG_G_SIZE				1
+#define SYSREG_TLBELO_C_OFFSET			9
+#define SYSREG_TLBELO_C_SIZE			1
+#define SYSREG_PFN_OFFSET			10
+#define SYSREG_PFN_SIZE				22
 
 /* Bitfields in MMUCR */
-#define SYSREG_E_OFFSET                         0
-#define SYSREG_E_SIZE                           1
-#define SYSREG_M_OFFSET                         1
-#define SYSREG_M_SIZE                           1
-#define SYSREG_MMUCR_I_OFFSET                   2
-#define SYSREG_MMUCR_I_SIZE                     1
-#define SYSREG_MMUCR_N_OFFSET                   3
-#define SYSREG_MMUCR_N_SIZE                     1
-#define SYSREG_MMUCR_S_OFFSET                   4
-#define SYSREG_MMUCR_S_SIZE                     1
-#define SYSREG_DLA_OFFSET                       8
-#define SYSREG_DLA_SIZE                         6
-#define SYSREG_DRP_OFFSET                       14
-#define SYSREG_DRP_SIZE                         6
-#define SYSREG_ILA_OFFSET                       20
-#define SYSREG_ILA_SIZE                         6
-#define SYSREG_IRP_OFFSET                       26
-#define SYSREG_IRP_SIZE                         6
-
-/* Bitfields in TLBARLO */
-
-/* Bitfields in TLBARHI */
-
-/* Bitfields in PCCNT */
-
-/* Bitfields in PCNT0 */
-
-/* Bitfields in PCNT1 */
+#define SYSREG_E_OFFSET				0
+#define SYSREG_E_SIZE				1
+#define SYSREG_M_OFFSET				1
+#define SYSREG_M_SIZE				1
+#define SYSREG_MMUCR_I_OFFSET			2
+#define SYSREG_MMUCR_I_SIZE			1
+#define SYSREG_MMUCR_N_OFFSET			3
+#define SYSREG_MMUCR_N_SIZE			1
+#define SYSREG_MMUCR_S_OFFSET			4
+#define SYSREG_MMUCR_S_SIZE			1
+#define SYSREG_DLA_OFFSET			8
+#define SYSREG_DLA_SIZE				6
+#define SYSREG_DRP_OFFSET			14
+#define SYSREG_DRP_SIZE				6
+#define SYSREG_ILA_OFFSET			20
+#define SYSREG_ILA_SIZE				6
+#define SYSREG_IRP_OFFSET			26
+#define SYSREG_IRP_SIZE				6
 
 /* Bitfields in PCCR */
-
-/* Bitfields in BEAR */
+#define SYSREG_PCCR_R_OFFSET			1
+#define SYSREG_PCCR_R_SIZE			1
+#define SYSREG_PCCR_C_OFFSET			2
+#define SYSREG_PCCR_C_SIZE			1
+#define SYSREG_PCCR_S_OFFSET			3
+#define SYSREG_PCCR_S_SIZE			1
+#define SYSREG_IEC_OFFSET			4
+#define SYSREG_IEC_SIZE				1
+#define SYSREG_IE0_OFFSET			5
+#define SYSREG_IE0_SIZE				1
+#define SYSREG_IE1_OFFSET			6
+#define SYSREG_IE1_SIZE				1
+#define SYSREG_FC_OFFSET			8
+#define SYSREG_FC_SIZE				1
+#define SYSREG_F0_OFFSET			9
+#define SYSREG_F0_SIZE				1
+#define SYSREG_F1_OFFSET			10
+#define SYSREG_F1_SIZE				1
+#define SYSREG_CONF0_OFFSET			12
+#define SYSREG_CONF0_SIZE			6
+#define SYSREG_CONF1_OFFSET			18
+#define SYSREG_CONF1_SIZE			6
 
 /* Constants for ECR */
-#define ECR_UNRECOVERABLE                       0
-#define ECR_TLB_MULTIPLE                        1
-#define ECR_BUS_ERROR_WRITE                     2
-#define ECR_BUS_ERROR_READ                      3
-#define ECR_NMI                                 4
-#define ECR_ADDR_ALIGN_X                        5
-#define ECR_PROTECTION_X                        6
-#define ECR_DEBUG                               7
-#define ECR_ILLEGAL_OPCODE                      8
-#define ECR_UNIMPL_INSTRUCTION                  9
-#define ECR_PRIVILEGE_VIOLATION                 10
-#define ECR_FPE                                 11
-#define ECR_COPROC_ABSENT                       12
-#define ECR_ADDR_ALIGN_R                        13
-#define ECR_ADDR_ALIGN_W                        14
-#define ECR_PROTECTION_R                        15
-#define ECR_PROTECTION_W                        16
-#define ECR_DTLB_MODIFIED                       17
-#define ECR_TLB_MISS_X                          20
-#define ECR_TLB_MISS_R                          24
-#define ECR_TLB_MISS_W                          28
+#define ECR_UNRECOVERABLE			0
+#define ECR_TLB_MULTIPLE			1
+#define ECR_BUS_ERROR_WRITE			2
+#define ECR_BUS_ERROR_READ			3
+#define ECR_NMI					4
+#define ECR_ADDR_ALIGN_X			5
+#define ECR_PROTECTION_X			6
+#define ECR_DEBUG				7
+#define ECR_ILLEGAL_OPCODE			8
+#define ECR_UNIMPL_INSTRUCTION			9
+#define ECR_PRIVILEGE_VIOLATION			10
+#define ECR_FPE					11
+#define ECR_COPROC_ABSENT			12
+#define ECR_ADDR_ALIGN_R			13
+#define ECR_ADDR_ALIGN_W			14
+#define ECR_PROTECTION_R			15
+#define ECR_PROTECTION_W			16
+#define ECR_DTLB_MODIFIED			17
+#define ECR_TLB_MISS_X				20
+#define ECR_TLB_MISS_R				24
+#define ECR_TLB_MISS_W				28
 
 /* Bit manipulation macros */
-#define SYSREG_BIT(name)                        (1 << SYSREG_##name##_OFFSET)
-#define SYSREG_BF(name,value)                   (((value) & ((1 << SYSREG_##name##_SIZE) - 1)) << SYSREG_##name##_OFFSET)
-#define SYSREG_BFEXT(name,value)                (((value) >> SYSREG_##name##_OFFSET) & ((1 << SYSREG_##name##_SIZE) - 1))
-#define SYSREG_BFINS(name,value,old)            (((old) & ~(((1 << SYSREG_##name##_SIZE) - 1) << SYSREG_##name##_OFFSET)) | SYSREG_BF(name,value))
+#define SYSREG_BIT(name)				\
+	(1 << SYSREG_##name##_OFFSET)
+#define SYSREG_BF(name,value)				\
+	(((value) & ((1 << SYSREG_##name##_SIZE) - 1))	\
+	 << SYSREG_##name##_OFFSET)
+#define SYSREG_BFEXT(name,value)\
+	(((value) >> SYSREG_##name##_OFFSET)		\
+	 & ((1 << SYSREG_##name##_SIZE) - 1))
+#define SYSREG_BFINS(name,value,old)			\
+	(((old) & ~(((1 << SYSREG_##name##_SIZE) - 1)	\
+		    << SYSREG_##name##_OFFSET))		\
+	 | SYSREG_BF(name,value))
 
+/* Register access macros */
 #ifdef __CHECKER__
 extern unsigned long __builtin_mfsr(unsigned long reg);
 extern void __builtin_mtsr(unsigned long reg, unsigned long value);
 #endif
 
-/* Register access macros */
-#define sysreg_read(reg)                        __builtin_mfsr(SYSREG_##reg)
-#define sysreg_write(reg, value)                __builtin_mtsr(SYSREG_##reg, value)
+#define sysreg_read(reg)		__builtin_mfsr(SYSREG_##reg)
+#define sysreg_write(reg, value)	__builtin_mtsr(SYSREG_##reg, value)
 
-#endif /* __ASM_AVR32_SYSREG_H__ */
+#endif /* __ASM_AVR32_SYSREG_H */
diff --git a/include/asm-avr32/system.h b/include/asm-avr32/system.h
index ac59605..a8236ba 100644
--- a/include/asm-avr32/system.h
+++ b/include/asm-avr32/system.h
@@ -9,6 +9,7 @@
 #define __ASM_AVR32_SYSTEM_H
 
 #include <linux/compiler.h>
+#include <linux/linkage.h>
 #include <linux/types.h>
 
 #include <asm/ptrace.h>
@@ -140,15 +141,9 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
 				   sizeof(*(ptr))))
 
 struct pt_regs;
-extern void __die(const char *, struct pt_regs *, unsigned long,
-		  const char *, const char *, unsigned long);
-extern void __die_if_kernel(const char *, struct pt_regs *, unsigned long,
-			    const char *, const char *, unsigned long);
-
-#define die(msg, regs, err)					\
-	__die(msg, regs, err, __FILE__ ":", __FUNCTION__, __LINE__)
-#define die_if_kernel(msg, regs, err)					\
-	__die_if_kernel(msg, regs, err, __FILE__ ":", __FUNCTION__, __LINE__)
+void NORET_TYPE die(const char *str, struct pt_regs *regs, long err);
+void _exception(long signr, struct pt_regs *regs, int code,
+		unsigned long addr);
 
 #define arch_align_stack(x)	(x)
 
diff --git a/include/asm-avr32/thread_info.h b/include/asm-avr32/thread_info.h
index d1f5b35..a2e606d 100644
--- a/include/asm-avr32/thread_info.h
+++ b/include/asm-avr32/thread_info.h
@@ -83,6 +83,7 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_SINGLE_STEP		6	/* single step after next break */
 #define TIF_MEMDIE		7
 #define TIF_RESTORE_SIGMASK	8	/* restore signal mask in do_signal */
+#define TIF_CPU_GOING_TO_SLEEP	9	/* CPU is entering sleep 0 mode */
 #define TIF_USERSPACE		31      /* true if FS sets userspace */
 
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
@@ -94,6 +95,7 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_SINGLE_STEP	(1 << TIF_SINGLE_STEP)
 #define _TIF_MEMDIE		(1 << TIF_MEMDIE)
 #define _TIF_RESTORE_SIGMASK	(1 << TIF_RESTORE_SIGMASK)
+#define _TIF_CPU_GOING_TO_SLEEP (1 << TIF_CPU_GOING_TO_SLEEP)
 
 /* XXX: These two masks must never span more than 16 bits! */
 /* work to do on interrupt/exception return */
diff --git a/include/asm-avr32/uaccess.h b/include/asm-avr32/uaccess.h
index 74a679e..ed09239 100644
--- a/include/asm-avr32/uaccess.h
+++ b/include/asm-avr32/uaccess.h
@@ -181,24 +181,23 @@ extern int __put_user_bad(void);
 
 #define __get_user_nocheck(x, ptr, size)				\
 ({									\
-	typeof(*(ptr)) __gu_val = (typeof(*(ptr)) __force)0;		\
+	unsigned long __gu_val = 0;					\
 	int __gu_err = 0;						\
 									\
 	switch (size) {							\
 	case 1: __get_user_asm("ub", __gu_val, ptr, __gu_err); break;	\
 	case 2: __get_user_asm("uh", __gu_val, ptr, __gu_err); break;	\
 	case 4: __get_user_asm("w", __gu_val, ptr, __gu_err); break;	\
-	case 8: __get_user_asm("d", __gu_val, ptr, __gu_err); break;	\
 	default: __gu_err = __get_user_bad(); break;			\
 	}								\
 									\
-	x = __gu_val;							\
+	x = (typeof(*(ptr)))__gu_val;					\
 	__gu_err;							\
 })
 
 #define __get_user_check(x, ptr, size)					\
 ({									\
-	typeof(*(ptr)) __gu_val = (typeof(*(ptr)) __force)0;		\
+	unsigned long __gu_val = 0;					\
 	const typeof(*(ptr)) __user * __gu_addr = (ptr);		\
 	int __gu_err = 0;						\
 									\
@@ -216,10 +215,6 @@ extern int __put_user_bad(void);
 			__get_user_asm("w", __gu_val, __gu_addr,	\
 				       __gu_err);			\
 			break;						\
-		case 8:							\
-			__get_user_asm("d", __gu_val, __gu_addr,	\
-				       __gu_err);			\
-			break;						\
 		default:						\
 			__gu_err = __get_user_bad();			\
 			break;						\
@@ -227,7 +222,7 @@ extern int __put_user_bad(void);
 	} else {							\
 		__gu_err = -EFAULT;					\
 	}								\
-	x = __gu_val;							\
+	x = (typeof(*(ptr)))__gu_val;					\
 	__gu_err;							\
 })
 
diff --git a/include/asm-avr32/unaligned.h b/include/asm-avr32/unaligned.h
index 3042723..7913617 100644
--- a/include/asm-avr32/unaligned.h
+++ b/include/asm-avr32/unaligned.h
@@ -6,20 +6,31 @@
  * implementation.  The AVR32 AP implementation can handle unaligned
  * words, but halfwords must be halfword-aligned, and doublewords must
  * be word-aligned.
- *
- * TODO: Make all this CPU-specific and optimize.
  */
 
-#include <linux/string.h>
+#include <asm-generic/unaligned.h>
 
-/* Use memmove here, so gcc does not insert a __builtin_memcpy. */
+#ifdef CONFIG_CPU_AT32AP7000
 
+/* REVISIT calling memmove() may be smaller for 64-bit values ... */
+
+#undef get_unaligned
 #define get_unaligned(ptr) \
-  ({ __typeof__(*(ptr)) __tmp; memmove(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })
+	___get_unaligned(ptr, sizeof((*ptr)))
+#define ___get_unaligned(ptr, size) \
+	((size == 4) ? *(ptr) : __get_unaligned(ptr, size))
+
+#undef put_unaligned
+#define put_unaligned(val, ptr) \
+	___put_unaligned((__u64)(val), ptr, sizeof((*ptr)))
+#define ___put_unaligned(val, ptr, size)		\
+do {							\
+	if (size == 4)					\
+		*(ptr) = (val);				\
+	else						\
+		__put_unaligned(val, ptr, size);	\
+} while (0)
 
-#define put_unaligned(val, ptr)				\
-  ({ __typeof__(*(ptr)) __tmp = (val);			\
-     memmove((ptr), &__tmp, sizeof(*(ptr)));		\
-     (void)0; })
+#endif
 
 #endif /* __ASM_AVR32_UNALIGNED_H */
diff --git a/include/asm-frv/pgtable.h b/include/asm-frv/pgtable.h
index 8a05aa1..2687c77 100644
--- a/include/asm-frv/pgtable.h
+++ b/include/asm-frv/pgtable.h
@@ -509,10 +509,6 @@ static inline int pte_file(pte_t pte)
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
 		remap_pfn_range(vma, vaddr, pfn, size, prot)
 
-#define MK_IOSPACE_PFN(space, pfn)	(pfn)
-#define GET_IOSPACE(pfn)		0
-#define GET_PFN(pfn)			(pfn)
-
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
diff --git a/include/asm-frv/scatterlist.h b/include/asm-frv/scatterlist.h
index fb38fd3..8e827fa 100644
--- a/include/asm-frv/scatterlist.h
+++ b/include/asm-frv/scatterlist.h
@@ -1,6 +1,8 @@
 #ifndef _ASM_SCATTERLIST_H
 #define _ASM_SCATTERLIST_H
 
+#include <asm/types.h>
+
 /*
  * Drivers must set either ->address or (preferred) ->page and ->offset
  * to indicate where data must be transferred to/from.
diff --git a/include/asm-h8300/pgtable.h b/include/asm-h8300/pgtable.h
index 8b7c685..170ea02 100644
--- a/include/asm-h8300/pgtable.h
+++ b/include/asm-h8300/pgtable.h
@@ -55,10 +55,6 @@ extern int is_in_rom(unsigned long);
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
 		remap_pfn_range(vma, vaddr, pfn, size, prot)
 
-#define MK_IOSPACE_PFN(space, pfn)	(pfn)
-#define GET_IOSPACE(pfn)		0
-#define GET_PFN(pfn)			(pfn)
-
 /*
  * All 32bit addresses are effectively valid for vmalloc...
  * Sort of meaningless for non-VM targets.
diff --git a/include/asm-h8300/scatterlist.h b/include/asm-h8300/scatterlist.h
index 7627f0c..985fdf5 100644
--- a/include/asm-h8300/scatterlist.h
+++ b/include/asm-h8300/scatterlist.h
@@ -1,6 +1,8 @@
 #ifndef _H8300_SCATTERLIST_H
 #define _H8300_SCATTERLIST_H
 
+#include <asm/types.h>
+
 struct scatterlist {
 	struct page	*page;
 	unsigned int	offset;
diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h
index c3b58d4..994cf30 100644
--- a/include/asm-i386/pgtable.h
+++ b/include/asm-i386/pgtable.h
@@ -519,10 +519,6 @@ do {									\
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
 		remap_pfn_range(vma, vaddr, pfn, size, prot)
 
-#define MK_IOSPACE_PFN(space, pfn)	(pfn)
-#define GET_IOSPACE(pfn)		0
-#define GET_PFN(pfn)			(pfn)
-
 #include <asm-generic/pgtable.h>
 
 #endif /* _I386_PGTABLE_H */
diff --git a/include/asm-i386/scatterlist.h b/include/asm-i386/scatterlist.h
index 55d6c95..d7e45a8 100644
--- a/include/asm-i386/scatterlist.h
+++ b/include/asm-i386/scatterlist.h
@@ -1,6 +1,8 @@
 #ifndef _I386_SCATTERLIST_H
 #define _I386_SCATTERLIST_H
 
+#include <asm/types.h>
+
 struct scatterlist {
     struct page		*page;
     unsigned int	offset;
diff --git a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h
index 5531827..670b706 100644
--- a/include/asm-ia64/pgtable.h
+++ b/include/asm-ia64/pgtable.h
@@ -485,10 +485,6 @@ extern void paging_init (void);
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
 		remap_pfn_range(vma, vaddr, pfn, size, prot)
 
-#define MK_IOSPACE_PFN(space, pfn)	(pfn)
-#define GET_IOSPACE(pfn)		0
-#define GET_PFN(pfn)			(pfn)
-
 /*
  * ZERO_PAGE is a global shared page that is always zero: used
  * for zero-mapped memory areas etc..
diff --git a/include/asm-ia64/scatterlist.h b/include/asm-ia64/scatterlist.h
index 9dbea88..a452ea2 100644
--- a/include/asm-ia64/scatterlist.h
+++ b/include/asm-ia64/scatterlist.h
@@ -6,6 +6,8 @@
  *	David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co
  */
 
+#include <asm/types.h>
+
 struct scatterlist {
 	struct page *page;
 	unsigned int offset;
diff --git a/include/asm-m32r/pgtable.h b/include/asm-m32r/pgtable.h
index 1c15ba7..8b2a2f1 100644
--- a/include/asm-m32r/pgtable.h
+++ b/include/asm-m32r/pgtable.h
@@ -381,10 +381,6 @@ static inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)	\
 		remap_pfn_range(vma, vaddr, pfn, size, prot)
 
-#define MK_IOSPACE_PFN(space, pfn)	(pfn)
-#define GET_IOSPACE(pfn)		0
-#define GET_PFN(pfn)			(pfn)
-
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
diff --git a/include/asm-m32r/scatterlist.h b/include/asm-m32r/scatterlist.h
index c2de96c..352415f 100644
--- a/include/asm-m32r/scatterlist.h
+++ b/include/asm-m32r/scatterlist.h
@@ -1,6 +1,8 @@
 #ifndef _ASM_M32R_SCATTERLIST_H
 #define _ASM_M32R_SCATTERLIST_H
 
+#include <asm/types.h>
+
 struct scatterlist {
     char *  address;    /* Location data is to be transferred to, NULL for
                          * highmem page */
diff --git a/include/asm-m68k/pgtable.h b/include/asm-m68k/pgtable.h
index f3aa053..555b87a 100644
--- a/include/asm-m68k/pgtable.h
+++ b/include/asm-m68k/pgtable.h
@@ -143,10 +143,6 @@ static inline void update_mmu_cache(struct vm_area_struct *vma,
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
 		remap_pfn_range(vma, vaddr, pfn, size, prot)
 
-#define MK_IOSPACE_PFN(space, pfn)	(pfn)
-#define GET_IOSPACE(pfn)		0
-#define GET_PFN(pfn)			(pfn)
-
 /* MMU-specific headers */
 
 #ifdef CONFIG_SUN3
diff --git a/include/asm-m68knommu/pgtable.h b/include/asm-m68knommu/pgtable.h
index 549ad23..9dfbbc2 100644
--- a/include/asm-m68knommu/pgtable.h
+++ b/include/asm-m68knommu/pgtable.h
@@ -59,10 +59,6 @@ extern int is_in_rom(unsigned long);
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
 		remap_pfn_range(vma, vaddr, pfn, size, prot)
 
-#define MK_IOSPACE_PFN(space, pfn)	(pfn)
-#define GET_IOSPACE(pfn)		0
-#define GET_PFN(pfn)			(pfn)
-
 /*
  * All 32bit addresses are effectively valid for vmalloc...
  * Sort of meaningless for non-VM targets.
diff --git a/include/asm-m68knommu/scatterlist.h b/include/asm-m68knommu/scatterlist.h
index 2085d6f..4da79d3 100644
--- a/include/asm-m68knommu/scatterlist.h
+++ b/include/asm-m68knommu/scatterlist.h
@@ -2,6 +2,7 @@
 #define _M68KNOMMU_SCATTERLIST_H
 
 #include <linux/mm.h>
+#include <asm/types.h>
 
 struct scatterlist {
 	struct page	*page;
diff --git a/include/asm-mips/pgtable.h b/include/asm-mips/pgtable.h
index 0d3295f..27d77d9 100644
--- a/include/asm-mips/pgtable.h
+++ b/include/asm-mips/pgtable.h
@@ -387,10 +387,6 @@ static inline int io_remap_pfn_range(struct vm_area_struct *vma,
 		remap_pfn_range(vma, vaddr, pfn, size, prot)
 #endif
 
-#define MK_IOSPACE_PFN(space, pfn)	(pfn)
-#define GET_IOSPACE(pfn)		0
-#define GET_PFN(pfn)			(pfn)
-
 #include <asm-generic/pgtable.h>
 
 /*
diff --git a/include/asm-mips/scatterlist.h b/include/asm-mips/scatterlist.h
index 2263470..7af104c 100644
--- a/include/asm-mips/scatterlist.h
+++ b/include/asm-mips/scatterlist.h
@@ -1,6 +1,8 @@
 #ifndef __ASM_SCATTERLIST_H
 #define __ASM_SCATTERLIST_H
 
+#include <asm/types.h>
+
 struct scatterlist {
 	struct page *	page;
 	unsigned int	offset;
diff --git a/include/asm-parisc/pgtable.h b/include/asm-parisc/pgtable.h
index d7e1b10..beb2adb 100644
--- a/include/asm-parisc/pgtable.h
+++ b/include/asm-parisc/pgtable.h
@@ -528,10 +528,6 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
 
 #define pgprot_noncached(prot) __pgprot(pgprot_val(prot) | _PAGE_NO_CACHE)
 
-#define MK_IOSPACE_PFN(space, pfn)	(pfn)
-#define GET_IOSPACE(pfn)		0
-#define GET_PFN(pfn)			(pfn)
-
 /* We provide our own get_unmapped_area to provide cache coherency */
 
 #define HAVE_ARCH_UNMAPPED_AREA
diff --git a/include/asm-parisc/scatterlist.h b/include/asm-parisc/scatterlist.h
index 236c1d0..e7211c7 100644
--- a/include/asm-parisc/scatterlist.h
+++ b/include/asm-parisc/scatterlist.h
@@ -2,6 +2,7 @@
 #define _ASM_PARISC_SCATTERLIST_H
 
 #include <asm/page.h>
+#include <asm/types.h>
 
 struct scatterlist {
 	struct page *page;
diff --git a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h
index b1fdbf4..bed452d 100644
--- a/include/asm-ppc/pgtable.h
+++ b/include/asm-ppc/pgtable.h
@@ -827,10 +827,6 @@ static inline int io_remap_pfn_range(struct vm_area_struct *vma,
 		remap_pfn_range(vma, vaddr, pfn, size, prot)
 #endif
 
-#define MK_IOSPACE_PFN(space, pfn)	(pfn)
-#define GET_IOSPACE(pfn)		0
-#define GET_PFN(pfn)			(pfn)
-
 /*
  * No page table caches to initialise
  */
diff --git a/include/asm-sh/pgtable.h b/include/asm-sh/pgtable.h
index 184d7fc..5b523c7 100644
--- a/include/asm-sh/pgtable.h
+++ b/include/asm-sh/pgtable.h
@@ -568,10 +568,6 @@ typedef pte_t *pte_addr_t;
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
 		remap_pfn_range(vma, vaddr, pfn, size, prot)
 
-#define MK_IOSPACE_PFN(space, pfn)	(pfn)
-#define GET_IOSPACE(pfn)		0
-#define GET_PFN(pfn)			(pfn)
-
 struct mm_struct;
 
 /*
diff --git a/include/asm-sh/scatterlist.h b/include/asm-sh/scatterlist.h
index d19e7cd..b9ae53c 100644
--- a/include/asm-sh/scatterlist.h
+++ b/include/asm-sh/scatterlist.h
@@ -1,6 +1,8 @@
 #ifndef __ASM_SH_SCATTERLIST_H
 #define __ASM_SH_SCATTERLIST_H
 
+#include <asm/types.h>
+
 struct scatterlist {
     struct page * page; /* Location for highmem page, if any */
     unsigned int offset;/* for highmem, page offset */
diff --git a/include/asm-sh64/pgtable.h b/include/asm-sh64/pgtable.h
index 6b97c4c..b875482 100644
--- a/include/asm-sh64/pgtable.h
+++ b/include/asm-sh64/pgtable.h
@@ -485,10 +485,6 @@ extern void update_mmu_cache(struct vm_area_struct * vma,
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
 		remap_pfn_range(vma, vaddr, pfn, size, prot)
 
-#define MK_IOSPACE_PFN(space, pfn)	(pfn)
-#define GET_IOSPACE(pfn)		0
-#define GET_PFN(pfn)			(pfn)
-
 #endif /* !__ASSEMBLY__ */
 
 /*
diff --git a/include/asm-sh64/scatterlist.h b/include/asm-sh64/scatterlist.h
index 5d8fa32..1c723f2 100644
--- a/include/asm-sh64/scatterlist.h
+++ b/include/asm-sh64/scatterlist.h
@@ -11,6 +11,8 @@
 #ifndef __ASM_SH64_SCATTERLIST_H
 #define __ASM_SH64_SCATTERLIST_H
 
+#include <asm/types.h>
+
 struct scatterlist {
     struct page * page; /* Location for highmem page, if any */
     unsigned int offset;/* for highmem, page offset */
diff --git a/include/asm-sparc64/scatterlist.h b/include/asm-sparc64/scatterlist.h
index ec4f3c6..048fdb4 100644
--- a/include/asm-sparc64/scatterlist.h
+++ b/include/asm-sparc64/scatterlist.h
@@ -3,6 +3,7 @@
 #define _SPARC64_SCATTERLIST_H
 
 #include <asm/page.h>
+#include <asm/types.h>
 
 struct scatterlist {
 	struct page	*page;
diff --git a/include/asm-v850/scatterlist.h b/include/asm-v850/scatterlist.h
index af1cba6..56f4029 100644
--- a/include/asm-v850/scatterlist.h
+++ b/include/asm-v850/scatterlist.h
@@ -14,6 +14,8 @@
 #ifndef __V850_SCATTERLIST_H__
 #define __V850_SCATTERLIST_H__
 
+#include <asm/types.h>
+
 struct scatterlist {
 	struct page	*page;
 	unsigned	offset;
diff --git a/include/asm-x86_64/pgtable.h b/include/asm-x86_64/pgtable.h
index 730bd60..1eb1043 100644
--- a/include/asm-x86_64/pgtable.h
+++ b/include/asm-x86_64/pgtable.h
@@ -413,10 +413,6 @@ extern int kern_addr_valid(unsigned long addr);
 #define io_remap_pfn_range(vma, vaddr, pfn, size, prot)		\
 		remap_pfn_range(vma, vaddr, pfn, size, prot)
 
-#define MK_IOSPACE_PFN(space, pfn)	(pfn)
-#define GET_IOSPACE(pfn)		0
-#define GET_PFN(pfn)			(pfn)
-
 #define HAVE_ARCH_UNMAPPED_AREA
 
 #define pgtable_cache_init()   do { } while (0)
diff --git a/include/asm-x86_64/scatterlist.h b/include/asm-x86_64/scatterlist.h
index 49d89f8..eaf7ada 100644
--- a/include/asm-x86_64/scatterlist.h
+++ b/include/asm-x86_64/scatterlist.h
@@ -1,6 +1,8 @@
 #ifndef _X8664_SCATTERLIST_H
 #define _X8664_SCATTERLIST_H
 
+#include <asm/types.h>
+
 struct scatterlist {
     struct page		*page;
     unsigned int	offset;
diff --git a/include/asm-xtensa/scatterlist.h b/include/asm-xtensa/scatterlist.h
index 38a2b9a..ca337a2 100644
--- a/include/asm-xtensa/scatterlist.h
+++ b/include/asm-xtensa/scatterlist.h
@@ -11,6 +11,8 @@
 #ifndef _XTENSA_SCATTERLIST_H
 #define _XTENSA_SCATTERLIST_H
 
+#include <asm/types.h>
+
 struct scatterlist {
 	struct page 	*page;
 	unsigned int	offset;
diff --git a/include/linux/fb.h b/include/linux/fb.h
index be913ec..deb2365 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -833,7 +833,7 @@ struct fb_info {
 #define fb_writeq sbus_writeq
 #define fb_memset sbus_memset_io
 
-#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || (defined(__sh__) && !defined(__SH5__)) || defined(__powerpc__)
+#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || (defined(__sh__) && !defined(__SH5__)) || defined(__powerpc__) || defined(__avr32__)
 
 #define fb_readb __raw_readb
 #define fb_readw __raw_readw
diff --git a/include/linux/gpio_mouse.h b/include/linux/gpio_mouse.h
new file mode 100644
index 0000000..7796683
--- /dev/null
+++ b/include/linux/gpio_mouse.h
@@ -0,0 +1,47 @@
+/*
+ * Driver for simulating a mouse on GPIO lines.
+ *
+ * Copyright (C) 2007 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 _GPIO_MOUSE_H
+#define _GPIO_MOUSE_H
+
+#define GPIO_MOUSE_POLARITY_ACT_HIGH	0x00
+#define GPIO_MOUSE_POLARITY_ACT_LOW	0x01
+
+/**
+ * struct gpio_mouse_platform_data
+ * @scan_ms: integer in ms specifying the scan periode.
+ * @polarity: Pin polarity, active high or low.
+ * @up: GPIO line for up value.
+ * @down: GPIO line for down value.
+ * @left: GPIO line for left value.
+ * @right: GPIO line for right value.
+ * @bleft: GPIO line for left button.
+ * @bright: GPIO line for right button.
+ * @bmiddle: GPIO line for middle button.
+ *
+ * This struct must be added to the platform_device in the board code. It is
+ * used by the gpio_mouse driver to setup GPIO lines, calculate mouse movement
+ * and have a reference to the timer used for scanning.
+ */
+struct gpio_mouse_platform_data {
+	int scan_ms;
+	int polarity;
+
+	int up;
+	int down;
+	int left;
+	int right;
+
+	int bleft;
+	int bmiddle;
+	int bright;
+};
+
+#endif /* _GPIO_MOUSE_H */
diff --git a/include/linux/i2c-gpio.h b/include/linux/i2c-gpio.h
new file mode 100644
index 0000000..c1bcb1f
--- /dev/null
+++ b/include/linux/i2c-gpio.h
@@ -0,0 +1,38 @@
+/*
+ * i2c-gpio interface to platform code
+ *
+ * Copyright (C) 2007 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 _LINUX_I2C_GPIO_H
+#define _LINUX_I2C_GPIO_H
+
+/**
+ * struct i2c_gpio_platform_data - Platform-dependent data for i2c-gpio
+ * @sda_pin: GPIO pin ID to use for SDA
+ * @scl_pin: GPIO pin ID to use for SCL
+ * @udelay: signal toggle delay. SCL frequency is (500 / udelay) kHz
+ * @timeout: clock stretching timeout in jiffies. If the slave keeps
+ *	SCL low for longer than this, the transfer will time out.
+ * @sda_is_open_drain: SDA is configured as open drain, i.e. the pin
+ *	isn't actively driven high when setting the output value high.
+ *	gpio_get_value() must return the actual pin state even if the
+ *	pin is configured as an output.
+ * @scl_is_open_drain: SCL is set up as open drain. Same requirements
+ *	as for sda_is_open_drain apply.
+ * @scl_is_output_only: SCL output drivers cannot be turned off.
+ */
+struct i2c_gpio_platform_data {
+	unsigned int	sda_pin;
+	unsigned int	scl_pin;
+	int		udelay;
+	int		timeout;
+	unsigned int	sda_is_open_drain:1;
+	unsigned int	scl_is_open_drain:1;
+	unsigned int	scl_is_output_only:1;
+};
+
+#endif /* _LINUX_I2C_GPIO_H */
diff --git a/include/linux/spi/at73c213.h b/include/linux/spi/at73c213.h
new file mode 100644
index 0000000..44ebe7d
--- /dev/null
+++ b/include/linux/spi/at73c213.h
@@ -0,0 +1,26 @@
+/*
+ * Board-specific data used to set up AT73c213 audio DAC driver.
+ */
+
+struct at73c213_board_info {
+
+	/* This identifies a clock suitable for clk_get(NULL, dac_clk).
+	 * One might expect something like clk_get(&spidev->dev, "dac") to
+	 * work, but current clock framework implementations don't support
+	 * association of such clocks with non-core (e.g. SPI) devices.
+	 */
+	char	dac_clk[8];
+
+	/* SPI is used only for the control interface.  Data is streamed
+	 * using "I2S" formats through a different interface, with its own
+	 * driver and associated resources (registers, irq, clock).
+	 */
+	int	i2s_dev;
+
+	/* this name is seen by userspace tools */
+	char	shortname[32];
+
+	/* REVISIT should target bitrate be provided here?
+	 * It can not be provided here, as it has to be calculated when probed
+	 */
+};
diff --git a/include/linux/ssc.h b/include/linux/ssc.h
new file mode 100644
index 0000000..9705e4a
--- /dev/null
+++ b/include/linux/ssc.h
@@ -0,0 +1,355 @@
+#ifndef __INCLUDE_ATMEL_SSC_H
+#define __INCLUDE_ATMEL_SSC_H
+
+#include <linux/platform_device.h>
+#include <asm/irq.h>
+
+#define ATMEL_SSC_MODE_I2S_MASTER	0x00000001
+#define ATMEL_SSC_MODE_I2S_SLAVE	0x00000002
+#define ATMEL_SSC_MODE_SPI_MASTER	0x00000003
+
+#define ATMEL_SSC_SPI_MODE0	0	/* SPI: CPOL = 0, CPHA = 1 */
+#define ATMEL_SSC_SPI_MODE1	1	/* SPI: CPOL = 0, CHPA = 0 */
+#define ATMEL_SSC_SPI_MODE2	2	/* SPI: CPOL = 1, CPHA = 1 */
+#define ATMEL_SSC_SPI_MODE3	3	/* SPI: CPOL = 1, CPHA = 0 */
+
+struct ssc_device {
+	void __iomem		*regs;
+	struct platform_device	*pdev;
+	struct clk		*clk;
+	char			name[6];
+	int			user;
+	int			irq;
+};
+
+struct ssc_mode {
+	unsigned int	mode;
+	unsigned int	bauddiv;
+	unsigned int	data_length;
+	unsigned int	ssc_rxtx;
+	unsigned int	spi_mode;
+	unsigned int	spi_cs_pio_pin;
+};
+
+struct ssc_xfer_info {
+	unsigned long	data;
+	unsigned long	len;
+	unsigned long	next_data;
+	unsigned long	next_len;
+};
+
+struct ssc_device* __must_check ssc_request(unsigned int ssc_num);
+void ssc_free(struct ssc_device *ssc);
+
+int ssc_set_mode(struct ssc_device *ssc, struct ssc_mode *mode);
+
+int ssc_set_rx_buffers(struct ssc_device *ssc, struct ssc_xfer_info *xfer);
+int ssc_get_rx_buffers(struct ssc_device *ssc, struct ssc_xfer_info *xfer);
+int ssc_set_tx_buffers(struct ssc_device *ssc, struct ssc_xfer_info *xfer);
+int ssc_get_tx_buffers(struct ssc_device *ssc, struct ssc_xfer_info *xfer);
+
+int ssc_enable(struct ssc_device *ssc, char tx, char rx);
+int ssc_enable_xfer(struct ssc_device *ssc, char tx, char rx);
+int ssc_disable(struct ssc_device *ssc, char tx, char rx);
+int ssc_disable_xfer(struct ssc_device *ssc, char tx, char rx);
+
+int ssc_enable_int(struct ssc_device *ssc, unsigned int mask);
+int ssc_disable_int(struct ssc_device *ssc, unsigned int mask);
+int ssc_get_int_mask(struct ssc_device *ssc, unsigned int *mask);
+
+int ssc_clk_get_rate(struct ssc_device *ssc);
+
+int ssc_to_irq(struct ssc_device *ssc);
+struct ssc_device* irq_to_ssc(unsigned int irq);
+
+void at32_init_ssc(struct platform_device *pdev);
+
+/* SSC register offsets */
+
+/* SSC Control Register */
+#define SSC_CR				0x00000000
+#define SSC_CR_RXDIS_SIZE			 1
+#define SSC_CR_RXDIS_OFFSET			 1
+#define SSC_CR_RXEN_SIZE			 1
+#define SSC_CR_RXEN_OFFSET			 0
+#define SSC_CR_SWRST_SIZE			 1
+#define SSC_CR_SWRST_OFFSET			15
+#define SSC_CR_TXDIS_SIZE			 1
+#define SSC_CR_TXDIS_OFFSET			 9
+#define SSC_CR_TXEN_SIZE			 1
+#define SSC_CR_TXEN_OFFSET			 8
+
+/* SSC Clock Mode Register */
+#define SSC_CMR				0x00000004
+#define SSC_CMR_DIV_SIZE			12
+#define SSC_CMR_DIV_OFFSET			 0
+
+/* SSC Receive Clock Mode Register */
+#define SSC_RCMR			0x00000010
+#define SSC_RCMR_CKG_SIZE			 2
+#define SSC_RCMR_CKG_OFFSET			 6
+#define SSC_RCMR_CKI_SIZE			 1
+#define SSC_RCMR_CKI_OFFSET			 5
+#define SSC_RCMR_CKO_SIZE			 3
+#define SSC_RCMR_CKO_OFFSET			 2
+#define SSC_RCMR_CKS_SIZE			 2
+#define SSC_RCMR_CKS_OFFSET			 0
+#define SSC_RCMR_PERIOD_SIZE			 8
+#define SSC_RCMR_PERIOD_OFFSET			24
+#define SSC_RCMR_START_SIZE			 4
+#define SSC_RCMR_START_OFFSET			 8
+#define SSC_RCMR_STOP_SIZE			 1
+#define SSC_RCMR_STOP_OFFSET			12
+#define SSC_RCMR_STTDLY_SIZE			 8
+#define SSC_RCMR_STTDLY_OFFSET			16
+
+/* SSC Receive Frame Mode Register */
+#define SSC_RFMR			0x00000014
+#define SSC_RFMR_DATLEN_SIZE			 5
+#define SSC_RFMR_DATLEN_OFFSET			 0
+#define SSC_RFMR_DATNB_SIZE			 4
+#define SSC_RFMR_DATNB_OFFSET			 8
+#define SSC_RFMR_FSEDGE_SIZE			 1
+#define SSC_RFMR_FSEDGE_OFFSET			24
+#define SSC_RFMR_FSLEN_SIZE			 4
+#define SSC_RFMR_FSLEN_OFFSET			16
+#define SSC_RFMR_FSOS_SIZE			 4
+#define SSC_RFMR_FSOS_OFFSET			20
+#define SSC_RFMR_LOOP_SIZE			 1
+#define SSC_RFMR_LOOP_OFFSET			 5
+#define SSC_RFMR_MSBF_SIZE			 1
+#define SSC_RFMR_MSBF_OFFSET			 7
+
+/* SSC Transmit Clock Mode Register */
+#define SSC_TCMR			0x00000018
+#define SSC_TCMR_CKG_SIZE			 2
+#define SSC_TCMR_CKG_OFFSET			 6
+#define SSC_TCMR_CKI_SIZE			 1
+#define SSC_TCMR_CKI_OFFSET			 5
+#define SSC_TCMR_CKO_SIZE			 3
+#define SSC_TCMR_CKO_OFFSET			 2
+#define SSC_TCMR_CKS_SIZE			 2
+#define SSC_TCMR_CKS_OFFSET			 0
+#define SSC_TCMR_PERIOD_SIZE			 8
+#define SSC_TCMR_PERIOD_OFFSET			24
+#define SSC_TCMR_START_SIZE			 4
+#define SSC_TCMR_START_OFFSET			 8
+#define SSC_TCMR_STTDLY_SIZE			 8
+#define SSC_TCMR_STTDLY_OFFSET			16
+
+/* SSC Transmit Frame Mode Register */
+#define SSC_TFMR			0x0000001c
+#define SSC_TFMR_DATDEF_SIZE			 1
+#define SSC_TFMR_DATDEF_OFFSET			 5
+#define SSC_TFMR_DATLEN_SIZE			 5
+#define SSC_TFMR_DATLEN_OFFSET			 0
+#define SSC_TFMR_DATNB_SIZE			 4
+#define SSC_TFMR_DATNB_OFFSET			 8
+#define SSC_TFMR_FSDEN_SIZE			 1
+#define SSC_TFMR_FSDEN_OFFSET			23
+#define SSC_TFMR_FSEDGE_SIZE			 1
+#define SSC_TFMR_FSEDGE_OFFSET			24
+#define SSC_TFMR_FSLEN_SIZE			 4
+#define SSC_TFMR_FSLEN_OFFSET			16
+#define SSC_TFMR_FSOS_SIZE			 3
+#define SSC_TFMR_FSOS_OFFSET			20
+#define SSC_TFMR_MSBF_SIZE			 1
+#define SSC_TFMR_MSBF_OFFSET			 7
+
+/* SSC Receive Hold Register */
+#define SSC_RHR				0x00000020
+#define SSC_RHR_RDAT_SIZE			32
+#define SSC_RHR_RDAT_OFFSET			 0
+
+/* SSC Transmit Hold Register */
+#define SSC_THR				0x00000024
+#define SSC_THR_TDAT_SIZE			32
+#define SSC_THR_TDAT_OFFSET			 0
+
+/* SSC Receive Sync. Holding Register */
+#define SSC_RSHR			0x00000030
+#define SSC_RSHR_RSDAT_SIZE			16
+#define SSC_RSHR_RSDAT_OFFSET			 0
+
+/* SSC Transmit Sync. Holding Register */
+#define SSC_TSHR			0x00000034
+#define SSC_TSHR_TSDAT_SIZE			16
+#define SSC_TSHR_RSDAT_OFFSET			 0
+
+/* SSC Receive Compare 0 Register */
+#define SSC_RC0R			0x00000038
+#define SSC_RC0R_CP0_SIZE			16
+#define SSC_RC0R_CP0_OFFSET			 0
+
+/* SSC Receive Compare 1 Register */
+#define SSC_RC1R			0x0000003c
+#define SSC_RC1R_CP1_SIZE			16
+#define SSC_RC1R_CP1_OFFSET			 0
+
+/* SSC Status Register */
+#define SSC_SR				0x00000040
+#define SSC_SR_CP0_SIZE				 1
+#define SSC_SR_CP0_OFFSET			 8
+#define SSC_SR_CP1_SIZE				 1
+#define SSC_SR_CP1_OFFSET			 9
+#define SSC_SR_ENDRX_SIZE			 1
+#define SSC_SR_ENDRX_OFFSET			 6
+#define SSC_SR_ENDTX_SIZE			 1
+#define SSC_SR_ENDTX_OFFSET			 2
+#define SSC_SR_OVRUN_SIZE			 1
+#define SSC_SR_OVRUN_OFFSET			 5
+#define SSC_SR_RXBUFF_SIZE			 1
+#define SSC_SR_RXBUFF_OFFSET			 7
+#define SSC_SR_RXEN_SIZE			 1
+#define SSC_SR_RXEN_OFFSET			17
+#define SSC_SR_RXRDY_SIZE			 1
+#define SSC_SR_RXRDY_OFFSET			 4
+#define SSC_SR_RXSYN_SIZE			 1
+#define SSC_SR_RXSYN_OFFSET			11
+#define SSC_SR_TXBUFE_SIZE			 1
+#define SSC_SR_TXBUFE_OFFSET			 3
+#define SSC_SR_TXEMPTY_SIZE			 1
+#define SSC_SR_TXEMPTY_OFFSET			 1
+#define SSC_SR_TXEN_SIZE			 1
+#define SSC_SR_TXEN_OFFSET			16
+#define SSC_SR_TXRDY_SIZE			 1
+#define SSC_SR_TXRDY_OFFSET			 0
+#define SSC_SR_TXSYN_SIZE			 1
+#define SSC_SR_TXSYN_OFFSET			10
+
+/* SSC Interrupt Enable Register */
+#define SSC_IER				0x00000044
+#define SSC_IER_CP0_SIZE			 1
+#define SSC_IER_CP0_OFFSET			 8
+#define SSC_IER_CP1_SIZE			 1
+#define SSC_IER_CP1_OFFSET			 9
+#define SSC_IER_ENDRX_SIZE			 1
+#define SSC_IER_ENDRX_OFFSET			 6
+#define SSC_IER_ENDTX_SIZE			 1
+#define SSC_IER_ENDTX_OFFSET			 2
+#define SSC_IER_OVRUN_SIZE			 1
+#define SSC_IER_OVRUN_OFFSET			 5
+#define SSC_IER_RXBUFF_SIZE			 1
+#define SSC_IER_RXBUFF_OFFSET			 7
+#define SSC_IER_RXRDY_SIZE			 1
+#define SSC_IER_RXRDY_OFFSET			 4
+#define SSC_IER_RXSYN_SIZE			 1
+#define SSC_IER_RXSYN_OFFSET			11
+#define SSC_IER_TXBUFE_SIZE			 1
+#define SSC_IER_TXBUFE_OFFSET			 3
+#define SSC_IER_TXEMPTY_SIZE			 1
+#define SSC_IER_TXEMPTY_OFFSET			 1
+#define SSC_IER_TXRDY_SIZE			 1
+#define SSC_IER_TXRDY_OFFSET			 0
+#define SSC_IER_TXSYN_SIZE			 1
+#define SSC_IER_TXSYN_OFFSET			10
+
+/* SSC Interrupt Disable Register */
+#define SSC_IDR				0x00000048
+#define SSC_IDR_CP0_SIZE			 1
+#define SSC_IDR_CP0_OFFSET			 8
+#define SSC_IDR_CP1_SIZE			 1
+#define SSC_IDR_CP1_OFFSET			 9
+#define SSC_IDR_ENDRX_SIZE			 1
+#define SSC_IDR_ENDRX_OFFSET			 6
+#define SSC_IDR_ENDTX_SIZE			 1
+#define SSC_IDR_ENDTX_OFFSET			 2
+#define SSC_IDR_OVRUN_SIZE			 1
+#define SSC_IDR_OVRUN_OFFSET			 5
+#define SSC_IDR_RXBUFF_SIZE			 1
+#define SSC_IDR_RXBUFF_OFFSET			 7
+#define SSC_IDR_RXRDY_SIZE			 1
+#define SSC_IDR_RXRDY_OFFSET			 4
+#define SSC_IDR_RXSYN_SIZE			 1
+#define SSC_IDR_RXSYN_OFFSET			11
+#define SSC_IDR_TXBUFE_SIZE			 1
+#define SSC_IDR_TXBUFE_OFFSET			 3
+#define SSC_IDR_TXEMPTY_SIZE			 1
+#define SSC_IDR_TXEMPTY_OFFSET			 1
+#define SSC_IDR_TXRDY_SIZE			 1
+#define SSC_IDR_TXRDY_OFFSET			 0
+#define SSC_IDR_TXSYN_SIZE			 1
+#define SSC_IDR_TXSYN_OFFSET			10
+
+/* SSC Interrupt Mask Register */
+#define SSC_IMR				0x0000004c
+#define SSC_IMR_CP0_SIZE			 1
+#define SSC_IMR_CP0_OFFSET			 8
+#define SSC_IMR_CP1_SIZE			 1
+#define SSC_IMR_CP1_OFFSET			 9
+#define SSC_IMR_ENDRX_SIZE			 1
+#define SSC_IMR_ENDRX_OFFSET			 6
+#define SSC_IMR_ENDTX_SIZE			 1
+#define SSC_IMR_ENDTX_OFFSET			 2
+#define SSC_IMR_OVRUN_SIZE			 1
+#define SSC_IMR_OVRUN_OFFSET			 5
+#define SSC_IMR_RXBUFF_SIZE			 1
+#define SSC_IMR_RXBUFF_OFFSET			 7
+#define SSC_IMR_RXRDY_SIZE			 1
+#define SSC_IMR_RXRDY_OFFSET			 4
+#define SSC_IMR_RXSYN_SIZE			 1
+#define SSC_IMR_RXSYN_OFFSET			11
+#define SSC_IMR_TXBUFE_SIZE			 1
+#define SSC_IMR_TXBUFE_OFFSET			 3
+#define SSC_IMR_TXEMPTY_SIZE			 1
+#define SSC_IMR_TXEMPTY_OFFSET			 1
+#define SSC_IMR_TXRDY_SIZE			 1
+#define SSC_IMR_TXRDY_OFFSET			 0
+#define SSC_IMR_TXSYN_SIZE			 1
+#define SSC_IMR_TXSYN_OFFSET			10
+
+/* SSC PDC Receive Pointer Register */
+#define SSC_PDC_RPR			0x00000100
+
+/* SSC PDC Receive Counter Register */
+#define SSC_PDC_RCR			0x00000104
+
+/* SSC PDC Transmit Pointer Register */
+#define SSC_PDC_TPR			0x00000108
+
+/* SSC PDC Receive Next Pointer Register */
+#define SSC_PDC_RNPR			0x00000110
+
+/* SSC PDC Receive Next Counter Register */
+#define SSC_PDC_RNCR			0x00000114
+
+/* SSC PDC Transmit Counter Register */
+#define SSC_PDC_TCR			0x0000010c
+
+/* SSC PDC Transmit Next Pointer Register */
+#define SSC_PDC_TNPR			0x00000118
+
+/* SSC PDC Transmit Next Counter Register */
+#define SSC_PDC_TNCR			0x0000011c
+
+/* SSC PDC Transfer Control Register */
+#define SSC_PDC_PTCR			0x00000120
+#define SSC_PDC_PTCR_RXTDIS_SIZE		 1
+#define SSC_PDC_PTCR_RXTDIS_OFFSET		 1
+#define SSC_PDC_PTCR_RXTEN_SIZE			 1
+#define SSC_PDC_PTCR_RXTEN_OFFSET		 0
+#define SSC_PDC_PTCR_TXTDIS_SIZE		 1
+#define SSC_PDC_PTCR_TXTDIS_OFFSET		 9
+#define SSC_PDC_PTCR_TXTEN_SIZE			 1
+#define SSC_PDC_PTCR_TXTEN_OFFSET		 8
+
+/* SSC PDC Transfer Status Register */
+#define SSC_PDC_PTSR			0x00000124
+#define SSC_PDC_PTSR_RXTEN_SIZE			 1
+#define SSC_PDC_PTSR_RXTEN_OFFSET		 0
+#define SSC_PDC_PTSR_TXTEN_SIZE			 1
+#define SSC_PDC_PTSR_TXTEN_OFFSET		 8
+
+/* Bit manipulation macros */
+#define SSC_BIT(name)                          (1 << SSC_##name##_OFFSET)
+#define SSC_BF(name,value)                     (((value) & ((1 << SSC_##name##_SIZE) - 1)) << SSC_##name##_OFFSET)
+#define SSC_BFEXT(name,value)                  (((value) >> SSC_##name##_OFFSET) & ((1 << SSC_##name##_SIZE) - 1))
+#define SSC_BFINS(name,value,old)              (((old) & ~(((1 << SSC_##name##_SIZE) - 1) << SSC_##name##_OFFSET)) | SSC_BF(name,value))
+
+/* Register access macros */
+#define ssc_readl(port,reg)					\
+	__raw_readl((port)->regs + SSC_##reg)
+#define ssc_writel(port,reg,value)				\
+	__raw_writel((value), (port)->regs + SSC_##reg)
+
+#endif /* __INCLUDE_ATMEL_SSC_H */
diff --git a/include/pcmcia/cs_types.h b/include/pcmcia/cs_types.h
index c1d1629..5f38803 100644
--- a/include/pcmcia/cs_types.h
+++ b/include/pcmcia/cs_types.h
@@ -21,7 +21,7 @@
 #include <sys/types.h>
 #endif
 
-#if defined(__arm__) || defined(__mips__)
+#if defined(__arm__) || defined(__mips__) || defined(__avr32__)
 /* This (ioaddr_t) is exposed to userspace & hence cannot be changed. */
 typedef u_int   ioaddr_t;
 #else
diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
new file mode 100644
index 0000000..4eea637
--- /dev/null
+++ b/include/video/atmel_lcdc.h
@@ -0,0 +1,196 @@
+/*
+ *  Header file for AT91/AT32 LCD Controller
+ *
+ *  Data structure and register user interface
+ *
+ *  Copyright (C) 2007 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ATMEL_LCDC_H__
+#define __ATMEL_LCDC_H__
+
+ /* LCD Controller info data structure */
+struct atmel_lcdfb_info {
+	spinlock_t		lock;
+	struct fb_info		*info;
+	void __iomem		*mmio;
+	unsigned long		irq_base;
+
+	unsigned int		guard_time;
+	struct platform_device	*pdev;
+	struct clk		*bus_clk;
+	struct clk		*lcdc_clk;
+	unsigned int		default_bpp;
+	unsigned int		default_lcdcon2;
+	unsigned int		default_dmacon;
+	void (*atmel_lcdfb_power_control)(int on);
+	struct fb_monspecs	*default_monspecs;
+	u32			pseudo_palette[16];
+};
+
+#define ATMEL_LCDC_DMABADDR1	0x00
+#define ATMEL_LCDC_DMABADDR2	0x04
+#define ATMEL_LCDC_DMAFRMPT1	0x08
+#define ATMEL_LCDC_DMAFRMPT2	0x0c
+#define ATMEL_LCDC_DMAFRMADD1	0x10
+#define ATMEL_LCDC_DMAFRMADD2	0x14
+
+#define ATMEL_LCDC_DMAFRMCFG	0x18
+#define	ATMEL_LCDC_FRSIZE	(0x7fffff <<  0)
+#define	ATMEL_LCDC_BLENGTH_OFFSET	24
+#define	ATMEL_LCDC_BLENGTH	(0x7f     << ATMEL_LCDC_BLENGTH_OFFSET)
+
+#define ATMEL_LCDC_DMACON	0x1c
+#define	ATMEL_LCDC_DMAEN	(0x1 << 0)
+#define	ATMEL_LCDC_DMARST	(0x1 << 1)
+#define	ATMEL_LCDC_DMABUSY	(0x1 << 2)
+#define		ATMEL_LCDC_DMAUPDT	(0x1 << 3)
+#define		ATMEL_LCDC_DMA2DEN	(0x1 << 4)
+
+#define ATMEL_LCDC_DMA2DCFG	0x20
+#define		ATMEL_LCDC_ADDRINC_OFFSET	0
+#define		ATMEL_LCDC_ADDRINC		(0xffff)
+#define		ATMEL_LCDC_PIXELOFF_OFFSET	24
+#define		ATMEL_LCDC_PIXELOFF		(0x1f << 24)
+
+#define ATMEL_LCDC_LCDCON1	0x0800
+#define	ATMEL_LCDC_BYPASS	(1     <<  0)
+#define	ATMEL_LCDC_CLKVAL_OFFSET	12
+#define	ATMEL_LCDC_CLKVAL	(0x1ff << ATMEL_LCDC_CLKVAL_OFFSET)
+#define	ATMEL_LCDC_LINCNT	(0x7ff << 21)
+
+#define ATMEL_LCDC_LCDCON2	0x0804
+#define	ATMEL_LCDC_DISTYPE	(3 << 0)
+#define		ATMEL_LCDC_DISTYPE_STNMONO	(0 << 0)
+#define		ATMEL_LCDC_DISTYPE_STNCOLOR	(1 << 0)
+#define		ATMEL_LCDC_DISTYPE_TFT		(2 << 0)
+#define	ATMEL_LCDC_SCANMOD	(1 << 2)
+#define		ATMEL_LCDC_SCANMOD_SINGLE	(0 << 2)
+#define		ATMEL_LCDC_SCANMOD_DUAL		(1 << 2)
+#define	ATMEL_LCDC_IFWIDTH	(3 << 3)
+#define		ATMEL_LCDC_IFWIDTH_4		(0 << 3)
+#define		ATMEL_LCDC_IFWIDTH_8		(1 << 3)
+#define		ATMEL_LCDC_IFWIDTH_16		(2 << 3)
+#define	ATMEL_LCDC_PIXELSIZE	(7 << 5)
+#define		ATMEL_LCDC_PIXELSIZE_1		(0 << 5)
+#define		ATMEL_LCDC_PIXELSIZE_2		(1 << 5)
+#define		ATMEL_LCDC_PIXELSIZE_4		(2 << 5)
+#define		ATMEL_LCDC_PIXELSIZE_8		(3 << 5)
+#define		ATMEL_LCDC_PIXELSIZE_16		(4 << 5)
+#define		ATMEL_LCDC_PIXELSIZE_24		(5 << 5)
+#define		ATMEL_LCDC_PIXELSIZE_32		(6 << 5)
+#define	ATMEL_LCDC_INVVD	(1 << 8)
+#define		ATMEL_LCDC_INVVD_NORMAL		(0 << 8)
+#define		ATMEL_LCDC_INVVD_INVERTED	(1 << 8)
+#define	ATMEL_LCDC_INVFRAME	(1 << 9 )
+#define		ATMEL_LCDC_INVFRAME_NORMAL	(0 << 9)
+#define		ATMEL_LCDC_INVFRAME_INVERTED	(1 << 9)
+#define	ATMEL_LCDC_INVLINE	(1 << 10)
+#define		ATMEL_LCDC_INVLINE_NORMAL	(0 << 10)
+#define		ATMEL_LCDC_INVLINE_INVERTED	(1 << 10)
+#define	ATMEL_LCDC_INVCLK	(1 << 11)
+#define		ATMEL_LCDC_INVCLK_NORMAL	(0 << 11)
+#define		ATMEL_LCDC_INVCLK_INVERTED	(1 << 11)
+#define	ATMEL_LCDC_INVDVAL	(1 << 12)
+#define		ATMEL_LCDC_INVDVAL_NORMAL	(0 << 12)
+#define		ATMEL_LCDC_INVDVAL_INVERTED	(1 << 12)
+#define	ATMEL_LCDC_CLKMOD	(1 << 15)
+#define		ATMEL_LCDC_CLKMOD_ACTIVEDISPLAY	(0 << 15)
+#define		ATMEL_LCDC_CLKMOD_ALWAYSACTIVE	(1 << 15)
+#define	ATMEL_LCDC_MEMOR	(1 << 31)
+#define		ATMEL_LCDC_MEMOR_BIG		(0 << 31)
+#define		ATMEL_LCDC_MEMOR_LITTLE		(1 << 31)
+
+#define ATMEL_LCDC_TIM1		0x0808
+#define	ATMEL_LCDC_VFP		(0xff <<  0)
+#define	ATMEL_LCDC_VBP_OFFSET		8
+#define	ATMEL_LCDC_VBP		(0xff <<  ATMEL_LCDC_VBP_OFFSET)
+#define	ATMEL_LCDC_VPW_OFFSET		16
+#define	ATMEL_LCDC_VPW		(0x3f << ATMEL_LCDC_VPW_OFFSET)
+#define	ATMEL_LCDC_VHDLY_OFFSET		24
+#define	ATMEL_LCDC_VHDLY	(0xf  << ATMEL_LCDC_VHDLY_OFFSET)
+
+#define ATMEL_LCDC_TIM2		0x080c
+#define	ATMEL_LCDC_HBP		(0xff  <<  0)
+#define	ATMEL_LCDC_HPW_OFFSET		8
+#define	ATMEL_LCDC_HPW		(0x3f  <<  ATMEL_LCDC_HPW_OFFSET)
+#define	ATMEL_LCDC_HFP_OFFSET		21
+#define	ATMEL_LCDC_HFP		(0x7ff << ATMEL_LCDC_HFP_OFFSET)
+
+#define ATMEL_LCDC_LCDFRMCFG	0x0810
+#define	ATMEL_LCDC_LINEVAL	(0x7ff <<  0)
+#define	ATMEL_LCDC_HOZVAL_OFFSET	21
+#define	ATMEL_LCDC_HOZVAL	(0x7ff << ATMEL_LCDC_HOZVAL_OFFSET)
+
+#define ATMEL_LCDC_FIFO		0x0814
+#define	ATMEL_LCDC_FIFOTH	(0xffff)
+
+#define ATMEL_LCDC_MVAL		0x0818
+
+#define ATMEL_LCDC_DP1_2	0x081c
+#define ATMEL_LCDC_DP4_7	0x0820
+#define ATMEL_LCDC_DP3_5	0x0824
+#define ATMEL_LCDC_DP2_3	0x0828
+#define ATMEL_LCDC_DP5_7	0x082c
+#define ATMEL_LCDC_DP3_4	0x0830
+#define ATMEL_LCDC_DP4_5	0x0834
+#define ATMEL_LCDC_DP6_7	0x0838
+#define	ATMEL_LCDC_DP1_2_VAL	(0xff)
+#define	ATMEL_LCDC_DP4_7_VAL	(0xfffffff)
+#define	ATMEL_LCDC_DP3_5_VAL	(0xfffff)
+#define	ATMEL_LCDC_DP2_3_VAL	(0xfff)
+#define	ATMEL_LCDC_DP5_7_VAL	(0xfffffff)
+#define	ATMEL_LCDC_DP3_4_VAL	(0xffff)
+#define	ATMEL_LCDC_DP4_5_VAL	(0xfffff)
+#define	ATMEL_LCDC_DP6_7_VAL	(0xfffffff)
+
+#define ATMEL_LCDC_PWRCON	0x083c
+#define	ATMEL_LCDC_PWR		(1    <<  0)
+#define	ATMEL_LCDC_GUARDT_OFFSET	1
+#define	ATMEL_LCDC_GUARDT	(0x7f <<  ATMEL_LCDC_GUARDT_OFFSET)
+#define	ATMEL_LCDC_BUSY		(1    << 31)
+
+#define ATMEL_LCDC_CONTRAST_CTR	0x0840
+#define	ATMEL_LCDC_PS		(3 << 0)
+#define		ATMEL_LCDC_PS_DIV1		(0 << 0)
+#define		ATMEL_LCDC_PS_DIV2		(1 << 0)
+#define		ATMEL_LCDC_PS_DIV4		(2 << 0)
+#define		ATMEL_LCDC_PS_DIV8		(3 << 0)
+#define	ATMEL_LCDC_POL		(1 << 2)
+#define		ATMEL_LCDC_POL_NEGATIVE		(0 << 2)
+#define		ATMEL_LCDC_POL_POSITIVE		(1 << 2)
+#define	ATMEL_LCDC_ENA		(1 << 3)
+#define		ATMEL_LCDC_ENA_PWMDISABLE	(0 << 3)
+#define		ATMEL_LCDC_ENA_PWMENABLE	(1 << 3)
+
+#define ATMEL_LCDC_CONTRAST_VAL	0x0844
+#define	ATMEL_LCDC_CVAL	(0xff)
+
+#define ATMEL_LCDC_IER		0x0848
+#define ATMEL_LCDC_IDR		0x084c
+#define ATMEL_LCDC_IMR		0x0850
+#define ATMEL_LCDC_ISR		0x0854
+#define ATMEL_LCDC_ICR		0x0858
+#define	ATMEL_LCDC_LNI		(1 << 0)
+#define	ATMEL_LCDC_LSTLNI	(1 << 1)
+#define	ATMEL_LCDC_EOFI		(1 << 2)
+#define	ATMEL_LCDC_UFLWI	(1 << 4)
+#define	ATMEL_LCDC_OWRI		(1 << 5)
+#define	ATMEL_LCDC_MERI		(1 << 6)
+
+#define ATMEL_LCDC_LUT(n)	(0x0c00 + ((n)*4))
+
+#endif /* __ATMEL_LCDC_H__ */
diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl
index f7844f6..6631586 100755
--- a/scripts/checkstack.pl
+++ b/scripts/checkstack.pl
@@ -12,6 +12,7 @@
 #	sh64 port by Paul Mundt
 #	Random bits by Matt Mackall <mpm@selenic.com>
 #	M68k port by Geert Uytterhoeven and Andreas Schwab
+#	AVR32 port by Haavard Skinnemoen <hskinnemoen@atmel.com>
 #
 #	Usage:
 #	objdump -d vmlinux | stackcheck.pl [arch]
@@ -37,6 +38,10 @@ my (@stack, $re, $x, $xs);
 	if ($arch eq 'arm') {
 		#c0008ffc:	e24dd064	sub	sp, sp, #100	; 0x64
 		$re = qr/.*sub.*sp, sp, #(([0-9]{2}|[3-9])[0-9]{2})/o;
+	} elsif ($arch eq 'avr32') {
+		#8000008a:       20 1d           sub sp,4
+		#80000ca8:       fa cd 05 b0     sub sp,sp,1456
+		$re = qr/^.*sub.*sp.*,([0-9]{1,8})/o;
 	} elsif ($arch =~ /^i[3456]86$/) {
 		#c0105234:       81 ec ac 05 00 00       sub    $0x5ac,%esp
 		$re = qr/^.*[as][du][db]    \$(0x$x{1,8}),\%esp$/o;
diff --git a/sound/Kconfig b/sound/Kconfig
index 97532bb..2bad674 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -62,9 +62,13 @@ source "sound/aoa/Kconfig"
 
 source "sound/arm/Kconfig"
 
+source "sound/spi/Kconfig"
+
+source "sound/avr32/Kconfig"
+
 source "sound/mips/Kconfig"
 
-# the following will depend on the order of config.
+# tee following will depend on the order of config.
 # here assuming USB is defined before ALSA
 source "sound/usb/Kconfig"
 
diff --git a/sound/Makefile b/sound/Makefile
index b7c7fb7..fda6893 100644
--- a/sound/Makefile
+++ b/sound/Makefile
@@ -5,7 +5,8 @@ obj-$(CONFIG_SOUND) += soundcore.o
 obj-$(CONFIG_SOUND_PRIME) += sound_firmware.o
 obj-$(CONFIG_SOUND_PRIME) += oss/
 obj-$(CONFIG_DMASOUND) += oss/
-obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ soc/
+obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ avr32/ synth/ usb/ \
+		      sparc/ spi/ parisc/ pcmcia/ mips/ soc/
 obj-$(CONFIG_SND_AOA) += aoa/
 
 # This one must be compilable even if sound is configured out
diff --git a/sound/avr32/Kconfig b/sound/avr32/Kconfig
new file mode 100644
index 0000000..adfe779
--- /dev/null
+++ b/sound/avr32/Kconfig
@@ -0,0 +1,12 @@
+menu "AVR32 devices"
+	depends on SND != n && AVR32
+
+config SND_ATMEL_AC97
+	tristate "Atmel AC97 Controller Driver"
+	depends on SND
+	select SND_PCM
+	select SND_AC97_CODEC
+	help
+	  ALSA sound driver for the Atmel AC97 controller.
+
+endmenu
diff --git a/sound/avr32/Makefile b/sound/avr32/Makefile
new file mode 100644
index 0000000..fd864b7
--- /dev/null
+++ b/sound/avr32/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for ALSA
+#
+
+snd-atmel-ac97-objs		:= ac97c.o
+obj-$(CONFIG_SND_ATMEL_AC97)	+= snd-atmel-ac97.o
diff --git a/sound/avr32/ac97c.c b/sound/avr32/ac97c.c
new file mode 100644
index 0000000..32f6639
--- /dev/null
+++ b/sound/avr32/ac97c.c
@@ -0,0 +1,880 @@
+/*
+ * Driver for the Atmel AC97 Controller
+ *
+ * Copyright (C) 2005-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.
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/ac97_codec.h>
+#include <sound/memalloc.h>
+
+#include <asm/io.h>
+#include <asm/dma-controller.h>
+
+#include "ac97c.h"
+
+/*
+ * Module parameters
+ */
+static char *id;
+module_param(id, charp, 0444);
+MODULE_PARM_DESC(id, "ID string for Atmel AC97 controller");
+
+static DEFINE_MUTEX(opened_mutex);
+
+struct atmel_ac97_dma_info {
+	struct dma_request_cyclic req_tx;
+	struct dma_request_cyclic req_rx;
+	unsigned short rx_periph_id;
+	unsigned short tx_periph_id;
+};
+
+typedef struct atmel_ac97 {
+	spinlock_t lock;
+	void __iomem *regs;
+	struct snd_pcm_substream *playback_substream;
+	struct snd_pcm_substream *capture_substream;
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+	struct snd_ac97 *ac97;
+	struct snd_ac97_bus *ac97_bus;
+	int opened;
+	int period;
+	u64 cur_format;
+	unsigned int cur_rate;
+	struct clk *mck;
+	struct platform_device *pdev;
+        struct atmel_ac97_dma_info dma;
+} atmel_ac97_t;
+#define get_chip(card) ((atmel_ac97_t *)(card)->private_data)
+
+#define ac97c_writel(chip, reg, val)			\
+	__raw_writel((val), (chip)->regs + AC97C_##reg)
+#define ac97c_readl(chip, reg)				\
+	__raw_readl((chip)->regs + AC97C_##reg)
+
+/*
+ * PCM part
+ */
+static struct snd_pcm_hardware snd_atmel_ac97_playback_hw = {
+	.info			= (SNDRV_PCM_INFO_INTERLEAVED
+				  |SNDRV_PCM_INFO_MMAP
+				  |SNDRV_PCM_INFO_MMAP_VALID
+				  |SNDRV_PCM_INFO_BLOCK_TRANSFER
+				  |SNDRV_PCM_INFO_JOINT_DUPLEX),
+	.formats		= (SNDRV_PCM_FMTBIT_S16_BE|SNDRV_PCM_FMTBIT_S16_LE),
+	.rates			= (SNDRV_PCM_RATE_CONTINUOUS),
+	.rate_min		= 4000,
+	.rate_max		= 48000,
+	.channels_min		= 1,
+	.channels_max		= 6,
+	.buffer_bytes_max	= 64*1024,
+	.period_bytes_min	= 512,
+	.period_bytes_max	= 4095,
+	.periods_min		= 8,
+	.periods_max		= 1024,
+};
+
+static struct snd_pcm_hardware snd_atmel_ac97_capture_hw = {
+	.info			= (SNDRV_PCM_INFO_INTERLEAVED
+				  |SNDRV_PCM_INFO_MMAP
+				  |SNDRV_PCM_INFO_MMAP_VALID
+				  |SNDRV_PCM_INFO_BLOCK_TRANSFER
+				  |SNDRV_PCM_INFO_JOINT_DUPLEX),
+	.formats		= (SNDRV_PCM_FMTBIT_S16_BE|SNDRV_PCM_FMTBIT_S16_LE),
+	.rates			= (SNDRV_PCM_RATE_CONTINUOUS),
+	.rate_min		= 4000,
+	.rate_max		= 48000,
+	.channels_min		= 1,
+	.channels_max		= 2,
+	.buffer_bytes_max	= 64*1024,
+	.period_bytes_min	= 512,
+	.period_bytes_max	= 4095,
+	.periods_min		= 8,
+	.periods_max		= 1024,
+};
+
+/* Joint full duplex variables */
+unsigned int hw_rates[1];
+unsigned int hw_formats[1];
+struct snd_pcm_hw_constraint_list hw_constraint_rates;
+struct snd_pcm_hw_constraint_list hw_constraint_formats;
+
+/*
+ * PCM functions
+ */
+static int
+snd_atmel_ac97_playback_open(struct snd_pcm_substream *substream)
+{
+	atmel_ac97_t *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	mutex_lock(&opened_mutex);
+	chip->opened++;
+	runtime->hw = snd_atmel_ac97_playback_hw;
+	if (chip->cur_rate) {
+		runtime->hw.rate_min = chip->cur_rate;
+		runtime->hw.rate_max = chip->cur_rate;
+	}
+	if (chip->cur_format)
+		runtime->hw.formats = (1ULL<<chip->cur_format);
+	mutex_unlock(&opened_mutex);
+	chip->playback_substream = substream;
+	chip->period = 0;
+	return 0;
+}
+
+static int
+snd_atmel_ac97_capture_open(struct snd_pcm_substream *substream)
+{
+	atmel_ac97_t *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	mutex_lock(&opened_mutex);
+	chip->opened++;
+	runtime->hw = snd_atmel_ac97_capture_hw;
+	if (chip->cur_rate) {
+		runtime->hw.rate_min = chip->cur_rate;
+		runtime->hw.rate_max = chip->cur_rate;
+	}
+	if (chip->cur_format)
+		runtime->hw.formats = (1ULL<<chip->cur_format);
+	mutex_unlock(&opened_mutex);
+	chip->capture_substream = substream;
+	chip->period = 0;
+	return 0;
+}
+
+static int snd_atmel_ac97_playback_close(struct snd_pcm_substream *substream)
+{
+	atmel_ac97_t *chip = snd_pcm_substream_chip(substream);
+	mutex_lock(&opened_mutex);
+	chip->opened--;
+	if (!chip->opened) {
+		chip->cur_rate = 0;
+		chip->cur_format = 0;
+	}
+	mutex_unlock(&opened_mutex);
+	return 0;
+}
+
+static int snd_atmel_ac97_capture_close(struct snd_pcm_substream *substream)
+{
+	atmel_ac97_t *chip = snd_pcm_substream_chip(substream);
+	mutex_lock(&opened_mutex);
+	chip->opened--;
+	if (!chip->opened) {
+		chip->cur_rate = 0;
+		chip->cur_format = 0;
+	}
+	mutex_unlock(&opened_mutex);
+	return 0;
+}
+
+static int snd_atmel_ac97_playback_hw_params(struct snd_pcm_substream *substream,
+				    struct snd_pcm_hw_params *hw_params)
+{
+	atmel_ac97_t *chip = snd_pcm_substream_chip(substream);
+	int err;
+
+	err = snd_pcm_lib_malloc_pages(substream,
+					params_buffer_bytes(hw_params));
+	if (err < 0)
+		return err;
+
+	/* Set restrictions to params */
+	mutex_lock(&opened_mutex);
+	chip->cur_rate = params_rate(hw_params);
+	chip->cur_format = params_format(hw_params);
+	mutex_unlock(&opened_mutex);
+
+	return 0;
+}
+
+static int snd_atmel_ac97_capture_hw_params(struct snd_pcm_substream *substream,
+				    struct snd_pcm_hw_params *hw_params)
+{
+	atmel_ac97_t *chip = snd_pcm_substream_chip(substream);
+	int err;
+
+	err = snd_pcm_lib_malloc_pages(substream,
+					params_buffer_bytes(hw_params));
+	if (err < 0)
+		return err;
+
+	/* Set restrictions to params */
+	mutex_lock(&opened_mutex);
+	chip->cur_rate = params_rate(hw_params);
+	chip->cur_format = params_format(hw_params);
+	mutex_unlock(&opened_mutex);
+
+	return 0;
+}
+
+static int snd_atmel_ac97_playback_hw_free(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static int snd_atmel_ac97_capture_hw_free(struct snd_pcm_substream *substream)
+{
+
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static int snd_atmel_ac97_playback_prepare(struct snd_pcm_substream *substream)
+{
+	atmel_ac97_t *chip = snd_pcm_substream_chip(substream);
+	struct platform_device *pdev = chip->pdev;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int block_size = frames_to_bytes(runtime, runtime->period_size);
+	unsigned long word = 0;
+	unsigned long buffer_size = 0;
+
+	dma_sync_single_for_device(&pdev->dev, runtime->dma_addr,
+			block_size * 2, DMA_TO_DEVICE);
+
+	/* Assign slots to channels */
+	switch (substream->runtime->channels) {
+        case 1:
+		word |= AC97C_CH_ASSIGN(PCM_LEFT, A);
+		break;
+	case 2:
+		/* Assign Left and Right slot to Channel A */
+		word |= AC97C_CH_ASSIGN(PCM_LEFT, A)
+			| AC97C_CH_ASSIGN(PCM_RIGHT, A);
+		break;
+        default:
+		/* TODO: support more than two channels */
+		return -EINVAL;
+		break;
+	}
+	ac97c_writel(chip, OCA, word);
+
+	/* Configure sample format and size */
+        word = AC97C_CMR_PDCEN | AC97C_CMR_SIZE_16;
+
+        switch (runtime->format){
+        case SNDRV_PCM_FORMAT_S16_LE:
+		word |= AC97C_CMR_CEM_LITTLE;
+		break;
+        case SNDRV_PCM_FORMAT_S16_BE:
+        default:
+		word &= ~AC97C_CMR_CEM_LITTLE;
+		break;
+        }
+
+	ac97c_writel(chip, CAMR, word);
+
+        /* Set variable rate if needed */
+        if (runtime->rate != 48000) {
+		word = ac97c_readl(chip, MR);
+		word |= AC97C_MR_VRA;
+		ac97c_writel(chip, MR, word);
+        } else {
+		/* Clear Variable Rate Bit */
+		word = ac97c_readl(chip, MR);
+		word &= ~AC97C_MR_VRA;
+		ac97c_writel(chip, MR, word);
+        }
+
+        /* Set rate */
+        snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
+
+	buffer_size = frames_to_bytes(runtime, runtime->period_size) *
+		runtime->periods;
+
+	chip->dma.req_tx.buffer_size = buffer_size;
+        chip->dma.req_tx.periods = runtime->periods;
+
+	BUG_ON(chip->dma.req_tx.buffer_size !=
+			(chip->dma.req_tx.periods *
+			 frames_to_bytes(runtime, runtime->period_size)));
+
+        chip->dma.req_tx.buffer_start = runtime->dma_addr;
+        chip->dma.req_tx.data_reg = (dma_addr_t)(chip->regs + AC97C_CATHR + 2);
+        chip->dma.req_tx.periph_id = chip->dma.tx_periph_id;
+        chip->dma.req_tx.direction = DMA_DIR_MEM_TO_PERIPH;
+        chip->dma.req_tx.width = DMA_WIDTH_16BIT;
+        chip->dma.req_tx.dev_id = chip;
+
+	return 0;
+}
+
+static int snd_atmel_ac97_capture_prepare(struct snd_pcm_substream *substream)
+{
+	atmel_ac97_t *chip = snd_pcm_substream_chip(substream);
+	struct platform_device *pdev = chip->pdev;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int block_size = frames_to_bytes(runtime, runtime->period_size);
+	unsigned long word = 0;
+	unsigned long buffer_size = 0;
+
+	dma_sync_single_for_device(&pdev->dev, runtime->dma_addr,
+			block_size * 2, DMA_FROM_DEVICE);
+
+	/* Assign slots to channels */
+	switch (substream->runtime->channels) {
+        case 1:
+		word |= AC97C_CH_ASSIGN(PCM_LEFT, A);
+		break;
+        case 2:
+		/* Assign Left and Right slot to Channel A */
+		word |= AC97C_CH_ASSIGN(PCM_LEFT, A)
+			| AC97C_CH_ASSIGN(PCM_RIGHT, A);
+		break;
+	default:
+		/* TODO: support more than two channels */
+		return -EINVAL;
+		break;
+	}
+	ac97c_writel(chip, ICA, word);
+
+	/* Configure sample format and size */
+        word = AC97C_CMR_PDCEN | AC97C_CMR_SIZE_16;
+
+	switch (runtime->format) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		word |= AC97C_CMR_CEM_LITTLE;
+		break;
+	case SNDRV_PCM_FORMAT_S16_BE:
+	default:
+		word &= ~(AC97C_CMR_CEM_LITTLE);
+		break;
+	}
+
+	ac97c_writel(chip, CAMR, word);
+
+	/* Set variable rate if needed */
+	if (runtime->rate != 48000) {
+		word = ac97c_readl(chip, MR);
+		word |= AC97C_MR_VRA;
+		ac97c_writel(chip, MR, word);
+	} else {
+		/* Clear Variable Rate Bit */
+		word = ac97c_readl(chip, MR);
+		word &= ~(AC97C_MR_VRA);
+		ac97c_writel(chip, MR, word);
+	}
+
+	/* Set rate */
+	snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
+
+	buffer_size = frames_to_bytes(runtime, runtime->period_size) *
+		runtime->periods;
+
+	chip->dma.req_rx.buffer_size = buffer_size;
+	chip->dma.req_rx.periods = runtime->periods;
+
+	BUG_ON(chip->dma.req_rx.buffer_size !=
+			(chip->dma.req_rx.periods *
+			 frames_to_bytes(runtime, runtime->period_size)));
+
+	chip->dma.req_rx.buffer_start = runtime->dma_addr;
+	chip->dma.req_rx.data_reg = (dma_addr_t)(chip->regs + AC97C_CARHR + 2);
+	chip->dma.req_rx.periph_id = chip->dma.rx_periph_id;
+	chip->dma.req_rx.direction = DMA_DIR_PERIPH_TO_MEM;
+	chip->dma.req_rx.width = DMA_WIDTH_16BIT;
+	chip->dma.req_rx.dev_id = chip;
+
+	return 0;
+}
+
+static int snd_atmel_ac97_playback_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	atmel_ac97_t *chip = snd_pcm_substream_chip(substream);
+	unsigned long camr;
+	int flags, err = 0;
+
+	spin_lock_irqsave(&chip->lock, flags);
+	camr = ac97c_readl(chip, CAMR);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		err = dma_prepare_request_cyclic(chip->dma.req_tx.req.dmac,
+				&chip->dma.req_tx);
+		dma_start_request(chip->dma.req_tx.req.dmac,
+				chip->dma.req_tx.req.channel);
+		camr |= AC97C_CMR_CENA;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		err = dma_stop_request(chip->dma.req_tx.req.dmac,
+				chip->dma.req_tx.req.channel);
+		if (chip->opened <= 1)
+			camr &= ~AC97C_CMR_CENA;
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	ac97c_writel(chip, CAMR, camr);
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+	return err;
+}
+
+static int snd_atmel_ac97_capture_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	atmel_ac97_t *chip = snd_pcm_substream_chip(substream);
+	unsigned long camr;
+	int flags, err = 0;
+
+	spin_lock_irqsave(&chip->lock, flags);
+	camr = ac97c_readl(chip, CAMR);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		err = dma_prepare_request_cyclic(chip->dma.req_rx.req.dmac,
+				&chip->dma.req_rx);
+		dma_start_request(chip->dma.req_rx.req.dmac,
+				chip->dma.req_rx.req.channel);
+		camr |= AC97C_CMR_CENA;
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		err = dma_stop_request(chip->dma.req_rx.req.dmac,
+				chip->dma.req_rx.req.channel);
+		mutex_lock(&opened_mutex);
+		if (chip->opened <= 1)
+			camr &= ~AC97C_CMR_CENA;
+		mutex_unlock(&opened_mutex);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	ac97c_writel(chip, CAMR, camr);
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+	return err;
+}
+
+static snd_pcm_uframes_t snd_atmel_ac97_playback_pointer(struct snd_pcm_substream *substream)
+{
+	atmel_ac97_t *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	snd_pcm_uframes_t pos;
+	unsigned long bytes;
+
+        bytes = (dma_get_current_pos
+			(chip->dma.req_tx.req.dmac,
+			 chip->dma.req_tx.req.channel) - runtime->dma_addr);
+	pos = bytes_to_frames(runtime, bytes);
+	if (pos >= runtime->buffer_size)
+		pos -= runtime->buffer_size;
+
+	return pos;
+}
+
+static snd_pcm_uframes_t snd_atmel_ac97_capture_pointer(struct snd_pcm_substream *substream)
+{
+	atmel_ac97_t *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	snd_pcm_uframes_t pos;
+	unsigned long bytes;
+
+        bytes = (dma_get_current_pos
+			(chip->dma.req_rx.req.dmac,chip->dma.req_rx.req.channel) -
+			runtime->dma_addr);
+	pos = bytes_to_frames(runtime, bytes);
+	if (pos >= runtime->buffer_size)
+		pos -= runtime->buffer_size;
+
+
+	return pos;
+}
+
+static struct snd_pcm_ops atmel_ac97_playback_ops = {
+	.open		= snd_atmel_ac97_playback_open,
+	.close		= snd_atmel_ac97_playback_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= snd_atmel_ac97_playback_hw_params,
+	.hw_free	= snd_atmel_ac97_playback_hw_free,
+	.prepare	= snd_atmel_ac97_playback_prepare,
+	.trigger	= snd_atmel_ac97_playback_trigger,
+	.pointer	= snd_atmel_ac97_playback_pointer,
+};
+
+static struct snd_pcm_ops atmel_ac97_capture_ops = {
+	.open		= snd_atmel_ac97_capture_open,
+	.close		= snd_atmel_ac97_capture_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= snd_atmel_ac97_capture_hw_params,
+	.hw_free	= snd_atmel_ac97_capture_hw_free,
+	.prepare	= snd_atmel_ac97_capture_prepare,
+	.trigger	= snd_atmel_ac97_capture_trigger,
+	.pointer	= snd_atmel_ac97_capture_pointer,
+};
+
+static struct ac97_pcm atmel_ac97_pcm_defs[] __devinitdata = {
+	/* Playback */
+	{
+		.exclusive = 1,
+		.r = { {
+			.slots = ((1 << AC97_SLOT_PCM_LEFT)
+					| (1 << AC97_SLOT_PCM_RIGHT)
+					| (1 << AC97_SLOT_PCM_CENTER)
+					| (1 << AC97_SLOT_PCM_SLEFT)
+					| (1 << AC97_SLOT_PCM_SRIGHT)
+					| (1 << AC97_SLOT_LFE)),
+		} }
+	},
+	/* PCM in */
+	{
+		.stream = 1,
+		.exclusive = 1,
+		.r = { {
+			.slots = ((1 << AC97_SLOT_PCM_LEFT)
+					| (1 << AC97_SLOT_PCM_RIGHT)),
+		} }
+	},
+	/* Mic in */
+	{
+		.stream = 1,
+		.exclusive = 1,
+		.r = { {
+			.slots = (1<<AC97_SLOT_MIC),
+		} }
+	},
+};
+
+static int __devinit snd_atmel_ac97_pcm_new(atmel_ac97_t *chip)
+{
+	struct snd_pcm *pcm;
+	int err;
+
+	err = snd_ac97_pcm_assign(chip->ac97_bus,
+			ARRAY_SIZE(atmel_ac97_pcm_defs),
+			atmel_ac97_pcm_defs);
+	if (err)
+		return err;
+
+	err = snd_pcm_new(chip->card, "Atmel-AC97", 0, 1, 1, &pcm);
+	if (err)
+		return err;
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+			&atmel_ac97_playback_ops);
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+			&atmel_ac97_capture_ops);
+
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      &chip->pdev->dev,
+					      128 * 1024, 128 * 1024);
+
+	pcm->private_data = chip;
+	pcm->info_flags = 0;
+	strcpy(pcm->name, "Atmel-AC97");
+	chip->pcm = pcm;
+
+	return 0;
+}
+
+/* Mixer part */
+static int snd_atmel_ac97_mixer_new(atmel_ac97_t *chip)
+{
+	int err;
+	struct snd_ac97_template template;
+
+	memset(&template, 0, sizeof(template));
+	template.private_data = chip;
+	err = snd_ac97_mixer(chip->ac97_bus, &template, &chip->ac97);
+
+	return err;
+}
+
+static void atmel_ac97_error(struct dma_request *_req)
+{
+	struct dma_request_cyclic *req = to_dma_request_cyclic(_req);
+
+	printk(KERN_WARNING
+	       "DMA Controller error, channel %d (AC97C)\n",
+	       req->req.channel);
+}
+
+static void atmel_ac97_block_complete(struct dma_request *_req)
+{
+	struct dma_request_cyclic *req = to_dma_request_cyclic(_req);
+	atmel_ac97_t *chip = req->dev_id;
+	if (req->periph_id == chip->dma.tx_periph_id)
+		snd_pcm_period_elapsed(chip->playback_substream);
+	else
+		snd_pcm_period_elapsed(chip->capture_substream);
+}
+
+/*
+ * Codec part
+ */
+static void snd_atmel_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+				 unsigned short val)
+{
+	atmel_ac97_t *chip = get_chip(ac97);
+	unsigned long word;
+	int timeout = 40;
+
+	word = (reg & 0x7f) << 16 | val;
+
+	do {
+		if (ac97c_readl(chip, COSR) & AC97C_CSR_TXRDY) {
+			ac97c_writel(chip, COTHR, word);
+			return;
+		}
+		udelay(1);
+	} while (--timeout);
+
+	snd_printk(KERN_WARNING "atmel-ac97: codec write timeout\n");
+}
+
+static unsigned short snd_atmel_ac97_read(struct snd_ac97 *ac97,
+					  unsigned short reg)
+{
+	atmel_ac97_t *chip = get_chip(ac97);
+	unsigned long word;
+	int timeout = 40;
+	int write = 10;
+
+	word = (0x80 | (reg & 0x7f)) << 16;
+
+	if ((ac97c_readl(chip, COSR) & AC97C_CSR_RXRDY) != 0)
+		ac97c_readl(chip, CORHR);
+
+retry_write:
+	timeout = 40;
+
+	do {
+                if ((ac97c_readl(chip, COSR) & AC97C_CSR_TXRDY) != 0) {
+			ac97c_writel(chip, COTHR, word);
+			goto read_reg;
+                }
+		mdelay(10);
+	} while (--timeout);
+
+	if (!--write)
+		goto timed_out;
+	goto retry_write;
+
+read_reg:
+	do {
+		if ((ac97c_readl(chip, COSR) & AC97C_CSR_RXRDY) != 0){
+			unsigned short val = ac97c_readl(chip, CORHR);
+			return val;
+		}
+		mdelay(10);
+	} while (--timeout);
+
+	if (!--write)
+		goto timed_out;
+	goto retry_write;
+
+timed_out:
+	snd_printk(KERN_INFO "atmel-ac97: codec read timeout\n");
+	return 0xffff;
+}
+
+static void snd_atmel_ac97_reset(atmel_ac97_t *chip)
+{
+	/* TODO: Perform hard reset of codec as well */
+	ac97c_writel(chip, MR, AC97C_MR_WRST);
+	mdelay(1);
+	ac97c_writel(chip, MR, AC97C_MR_ENA);
+}
+
+static void snd_atmel_ac97_destroy(struct snd_card *card)
+{
+	atmel_ac97_t *chip = get_chip(card);
+
+	if (chip->regs)
+		iounmap(chip->regs);
+
+	if (chip->mck) {
+		clk_disable(chip->mck);
+		clk_put(chip->mck);
+	}
+
+        if (chip->dma.req_tx.req.dmac){
+		dma_release_channel(chip->dma.req_tx.req.dmac,
+				    chip->dma.req_tx.req.channel);
+        }
+        if (chip->dma.req_rx.req.dmac) {
+		dma_release_channel(chip->dma.req_rx.req.dmac,
+				    chip->dma.req_rx.req.channel);
+        }
+}
+
+static int __devinit snd_atmel_ac97_create(struct snd_card *card,
+					   struct platform_device *pdev)
+{
+	static struct snd_ac97_bus_ops ops = {
+		.write	= snd_atmel_ac97_write,
+		.read	= snd_atmel_ac97_read,
+	};
+	atmel_ac97_t *chip = get_chip(card);
+	struct resource *regs;
+	struct clk *mck;
+        int err;
+
+	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!regs)
+		return -ENXIO;
+
+	mck = clk_get(&pdev->dev, "pclk");
+	if (IS_ERR(mck))
+		return PTR_ERR(mck);
+	clk_enable(mck);
+	chip->mck = mck;
+
+	card->private_free = snd_atmel_ac97_destroy;
+
+	spin_lock_init(&chip->lock);
+	chip->card = card;
+	chip->pdev = pdev;
+
+	chip->regs = ioremap(regs->start, regs->end - regs->start + 1);
+	if (!chip->regs)
+		return -ENOMEM;
+
+	snd_card_set_dev(card, &pdev->dev);
+
+	err = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus);
+
+	return err;
+}
+
+static int __devinit snd_atmel_ac97_probe(struct platform_device *pdev)
+{
+	static int dev;
+	struct snd_card *card;
+	atmel_ac97_t *chip;
+	int err;
+        int ch;
+
+	mutex_init(&opened_mutex);
+
+	err = -ENOMEM;
+	card = snd_card_new(-1, id, THIS_MODULE, sizeof(atmel_ac97_t));
+	if (!card)
+		goto out;
+	chip = get_chip(card);
+
+	err = snd_atmel_ac97_create(card, pdev);
+	if (err)
+		goto out_free_card;
+
+	snd_atmel_ac97_reset(chip);
+
+	err = snd_atmel_ac97_mixer_new(chip);
+	if (err)
+		goto out_free_card;
+
+	err = snd_atmel_ac97_pcm_new(chip);
+	if (err)
+		goto out_free_card;
+
+	/* TODO: Get this information from the platform device */
+	chip->dma.req_tx.req.dmac = find_dma_controller(0);
+	if (!chip->dma.req_tx.req.dmac) {
+		printk(KERN_ERR
+		       "atmel-ac97c: No DMA controller for TX, aborting\n");
+		goto out_free_card;
+	}
+	chip->dma.req_rx.req.dmac = find_dma_controller(0);
+	if (!chip->dma.req_rx.req.dmac) {
+		snd_printk(KERN_ERR
+		       "atmel-ac97c: No DMA controller available for RX, aborting\n");
+		goto out_free_card;
+	}
+
+	chip->dma.rx_periph_id = 3;
+	chip->dma.tx_periph_id = 4;
+
+	ch = dma_alloc_channel(chip->dma.req_tx.req.dmac);
+	if (ch < 0) {
+		printk(KERN_ERR
+		       "atmel-ac97c: Unable to allocate TX DMA channel, aborting\n");
+		goto out_free_card;
+	}
+	chip->dma.req_tx.req.channel = ch;
+	chip->dma.req_tx.width = DMA_WIDTH_16BIT;
+	chip->dma.req_tx.req.block_complete = atmel_ac97_block_complete;
+	chip->dma.req_tx.req.error = atmel_ac97_error;
+
+	ch = dma_alloc_channel(chip->dma.req_rx.req.dmac);
+	if (ch < 0) {
+		snd_printk(KERN_ERR
+		       "atmel-ac97c: Unable to allocate RX DMA channel, aborting\n");
+		goto out_free_card;
+	}
+	chip->dma.req_rx.req.channel = ch;
+	chip->dma.req_rx.width = DMA_WIDTH_16BIT;
+	chip->dma.req_rx.req.block_complete = atmel_ac97_block_complete;
+	chip->dma.req_rx.req.error = atmel_ac97_error;
+
+	strcpy(card->driver, "ac97c");
+	strcpy(card->shortname, "Atmel-AC97");
+	sprintf(card->longname, "Atmel AVR32 AC97 Controller at 0x%p, dma rx %i and tx %i",
+		chip->regs, chip->dma.rx_periph_id, chip->dma.tx_periph_id);
+
+	err = snd_card_register(card);
+	if (err)
+		goto out_free_card;
+
+	platform_set_drvdata(pdev, card);
+	dev++;
+	return 0;
+
+out_free_card:
+	snd_card_free(card);
+out:
+	return err;
+}
+
+static int __devexit snd_atmel_ac97_remove(struct platform_device *pdev)
+{
+	struct snd_card *card = platform_get_drvdata(pdev);
+
+	snd_card_free(card);
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+static struct platform_driver atmel_ac97_driver = {
+	.remove		= __devexit_p(snd_atmel_ac97_remove),
+	.driver		= {
+		.name	= "atmel_ac97c",
+	},
+};
+
+static int __init atmel_ac97_init(void)
+{
+	return platform_driver_probe(&atmel_ac97_driver, snd_atmel_ac97_probe);
+}
+
+static void __exit atmel_ac97_exit(void)
+{
+	platform_driver_unregister(&atmel_ac97_driver);
+}
+
+module_init(atmel_ac97_init);
+module_exit(atmel_ac97_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Driver for Atmel AC97 Controller");
+MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
diff --git a/sound/avr32/ac97c.h b/sound/avr32/ac97c.h
new file mode 100644
index 0000000..96246e7
--- /dev/null
+++ b/sound/avr32/ac97c.h
@@ -0,0 +1,71 @@
+/*
+ * Register definitions for the Atmel AC97 Controller.
+ *
+ * Copyright (C) 2005-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 __SOUND_AVR32_AC97C_H
+#define __SOUND_AVR32_AC97C_H
+
+#define AC97C_MR		0x08
+#define AC97C_ICA		0x10
+#define AC97C_OCA		0x14
+#define AC97C_CARHR		0x20
+#define AC97C_CATHR		0x24
+#define AC97C_CASR		0x28
+#define AC97C_CAMR		0x2c
+#define AC97C_CBRHR		0x30
+#define AC97C_CBTHR		0x34
+#define AC97C_CBSR		0x38
+#define AC97C_CBMR		0x3c
+#define AC97C_CORHR		0x40
+#define AC97C_COTHR		0x44
+#define AC97C_COSR		0x48
+#define AC97C_COMR		0x4c
+#define AC97C_SR		0x50
+#define AC97C_IER		0x54
+#define AC97C_IDR		0x58
+#define AC97C_IMR		0x5c
+#define AC97C_VERSION		0xfc
+
+#define AC97C_CATPR		PDC_TPR
+#define AC97C_CATCR		PDC_TCR
+#define AC97C_CATNPR		PDC_TNPR
+#define AC97C_CATNCR		PDC_TNCR
+#define AC97C_CARPR		PDC_RPR
+#define AC97C_CARCR		PDC_RCR
+#define AC97C_CARNPR		PDC_RNPR
+#define AC97C_CARNCR		PDC_RNCR
+#define AC97C_PTCR		PDC_PTCR
+
+#define AC97C_MR_ENA		(1 << 0)
+#define AC97C_MR_WRST		(1 << 1)
+#define AC97C_MR_VRA		(1 << 2)
+
+#define AC97C_CSR_TXRDY		(1 << 0)
+#define AC97C_CSR_UNRUN		(1 << 2)
+#define AC97C_CSR_RXRDY		(1 << 4)
+#define AC97C_CSR_ENDTX		(1 << 10)
+#define AC97C_CSR_ENDRX		(1 << 14)
+
+#define AC97C_CMR_SIZE_20	(0 << 16)
+#define AC97C_CMR_SIZE_18	(1 << 16)
+#define AC97C_CMR_SIZE_16	(2 << 16)
+#define AC97C_CMR_SIZE_10	(3 << 16)
+#define AC97C_CMR_CEM_LITTLE	(1 << 18)
+#define AC97C_CMR_CEM_BIG	(0 << 18)
+#define AC97C_CMR_CENA		(1 << 21)
+#define AC97C_CMR_PDCEN		(1 << 22)
+
+#define AC97C_SR_CAEVT		(1 << 3)
+
+#define AC97C_CH_ASSIGN(slot, channel)					\
+	(AC97C_CHANNEL_##channel << (3 * (AC97_SLOT_##slot - 3)))
+#define AC97C_CHANNEL_NONE	0x0
+#define AC97C_CHANNEL_A		0x1
+#define AC97C_CHANNEL_B		0x2
+
+#endif /* __SOUND_AVR32_AC97C_H */
diff --git a/sound/spi/Kconfig b/sound/spi/Kconfig
new file mode 100644
index 0000000..6814353
--- /dev/null
+++ b/sound/spi/Kconfig
@@ -0,0 +1,31 @@
+#SPI drivers
+
+menu "SPI devices"
+	depends on SND != n
+
+config SND_AT73C213
+	tristate "Atmel AT73C213 DAC driver"
+	depends on ATMEL_SSC
+	select SND_PCM
+	help
+	  Say Y here if you want to use the Atmel AT73C213 DAC. This device can
+	  be found on several development boards for AT91 and AVR32.
+
+	  This driver requires the Atmel SSC driver for sound sink, a
+	  peripheral found on most AT91 and AVR32 microprocessors.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called snd-at73c213.
+
+config SND_AT73C213_TARGET_BITRATE
+	int "Target bitrate for AT73C213"
+	depends on SND_AT73C213
+	default "48000"
+	range 8000 50000
+	help
+	  Sets the target bitrate for the bitrate calculator in the driver.
+	  Limited by hardware to be between 8000 Hz and 50000 Hz.
+
+	  Set to 48000 Hz by default.
+
+endmenu
diff --git a/sound/spi/Makefile b/sound/spi/Makefile
new file mode 100644
index 0000000..026fb73
--- /dev/null
+++ b/sound/spi/Makefile
@@ -0,0 +1,5 @@
+# Makefile for SPI drivers
+
+snd-at73c213-objs		:= at73c213.o
+
+obj-$(CONFIG_SND_AT73C213)	+= snd-at73c213.o
diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c
new file mode 100644
index 0000000..f94e417
--- /dev/null
+++ b/sound/spi/at73c213.c
@@ -0,0 +1,1123 @@
+/*
+ * Driver for AT73C213 16-bit stereo DAC connected to Atmel SSC
+ *
+ * Copyright (C) 2006 Atmel Norway
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this
+ * distribution in the file called COPYING.
+ */
+
+/*#define DEBUG*/
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kmod.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/initval.h>
+#include <sound/driver.h>
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+
+#include <linux/ssc.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/at73c213.h>
+
+#include <asm/io.h>
+#include <asm/processor.h>
+
+#include "at73c213.h"
+
+#define BITRATE_MIN	 8000 /* hardware limit? */
+#define BITRATE_TARGET	CONFIG_SND_AT73C213_TARGET_BITRATE
+#define BITRATE_MAX	50000 /* hardware limit */
+
+/* initial (hardware reset) AT73C213 register values */
+static unsigned char snd_at73c213_original_image[18] =
+{
+	0x00,	/* 00 - CTRL    */
+	0x05,	/* 01 - LLIG    */
+	0x05,	/* 02 - RLIG    */
+	0x08,	/* 03 - LPMG    */
+	0x08,	/* 04 - RPMG    */
+	0x00,	/* 05 - LLOG    */
+	0x00,	/* 06 - RLOG    */
+	0x22,	/* 07 - OLC     */
+	0x09,	/* 08 - MC      */
+	0x00,	/* 09 - CSFC    */
+	0x00,	/* 0A - MISC    */
+	0x00,	/* 0B -         */
+	0x00,	/* 0C - PRECH   */
+	0x05,	/* 0D - AUXG    */
+	0x00,	/* 0E -         */
+	0x00,	/* 0F -         */
+	0x00,	/* 10 - RST     */
+	0x00,	/* 11 - PA_CTRL */
+};
+
+/* SSC setup */
+static struct ssc_mode ssc_at73c213 =
+{
+	.mode			= ATMEL_SSC_MODE_I2S_MASTER,
+	.data_length		= 16,
+};
+
+/* chip-specific data */
+struct snd_at73c213 {
+	struct snd_card			*card;
+	struct snd_pcm			*pcm;
+	struct snd_pcm_substream	*substream;
+	int				irq;
+	int				period;
+	unsigned long			bitrate;
+	struct clk			*bitclk;
+	struct clk			*dac_clk;
+	struct ssc_device		*ssc;
+	struct spi_device		*spi;
+	struct at73c213_board_info	*info;
+	struct ssc_xfer_info		ssc_xfer;
+	u8				spi_wbuffer[2];
+	u8				spi_rbuffer[2];
+	/* image of the SPI registers in AT73C213 */
+	u8				image[18];
+	spinlock_t			lock;
+};
+
+#define get_chip(card) ((struct snd_at73c213 *)card->private_data)
+
+static int
+snd_at73c213_write_reg(struct snd_at73c213 *chip, u8 reg, u8 val)
+{
+	struct spi_message msg;
+	struct spi_transfer msg_xfer = {
+		.len		= 2,
+		.cs_change	= 0,
+	};
+
+	spi_message_init(&msg);
+
+	chip->spi_wbuffer[0] = reg;
+	chip->spi_wbuffer[1] = val;
+
+	msg_xfer.tx_buf = chip->spi_wbuffer;
+	msg_xfer.rx_buf = chip->spi_rbuffer;
+	spi_message_add_tail(&msg_xfer, &msg);
+
+	return spi_sync(chip->spi, &msg);
+}
+
+#define write_reg(_spi, reg, val)				\
+	do {							\
+		retval = snd_at73c213_write_reg(_spi, reg, val);	\
+		if (retval)					\
+			goto out;				\
+	} while (0)
+
+static struct snd_pcm_hardware snd_at73c213_playback_hw = {
+	.info		= SNDRV_PCM_INFO_INTERLEAVED |
+			  SNDRV_PCM_INFO_BLOCK_TRANSFER,
+	.formats	= SNDRV_PCM_FMTBIT_S16_BE,
+	.rates		= SNDRV_PCM_RATE_CONTINUOUS,
+	.rate_min	= 8000,  /* overwritten by chip->bitrate */
+	.rate_max	= 50000, /* overwritten by chip->bitrate */
+	.channels_min	= 2,
+	.channels_max	= 2,
+	.buffer_bytes_max = 64 * 1024 - 1,
+	.period_bytes_min = 512,
+	.period_bytes_max = 64 * 1024 - 1,
+	.periods_min	= 4,
+	.periods_max	= 1024,
+};
+
+/*
+ * calculate and set bitrate and divisions
+ */
+static int snd_at73c213_set_bitrate(struct snd_at73c213 *chip)
+{
+	unsigned long ssc_rate = ssc_clk_get_rate(chip->ssc);
+	unsigned long dac_rate_new, ssc_div, status;
+	unsigned long ssc_div_max, ssc_div_min;
+	int max_tries, retval;
+
+	/* We connect two clocks here, picking divisors so the I2S clocks
+	 * out data at the same rate the DAC clocks it in ... and as close
+	 * as practical to the desired target rate.
+	 *
+	 * The DAC master clock (MCLK) is programmable, and is either 256
+	 * or (not here) 384 times the I2S output clock (BCLK).
+	 */
+
+	/* SSC clock / (bitrate * stereo * 16-bit) */
+	ssc_div = ssc_rate / (BITRATE_TARGET * 2 * 16);
+	ssc_div_min = ssc_rate / (BITRATE_MAX * 2 * 16);
+	ssc_div_max = ssc_rate / (BITRATE_MIN * 2 * 16);
+	max_tries = (ssc_div_max - ssc_div_min) / 2;
+
+	if ((ssc_div % 2) != 0)
+		ssc_div++;
+	if ((ssc_rate / (ssc_div * 2 * 16)) < BITRATE_MIN) {
+		ssc_div -= 2;
+		if ((ssc_rate / (ssc_div * 2 * 16)) > BITRATE_MAX) {
+			return -ENXIO;
+		}
+	}
+
+	/* search for a possible bitrate */
+	do {
+		/* SSC clock / (ssc divider * 16-bit * stereo) */
+		if ((ssc_rate / (ssc_div * 2 * 16)) < BITRATE_MIN)
+			return -ENXIO;
+
+		dac_rate_new = 8 * (ssc_rate / ssc_div); /* 256 / (2 * 16) = 8 */
+
+		status = clk_round_rate(chip->dac_clk, dac_rate_new);
+		if (status < 0)
+			return status;
+
+		/* ignore difference smaller than 256 Hz */
+		if ((status/256) == (dac_rate_new/256))
+			goto set_rate;
+
+		ssc_div += 2;
+	} while (--max_tries);
+
+	/* not able to find a bitrate */
+	return -ENXIO;
+
+set_rate:
+	status = clk_set_rate(chip->dac_clk, status);
+	if (status < 0)
+		return status;
+
+	ssc_at73c213.bauddiv = ssc_div;
+	retval = ssc_set_mode(chip->ssc, &ssc_at73c213);
+	if (retval)
+		return retval;
+
+	/* SSC clock / (ssc divider * 16-bit * stereo) */
+	chip->bitrate = ssc_rate / (ssc_div * 16 * 2);
+
+	printk(KERN_INFO "at73c213: supported bitrate is %lu (%lu divider)\n",
+			chip->bitrate, ssc_div);
+
+	return 0;
+}
+
+/* open callback */
+static int snd_at73c213_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_at73c213 *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	snd_at73c213_playback_hw.rate_min = chip->bitrate;
+	snd_at73c213_playback_hw.rate_max = chip->bitrate;
+	runtime->hw = snd_at73c213_playback_hw;
+	chip->substream = substream;
+
+	return 0;
+}
+
+/* close callback */
+static int snd_at73c213_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct snd_at73c213 *chip = snd_pcm_substream_chip(substream);
+	chip->substream = NULL;
+	return 0;
+}
+
+/* hw_params callback */
+static int snd_at73c213_pcm_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *hw_params)
+{
+	return snd_pcm_lib_malloc_pages(substream,
+					params_buffer_bytes(hw_params));
+}
+
+/* hw_free callback */
+static int snd_at73c213_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+/* prepare callback */
+static int snd_at73c213_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_at73c213 *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int block_size;
+
+	block_size = frames_to_bytes(runtime, runtime->period_size);
+
+	chip->period = 0;
+
+	/* Make sure that our data are actually readable by the SSC */
+	dma_sync_single_for_device(&chip->spi->dev,
+			(long)runtime->dma_area,
+			block_size, DMA_TO_DEVICE);
+	dma_sync_single_for_device(&chip->spi->dev,
+			(long)runtime->dma_area + block_size,
+			block_size, DMA_TO_DEVICE);
+
+	chip->ssc_xfer.data	 = (long)runtime->dma_area;
+	chip->ssc_xfer.data	 &= ~0xe0000000;
+	chip->ssc_xfer.len	 = runtime->period_size * 2;
+	chip->ssc_xfer.next_data = (long)runtime->dma_area + block_size;
+	chip->ssc_xfer.next_data &= ~0xe0000000;
+	chip->ssc_xfer.next_len  = runtime->period_size * 2;
+	ssc_set_tx_buffers(chip->ssc, &chip->ssc_xfer);
+
+	return 0;
+}
+
+/* trigger callback */
+static int snd_at73c213_pcm_trigger(struct snd_pcm_substream *substream,
+				   int cmd)
+{
+	struct snd_at73c213 *chip = snd_pcm_substream_chip(substream);
+	int retval = 0;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&chip->lock, flags);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		ssc_enable_int(chip->ssc, SSC_BIT(IER_ENDTX));
+		ssc_enable_xfer(chip->ssc, 1, 0);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		ssc_disable_xfer(chip->ssc, 1, 0);
+		ssc_disable_int(chip->ssc, SSC_BIT(IDR_ENDTX));
+		break;
+	default:
+		printk(KERN_WARNING "at73c213: spurious command %x\n", cmd);
+		retval = -EINVAL;
+		break;
+	}
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	return retval;
+}
+
+/* pointer callback */
+static snd_pcm_uframes_t snd_at73c213_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_at73c213 *chip = snd_pcm_substream_chip(substream);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	snd_pcm_uframes_t pos;
+	unsigned long bytes;
+
+	ssc_get_tx_buffers(chip->ssc, &chip->ssc_xfer);
+	bytes = chip->ssc_xfer.data - (unsigned long)runtime->dma_area;
+
+	pos = bytes_to_frames(runtime, bytes);
+	if (pos >= runtime->buffer_size)
+		pos -= runtime->buffer_size;
+
+	return pos;
+}
+
+/* operators */
+static struct snd_pcm_ops at73c213_playback_ops = {
+	.open		= snd_at73c213_pcm_open,
+	.close		= snd_at73c213_pcm_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= snd_at73c213_pcm_hw_params,
+	.hw_free	= snd_at73c213_pcm_hw_free,
+	.prepare	= snd_at73c213_pcm_prepare,
+	.trigger	= snd_at73c213_pcm_trigger,
+	.pointer	= snd_at73c213_pcm_pointer,
+};
+
+/* free a pcm device */
+static void snd_at73c213_pcm_free(struct snd_pcm *pcm)
+{
+	struct snd_at73c213 *chip = snd_pcm_chip(pcm);
+	if (chip->pcm) {
+		snd_pcm_lib_preallocate_free_for_all(chip->pcm);
+		chip->pcm = NULL;
+	}
+}
+
+/* create a new pcm device */
+static int __devinit snd_at73c213_pcm_new(struct snd_at73c213 *chip, int device)
+{
+	struct snd_pcm *pcm;
+	int retval;
+
+	retval = snd_pcm_new(chip->card, chip->card->shortname, device, 1, 0, &pcm);
+	if (retval < 0)
+		return retval;
+
+	pcm->private_data = chip;
+	pcm->private_free = snd_at73c213_pcm_free;
+	pcm->info_flags = SNDRV_PCM_INFO_BLOCK_TRANSFER;
+	strcpy(pcm->name, "at73c213");
+	chip->pcm = pcm;
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &at73c213_playback_ops);
+
+	/* TODO: why can I not use SNDRV_DMA_TYPE_DEV? */
+	retval = snd_pcm_lib_preallocate_pages_for_all(chip->pcm,
+			SNDRV_DMA_TYPE_CONTINUOUS,
+			snd_dma_continuous_data(GFP_KERNEL),
+			64 * 1024, 64 * 1024);
+	return 0;
+}
+
+static irqreturn_t snd_at73c213_interrupt(int irq, void *dev_id)
+{
+	struct snd_at73c213 *chip = dev_id;
+	struct snd_pcm_runtime *runtime = chip->substream->runtime;
+	u32 status;
+	int offset, next_period, block_size, mask, retval;
+
+	spin_lock(&chip->lock);
+
+	block_size = frames_to_bytes(runtime, runtime->period_size);
+
+	retval = ssc_get_int_mask(chip->ssc, &status);
+	if (retval)
+		return retval;
+
+	if (status & SSC_BIT(IMR_ENDTX)) {
+		chip->period++;
+		if (chip->period == runtime->periods)
+			chip->period = 0;
+		next_period = chip->period + 1;
+		if (next_period == runtime->periods)
+			next_period = 0;
+
+		offset = block_size * next_period;
+
+		/* make sure that our data are actually readable by the SSC */
+		dma_sync_single_for_device(&chip->spi->dev,
+				(long)runtime->dma_area + offset,
+				block_size, DMA_TO_DEVICE);
+		chip->ssc_xfer.data	 = 0; /* only update next pointer */
+		chip->ssc_xfer.next_data = (long)runtime->dma_area + offset;
+		chip->ssc_xfer.next_data &= ~0xe0000000;
+		chip->ssc_xfer.next_len  = runtime->period_size * 2;
+		ssc_set_tx_buffers(chip->ssc, &chip->ssc_xfer);
+	} else {
+		printk(KERN_WARNING
+				"Spurious SSC interrupt, status = 0x%08lx\n",
+				(unsigned long)status);
+		ssc_disable_int(chip->ssc, status);
+	}
+
+	ssc_get_int_mask(chip->ssc, &mask);
+	spin_unlock(&chip->lock);
+
+	if (status & SSC_BIT(IMR_ENDTX))
+		snd_pcm_period_elapsed(chip->substream);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Mixer functions
+ */
+#if 0 /* Function not in use */
+static int snd_at73c213_mono_info(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_info *uinfo)
+{
+	unsigned long mask = (kcontrol->private_value >> 16) & 0xff;
+
+	uinfo->type = (mask == 1) ?
+		SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = mask;
+
+	return 0;
+}
+#endif
+
+static int snd_at73c213_mono_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	int reg = kcontrol->private_value & 0xff;
+	int shift = (kcontrol->private_value >> 8) & 0xff;
+	int mask = (kcontrol->private_value >> 16) & 0xff;
+	int invert = (kcontrol->private_value >> 24) & 0xff;
+
+	spin_lock_irqsave(&chip->lock, flags);
+
+	ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask;
+
+	if (invert)
+		ucontrol->value.integer.value[0] =
+			(mask - ucontrol->value.integer.value[0]);
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	return 0;
+}
+
+static int snd_at73c213_mono_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	int reg = kcontrol->private_value & 0xff;
+	int shift = (kcontrol->private_value >> 8) & 0xff;
+	int mask = (kcontrol->private_value >> 16) & 0xff;
+	int invert = (kcontrol->private_value >> 24) & 0xff;
+	int change, retval;
+	unsigned short val;
+
+	val = (ucontrol->value.integer.value[0] & mask);
+	if (invert)
+		val = mask - val;
+	val <<= shift;
+
+	spin_lock_irqsave(&chip->lock, flags);
+
+	val = (chip->image[reg] & ~(mask << shift)) | val;
+	change = val != chip->image[reg];
+	write_reg(chip, reg, val);
+
+	chip->image[reg] = val;
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	return change;
+
+out:
+	return retval;
+}
+
+static int snd_at73c213_stereo_info(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_info *uinfo)
+{
+	int mask = (kcontrol->private_value >> 24) & 0xFF;
+
+	uinfo->type = mask == 1 ?
+		SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = mask;
+
+	return 0;
+}
+
+static int snd_at73c213_stereo_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	int left_reg = kcontrol->private_value & 0xff;
+	int right_reg = (kcontrol->private_value >> 8) & 0xff;
+	int shift_left = (kcontrol->private_value >> 16) & 0x07;
+	int shift_right = (kcontrol->private_value >> 19) & 0x07;
+	int mask = (kcontrol->private_value >> 24) & 0xff;
+	int invert = (kcontrol->private_value >> 22) & 1;
+
+	spin_lock_irqsave(&chip->lock, flags);
+
+	ucontrol->value.integer.value[0] =
+		(chip->image[left_reg] >> shift_left) & mask;
+	ucontrol->value.integer.value[1] =
+		(chip->image[right_reg] >> shift_right) & mask;
+
+	if (invert) {
+		ucontrol->value.integer.value[0] =
+			(mask - ucontrol->value.integer.value[0]);
+		ucontrol->value.integer.value[1] =
+			(mask - ucontrol->value.integer.value[1]);
+	}
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	return 0;
+}
+
+static int snd_at73c213_stereo_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	int left_reg = kcontrol->private_value & 0xff;
+	int right_reg = (kcontrol->private_value >> 8) & 0xff;
+	int shift_left = (kcontrol->private_value >> 16) & 0x07;
+	int shift_right = (kcontrol->private_value >> 19) & 0x07;
+	int mask = (kcontrol->private_value >> 24) & 0xff;
+	int invert = (kcontrol->private_value >> 22) & 1;
+	int change, retval;
+	unsigned short val1, val2;
+
+	val1 = ucontrol->value.integer.value[0] & mask;
+	val2 = ucontrol->value.integer.value[1] & mask;
+	if (invert) {
+		val1 = mask - val1;
+		val2 = mask - val2;
+	}
+	val1 <<= shift_left;
+	val2 <<= shift_right;
+
+	spin_lock_irqsave(&chip->lock, flags);
+
+	val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
+	val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2;
+	change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg];
+	write_reg(chip, left_reg, val1);
+	write_reg(chip, right_reg, val2);
+
+	chip->image[left_reg] = val1;
+	chip->image[right_reg] = val2;
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	return change;
+
+out:
+	return retval;
+}
+
+static int snd_at73c213_mono_switch_info(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+
+	return 0;
+}
+
+static int snd_at73c213_mono_switch_get(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	int reg = kcontrol->private_value & 0xff;
+	int shift = (kcontrol->private_value >> 8) & 0xff;
+	int invert = (kcontrol->private_value >> 24) & 0xff;
+
+	spin_lock_irqsave(&chip->lock, flags);
+
+	ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & 0x01;
+
+	if (invert)
+		ucontrol->value.integer.value[0] =
+			(0x01 - ucontrol->value.integer.value[0]);
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	return 0;
+}
+
+static int snd_at73c213_mono_switch_put(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	int reg = kcontrol->private_value & 0xff;
+	int shift = (kcontrol->private_value >> 8) & 0xff;
+	int mask = (kcontrol->private_value >> 16) & 0xff;
+	int invert = (kcontrol->private_value >> 24) & 0xff;
+	int change, retval;
+	unsigned short val;
+
+	if (ucontrol->value.integer.value[0])
+		val = mask;
+	else
+		val = 0;
+
+	if (invert)
+		val = mask - val;
+	val <<= shift;
+
+	spin_lock_irqsave(&chip->lock, flags);
+
+	val |= (chip->image[reg] & ~(mask << shift));
+	change = val != chip->image[reg];
+
+	write_reg(chip, reg, val);
+
+	chip->image[reg] = val;
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	return change;
+
+out:
+	return retval;
+}
+
+static int snd_at73c213_pa_volume_info(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = ((kcontrol->private_value >> 16) & 0xFF) - 1;
+
+	return 0;
+}
+
+static int snd_at73c213_line_capture_volume_info(
+		struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 14;
+	uinfo->value.integer.max = 31;
+
+	return 0;
+}
+
+static int snd_at73c213_aux_capture_volume_info(
+		struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 14;
+	uinfo->value.integer.max = 31;
+
+	return 0;
+}
+
+#define AT73C213_MONO(xname, xindex, reg, shift, mask, invert) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+  .info = snd_at73c213_mono_info, \
+  .get = snd_at73c213_mono_get, .put = snd_at73c213_mono_put, \
+  .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
+
+#define AT73C213_MONO_SWITCH(xname, xindex, reg, shift, mask, invert) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+  .info = snd_at73c213_mono_switch_info, \
+  .get = snd_at73c213_mono_switch_get, .put = snd_at73c213_mono_switch_put, \
+  .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
+
+#define AT73C213_STEREO(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+  .info = snd_at73c213_stereo_info, \
+  .get = snd_at73c213_stereo_get, .put = snd_at73c213_stereo_put, \
+  .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
+
+static struct snd_kcontrol_new snd_at73c213_controls[] __devinitdata = {
+AT73C213_STEREO("Master Playback Volume", 0, DAC_LMPG, DAC_RMPG, 0, 0, 0x1F, 1),
+AT73C213_STEREO("Master Playback Switch", 0, DAC_LMPG, DAC_RMPG, 5, 5, 1, 1),
+AT73C213_STEREO("PCM Playback Volume", 0, DAC_LLOG, DAC_RLOG, 0, 0, 0x1F, 1),
+AT73C213_STEREO("PCM Playback Switch", 0, DAC_LLOG, DAC_RLOG, 5, 5, 1, 1),
+AT73C213_MONO_SWITCH("Mono PA Playback Switch", 0, DAC_CTRL, DAC_CTRL_ONPADRV, 0x01, 0),
+{
+	.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name	= "PA Playback Volume",
+	.index	= 0,
+	.info	= snd_at73c213_pa_volume_info,
+	.get	= snd_at73c213_mono_get,
+	.put	= snd_at73c213_mono_put,
+	.private_value	= PA_CTRL|(PA_CTRL_APAGAIN<<8)|(0x0F<<16)|(1<<24),
+},
+AT73C213_MONO_SWITCH("PA High Gain Playback Switch", 0, PA_CTRL, PA_CTRL_APALP, 0x01, 1),
+AT73C213_MONO_SWITCH("PA Playback Switch", 0, PA_CTRL, PA_CTRL_APAON, 0x01, 0),
+{
+	.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name	= "Aux Capture Volume",
+	.index	= 0,
+	.info	= snd_at73c213_aux_capture_volume_info,
+	.get	= snd_at73c213_mono_get,
+	.put	= snd_at73c213_mono_put,
+	.private_value	= DAC_AUXG|(0<<8)|(0x1F<<16)|(1<<24),
+},
+AT73C213_MONO_SWITCH("Aux Capture Switch", 0, DAC_CTRL, DAC_CTRL_ONAUXIN, 0x01, 0),
+{
+	.iface	= SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name	= "Line Capture Volume",
+	.index	= 0,
+	.info	= snd_at73c213_line_capture_volume_info,
+	.get	= snd_at73c213_stereo_get,
+	.put	= snd_at73c213_stereo_put,
+	.private_value	= DAC_LLIG|(DAC_RLIG<<8)|(0<<16)|(0<<19)|(0x1F<<24)|(1<<22),
+},
+AT73C213_MONO_SWITCH("Line Capture Switch", 0, DAC_CTRL, 0, 0x03, 0),
+};
+
+static int __devinit snd_at73c213_mixer(struct snd_at73c213 *chip)
+{
+	struct snd_card *card;
+	int errval, idx;
+
+	if (chip == NULL || chip->pcm == NULL)
+		return -EINVAL;
+
+	card = chip->card;
+
+	strcpy(card->mixername, chip->pcm->name);
+
+	for (idx = 0; idx < ARRAY_SIZE(snd_at73c213_controls); idx++) {
+		if ((errval = snd_ctl_add(card,
+				snd_ctl_new1(&snd_at73c213_controls[idx],
+				chip))) < 0) {
+			goto cleanup;
+		}
+	}
+
+	return 0;
+
+cleanup:
+	for (idx = 1; idx < ARRAY_SIZE(snd_at73c213_controls) + 1; idx++) {
+		struct snd_kcontrol *kctl;
+		kctl = snd_ctl_find_numid(card, idx);
+		if (kctl)
+			snd_ctl_remove(card, kctl);
+	}
+	return errval;
+}
+
+/*
+ * Device functions
+ */
+static int snd_at73c213_chip_init(struct snd_at73c213 *chip)
+{
+	int retval;
+	unsigned char dac_ctrl = 0;
+
+	retval = snd_at73c213_set_bitrate(chip);
+	if (retval)
+		goto out;
+
+	/* enable DAC master clock */
+	clk_enable(chip->dac_clk);
+
+	/* initialize at73c213 on SPI bus */
+	write_reg(chip, DAC_RST, 0x04);
+	msleep(1);
+	write_reg(chip, DAC_RST, 0x03);
+
+	/* precharge everything */
+	write_reg(chip, DAC_PRECH, 0xFF);
+	write_reg(chip, PA_CTRL, (1<<PA_CTRL_APAPRECH));
+	write_reg(chip, DAC_CTRL, (1<<DAC_CTRL_ONLNOL)|(1<<DAC_CTRL_ONLNOR));
+
+	msleep(50);
+
+	/* stop precharging PA */
+	write_reg(chip, PA_CTRL, (1<<PA_CTRL_APALP)|0x0F);
+	chip->image[PA_CTRL] = (1<<PA_CTRL_APALP)|0x0F;
+
+	msleep(450);
+
+	/* stop precharging DAC, turn on master power */
+	write_reg(chip, DAC_PRECH, (1<<DAC_PRECH_ONMSTR));
+	chip->image[DAC_PRECH] = (1<<DAC_PRECH_ONMSTR);
+
+	msleep(1);
+
+	/* turn on DAC */
+	dac_ctrl = (1<<DAC_CTRL_ONDACL)|(1<<DAC_CTRL_ONDACR)|
+			(1<<DAC_CTRL_ONLNOL)|(1<<DAC_CTRL_ONLNOR);
+
+	write_reg(chip, DAC_CTRL, dac_ctrl);
+	chip->image[DAC_CTRL] = dac_ctrl;
+
+	/* mute sound */
+	write_reg(chip, DAC_LMPG, 0x3F);
+	chip->image[DAC_LMPG] = 0x3F;
+	write_reg(chip, DAC_RMPG, 0x3F);
+	chip->image[DAC_RMPG] = 0x3F;
+	write_reg(chip, DAC_LLOG, 0x3F);
+	chip->image[DAC_LLOG] = 0x3F;
+	write_reg(chip, DAC_RLOG, 0x3F);
+	chip->image[DAC_RLOG] = 0x3F;
+	write_reg(chip, DAC_LLIG, 0x11);
+	chip->image[DAC_LLIG] = 0x11;
+	write_reg(chip, DAC_RLIG, 0x11);
+	chip->image[DAC_RLIG] = 0x11;
+	write_reg(chip, DAC_AUXG, 0x11);
+	chip->image[DAC_AUXG] = 0x11;
+
+	/* enable I2S clock */
+	retval = ssc_enable(chip->ssc, 1, 0);
+out:
+	return retval;
+}
+
+static int snd_at73c213_dev_free(struct snd_device *device)
+{
+	struct snd_at73c213 *chip = device->device_data;
+
+	ssc_disable(chip->ssc, 1, 0);
+	if (chip->irq >= 0) {
+		free_irq(chip->irq, chip);
+		chip->irq = -1;
+	}
+	ssc_free(chip->ssc);
+
+	return 0;
+}
+
+static int __devinit snd_at73c213_init(struct snd_card *card,
+					 struct spi_device *spi)
+{
+	static struct snd_device_ops ops = {
+		.dev_free	= snd_at73c213_dev_free,
+	};
+	struct snd_at73c213 *chip = get_chip(card);
+	int irq, retval;
+
+	irq = ssc_to_irq(chip->ssc);
+	if (irq < 0)
+		return irq;
+
+	spin_lock_init(&chip->lock);
+	chip->card = card;
+	chip->irq = -1;
+
+	retval = -ENOMEM;
+
+	retval = spi_setup(chip->spi);
+	if (retval)
+		goto cleanup;
+
+	retval = request_irq(irq, snd_at73c213_interrupt, 0, "at73c213", chip);
+	if (retval) {
+		snd_printk("unable to request irq %d\n", irq);
+		goto cleanup;
+	}
+	chip->irq = irq;
+
+	memcpy(&chip->image, &snd_at73c213_original_image,
+			sizeof(snd_at73c213_original_image));
+
+	retval = snd_at73c213_chip_init(chip);
+	if (retval)
+		goto cleanup;
+
+	retval = snd_at73c213_pcm_new(chip, 0);
+	if (retval)
+		goto cleanup;
+
+	retval = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+	if (retval)
+		goto cleanup;
+
+	retval = snd_at73c213_mixer(chip);
+	if (retval)
+		goto cleanup;
+
+	snd_card_set_dev(card, &spi->dev);
+
+	return retval;
+
+cleanup:
+	if (!list_empty(&card->devices))
+		snd_device_free(card, chip);
+	if (chip->pcm)
+		dev_dbg(&spi->dev, "FIXME: howto free pcm?\n");
+	if (chip->irq >= 0) {
+		free_irq(chip->irq, chip);
+		chip->irq = -1;
+	}
+	return retval;
+}
+
+static int snd_at73c213_probe(struct spi_device *spi)
+{
+	struct at73c213_board_info	*info;
+	struct clk			*dac_clk;
+	struct snd_card			*card;
+	struct snd_at73c213		*chip;
+	int				retval;
+	char				id[16];
+
+	info = spi->dev.platform_data;
+	if (!info) {
+		dev_dbg(&spi->dev, "no platform_data\n");
+		return -ENXIO;
+	}
+
+	dac_clk = clk_get(NULL, info->dac_clk);
+	if (IS_ERR(dac_clk)) {
+		dev_dbg(&spi->dev, "unable to get DAC clk '%s'\n",
+				info->dac_clk);
+		return (PTR_ERR(dac_clk));
+	}
+
+	retval = -ENOMEM;
+
+	/* allocate "card" using some unused identifiers */
+	snprintf(id, sizeof id, "at73c213_%d", info->i2s_dev);
+	card = snd_card_new(-1, id, THIS_MODULE, sizeof(struct snd_at73c213));
+	if (!card)
+		goto cleanup_card;
+
+	chip = card->private_data;
+	chip->spi = spi;
+	chip->info = info;
+	chip->dac_clk = dac_clk;
+
+	chip->ssc = ssc_request(info->i2s_dev);
+	if (IS_ERR(chip->ssc)) {
+		dev_dbg(&spi->dev, "could not get ssc%d device\n",
+				info->i2s_dev);
+		retval = (PTR_ERR(chip->ssc));
+		goto cleanup;
+	}
+
+	retval = snd_at73c213_init(card, spi);
+	if (retval)
+		goto cleanup;
+
+	strcpy(card->driver, "at73c213");
+	strcpy(card->shortname, info->shortname);
+	sprintf(card->longname, "%s on irq %d", card->shortname, chip->irq);
+
+	retval = snd_card_register(card);
+	if (retval)
+		goto cleanup;
+
+	dev_set_drvdata(&spi->dev, card);
+	return 0;
+
+cleanup:
+	if (IS_ERR(chip->ssc))
+		ssc_free(chip->ssc);
+	if (card)
+		snd_card_free(card);
+cleanup_card:
+	if (dac_clk)
+		clk_put(dac_clk);
+	return retval;
+}
+
+static int __devexit snd_at73c213_remove(struct spi_device *spi)
+{
+	struct snd_card *card = dev_get_drvdata(&spi->dev);
+	struct snd_at73c213 *chip = card->private_data;
+	int retval;
+
+	/* Stop playback */
+	ssc_disable(chip->ssc, 1, 0);
+
+	/* Mute sound */
+	write_reg(chip, DAC_LMPG, 0x3F);
+	chip->image[DAC_LMPG] = 0x3F;
+	write_reg(chip, DAC_RMPG, 0x3F);
+	chip->image[DAC_RMPG] = 0x3F;
+	write_reg(chip, DAC_LLOG, 0x3F);
+	chip->image[DAC_LLOG] = 0x3F;
+	write_reg(chip, DAC_RLOG, 0x3F);
+	chip->image[DAC_RLOG] = 0x3F;
+	write_reg(chip, DAC_LLIG, 0x11);
+	chip->image[DAC_LLIG] = 0x11;
+	write_reg(chip, DAC_RLIG, 0x11);
+	chip->image[DAC_RLIG] = 0x11;
+	write_reg(chip, DAC_AUXG, 0x11);
+	chip->image[DAC_AUXG] = 0x11;
+
+	/* Turn off PA */
+	write_reg(chip, PA_CTRL, (chip->image[PA_CTRL]|0x0F));
+	chip->image[PA_CTRL] |= 0x0F;
+	msleep(10);
+	write_reg(chip, PA_CTRL, (1<<PA_CTRL_APALP)|0x0F);
+	chip->image[PA_CTRL] = (1<<PA_CTRL_APALP)|0x0F;
+
+	/* Turn off external DAC */
+	write_reg(chip, DAC_CTRL, 0x0C);
+	chip->image[DAC_CTRL] = 0x0C;
+	msleep(2);
+	write_reg(chip, DAC_CTRL, 0x00);
+	chip->image[DAC_CTRL] = 0x00;
+
+	/* Turn off master power */
+	write_reg(chip, DAC_PRECH, 0x00);
+	chip->image[DAC_PRECH] = 0x00;
+
+	/* Stop DAC master clock */
+	if (chip->dac_clk) {
+		clk_disable(chip->dac_clk);
+		clk_put(chip->dac_clk);
+	}
+
+out:
+	if (card) {
+		snd_card_free(card);
+		dev_set_drvdata(&spi->dev, NULL);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int snd_at73c213_suspend(struct spi_device *spi, pm_message_t msg)
+{
+	struct snd_card *card = dev_get_drvdata(&spi->dev);
+	struct snd_at73c213 *chip = card->private_data;
+
+	ssc_disable(chip->ssc, 1, 0);
+	clk_disable(chip->dac_clk);
+
+	return 0;
+}
+
+static int snd_at73c213_resume(struct spi_device *spi)
+{
+	struct snd_card *card = dev_get_drvdata(&spi->dev);
+	struct snd_at73c213 *chip = card->private_data;
+
+	clk_enable(chip->dac_clk);
+	ssc_enable(chip->ssc, 1, 0);
+
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+/* Driver core initialization */
+static struct spi_driver at73c213_driver = {
+	.driver		= {
+		.name	= "at73c213",
+	},
+	.probe		= snd_at73c213_probe,
+#ifdef CONFIG_PM
+	.suspend	= snd_at73c213_suspend,
+	.resume		= snd_at73c213_resume,
+#endif
+	.remove		= __devexit_p(snd_at73c213_remove),
+};
+
+static int __init at73c213_init(void)
+{
+	return spi_register_driver(&at73c213_driver);
+}
+module_init(at73c213_init);
+
+static void __exit at73c213_exit(void)
+{
+	spi_unregister_driver(&at73c213_driver);
+}
+module_exit(at73c213_exit);
+
+MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
+MODULE_DESCRIPTION("Sound driver for AT73C213 with Atmel SSC");
+MODULE_LICENSE("GPL");
diff --git a/sound/spi/at73c213.h b/sound/spi/at73c213.h
new file mode 100644
index 0000000..fd8b372
--- /dev/null
+++ b/sound/spi/at73c213.h
@@ -0,0 +1,119 @@
+/*
+ * Driver for the AT73C213 16-bit stereo DAC on Atmel ATSTK1000
+ *
+ * Copyright (C) 2006 - 2007 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this
+ * distribution in the file called COPYING.
+ */
+
+#ifndef _SND_AT73C213_H
+#define _SND_AT73C213_H
+
+/* DAC control register */
+#define DAC_CTRL		0x00
+#define DAC_CTRL_ONPADRV	7
+#define DAC_CTRL_ONAUXIN	6
+#define DAC_CTRL_ONDACR		5
+#define DAC_CTRL_ONDACL		4
+#define DAC_CTRL_ONLNOR		3
+#define DAC_CTRL_ONLNOL		2
+#define DAC_CTRL_ONLNIR		1
+#define DAC_CTRL_ONLNIL		0
+
+/* DAC left line in gain register */
+#define DAC_LLIG		0x01
+#define DAC_LLIG_LLIG		0
+
+/* DAC right line in gain register */
+#define DAC_RLIG		0x02
+#define DAC_RLIG_RLIG		0
+
+/* DAC Left Master Playback Gain Register */
+#define DAC_LMPG		0x03
+#define DAC_LMPG_LMPG		0
+
+/* DAC Right Master Playback Gain Register */
+#define DAC_RMPG		0x04
+#define DAC_RMPG_RMPG		0
+
+/* DAC Left Line Out Gain Register */
+#define DAC_LLOG		0x05
+#define DAC_LLOG_LLOG		0
+
+/* DAC Right Line Out Gain Register */
+#define DAC_RLOG		0x06
+#define DAC_RLOG_RLOG		0
+
+/* DAC Output Level Control Register */
+#define DAC_OLC			0x07
+#define DAC_OLC_RSHORT		7
+#define DAC_OLC_ROLC		4
+#define DAC_OLC_LSHORT		3
+#define DAC_OLC_LOLC		0
+
+/* DAC Mixer Control Register */
+#define DAC_MC			0x08
+#define DAC_MC_INVR		5
+#define DAC_MC_INVL		4
+#define DAC_MC_RMSMIN2		3
+#define DAC_MC_RMSMIN1		2
+#define DAC_MC_LMSMIN2		1
+#define DAC_MC_LMSMIN1		0
+
+/* DAC Clock and Sampling Frequency Control Register */
+#define DAC_CSFC		0x09
+#define DAC_CSFC_OVRSEL		4
+
+/* DAC Miscellaneous Register */
+#define DAC_MISC		0x0A
+#define DAC_MISC_VCMCAPSEL	7
+#define DAC_MISC_DINTSEL	4
+#define DAC_MISC_DITHEN		3
+#define DAC_MISC_DEEMPEN	2
+#define DAC_MISC_NBITS		0
+
+/* DAC Precharge Control Register */
+#define DAC_PRECH		0x0C
+#define DAC_PRECH_PRCHGPDRV	7
+#define DAC_PRECH_PRCHGAUX1	6
+#define DAC_PRECH_PRCHGLNOR	5
+#define DAC_PRECH_PRCHGLNOL	4
+#define DAC_PRECH_PRCHGLNIR	3
+#define DAC_PRECH_PRCHGLNIL	2
+#define DAC_PRECH_PRCHG		1
+#define DAC_PRECH_ONMSTR	0
+
+/* DAC Auxiliary Input Gain Control Register */
+#define DAC_AUXG		0x0D
+#define DAC_AUXG_AUXG		0
+
+/* DAC Reset Register */
+#define DAC_RST			0x10
+#define DAC_RST_RESMASK		2
+#define DAC_RST_RESFILZ		1
+#define DAC_RST_RSTZ		0
+
+/* Power Amplifier Control Register */
+#define PA_CTRL			0x11
+#define PA_CTRL_APAON		6
+#define PA_CTRL_APAPRECH	5
+#define PA_CTRL_APALP		4
+#define PA_CTRL_APAGAIN		0
+
+#endif /* _SND_AT73C213_H */