Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/arch/arm/mach-omap/Kconfig b/arch/arm/mach-omap/Kconfig
new file mode 100644
index 0000000..9e42efa
--- /dev/null
+++ b/arch/arm/mach-omap/Kconfig
@@ -0,0 +1,221 @@
+if ARCH_OMAP
+
+menu "TI OMAP Implementations"
+
+comment "OMAP Core Type"
+
+config ARCH_OMAP730
+	depends on ARCH_OMAP
+	bool "OMAP730 Based System"
+	select ARCH_OMAP_OTG
+
+config ARCH_OMAP1510
+	depends on ARCH_OMAP
+	default y
+	bool "OMAP1510 Based System"
+
+config ARCH_OMAP16XX
+	depends on ARCH_OMAP
+	bool "OMAP16XX Based System"
+	select ARCH_OMAP_OTG
+
+config ARCH_OMAP_OTG
+	bool
+
+comment "OMAP Board Type"
+
+config MACH_OMAP_INNOVATOR
+	bool "TI Innovator"
+	depends on ARCH_OMAP1510 || ARCH_OMAP16XX
+	help
+          TI OMAP 1510 or 1610 Innovator board support. Say Y here if you
+          have such a board.
+
+config MACH_OMAP_H2
+	bool "TI H2 Support"
+	depends on ARCH_OMAP16XX
+    	help
+	  TI OMAP 1610/1611B H2 board support. Say Y here if you have such
+	  a board.
+
+config MACH_OMAP_H3
+	bool "TI H3 Support"
+	depends on ARCH_OMAP16XX
+    	help
+	  TI OMAP 1710 H3 board support. Say Y here if you have such
+	  a board.
+
+config MACH_OMAP_H4
+	bool "TI H4 Support"
+	depends on ARCH_OMAP16XX
+    	help
+	  TI OMAP 1610 H4 board support. Say Y here if you have such
+	  a board.
+
+config MACH_OMAP_OSK
+	bool "TI OSK Support"
+	depends on ARCH_OMAP16XX
+    	help
+	  TI OMAP 5912 OSK (OMAP Starter Kit) board support. Say Y here
+          if you have such a board.
+
+config MACH_OMAP_PERSEUS2
+	bool "TI Perseus2"
+	depends on ARCH_OMAP730
+    	help
+	  Support for TI OMAP 730 Perseus2 board. Say Y here if you have such
+	  a board.
+
+config MACH_VOICEBLUE
+	bool "Voiceblue"
+	depends on ARCH_OMAP1510
+	help
+	  Support for Voiceblue GSM/VoIP gateway. Say Y here if you have such
+	  board.
+
+config MACH_NETSTAR
+	bool "NetStar"
+	depends on ARCH_OMAP1510
+	help
+	  Support for NetStar PBX. Say Y here if you have such a board.
+
+config MACH_OMAP_GENERIC
+	bool "Generic OMAP board"
+	depends on ARCH_OMAP1510 || ARCH_OMAP16XX
+	help
+          Support for generic OMAP-1510, 1610 or 1710 board with
+          no FPGA. Can be used as template for porting Linux to
+          custom OMAP boards. Say Y here if you have a custom
+          board.
+
+comment "OMAP Feature Selections"
+
+#config OMAP_BOOT_TAG
+#	bool "OMAP bootloader information passing"
+#        depends on ARCH_OMAP
+#        default n
+#        help
+#          Say Y, if you have a bootloader which passes information
+#          about your board and its peripheral configuration.
+
+config OMAP_MUX
+	bool "OMAP multiplexing support"
+        depends on ARCH_OMAP
+	default y
+        help
+          Pin multiplexing support for OMAP boards. If your bootloader
+          sets the multiplexing correctly, say N. Otherwise, or if unsure,
+          say Y.
+
+config OMAP_MUX_DEBUG
+	bool "Multiplexing debug output"
+        depends on OMAP_MUX
+        default n
+        help
+          Makes the multiplexing functions print out a lot of debug info.
+          This is useful if you want to find out the correct values of the
+          multiplexing registers.
+
+config OMAP_MUX_WARNINGS
+	bool "Warn about pins the bootloader didn't set up"
+        depends on OMAP_MUX
+        default y
+        help
+	  Choose Y here to warn whenever driver initialization logic needs
+	  to change the pin multiplexing setup.  When there are no warnings
+	  printed, it's safe to deselect OMAP_MUX for your product.
+
+choice
+        prompt "System timer"
+	default OMAP_MPU_TIMER
+
+config OMAP_MPU_TIMER
+	bool "Use mpu timer"
+	help
+	  Select this option if you want to use the OMAP mpu timer. This
+	  timer provides more intra-tick resolution than the 32KHz timer,
+	  but consumes more power.
+
+config OMAP_32K_TIMER
+	bool "Use 32KHz timer"
+	depends on ARCH_OMAP16XX
+	help
+	  Select this option if you want to enable the OMAP 32KHz timer.
+	  This timer saves power compared to the OMAP_MPU_TIMER, and has
+	  support for no tick during idle. The 32KHz timer provides less
+	  intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is
+	  currently only available for OMAP-16xx.
+
+endchoice
+
+config OMAP_32K_TIMER_HZ
+       int "Kernel internal timer frequency for 32KHz timer"
+       range 32 1024
+       depends on OMAP_32K_TIMER
+       default "128"
+       help
+	  Kernel internal timer frequency should be a divisor of 32768,
+	  such as 64 or 128.
+
+choice
+	prompt "Low-level debug console UART"
+	depends on ARCH_OMAP
+	default OMAP_LL_DEBUG_UART1
+
+config OMAP_LL_DEBUG_UART1
+	bool "UART1"
+
+config OMAP_LL_DEBUG_UART2
+	bool "UART2"
+
+config OMAP_LL_DEBUG_UART3
+	bool "UART3"
+
+endchoice
+
+config OMAP_ARM_195MHZ
+	bool "OMAP ARM 195 MHz CPU"
+	depends on ARCH_OMAP730
+	help
+          Enable 195MHz clock for OMAP CPU. If unsure, say N.
+
+config OMAP_ARM_192MHZ
+	bool "OMAP ARM 192 MHz CPU"
+	depends on ARCH_OMAP16XX
+	help
+          Enable 192MHz clock for OMAP CPU. If unsure, say N.
+
+config OMAP_ARM_182MHZ
+	bool "OMAP ARM 182 MHz CPU"
+	depends on ARCH_OMAP730
+	help
+          Enable 182MHz clock for OMAP CPU. If unsure, say N.
+
+config OMAP_ARM_168MHZ
+	bool "OMAP ARM 168 MHz CPU"
+	depends on ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730
+	help
+          Enable 168MHz clock for OMAP CPU. If unsure, say N.
+
+config OMAP_ARM_120MHZ
+	bool "OMAP ARM 120 MHz CPU"
+	depends on ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730
+	help
+          Enable 120MHz clock for OMAP CPU. If unsure, say N.
+
+config OMAP_ARM_60MHZ
+	bool "OMAP ARM 60 MHz CPU"
+	depends on ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730
+        default y
+	help
+          Enable 60MHz clock for OMAP CPU. If unsure, say Y.
+
+config OMAP_ARM_30MHZ
+	bool "OMAP ARM 30 MHz CPU"
+	depends on ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730
+	help
+          Enable 30MHz clock for OMAP CPU. If unsure, say N.
+
+endmenu
+
+endif
diff --git a/arch/arm/mach-omap/Makefile b/arch/arm/mach-omap/Makefile
new file mode 100644
index 0000000..4cafb11
--- /dev/null
+++ b/arch/arm/mach-omap/Makefile
@@ -0,0 +1,40 @@
+#
+# Makefile for the linux kernel.
+#
+
+# Common support
+obj-y := common.o time.o irq.o dma.o clock.o mux.o gpio.o mcbsp.o usb.o
+obj-m :=
+obj-n :=
+obj-  :=
+led-y := leds.o
+
+# Specific board support
+obj-$(CONFIG_MACH_OMAP_H2) += board-h2.o
+obj-$(CONFIG_MACH_OMAP_INNOVATOR) += board-innovator.o
+obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o
+obj-$(CONFIG_MACH_OMAP_PERSEUS2) += board-perseus2.o
+obj-$(CONFIG_MACH_OMAP_OSK) += board-osk.o
+obj-$(CONFIG_MACH_OMAP_H3) += board-h3.o
+obj-$(CONFIG_MACH_VOICEBLUE) += board-voiceblue.o
+obj-$(CONFIG_MACH_NETSTAR) += board-netstar.o
+
+# OCPI interconnect support for 1710, 1610 and 5912
+obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
+
+# LEDs support
+led-$(CONFIG_MACH_OMAP_H2) += leds-h2p2-debug.o
+led-$(CONFIG_MACH_OMAP_INNOVATOR) += leds-innovator.o
+led-$(CONFIG_MACH_OMAP_PERSEUS2) += leds-h2p2-debug.o
+obj-$(CONFIG_LEDS) += $(led-y)
+
+# Power Management
+obj-$(CONFIG_PM) += pm.o sleep.o
+
+ifeq ($(CONFIG_ARCH_OMAP1510),y)
+# Innovator-1510 FPGA
+obj-$(CONFIG_MACH_OMAP_INNOVATOR) += fpga.o
+endif
+
+# kgdb support
+obj-$(CONFIG_KGDB_SERIAL)	+= kgdb-serial.o
diff --git a/arch/arm/mach-omap/Makefile.boot b/arch/arm/mach-omap/Makefile.boot
new file mode 100644
index 0000000..fee1a6a
--- /dev/null
+++ b/arch/arm/mach-omap/Makefile.boot
@@ -0,0 +1,4 @@
+   zreladdr-y		:= 0x10008000
+params_phys-y		:= 0x10000100
+initrd_phys-y		:= 0x10800000
+
diff --git a/arch/arm/mach-omap/board-generic.c b/arch/arm/mach-omap/board-generic.c
new file mode 100644
index 0000000..2102a2c
--- /dev/null
+++ b/arch/arm/mach-omap/board-generic.c
@@ -0,0 +1,98 @@
+/*
+ * linux/arch/arm/mach-omap/board-generic.c
+ *
+ * Modified from board-innovator1510.c
+ *
+ * Code for generic OMAP board. Should work on many OMAP systems where
+ * the device drivers take care of all the necessary hardware initialization.
+ * Do not put any board specific code to this file; create a new machine
+ * type if you need custom low-level initializations.
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/usb.h>
+#include <asm/arch/board.h>
+
+#include "common.h"
+
+static int __initdata generic_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
+
+static void __init omap_generic_init_irq(void)
+{
+	omap_init_irq();
+}
+
+/* assume no Mini-AB port */
+
+#ifdef CONFIG_ARCH_OMAP1510
+static struct omap_usb_config generic1510_usb_config __initdata = {
+	.register_host	= 1,
+	.register_dev	= 1,
+	.hmc_mode	= 16,
+	.pins[0]	= 3,
+};
+#endif
+
+#if defined(CONFIG_ARCH_OMAP16XX)
+static struct omap_usb_config generic1610_usb_config __initdata = {
+	.register_host	= 1,
+	.register_dev	= 1,
+	.hmc_mode	= 16,
+	.pins[0]	= 6,
+};
+#endif
+
+static struct omap_board_config_kernel generic_config[] = {
+	{ OMAP_TAG_USB,           NULL },
+};
+
+static void __init omap_generic_init(void)
+{
+	/*
+	 * Make sure the serial ports are muxed on at this point.
+	 * You have to mux them off in device drivers later on
+	 * if not needed.
+	 */
+#ifdef CONFIG_ARCH_OMAP1510
+	if (cpu_is_omap1510()) {
+		generic_config[0].data = &generic1510_usb_config;
+	}
+#endif
+#if defined(CONFIG_ARCH_OMAP16XX)
+	if (!cpu_is_omap1510()) {
+		generic_config[0].data = &generic1610_usb_config;
+	}
+#endif
+	omap_board_config = generic_config;
+	omap_board_config_size = ARRAY_SIZE(generic_config);
+	omap_serial_init(generic_serial_ports);
+}
+
+static void __init omap_generic_map_io(void)
+{
+	omap_map_io();
+}
+
+MACHINE_START(OMAP_GENERIC, "Generic OMAP1510/1610/1710")
+	MAINTAINER("Tony Lindgren <tony@atomide.com>")
+	BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000)
+	BOOT_PARAMS(0x10000100)
+	MAPIO(omap_generic_map_io)
+	INITIRQ(omap_generic_init_irq)
+	INIT_MACHINE(omap_generic_init)
+	.timer		= &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap/board-h2.c b/arch/arm/mach-omap/board-h2.c
new file mode 100644
index 0000000..1f06783
--- /dev/null
+++ b/arch/arm/mach-omap/board-h2.c
@@ -0,0 +1,187 @@
+/*
+ * linux/arch/arm/mach-omap/board-h2.c
+ *
+ * Board specific inits for OMAP-1610 H2
+ *
+ * Copyright (C) 2001 RidgeRun, Inc.
+ * Author: Greg Lonnon <glonnon@ridgerun.com>
+ *
+ * Copyright (C) 2002 MontaVista Software, Inc.
+ *
+ * Separated FPGA interrupts from innovator1510.c and cleaned up for 2.6
+ * Copyright (C) 2004 Nokia Corporation by Tony Lindrgen <tony@atomide.com>
+ *
+ * H2 specific changes and cleanup
+ * Copyright (C) 2004 Nokia Corporation by Imre Deak <imre.deak@nokia.com>
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/tc.h>
+#include <asm/arch/usb.h>
+
+#include "common.h"
+
+extern int omap_gpio_init(void);
+
+static int __initdata h2_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
+
+static struct mtd_partition h2_partitions[] = {
+	/* bootloader (U-Boot, etc) in first sector */
+	{
+	      .name		= "bootloader",
+	      .offset		= 0,
+	      .size		= SZ_128K,
+	      .mask_flags	= MTD_WRITEABLE, /* force read-only */
+	},
+	/* bootloader params in the next sector */
+	{
+	      .name		= "params",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= SZ_128K,
+	      .mask_flags	= 0,
+	},
+	/* kernel */
+	{
+	      .name		= "kernel",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= SZ_2M,
+	      .mask_flags	= 0
+	},
+	/* file system */
+	{
+	      .name		= "filesystem",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= MTDPART_SIZ_FULL,
+	      .mask_flags	= 0
+	}
+};
+
+static struct flash_platform_data h2_flash_data = {
+	.map_name	= "cfi_probe",
+	.width		= 2,
+	.parts		= h2_partitions,
+	.nr_parts	= ARRAY_SIZE(h2_partitions),
+};
+
+static struct resource h2_flash_resource = {
+	.start		= OMAP_CS2B_PHYS,
+	.end		= OMAP_CS2B_PHYS + OMAP_CS2B_SIZE - 1,
+	.flags		= IORESOURCE_MEM,
+};
+
+static struct platform_device h2_flash_device = {
+	.name		= "omapflash",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &h2_flash_data,
+	},
+	.num_resources	= 1,
+	.resource	= &h2_flash_resource,
+};
+
+static struct resource h2_smc91x_resources[] = {
+	[0] = {
+		.start	= OMAP1610_ETHR_START,		/* Physical */
+		.end	= OMAP1610_ETHR_START + 0xf,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= OMAP_GPIO_IRQ(0),
+		.end	= OMAP_GPIO_IRQ(0),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device h2_smc91x_device = {
+	.name		= "smc91x",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(h2_smc91x_resources),
+	.resource	= h2_smc91x_resources,
+};
+
+static struct platform_device *h2_devices[] __initdata = {
+	&h2_flash_device,
+	&h2_smc91x_device,
+};
+
+static void __init h2_init_smc91x(void)
+{
+	if ((omap_request_gpio(0)) < 0) {
+		printk("Error requesting gpio 0 for smc91x irq\n");
+		return;
+	}
+	omap_set_gpio_edge_ctrl(0, OMAP_GPIO_FALLING_EDGE);
+}
+
+void h2_init_irq(void)
+{
+	omap_init_irq();
+	omap_gpio_init();
+	h2_init_smc91x();
+}
+
+static struct omap_usb_config h2_usb_config __initdata = {
+	/* usb1 has a Mini-AB port and external isp1301 transceiver */
+	.otg		= 2,
+
+#ifdef	CONFIG_USB_GADGET_OMAP
+	.hmc_mode	= 19,	// 0:host(off) 1:dev|otg 2:disabled
+	// .hmc_mode	= 21,	// 0:host(off) 1:dev(loopback) 2:host(loopback)
+#elif	defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+	/* needs OTG cable, or NONSTANDARD (B-to-MiniB) */
+	.hmc_mode	= 20,	// 1:dev|otg(off) 1:host 2:disabled
+#endif
+
+	.pins[1]	= 3,
+};
+
+static struct omap_mmc_config h2_mmc_config __initdata = {
+	.mmc_blocks		= 1,
+	.mmc1_power_pin		= -1,	/* tps65010 gpio3 */
+	.mmc1_switch_pin	= OMAP_MPUIO(1),
+};
+
+static struct omap_board_config_kernel h2_config[] = {
+	{ OMAP_TAG_USB,           &h2_usb_config },
+	{ OMAP_TAG_MMC,           &h2_mmc_config },
+};
+
+static void __init h2_init(void)
+{
+	platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices));
+	omap_board_config = h2_config;
+	omap_board_config_size = ARRAY_SIZE(h2_config);
+}
+
+static void __init h2_map_io(void)
+{
+	omap_map_io();
+	omap_serial_init(h2_serial_ports);
+}
+
+MACHINE_START(OMAP_H2, "TI-H2")
+	MAINTAINER("Imre Deak <imre.deak@nokia.com>")
+	BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000)
+	BOOT_PARAMS(0x10000100)
+	MAPIO(h2_map_io)
+	INITIRQ(h2_init_irq)
+	INIT_MACHINE(h2_init)
+	.timer		= &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap/board-h3.c b/arch/arm/mach-omap/board-h3.c
new file mode 100644
index 0000000..486a5a0
--- /dev/null
+++ b/arch/arm/mach-omap/board-h3.c
@@ -0,0 +1,205 @@
+/*
+ * linux/arch/arm/mach-omap/board-h3.c
+ *
+ * This file contains OMAP1710 H3 specific code.
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ * Copyright (C) 2002 MontaVista Software, Inc.
+ * Copyright (C) 2001 RidgeRun, Inc.
+ * Author: RidgeRun, Inc.
+ *         Greg Lonnon (glonnon@ridgerun.com) or info@ridgerun.com
+ *
+ * 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/config.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/major.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/setup.h>
+#include <asm/page.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/tc.h>
+#include <asm/arch/usb.h>
+
+#include "common.h"
+
+extern int omap_gpio_init(void);
+
+static int __initdata h3_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
+
+static struct mtd_partition h3_partitions[] = {
+	/* bootloader (U-Boot, etc) in first sector */
+	{
+	      .name		= "bootloader",
+	      .offset		= 0,
+	      .size		= SZ_128K,
+	      .mask_flags	= MTD_WRITEABLE, /* force read-only */
+	},
+	/* bootloader params in the next sector */
+	{
+	      .name		= "params",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= SZ_128K,
+	      .mask_flags	= 0,
+	},
+	/* kernel */
+	{
+	      .name		= "kernel",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= SZ_2M,
+	      .mask_flags	= 0
+	},
+	/* file system */
+	{
+	      .name		= "filesystem",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= MTDPART_SIZ_FULL,
+	      .mask_flags	= 0
+	}
+};
+
+static struct flash_platform_data h3_flash_data = {
+	.map_name	= "cfi_probe",
+	.width		= 2,
+	.parts		= h3_partitions,
+	.nr_parts	= ARRAY_SIZE(h3_partitions),
+};
+
+static struct resource h3_flash_resource = {
+	.start		= OMAP_CS2B_PHYS,
+	.end		= OMAP_CS2B_PHYS + OMAP_CS2B_SIZE - 1,
+	.flags		= IORESOURCE_MEM,
+};
+
+static struct platform_device flash_device = {
+	.name		= "omapflash",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &h3_flash_data,
+	},
+	.num_resources	= 1,
+	.resource	= &h3_flash_resource,
+};
+
+static struct resource smc91x_resources[] = {
+	[0] = {
+		.start	= OMAP1710_ETHR_START,		/* Physical */
+		.end	= OMAP1710_ETHR_START + 0xf,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= OMAP_GPIO_IRQ(40),
+		.end	= OMAP_GPIO_IRQ(40),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device smc91x_device = {
+	.name		= "smc91x",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(smc91x_resources),
+	.resource	= smc91x_resources,
+};
+
+#define GPTIMER_BASE		0xFFFB1400
+#define GPTIMER_REGS(x)	(0xFFFB1400 + (x * 0x800))
+#define GPTIMER_REGS_SIZE	0x46
+
+static struct resource intlat_resources[] = {
+	[0] = {
+		.start  = GPTIMER_REGS(0),	      /* Physical */
+		.end    = GPTIMER_REGS(0) + GPTIMER_REGS_SIZE,
+		.flags  = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start  = INT_1610_GPTIMER1,
+		.end    = INT_1610_GPTIMER1,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device intlat_device = {
+	.name	   = "omap_intlat",
+	.id	     = 0,
+	.num_resources  = ARRAY_SIZE(intlat_resources),
+	.resource       = intlat_resources,
+};
+
+static struct platform_device *devices[] __initdata = {
+	&flash_device,
+        &smc91x_device,
+	&intlat_device,
+};
+
+static struct omap_usb_config h3_usb_config __initdata = {
+	/* usb1 has a Mini-AB port and external isp1301 transceiver */
+	.otg	    = 2,
+
+#ifdef CONFIG_USB_GADGET_OMAP
+	.hmc_mode       = 19,   /* 0:host(off) 1:dev|otg 2:disabled */
+#elif  defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+	/* NONSTANDARD CABLE NEEDED (B-to-Mini-B) */
+	.hmc_mode       = 20,   /* 1:dev|otg(off) 1:host 2:disabled */
+#endif
+
+	.pins[1]	= 3,
+};
+
+static struct omap_board_config_kernel h3_config[] = {
+	{ OMAP_TAG_USB,	 &h3_usb_config },
+};
+
+static void __init h3_init(void)
+{
+	(void) platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
+static void __init h3_init_smc91x(void)
+{
+	omap_cfg_reg(W15_1710_GPIO40);
+	if (omap_request_gpio(40) < 0) {
+		printk("Error requesting gpio 40 for smc91x irq\n");
+		return;
+	}
+	omap_set_gpio_edge_ctrl(40, OMAP_GPIO_FALLING_EDGE);
+}
+
+void h3_init_irq(void)
+{
+	omap_init_irq();
+	omap_gpio_init();
+	h3_init_smc91x();
+}
+
+static void __init h3_map_io(void)
+{
+	omap_map_io();
+	omap_serial_init(h3_serial_ports);
+}
+
+MACHINE_START(OMAP_H3, "TI OMAP1710 H3 board")
+	MAINTAINER("Texas Instruments, Inc.")
+	BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000)
+	BOOT_PARAMS(0x10000100)
+	MAPIO(h3_map_io)
+	INITIRQ(h3_init_irq)
+	INIT_MACHINE(h3_init)
+	.timer		= &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap/board-innovator.c b/arch/arm/mach-omap/board-innovator.c
new file mode 100644
index 0000000..57cf4da
--- /dev/null
+++ b/arch/arm/mach-omap/board-innovator.c
@@ -0,0 +1,280 @@
+/*
+ * linux/arch/arm/mach-omap/board-innovator.c
+ *
+ * Board specific inits for OMAP-1510 and OMAP-1610 Innovator
+ *
+ * Copyright (C) 2001 RidgeRun, Inc.
+ * Author: Greg Lonnon <glonnon@ridgerun.com>
+ *
+ * Copyright (C) 2002 MontaVista Software, Inc.
+ *
+ * Separated FPGA interrupts from innovator1510.c and cleaned up for 2.6
+ * Copyright (C) 2004 Nokia Corporation by Tony Lindrgen <tony@atomide.com>
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/fpga.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/tc.h>
+#include <asm/arch/usb.h>
+
+#include "common.h"
+
+static int __initdata innovator_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
+
+static struct mtd_partition innovator_partitions[] = {
+	/* bootloader (U-Boot, etc) in first sector */
+	{
+	      .name		= "bootloader",
+	      .offset		= 0,
+	      .size		= SZ_128K,
+	      .mask_flags	= MTD_WRITEABLE, /* force read-only */
+	},
+	/* bootloader params in the next sector */
+	{
+	      .name		= "params",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= SZ_128K,
+	      .mask_flags	= 0,
+	},
+	/* kernel */
+	{
+	      .name		= "kernel",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= SZ_2M,
+	      .mask_flags	= 0
+	},
+	/* rest of flash1 is a file system */
+	{
+	      .name		= "rootfs",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= SZ_16M - SZ_2M - 2 * SZ_128K,
+	      .mask_flags	= 0
+	},
+	/* file system */
+	{
+	      .name		= "filesystem",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= MTDPART_SIZ_FULL,
+	      .mask_flags	= 0
+	}
+};
+
+static struct flash_platform_data innovator_flash_data = {
+	.map_name	= "cfi_probe",
+	.width		= 2,
+	.parts		= innovator_partitions,
+	.nr_parts	= ARRAY_SIZE(innovator_partitions),
+};
+
+static struct resource innovator_flash_resource = {
+	.start		= OMAP_CS0_PHYS,
+	.end		= OMAP_CS0_PHYS + SZ_32M - 1,
+	.flags		= IORESOURCE_MEM,
+};
+
+static struct platform_device innovator_flash_device = {
+	.name		= "omapflash",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &innovator_flash_data,
+	},
+	.num_resources	= 1,
+	.resource	= &innovator_flash_resource,
+};
+
+#ifdef CONFIG_ARCH_OMAP1510
+
+/* Only FPGA needs to be mapped here. All others are done with ioremap */
+static struct map_desc innovator1510_io_desc[] __initdata = {
+{ OMAP1510_FPGA_BASE, OMAP1510_FPGA_START, OMAP1510_FPGA_SIZE,
+	MT_DEVICE },
+};
+
+static struct resource innovator1510_smc91x_resources[] = {
+	[0] = {
+		.start	= OMAP1510_FPGA_ETHR_START,	/* Physical */
+		.end	= OMAP1510_FPGA_ETHR_START + 0xf,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= OMAP1510_INT_ETHER,
+		.end	= OMAP1510_INT_ETHER,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device innovator1510_smc91x_device = {
+	.name		= "smc91x",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(innovator1510_smc91x_resources),
+	.resource	= innovator1510_smc91x_resources,
+};
+
+static struct platform_device *innovator1510_devices[] __initdata = {
+	&innovator_flash_device,
+	&innovator1510_smc91x_device,
+};
+
+#endif /* CONFIG_ARCH_OMAP1510 */
+
+#ifdef CONFIG_ARCH_OMAP16XX
+
+static struct resource innovator1610_smc91x_resources[] = {
+	[0] = {
+		.start	= INNOVATOR1610_ETHR_START,		/* Physical */
+		.end	= INNOVATOR1610_ETHR_START + 0xf,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= OMAP_GPIO_IRQ(0),
+		.end	= OMAP_GPIO_IRQ(0),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device innovator1610_smc91x_device = {
+	.name		= "smc91x",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(innovator1610_smc91x_resources),
+	.resource	= innovator1610_smc91x_resources,
+};
+
+static struct platform_device *innovator1610_devices[] __initdata = {
+	&innovator_flash_device,
+	&innovator1610_smc91x_device,
+};
+
+#endif /* CONFIG_ARCH_OMAP16XX */
+
+static void __init innovator_init_smc91x(void)
+{
+	if (cpu_is_omap1510()) {
+		fpga_write(fpga_read(OMAP1510_FPGA_RST) & ~1,
+			   OMAP1510_FPGA_RST);
+		udelay(750);
+	} else {
+		if ((omap_request_gpio(0)) < 0) {
+			printk("Error requesting gpio 0 for smc91x irq\n");
+			return;
+		}
+		omap_set_gpio_edge_ctrl(0, OMAP_GPIO_RISING_EDGE);
+	}
+}
+
+void innovator_init_irq(void)
+{
+	omap_init_irq();
+	omap_gpio_init();
+#ifdef CONFIG_ARCH_OMAP1510
+	if (cpu_is_omap1510()) {
+		omap1510_fpga_init_irq();
+	}
+#endif
+	innovator_init_smc91x();
+}
+
+#ifdef CONFIG_ARCH_OMAP1510
+static struct omap_usb_config innovator1510_usb_config __initdata = {
+	/* for bundled non-standard host and peripheral cables */
+	.hmc_mode	= 4,
+
+	.register_host	= 1,
+	.pins[1]	= 6,
+	.pins[2]	= 6,		/* Conflicts with UART2 */
+
+	.register_dev	= 1,
+	.pins[0]	= 2,
+};
+#endif
+
+#ifdef CONFIG_ARCH_OMAP16XX
+static struct omap_usb_config h2_usb_config __initdata = {
+	/* usb1 has a Mini-AB port and external isp1301 transceiver */
+	.otg		= 2,
+
+#ifdef	CONFIG_USB_GADGET_OMAP
+	.hmc_mode	= 19,	// 0:host(off) 1:dev|otg 2:disabled
+	// .hmc_mode	= 21,	// 0:host(off) 1:dev(loopback) 2:host(loopback)
+#elif	defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+	/* NONSTANDARD CABLE NEEDED (B-to-Mini-B) */
+	.hmc_mode	= 20,	// 1:dev|otg(off) 1:host 2:disabled
+#endif
+
+	.pins[1]	= 3,
+};
+#endif
+
+static struct omap_board_config_kernel innovator_config[] = {
+	{ OMAP_TAG_USB,         NULL },
+};
+
+static void __init innovator_init(void)
+{
+#ifdef CONFIG_ARCH_OMAP1510
+	if (cpu_is_omap1510()) {
+		platform_add_devices(innovator1510_devices, ARRAY_SIZE(innovator1510_devices));
+	}
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
+	if (!cpu_is_omap1510()) {
+		platform_add_devices(innovator1610_devices, ARRAY_SIZE(innovator1610_devices));
+	}
+#endif
+
+#ifdef CONFIG_ARCH_OMAP1510
+	if (cpu_is_omap1510())
+		innovator_config[0].data = &innovator1510_usb_config;
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
+	if (cpu_is_omap1610())
+		innovator_config[0].data = &h2_usb_config;
+#endif
+	omap_board_config = innovator_config;
+	omap_board_config_size = ARRAY_SIZE(innovator_config);
+}
+
+static void __init innovator_map_io(void)
+{
+	omap_map_io();
+
+#ifdef CONFIG_ARCH_OMAP1510
+	if (cpu_is_omap1510()) {
+		iotable_init(innovator1510_io_desc, ARRAY_SIZE(innovator1510_io_desc));
+		udelay(10);	/* Delay needed for FPGA */
+
+		/* Dump the Innovator FPGA rev early - useful info for support. */
+		printk("Innovator FPGA Rev %d.%d Board Rev %d\n",
+		       fpga_read(OMAP1510_FPGA_REV_HIGH),
+		       fpga_read(OMAP1510_FPGA_REV_LOW),
+		       fpga_read(OMAP1510_FPGA_BOARD_REV));
+	}
+#endif
+	omap_serial_init(innovator_serial_ports);
+}
+
+MACHINE_START(OMAP_INNOVATOR, "TI-Innovator")
+	MAINTAINER("MontaVista Software, Inc.")
+	BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000)
+	BOOT_PARAMS(0x10000100)
+	MAPIO(innovator_map_io)
+	INITIRQ(innovator_init_irq)
+	INIT_MACHINE(innovator_init)
+	.timer		= &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap/board-netstar.c b/arch/arm/mach-omap/board-netstar.c
new file mode 100644
index 0000000..54acbd2
--- /dev/null
+++ b/arch/arm/mach-omap/board-netstar.c
@@ -0,0 +1,151 @@
+/*
+ * Modified from board-generic.c
+ *
+ * Copyright (C) 2004 2N Telekomunikace, Ladislav Michl <michl@2n.cz>
+ *
+ * Code for Netstar OMAP board.
+ *
+ * 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/device.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/usb.h>
+
+#include "common.h"
+
+extern void __init omap_init_time(void);
+extern int omap_gpio_init(void);
+
+static struct resource netstar_smc91x_resources[] = {
+	[0] = {
+		.start	= OMAP_CS1_PHYS + 0x300,
+		.end	= OMAP_CS1_PHYS + 0x300 + 16,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= OMAP_GPIO_IRQ(8),
+		.end	= OMAP_GPIO_IRQ(8),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device netstar_smc91x_device = {
+	.name		= "smc91x",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(netstar_smc91x_resources),
+	.resource	= netstar_smc91x_resources,
+};
+
+static struct platform_device *netstar_devices[] __initdata = {
+	&netstar_smc91x_device,
+};
+
+static void __init netstar_init_irq(void)
+{
+	omap_init_irq();
+	omap_gpio_init();
+}
+
+static void __init netstar_init(void)
+{
+	/* green LED */
+	omap_request_gpio(4);
+	omap_set_gpio_direction(4, 0);
+	/* smc91x reset */
+	omap_request_gpio(7);
+	omap_set_gpio_direction(7, 0);
+	omap_set_gpio_dataout(7, 1);
+	udelay(2);	/* wait at least 100ns */
+	omap_set_gpio_dataout(7, 0);
+	mdelay(50);	/* 50ms until PHY ready */
+	/* smc91x interrupt pin */
+	omap_request_gpio(8);
+	omap_set_gpio_edge_ctrl(8, OMAP_GPIO_RISING_EDGE);
+
+	omap_request_gpio(12);
+	omap_request_gpio(13);
+	omap_request_gpio(14);
+	omap_request_gpio(15);
+	omap_set_gpio_edge_ctrl(12, OMAP_GPIO_FALLING_EDGE);
+	omap_set_gpio_edge_ctrl(13, OMAP_GPIO_FALLING_EDGE);
+	omap_set_gpio_edge_ctrl(14, OMAP_GPIO_FALLING_EDGE);
+	omap_set_gpio_edge_ctrl(15, OMAP_GPIO_FALLING_EDGE);
+
+	platform_add_devices(netstar_devices, ARRAY_SIZE(netstar_devices));
+
+	/* Switch on green LED */
+	omap_set_gpio_dataout(4, 0);
+	/* Switch off red LED */
+	omap_writeb(0x00, OMAP_LPG1_PMR);	/* Disable clock */
+	omap_writeb(0x80, OMAP_LPG1_LCR);
+}
+
+static int __initdata omap_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
+
+static void __init netstar_map_io(void)
+{
+	omap_map_io();
+	omap_serial_init(omap_serial_ports);
+}
+
+#define MACHINE_PANICED		1
+#define MACHINE_REBOOTING	2
+#define MACHINE_REBOOT		4
+static unsigned long machine_state;
+
+static int panic_event(struct notifier_block *this, unsigned long event,
+	 void *ptr)
+{
+	if (test_and_set_bit(MACHINE_PANICED, &machine_state))
+		return NOTIFY_DONE;
+
+	/* Switch off green LED */
+	omap_set_gpio_dataout(4, 1);
+	/* Flash red LED */
+	omap_writeb(0x78, OMAP_LPG1_LCR);
+	omap_writeb(0x01, OMAP_LPG1_PMR);	/* Enable clock */
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block panic_block = {
+	.notifier_call	= panic_event,
+};
+
+static int __init netstar_late_init(void)
+{
+	/* TODO: Setup front panel switch here */
+
+	/* Setup panic notifier */
+	notifier_chain_register(&panic_notifier_list, &panic_block);
+
+	return 0;
+}
+
+postcore_initcall(netstar_late_init);
+
+MACHINE_START(NETSTAR, "NetStar OMAP5910")
+	MAINTAINER("Ladislav Michl <michl@2n.cz>")
+	BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000)
+	BOOT_PARAMS(0x10000100)
+	MAPIO(netstar_map_io)
+	INITIRQ(netstar_init_irq)
+	INIT_MACHINE(netstar_init)
+	.timer = &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap/board-osk.c b/arch/arm/mach-omap/board-osk.c
new file mode 100644
index 0000000..a951fc8
--- /dev/null
+++ b/arch/arm/mach-omap/board-osk.c
@@ -0,0 +1,169 @@
+/*
+ * linux/arch/arm/mach-omap/board-osk.c
+ *
+ * Board specific init for OMAP5912 OSK
+ *
+ * Written by Dirk Behme <dirk.behme@de.bosch.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.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/usb.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/tc.h>
+
+#include "common.h"
+
+static struct map_desc osk5912_io_desc[] __initdata = {
+{ OMAP_OSK_NOR_FLASH_BASE, OMAP_OSK_NOR_FLASH_START, OMAP_OSK_NOR_FLASH_SIZE,
+	MT_DEVICE },
+};
+
+static int __initdata osk_serial_ports[OMAP_MAX_NR_PORTS] = {1, 0, 0};
+
+static struct resource osk5912_smc91x_resources[] = {
+	[0] = {
+		.start	= OMAP_OSK_ETHR_START,		/* Physical */
+		.end	= OMAP_OSK_ETHR_START + 0xf,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= OMAP_GPIO_IRQ(0),
+		.end	= OMAP_GPIO_IRQ(0),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device osk5912_smc91x_device = {
+	.name		= "smc91x",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(osk5912_smc91x_resources),
+	.resource	= osk5912_smc91x_resources,
+};
+
+static struct resource osk5912_cf_resources[] = {
+	[0] = {
+		.start	= OMAP_GPIO_IRQ(62),
+		.end	= OMAP_GPIO_IRQ(62),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device osk5912_cf_device = {
+	.name		= "omap_cf",
+	.id		= -1,
+	.dev = {
+		.platform_data	= (void *) 2 /* CS2 */,
+	},
+	.num_resources	= ARRAY_SIZE(osk5912_cf_resources),
+	.resource	= osk5912_cf_resources,
+};
+
+static struct platform_device *osk5912_devices[] __initdata = {
+	&osk5912_smc91x_device,
+	&osk5912_cf_device,
+};
+
+static void __init osk_init_smc91x(void)
+{
+	if ((omap_request_gpio(0)) < 0) {
+		printk("Error requesting gpio 0 for smc91x irq\n");
+		return;
+	}
+	omap_set_gpio_edge_ctrl(0, OMAP_GPIO_RISING_EDGE);
+
+	/* Check EMIFS wait states to fix errors with SMC_GET_PKT_HDR */
+	EMIFS_CCS(1) |= 0x2;
+}
+
+static void __init osk_init_cf(void)
+{
+	omap_cfg_reg(M7_1610_GPIO62);
+	if ((omap_request_gpio(62)) < 0) {
+		printk("Error requesting gpio 62 for CF irq\n");
+		return;
+	}
+	/* it's really active-low */
+	omap_set_gpio_edge_ctrl(62, OMAP_GPIO_FALLING_EDGE);
+}
+
+void osk_init_irq(void)
+{
+	omap_init_irq();
+	omap_gpio_init();
+	osk_init_smc91x();
+	osk_init_cf();
+}
+
+static struct omap_usb_config osk_usb_config __initdata = {
+	/* has usb host connector (A) ... for development it can also
+	 * be used, with a NONSTANDARD gender-bending cable/dongle, as
+	 * a peripheral.
+	 */
+#ifdef	CONFIG_USB_GADGET_OMAP
+	.register_dev	= 1,
+	.hmc_mode	= 0,
+#else
+	.register_host	= 1,
+	.hmc_mode	= 16,
+	.rwc		= 1,
+#endif
+	.pins[0]	= 2,
+};
+
+static struct omap_board_config_kernel osk_config[] = {
+	{ OMAP_TAG_USB,           &osk_usb_config },
+};
+
+static void __init osk_init(void)
+{
+	platform_add_devices(osk5912_devices, ARRAY_SIZE(osk5912_devices));
+	omap_board_config = osk_config;
+	omap_board_config_size = ARRAY_SIZE(osk_config);
+	USB_TRANSCEIVER_CTRL_REG |= (3 << 1);
+}
+
+static void __init osk_map_io(void)
+{
+	omap_map_io();
+	iotable_init(osk5912_io_desc, ARRAY_SIZE(osk5912_io_desc));
+	omap_serial_init(osk_serial_ports);
+}
+
+MACHINE_START(OMAP_OSK, "TI-OSK")
+	MAINTAINER("Dirk Behme <dirk.behme@de.bosch.com>")
+	BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000)
+	BOOT_PARAMS(0x10000100)
+	MAPIO(osk_map_io)
+	INITIRQ(osk_init_irq)
+	INIT_MACHINE(osk_init)
+	.timer		= &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap/board-perseus2.c b/arch/arm/mach-omap/board-perseus2.c
new file mode 100644
index 0000000..64515ae
--- /dev/null
+++ b/arch/arm/mach-omap/board-perseus2.c
@@ -0,0 +1,189 @@
+/*
+ * linux/arch/arm/mach-omap/board-perseus2.c
+ *
+ * Modified from board-generic.c
+ *
+ * Original OMAP730 support by Jean Pihet <j-pihet@ti.com>
+ * Updated for 2.6 by Kevin Hilman <kjh@hilman.org>
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/fpga.h>
+
+#include "common.h"
+
+static struct resource smc91x_resources[] = {
+	[0] = {
+		.start	= H2P2_DBG_FPGA_ETHR_START,	/* Physical */
+		.end	= H2P2_DBG_FPGA_ETHR_START + 0xf,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= INT_730_MPU_EXT_NIRQ,
+		.end	= 0,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static int __initdata p2_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 0};
+
+static struct mtd_partition p2_partitions[] = {
+	/* bootloader (U-Boot, etc) in first sector */
+	{
+	      .name		= "bootloader",
+	      .offset		= 0,
+	      .size		= SZ_128K,
+	      .mask_flags	= MTD_WRITEABLE, /* force read-only */
+	},
+	/* bootloader params in the next sector */
+	{
+	      .name		= "params",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= SZ_128K,
+	      .mask_flags	= 0,
+	},
+	/* kernel */
+	{
+	      .name		= "kernel",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= SZ_2M,
+	      .mask_flags	= 0
+	},
+	/* rest of flash is a file system */
+	{
+	      .name		= "rootfs",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= MTDPART_SIZ_FULL,
+	      .mask_flags	= 0
+	},
+};
+
+static struct flash_platform_data p2_flash_data = {
+	.map_name	= "cfi_probe",
+	.width		= 2,
+	.parts		= p2_partitions,
+	.nr_parts	= ARRAY_SIZE(p2_partitions),
+};
+
+static struct resource p2_flash_resource = {
+	.start		= OMAP_FLASH_0_START,
+	.end		= OMAP_FLASH_0_START + OMAP_FLASH_0_SIZE - 1,
+	.flags		= IORESOURCE_MEM,
+};
+
+static struct platform_device p2_flash_device = {
+	.name		= "omapflash",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &p2_flash_data,
+	},
+	.num_resources	= 1,
+	.resource	= &p2_flash_resource,
+};
+
+static struct platform_device smc91x_device = {
+	.name		= "smc91x",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(smc91x_resources),
+	.resource	= smc91x_resources,
+};
+
+static struct platform_device *devices[] __initdata = {
+	&p2_flash_device,
+	&smc91x_device,
+};
+
+static void __init omap_perseus2_init(void)
+{
+	(void) platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
+static void __init perseus2_init_smc91x(void)
+{
+	fpga_write(1, H2P2_DBG_FPGA_LAN_RESET);
+	mdelay(50);
+	fpga_write(fpga_read(H2P2_DBG_FPGA_LAN_RESET) & ~1,
+		   H2P2_DBG_FPGA_LAN_RESET);
+	mdelay(50);
+}
+
+void omap_perseus2_init_irq(void)
+{
+	omap_init_irq();
+	omap_gpio_init();
+	perseus2_init_smc91x();
+}
+
+/* Only FPGA needs to be mapped here. All others are done with ioremap */
+static struct map_desc omap_perseus2_io_desc[] __initdata = {
+	{H2P2_DBG_FPGA_BASE, H2P2_DBG_FPGA_START, H2P2_DBG_FPGA_SIZE,
+	 MT_DEVICE},
+};
+
+static void __init omap_perseus2_map_io(void)
+{
+	omap_map_io();
+	iotable_init(omap_perseus2_io_desc,
+		     ARRAY_SIZE(omap_perseus2_io_desc));
+
+	/* Early, board-dependent init */
+
+	/*
+	 * Hold GSM Reset until needed
+	 */
+	omap_writew(omap_readw(OMAP730_DSP_M_CTL) & ~1, OMAP730_DSP_M_CTL);
+
+	/*
+	 * UARTs -> done automagically by 8250 driver
+	 */
+
+	/*
+	 * CSx timings, GPIO Mux ... setup
+	 */
+
+	/* Flash: CS0 timings setup */
+	omap_writel(0x0000fff3, OMAP730_FLASH_CFG_0);
+	omap_writel(0x00000088, OMAP730_FLASH_ACFG_0);
+
+	/*
+	 * Ethernet support trough the debug board
+	 * CS1 timings setup
+	 */
+	omap_writel(0x0000fff3, OMAP730_FLASH_CFG_1);
+	omap_writel(0x00000000, OMAP730_FLASH_ACFG_1);
+
+	/*
+	 * Configure MPU_EXT_NIRQ IO in IO_CONF9 register,
+	 * It is used as the Ethernet controller interrupt
+	 */
+	omap_writel(omap_readl(OMAP730_IO_CONF_9) & 0x1FFFFFFF, OMAP730_IO_CONF_9);
+	omap_serial_init(p2_serial_ports);
+}
+
+MACHINE_START(OMAP_PERSEUS2, "OMAP730 Perseus2")
+	MAINTAINER("Kevin Hilman <kjh@hilman.org>")
+	BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000)
+	BOOT_PARAMS(0x10000100)
+	MAPIO(omap_perseus2_map_io)
+	INITIRQ(omap_perseus2_init_irq)
+	INIT_MACHINE(omap_perseus2_init)
+	.timer		= &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap/board-voiceblue.c b/arch/arm/mach-omap/board-voiceblue.c
new file mode 100644
index 0000000..f1a5bff
--- /dev/null
+++ b/arch/arm/mach-omap/board-voiceblue.c
@@ -0,0 +1,256 @@
+/*
+ * linux/arch/arm/mach-omap/board-voiceblue.c
+ *
+ * Modified from board-generic.c
+ *
+ * Copyright (C) 2004 2N Telekomunikace, Ladislav Michl <michl@2n.cz>
+ *
+ * Code for OMAP5910 based VoiceBlue board (VoIP to GSM gateway).
+ *
+ * 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/device.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_reg.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/tc.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/usb.h>
+
+#include "common.h"
+
+extern void omap_init_time(void);
+extern int omap_gpio_init(void);
+
+static struct plat_serial8250_port voiceblue_ports[] = {
+	{
+		.mapbase	= (unsigned long)(OMAP_CS1_PHYS + 0x40000),
+		.irq		= OMAP_GPIO_IRQ(12),
+		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP,
+		.iotype		= UPIO_MEM,
+		.regshift	= 1,
+		.uartclk	= 3686400,
+	},
+	{
+		.mapbase	= (unsigned long)(OMAP_CS1_PHYS + 0x50000),
+		.irq		= OMAP_GPIO_IRQ(13),
+		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP,
+		.iotype		= UPIO_MEM,
+		.regshift	= 1,
+		.uartclk	= 3686400,
+	},
+	{
+		.mapbase	= (unsigned long)(OMAP_CS1_PHYS + 0x60000),
+		.irq		= OMAP_GPIO_IRQ(14),
+		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP,
+		.iotype		= UPIO_MEM,
+		.regshift	= 1,
+		.uartclk	= 3686400,
+	},
+	{
+		.mapbase	= (unsigned long)(OMAP_CS1_PHYS + 0x70000),
+		.irq		= OMAP_GPIO_IRQ(15),
+		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP,
+		.iotype		= UPIO_MEM,
+		.regshift	= 1,
+		.uartclk	= 3686400,
+	},
+	{ },
+};
+
+static struct platform_device serial_device = {
+	.name			= "serial8250",
+	.id			= 1,
+	.dev			= {
+		.platform_data	= voiceblue_ports,
+	},
+};
+
+static int __init ext_uart_init(void)
+{
+	return platform_device_register(&serial_device);
+}
+arch_initcall(ext_uart_init);
+
+static struct resource voiceblue_smc91x_resources[] = {
+	[0] = {
+		.start	= OMAP_CS2_PHYS + 0x300,
+		.end	= OMAP_CS2_PHYS + 0x300 + 16,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= OMAP_GPIO_IRQ(8),
+		.end	= OMAP_GPIO_IRQ(8),
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device voiceblue_smc91x_device = {
+	.name		= "smc91x",
+	.id		= 0,
+	.num_resources	= ARRAY_SIZE(voiceblue_smc91x_resources),
+	.resource	= voiceblue_smc91x_resources,
+};
+
+static struct platform_device *voiceblue_devices[] __initdata = {
+	&voiceblue_smc91x_device,
+};
+
+static struct omap_usb_config voiceblue_usb_config __initdata = {
+	.hmc_mode	= 3,
+	.register_host	= 1,
+	.register_dev   = 1,
+	.pins[0]	= 2,
+	.pins[1]	= 6,
+	.pins[2]	= 6,
+};
+
+static struct omap_board_config_kernel voiceblue_config[] = {
+	{ OMAP_TAG_USB, &voiceblue_usb_config },
+};
+
+static void __init voiceblue_init_irq(void)
+{
+	omap_init_irq();
+	omap_gpio_init();
+}
+
+static void __init voiceblue_init(void)
+{
+	/* There is a good chance board is going up, so enable Power LED
+	 * (it is connected through invertor) */
+	omap_writeb(0x00, OMAP_LPG1_LCR);
+	/* Watchdog */
+	omap_request_gpio(0);
+	/* smc91x reset */
+	omap_request_gpio(7);
+	omap_set_gpio_direction(7, 0);
+	omap_set_gpio_dataout(7, 1);
+	udelay(2);	/* wait at least 100ns */
+	omap_set_gpio_dataout(7, 0);
+	mdelay(50);	/* 50ms until PHY ready */
+	/* smc91x interrupt pin */
+	omap_request_gpio(8);
+	omap_set_gpio_edge_ctrl(8, OMAP_GPIO_RISING_EDGE);
+	/* 16C554 reset*/
+	omap_request_gpio(6);
+	omap_set_gpio_direction(6, 0);
+	omap_set_gpio_dataout(6, 0);
+	/* 16C554 interrupt pins */
+	omap_request_gpio(12);
+	omap_request_gpio(13);
+	omap_request_gpio(14);
+	omap_request_gpio(15);
+	omap_set_gpio_edge_ctrl(12, OMAP_GPIO_RISING_EDGE);
+	omap_set_gpio_edge_ctrl(13, OMAP_GPIO_RISING_EDGE);
+	omap_set_gpio_edge_ctrl(14, OMAP_GPIO_RISING_EDGE);
+	omap_set_gpio_edge_ctrl(15, OMAP_GPIO_RISING_EDGE);
+
+	platform_add_devices(voiceblue_devices, ARRAY_SIZE(voiceblue_devices));
+	omap_board_config = voiceblue_config;
+	omap_board_config_size = ARRAY_SIZE(voiceblue_config);
+}
+
+static int __initdata omap_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
+
+static void __init voiceblue_map_io(void)
+{
+	omap_map_io();
+	omap_serial_init(omap_serial_ports);
+}
+
+#define MACHINE_PANICED		1
+#define MACHINE_REBOOTING	2
+#define MACHINE_REBOOT		4
+static unsigned long machine_state;
+
+static int panic_event(struct notifier_block *this, unsigned long event,
+	 void *ptr)
+{
+	if (test_and_set_bit(MACHINE_PANICED, &machine_state))
+		return NOTIFY_DONE;
+
+	/* Flash Power LED
+	 * (TODO: Enable clock right way (enabled in bootloader already)) */
+	omap_writeb(0x78, OMAP_LPG1_LCR);
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block panic_block = {
+	.notifier_call	= panic_event,
+};
+
+static int __init setup_notifier(void)
+{
+	/* Setup panic notifier */
+	notifier_chain_register(&panic_notifier_list, &panic_block);
+
+	return 0;
+}
+
+postcore_initcall(setup_notifier);
+
+static int wdt_gpio_state;
+
+void voiceblue_wdt_enable(void)
+{
+	omap_set_gpio_direction(0, 0);
+	omap_set_gpio_dataout(0, 0);
+	omap_set_gpio_dataout(0, 1);
+	omap_set_gpio_dataout(0, 0);
+	wdt_gpio_state = 0;
+}
+
+void voiceblue_wdt_disable(void)
+{
+	omap_set_gpio_dataout(0, 0);
+	omap_set_gpio_dataout(0, 1);
+	omap_set_gpio_dataout(0, 0);
+	omap_set_gpio_direction(0, 1);
+}
+
+void voiceblue_wdt_ping(void)
+{
+	if (test_bit(MACHINE_REBOOT, &machine_state))
+		return;
+
+	wdt_gpio_state = !wdt_gpio_state;
+	omap_set_gpio_dataout(0, wdt_gpio_state);
+}
+
+void voiceblue_reset(void)
+{
+	set_bit(MACHINE_REBOOT, &machine_state);
+	voiceblue_wdt_enable();
+	while (1) ;
+}
+
+EXPORT_SYMBOL(voiceblue_wdt_enable);
+EXPORT_SYMBOL(voiceblue_wdt_disable);
+EXPORT_SYMBOL(voiceblue_wdt_ping);
+
+MACHINE_START(VOICEBLUE, "VoiceBlue OMAP5910")
+	MAINTAINER("Ladislav Michl <michl@2n.cz>")
+	BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000)
+	BOOT_PARAMS(0x10000100)
+	MAPIO(voiceblue_map_io)
+	INITIRQ(voiceblue_init_irq)
+	INIT_MACHINE(voiceblue_init)
+	.timer = &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap/clock.c b/arch/arm/mach-omap/clock.c
new file mode 100644
index 0000000..e91186b
--- /dev/null
+++ b/arch/arm/mach-omap/clock.c
@@ -0,0 +1,1076 @@
+/*
+ *  linux/arch/arm/mach-omap/clock.c
+ *
+ *  Copyright (C) 2004 Nokia corporation
+ *  Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ *
+ * 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/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+
+#include <asm/semaphore.h>
+#include <asm/hardware/clock.h>
+#include <asm/arch/board.h>
+#include <asm/arch/usb.h>
+
+#include "clock.h"
+
+static LIST_HEAD(clocks);
+static DECLARE_MUTEX(clocks_sem);
+static DEFINE_SPINLOCK(clockfw_lock);
+static void propagate_rate(struct clk *  clk);
+/* External clock (MCLK & BCLK) functions */
+static int set_ext_clk_rate(struct clk *  clk, unsigned long rate);
+static long round_ext_clk_rate(struct clk *  clk, unsigned long rate);
+static void init_ext_clk(struct clk *  clk);
+/* MPU virtual clock functions */
+static int select_table_rate(struct clk *  clk, unsigned long rate);
+static long round_to_table_rate(struct clk *  clk, unsigned long rate);
+void clk_setdpll(__u16, __u16);
+
+struct mpu_rate rate_table[] = {
+	/* MPU MHz, xtal MHz, dpll1 MHz, CKCTL, DPLL_CTL
+	 * armdiv, dspdiv, dspmmu, tcdiv, perdiv, lcddiv
+	 */
+#if defined(CONFIG_OMAP_ARM_216MHZ)
+	{ 216000000, 12000000, 216000000, 0x050d, 0x2910 }, /* 1/1/2/2/2/8 */
+#endif
+#if defined(CONFIG_OMAP_ARM_195MHZ)
+	{ 195000000, 13000000, 195000000, 0x050e, 0x2790 }, /* 1/1/2/2/4/8 */
+#endif
+#if defined(CONFIG_OMAP_ARM_192MHZ)
+	{ 192000000, 19200000, 192000000, 0x050f, 0x2510 }, /* 1/1/2/2/8/8 */
+	{ 192000000, 12000000, 192000000, 0x050f, 0x2810 }, /* 1/1/2/2/8/8 */
+	{  96000000, 12000000, 192000000, 0x055f, 0x2810 }, /* 2/2/2/2/8/8 */
+	{  48000000, 12000000, 192000000, 0x0ccf, 0x2810 }, /* 4/4/4/4/8/8 */
+	{  24000000, 12000000, 192000000, 0x0fff, 0x2810 }, /* 8/8/8/8/8/8 */
+#endif
+#if defined(CONFIG_OMAP_ARM_182MHZ)
+	{ 182000000, 13000000, 182000000, 0x050e, 0x2710 }, /* 1/1/2/2/4/8 */
+#endif
+#if defined(CONFIG_OMAP_ARM_168MHZ)
+	{ 168000000, 12000000, 168000000, 0x010f, 0x2710 }, /* 1/1/1/2/8/8 */
+#endif
+#if defined(CONFIG_OMAP_ARM_150MHZ)
+	{ 150000000, 12000000, 150000000, 0x150a, 0x2cb0 }, /* 0/0/1/1/2/2 */
+#endif
+#if defined(CONFIG_OMAP_ARM_120MHZ)
+	{ 120000000, 12000000, 120000000, 0x010a, 0x2510 }, /* 1/1/1/2/4/4 */
+#endif
+#if defined(CONFIG_OMAP_ARM_96MHZ)
+	{  96000000, 12000000,  96000000, 0x0005, 0x2410 }, /* 1/1/1/1/2/2 */
+#endif
+#if defined(CONFIG_OMAP_ARM_60MHZ)
+	{  60000000, 12000000,  60000000, 0x0005, 0x2290 }, /* 1/1/1/1/2/2 */
+#endif
+#if defined(CONFIG_OMAP_ARM_30MHZ)
+	{  30000000, 12000000,  60000000, 0x0555, 0x2290 }, /* 2/2/2/2/2/2 */
+#endif
+	{ 0, 0, 0, 0, 0 },
+};
+
+
+static void ckctl_recalc(struct clk *  clk)
+{
+	int dsor;
+
+	/* Calculate divisor encoded as 2-bit exponent */
+	dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset));
+	if (unlikely(clk->rate == clk->parent->rate / dsor))
+		return; /* No change, quick exit */
+	clk->rate = clk->parent->rate / dsor;
+
+	if (unlikely(clk->flags & RATE_PROPAGATES))
+		propagate_rate(clk);
+}
+
+
+static void followparent_recalc(struct clk *  clk)
+{
+	clk->rate = clk->parent->rate;
+}
+
+
+static void watchdog_recalc(struct clk *  clk)
+{
+	clk->rate = clk->parent->rate / 14;
+}
+
+
+static struct clk ck_ref = {
+	.name		= "ck_ref",
+	.rate		= 12000000,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  ALWAYS_ENABLED,
+};
+
+static struct clk ck_dpll1 = {
+	.name		= "ck_dpll1",
+	.parent		= &ck_ref,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  RATE_PROPAGATES | ALWAYS_ENABLED,
+};
+
+static struct clk ck_dpll1out = {
+	.name		= "ck_dpll1out",
+	.parent		= &ck_dpll1,
+	.flags		= CLOCK_IN_OMAP16XX,
+	.enable_reg	= ARM_IDLECT2,
+	.enable_bit	= EN_CKOUT_ARM,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk arm_ck = {
+	.name		= "arm_ck",
+	.parent		= &ck_dpll1,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  RATE_CKCTL | RATE_PROPAGATES | ALWAYS_ENABLED,
+	.rate_offset	= CKCTL_ARMDIV_OFFSET,
+	.recalc		= &ckctl_recalc,
+};
+
+static struct clk armper_ck = {
+	.name		= "armper_ck",
+	.parent		= &ck_dpll1,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  RATE_CKCTL,
+	.enable_reg	= ARM_IDLECT2,
+	.enable_bit	= EN_PERCK,
+	.rate_offset	= CKCTL_PERDIV_OFFSET,
+	.recalc		= &ckctl_recalc,
+};
+
+static struct clk arm_gpio_ck = {
+	.name		= "arm_gpio_ck",
+	.parent		= &ck_dpll1,
+	.flags		= CLOCK_IN_OMAP1510,
+	.enable_reg	= ARM_IDLECT2,
+	.enable_bit	= EN_GPIOCK,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk armxor_ck = {
+	.name		= "armxor_ck",
+	.parent		= &ck_ref,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+	.enable_reg	= ARM_IDLECT2,
+	.enable_bit	= EN_XORPCK,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk armtim_ck = {
+	.name		= "armtim_ck",
+	.parent		= &ck_ref,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+	.enable_reg	= ARM_IDLECT2,
+	.enable_bit	= EN_TIMCK,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk armwdt_ck = {
+	.name		= "armwdt_ck",
+	.parent		= &ck_ref,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+	.enable_reg	= ARM_IDLECT2,
+	.enable_bit	= EN_WDTCK,
+	.recalc		= &watchdog_recalc,
+};
+
+static struct clk arminth_ck16xx = {
+	.name		= "arminth_ck",
+	.parent		= &arm_ck,
+	.flags		= CLOCK_IN_OMAP16XX,
+	.recalc		= &followparent_recalc,
+	/* Note: On 16xx the frequency can be divided by 2 by programming
+	 * ARM_CKCTL:ARM_INTHCK_SEL(14) to 1
+	 *
+	 * 1510 version is in TC clocks.
+	 */
+};
+
+static struct clk dsp_ck = {
+	.name		= "dsp_ck",
+	.parent		= &ck_dpll1,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  RATE_CKCTL,
+	.enable_reg	= ARM_CKCTL,
+	.enable_bit	= EN_DSPCK,
+	.rate_offset	= CKCTL_DSPDIV_OFFSET,
+	.recalc		= &ckctl_recalc,
+};
+
+static struct clk dspmmu_ck = {
+	.name		= "dspmmu_ck",
+	.parent		= &ck_dpll1,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  RATE_CKCTL | ALWAYS_ENABLED,
+	.rate_offset	= CKCTL_DSPMMUDIV_OFFSET,
+	.recalc		= &ckctl_recalc,
+};
+
+static struct clk tc_ck = {
+	.name		= "tc_ck",
+	.parent		= &ck_dpll1,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730 |
+			  RATE_CKCTL | RATE_PROPAGATES | ALWAYS_ENABLED,
+	.rate_offset	= CKCTL_TCDIV_OFFSET,
+	.recalc		= &ckctl_recalc,
+};
+
+static struct clk arminth_ck1510 = {
+	.name		= "arminth_ck",
+	.parent		= &tc_ck,
+	.flags		= CLOCK_IN_OMAP1510,
+	.recalc		= &followparent_recalc,
+	/* Note: On 1510 the frequency follows TC_CK
+	 *
+	 * 16xx version is in MPU clocks.
+	 */
+};
+
+static struct clk tipb_ck = {
+	.name		= "tibp_ck",
+	.parent		= &tc_ck,
+	.flags		= CLOCK_IN_OMAP1510,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk l3_ocpi_ck = {
+	.name		= "l3_ocpi_ck",
+	.parent		= &tc_ck,
+	.flags		= CLOCK_IN_OMAP16XX,
+	.enable_reg	= ARM_IDLECT3,
+	.enable_bit	= EN_OCPI_CK,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk tc1_ck = {
+	.name		= "tc1_ck",
+	.parent		= &tc_ck,
+	.flags		= CLOCK_IN_OMAP16XX,
+	.enable_reg	= ARM_IDLECT3,
+	.enable_bit	= EN_TC1_CK,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk tc2_ck = {
+	.name		= "tc2_ck",
+	.parent		= &tc_ck,
+	.flags		= CLOCK_IN_OMAP16XX,
+	.enable_reg	= ARM_IDLECT3,
+	.enable_bit	= EN_TC2_CK,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk dma_ck = {
+	.name		= "dma_ck",
+	.parent		= &tc_ck,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk dma_lcdfree_ck = {
+	.name		= "dma_lcdfree_ck",
+	.parent		= &tc_ck,
+	.flags		= CLOCK_IN_OMAP16XX,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk api_ck = {
+	.name		= "api_ck",
+	.parent		= &tc_ck,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+	.enable_reg	= ARM_IDLECT2,
+	.enable_bit	= EN_APICK,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk lb_ck = {
+	.name		= "lb_ck",
+	.parent		= &tc_ck,
+	.flags		= CLOCK_IN_OMAP1510,
+	.enable_reg	= ARM_IDLECT2,
+	.enable_bit	= EN_LBCK,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk rhea1_ck = {
+	.name		= "rhea1_ck",
+	.parent		= &tc_ck,
+	.flags		= CLOCK_IN_OMAP16XX,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk rhea2_ck = {
+	.name		= "rhea2_ck",
+	.parent		= &tc_ck,
+	.flags		= CLOCK_IN_OMAP16XX,
+	.recalc		= &followparent_recalc,
+};
+
+static struct clk lcd_ck = {
+	.name		= "lcd_ck",
+	.parent		= &ck_dpll1,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730 |
+			  RATE_CKCTL,
+	.enable_reg	= ARM_IDLECT2,
+	.enable_bit	= EN_LCDCK,
+	.rate_offset	= CKCTL_LCDDIV_OFFSET,
+	.recalc		= &ckctl_recalc,
+};
+
+static struct clk uart1_ck = {
+	.name		= "uart1_ck",
+	/* Direct from ULPD, no parent */
+	.rate		= 48000000,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  RATE_FIXED | ENABLE_REG_32BIT,
+	.enable_reg	= MOD_CONF_CTRL_0,
+	.enable_bit	= 29,
+	/* (Only on 1510)
+	 * The "enable bit" actually chooses between 48MHz and 12MHz.
+	 */
+};
+
+static struct clk uart2_ck = {
+	.name		= "uart2_ck",
+	/* Direct from ULPD, no parent */
+	.rate		= 48000000,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  RATE_FIXED | ENABLE_REG_32BIT,
+	.enable_reg	= MOD_CONF_CTRL_0,
+	.enable_bit	= 30,
+	/* (for both 1510 and 16xx)
+	 * The "enable bit" actually chooses between 48MHz and 12MHz/32kHz.
+	 */
+};
+
+static struct clk uart3_ck = {
+	.name		= "uart3_ck",
+	/* Direct from ULPD, no parent */
+	.rate		= 48000000,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  RATE_FIXED | ENABLE_REG_32BIT,
+	.enable_reg	= MOD_CONF_CTRL_0,
+	.enable_bit	= 31,
+	/* (Only on 1510)
+	 * The "enable bit" actually chooses between 48MHz and 12MHz.
+	 */
+};
+
+static struct clk usb_clko = {	/* 6 MHz output on W4_USB_CLKO */
+	.name		= "usb_clko",
+	/* Direct from ULPD, no parent */
+	.rate		= 6000000,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  RATE_FIXED | ENABLE_REG_32BIT,
+	.enable_reg	= ULPD_CLOCK_CTRL,
+	.enable_bit	= USB_MCLK_EN_BIT,
+};
+
+static struct clk usb_hhc_ck1510 = {
+	.name		= "usb_hhc_ck",
+	/* Direct from ULPD, no parent */
+	.rate		= 48000000, /* Actually 2 clocks, 12MHz and 48MHz */
+	.flags		= CLOCK_IN_OMAP1510 |
+			  RATE_FIXED | ENABLE_REG_32BIT,
+	.enable_reg	= MOD_CONF_CTRL_0,
+	.enable_bit	= USB_HOST_HHC_UHOST_EN,
+};
+
+static struct clk usb_hhc_ck16xx = {
+	.name		= "usb_hhc_ck",
+	/* Direct from ULPD, no parent */
+	.rate		= 48000000,
+	/* OTG_SYSCON_2.OTG_PADEN == 0 (not 1510-compatible) */
+	.flags		= CLOCK_IN_OMAP16XX |
+			  RATE_FIXED | ENABLE_REG_32BIT,
+	.enable_reg	= OTG_BASE + 0x08 /* OTG_SYSCON_2 */,
+	.enable_bit	= 8 /* UHOST_EN */,
+};
+
+static struct clk mclk_1510 = {
+	.name		= "mclk",
+	/* Direct from ULPD, no parent. May be enabled by ext hardware. */
+	.rate		= 12000000,
+	.flags		= CLOCK_IN_OMAP1510 | RATE_FIXED,
+};
+
+static struct clk mclk_16xx = {
+	.name		= "mclk",
+	/* Direct from ULPD, no parent. May be enabled by ext hardware. */
+	.flags		= CLOCK_IN_OMAP16XX,
+	.enable_reg	= COM_CLK_DIV_CTRL_SEL,
+	.enable_bit	= COM_ULPD_PLL_CLK_REQ,
+	.set_rate	= &set_ext_clk_rate,
+	.round_rate	= &round_ext_clk_rate,
+	.init		= &init_ext_clk,
+};
+
+static struct clk bclk_1510 = {
+	.name		= "bclk",
+	/* Direct from ULPD, no parent. May be enabled by ext hardware. */
+	.rate		= 12000000,
+	.flags		= CLOCK_IN_OMAP1510 | RATE_FIXED,
+};
+
+static struct clk bclk_16xx = {
+	.name		= "bclk",
+	/* Direct from ULPD, no parent. May be enabled by ext hardware. */
+	.flags		= CLOCK_IN_OMAP16XX,
+	.enable_reg	= SWD_CLK_DIV_CTRL_SEL,
+	.enable_bit	= SWD_ULPD_PLL_CLK_REQ,
+	.set_rate	= &set_ext_clk_rate,
+	.round_rate	= &round_ext_clk_rate,
+	.init		= &init_ext_clk,
+};
+
+static struct clk mmc1_ck = {
+	.name		= "mmc1_ck",
+	/* Functional clock is direct from ULPD, interface clock is ARMPER */
+	.parent		= &armper_ck,
+	.rate		= 48000000,
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  RATE_FIXED | ENABLE_REG_32BIT,
+	.enable_reg	= MOD_CONF_CTRL_0,
+	.enable_bit	= 23,
+};
+
+static struct clk mmc2_ck = {
+	.name		= "mmc2_ck",
+	/* Functional clock is direct from ULPD, interface clock is ARMPER */
+	.parent		= &armper_ck,
+	.rate		= 48000000,
+	.flags		= CLOCK_IN_OMAP16XX |
+			  RATE_FIXED | ENABLE_REG_32BIT,
+	.enable_reg	= MOD_CONF_CTRL_0,
+	.enable_bit	= 20,
+};
+
+static struct clk virtual_ck_mpu = {
+	.name		= "mpu",
+	.flags		= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+			  VIRTUAL_CLOCK | ALWAYS_ENABLED,
+	.parent		= &arm_ck, /* Is smarter alias for */
+	.recalc		= &followparent_recalc,
+	.set_rate	= &select_table_rate,
+	.round_rate	= &round_to_table_rate,
+};
+
+
+static struct clk *  onchip_clks[] = {
+	/* non-ULPD clocks */
+	&ck_ref,
+	&ck_dpll1,
+	/* CK_GEN1 clocks */
+	&ck_dpll1out,
+	&arm_ck,
+	&armper_ck,
+	&arm_gpio_ck,
+	&armxor_ck,
+	&armtim_ck,
+	&armwdt_ck,
+	&arminth_ck1510,  &arminth_ck16xx,
+	/* CK_GEN2 clocks */
+	&dsp_ck,
+	&dspmmu_ck,
+	/* CK_GEN3 clocks */
+	&tc_ck,
+	&tipb_ck,
+	&l3_ocpi_ck,
+	&tc1_ck,
+	&tc2_ck,
+	&dma_ck,
+	&dma_lcdfree_ck,
+	&api_ck,
+	&lb_ck,
+	&rhea1_ck,
+	&rhea2_ck,
+	&lcd_ck,
+	/* ULPD clocks */
+	&uart1_ck,
+	&uart2_ck,
+	&uart3_ck,
+	&usb_clko,
+	&usb_hhc_ck1510, &usb_hhc_ck16xx,
+	&mclk_1510,  &mclk_16xx,
+	&bclk_1510,  &bclk_16xx,
+	&mmc1_ck,
+	&mmc2_ck,
+	/* Virtual clocks */
+	&virtual_ck_mpu,
+};
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+	struct clk *p, *clk = ERR_PTR(-ENOENT);
+
+	down(&clocks_sem);
+	list_for_each_entry(p, &clocks, node) {
+		if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
+			clk = p;
+			break;
+		}
+	}
+	up(&clocks_sem);
+
+	return clk;
+}
+EXPORT_SYMBOL(clk_get);
+
+
+void clk_put(struct clk *clk)
+{
+	if (clk && !IS_ERR(clk))
+		module_put(clk->owner);
+}
+EXPORT_SYMBOL(clk_put);
+
+
+int __clk_enable(struct clk *clk)
+{
+	__u16 regval16;
+	__u32 regval32;
+
+	if (clk->flags & ALWAYS_ENABLED)
+		return 0;
+
+	if (unlikely(clk->enable_reg == 0)) {
+		printk(KERN_ERR "clock.c: Enable for %s without enable code\n",
+		       clk->name);
+		return 0;
+	}
+
+	if (clk->flags & ENABLE_REG_32BIT) {
+		regval32 = omap_readl(clk->enable_reg);
+		regval32 |= (1 << clk->enable_bit);
+		omap_writel(regval32, clk->enable_reg);
+	} else {
+		regval16 = omap_readw(clk->enable_reg);
+		regval16 |= (1 << clk->enable_bit);
+		omap_writew(regval16, clk->enable_reg);
+	}
+
+	return 0;
+}
+
+
+void __clk_disable(struct clk *clk)
+{
+	__u16 regval16;
+	__u32 regval32;
+
+	if (clk->enable_reg == 0)
+		return;
+
+	if (clk->flags & ENABLE_REG_32BIT) {
+		regval32 = omap_readl(clk->enable_reg);
+		regval32 &= ~(1 << clk->enable_bit);
+		omap_writel(regval32, clk->enable_reg);
+	} else {
+		regval16 = omap_readw(clk->enable_reg);
+		regval16 &= ~(1 << clk->enable_bit);
+		omap_writew(regval16, clk->enable_reg);
+	}
+}
+
+
+void __clk_unuse(struct clk *clk)
+{
+	if (clk->usecount > 0 && !(--clk->usecount)) {
+		__clk_disable(clk);
+		if (likely(clk->parent))
+			__clk_unuse(clk->parent);
+	}
+}
+
+
+int __clk_use(struct clk *clk)
+{
+	int ret = 0;
+	if (clk->usecount++ == 0) {
+		if (likely(clk->parent))
+			ret = __clk_use(clk->parent);
+
+		if (unlikely(ret != 0)) {
+			clk->usecount--;
+			return ret;
+		}
+
+		ret = __clk_enable(clk);
+
+		if (unlikely(ret != 0) && clk->parent) {
+			__clk_unuse(clk->parent);
+			clk->usecount--;
+		}
+	}
+
+	return ret;
+}
+
+
+int clk_enable(struct clk *clk)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	ret = __clk_enable(clk);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL(clk_enable);
+
+
+void clk_disable(struct clk *clk)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	__clk_disable(clk);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+}
+EXPORT_SYMBOL(clk_disable);
+
+
+int clk_use(struct clk *clk)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	ret = __clk_use(clk);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL(clk_use);
+
+
+void clk_unuse(struct clk *clk)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	__clk_unuse(clk);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+}
+EXPORT_SYMBOL(clk_unuse);
+
+
+int clk_get_usecount(struct clk *clk)
+{
+        return clk->usecount;
+}
+EXPORT_SYMBOL(clk_get_usecount);
+
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	return clk->rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+
+static __u16 verify_ckctl_value(__u16 newval)
+{
+	/* This function checks for following limitations set
+	 * by the hardware (all conditions must be true):
+	 * DSPMMU_CK == DSP_CK  or  DSPMMU_CK == DSP_CK/2
+	 * ARM_CK >= TC_CK
+	 * DSP_CK >= TC_CK
+	 * DSPMMU_CK >= TC_CK
+	 *
+	 * In addition following rules are enforced:
+	 * LCD_CK <= TC_CK
+	 * ARMPER_CK <= TC_CK
+	 *
+	 * However, maximum frequencies are not checked for!
+	 */
+	__u8 per_exp;
+	__u8 lcd_exp;
+	__u8 arm_exp;
+	__u8 dsp_exp;
+	__u8 tc_exp;
+	__u8 dspmmu_exp;
+
+	per_exp = (newval >> CKCTL_PERDIV_OFFSET) & 3;
+	lcd_exp = (newval >> CKCTL_LCDDIV_OFFSET) & 3;
+	arm_exp = (newval >> CKCTL_ARMDIV_OFFSET) & 3;
+	dsp_exp = (newval >> CKCTL_DSPDIV_OFFSET) & 3;
+	tc_exp = (newval >> CKCTL_TCDIV_OFFSET) & 3;
+	dspmmu_exp = (newval >> CKCTL_DSPMMUDIV_OFFSET) & 3;
+
+	if (dspmmu_exp < dsp_exp)
+		dspmmu_exp = dsp_exp;
+	if (dspmmu_exp > dsp_exp+1)
+		dspmmu_exp = dsp_exp+1;
+	if (tc_exp < arm_exp)
+		tc_exp = arm_exp;
+	if (tc_exp < dspmmu_exp)
+		tc_exp = dspmmu_exp;
+	if (tc_exp > lcd_exp)
+		lcd_exp = tc_exp;
+	if (tc_exp > per_exp)
+		per_exp = tc_exp;
+
+	newval &= 0xf000;
+	newval |= per_exp << CKCTL_PERDIV_OFFSET;
+	newval |= lcd_exp << CKCTL_LCDDIV_OFFSET;
+	newval |= arm_exp << CKCTL_ARMDIV_OFFSET;
+	newval |= dsp_exp << CKCTL_DSPDIV_OFFSET;
+	newval |= tc_exp << CKCTL_TCDIV_OFFSET;
+	newval |= dspmmu_exp << CKCTL_DSPMMUDIV_OFFSET;
+
+	return newval;
+}
+
+
+static int calc_dsor_exp(struct clk *clk, unsigned long rate)
+{
+	/* Note: If target frequency is too low, this function will return 4,
+	 * which is invalid value. Caller must check for this value and act
+	 * accordingly.
+	 *
+	 * Note: This function does not check for following limitations set
+	 * by the hardware (all conditions must be true):
+	 * DSPMMU_CK == DSP_CK  or  DSPMMU_CK == DSP_CK/2
+	 * ARM_CK >= TC_CK
+	 * DSP_CK >= TC_CK
+	 * DSPMMU_CK >= TC_CK
+	 */
+	unsigned long realrate;
+	struct clk *  parent;
+	unsigned  dsor_exp;
+
+	if (unlikely(!(clk->flags & RATE_CKCTL)))
+		return -EINVAL;
+
+	parent = clk->parent;
+	if (unlikely(parent == 0))
+		return -EIO;
+
+	realrate = parent->rate;
+	for (dsor_exp=0; dsor_exp<4; dsor_exp++) {
+		if (realrate <= rate)
+			break;
+
+		realrate /= 2;
+	}
+
+	return dsor_exp;
+}
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	int dsor_exp;
+
+	if (clk->flags & RATE_FIXED)
+		return clk->rate;
+
+	if (clk->flags & RATE_CKCTL) {
+		dsor_exp = calc_dsor_exp(clk, rate);
+		if (dsor_exp < 0)
+			return dsor_exp;
+		if (dsor_exp > 3)
+			dsor_exp = 3;
+		return clk->parent->rate / (1 << dsor_exp);
+	}
+
+	if(clk->round_rate != 0)
+		return clk->round_rate(clk, rate);
+
+	return clk->rate;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+
+static void propagate_rate(struct clk *  clk)
+{
+	struct clk **  clkp;
+
+	for (clkp = onchip_clks; clkp < onchip_clks+ARRAY_SIZE(onchip_clks); clkp++) {
+		if (likely((*clkp)->parent != clk)) continue;
+		if (likely((*clkp)->recalc))
+			(*clkp)->recalc(*clkp);
+	}
+}
+
+
+static int select_table_rate(struct clk *  clk, unsigned long rate)
+{
+	/* Find the highest supported frequency <= rate and switch to it */
+	struct mpu_rate *  ptr;
+
+	if (clk != &virtual_ck_mpu)
+		return -EINVAL;
+
+	for (ptr = rate_table; ptr->rate; ptr++) {
+		if (ptr->xtal != ck_ref.rate)
+			continue;
+
+		/* DPLL1 cannot be reprogrammed without risking system crash */
+		if (likely(ck_dpll1.rate!=0) && ptr->pll_rate != ck_dpll1.rate)
+			continue;
+
+		/* Can check only after xtal frequency check */
+		if (ptr->rate <= rate)
+			break;
+	}
+
+	if (!ptr->rate)
+		return -EINVAL;
+
+	if (unlikely(ck_dpll1.rate == 0)) {
+		omap_writew(ptr->dpllctl_val, DPLL_CTL);
+		ck_dpll1.rate = ptr->pll_rate;
+	}
+	omap_writew(ptr->ckctl_val, ARM_CKCTL);
+	propagate_rate(&ck_dpll1);
+	return 0;
+}
+
+
+static long round_to_table_rate(struct clk *  clk, unsigned long rate)
+{
+	/* Find the highest supported frequency <= rate */
+	struct mpu_rate *  ptr;
+	long  highest_rate;
+
+	if (clk != &virtual_ck_mpu)
+		return -EINVAL;
+
+	highest_rate = -EINVAL;
+
+	for (ptr = rate_table; ptr->rate; ptr++) {
+		if (ptr->xtal != ck_ref.rate)
+			continue;
+
+		highest_rate = ptr->rate;
+
+		/* Can check only after xtal frequency check */
+		if (ptr->rate <= rate)
+			break;
+	}
+
+	return highest_rate;
+}
+
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	int  ret = -EINVAL;
+	int  dsor_exp;
+	__u16  regval;
+	unsigned long  flags;
+
+	if (clk->flags & RATE_CKCTL) {
+		dsor_exp = calc_dsor_exp(clk, rate);
+		if (dsor_exp > 3)
+			dsor_exp = -EINVAL;
+		if (dsor_exp < 0)
+			return dsor_exp;
+
+		spin_lock_irqsave(&clockfw_lock, flags);
+		regval = omap_readw(ARM_CKCTL);
+		regval &= ~(3 << clk->rate_offset);
+		regval |= dsor_exp << clk->rate_offset;
+		regval = verify_ckctl_value(regval);
+		omap_writew(regval, ARM_CKCTL);
+		clk->rate = clk->parent->rate / (1 << dsor_exp);
+		spin_unlock_irqrestore(&clockfw_lock, flags);
+		ret = 0;
+	} else if(clk->set_rate != 0) {
+		spin_lock_irqsave(&clockfw_lock, flags);
+		ret = clk->set_rate(clk, rate);
+		spin_unlock_irqrestore(&clockfw_lock, flags);
+	}
+
+	if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES)))
+		propagate_rate(clk);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+
+static unsigned calc_ext_dsor(unsigned long rate)
+{
+	unsigned dsor;
+
+	/* MCLK and BCLK divisor selection is not linear:
+	 * freq = 96MHz / dsor
+	 *
+	 * RATIO_SEL range: dsor <-> RATIO_SEL
+	 * 0..6: (RATIO_SEL+2) <-> (dsor-2)
+	 * 6..48:  (8+(RATIO_SEL-6)*2) <-> ((dsor-8)/2+6)
+	 * Minimum dsor is 2 and maximum is 96. Odd divisors starting from 9
+	 * can not be used.
+	 */
+	for (dsor = 2; dsor < 96; ++dsor) {
+		if ((dsor & 1) && dsor > 8)
+		  	continue;
+		if (rate >= 96000000 / dsor)
+			break;
+	}
+	return dsor;
+}
+
+
+static int set_ext_clk_rate(struct clk *  clk, unsigned long rate)
+{
+	unsigned dsor;
+	__u16 ratio_bits;
+
+	dsor = calc_ext_dsor(rate);
+	clk->rate = 96000000 / dsor;
+	if (dsor > 8)
+		ratio_bits = ((dsor - 8) / 2 + 6) << 2;
+	else
+		ratio_bits = (dsor - 2) << 2;
+
+	ratio_bits |= omap_readw(clk->enable_reg) & ~0xfd;
+	omap_writew(ratio_bits, clk->enable_reg);
+
+	return 0;
+}
+
+
+static long round_ext_clk_rate(struct clk *  clk, unsigned long rate)
+{
+	return 96000000 / calc_ext_dsor(rate);
+}
+
+
+static void init_ext_clk(struct clk *  clk)
+{
+	unsigned dsor;
+	__u16 ratio_bits;
+
+	/* Determine current rate and ensure clock is based on 96MHz APLL */
+	ratio_bits = omap_readw(clk->enable_reg) & ~1;
+	omap_writew(ratio_bits, clk->enable_reg);
+
+	ratio_bits = (ratio_bits & 0xfc) >> 2;
+	if (ratio_bits > 6)
+		dsor = (ratio_bits - 6) * 2 + 8;
+	else
+		dsor = ratio_bits + 2;
+
+	clk-> rate = 96000000 / dsor;
+}
+
+
+int clk_register(struct clk *clk)
+{
+	down(&clocks_sem);
+	list_add(&clk->node, &clocks);
+	if (clk->init)
+		clk->init(clk);
+	up(&clocks_sem);
+	return 0;
+}
+EXPORT_SYMBOL(clk_register);
+
+void clk_unregister(struct clk *clk)
+{
+	down(&clocks_sem);
+	list_del(&clk->node);
+	up(&clocks_sem);
+}
+EXPORT_SYMBOL(clk_unregister);
+
+
+
+int __init clk_init(void)
+{
+	struct clk **  clkp;
+	const struct omap_clock_config *info;
+	int crystal_type = 0; /* Default 12 MHz */
+
+	for (clkp = onchip_clks; clkp < onchip_clks+ARRAY_SIZE(onchip_clks); clkp++) {
+		if (((*clkp)->flags &CLOCK_IN_OMAP1510) && cpu_is_omap1510()) {
+			clk_register(*clkp);
+			continue;
+		}
+
+		if (((*clkp)->flags &CLOCK_IN_OMAP16XX) && cpu_is_omap16xx()) {
+			clk_register(*clkp);
+			continue;
+		}
+
+		if (((*clkp)->flags &CLOCK_IN_OMAP730) && cpu_is_omap730()) {
+			clk_register(*clkp);
+			continue;
+		}
+	}
+
+	info = omap_get_config(OMAP_TAG_CLOCK, struct omap_clock_config);
+	if (info != NULL) {
+		if (!cpu_is_omap1510())
+			crystal_type = info->system_clock_type;
+	}
+
+#if defined(CONFIG_ARCH_OMAP730)
+	ck_ref.rate = 13000000;
+#elif defined(CONFIG_ARCH_OMAP16XX)
+	if (crystal_type == 2)
+		ck_ref.rate = 19200000;
+#endif
+
+	/* We want to be in syncronous scalable mode */
+	omap_writew(0x1000, ARM_SYSST);
+
+	/* Find the highest supported frequency and enable it */
+	if (select_table_rate(&virtual_ck_mpu, ~0)) {
+		printk(KERN_ERR "System frequencies not set. Check your config.\n");
+		/* Guess sane values (60MHz) */
+		omap_writew(0x2290, DPLL_CTL);
+		omap_writew(0x1005, ARM_CKCTL);
+		ck_dpll1.rate = 60000000;
+		propagate_rate(&ck_dpll1);
+		printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): %ld/%ld/%ld\n",
+		       ck_ref.rate, ck_dpll1.rate, arm_ck.rate);
+	}
+
+	/* Cache rates for clocks connected to ck_ref (not dpll1) */
+	propagate_rate(&ck_ref);
+
+#ifdef CONFIG_MACH_OMAP_PERSEUS2
+	/* Select slicer output as OMAP input clock */
+	omap_writew(omap_readw(OMAP730_PCC_UPLD_CTRL) & ~0x1, OMAP730_PCC_UPLD_CTRL);
+#endif
+
+	/* Turn off DSP and ARM_TIMXO. Make sure ARM_INTHCK is not divided */
+	omap_writew(omap_readw(ARM_CKCTL) & 0x0fff, ARM_CKCTL);
+
+	/* Put DSP/MPUI into reset until needed */
+	omap_writew(0, ARM_RSTCT1);
+	omap_writew(1, ARM_RSTCT2);
+	omap_writew(0x400, ARM_IDLECT1);
+
+	/*
+	 * According to OMAP5910 Erratum SYS_DMA_1, bit DMACK_REQ (bit 8)
+	 * of the ARM_IDLECT2 register must be set to zero. The power-on
+	 * default value of this bit is one.
+	 */
+	omap_writew(0x0000, ARM_IDLECT2);	/* Turn LCD clock off also */
+
+	/*
+	 * Only enable those clocks we will need, let the drivers
+	 * enable other clocks as necessary
+	 */
+	clk_use(&armper_ck);
+	clk_use(&armxor_ck);
+	clk_use(&armtim_ck);
+
+	if (cpu_is_omap1510())
+		clk_enable(&arm_gpio_ck);
+
+	return 0;
+}
diff --git a/arch/arm/mach-omap/clock.h b/arch/arm/mach-omap/clock.h
new file mode 100644
index 0000000..08c0ddd
--- /dev/null
+++ b/arch/arm/mach-omap/clock.h
@@ -0,0 +1,112 @@
+/*
+ *  linux/arch/arm/mach-omap/clock.h
+ *
+ *  Copyright (C) 2004 Nokia corporation
+ *  Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ *  Based on clocks.h by Tony Lindgren, Gordon McNutt and RidgeRun, 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.
+ */
+
+#ifndef __ARCH_ARM_OMAP_CLOCK_H
+#define __ARCH_ARM_OMAP_CLOCK_H
+
+struct module;
+
+struct clk {
+	struct list_head	node;
+	struct module		*owner;
+	const char		*name;
+	struct clk		*parent;
+	unsigned long		rate;
+	__s8			usecount;
+	__u16			flags;
+	__u32			enable_reg;
+	__u8			enable_bit;
+	__u8			rate_offset;
+	void			(*recalc)(struct clk *);
+	int			(*set_rate)(struct clk *, unsigned long);
+	long			(*round_rate)(struct clk *, unsigned long);
+	void			(*init)(struct clk *);
+};
+
+
+struct mpu_rate {
+	unsigned long		rate;
+	unsigned long		xtal;
+	unsigned long		pll_rate;
+	__u16			ckctl_val;
+	__u16			dpllctl_val;
+};
+
+
+/* Clock flags */
+#define RATE_CKCTL		1
+#define RATE_FIXED		2
+#define RATE_PROPAGATES		4
+#define VIRTUAL_CLOCK		8
+#define ALWAYS_ENABLED		16
+#define ENABLE_REG_32BIT	32
+#define CLOCK_IN_OMAP16XX	64
+#define CLOCK_IN_OMAP1510	128
+#define CLOCK_IN_OMAP730	256
+
+/* ARM_CKCTL bit shifts */
+#define CKCTL_PERDIV_OFFSET	0
+#define CKCTL_LCDDIV_OFFSET	2
+#define CKCTL_ARMDIV_OFFSET	4
+#define CKCTL_DSPDIV_OFFSET	6
+#define CKCTL_TCDIV_OFFSET	8
+#define CKCTL_DSPMMUDIV_OFFSET	10
+/*#define ARM_TIMXO		12*/
+#define EN_DSPCK		13
+/*#define ARM_INTHCK_SEL	14*/ /* Divide-by-2 for mpu inth_ck */
+
+/* ARM_IDLECT1 bit shifts */
+/*#define IDLWDT_ARM	0*/
+/*#define IDLXORP_ARM	1*/
+/*#define IDLPER_ARM	2*/
+/*#define IDLLCD_ARM	3*/
+/*#define IDLLB_ARM	4*/
+/*#define IDLHSAB_ARM	5*/
+/*#define IDLIF_ARM	6*/
+/*#define IDLDPLL_ARM	7*/
+/*#define IDLAPI_ARM	8*/
+/*#define IDLTIM_ARM	9*/
+/*#define SETARM_IDLE	11*/
+
+/* ARM_IDLECT2 bit shifts */
+#define EN_WDTCK	0
+#define EN_XORPCK	1
+#define EN_PERCK	2
+#define EN_LCDCK	3
+#define EN_LBCK		4 /* Not on 1610/1710 */
+/*#define EN_HSABCK	5*/
+#define EN_APICK	6
+#define EN_TIMCK	7
+#define DMACK_REQ	8
+#define EN_GPIOCK	9 /* Not on 1610/1710 */
+/*#define EN_LBFREECK	10*/
+#define EN_CKOUT_ARM	11
+
+/* ARM_IDLECT3 bit shifts */
+#define EN_OCPI_CK	0
+#define EN_TC1_CK	2
+#define EN_TC2_CK	4
+
+/* Various register defines for clock controls scattered around OMAP chip */
+#define USB_MCLK_EN_BIT		4	/* In ULPD_CLKC_CTRL */
+#define USB_HOST_HHC_UHOST_EN	9	/* In MOD_CONF_CTRL_0 */
+#define SWD_ULPD_PLL_CLK_REQ	1	/* In SWD_CLK_DIV_CTRL_SEL */
+#define COM_ULPD_PLL_CLK_REQ	1	/* In COM_CLK_DIV_CTRL_SEL */
+#define SWD_CLK_DIV_CTRL_SEL	0xfffe0874
+#define COM_CLK_DIV_CTRL_SEL	0xfffe0878
+
+
+int clk_register(struct clk *clk);
+void clk_unregister(struct clk *clk);
+int clk_init(void);
+
+#endif
diff --git a/arch/arm/mach-omap/common.c b/arch/arm/mach-omap/common.c
new file mode 100644
index 0000000..265cde4
--- /dev/null
+++ b/arch/arm/mach-omap/common.c
@@ -0,0 +1,549 @@
+/*
+ * linux/arch/arm/mach-omap/common.c
+ *
+ * Code common to all OMAP machines.
+ *
+ * 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/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/console.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_reg.h>
+
+#include <asm/hardware.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/mach/map.h>
+#include <asm/hardware/clock.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/fpga.h>
+
+#include "clock.h"
+
+#define DEBUG 1
+
+struct omap_id {
+	u16	jtag_id;	/* Used to determine OMAP type */
+	u8	die_rev;	/* Processor revision */
+	u32	omap_id;	/* OMAP revision */
+	u32	type;		/* Cpu id bits [31:08], cpu class bits [07:00] */
+};
+
+/* Register values to detect the OMAP version */
+static struct omap_id omap_ids[] __initdata = {
+	{ .jtag_id = 0x355f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300100},
+	{ .jtag_id = 0xb55f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300300},
+	{ .jtag_id = 0xb470, .die_rev = 0x0, .omap_id = 0x03310100, .type = 0x15100000},
+	{ .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x16100000},
+	{ .jtag_id = 0xb576, .die_rev = 0x2, .omap_id = 0x03320100, .type = 0x16110000},
+	{ .jtag_id = 0xb576, .die_rev = 0x3, .omap_id = 0x03320100, .type = 0x16100c00},
+	{ .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320200, .type = 0x16100d00},
+	{ .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00},
+	{ .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00},
+	{ .jtag_id = 0xb576, .die_rev = 0x1, .omap_id = 0x03320100, .type = 0x16110000},
+	{ .jtag_id = 0xb58c, .die_rev = 0x2, .omap_id = 0x03320200, .type = 0x16110b00},
+	{ .jtag_id = 0xb58c, .die_rev = 0x3, .omap_id = 0x03320200, .type = 0x16110c00},
+	{ .jtag_id = 0xb65f, .die_rev = 0x0, .omap_id = 0x03320400, .type = 0x16212300},
+	{ .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320400, .type = 0x16212300},
+	{ .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320500, .type = 0x16212300},
+	{ .jtag_id = 0xb5f7, .die_rev = 0x0, .omap_id = 0x03330000, .type = 0x17100000},
+	{ .jtag_id = 0xb5f7, .die_rev = 0x1, .omap_id = 0x03330100, .type = 0x17100000},
+	{ .jtag_id = 0xb5f7, .die_rev = 0x2, .omap_id = 0x03330100, .type = 0x17100000},
+};
+
+/*
+ * Get OMAP type from PROD_ID.
+ * 1710 has the PROD_ID in bits 15:00, not in 16:01 as documented in TRM.
+ * 1510 PROD_ID is empty, and 1610 PROD_ID does not make sense.
+ * Undocumented register in TEST BLOCK is used as fallback; This seems to
+ * work on 1510, 1610 & 1710. The official way hopefully will work in future
+ * processors.
+ */
+static u16 __init omap_get_jtag_id(void)
+{
+	u32 prod_id, omap_id;
+
+	prod_id = omap_readl(OMAP_PRODUCTION_ID_1);
+	omap_id = omap_readl(OMAP32_ID_1);
+
+	/* Check for unusable OMAP_PRODUCTION_ID_1 on 1611B/5912 and 730 */
+	if (((prod_id >> 20) == 0) || (prod_id == omap_id))
+		prod_id = 0;
+	else
+		prod_id &= 0xffff;
+
+	if (prod_id)
+		return prod_id;
+
+	/* Use OMAP32_ID_1 as fallback */
+	prod_id = ((omap_id >> 12) & 0xffff);
+
+	return prod_id;
+}
+
+/*
+ * Get OMAP revision from DIE_REV.
+ * Early 1710 processors may have broken OMAP_DIE_ID, it contains PROD_ID.
+ * Undocumented register in the TEST BLOCK is used as fallback.
+ * REVISIT: This does not seem to work on 1510
+ */
+static u8 __init omap_get_die_rev(void)
+{
+	u32 die_rev;
+
+	die_rev = omap_readl(OMAP_DIE_ID_1);
+
+	/* Check for broken OMAP_DIE_ID on early 1710 */
+	if (((die_rev >> 12) & 0xffff) == omap_get_jtag_id())
+		die_rev = 0;
+
+	die_rev = (die_rev >> 17) & 0xf;
+	if (die_rev)
+		return die_rev;
+
+	die_rev = (omap_readl(OMAP32_ID_1) >> 28) & 0xf;
+
+	return die_rev;
+}
+
+static void __init omap_check_revision(void)
+{
+	int i;
+	u16 jtag_id;
+	u8 die_rev;
+	u32 omap_id;
+	u8 cpu_type;
+
+	jtag_id = omap_get_jtag_id();
+	die_rev = omap_get_die_rev();
+	omap_id = omap_readl(OMAP32_ID_0);
+
+#ifdef DEBUG
+	printk("OMAP_DIE_ID_0: 0x%08x\n", omap_readl(OMAP_DIE_ID_0));
+	printk("OMAP_DIE_ID_1: 0x%08x DIE_REV: %i\n",
+		omap_readl(OMAP_DIE_ID_1),
+	       (omap_readl(OMAP_DIE_ID_1) >> 17) & 0xf);
+	printk("OMAP_PRODUCTION_ID_0: 0x%08x\n", omap_readl(OMAP_PRODUCTION_ID_0));
+	printk("OMAP_PRODUCTION_ID_1: 0x%08x JTAG_ID: 0x%04x\n",
+		omap_readl(OMAP_PRODUCTION_ID_1),
+		omap_readl(OMAP_PRODUCTION_ID_1) & 0xffff);
+	printk("OMAP32_ID_0: 0x%08x\n", omap_readl(OMAP32_ID_0));
+	printk("OMAP32_ID_1: 0x%08x\n", omap_readl(OMAP32_ID_1));
+	printk("JTAG_ID: 0x%04x DIE_REV: %i\n", jtag_id, die_rev);
+#endif
+
+	system_serial_high = omap_readl(OMAP_DIE_ID_0);
+	system_serial_low = omap_readl(OMAP_DIE_ID_1);
+
+	/* First check only the major version in a safe way */
+	for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
+		if (jtag_id == (omap_ids[i].jtag_id)) {
+			system_rev = omap_ids[i].type;
+			break;
+		}
+	}
+
+	/* Check if we can find the die revision */
+	for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
+		if (jtag_id == omap_ids[i].jtag_id && die_rev == omap_ids[i].die_rev) {
+			system_rev = omap_ids[i].type;
+			break;
+		}
+	}
+
+	/* Finally check also the omap_id */
+	for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
+		if (jtag_id == omap_ids[i].jtag_id
+		    && die_rev == omap_ids[i].die_rev
+		    && omap_id == omap_ids[i].omap_id) {
+			system_rev = omap_ids[i].type;
+			break;
+		}
+	}
+
+	/* Add the cpu class info (7xx, 15xx, 16xx, 24xx) */
+	cpu_type = system_rev >> 24;
+
+	switch (cpu_type) {
+	case 0x07:
+		system_rev |= 0x07;
+		break;
+	case 0x15:
+		system_rev |= 0x15;
+		break;
+	case 0x16:
+	case 0x17:
+		system_rev |= 0x16;
+		break;
+	case 0x24:
+		system_rev |= 0x24;
+		break;
+	default:
+		printk("Unknown OMAP cpu type: 0x%02x\n", cpu_type);
+	}
+
+	printk("OMAP%04x", system_rev >> 16);
+	if ((system_rev >> 8) & 0xff)
+		printk("%x", (system_rev >> 8) & 0xff);
+	printk(" revision %i handled as %02xxx id: %08x%08x\n",
+	       die_rev, system_rev & 0xff, system_serial_low,
+	       system_serial_high);
+}
+
+/*
+ * ----------------------------------------------------------------------------
+ * OMAP I/O mapping
+ *
+ * The machine specific code may provide the extra mapping besides the
+ * default mapping provided here.
+ * ----------------------------------------------------------------------------
+ */
+
+static struct map_desc omap_io_desc[] __initdata = {
+ { IO_VIRT,      	IO_PHYS,             IO_SIZE,        	   MT_DEVICE },
+};
+
+#ifdef CONFIG_ARCH_OMAP730
+static struct map_desc omap730_io_desc[] __initdata = {
+ { OMAP730_DSP_BASE,    OMAP730_DSP_START,    OMAP730_DSP_SIZE,    MT_DEVICE },
+ { OMAP730_DSPREG_BASE, OMAP730_DSPREG_START, OMAP730_DSPREG_SIZE, MT_DEVICE },
+ { OMAP730_SRAM_BASE,   OMAP730_SRAM_START,   OMAP730_SRAM_SIZE,   MT_DEVICE }
+};
+#endif
+
+#ifdef CONFIG_ARCH_OMAP1510
+static struct map_desc omap1510_io_desc[] __initdata = {
+ { OMAP1510_DSP_BASE,    OMAP1510_DSP_START,    OMAP1510_DSP_SIZE,    MT_DEVICE },
+ { OMAP1510_DSPREG_BASE, OMAP1510_DSPREG_START, OMAP1510_DSPREG_SIZE, MT_DEVICE },
+ { OMAP1510_SRAM_BASE,   OMAP1510_SRAM_START,   OMAP1510_SRAM_SIZE,   MT_DEVICE }
+};
+#endif
+
+#if defined(CONFIG_ARCH_OMAP16XX)
+static struct map_desc omap1610_io_desc[] __initdata = {
+ { OMAP16XX_DSP_BASE,    OMAP16XX_DSP_START,    OMAP16XX_DSP_SIZE,    MT_DEVICE },
+ { OMAP16XX_DSPREG_BASE, OMAP16XX_DSPREG_START, OMAP16XX_DSPREG_SIZE, MT_DEVICE },
+ { OMAP16XX_SRAM_BASE,   OMAP16XX_SRAM_START,   OMAP1610_SRAM_SIZE,   MT_DEVICE }
+};
+
+static struct map_desc omap5912_io_desc[] __initdata = {
+ { OMAP16XX_DSP_BASE,    OMAP16XX_DSP_START,    OMAP16XX_DSP_SIZE,    MT_DEVICE },
+ { OMAP16XX_DSPREG_BASE, OMAP16XX_DSPREG_START, OMAP16XX_DSPREG_SIZE, MT_DEVICE },
+/*
+ * The OMAP5912 has 250kByte internal SRAM. Because the mapping is baseed on page
+ * size (4kByte), it seems that the last 2kByte (=0x800) of the 250kByte are not mapped.
+ * Add additional 2kByte (0x800) so that the last page is mapped and the last 2kByte
+ * can be used.
+ */
+ { OMAP16XX_SRAM_BASE,   OMAP16XX_SRAM_START,   OMAP5912_SRAM_SIZE + 0x800,   MT_DEVICE }
+};
+#endif
+
+static int initialized = 0;
+
+static void __init _omap_map_io(void)
+{
+	initialized = 1;
+
+	/* We have to initialize the IO space mapping before we can run
+	 * cpu_is_omapxxx() macros. */
+	iotable_init(omap_io_desc, ARRAY_SIZE(omap_io_desc));
+	omap_check_revision();
+
+#ifdef CONFIG_ARCH_OMAP730
+	if (cpu_is_omap730()) {
+		iotable_init(omap730_io_desc, ARRAY_SIZE(omap730_io_desc));
+	}
+#endif
+#ifdef CONFIG_ARCH_OMAP1510
+	if (cpu_is_omap1510()) {
+		iotable_init(omap1510_io_desc, ARRAY_SIZE(omap1510_io_desc));
+	}
+#endif
+#if defined(CONFIG_ARCH_OMAP16XX)
+	if (cpu_is_omap1610() || cpu_is_omap1710()) {
+		iotable_init(omap1610_io_desc, ARRAY_SIZE(omap1610_io_desc));
+	}
+	if (cpu_is_omap5912()) {
+		iotable_init(omap5912_io_desc, ARRAY_SIZE(omap5912_io_desc));
+	}
+#endif
+
+	/* REVISIT: Refer to OMAP5910 Errata, Advisory SYS_1: "Timeout Abort
+	 * on a Posted Write in the TIPB Bridge".
+	 */
+	omap_writew(0x0, MPU_PUBLIC_TIPB_CNTL);
+	omap_writew(0x0, MPU_PRIVATE_TIPB_CNTL);
+
+	/* Must init clocks early to assure that timer interrupt works
+	 */
+	clk_init();
+}
+
+/*
+ * This should only get called from board specific init
+ */
+void omap_map_io(void)
+{
+	if (!initialized)
+		_omap_map_io();
+}
+
+static inline unsigned int omap_serial_in(struct plat_serial8250_port *up,
+					  int offset)
+{
+	offset <<= up->regshift;
+	return (unsigned int)__raw_readb(up->membase + offset);
+}
+
+static inline void omap_serial_outp(struct plat_serial8250_port *p, int offset,
+				    int value)
+{
+	offset <<= p->regshift;
+	__raw_writeb(value, p->membase + offset);
+}
+
+/*
+ * Internal UARTs need to be initialized for the 8250 autoconfig to work
+ * properly. Note that the TX watermark initialization may not be needed
+ * once the 8250.c watermark handling code is merged.
+ */
+static void __init omap_serial_reset(struct plat_serial8250_port *p)
+{
+	omap_serial_outp(p, UART_OMAP_MDR1, 0x07);	/* disable UART */
+	omap_serial_outp(p, UART_OMAP_SCR, 0x08);	/* TX watermark */
+	omap_serial_outp(p, UART_OMAP_MDR1, 0x00);	/* enable UART */
+
+	if (!cpu_is_omap1510()) {
+		omap_serial_outp(p, UART_OMAP_SYSC, 0x01);
+		while (!(omap_serial_in(p, UART_OMAP_SYSC) & 0x01));
+	}
+}
+
+static struct plat_serial8250_port serial_platform_data[] = {
+	{
+		.membase	= (char*)IO_ADDRESS(OMAP_UART1_BASE),
+		.mapbase	= (unsigned long)OMAP_UART1_BASE,
+		.irq		= INT_UART1,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+		.uartclk	= OMAP16XX_BASE_BAUD * 16,
+	},
+	{
+		.membase	= (char*)IO_ADDRESS(OMAP_UART2_BASE),
+		.mapbase	= (unsigned long)OMAP_UART2_BASE,
+		.irq		= INT_UART2,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+		.uartclk	= OMAP16XX_BASE_BAUD * 16,
+	},
+	{
+		.membase	= (char*)IO_ADDRESS(OMAP_UART3_BASE),
+		.mapbase	= (unsigned long)OMAP_UART3_BASE,
+		.irq		= INT_UART3,
+		.flags		= UPF_BOOT_AUTOCONF,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+		.uartclk	= OMAP16XX_BASE_BAUD * 16,
+	},
+	{ },
+};
+
+static struct platform_device serial_device = {
+	.name			= "serial8250",
+	.id			= 0,
+	.dev			= {
+		.platform_data	= serial_platform_data,
+	},
+};
+
+/*
+ * Note that on Innovator-1510 UART2 pins conflict with USB2.
+ * By default UART2 does not work on Innovator-1510 if you have
+ * USB OHCI enabled. To use UART2, you must disable USB2 first.
+ */
+void __init omap_serial_init(int ports[OMAP_MAX_NR_PORTS])
+{
+	int i;
+
+	if (cpu_is_omap730()) {
+		serial_platform_data[0].regshift = 0;
+		serial_platform_data[1].regshift = 0;
+		serial_platform_data[0].irq = INT_730_UART_MODEM_1;
+		serial_platform_data[1].irq = INT_730_UART_MODEM_IRDA_2;
+	}
+
+	if (cpu_is_omap1510()) {
+		serial_platform_data[0].uartclk = OMAP1510_BASE_BAUD * 16;
+		serial_platform_data[1].uartclk = OMAP1510_BASE_BAUD * 16;
+		serial_platform_data[2].uartclk = OMAP1510_BASE_BAUD * 16;
+	}
+
+	for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
+		unsigned char reg;
+
+		if (ports[i] == 0) {
+			serial_platform_data[i].membase = 0;
+			serial_platform_data[i].mapbase = 0;
+			continue;
+		}
+
+		switch (i) {
+		case 0:
+			if (cpu_is_omap1510()) {
+				omap_cfg_reg(UART1_TX);
+				omap_cfg_reg(UART1_RTS);
+				if (machine_is_omap_innovator()) {
+					reg = fpga_read(OMAP1510_FPGA_POWER);
+					reg |= OMAP1510_FPGA_PCR_COM1_EN;
+					fpga_write(reg, OMAP1510_FPGA_POWER);
+					udelay(10);
+				}
+			}
+			break;
+		case 1:
+			if (cpu_is_omap1510()) {
+				omap_cfg_reg(UART2_TX);
+				omap_cfg_reg(UART2_RTS);
+				if (machine_is_omap_innovator()) {
+					reg = fpga_read(OMAP1510_FPGA_POWER);
+					reg |= OMAP1510_FPGA_PCR_COM2_EN;
+					fpga_write(reg, OMAP1510_FPGA_POWER);
+					udelay(10);
+				}
+			}
+			break;
+		case 2:
+			if (cpu_is_omap1510()) {
+				omap_cfg_reg(UART3_TX);
+				omap_cfg_reg(UART3_RX);
+			}
+			if (cpu_is_omap1710()) {
+				clk_enable(clk_get(0, "uart3_ck"));
+			}
+			break;
+		}
+		omap_serial_reset(&serial_platform_data[i]);
+	}
+}
+
+static int __init omap_init(void)
+{
+	return platform_device_register(&serial_device);
+}
+arch_initcall(omap_init);
+
+#define NO_LENGTH_CHECK 0xffffffff
+
+extern int omap_bootloader_tag_len;
+extern u8 omap_bootloader_tag[];
+
+struct omap_board_config_kernel *omap_board_config;
+int omap_board_config_size = 0;
+
+static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out)
+{
+	struct omap_board_config_kernel *kinfo = NULL;
+	int i;
+
+#ifdef CONFIG_OMAP_BOOT_TAG
+	struct omap_board_config_entry *info = NULL;
+
+	if (omap_bootloader_tag_len > 4)
+		info = (struct omap_board_config_entry *) omap_bootloader_tag;
+	while (info != NULL) {
+		u8 *next;
+
+		if (info->tag == tag) {
+			if (skip == 0)
+				break;
+			skip--;
+		}
+
+		if ((info->len & 0x03) != 0) {
+			/* We bail out to avoid an alignment fault */
+			printk(KERN_ERR "OMAP peripheral config: Length (%d) not word-aligned (tag %04x)\n",
+			       info->len, info->tag);
+			return NULL;
+		}
+		next = (u8 *) info + sizeof(*info) + info->len;
+		if (next >= omap_bootloader_tag + omap_bootloader_tag_len)
+			info = NULL;
+		else
+			info = (struct omap_board_config_entry *) next;
+	}
+	if (info != NULL) {
+		/* Check the length as a lame attempt to check for
+		 * binary inconsistancy. */
+		if (len != NO_LENGTH_CHECK) {
+			/* Word-align len */
+			if (len & 0x03)
+				len = (len + 3) & ~0x03;
+			if (info->len != len) {
+				printk(KERN_ERR "OMAP peripheral config: Length mismatch with tag %x (want %d, got %d)\n",
+				       tag, len, info->len);
+				return NULL;
+			}
+		}
+		if (len_out != NULL)
+			*len_out = info->len;
+		return info->data;
+	}
+#endif
+	/* Try to find the config from the board-specific structures
+	 * in the kernel. */
+	for (i = 0; i < omap_board_config_size; i++) {
+		if (omap_board_config[i].tag == tag) {
+			kinfo = &omap_board_config[i];
+			break;
+		}
+	}
+	if (kinfo == NULL)
+		return NULL;
+	return kinfo->data;
+}
+
+const void *__omap_get_config(u16 tag, size_t len, int nr)
+{
+        return get_config(tag, len, nr, NULL);
+}
+EXPORT_SYMBOL(__omap_get_config);
+
+const void *omap_get_var_config(u16 tag, size_t *len)
+{
+        return get_config(tag, NO_LENGTH_CHECK, 0, len);
+}
+EXPORT_SYMBOL(omap_get_var_config);
+
+static int __init omap_add_serial_console(void)
+{
+	const struct omap_uart_config *info;
+
+	info = omap_get_config(OMAP_TAG_UART, struct omap_uart_config);
+	if (info != NULL && info->console_uart) {
+		static char speed[11], *opt = NULL;
+
+		if (info->console_speed) {
+			snprintf(speed, sizeof(speed), "%u", info->console_speed);
+			opt = speed;
+		}
+		return add_preferred_console("ttyS", info->console_uart - 1, opt);
+	}
+	return 0;
+}
+console_initcall(omap_add_serial_console);
diff --git a/arch/arm/mach-omap/common.h b/arch/arm/mach-omap/common.h
new file mode 100644
index 0000000..9f62858
--- /dev/null
+++ b/arch/arm/mach-omap/common.h
@@ -0,0 +1,36 @@
+/*
+ * linux/arch/arm/mach-omap/common.h
+ *
+ * Header for code common to all OMAP machines.
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP_COMMON_H
+#define __ARCH_ARM_MACH_OMAP_COMMON_H
+
+struct sys_timer;
+
+extern void omap_map_io(void);
+extern struct sys_timer omap_timer;
+extern void omap_serial_init(int ports[]);
+
+#endif /* __ARCH_ARM_MACH_OMAP_COMMON_H */
diff --git a/arch/arm/mach-omap/dma.c b/arch/arm/mach-omap/dma.c
new file mode 100644
index 0000000..7a9ebe8
--- /dev/null
+++ b/arch/arm/mach-omap/dma.c
@@ -0,0 +1,1086 @@
+/*
+ * linux/arch/arm/omap/dma.c
+ *
+ * Copyright (C) 2003 Nokia Corporation
+ * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ * DMA channel linking for 1610 by Samuel Ortiz <samuel.ortiz@nokia.com>
+ * Graphics DMA and LCD DMA graphics tranformations
+ * by Imre Deak <imre.deak@nokia.com>
+ * Some functions based on earlier dma-omap.c Copyright (C) 2001 RidgeRun, Inc.
+ *
+ * Support functions for the OMAP internal DMA channels.
+ *
+ * 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/init.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+
+#include <asm/arch/tc.h>
+
+#define OMAP_DMA_ACTIVE		0x01
+
+#define OMAP_DMA_CCR_EN		(1 << 7)
+
+#define OMAP_FUNC_MUX_ARM_BASE	(0xfffe1000 + 0xec)
+
+static int enable_1510_mode = 0;
+
+struct omap_dma_lch {
+	int next_lch;
+	int dev_id;
+	u16 saved_csr;
+	u16 enabled_irqs;
+	const char *dev_name;
+	void (* callback)(int lch, u16 ch_status, void *data);
+	void *data;
+	long flags;
+};
+
+static int dma_chan_count;
+
+static spinlock_t dma_chan_lock;
+static struct omap_dma_lch dma_chan[OMAP_LOGICAL_DMA_CH_COUNT];
+
+const static u8 dma_irq[OMAP_LOGICAL_DMA_CH_COUNT] = {
+	INT_DMA_CH0_6, INT_DMA_CH1_7, INT_DMA_CH2_8, INT_DMA_CH3,
+	INT_DMA_CH4, INT_DMA_CH5, INT_1610_DMA_CH6, INT_1610_DMA_CH7,
+	INT_1610_DMA_CH8, INT_1610_DMA_CH9, INT_1610_DMA_CH10,
+	INT_1610_DMA_CH11, INT_1610_DMA_CH12, INT_1610_DMA_CH13,
+	INT_1610_DMA_CH14, INT_1610_DMA_CH15, INT_DMA_LCD
+};
+
+static inline int get_gdma_dev(int req)
+{
+	u32 reg = OMAP_FUNC_MUX_ARM_BASE + ((req - 1) / 5) * 4;
+	int shift = ((req - 1) % 5) * 6;
+
+	return ((omap_readl(reg) >> shift) & 0x3f) + 1;
+}
+
+static inline void set_gdma_dev(int req, int dev)
+{
+	u32 reg = OMAP_FUNC_MUX_ARM_BASE + ((req - 1) / 5) * 4;
+	int shift = ((req - 1) % 5) * 6;
+	u32 l;
+
+	l = omap_readl(reg);
+	l &= ~(0x3f << shift);
+	l |= (dev - 1) << shift;
+	omap_writel(l, reg);
+}
+
+static void clear_lch_regs(int lch)
+{
+	int i;
+	u32 lch_base = OMAP_DMA_BASE + lch * 0x40;
+
+	for (i = 0; i < 0x2c; i += 2)
+		omap_writew(0, lch_base + i);
+}
+
+void omap_set_dma_priority(int dst_port, int priority)
+{
+	unsigned long reg;
+	u32 l;
+
+	switch (dst_port) {
+	case OMAP_DMA_PORT_OCP_T1:	/* FFFECC00 */
+		reg = OMAP_TC_OCPT1_PRIOR;
+		break;
+	case OMAP_DMA_PORT_OCP_T2:	/* FFFECCD0 */
+		reg = OMAP_TC_OCPT2_PRIOR;
+		break;
+	case OMAP_DMA_PORT_EMIFF:	/* FFFECC08 */
+		reg = OMAP_TC_EMIFF_PRIOR;
+		break;
+	case OMAP_DMA_PORT_EMIFS:	/* FFFECC04 */
+		reg = OMAP_TC_EMIFS_PRIOR;
+		break;
+	default:
+		BUG();
+		return;
+	}
+	l = omap_readl(reg);
+	l &= ~(0xf << 8);
+	l |= (priority & 0xf) << 8;
+	omap_writel(l, reg);
+}
+
+void omap_set_dma_transfer_params(int lch, int data_type, int elem_count,
+				  int frame_count, int sync_mode)
+{
+	u16 w;
+
+	w = omap_readw(OMAP_DMA_CSDP(lch));
+	w &= ~0x03;
+	w |= data_type;
+	omap_writew(w, OMAP_DMA_CSDP(lch));
+
+	w = omap_readw(OMAP_DMA_CCR(lch));
+	w &= ~(1 << 5);
+	if (sync_mode == OMAP_DMA_SYNC_FRAME)
+		w |= 1 << 5;
+	omap_writew(w, OMAP_DMA_CCR(lch));
+
+	w = omap_readw(OMAP_DMA_CCR2(lch));
+	w &= ~(1 << 2);
+	if (sync_mode == OMAP_DMA_SYNC_BLOCK)
+		w |= 1 << 2;
+	omap_writew(w, OMAP_DMA_CCR2(lch));
+
+	omap_writew(elem_count, OMAP_DMA_CEN(lch));
+	omap_writew(frame_count, OMAP_DMA_CFN(lch));
+
+}
+void omap_set_dma_color_mode(int lch, enum omap_dma_color_mode mode, u32 color)
+{
+	u16 w;
+
+	BUG_ON(omap_dma_in_1510_mode());
+
+	w = omap_readw(OMAP_DMA_CCR2(lch)) & ~0x03;
+	switch (mode) {
+	case OMAP_DMA_CONSTANT_FILL:
+		w |= 0x01;
+		break;
+	case OMAP_DMA_TRANSPARENT_COPY:
+		w |= 0x02;
+		break;
+	case OMAP_DMA_COLOR_DIS:
+		break;
+	default:
+		BUG();
+	}
+	omap_writew(w, OMAP_DMA_CCR2(lch));
+
+	w = omap_readw(OMAP_DMA_LCH_CTRL(lch)) & ~0x0f;
+	/* Default is channel type 2D */
+	if (mode) {
+		omap_writew((u16)color, OMAP_DMA_COLOR_L(lch));
+		omap_writew((u16)(color >> 16), OMAP_DMA_COLOR_U(lch));
+		w |= 1;		/* Channel type G */
+	}
+	omap_writew(w, OMAP_DMA_LCH_CTRL(lch));
+}
+
+
+void omap_set_dma_src_params(int lch, int src_port, int src_amode,
+			     unsigned long src_start)
+{
+	u16 w;
+
+	w = omap_readw(OMAP_DMA_CSDP(lch));
+	w &= ~(0x1f << 2);
+	w |= src_port << 2;
+	omap_writew(w, OMAP_DMA_CSDP(lch));
+
+	w = omap_readw(OMAP_DMA_CCR(lch));
+	w &= ~(0x03 << 12);
+	w |= src_amode << 12;
+	omap_writew(w, OMAP_DMA_CCR(lch));
+
+	omap_writew(src_start >> 16, OMAP_DMA_CSSA_U(lch));
+	omap_writew(src_start, OMAP_DMA_CSSA_L(lch));
+}
+
+void omap_set_dma_src_index(int lch, int eidx, int fidx)
+{
+	omap_writew(eidx, OMAP_DMA_CSEI(lch));
+	omap_writew(fidx, OMAP_DMA_CSFI(lch));
+}
+
+void omap_set_dma_src_data_pack(int lch, int enable)
+{
+	u16 w;
+
+	w = omap_readw(OMAP_DMA_CSDP(lch)) & ~(1 << 6);
+	w |= enable ? (1 << 6) : 0;
+	omap_writew(w, OMAP_DMA_CSDP(lch));
+}
+
+void omap_set_dma_src_burst_mode(int lch, enum omap_dma_burst_mode burst_mode)
+{
+	u16 w;
+
+	w = omap_readw(OMAP_DMA_CSDP(lch)) & ~(0x03 << 7);
+	switch (burst_mode) {
+	case OMAP_DMA_DATA_BURST_DIS:
+		break;
+	case OMAP_DMA_DATA_BURST_4:
+		w |= (0x01 << 7);
+		break;
+	case OMAP_DMA_DATA_BURST_8:
+		/* not supported by current hardware
+		 * w |= (0x03 << 7);
+		 * fall through
+		 */
+	default:
+		BUG();
+	}
+	omap_writew(w, OMAP_DMA_CSDP(lch));
+}
+
+void omap_set_dma_dest_params(int lch, int dest_port, int dest_amode,
+			      unsigned long dest_start)
+{
+	u16 w;
+
+	w = omap_readw(OMAP_DMA_CSDP(lch));
+	w &= ~(0x1f << 9);
+	w |= dest_port << 9;
+	omap_writew(w, OMAP_DMA_CSDP(lch));
+
+	w = omap_readw(OMAP_DMA_CCR(lch));
+	w &= ~(0x03 << 14);
+	w |= dest_amode << 14;
+	omap_writew(w, OMAP_DMA_CCR(lch));
+
+	omap_writew(dest_start >> 16, OMAP_DMA_CDSA_U(lch));
+	omap_writew(dest_start, OMAP_DMA_CDSA_L(lch));
+}
+
+void omap_set_dma_dest_index(int lch, int eidx, int fidx)
+{
+	omap_writew(eidx, OMAP_DMA_CDEI(lch));
+	omap_writew(fidx, OMAP_DMA_CDFI(lch));
+}
+
+void omap_set_dma_dest_data_pack(int lch, int enable)
+{
+	u16 w;
+
+	w = omap_readw(OMAP_DMA_CSDP(lch)) & ~(1 << 13);
+	w |= enable ? (1 << 13) : 0;
+	omap_writew(w, OMAP_DMA_CSDP(lch));
+}
+
+void omap_set_dma_dest_burst_mode(int lch, enum omap_dma_burst_mode burst_mode)
+{
+	u16 w;
+
+	w = omap_readw(OMAP_DMA_CSDP(lch)) & ~(0x03 << 14);
+	switch (burst_mode) {
+	case OMAP_DMA_DATA_BURST_DIS:
+		break;
+	case OMAP_DMA_DATA_BURST_4:
+		w |= (0x01 << 14);
+		break;
+	case OMAP_DMA_DATA_BURST_8:
+		w |= (0x03 << 14);
+		break;
+	default:
+		printk(KERN_ERR "Invalid DMA burst mode\n");
+		BUG();
+		return;
+	}
+	omap_writew(w, OMAP_DMA_CSDP(lch));
+}
+
+static inline void init_intr(int lch)
+{
+	u16 w;
+
+	/* Read CSR to make sure it's cleared. */
+	w = omap_readw(OMAP_DMA_CSR(lch));
+	/* Enable some nice interrupts. */
+	omap_writew(dma_chan[lch].enabled_irqs, OMAP_DMA_CICR(lch));
+	dma_chan[lch].flags |= OMAP_DMA_ACTIVE;
+}
+
+static inline void enable_lnk(int lch)
+{
+	u16 w;
+
+	/* Clear the STOP_LNK bits */
+	w = omap_readw(OMAP_DMA_CLNK_CTRL(lch));
+	w &= ~(1 << 14);
+	omap_writew(w, OMAP_DMA_CLNK_CTRL(lch));
+
+	/* And set the ENABLE_LNK bits */
+	if (dma_chan[lch].next_lch != -1)
+		omap_writew(dma_chan[lch].next_lch | (1 << 15),
+			    OMAP_DMA_CLNK_CTRL(lch));
+}
+
+static inline void disable_lnk(int lch)
+{
+	u16 w;
+
+	/* Disable interrupts */
+	omap_writew(0, OMAP_DMA_CICR(lch));
+
+	/* Set the STOP_LNK bit */
+	w = omap_readw(OMAP_DMA_CLNK_CTRL(lch));
+	w |= (1 << 14);
+	w = omap_writew(w, OMAP_DMA_CLNK_CTRL(lch));
+
+	dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE;
+}
+
+void omap_start_dma(int lch)
+{
+	u16 w;
+
+	if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) {
+		int next_lch, cur_lch;
+		char dma_chan_link_map[OMAP_LOGICAL_DMA_CH_COUNT];
+
+		dma_chan_link_map[lch] = 1;
+		/* Set the link register of the first channel */
+		enable_lnk(lch);
+
+		memset(dma_chan_link_map, 0, sizeof(dma_chan_link_map));
+		cur_lch = dma_chan[lch].next_lch;
+		do {
+			next_lch = dma_chan[cur_lch].next_lch;
+
+                        /* The loop case: we've been here already */
+			if (dma_chan_link_map[cur_lch])
+				break;
+			/* Mark the current channel */
+			dma_chan_link_map[cur_lch] = 1;
+
+			enable_lnk(cur_lch);
+			init_intr(cur_lch);
+
+			cur_lch = next_lch;
+		} while (next_lch != -1);
+	}
+
+	init_intr(lch);
+
+	w = omap_readw(OMAP_DMA_CCR(lch));
+	w |= OMAP_DMA_CCR_EN;
+	omap_writew(w, OMAP_DMA_CCR(lch));
+	dma_chan[lch].flags |= OMAP_DMA_ACTIVE;
+}
+
+void omap_stop_dma(int lch)
+{
+	u16 w;
+
+	if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) {
+		int next_lch, cur_lch = lch;
+		char dma_chan_link_map[OMAP_LOGICAL_DMA_CH_COUNT];
+
+		memset(dma_chan_link_map, 0, sizeof(dma_chan_link_map));
+		do {
+			/* The loop case: we've been here already */
+			if (dma_chan_link_map[cur_lch])
+				break;
+			/* Mark the current channel */
+			dma_chan_link_map[cur_lch] = 1;
+
+			disable_lnk(cur_lch);
+
+			next_lch = dma_chan[cur_lch].next_lch;
+			cur_lch = next_lch;
+		} while (next_lch != -1);
+
+		return;
+	}
+	/* Disable all interrupts on the channel */
+	omap_writew(0, OMAP_DMA_CICR(lch));
+
+	w = omap_readw(OMAP_DMA_CCR(lch));
+	w &= ~OMAP_DMA_CCR_EN;
+	omap_writew(w, OMAP_DMA_CCR(lch));
+	dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE;
+}
+
+void omap_enable_dma_irq(int lch, u16 bits)
+{
+	dma_chan[lch].enabled_irqs |= bits;
+}
+
+void omap_disable_dma_irq(int lch, u16 bits)
+{
+	dma_chan[lch].enabled_irqs &= ~bits;
+}
+
+static int dma_handle_ch(int ch)
+{
+	u16 csr;
+
+	if (enable_1510_mode && ch >= 6) {
+		csr = dma_chan[ch].saved_csr;
+		dma_chan[ch].saved_csr = 0;
+	} else
+		csr = omap_readw(OMAP_DMA_CSR(ch));
+	if (enable_1510_mode && ch <= 2 && (csr >> 7) != 0) {
+		dma_chan[ch + 6].saved_csr = csr >> 7;
+		csr &= 0x7f;
+	}
+	if (!csr)
+		return 0;
+	if (unlikely(dma_chan[ch].dev_id == -1)) {
+		printk(KERN_WARNING "Spurious interrupt from DMA channel %d (CSR %04x)\n",
+		       ch, csr);
+		return 0;
+	}
+	if (unlikely(csr & OMAP_DMA_TOUT_IRQ))
+		printk(KERN_WARNING "DMA timeout with device %d\n", dma_chan[ch].dev_id);
+	if (unlikely(csr & OMAP_DMA_DROP_IRQ))
+		printk(KERN_WARNING "DMA synchronization event drop occurred with device %d\n",
+		       dma_chan[ch].dev_id);
+	if (likely(csr & OMAP_DMA_BLOCK_IRQ))
+		dma_chan[ch].flags &= ~OMAP_DMA_ACTIVE;
+	if (likely(dma_chan[ch].callback != NULL))
+		dma_chan[ch].callback(ch, csr, dma_chan[ch].data);
+	return 1;
+}
+
+static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int ch = ((int) dev_id) - 1;
+	int handled = 0;
+
+	for (;;) {
+		int handled_now = 0;
+
+		handled_now += dma_handle_ch(ch);
+		if (enable_1510_mode && dma_chan[ch + 6].saved_csr)
+			handled_now += dma_handle_ch(ch + 6);
+		if (!handled_now)
+			break;
+		handled += handled_now;
+	}
+
+	return handled ? IRQ_HANDLED : IRQ_NONE;
+}
+
+int omap_request_dma(int dev_id, const char *dev_name,
+		     void (* callback)(int lch, u16 ch_status, void *data),
+		     void *data, int *dma_ch_out)
+{
+	int ch, free_ch = -1;
+	unsigned long flags;
+	struct omap_dma_lch *chan;
+
+	spin_lock_irqsave(&dma_chan_lock, flags);
+	for (ch = 0; ch < dma_chan_count; ch++) {
+		if (free_ch == -1 && dma_chan[ch].dev_id == -1) {
+			free_ch = ch;
+			if (dev_id == 0)
+				break;
+		}
+	}
+	if (free_ch == -1) {
+		spin_unlock_irqrestore(&dma_chan_lock, flags);
+		return -EBUSY;
+	}
+	chan = dma_chan + free_ch;
+	chan->dev_id = dev_id;
+	clear_lch_regs(free_ch);
+	spin_unlock_irqrestore(&dma_chan_lock, flags);
+
+	chan->dev_id = dev_id;
+	chan->dev_name = dev_name;
+	chan->callback = callback;
+	chan->data = data;
+	chan->enabled_irqs = OMAP_DMA_TOUT_IRQ | OMAP_DMA_DROP_IRQ | OMAP_DMA_BLOCK_IRQ;
+
+	if (cpu_is_omap16xx()) {
+		/* If the sync device is set, configure it dynamically. */
+		if (dev_id != 0) {
+			set_gdma_dev(free_ch + 1, dev_id);
+			dev_id = free_ch + 1;
+		}
+		/* Disable the 1510 compatibility mode and set the sync device
+		 * id. */
+		omap_writew(dev_id | (1 << 10), OMAP_DMA_CCR(free_ch));
+	} else {
+		omap_writew(dev_id, OMAP_DMA_CCR(free_ch));
+	}
+	*dma_ch_out = free_ch;
+
+	return 0;
+}
+
+void omap_free_dma(int ch)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dma_chan_lock, flags);
+	if (dma_chan[ch].dev_id == -1) {
+		printk("omap_dma: trying to free nonallocated DMA channel %d\n", ch);
+		spin_unlock_irqrestore(&dma_chan_lock, flags);
+		return;
+	}
+	dma_chan[ch].dev_id = -1;
+	spin_unlock_irqrestore(&dma_chan_lock, flags);
+
+	/* Disable all DMA interrupts for the channel. */
+	omap_writew(0, OMAP_DMA_CICR(ch));
+	/* Make sure the DMA transfer is stopped. */
+	omap_writew(0, OMAP_DMA_CCR(ch));
+}
+
+int omap_dma_in_1510_mode(void)
+{
+	return enable_1510_mode;
+}
+
+/*
+ * lch_queue DMA will start right after lch_head one is finished.
+ * For this DMA link to start, you still need to start (see omap_start_dma)
+ * the first one. That will fire up the entire queue.
+ */
+void omap_dma_link_lch (int lch_head, int lch_queue)
+{
+	if (omap_dma_in_1510_mode()) {
+		printk(KERN_ERR "DMA linking is not supported in 1510 mode\n");
+		BUG();
+		return;
+	}
+
+	if ((dma_chan[lch_head].dev_id == -1) ||
+	    (dma_chan[lch_queue].dev_id == -1)) {
+		printk(KERN_ERR "omap_dma: trying to link non requested channels\n");
+		dump_stack();
+	}
+
+	dma_chan[lch_head].next_lch = lch_queue;
+}
+
+/*
+ * Once the DMA queue is stopped, we can destroy it.
+ */
+void omap_dma_unlink_lch (int lch_head, int lch_queue)
+{
+	if (omap_dma_in_1510_mode()) {
+		printk(KERN_ERR "DMA linking is not supported in 1510 mode\n");
+		BUG();
+		return;
+	}
+
+	if (dma_chan[lch_head].next_lch != lch_queue ||
+	    dma_chan[lch_head].next_lch == -1) {
+		printk(KERN_ERR "omap_dma: trying to unlink non linked channels\n");
+		dump_stack();
+	}
+
+
+	if ((dma_chan[lch_head].flags & OMAP_DMA_ACTIVE) ||
+	    (dma_chan[lch_head].flags & OMAP_DMA_ACTIVE)) {
+		printk(KERN_ERR "omap_dma: You need to stop the DMA channels before unlinking\n");
+		dump_stack();
+	}
+
+	dma_chan[lch_head].next_lch = -1;
+}
+
+
+static struct lcd_dma_info {
+	spinlock_t lock;
+	int reserved;
+	void (* callback)(u16 status, void *data);
+	void *cb_data;
+
+	int active;
+	unsigned long addr, size;
+	int rotate, data_type, xres, yres;
+	int vxres;
+	int mirror;
+	int xscale, yscale;
+	int ext_ctrl;
+	int src_port;
+	int single_transfer;
+} lcd_dma;
+
+void omap_set_lcd_dma_b1(unsigned long addr, u16 fb_xres, u16 fb_yres,
+			 int data_type)
+{
+	lcd_dma.addr = addr;
+	lcd_dma.data_type = data_type;
+	lcd_dma.xres = fb_xres;
+	lcd_dma.yres = fb_yres;
+}
+
+void omap_set_lcd_dma_src_port(int port)
+{
+	lcd_dma.src_port = port;
+}
+
+void omap_set_lcd_dma_ext_controller(int external)
+{
+	lcd_dma.ext_ctrl = external;
+}
+
+void omap_set_lcd_dma_single_transfer(int single)
+{
+	lcd_dma.single_transfer = single;
+}
+
+
+void omap_set_lcd_dma_b1_rotation(int rotate)
+{
+	if (omap_dma_in_1510_mode()) {
+		printk(KERN_ERR "DMA rotation is not supported in 1510 mode\n");
+		BUG();
+		return;
+	}
+	lcd_dma.rotate = rotate;
+}
+
+void omap_set_lcd_dma_b1_mirror(int mirror)
+{
+	if (omap_dma_in_1510_mode()) {
+		printk(KERN_ERR "DMA mirror is not supported in 1510 mode\n");
+		BUG();
+	}
+	lcd_dma.mirror = mirror;
+}
+
+void omap_set_lcd_dma_b1_vxres(unsigned long vxres)
+{
+	if (omap_dma_in_1510_mode()) {
+		printk(KERN_ERR "DMA virtual resulotion is not supported "
+				"in 1510 mode\n");
+		BUG();
+	}
+	lcd_dma.vxres = vxres;
+}
+
+void omap_set_lcd_dma_b1_scale(unsigned int xscale, unsigned int yscale)
+{
+	if (omap_dma_in_1510_mode()) {
+		printk(KERN_ERR "DMA scale is not supported in 1510 mode\n");
+		BUG();
+	}
+	lcd_dma.xscale = xscale;
+	lcd_dma.yscale = yscale;
+}
+
+static void set_b1_regs(void)
+{
+	unsigned long top, bottom;
+	int es;
+	u16 w;
+	unsigned long en, fn;
+	long ei, fi;
+	unsigned long vxres;
+	unsigned int xscale, yscale;
+
+	switch (lcd_dma.data_type) {
+	case OMAP_DMA_DATA_TYPE_S8:
+		es = 1;
+		break;
+	case OMAP_DMA_DATA_TYPE_S16:
+		es = 2;
+		break;
+	case OMAP_DMA_DATA_TYPE_S32:
+		es = 4;
+		break;
+	default:
+		BUG();
+		return;
+	}
+
+	vxres = lcd_dma.vxres ? lcd_dma.vxres : lcd_dma.xres;
+	xscale = lcd_dma.xscale ? lcd_dma.xscale : 1;
+	yscale = lcd_dma.yscale ? lcd_dma.yscale : 1;
+	BUG_ON(vxres < lcd_dma.xres);
+#define PIXADDR(x,y) (lcd_dma.addr + ((y) * vxres * yscale + (x) * xscale) * es)
+#define PIXSTEP(sx, sy, dx, dy) (PIXADDR(dx, dy) - PIXADDR(sx, sy) - es + 1)
+	switch (lcd_dma.rotate) {
+	case 0:
+		if (!lcd_dma.mirror) {
+			top = PIXADDR(0, 0);
+			bottom = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1);
+			/* 1510 DMA requires the bottom address to be 2 more
+			 * than the actual last memory access location. */
+			if (omap_dma_in_1510_mode() &&
+			    lcd_dma.data_type == OMAP_DMA_DATA_TYPE_S32)
+				bottom += 2;
+			ei = PIXSTEP(0, 0, 1, 0);
+			fi = PIXSTEP(lcd_dma.xres - 1, 0, 0, 1);
+		} else {
+			top = PIXADDR(lcd_dma.xres - 1, 0);
+			bottom = PIXADDR(0, lcd_dma.yres - 1);
+			ei = PIXSTEP(1, 0, 0, 0);
+			fi = PIXSTEP(0, 0, lcd_dma.xres - 1, 1);
+		}
+		en = lcd_dma.xres;
+		fn = lcd_dma.yres;
+		break;
+	case 90:
+		if (!lcd_dma.mirror) {
+			top = PIXADDR(0, lcd_dma.yres - 1);
+			bottom = PIXADDR(lcd_dma.xres - 1, 0);
+			ei = PIXSTEP(0, 1, 0, 0);
+			fi = PIXSTEP(0, 0, 1, lcd_dma.yres - 1);
+		} else {
+			top = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1);
+			bottom = PIXADDR(0, 0);
+			ei = PIXSTEP(0, 1, 0, 0);
+			fi = PIXSTEP(1, 0, 0, lcd_dma.yres - 1);
+		}
+		en = lcd_dma.yres;
+		fn = lcd_dma.xres;
+		break;
+	case 180:
+		if (!lcd_dma.mirror) {
+			top = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1);
+			bottom = PIXADDR(0, 0);
+			ei = PIXSTEP(1, 0, 0, 0);
+			fi = PIXSTEP(0, 1, lcd_dma.xres - 1, 0);
+		} else {
+			top = PIXADDR(0, lcd_dma.yres - 1);
+			bottom = PIXADDR(lcd_dma.xres - 1, 0);
+			ei = PIXSTEP(0, 0, 1, 0);
+			fi = PIXSTEP(lcd_dma.xres - 1, 1, 0, 0);
+		}
+		en = lcd_dma.xres;
+		fn = lcd_dma.yres;
+		break;
+	case 270:
+		if (!lcd_dma.mirror) {
+			top = PIXADDR(lcd_dma.xres - 1, 0);
+			bottom = PIXADDR(0, lcd_dma.yres - 1);
+			ei = PIXSTEP(0, 0, 0, 1);
+			fi = PIXSTEP(1, lcd_dma.yres - 1, 0, 0);
+		} else {
+			top = PIXADDR(0, 0);
+			bottom = PIXADDR(lcd_dma.xres - 1, lcd_dma.yres - 1);
+			ei = PIXSTEP(0, 0, 0, 1);
+			fi = PIXSTEP(0, lcd_dma.yres - 1, 1, 0);
+		}
+		en = lcd_dma.yres;
+		fn = lcd_dma.xres;
+		break;
+	default:
+		BUG();
+		return;	/* Supress warning about uninitialized vars */
+	}
+
+	if (omap_dma_in_1510_mode()) {
+		omap_writew(top >> 16, OMAP1510_DMA_LCD_TOP_F1_U);
+		omap_writew(top, OMAP1510_DMA_LCD_TOP_F1_L);
+		omap_writew(bottom >> 16, OMAP1510_DMA_LCD_BOT_F1_U);
+		omap_writew(bottom, OMAP1510_DMA_LCD_BOT_F1_L);
+
+		return;
+	}
+
+	/* 1610 regs */
+	omap_writew(top >> 16, OMAP1610_DMA_LCD_TOP_B1_U);
+	omap_writew(top, OMAP1610_DMA_LCD_TOP_B1_L);
+	omap_writew(bottom >> 16, OMAP1610_DMA_LCD_BOT_B1_U);
+	omap_writew(bottom, OMAP1610_DMA_LCD_BOT_B1_L);
+
+	omap_writew(en, OMAP1610_DMA_LCD_SRC_EN_B1);
+	omap_writew(fn, OMAP1610_DMA_LCD_SRC_FN_B1);
+
+	w = omap_readw(OMAP1610_DMA_LCD_CSDP);
+	w &= ~0x03;
+	w |= lcd_dma.data_type;
+	omap_writew(w, OMAP1610_DMA_LCD_CSDP);
+
+	w = omap_readw(OMAP1610_DMA_LCD_CTRL);
+	/* Always set the source port as SDRAM for now*/
+	w &= ~(0x03 << 6);
+	if (lcd_dma.ext_ctrl)
+		w |= 1 << 8;
+	else
+		w &= ~(1 << 8);
+	if (lcd_dma.callback != NULL)
+		w |= 1 << 1;            /* Block interrupt enable */
+	else
+		w &= ~(1 << 1);
+	omap_writew(w, OMAP1610_DMA_LCD_CTRL);
+
+	if (!(lcd_dma.rotate || lcd_dma.mirror ||
+	      lcd_dma.vxres || lcd_dma.xscale || lcd_dma.yscale))
+		return;
+
+	w = omap_readw(OMAP1610_DMA_LCD_CCR);
+	/* Set the double-indexed addressing mode */
+	w |= (0x03 << 12);
+	omap_writew(w, OMAP1610_DMA_LCD_CCR);
+
+	omap_writew(ei, OMAP1610_DMA_LCD_SRC_EI_B1);
+	omap_writew(fi >> 16, OMAP1610_DMA_LCD_SRC_FI_B1_U);
+	omap_writew(fi, OMAP1610_DMA_LCD_SRC_FI_B1_L);
+}
+
+static irqreturn_t lcd_dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	u16 w;
+
+	w = omap_readw(OMAP1610_DMA_LCD_CTRL);
+	if (unlikely(!(w & (1 << 3)))) {
+		printk(KERN_WARNING "Spurious LCD DMA IRQ\n");
+		return IRQ_NONE;
+	}
+	/* Ack the IRQ */
+	w |= (1 << 3);
+	omap_writew(w, OMAP1610_DMA_LCD_CTRL);
+	lcd_dma.active = 0;
+	if (lcd_dma.callback != NULL)
+		lcd_dma.callback(w, lcd_dma.cb_data);
+
+	return IRQ_HANDLED;
+}
+
+int omap_request_lcd_dma(void (* callback)(u16 status, void *data),
+			 void *data)
+{
+	spin_lock_irq(&lcd_dma.lock);
+	if (lcd_dma.reserved) {
+		spin_unlock_irq(&lcd_dma.lock);
+		printk(KERN_ERR "LCD DMA channel already reserved\n");
+		BUG();
+		return -EBUSY;
+	}
+	lcd_dma.reserved = 1;
+	spin_unlock_irq(&lcd_dma.lock);
+	lcd_dma.callback = callback;
+	lcd_dma.cb_data = data;
+	lcd_dma.active = 0;
+	lcd_dma.single_transfer = 0;
+	lcd_dma.rotate = 0;
+	lcd_dma.vxres = 0;
+	lcd_dma.mirror = 0;
+	lcd_dma.xscale = 0;
+	lcd_dma.yscale = 0;
+	lcd_dma.ext_ctrl = 0;
+	lcd_dma.src_port = 0;
+
+	return 0;
+}
+
+void omap_free_lcd_dma(void)
+{
+	spin_lock(&lcd_dma.lock);
+	if (!lcd_dma.reserved) {
+		spin_unlock(&lcd_dma.lock);
+		printk(KERN_ERR "LCD DMA is not reserved\n");
+		BUG();
+		return;
+	}
+	if (!enable_1510_mode)
+		omap_writew(omap_readw(OMAP1610_DMA_LCD_CCR) & ~1, OMAP1610_DMA_LCD_CCR);
+	lcd_dma.reserved = 0;
+	spin_unlock(&lcd_dma.lock);
+}
+
+void omap_enable_lcd_dma(void)
+{
+	u16 w;
+
+	/* Set the Enable bit only if an external controller is
+	 * connected. Otherwise the OMAP internal controller will
+	 * start the transfer when it gets enabled.
+	 */
+	if (enable_1510_mode || !lcd_dma.ext_ctrl)
+		return;
+	w = omap_readw(OMAP1610_DMA_LCD_CCR);
+	w |= 1 << 7;
+	omap_writew(w, OMAP1610_DMA_LCD_CCR);
+	lcd_dma.active = 1;
+}
+
+void omap_setup_lcd_dma(void)
+{
+	BUG_ON(lcd_dma.active);
+	if (!enable_1510_mode) {
+		/* Set some reasonable defaults */
+		omap_writew(0x5440, OMAP1610_DMA_LCD_CCR);
+		omap_writew(0x9102, OMAP1610_DMA_LCD_CSDP);
+		omap_writew(0x0004, OMAP1610_DMA_LCD_LCH_CTRL);
+	}
+	set_b1_regs();
+	if (!enable_1510_mode) {
+		u16 w;
+
+		w = omap_readw(OMAP1610_DMA_LCD_CCR);
+		/* If DMA was already active set the end_prog bit to have
+		 * the programmed register set loaded into the active
+		 * register set.
+		 */
+		w |= 1 << 11;		/* End_prog */
+		if (!lcd_dma.single_transfer)
+	        	w |= (3 << 8);	/* Auto_init, repeat */
+		omap_writew(w, OMAP1610_DMA_LCD_CCR);
+	}
+}
+
+void omap_stop_lcd_dma(void)
+{
+	lcd_dma.active = 0;
+	if (!enable_1510_mode && lcd_dma.ext_ctrl)
+		omap_writew(omap_readw(OMAP1610_DMA_LCD_CCR) & ~(1 << 7),
+			    OMAP1610_DMA_LCD_CCR);
+}
+
+/*
+ * Clears any DMA state so the DMA engine is ready to restart with new buffers
+ * through omap_start_dma(). Any buffers in flight are discarded.
+ */
+void omap_clear_dma(int lch)
+{
+	unsigned long flags;
+	int status;
+
+	local_irq_save(flags);
+	omap_writew(omap_readw(OMAP_DMA_CCR(lch)) & ~OMAP_DMA_CCR_EN,
+		    OMAP_DMA_CCR(lch));
+	status = OMAP_DMA_CSR(lch);	/* clear pending interrupts */
+	local_irq_restore(flags);
+}
+
+/*
+ * Returns current physical source address for the given DMA channel.
+ * If the channel is running the caller must disable interrupts prior calling
+ * this function and process the returned value before re-enabling interrupt to
+ * prevent races with the interrupt handler. Note that in continuous mode there
+ * is a chance for CSSA_L register overflow inbetween the two reads resulting
+ * in incorrect return value.
+ */
+dma_addr_t omap_get_dma_src_pos(int lch)
+{
+	return (dma_addr_t) (OMAP_DMA_CSSA_L(lch) |
+			     (OMAP_DMA_CSSA_U(lch) << 16));
+}
+
+/*
+ * Returns current physical destination address for the given DMA channel.
+ * If the channel is running the caller must disable interrupts prior calling
+ * this function and process the returned value before re-enabling interrupt to
+ * prevent races with the interrupt handler. Note that in continuous mode there
+ * is a chance for CDSA_L register overflow inbetween the two reads resulting
+ * in incorrect return value.
+ */
+dma_addr_t omap_get_dma_dst_pos(int lch)
+{
+	return (dma_addr_t) (OMAP_DMA_CDSA_L(lch) |
+			     (OMAP_DMA_CDSA_U(lch) << 16));
+}
+
+static int __init omap_init_dma(void)
+{
+	int ch, r;
+
+	if (cpu_is_omap1510()) {
+		printk(KERN_INFO "DMA support for OMAP1510 initialized\n");
+		dma_chan_count = 9;
+		enable_1510_mode = 1;
+	} else if (cpu_is_omap16xx() || cpu_is_omap730()) {
+		printk(KERN_INFO "OMAP DMA hardware version %d\n",
+		       omap_readw(OMAP_DMA_HW_ID));
+		printk(KERN_INFO "DMA capabilities: %08x:%08x:%04x:%04x:%04x\n",
+		       (omap_readw(OMAP_DMA_CAPS_0_U) << 16) | omap_readw(OMAP_DMA_CAPS_0_L),
+		       (omap_readw(OMAP_DMA_CAPS_1_U) << 16) | omap_readw(OMAP_DMA_CAPS_1_L),
+		       omap_readw(OMAP_DMA_CAPS_2), omap_readw(OMAP_DMA_CAPS_3),
+		       omap_readw(OMAP_DMA_CAPS_4));
+		if (!enable_1510_mode) {
+			u16 w;
+
+			/* Disable OMAP 3.0/3.1 compatibility mode. */
+			w = omap_readw(OMAP_DMA_GSCR);
+			w |= 1 << 3;
+			omap_writew(w, OMAP_DMA_GSCR);
+			dma_chan_count = 16;
+		} else
+			dma_chan_count = 9;
+	} else {
+		dma_chan_count = 0;
+		return 0;
+	}
+
+	memset(&lcd_dma, 0, sizeof(lcd_dma));
+	spin_lock_init(&lcd_dma.lock);
+	spin_lock_init(&dma_chan_lock);
+	memset(&dma_chan, 0, sizeof(dma_chan));
+
+	for (ch = 0; ch < dma_chan_count; ch++) {
+		dma_chan[ch].dev_id = -1;
+		dma_chan[ch].next_lch = -1;
+
+		if (ch >= 6 && enable_1510_mode)
+			continue;
+
+		/* request_irq() doesn't like dev_id (ie. ch) being zero,
+		 * so we have to kludge around this. */
+		r = request_irq(dma_irq[ch], dma_irq_handler, 0, "DMA",
+				(void *) (ch + 1));
+		if (r != 0) {
+			int i;
+
+			printk(KERN_ERR "unable to request IRQ %d for DMA (error %d)\n",
+			       dma_irq[ch], r);
+			for (i = 0; i < ch; i++)
+				free_irq(dma_irq[i], (void *) (i + 1));
+			return r;
+		}
+	}
+	r = request_irq(INT_DMA_LCD, lcd_dma_irq_handler, 0, "LCD DMA", NULL);
+	if (r != 0) {
+		int i;
+
+		printk(KERN_ERR "unable to request IRQ for LCD DMA (error %d)\n", r);
+		for (i = 0; i < dma_chan_count; i++)
+			free_irq(dma_irq[i], (void *) (i + 1));
+		return r;
+	}
+	return 0;
+}
+
+arch_initcall(omap_init_dma);
+
+
+EXPORT_SYMBOL(omap_get_dma_src_pos);
+EXPORT_SYMBOL(omap_get_dma_dst_pos);
+EXPORT_SYMBOL(omap_clear_dma);
+EXPORT_SYMBOL(omap_set_dma_priority);
+EXPORT_SYMBOL(omap_request_dma);
+EXPORT_SYMBOL(omap_free_dma);
+EXPORT_SYMBOL(omap_start_dma);
+EXPORT_SYMBOL(omap_stop_dma);
+EXPORT_SYMBOL(omap_enable_dma_irq);
+EXPORT_SYMBOL(omap_disable_dma_irq);
+
+EXPORT_SYMBOL(omap_set_dma_transfer_params);
+EXPORT_SYMBOL(omap_set_dma_color_mode);
+
+EXPORT_SYMBOL(omap_set_dma_src_params);
+EXPORT_SYMBOL(omap_set_dma_src_index);
+EXPORT_SYMBOL(omap_set_dma_src_data_pack);
+EXPORT_SYMBOL(omap_set_dma_src_burst_mode);
+
+EXPORT_SYMBOL(omap_set_dma_dest_params);
+EXPORT_SYMBOL(omap_set_dma_dest_index);
+EXPORT_SYMBOL(omap_set_dma_dest_data_pack);
+EXPORT_SYMBOL(omap_set_dma_dest_burst_mode);
+
+EXPORT_SYMBOL(omap_dma_link_lch);
+EXPORT_SYMBOL(omap_dma_unlink_lch);
+
+EXPORT_SYMBOL(omap_request_lcd_dma);
+EXPORT_SYMBOL(omap_free_lcd_dma);
+EXPORT_SYMBOL(omap_enable_lcd_dma);
+EXPORT_SYMBOL(omap_setup_lcd_dma);
+EXPORT_SYMBOL(omap_stop_lcd_dma);
+EXPORT_SYMBOL(omap_set_lcd_dma_b1);
+EXPORT_SYMBOL(omap_set_lcd_dma_single_transfer);
+EXPORT_SYMBOL(omap_set_lcd_dma_ext_controller);
+EXPORT_SYMBOL(omap_set_lcd_dma_b1_rotation);
+EXPORT_SYMBOL(omap_set_lcd_dma_b1_vxres);
+EXPORT_SYMBOL(omap_set_lcd_dma_b1_scale);
+EXPORT_SYMBOL(omap_set_lcd_dma_b1_mirror);
+
diff --git a/arch/arm/mach-omap/fpga.c b/arch/arm/mach-omap/fpga.c
new file mode 100644
index 0000000..7c08f6c
--- /dev/null
+++ b/arch/arm/mach-omap/fpga.c
@@ -0,0 +1,188 @@
+/*
+ * linux/arch/arm/mach-omap/fpga.c
+ *
+ * Interrupt handler for OMAP-1510 Innovator FPGA
+ *
+ * Copyright (C) 2001 RidgeRun, Inc.
+ * Author: Greg Lonnon <glonnon@ridgerun.com>
+ *
+ * Copyright (C) 2002 MontaVista Software, Inc.
+ *
+ * Separated FPGA interrupts from innovator1510.c and cleaned up for 2.6
+ * Copyright (C) 2004 Nokia Corporation by Tony Lindrgen <tony@atomide.com>
+ *
+ * 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/config.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+
+#include <asm/arch/fpga.h>
+#include <asm/arch/gpio.h>
+
+static void fpga_mask_irq(unsigned int irq)
+{
+	irq -= OMAP1510_IH_FPGA_BASE;
+
+	if (irq < 8)
+		__raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_LO)
+			      & ~(1 << irq)), OMAP1510_FPGA_IMR_LO);
+	else if (irq < 16)
+		__raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_HI)
+			      & ~(1 << (irq - 8))), OMAP1510_FPGA_IMR_HI);
+	else
+		__raw_writeb((__raw_readb(INNOVATOR_FPGA_IMR2)
+			      & ~(1 << (irq - 16))), INNOVATOR_FPGA_IMR2);
+}
+
+
+static inline u32 get_fpga_unmasked_irqs(void)
+{
+	return
+		((__raw_readb(OMAP1510_FPGA_ISR_LO) &
+		  __raw_readb(OMAP1510_FPGA_IMR_LO))) |
+		((__raw_readb(OMAP1510_FPGA_ISR_HI) &
+		  __raw_readb(OMAP1510_FPGA_IMR_HI)) << 8) |
+		((__raw_readb(INNOVATOR_FPGA_ISR2) &
+		  __raw_readb(INNOVATOR_FPGA_IMR2)) << 16);
+}
+
+
+static void fpga_ack_irq(unsigned int irq)
+{
+	/* Don't need to explicitly ACK FPGA interrupts */
+}
+
+static void fpga_unmask_irq(unsigned int irq)
+{
+	irq -= OMAP1510_IH_FPGA_BASE;
+
+	if (irq < 8)
+		__raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_LO) | (1 << irq)),
+		     OMAP1510_FPGA_IMR_LO);
+	else if (irq < 16)
+		__raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_HI)
+			      | (1 << (irq - 8))), OMAP1510_FPGA_IMR_HI);
+	else
+		__raw_writeb((__raw_readb(INNOVATOR_FPGA_IMR2)
+			      | (1 << (irq - 16))), INNOVATOR_FPGA_IMR2);
+}
+
+static void fpga_mask_ack_irq(unsigned int irq)
+{
+	fpga_mask_irq(irq);
+	fpga_ack_irq(irq);
+}
+
+void innovator_fpga_IRQ_demux(unsigned int irq, struct irqdesc *desc,
+			      struct pt_regs *regs)
+{
+	struct irqdesc *d;
+	u32 stat;
+	int fpga_irq;
+
+	stat = get_fpga_unmasked_irqs();
+
+	if (!stat)
+		return;
+
+	for (fpga_irq = OMAP1510_IH_FPGA_BASE;
+	     (fpga_irq < (OMAP1510_IH_FPGA_BASE + NR_FPGA_IRQS)) && stat;
+	     fpga_irq++, stat >>= 1) {
+		if (stat & 1) {
+			d = irq_desc + fpga_irq;
+			d->handle(fpga_irq, d, regs);
+		}
+	}
+}
+
+static struct irqchip omap_fpga_irq_ack = {
+	.ack		= fpga_mask_ack_irq,
+	.mask		= fpga_mask_irq,
+	.unmask		= fpga_unmask_irq,
+};
+
+
+static struct irqchip omap_fpga_irq = {
+	.ack		= fpga_ack_irq,
+	.mask		= fpga_mask_irq,
+	.unmask		= fpga_unmask_irq,
+};
+
+/*
+ * All of the FPGA interrupt request inputs except for the touchscreen are
+ * edge-sensitive; the touchscreen is level-sensitive.  The edge-sensitive
+ * interrupts are acknowledged as a side-effect of reading the interrupt
+ * status register from the FPGA.  The edge-sensitive interrupt inputs
+ * cause a problem with level interrupt requests, such as Ethernet.  The
+ * problem occurs when a level interrupt request is asserted while its
+ * interrupt input is masked in the FPGA, which results in a missed
+ * interrupt.
+ *
+ * In an attempt to workaround the problem with missed interrupts, the
+ * mask_ack routine for all of the FPGA interrupts has been changed from
+ * fpga_mask_ack_irq() to fpga_ack_irq() so that the specific FPGA interrupt
+ * being serviced is left unmasked.  We can do this because the FPGA cascade
+ * interrupt is installed with the SA_INTERRUPT flag, which leaves all
+ * interrupts masked at the CPU while an FPGA interrupt handler executes.
+ *
+ * Limited testing indicates that this workaround appears to be effective
+ * for the smc9194 Ethernet driver used on the Innovator.  It should work
+ * on other FPGA interrupts as well, but any drivers that explicitly mask
+ * interrupts at the interrupt controller via disable_irq/enable_irq
+ * could pose a problem.
+ */
+void omap1510_fpga_init_irq(void)
+{
+	int i;
+
+	__raw_writeb(0, OMAP1510_FPGA_IMR_LO);
+	__raw_writeb(0, OMAP1510_FPGA_IMR_HI);
+	__raw_writeb(0, INNOVATOR_FPGA_IMR2);
+
+	for (i = OMAP1510_IH_FPGA_BASE; i < (OMAP1510_IH_FPGA_BASE + NR_FPGA_IRQS); i++) {
+
+		if (i == OMAP1510_INT_FPGA_TS) {
+			/*
+			 * The touchscreen interrupt is level-sensitive, so
+			 * we'll use the regular mask_ack routine for it.
+			 */
+			set_irq_chip(i, &omap_fpga_irq_ack);
+		}
+		else {
+			/*
+			 * All FPGA interrupts except the touchscreen are
+			 * edge-sensitive, so we won't mask them.
+			 */
+			set_irq_chip(i, &omap_fpga_irq);
+		}
+
+		set_irq_handler(i, do_edge_IRQ);
+		set_irq_flags(i, IRQF_VALID);
+	}
+
+	/*
+	 * The FPGA interrupt line is connected to GPIO13. Claim this pin for
+	 * the ARM.
+	 *
+	 * NOTE: For general GPIO/MPUIO access and interrupts, please see
+	 * gpio.[ch]
+	 */
+	omap_request_gpio(13);
+	omap_set_gpio_direction(13, 1);
+	omap_set_gpio_edge_ctrl(13, OMAP_GPIO_RISING_EDGE);
+	set_irq_chained_handler(OMAP1510_INT_FPGA, innovator_fpga_IRQ_demux);
+}
+
+EXPORT_SYMBOL(omap1510_fpga_init_irq);
diff --git a/arch/arm/mach-omap/gpio.c b/arch/arm/mach-omap/gpio.c
new file mode 100644
index 0000000..9045dfd
--- /dev/null
+++ b/arch/arm/mach-omap/gpio.c
@@ -0,0 +1,762 @@
+/*
+ *  linux/arch/arm/mach-omap/gpio.c
+ *
+ * Support functions for OMAP GPIO
+ *
+ * Copyright (C) 2003 Nokia Corporation
+ * Written by Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * 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/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/gpio.h>
+#include <asm/mach/irq.h>
+
+#include <asm/io.h>
+
+/*
+ * OMAP1510 GPIO registers
+ */
+#define OMAP1510_GPIO_BASE		0xfffce000
+#define OMAP1510_GPIO_DATA_INPUT	0x00
+#define OMAP1510_GPIO_DATA_OUTPUT	0x04
+#define OMAP1510_GPIO_DIR_CONTROL	0x08
+#define OMAP1510_GPIO_INT_CONTROL	0x0c
+#define OMAP1510_GPIO_INT_MASK		0x10
+#define OMAP1510_GPIO_INT_STATUS	0x14
+#define OMAP1510_GPIO_PIN_CONTROL	0x18
+
+#define OMAP1510_IH_GPIO_BASE		64
+
+/*
+ * OMAP1610 specific GPIO registers
+ */
+#define OMAP1610_GPIO1_BASE		0xfffbe400
+#define OMAP1610_GPIO2_BASE		0xfffbec00
+#define OMAP1610_GPIO3_BASE		0xfffbb400
+#define OMAP1610_GPIO4_BASE		0xfffbbc00
+#define OMAP1610_GPIO_REVISION		0x0000
+#define OMAP1610_GPIO_SYSCONFIG		0x0010
+#define OMAP1610_GPIO_SYSSTATUS		0x0014
+#define OMAP1610_GPIO_IRQSTATUS1	0x0018
+#define OMAP1610_GPIO_IRQENABLE1	0x001c
+#define OMAP1610_GPIO_DATAIN		0x002c
+#define OMAP1610_GPIO_DATAOUT		0x0030
+#define OMAP1610_GPIO_DIRECTION		0x0034
+#define OMAP1610_GPIO_EDGE_CTRL1	0x0038
+#define OMAP1610_GPIO_EDGE_CTRL2	0x003c
+#define OMAP1610_GPIO_CLEAR_IRQENABLE1	0x009c
+#define OMAP1610_GPIO_CLEAR_DATAOUT	0x00b0
+#define OMAP1610_GPIO_SET_IRQENABLE1	0x00dc
+#define OMAP1610_GPIO_SET_DATAOUT	0x00f0
+
+/*
+ * OMAP730 specific GPIO registers
+ */
+#define OMAP730_GPIO1_BASE		0xfffbc000
+#define OMAP730_GPIO2_BASE		0xfffbc800
+#define OMAP730_GPIO3_BASE		0xfffbd000
+#define OMAP730_GPIO4_BASE		0xfffbd800
+#define OMAP730_GPIO5_BASE		0xfffbe000
+#define OMAP730_GPIO6_BASE		0xfffbe800
+#define OMAP730_GPIO_DATA_INPUT		0x00
+#define OMAP730_GPIO_DATA_OUTPUT	0x04
+#define OMAP730_GPIO_DIR_CONTROL	0x08
+#define OMAP730_GPIO_INT_CONTROL	0x0c
+#define OMAP730_GPIO_INT_MASK		0x10
+#define OMAP730_GPIO_INT_STATUS		0x14
+
+#define OMAP_MPUIO_MASK		(~OMAP_MAX_GPIO_LINES & 0xff)
+
+struct gpio_bank {
+	u32 base;
+	u16 irq;
+	u16 virtual_irq_start;
+	u8 method;
+	u32 reserved_map;
+	spinlock_t lock;
+};
+
+#define METHOD_MPUIO		0
+#define METHOD_GPIO_1510	1
+#define METHOD_GPIO_1610	2
+#define METHOD_GPIO_730		3
+
+#if defined(CONFIG_ARCH_OMAP16XX)
+static struct gpio_bank gpio_bank_1610[5] = {
+	{ OMAP_MPUIO_BASE,     INT_MPUIO,	    IH_MPUIO_BASE,     METHOD_MPUIO},
+	{ OMAP1610_GPIO1_BASE, INT_GPIO_BANK1,	    IH_GPIO_BASE,      METHOD_GPIO_1610 },
+	{ OMAP1610_GPIO2_BASE, INT_1610_GPIO_BANK2, IH_GPIO_BASE + 16, METHOD_GPIO_1610 },
+	{ OMAP1610_GPIO3_BASE, INT_1610_GPIO_BANK3, IH_GPIO_BASE + 32, METHOD_GPIO_1610 },
+	{ OMAP1610_GPIO4_BASE, INT_1610_GPIO_BANK4, IH_GPIO_BASE + 48, METHOD_GPIO_1610 },
+};
+#endif
+
+#ifdef CONFIG_ARCH_OMAP1510
+static struct gpio_bank gpio_bank_1510[2] = {
+	{ OMAP_MPUIO_BASE,    INT_MPUIO,      IH_MPUIO_BASE, METHOD_MPUIO },
+	{ OMAP1510_GPIO_BASE, INT_GPIO_BANK1, IH_GPIO_BASE,  METHOD_GPIO_1510 }
+};
+#endif
+
+#ifdef CONFIG_ARCH_OMAP730
+static struct gpio_bank gpio_bank_730[7] = {
+	{ OMAP_MPUIO_BASE,     INT_730_MPUIO,	    IH_MPUIO_BASE,	METHOD_MPUIO },
+	{ OMAP730_GPIO1_BASE,  INT_730_GPIO_BANK1,  IH_GPIO_BASE,	METHOD_GPIO_730 },
+	{ OMAP730_GPIO2_BASE,  INT_730_GPIO_BANK2,  IH_GPIO_BASE + 32,	METHOD_GPIO_730 },
+	{ OMAP730_GPIO3_BASE,  INT_730_GPIO_BANK3,  IH_GPIO_BASE + 64,	METHOD_GPIO_730 },
+	{ OMAP730_GPIO4_BASE,  INT_730_GPIO_BANK4,  IH_GPIO_BASE + 96,	METHOD_GPIO_730 },
+	{ OMAP730_GPIO5_BASE,  INT_730_GPIO_BANK5,  IH_GPIO_BASE + 128, METHOD_GPIO_730 },
+	{ OMAP730_GPIO6_BASE,  INT_730_GPIO_BANK6,  IH_GPIO_BASE + 160, METHOD_GPIO_730 },
+};
+#endif
+
+static struct gpio_bank *gpio_bank;
+static int gpio_bank_count;
+
+static inline struct gpio_bank *get_gpio_bank(int gpio)
+{
+#ifdef CONFIG_ARCH_OMAP1510
+	if (cpu_is_omap1510()) {
+		if (OMAP_GPIO_IS_MPUIO(gpio))
+			return &gpio_bank[0];
+		return &gpio_bank[1];
+	}
+#endif
+#if defined(CONFIG_ARCH_OMAP16XX)
+	if (cpu_is_omap16xx()) {
+		if (OMAP_GPIO_IS_MPUIO(gpio))
+			return &gpio_bank[0];
+		return &gpio_bank[1 + (gpio >> 4)];
+	}
+#endif
+#ifdef CONFIG_ARCH_OMAP730
+	if (cpu_is_omap730()) {
+		if (OMAP_GPIO_IS_MPUIO(gpio))
+			return &gpio_bank[0];
+		return &gpio_bank[1 + (gpio >> 5)];
+	}
+#endif
+}
+
+static inline int get_gpio_index(int gpio)
+{
+	if (cpu_is_omap730())
+		return gpio & 0x1f;
+	else
+		return gpio & 0x0f;
+}
+
+static inline int gpio_valid(int gpio)
+{
+	if (gpio < 0)
+		return -1;
+	if (OMAP_GPIO_IS_MPUIO(gpio)) {
+		if ((gpio & OMAP_MPUIO_MASK) > 16)
+			return -1;
+		return 0;
+	}
+#ifdef CONFIG_ARCH_OMAP1510
+	if (cpu_is_omap1510() && gpio < 16)
+		return 0;
+#endif
+#if defined(CONFIG_ARCH_OMAP16XX)
+	if ((cpu_is_omap16xx()) && gpio < 64)
+		return 0;
+#endif
+#ifdef CONFIG_ARCH_OMAP730
+	if (cpu_is_omap730() && gpio < 192)
+		return 0;
+#endif
+	return -1;
+}
+
+static int check_gpio(int gpio)
+{
+	if (unlikely(gpio_valid(gpio)) < 0) {
+		printk(KERN_ERR "omap-gpio: invalid GPIO %d\n", gpio);
+		dump_stack();
+		return -1;
+	}
+	return 0;
+}
+
+static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
+{
+	u32 reg = bank->base;
+	u32 l;
+
+	switch (bank->method) {
+	case METHOD_MPUIO:
+		reg += OMAP_MPUIO_IO_CNTL;
+		break;
+	case METHOD_GPIO_1510:
+		reg += OMAP1510_GPIO_DIR_CONTROL;
+		break;
+	case METHOD_GPIO_1610:
+		reg += OMAP1610_GPIO_DIRECTION;
+		break;
+	case METHOD_GPIO_730:
+		reg += OMAP730_GPIO_DIR_CONTROL;
+		break;
+	}
+	l = __raw_readl(reg);
+	if (is_input)
+		l |= 1 << gpio;
+	else
+		l &= ~(1 << gpio);
+	__raw_writel(l, reg);
+}
+
+void omap_set_gpio_direction(int gpio, int is_input)
+{
+	struct gpio_bank *bank;
+
+	if (check_gpio(gpio) < 0)
+		return;
+	bank = get_gpio_bank(gpio);
+	spin_lock(&bank->lock);
+	_set_gpio_direction(bank, get_gpio_index(gpio), is_input);
+	spin_unlock(&bank->lock);
+}
+
+static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable)
+{
+	u32 reg = bank->base;
+	u32 l = 0;
+
+	switch (bank->method) {
+	case METHOD_MPUIO:
+		reg += OMAP_MPUIO_OUTPUT;
+		l = __raw_readl(reg);
+		if (enable)
+			l |= 1 << gpio;
+		else
+			l &= ~(1 << gpio);
+		break;
+	case METHOD_GPIO_1510:
+		reg += OMAP1510_GPIO_DATA_OUTPUT;
+		l = __raw_readl(reg);
+		if (enable)
+			l |= 1 << gpio;
+		else
+			l &= ~(1 << gpio);
+		break;
+	case METHOD_GPIO_1610:
+		if (enable)
+			reg += OMAP1610_GPIO_SET_DATAOUT;
+		else
+			reg += OMAP1610_GPIO_CLEAR_DATAOUT;
+		l = 1 << gpio;
+		break;
+	case METHOD_GPIO_730:
+		reg += OMAP730_GPIO_DATA_OUTPUT;
+		l = __raw_readl(reg);
+		if (enable)
+			l |= 1 << gpio;
+		else
+			l &= ~(1 << gpio);
+		break;
+	default:
+		BUG();
+		return;
+	}
+	__raw_writel(l, reg);
+}
+
+void omap_set_gpio_dataout(int gpio, int enable)
+{
+	struct gpio_bank *bank;
+
+	if (check_gpio(gpio) < 0)
+		return;
+	bank = get_gpio_bank(gpio);
+	spin_lock(&bank->lock);
+	_set_gpio_dataout(bank, get_gpio_index(gpio), enable);
+	spin_unlock(&bank->lock);
+}
+
+int omap_get_gpio_datain(int gpio)
+{
+	struct gpio_bank *bank;
+	u32 reg;
+
+	if (check_gpio(gpio) < 0)
+		return -1;
+	bank = get_gpio_bank(gpio);
+	reg = bank->base;
+	switch (bank->method) {
+	case METHOD_MPUIO:
+		reg += OMAP_MPUIO_INPUT_LATCH;
+		break;
+	case METHOD_GPIO_1510:
+		reg += OMAP1510_GPIO_DATA_INPUT;
+		break;
+	case METHOD_GPIO_1610:
+		reg += OMAP1610_GPIO_DATAIN;
+		break;
+	case METHOD_GPIO_730:
+		reg += OMAP730_GPIO_DATA_INPUT;
+		break;
+	default:
+		BUG();
+		return -1;
+	}
+	return (__raw_readl(reg) & (1 << get_gpio_index(gpio))) != 0;
+}
+
+static void _set_gpio_edge_ctrl(struct gpio_bank *bank, int gpio, int edge)
+{
+	u32 reg = bank->base;
+	u32 l;
+
+	switch (bank->method) {
+	case METHOD_MPUIO:
+		reg += OMAP_MPUIO_GPIO_INT_EDGE;
+		l = __raw_readl(reg);
+		if (edge == OMAP_GPIO_RISING_EDGE)
+			l |= 1 << gpio;
+		else
+			l &= ~(1 << gpio);
+		__raw_writel(l, reg);
+		break;
+	case METHOD_GPIO_1510:
+		reg += OMAP1510_GPIO_INT_CONTROL;
+		l = __raw_readl(reg);
+		if (edge == OMAP_GPIO_RISING_EDGE)
+			l |= 1 << gpio;
+		else
+			l &= ~(1 << gpio);
+		__raw_writel(l, reg);
+		break;
+	case METHOD_GPIO_1610:
+		edge &= 0x03;
+		if (gpio & 0x08)
+			reg += OMAP1610_GPIO_EDGE_CTRL2;
+		else
+			reg += OMAP1610_GPIO_EDGE_CTRL1;
+		gpio &= 0x07;
+		l = __raw_readl(reg);
+		l &= ~(3 << (gpio << 1));
+		l |= edge << (gpio << 1);
+		__raw_writel(l, reg);
+		break;
+	case METHOD_GPIO_730:
+		reg += OMAP730_GPIO_INT_CONTROL;
+		l = __raw_readl(reg);
+		if (edge == OMAP_GPIO_RISING_EDGE)
+			l |= 1 << gpio;
+		else
+			l &= ~(1 << gpio);
+		__raw_writel(l, reg);
+		break;
+	default:
+		BUG();
+		return;
+	}
+}
+
+void omap_set_gpio_edge_ctrl(int gpio, int edge)
+{
+	struct gpio_bank *bank;
+
+	if (check_gpio(gpio) < 0)
+		return;
+	bank = get_gpio_bank(gpio);
+	spin_lock(&bank->lock);
+	_set_gpio_edge_ctrl(bank, get_gpio_index(gpio), edge);
+	spin_unlock(&bank->lock);
+}
+
+
+static int _get_gpio_edge_ctrl(struct gpio_bank *bank, int gpio)
+{
+	u32 reg = bank->base, l;
+
+	switch (bank->method) {
+	case METHOD_MPUIO:
+		l = __raw_readl(reg + OMAP_MPUIO_GPIO_INT_EDGE);
+		return (l & (1 << gpio)) ?
+			OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE;
+	case METHOD_GPIO_1510:
+		l = __raw_readl(reg + OMAP1510_GPIO_INT_CONTROL);
+		return (l & (1 << gpio)) ?
+			OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE;
+	case METHOD_GPIO_1610:
+		if (gpio & 0x08)
+			reg += OMAP1610_GPIO_EDGE_CTRL2;
+		else
+			reg += OMAP1610_GPIO_EDGE_CTRL1;
+		return (__raw_readl(reg) >> ((gpio & 0x07) << 1)) & 0x03;
+	case METHOD_GPIO_730:
+		l = __raw_readl(reg + OMAP730_GPIO_INT_CONTROL);
+		return (l & (1 << gpio)) ?
+			OMAP_GPIO_RISING_EDGE : OMAP_GPIO_FALLING_EDGE;
+	default:
+		BUG();
+		return -1;
+	}
+}
+
+static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
+{
+	u32 reg = bank->base;
+
+	switch (bank->method) {
+	case METHOD_MPUIO:
+		/* MPUIO irqstatus is reset by reading the status register,
+		 * so do nothing here */
+		return;
+	case METHOD_GPIO_1510:
+		reg += OMAP1510_GPIO_INT_STATUS;
+		break;
+	case METHOD_GPIO_1610:
+		reg += OMAP1610_GPIO_IRQSTATUS1;
+		break;
+	case METHOD_GPIO_730:
+		reg += OMAP730_GPIO_INT_STATUS;
+		break;
+	default:
+		BUG();
+		return;
+	}
+	__raw_writel(gpio_mask, reg);
+}
+
+static inline void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio)
+{
+	_clear_gpio_irqbank(bank, 1 << get_gpio_index(gpio));
+}
+
+static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enable)
+{
+	u32 reg = bank->base;
+	u32 l;
+
+	switch (bank->method) {
+	case METHOD_MPUIO:
+		reg += OMAP_MPUIO_GPIO_MASKIT;
+		l = __raw_readl(reg);
+		if (enable)
+			l &= ~(gpio_mask);
+		else
+			l |= gpio_mask;
+		break;
+	case METHOD_GPIO_1510:
+		reg += OMAP1510_GPIO_INT_MASK;
+		l = __raw_readl(reg);
+		if (enable)
+			l &= ~(gpio_mask);
+		else
+			l |= gpio_mask;
+		break;
+	case METHOD_GPIO_1610:
+		if (enable)
+			reg += OMAP1610_GPIO_SET_IRQENABLE1;
+		else
+			reg += OMAP1610_GPIO_CLEAR_IRQENABLE1;
+		l = gpio_mask;
+		break;
+	case METHOD_GPIO_730:
+		reg += OMAP730_GPIO_INT_MASK;
+		l = __raw_readl(reg);
+		if (enable)
+			l &= ~(gpio_mask);
+		else
+			l |= gpio_mask;
+		break;
+	default:
+		BUG();
+		return;
+	}
+	__raw_writel(l, reg);
+}
+
+static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable)
+{
+	_enable_gpio_irqbank(bank, 1 << get_gpio_index(gpio), enable);
+}
+
+int omap_request_gpio(int gpio)
+{
+	struct gpio_bank *bank;
+
+	if (check_gpio(gpio) < 0)
+		return -EINVAL;
+
+	bank = get_gpio_bank(gpio);
+	spin_lock(&bank->lock);
+	if (unlikely(bank->reserved_map & (1 << get_gpio_index(gpio)))) {
+		printk(KERN_ERR "omap-gpio: GPIO %d is already reserved!\n", gpio);
+		dump_stack();
+		spin_unlock(&bank->lock);
+		return -1;
+	}
+	bank->reserved_map |= (1 << get_gpio_index(gpio));
+#ifdef CONFIG_ARCH_OMAP1510
+	if (bank->method == METHOD_GPIO_1510) {
+		u32 reg;
+
+		/* Claim the pin for the ARM */
+		reg = bank->base + OMAP1510_GPIO_PIN_CONTROL;
+		__raw_writel(__raw_readl(reg) | (1 << get_gpio_index(gpio)), reg);
+	}
+#endif
+	spin_unlock(&bank->lock);
+
+	return 0;
+}
+
+void omap_free_gpio(int gpio)
+{
+	struct gpio_bank *bank;
+
+	if (check_gpio(gpio) < 0)
+		return;
+	bank = get_gpio_bank(gpio);
+	spin_lock(&bank->lock);
+	if (unlikely(!(bank->reserved_map & (1 << get_gpio_index(gpio))))) {
+		printk(KERN_ERR "omap-gpio: GPIO %d wasn't reserved!\n", gpio);
+		dump_stack();
+		spin_unlock(&bank->lock);
+		return;
+	}
+	bank->reserved_map &= ~(1 << get_gpio_index(gpio));
+	_set_gpio_direction(bank, get_gpio_index(gpio), 1);
+	_set_gpio_irqenable(bank, gpio, 0);
+	_clear_gpio_irqstatus(bank, gpio);
+	spin_unlock(&bank->lock);
+}
+
+/*
+ * We need to unmask the GPIO bank interrupt as soon as possible to
+ * avoid missing GPIO interrupts for other lines in the bank.
+ * Then we need to mask-read-clear-unmask the triggered GPIO lines
+ * in the bank to avoid missing nested interrupts for a GPIO line.
+ * If we wait to unmask individual GPIO lines in the bank after the
+ * line's interrupt handler has been run, we may miss some nested
+ * interrupts.
+ */
+static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc,
+			     struct pt_regs *regs)
+{
+	u32 isr_reg = 0;
+	u32 isr;
+	unsigned int gpio_irq;
+	struct gpio_bank *bank;
+
+	desc->chip->ack(irq);
+
+	bank = (struct gpio_bank *) desc->data;
+	if (bank->method == METHOD_MPUIO)
+		isr_reg = bank->base + OMAP_MPUIO_GPIO_INT;
+#ifdef CONFIG_ARCH_OMAP1510
+	if (bank->method == METHOD_GPIO_1510)
+		isr_reg = bank->base + OMAP1510_GPIO_INT_STATUS;
+#endif
+#if defined(CONFIG_ARCH_OMAP16XX)
+	if (bank->method == METHOD_GPIO_1610)
+		isr_reg = bank->base + OMAP1610_GPIO_IRQSTATUS1;
+#endif
+#ifdef CONFIG_ARCH_OMAP730
+	if (bank->method == METHOD_GPIO_730)
+		isr_reg = bank->base + OMAP730_GPIO_INT_STATUS;
+#endif
+
+	isr = __raw_readl(isr_reg);
+	_enable_gpio_irqbank(bank, isr, 0);
+	_clear_gpio_irqbank(bank, isr);
+	_enable_gpio_irqbank(bank, isr, 1);
+	desc->chip->unmask(irq);
+
+	if (unlikely(!isr))
+		return;
+
+	gpio_irq = bank->virtual_irq_start;
+	for (; isr != 0; isr >>= 1, gpio_irq++) {
+		struct irqdesc *d;
+		if (!(isr & 1))
+			continue;
+		d = irq_desc + gpio_irq;
+		d->handle(gpio_irq, d, regs);
+	}
+}
+
+static void gpio_ack_irq(unsigned int irq)
+{
+	unsigned int gpio = irq - IH_GPIO_BASE;
+	struct gpio_bank *bank = get_gpio_bank(gpio);
+
+	_clear_gpio_irqstatus(bank, gpio);
+}
+
+static void gpio_mask_irq(unsigned int irq)
+{
+	unsigned int gpio = irq - IH_GPIO_BASE;
+	struct gpio_bank *bank = get_gpio_bank(gpio);
+
+	_set_gpio_irqenable(bank, gpio, 0);
+}
+
+static void gpio_unmask_irq(unsigned int irq)
+{
+	unsigned int gpio = irq - IH_GPIO_BASE;
+	struct gpio_bank *bank = get_gpio_bank(gpio);
+
+	if (_get_gpio_edge_ctrl(bank, get_gpio_index(gpio)) == OMAP_GPIO_NO_EDGE) {
+		printk(KERN_ERR "OMAP GPIO %d: trying to enable GPIO IRQ while no edge is set\n",
+		       gpio);
+		_set_gpio_edge_ctrl(bank, get_gpio_index(gpio), OMAP_GPIO_RISING_EDGE);
+	}
+	_set_gpio_irqenable(bank, gpio, 1);
+}
+
+static void mpuio_ack_irq(unsigned int irq)
+{
+	/* The ISR is reset automatically, so do nothing here. */
+}
+
+static void mpuio_mask_irq(unsigned int irq)
+{
+	unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);
+	struct gpio_bank *bank = get_gpio_bank(gpio);
+
+	_set_gpio_irqenable(bank, gpio, 0);
+}
+
+static void mpuio_unmask_irq(unsigned int irq)
+{
+	unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);
+	struct gpio_bank *bank = get_gpio_bank(gpio);
+
+	_set_gpio_irqenable(bank, gpio, 1);
+}
+
+static struct irqchip gpio_irq_chip = {
+	.ack	= gpio_ack_irq,
+	.mask	= gpio_mask_irq,
+	.unmask = gpio_unmask_irq,
+};
+
+static struct irqchip mpuio_irq_chip = {
+	.ack	= mpuio_ack_irq,
+	.mask	= mpuio_mask_irq,
+	.unmask = mpuio_unmask_irq
+};
+
+static int initialized = 0;
+
+static int __init _omap_gpio_init(void)
+{
+	int i;
+	struct gpio_bank *bank;
+
+	initialized = 1;
+
+#ifdef CONFIG_ARCH_OMAP1510
+	if (cpu_is_omap1510()) {
+		printk(KERN_INFO "OMAP1510 GPIO hardware\n");
+		gpio_bank_count = 2;
+		gpio_bank = gpio_bank_1510;
+	}
+#endif
+#if defined(CONFIG_ARCH_OMAP16XX)
+	if (cpu_is_omap16xx()) {
+		int rev;
+
+		gpio_bank_count = 5;
+		gpio_bank = gpio_bank_1610;
+		rev = omap_readw(gpio_bank[1].base + OMAP1610_GPIO_REVISION);
+		printk(KERN_INFO "OMAP GPIO hardware version %d.%d\n",
+		       (rev >> 4) & 0x0f, rev & 0x0f);
+	}
+#endif
+#ifdef CONFIG_ARCH_OMAP730
+	if (cpu_is_omap730()) {
+		printk(KERN_INFO "OMAP730 GPIO hardware\n");
+		gpio_bank_count = 7;
+		gpio_bank = gpio_bank_730;
+	}
+#endif
+	for (i = 0; i < gpio_bank_count; i++) {
+		int j, gpio_count = 16;
+
+		bank = &gpio_bank[i];
+		bank->reserved_map = 0;
+		bank->base = IO_ADDRESS(bank->base);
+		spin_lock_init(&bank->lock);
+		if (bank->method == METHOD_MPUIO) {
+			omap_writew(0xFFFF, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_MASKIT);
+		}
+#ifdef CONFIG_ARCH_OMAP1510
+		if (bank->method == METHOD_GPIO_1510) {
+			__raw_writew(0xffff, bank->base + OMAP1510_GPIO_INT_MASK);
+			__raw_writew(0x0000, bank->base + OMAP1510_GPIO_INT_STATUS);
+		}
+#endif
+#if defined(CONFIG_ARCH_OMAP16XX)
+		if (bank->method == METHOD_GPIO_1610) {
+			__raw_writew(0x0000, bank->base + OMAP1610_GPIO_IRQENABLE1);
+			__raw_writew(0xffff, bank->base + OMAP1610_GPIO_IRQSTATUS1);
+		}
+#endif
+#ifdef CONFIG_ARCH_OMAP730
+		if (bank->method == METHOD_GPIO_730) {
+			__raw_writel(0xffffffff, bank->base + OMAP730_GPIO_INT_MASK);
+			__raw_writel(0x00000000, bank->base + OMAP730_GPIO_INT_STATUS);
+
+			gpio_count = 32; /* 730 has 32-bit GPIOs */
+		}
+#endif
+		for (j = bank->virtual_irq_start;
+		     j < bank->virtual_irq_start + gpio_count; j++) {
+			if (bank->method == METHOD_MPUIO)
+				set_irq_chip(j, &mpuio_irq_chip);
+			else
+				set_irq_chip(j, &gpio_irq_chip);
+			set_irq_handler(j, do_simple_IRQ);
+			set_irq_flags(j, IRQF_VALID);
+		}
+		set_irq_chained_handler(bank->irq, gpio_irq_handler);
+		set_irq_data(bank->irq, bank);
+	}
+
+	/* Enable system clock for GPIO module.
+	 * The CAM_CLK_CTRL *is* really the right place. */
+	if (cpu_is_omap1610() || cpu_is_omap1710())
+		omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04, ULPD_CAM_CLK_CTRL);
+
+	return 0;
+}
+
+/*
+ * This may get called early from board specific init
+ */
+int omap_gpio_init(void)
+{
+	if (!initialized)
+		return _omap_gpio_init();
+	else
+		return 0;
+}
+
+EXPORT_SYMBOL(omap_request_gpio);
+EXPORT_SYMBOL(omap_free_gpio);
+EXPORT_SYMBOL(omap_set_gpio_direction);
+EXPORT_SYMBOL(omap_set_gpio_dataout);
+EXPORT_SYMBOL(omap_get_gpio_datain);
+EXPORT_SYMBOL(omap_set_gpio_edge_ctrl);
+
+arch_initcall(omap_gpio_init);
diff --git a/arch/arm/mach-omap/irq.c b/arch/arm/mach-omap/irq.c
new file mode 100644
index 0000000..f01c992
--- /dev/null
+++ b/arch/arm/mach-omap/irq.c
@@ -0,0 +1,219 @@
+/*
+ * linux/arch/arm/mach-omap/irq.c
+ *
+ * Interrupt handler for all OMAP boards
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Written by Tony Lindgren <tony@atomide.com>
+ * Major cleanups by Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * Completely re-written to support various OMAP chips with bank specific
+ * interrupt handlers.
+ *
+ * Some snippets of the code taken from the older OMAP interrupt handler
+ * Copyright (C) 2001 RidgeRun, Inc. Greg Lonnon <glonnon@ridgerun.com>
+ *
+ * GPIO interrupt handler moved to gpio.c by Juha Yrjola
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <asm/arch/gpio.h>
+
+#include <asm/io.h>
+
+#define IRQ_BANK(irq) ((irq) >> 5)
+#define IRQ_BIT(irq)  ((irq) & 0x1f)
+
+struct omap_irq_bank {
+	unsigned long base_reg;
+	unsigned long trigger_map;
+};
+
+static unsigned int irq_bank_count = 0;
+static struct omap_irq_bank *irq_banks;
+
+static inline unsigned int irq_bank_readl(int bank, int offset)
+{
+	return omap_readl(irq_banks[bank].base_reg + offset);
+}
+
+static inline void irq_bank_writel(unsigned long value, int bank, int offset)
+{
+	omap_writel(value, irq_banks[bank].base_reg + offset);
+}
+
+static void omap_ack_irq(unsigned int irq)
+{
+	if (irq > 31)
+		omap_writel(0x1, OMAP_IH2_BASE + IRQ_CONTROL_REG_OFFSET);
+
+	omap_writel(0x1, OMAP_IH1_BASE + IRQ_CONTROL_REG_OFFSET);
+}
+
+static void omap_mask_irq(unsigned int irq)
+{
+	int bank = IRQ_BANK(irq);
+	u32 l;
+
+	l = omap_readl(irq_banks[bank].base_reg + IRQ_MIR_REG_OFFSET);
+	l |= 1 << IRQ_BIT(irq);
+	omap_writel(l, irq_banks[bank].base_reg + IRQ_MIR_REG_OFFSET);
+}
+
+static void omap_unmask_irq(unsigned int irq)
+{
+	int bank = IRQ_BANK(irq);
+	u32 l;
+
+	l = omap_readl(irq_banks[bank].base_reg + IRQ_MIR_REG_OFFSET);
+	l &= ~(1 << IRQ_BIT(irq));
+	omap_writel(l, irq_banks[bank].base_reg + IRQ_MIR_REG_OFFSET);
+}
+
+static void omap_mask_ack_irq(unsigned int irq)
+{
+	omap_mask_irq(irq);
+	omap_ack_irq(irq);
+}
+
+/*
+ * Allows tuning the IRQ type and priority
+ *
+ * NOTE: There is currently no OMAP fiq handler for Linux. Read the
+ *	 mailing list threads on FIQ handlers if you are planning to
+ *	 add a FIQ handler for OMAP.
+ */
+static void omap_irq_set_cfg(int irq, int fiq, int priority, int trigger)
+{
+	signed int bank;
+	unsigned long val, offset;
+
+	bank = IRQ_BANK(irq);
+	/* FIQ is only available on bank 0 interrupts */
+	fiq = bank ? 0 : (fiq & 0x1);
+	val = fiq | ((priority & 0x1f) << 2) | ((trigger & 0x1) << 1);
+	offset = IRQ_ILR0_REG_OFFSET + IRQ_BIT(irq) * 0x4;
+	irq_bank_writel(val, bank, offset);
+}
+
+#ifdef CONFIG_ARCH_OMAP730
+static struct omap_irq_bank omap730_irq_banks[] = {
+	{ .base_reg = OMAP_IH1_BASE, 		.trigger_map = 0xb3f8e22f },
+	{ .base_reg = OMAP_IH2_BASE, 		.trigger_map = 0xfdb9c1f2 },
+	{ .base_reg = OMAP_IH2_BASE + 0x100,	.trigger_map = 0x800040f3 },
+};
+#endif
+
+#ifdef CONFIG_ARCH_OMAP1510
+static struct omap_irq_bank omap1510_irq_banks[] = {
+	{ .base_reg = OMAP_IH1_BASE, 		.trigger_map = 0xb3febfff },
+	{ .base_reg = OMAP_IH2_BASE, 		.trigger_map = 0xffbfffed },
+};
+#endif
+
+#if defined(CONFIG_ARCH_OMAP16XX)
+
+static struct omap_irq_bank omap1610_irq_banks[] = {
+	{ .base_reg = OMAP_IH1_BASE, 		.trigger_map = 0xb3fefe8f },
+	{ .base_reg = OMAP_IH2_BASE, 		.trigger_map = 0xfdb7c1fd },
+	{ .base_reg = OMAP_IH2_BASE + 0x100,	.trigger_map = 0xfffff7ff },
+	{ .base_reg = OMAP_IH2_BASE + 0x200,	.trigger_map = 0xffffffff },
+};
+#endif
+
+static struct irqchip omap_irq_chip = {
+	.ack    = omap_mask_ack_irq,
+	.mask   = omap_mask_irq,
+	.unmask = omap_unmask_irq,
+};
+
+void __init omap_init_irq(void)
+{
+	int i, j;
+
+#ifdef CONFIG_ARCH_OMAP730
+	if (cpu_is_omap730()) {
+		irq_banks = omap730_irq_banks;
+		irq_bank_count = ARRAY_SIZE(omap730_irq_banks);
+	}
+#endif
+#ifdef CONFIG_ARCH_OMAP1510
+	if (cpu_is_omap1510()) {
+		irq_banks = omap1510_irq_banks;
+		irq_bank_count = ARRAY_SIZE(omap1510_irq_banks);
+	}
+#endif
+#if defined(CONFIG_ARCH_OMAP16XX)
+	if (cpu_is_omap16xx()) {
+		irq_banks = omap1610_irq_banks;
+		irq_bank_count = ARRAY_SIZE(omap1610_irq_banks);
+	}
+#endif
+	printk("Total of %i interrupts in %i interrupt banks\n",
+	       irq_bank_count * 32, irq_bank_count);
+
+	/* Mask and clear all interrupts */
+	for (i = 0; i < irq_bank_count; i++) {
+		irq_bank_writel(~0x0, i, IRQ_MIR_REG_OFFSET);
+		irq_bank_writel(0x0, i, IRQ_ITR_REG_OFFSET);
+	}
+
+	/* Clear any pending interrupts */
+	irq_bank_writel(0x03, 0, IRQ_CONTROL_REG_OFFSET);
+	irq_bank_writel(0x03, 1, IRQ_CONTROL_REG_OFFSET);
+
+	/* Enable interrupts in global mask */
+	if (cpu_is_omap730()) {
+		irq_bank_writel(0x0, 0, IRQ_GMR_REG_OFFSET);
+	}
+
+	/* Install the interrupt handlers for each bank */
+	for (i = 0; i < irq_bank_count; i++) {
+		for (j = i * 32; j < (i + 1) * 32; j++) {
+			int irq_trigger;
+
+			irq_trigger = irq_banks[i].trigger_map >> IRQ_BIT(j);
+			omap_irq_set_cfg(j, 0, 0, irq_trigger);
+
+			set_irq_chip(j, &omap_irq_chip);
+			set_irq_handler(j, do_level_IRQ);
+			set_irq_flags(j, IRQF_VALID);
+		}
+	}
+
+	/* Unmask level 2 handler */
+	if (cpu_is_omap730()) {
+		omap_unmask_irq(INT_730_IH2_IRQ);
+	} else {
+		omap_unmask_irq(INT_IH2_IRQ);
+	}
+}
diff --git a/arch/arm/mach-omap/leds-h2p2-debug.c b/arch/arm/mach-omap/leds-h2p2-debug.c
new file mode 100644
index 0000000..6e98290
--- /dev/null
+++ b/arch/arm/mach-omap/leds-h2p2-debug.c
@@ -0,0 +1,144 @@
+/*
+ * linux/arch/arm/mach-omap/leds-h2p2-debug.c
+ *
+ * Copyright 2003 by Texas Instruments Incorporated
+ *
+ * There are 16 LEDs on the debug board (all green); four may be used
+ * for logical 'green', 'amber', 'red', and 'blue' (after "claiming").
+ *
+ * The "surfer" expansion board and H2 sample board also have two-color
+ * green+red LEDs (in parallel), used here for timer and idle indicators.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/sched.h>
+#include <linux/version.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/leds.h>
+#include <asm/system.h>
+
+#include <asm/arch/fpga.h>
+#include <asm/arch/gpio.h>
+
+#include "leds.h"
+
+
+#define GPIO_LED_RED		3
+#define GPIO_LED_GREEN		OMAP_MPUIO(4)
+
+
+#define LED_STATE_ENABLED	0x01
+#define LED_STATE_CLAIMED	0x02
+#define LED_TIMER_ON		0x04
+
+#define GPIO_IDLE		GPIO_LED_GREEN
+#define GPIO_TIMER		GPIO_LED_RED
+
+
+void h2p2_dbg_leds_event(led_event_t evt)
+{
+	unsigned long flags;
+
+	static struct h2p2_dbg_fpga __iomem *fpga;
+	static u16 led_state, hw_led_state;
+
+	local_irq_save(flags);
+
+	if (!(led_state & LED_STATE_ENABLED) && evt != led_start)
+		goto done;
+
+	switch (evt) {
+	case led_start:
+		if (!fpga)
+			fpga = ioremap(H2P2_DBG_FPGA_START,
+						H2P2_DBG_FPGA_SIZE);
+		if (fpga) {
+			led_state |= LED_STATE_ENABLED;
+			__raw_writew(~0, &fpga->leds);
+		}
+		break;
+
+	case led_stop:
+	case led_halted:
+		/* all leds off during suspend or shutdown */
+		omap_set_gpio_dataout(GPIO_TIMER, 0);
+		omap_set_gpio_dataout(GPIO_IDLE, 0);
+		__raw_writew(~0, &fpga->leds);
+		led_state &= ~LED_STATE_ENABLED;
+		if (evt == led_halted) {
+			iounmap(fpga);
+			fpga = NULL;
+		}
+		goto done;
+
+	case led_claim:
+		led_state |= LED_STATE_CLAIMED;
+		hw_led_state = 0;
+		break;
+
+	case led_release:
+		led_state &= ~LED_STATE_CLAIMED;
+		break;
+
+#ifdef CONFIG_LEDS_TIMER
+	case led_timer:
+		led_state ^= LED_TIMER_ON;
+		omap_set_gpio_dataout(GPIO_TIMER, led_state & LED_TIMER_ON);
+		goto done;
+#endif
+
+#ifdef CONFIG_LEDS_CPU
+	case led_idle_start:
+		omap_set_gpio_dataout(GPIO_IDLE, 1);
+		goto done;
+
+	case led_idle_end:
+		omap_set_gpio_dataout(GPIO_IDLE, 0);
+		goto done;
+#endif
+
+	case led_green_on:
+		hw_led_state |= H2P2_DBG_FPGA_LED_GREEN;
+		break;
+	case led_green_off:
+		hw_led_state &= ~H2P2_DBG_FPGA_LED_GREEN;
+		break;
+
+	case led_amber_on:
+		hw_led_state |= H2P2_DBG_FPGA_LED_AMBER;
+		break;
+	case led_amber_off:
+		hw_led_state &= ~H2P2_DBG_FPGA_LED_AMBER;
+		break;
+
+	case led_red_on:
+		hw_led_state |= H2P2_DBG_FPGA_LED_RED;
+		break;
+	case led_red_off:
+		hw_led_state &= ~H2P2_DBG_FPGA_LED_RED;
+		break;
+
+	case led_blue_on:
+		hw_led_state |= H2P2_DBG_FPGA_LED_BLUE;
+		break;
+	case led_blue_off:
+		hw_led_state &= ~H2P2_DBG_FPGA_LED_BLUE;
+		break;
+
+	default:
+		break;
+	}
+
+
+	/*
+	 *  Actually burn the LEDs
+	 */
+	if (led_state & LED_STATE_CLAIMED)
+		__raw_writew(~hw_led_state, &fpga->leds);
+
+done:
+	local_irq_restore(flags);
+}
diff --git a/arch/arm/mach-omap/leds-innovator.c b/arch/arm/mach-omap/leds-innovator.c
new file mode 100644
index 0000000..8043b7d
--- /dev/null
+++ b/arch/arm/mach-omap/leds-innovator.c
@@ -0,0 +1,103 @@
+/*
+ * linux/arch/arm/mach-omap/leds-innovator.c
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/leds.h>
+#include <asm/system.h>
+
+#include "leds.h"
+
+
+#define LED_STATE_ENABLED	1
+#define LED_STATE_CLAIMED	2
+
+static unsigned int led_state;
+static unsigned int hw_led_state;
+
+void innovator_leds_event(led_event_t evt)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+	switch (evt) {
+	case led_start:
+		hw_led_state = 0;
+		led_state = LED_STATE_ENABLED;
+		break;
+
+	case led_stop:
+		led_state &= ~LED_STATE_ENABLED;
+		hw_led_state = 0;
+		break;
+
+	case led_claim:
+		led_state |= LED_STATE_CLAIMED;
+		hw_led_state = 0;
+		break;
+
+	case led_release:
+		led_state &= ~LED_STATE_CLAIMED;
+		hw_led_state = 0;
+		break;
+
+#ifdef CONFIG_LEDS_TIMER
+	case led_timer:
+		if (!(led_state & LED_STATE_CLAIMED))
+			hw_led_state ^= 0;
+		break;
+#endif
+
+#ifdef CONFIG_LEDS_CPU
+	case led_idle_start:
+		if (!(led_state & LED_STATE_CLAIMED))
+			hw_led_state |= 0;
+		break;
+
+	case led_idle_end:
+		if (!(led_state & LED_STATE_CLAIMED))
+			hw_led_state &= ~0;
+		break;
+#endif
+
+	case led_halted:
+		break;
+
+	case led_green_on:
+		if (led_state & LED_STATE_CLAIMED)
+			hw_led_state &= ~0;
+		break;
+
+	case led_green_off:
+		if (led_state & LED_STATE_CLAIMED)
+			hw_led_state |= 0;
+		break;
+
+	case led_amber_on:
+		break;
+
+	case led_amber_off:
+		break;
+
+	case led_red_on:
+		if (led_state & LED_STATE_CLAIMED)
+			hw_led_state &= ~0;
+		break;
+
+	case led_red_off:
+		if (led_state & LED_STATE_CLAIMED)
+			hw_led_state |= 0;
+		break;
+
+	default:
+		break;
+	}
+
+	if (led_state & LED_STATE_ENABLED)
+		;
+
+	local_irq_restore(flags);
+}
diff --git a/arch/arm/mach-omap/leds-osk.c b/arch/arm/mach-omap/leds-osk.c
new file mode 100644
index 0000000..f5177f4
--- /dev/null
+++ b/arch/arm/mach-omap/leds-osk.c
@@ -0,0 +1,198 @@
+/*
+ * linux/arch/arm/mach-omap/leds-osk.c
+ *
+ * LED driver for OSK, and optionally Mistral QVGA, boards
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/workqueue.h>
+
+#include <asm/hardware.h>
+#include <asm/leds.h>
+#include <asm/system.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/tps65010.h>
+
+#include "leds.h"
+
+
+#define LED_STATE_ENABLED	(1 << 0)
+#define LED_STATE_CLAIMED	(1 << 1)
+static u8 led_state;
+
+#define	GREEN_LED		(1 << 0)	/* TPS65010 LED1 */
+#define	AMBER_LED		(1 << 1)	/* TPS65010 LED2 */
+#define	RED_LED			(1 << 2)	/* TPS65010 GPIO2 */
+#define	TIMER_LED		(1 << 3)	/* Mistral board */
+#define	IDLE_LED		(1 << 4)	/* Mistral board */
+static u8 hw_led_state;
+
+
+/* TPS65010 leds are changed using i2c -- from a task context.
+ * Using one of these for the "idle" LED would be impractical...
+ */
+#define	TPS_LEDS	(GREEN_LED | RED_LED | AMBER_LED)
+
+static u8 tps_leds_change;
+
+static void tps_work(void *unused)
+{
+	for (;;) {
+		u8	leds;
+
+		local_irq_disable();
+		leds = tps_leds_change;
+		tps_leds_change = 0;
+		local_irq_enable();
+
+		if (!leds)
+			break;
+
+		/* careful:  the set_led() value is on/off/blink */
+		if (leds & GREEN_LED)
+			tps65010_set_led(LED1, !!(hw_led_state & GREEN_LED));
+		if (leds & AMBER_LED)
+			tps65010_set_led(LED2, !!(hw_led_state & AMBER_LED));
+
+		/* the gpio led doesn't have that issue */
+		if (leds & RED_LED)
+			tps65010_set_gpio_out_value(GPIO2,
+					!(hw_led_state & RED_LED));
+	}
+}
+
+static DECLARE_WORK(work, tps_work, NULL);
+
+#ifdef	CONFIG_FB_OMAP
+
+/* For now, all system indicators require the Mistral board, since that
+ * LED can be manipulated without a task context.  This LED is either red,
+ * or green, but not both; it can't give the full "disco led" effect.
+ */
+
+#define GPIO_LED_RED		3
+#define GPIO_LED_GREEN		OMAP_MPUIO(4)
+
+static void mistral_setled(void)
+{
+	int	red = 0;
+	int	green = 0;
+
+	if (hw_led_state & TIMER_LED)
+		red = 1;
+	else if (hw_led_state & IDLE_LED)
+		green = 1;
+	// else both sides are disabled
+
+	omap_set_gpio_dataout(GPIO_LED_GREEN, green);
+	omap_set_gpio_dataout(GPIO_LED_RED, red);
+}
+
+#endif
+
+void osk_leds_event(led_event_t evt)
+{
+	unsigned long	flags;
+	u16		leds;
+
+	local_irq_save(flags);
+
+	if (!(led_state & LED_STATE_ENABLED) && evt != led_start)
+		goto done;
+
+	leds = hw_led_state;
+	switch (evt) {
+	case led_start:
+		led_state |= LED_STATE_ENABLED;
+		hw_led_state = 0;
+		leds = ~0;
+		break;
+
+	case led_halted:
+	case led_stop:
+		led_state &= ~LED_STATE_ENABLED;
+		hw_led_state = 0;
+		// NOTE:  work may still be pending!!
+		break;
+
+	case led_claim:
+		led_state |= LED_STATE_CLAIMED;
+		hw_led_state = 0;
+		leds = ~0;
+		break;
+
+	case led_release:
+		led_state &= ~LED_STATE_CLAIMED;
+		hw_led_state = 0;
+		break;
+
+#ifdef	CONFIG_FB_OMAP
+
+#ifdef CONFIG_LEDS_TIMER
+	case led_timer:
+		hw_led_state ^= TIMER_LED;
+		mistral_setled();
+		break;
+#endif
+
+#ifdef CONFIG_LEDS_CPU
+	case led_idle_start:
+		hw_led_state |= IDLE_LED;
+		mistral_setled();
+		break;
+
+	case led_idle_end:
+		hw_led_state &= ~IDLE_LED;
+		mistral_setled();
+		break;
+#endif
+
+#endif	/* CONFIG_FB_OMAP */
+
+	/* "green" == tps LED1 (leftmost, normally power-good)
+	 * works only with DC adapter, not on battery power!
+	 */
+	case led_green_on:
+		if (led_state & LED_STATE_CLAIMED)
+			hw_led_state |= GREEN_LED;
+		break;
+	case led_green_off:
+		if (led_state & LED_STATE_CLAIMED)
+			hw_led_state &= ~GREEN_LED;
+		break;
+
+	/* "amber" == tps LED2 (middle) */
+	case led_amber_on:
+		if (led_state & LED_STATE_CLAIMED)
+			hw_led_state |= AMBER_LED;
+		break;
+	case led_amber_off:
+		if (led_state & LED_STATE_CLAIMED)
+			hw_led_state &= ~AMBER_LED;
+		break;
+
+	/* "red" == LED on tps gpio3 (rightmost) */
+	case led_red_on:
+		if (led_state & LED_STATE_CLAIMED)
+			hw_led_state |= RED_LED;
+		break;
+	case led_red_off:
+		if (led_state & LED_STATE_CLAIMED)
+			hw_led_state &= ~RED_LED;
+		break;
+
+	default:
+		break;
+	}
+
+	leds ^= hw_led_state;
+	leds &= TPS_LEDS;
+	if (leds && (led_state & LED_STATE_CLAIMED)) {
+		tps_leds_change |= leds;
+		schedule_work(&work);
+	}
+
+done:
+	local_irq_restore(flags);
+}
diff --git a/arch/arm/mach-omap/leds.c b/arch/arm/mach-omap/leds.c
new file mode 100644
index 0000000..8ab21fe
--- /dev/null
+++ b/arch/arm/mach-omap/leds.c
@@ -0,0 +1,61 @@
+/*
+ * linux/arch/arm/mach-omap/leds.c
+ *
+ * OMAP LEDs dispatcher
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/leds.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+
+#include "leds.h"
+
+static int __init
+omap_leds_init(void)
+{
+	if (machine_is_omap_innovator())
+		leds_event = innovator_leds_event;
+
+	else if (machine_is_omap_h2() || machine_is_omap_perseus2())
+		leds_event = h2p2_dbg_leds_event;
+
+	else if (machine_is_omap_osk())
+		leds_event = osk_leds_event;
+
+	else
+		return -1;
+
+	if (machine_is_omap_h2()
+			|| machine_is_omap_perseus2()
+			|| machine_is_omap_osk()) {
+
+		/* LED1/LED2 pins can be used as GPIO (as done here), or by
+		 * the LPG (works even in deep sleep!), to drive a bicolor
+		 * LED on the H2 sample board, and another on the H2/P2
+		 * "surfer" expansion board.
+		 *
+		 * The same pins drive a LED on the OSK Mistral board, but
+		 * that's a different kind of LED (just one color at a time).
+		 */
+		omap_cfg_reg(P18_1610_GPIO3);
+		if (omap_request_gpio(3) == 0)
+			omap_set_gpio_direction(3, 0);
+		else
+			printk(KERN_WARNING "LED: can't get GPIO3/red?\n");
+
+		omap_cfg_reg(MPUIO4);
+		if (omap_request_gpio(OMAP_MPUIO(4)) == 0)
+			omap_set_gpio_direction(OMAP_MPUIO(4), 0);
+		else
+			printk(KERN_WARNING "LED: can't get MPUIO4/green?\n");
+	}
+
+	leds_event(led_start);
+	return 0;
+}
+
+__initcall(omap_leds_init);
diff --git a/arch/arm/mach-omap/leds.h b/arch/arm/mach-omap/leds.h
new file mode 100644
index 0000000..a1e9fed
--- /dev/null
+++ b/arch/arm/mach-omap/leds.h
@@ -0,0 +1,3 @@
+extern void innovator_leds_event(led_event_t evt);
+extern void h2p2_dbg_leds_event(led_event_t evt);
+extern void osk_leds_event(led_event_t evt);
diff --git a/arch/arm/mach-omap/mcbsp.c b/arch/arm/mach-omap/mcbsp.c
new file mode 100644
index 0000000..7c4ad77
--- /dev/null
+++ b/arch/arm/mach-omap/mcbsp.c
@@ -0,0 +1,685 @@
+/*
+ * linux/arch/arm/omap/mcbsp.c
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Samuel Ortiz <samuel.ortiz@nokia.com>
+ *
+ *
+ * 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.
+ *
+ * Multichannel mode not supported.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <asm/arch/dma.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/mcbsp.h>
+
+#include <asm/hardware/clock.h>
+
+#ifdef CONFIG_MCBSP_DEBUG
+#define DBG(x...)	printk(x)
+#else
+#define DBG(x...)	do { } while (0)
+#endif
+
+struct omap_mcbsp {
+	u32                          io_base;
+	u8                           id;
+	u8                           free;
+	omap_mcbsp_word_length       rx_word_length;
+	omap_mcbsp_word_length       tx_word_length;
+
+	/* IRQ based TX/RX */
+	int                          rx_irq;
+	int                          tx_irq;
+
+	/* DMA stuff */
+	u8                           dma_rx_sync;
+	short                        dma_rx_lch;
+	u8                           dma_tx_sync;
+	short                        dma_tx_lch;
+
+	/* Completion queues */
+	struct completion            tx_irq_completion;
+	struct completion            rx_irq_completion;
+	struct completion            tx_dma_completion;
+	struct completion            rx_dma_completion;
+
+	spinlock_t                   lock;
+};
+
+static struct omap_mcbsp mcbsp[OMAP_MAX_MCBSP_COUNT];
+static struct clk *mcbsp_dsp_ck = 0;
+static struct clk *mcbsp_api_ck = 0;
+
+
+static void omap_mcbsp_dump_reg(u8 id)
+{
+	DBG("**** MCBSP%d regs ****\n", mcbsp[id].id);
+	DBG("DRR2:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DRR2));
+	DBG("DRR1:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DRR1));
+	DBG("DXR2:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DXR2));
+	DBG("DXR1:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DXR1));
+	DBG("SPCR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SPCR2));
+	DBG("SPCR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SPCR1));
+	DBG("RCR2:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, RCR2));
+	DBG("RCR1:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, RCR1));
+	DBG("XCR2:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, XCR2));
+	DBG("XCR1:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, XCR1));
+	DBG("SRGR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SRGR2));
+	DBG("SRGR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SRGR1));
+	DBG("PCR0:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, PCR0));
+	DBG("***********************\n");
+}
+
+
+static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct omap_mcbsp * mcbsp_tx = (struct omap_mcbsp *)(dev_id);
+
+	DBG("TX IRQ callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_tx->io_base, SPCR2));
+
+	complete(&mcbsp_tx->tx_irq_completion);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct omap_mcbsp * mcbsp_rx = (struct omap_mcbsp *)(dev_id);
+
+	DBG("RX IRQ callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_rx->io_base, SPCR2));
+
+	complete(&mcbsp_rx->rx_irq_completion);
+	return IRQ_HANDLED;
+}
+
+
+static void omap_mcbsp_tx_dma_callback(int lch, u16 ch_status, void *data)
+{
+	struct omap_mcbsp * mcbsp_dma_tx = (struct omap_mcbsp *)(data);
+
+	DBG("TX DMA callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_dma_tx->io_base, SPCR2));
+
+	/* We can free the channels */
+	omap_free_dma(mcbsp_dma_tx->dma_tx_lch);
+	mcbsp_dma_tx->dma_tx_lch = -1;
+
+	complete(&mcbsp_dma_tx->tx_dma_completion);
+}
+
+static void omap_mcbsp_rx_dma_callback(int lch, u16 ch_status, void *data)
+{
+	struct omap_mcbsp * mcbsp_dma_rx = (struct omap_mcbsp *)(data);
+
+	DBG("RX DMA callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_dma_rx->io_base, SPCR2));
+
+	/* We can free the channels */
+	omap_free_dma(mcbsp_dma_rx->dma_rx_lch);
+	mcbsp_dma_rx->dma_rx_lch = -1;
+
+	complete(&mcbsp_dma_rx->rx_dma_completion);
+}
+
+
+/*
+ * omap_mcbsp_config simply write a config to the
+ * appropriate McBSP.
+ * You either call this function or set the McBSP registers
+ * by yourself before calling omap_mcbsp_start().
+ */
+
+void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg * config)
+{
+	u32 io_base = mcbsp[id].io_base;
+
+	DBG("OMAP-McBSP: McBSP%d  io_base: 0x%8x\n", id+1, io_base);
+
+	/* We write the given config */
+	OMAP_MCBSP_WRITE(io_base, SPCR2, config->spcr2);
+	OMAP_MCBSP_WRITE(io_base, SPCR1, config->spcr1);
+	OMAP_MCBSP_WRITE(io_base, RCR2, config->rcr2);
+	OMAP_MCBSP_WRITE(io_base, RCR1, config->rcr1);
+	OMAP_MCBSP_WRITE(io_base, XCR2, config->xcr2);
+	OMAP_MCBSP_WRITE(io_base, XCR1, config->xcr1);
+	OMAP_MCBSP_WRITE(io_base, SRGR2, config->srgr2);
+	OMAP_MCBSP_WRITE(io_base, SRGR1, config->srgr1);
+	OMAP_MCBSP_WRITE(io_base, MCR2, config->mcr2);
+	OMAP_MCBSP_WRITE(io_base, MCR1, config->mcr1);
+	OMAP_MCBSP_WRITE(io_base, PCR0, config->pcr0);
+}
+
+
+
+static int omap_mcbsp_check(unsigned int id)
+{
+	if (cpu_is_omap730()) {
+		if (id > OMAP_MAX_MCBSP_COUNT - 1) {
+		       printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1);
+		       return -1;
+		}
+		return 0;
+	}
+
+	if (cpu_is_omap1510() || cpu_is_omap1610() || cpu_is_omap1710()) {
+		if (id > OMAP_MAX_MCBSP_COUNT) {
+			printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1);
+			return -1;
+		}
+		return 0;
+	}
+
+	return -1;
+}
+
+#define EN_XORPCK		1
+#define DSP_RSTCT2              0xe1008014
+
+static void omap_mcbsp_dsp_request(void)
+{
+	if (cpu_is_omap1510() || cpu_is_omap1610() || cpu_is_omap1710()) {
+		omap_writew((omap_readw(ARM_RSTCT1) | (1 << 1) | (1 << 2)),
+			    ARM_RSTCT1);
+		clk_enable(mcbsp_dsp_ck);
+		clk_enable(mcbsp_api_ck);
+
+		/* enable 12MHz clock to mcbsp 1 & 3 */
+		__raw_writew(__raw_readw(DSP_IDLECT2) | (1 << EN_XORPCK),
+			     DSP_IDLECT2);
+		__raw_writew(__raw_readw(DSP_RSTCT2) | 1 | 1 << 1,
+			     DSP_RSTCT2);
+	}
+}
+
+static void omap_mcbsp_dsp_free(void)
+{
+	/* Useless for now */
+}
+
+
+int omap_mcbsp_request(unsigned int id)
+{
+	int err;
+
+	if (omap_mcbsp_check(id) < 0)
+		return -EINVAL;
+
+	/*
+	 * On 1510, 1610 and 1710, McBSP1 and McBSP3
+	 * are DSP public peripherals.
+	 */
+	if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3)
+		omap_mcbsp_dsp_request();
+
+	spin_lock(&mcbsp[id].lock);
+	if (!mcbsp[id].free) {
+		printk (KERN_ERR "OMAP-McBSP: McBSP%d is currently in use\n", id + 1);
+		spin_unlock(&mcbsp[id].lock);
+		return -1;
+	}
+
+	mcbsp[id].free = 0;
+	spin_unlock(&mcbsp[id].lock);
+
+	/* We need to get IRQs here */
+	err = request_irq(mcbsp[id].tx_irq, omap_mcbsp_tx_irq_handler, 0,
+			  "McBSP",
+			  (void *) (&mcbsp[id]));
+	if (err != 0) {
+		printk(KERN_ERR "OMAP-McBSP: Unable to request TX IRQ %d for McBSP%d\n",
+		       mcbsp[id].tx_irq, mcbsp[id].id);
+		return err;
+	}
+
+	init_completion(&(mcbsp[id].tx_irq_completion));
+
+
+	err = request_irq(mcbsp[id].rx_irq, omap_mcbsp_rx_irq_handler, 0,
+			  "McBSP",
+			  (void *) (&mcbsp[id]));
+	if (err != 0) {
+		printk(KERN_ERR "OMAP-McBSP: Unable to request RX IRQ %d for McBSP%d\n",
+		       mcbsp[id].rx_irq, mcbsp[id].id);
+		free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id]));
+		return err;
+	}
+
+	init_completion(&(mcbsp[id].rx_irq_completion));
+	return 0;
+
+}
+
+void omap_mcbsp_free(unsigned int id)
+{
+	if (omap_mcbsp_check(id) < 0)
+		return;
+
+	if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3)
+		omap_mcbsp_dsp_free();
+
+	spin_lock(&mcbsp[id].lock);
+	if (mcbsp[id].free) {
+		printk (KERN_ERR "OMAP-McBSP: McBSP%d was not reserved\n", id + 1);
+		spin_unlock(&mcbsp[id].lock);
+		return;
+	}
+
+	mcbsp[id].free = 1;
+	spin_unlock(&mcbsp[id].lock);
+
+	/* Free IRQs */
+	free_irq(mcbsp[id].rx_irq, (void *) (&mcbsp[id]));
+	free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id]));
+}
+
+/*
+ * Here we start the McBSP, by enabling the sample
+ * generator, both transmitter and receivers,
+ * and the frame sync.
+ */
+void omap_mcbsp_start(unsigned int id)
+{
+	u32 io_base;
+	u16 w;
+
+	if (omap_mcbsp_check(id) < 0)
+		return;
+
+	io_base = mcbsp[id].io_base;
+
+	mcbsp[id].rx_word_length = ((OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7);
+	mcbsp[id].tx_word_length = ((OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7);
+
+	/* Start the sample generator */
+	w = OMAP_MCBSP_READ(io_base, SPCR2);
+	OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6));
+
+	/* Enable transmitter and receiver */
+	w = OMAP_MCBSP_READ(io_base, SPCR2);
+	OMAP_MCBSP_WRITE(io_base, SPCR2, w | 1);
+
+	w = OMAP_MCBSP_READ(io_base, SPCR1);
+	OMAP_MCBSP_WRITE(io_base, SPCR1, w | 1);
+
+	udelay(100);
+
+	/* Start frame sync */
+	w = OMAP_MCBSP_READ(io_base, SPCR2);
+	OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7));
+
+	/* Dump McBSP Regs */
+	omap_mcbsp_dump_reg(id);
+
+}
+
+void omap_mcbsp_stop(unsigned int id)
+{
+	u32 io_base;
+	u16 w;
+
+	if (omap_mcbsp_check(id) < 0)
+		return;
+
+	io_base = mcbsp[id].io_base;
+
+        /* Reset transmitter */
+	w = OMAP_MCBSP_READ(io_base, SPCR2);
+	OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1));
+
+	/* Reset receiver */
+	w = OMAP_MCBSP_READ(io_base, SPCR1);
+	OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~(1));
+
+	/* Reset the sample rate generator */
+	w = OMAP_MCBSP_READ(io_base, SPCR2);
+	OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6));
+}
+
+
+/*
+ * IRQ based word transmission.
+ */
+void omap_mcbsp_xmit_word(unsigned int id, u32 word)
+{
+	u32 io_base;
+	omap_mcbsp_word_length word_length = mcbsp[id].tx_word_length;
+
+	if (omap_mcbsp_check(id) < 0)
+		return;
+
+	io_base = mcbsp[id].io_base;
+
+	wait_for_completion(&(mcbsp[id].tx_irq_completion));
+
+	if (word_length > OMAP_MCBSP_WORD_16)
+		OMAP_MCBSP_WRITE(io_base, DXR2, word >> 16);
+	OMAP_MCBSP_WRITE(io_base, DXR1, word & 0xffff);
+}
+
+u32 omap_mcbsp_recv_word(unsigned int id)
+{
+	u32 io_base;
+	u16 word_lsb, word_msb = 0;
+	omap_mcbsp_word_length word_length = mcbsp[id].rx_word_length;
+
+	if (omap_mcbsp_check(id) < 0)
+		return -EINVAL;
+
+	io_base = mcbsp[id].io_base;
+
+	wait_for_completion(&(mcbsp[id].rx_irq_completion));
+
+	if (word_length > OMAP_MCBSP_WORD_16)
+		word_msb = OMAP_MCBSP_READ(io_base, DRR2);
+	word_lsb = OMAP_MCBSP_READ(io_base, DRR1);
+
+	return (word_lsb | (word_msb << 16));
+}
+
+
+/*
+ * Simple DMA based buffer rx/tx routines.
+ * Nothing fancy, just a single buffer tx/rx through DMA.
+ * The DMA resources are released once the transfer is done.
+ * For anything fancier, you should use your own customized DMA
+ * routines and callbacks.
+ */
+int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int length)
+{
+	int dma_tx_ch;
+
+	if (omap_mcbsp_check(id) < 0)
+		return -EINVAL;
+
+	if (omap_request_dma(mcbsp[id].dma_tx_sync, "McBSP TX", omap_mcbsp_tx_dma_callback,
+			     &mcbsp[id],
+			     &dma_tx_ch)) {
+		printk("OMAP-McBSP: Unable to request DMA channel for McBSP%d TX. Trying IRQ based TX\n", id+1);
+		return -EAGAIN;
+	}
+	mcbsp[id].dma_tx_lch = dma_tx_ch;
+
+	DBG("TX DMA on channel %d\n", dma_tx_ch);
+
+	init_completion(&(mcbsp[id].tx_dma_completion));
+
+	omap_set_dma_transfer_params(mcbsp[id].dma_tx_lch,
+				     OMAP_DMA_DATA_TYPE_S16,
+				     length >> 1, 1,
+				     OMAP_DMA_SYNC_ELEMENT);
+
+	omap_set_dma_dest_params(mcbsp[id].dma_tx_lch,
+				 OMAP_DMA_PORT_TIPB,
+				 OMAP_DMA_AMODE_CONSTANT,
+				 mcbsp[id].io_base + OMAP_MCBSP_REG_DXR1);
+
+	omap_set_dma_src_params(mcbsp[id].dma_tx_lch,
+				OMAP_DMA_PORT_EMIFF,
+				OMAP_DMA_AMODE_POST_INC,
+				buffer);
+
+	omap_start_dma(mcbsp[id].dma_tx_lch);
+	wait_for_completion(&(mcbsp[id].tx_dma_completion));
+	return 0;
+}
+
+
+int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int length)
+{
+	int dma_rx_ch;
+
+	if (omap_mcbsp_check(id) < 0)
+		return -EINVAL;
+
+	if (omap_request_dma(mcbsp[id].dma_rx_sync, "McBSP RX", omap_mcbsp_rx_dma_callback,
+			     &mcbsp[id],
+			     &dma_rx_ch)) {
+		printk("Unable to request DMA channel for McBSP%d RX. Trying IRQ based RX\n", id+1);
+		return -EAGAIN;
+	}
+	mcbsp[id].dma_rx_lch = dma_rx_ch;
+
+	DBG("RX DMA on channel %d\n", dma_rx_ch);
+
+	init_completion(&(mcbsp[id].rx_dma_completion));
+
+	omap_set_dma_transfer_params(mcbsp[id].dma_rx_lch,
+				     OMAP_DMA_DATA_TYPE_S16,
+				     length >> 1, 1,
+				     OMAP_DMA_SYNC_ELEMENT);
+
+	omap_set_dma_src_params(mcbsp[id].dma_rx_lch,
+				OMAP_DMA_PORT_TIPB,
+				OMAP_DMA_AMODE_CONSTANT,
+				mcbsp[id].io_base + OMAP_MCBSP_REG_DRR1);
+
+	omap_set_dma_dest_params(mcbsp[id].dma_rx_lch,
+				 OMAP_DMA_PORT_EMIFF,
+				 OMAP_DMA_AMODE_POST_INC,
+				 buffer);
+
+	omap_start_dma(mcbsp[id].dma_rx_lch);
+	wait_for_completion(&(mcbsp[id].rx_dma_completion));
+	return 0;
+}
+
+
+/*
+ * SPI wrapper.
+ * Since SPI setup is much simpler than the generic McBSP one,
+ * this wrapper just need an omap_mcbsp_spi_cfg structure as an input.
+ * Once this is done, you can call omap_mcbsp_start().
+ */
+void omap_mcbsp_set_spi_mode(unsigned int id, const struct omap_mcbsp_spi_cfg * spi_cfg)
+{
+	struct omap_mcbsp_reg_cfg mcbsp_cfg;
+
+	if (omap_mcbsp_check(id) < 0)
+		return;
+
+	memset(&mcbsp_cfg, 0, sizeof(struct omap_mcbsp_reg_cfg));
+
+	/* SPI has only one frame */
+	mcbsp_cfg.rcr1 |= (RWDLEN1(spi_cfg->word_length) | RFRLEN1(0));
+	mcbsp_cfg.xcr1 |= (XWDLEN1(spi_cfg->word_length) | XFRLEN1(0));
+
+        /* Clock stop mode */
+	if (spi_cfg->clk_stp_mode == OMAP_MCBSP_CLK_STP_MODE_NO_DELAY)
+		mcbsp_cfg.spcr1 |= (1 << 12);
+	else
+		mcbsp_cfg.spcr1 |= (3 << 11);
+
+	/* Set clock parities */
+	if (spi_cfg->rx_clock_polarity == OMAP_MCBSP_CLK_RISING)
+		mcbsp_cfg.pcr0 |= CLKRP;
+	else
+		mcbsp_cfg.pcr0 &= ~CLKRP;
+
+	if (spi_cfg->tx_clock_polarity == OMAP_MCBSP_CLK_RISING)
+		mcbsp_cfg.pcr0 &= ~CLKXP;
+	else
+		mcbsp_cfg.pcr0 |= CLKXP;
+
+	/* Set SCLKME to 0 and CLKSM to 1 */
+	mcbsp_cfg.pcr0 &= ~SCLKME;
+	mcbsp_cfg.srgr2 |= CLKSM;
+
+	/* Set FSXP */
+	if (spi_cfg->fsx_polarity == OMAP_MCBSP_FS_ACTIVE_HIGH)
+		mcbsp_cfg.pcr0 &= ~FSXP;
+	else
+		mcbsp_cfg.pcr0 |= FSXP;
+
+	if (spi_cfg->spi_mode == OMAP_MCBSP_SPI_MASTER) {
+		mcbsp_cfg.pcr0 |= CLKXM;
+		mcbsp_cfg.srgr1 |= CLKGDV(spi_cfg->clk_div -1);
+		mcbsp_cfg.pcr0 |= FSXM;
+		mcbsp_cfg.srgr2 &= ~FSGM;
+		mcbsp_cfg.xcr2 |= XDATDLY(1);
+		mcbsp_cfg.rcr2 |= RDATDLY(1);
+	}
+	else {
+		mcbsp_cfg.pcr0 &= ~CLKXM;
+		mcbsp_cfg.srgr1 |= CLKGDV(1);
+		mcbsp_cfg.pcr0 &= ~FSXM;
+		mcbsp_cfg.xcr2 &= ~XDATDLY(3);
+		mcbsp_cfg.rcr2 &= ~RDATDLY(3);
+	}
+
+	mcbsp_cfg.xcr2 &= ~XPHASE;
+	mcbsp_cfg.rcr2 &= ~RPHASE;
+
+	omap_mcbsp_config(id, &mcbsp_cfg);
+}
+
+
+/*
+ * McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
+ * 730 has only 2 McBSP, and both of them are MPU peripherals.
+ */
+struct omap_mcbsp_info {
+	u32 virt_base;
+	u8 dma_rx_sync, dma_tx_sync;
+	u16 rx_irq, tx_irq;
+};
+
+#ifdef CONFIG_ARCH_OMAP730
+static const struct omap_mcbsp_info mcbsp_730[] = {
+	[0] = { .virt_base = io_p2v(OMAP730_MCBSP1_BASE),
+		.dma_rx_sync = OMAP_DMA_MCBSP1_RX,
+		.dma_tx_sync = OMAP_DMA_MCBSP1_TX,
+		.rx_irq = INT_730_McBSP1RX,
+		.tx_irq = INT_730_McBSP1TX },
+	[1] = { .virt_base = io_p2v(OMAP730_MCBSP2_BASE),
+		.dma_rx_sync = OMAP_DMA_MCBSP3_RX,
+		.dma_tx_sync = OMAP_DMA_MCBSP3_TX,
+		.rx_irq = INT_730_McBSP2RX,
+		.tx_irq = INT_730_McBSP2TX },
+};
+#endif
+
+#ifdef CONFIG_ARCH_OMAP1510
+static const struct omap_mcbsp_info mcbsp_1510[] = {
+	[0] = { .virt_base = OMAP1510_MCBSP1_BASE,
+		.dma_rx_sync = OMAP_DMA_MCBSP1_RX,
+		.dma_tx_sync = OMAP_DMA_MCBSP1_TX,
+		.rx_irq = INT_McBSP1RX,
+		.tx_irq = INT_McBSP1TX },
+	[1] = { .virt_base = io_p2v(OMAP1510_MCBSP2_BASE),
+		.dma_rx_sync = OMAP_DMA_MCBSP2_RX,
+		.dma_tx_sync = OMAP_DMA_MCBSP2_TX,
+		.rx_irq = INT_1510_SPI_RX,
+		.tx_irq = INT_1510_SPI_TX },
+	[2] = { .virt_base = OMAP1510_MCBSP3_BASE,
+		.dma_rx_sync = OMAP_DMA_MCBSP3_RX,
+		.dma_tx_sync = OMAP_DMA_MCBSP3_TX,
+		.rx_irq = INT_McBSP3RX,
+		.tx_irq = INT_McBSP3TX },
+};
+#endif
+
+#if defined(CONFIG_ARCH_OMAP16XX)
+static const struct omap_mcbsp_info mcbsp_1610[] = {
+	[0] = { .virt_base = OMAP1610_MCBSP1_BASE,
+		.dma_rx_sync = OMAP_DMA_MCBSP1_RX,
+		.dma_tx_sync = OMAP_DMA_MCBSP1_TX,
+		.rx_irq = INT_McBSP1RX,
+		.tx_irq = INT_McBSP1TX },
+	[1] = { .virt_base = io_p2v(OMAP1610_MCBSP2_BASE),
+		.dma_rx_sync = OMAP_DMA_MCBSP2_RX,
+		.dma_tx_sync = OMAP_DMA_MCBSP2_TX,
+		.rx_irq = INT_1610_McBSP2_RX,
+		.tx_irq = INT_1610_McBSP2_TX },
+	[2] = { .virt_base = OMAP1610_MCBSP3_BASE,
+		.dma_rx_sync = OMAP_DMA_MCBSP3_RX,
+		.dma_tx_sync = OMAP_DMA_MCBSP3_TX,
+		.rx_irq = INT_McBSP3RX,
+		.tx_irq = INT_McBSP3TX },
+};
+#endif
+
+static int __init omap_mcbsp_init(void)
+{
+	int mcbsp_count = 0, i;
+	static const struct omap_mcbsp_info *mcbsp_info;
+
+	printk("Initializing OMAP McBSP system\n");
+
+	mcbsp_dsp_ck = clk_get(0, "dsp_ck");
+	if (IS_ERR(mcbsp_dsp_ck)) {
+		printk(KERN_ERR "mcbsp: could not acquire dsp_ck handle.\n");
+		return PTR_ERR(mcbsp_dsp_ck);
+	}
+	mcbsp_api_ck = clk_get(0, "api_ck");
+	if (IS_ERR(mcbsp_dsp_ck)) {
+		printk(KERN_ERR "mcbsp: could not acquire api_ck handle.\n");
+		return PTR_ERR(mcbsp_api_ck);
+	}
+
+#ifdef CONFIG_ARCH_OMAP730
+	if (cpu_is_omap730()) {
+		mcbsp_info = mcbsp_730;
+		mcbsp_count = ARRAY_SIZE(mcbsp_730);
+	}
+#endif
+#ifdef CONFIG_ARCH_OMAP1510
+	if (cpu_is_omap1510()) {
+		mcbsp_info = mcbsp_1510;
+		mcbsp_count = ARRAY_SIZE(mcbsp_1510);
+	}
+#endif
+#if defined(CONFIG_ARCH_OMAP16XX)
+	if (cpu_is_omap1610() || cpu_is_omap1710()) {
+		mcbsp_info = mcbsp_1610;
+		mcbsp_count = ARRAY_SIZE(mcbsp_1610);
+	}
+#endif
+	for (i = 0; i < OMAP_MAX_MCBSP_COUNT ; i++) {
+		if (i >= mcbsp_count) {
+			mcbsp[i].io_base = 0;
+			mcbsp[i].free = 0;
+                        continue;
+		}
+		mcbsp[i].id = i + 1;
+		mcbsp[i].free = 1;
+		mcbsp[i].dma_tx_lch = -1;
+		mcbsp[i].dma_rx_lch = -1;
+
+		mcbsp[i].io_base = mcbsp_info[i].virt_base;
+		mcbsp[i].tx_irq = mcbsp_info[i].tx_irq;
+		mcbsp[i].rx_irq = mcbsp_info[i].rx_irq;
+		mcbsp[i].dma_rx_sync = mcbsp_info[i].dma_rx_sync;
+		mcbsp[i].dma_tx_sync = mcbsp_info[i].dma_tx_sync;
+		spin_lock_init(&mcbsp[i].lock);
+	}
+
+	return 0;
+}
+
+
+arch_initcall(omap_mcbsp_init);
+
+EXPORT_SYMBOL(omap_mcbsp_config);
+EXPORT_SYMBOL(omap_mcbsp_request);
+EXPORT_SYMBOL(omap_mcbsp_free);
+EXPORT_SYMBOL(omap_mcbsp_start);
+EXPORT_SYMBOL(omap_mcbsp_stop);
+EXPORT_SYMBOL(omap_mcbsp_xmit_word);
+EXPORT_SYMBOL(omap_mcbsp_recv_word);
+EXPORT_SYMBOL(omap_mcbsp_xmit_buffer);
+EXPORT_SYMBOL(omap_mcbsp_recv_buffer);
+EXPORT_SYMBOL(omap_mcbsp_set_spi_mode);
diff --git a/arch/arm/mach-omap/mux.c b/arch/arm/mach-omap/mux.c
new file mode 100644
index 0000000..bcf3c6e
--- /dev/null
+++ b/arch/arm/mach-omap/mux.c
@@ -0,0 +1,163 @@
+/*
+ * linux/arch/arm/mach-omap/mux.c
+ *
+ * Utility to set the Omap MUX and PULL_DWN registers from a table in mux.h
+ *
+ * Copyright (C) 2003 Nokia Corporation
+ *
+ * Written by Tony Lindgren <tony.lindgren@nokia.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.
+ *
+ * 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
+ *
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <linux/spinlock.h>
+
+#define __MUX_C__
+#include <asm/arch/mux.h>
+
+#ifdef CONFIG_OMAP_MUX
+
+/*
+ * Sets the Omap MUX and PULL_DWN registers based on the table
+ */
+int __init_or_module
+omap_cfg_reg(const reg_cfg_t reg_cfg)
+{
+	static DEFINE_SPINLOCK(mux_spin_lock);
+
+	unsigned long flags;
+	reg_cfg_set *cfg;
+	unsigned int reg_orig = 0, reg = 0, pu_pd_orig = 0, pu_pd = 0,
+		pull_orig = 0, pull = 0;
+	unsigned int mask, warn = 0;
+
+	if (reg_cfg > ARRAY_SIZE(reg_cfg_table)) {
+		printk(KERN_ERR "MUX: reg_cfg %d\n", reg_cfg);
+		return -EINVAL;
+	}
+
+	cfg = &reg_cfg_table[reg_cfg];
+
+	/*
+	 * We do a pretty long section here with lock on, but pin muxing
+	 * should only happen on driver init for each driver, so it's not time
+	 * critical.
+	 */
+	spin_lock_irqsave(&mux_spin_lock, flags);
+
+	/* Check the mux register in question */
+	if (cfg->mux_reg) {
+		unsigned	tmp1, tmp2;
+
+		reg_orig = omap_readl(cfg->mux_reg);
+
+		/* The mux registers always seem to be 3 bits long */
+		mask = (0x7 << cfg->mask_offset);
+		tmp1 = reg_orig & mask;
+		reg = reg_orig & ~mask;
+
+		tmp2 = (cfg->mask << cfg->mask_offset);
+		reg |= tmp2;
+
+		if (tmp1 != tmp2)
+			warn = 1;
+
+		omap_writel(reg, cfg->mux_reg);
+	}
+
+	/* Check for pull up or pull down selection on 1610 */
+	if (!cpu_is_omap1510()) {
+		if (cfg->pu_pd_reg && cfg->pull_val) {
+			pu_pd_orig = omap_readl(cfg->pu_pd_reg);
+			mask = 1 << cfg->pull_bit;
+
+			if (cfg->pu_pd_val) {
+				if (!(pu_pd_orig & mask))
+					warn = 1;
+				/* Use pull up */
+				pu_pd = pu_pd_orig | mask;
+			} else {
+				if (pu_pd_orig & mask)
+					warn = 1;
+				/* Use pull down */
+				pu_pd = pu_pd_orig & ~mask;
+			}
+			omap_writel(pu_pd, cfg->pu_pd_reg);
+		}
+	}
+
+	/* Check for an associated pull down register */
+	if (cfg->pull_reg) {
+		pull_orig = omap_readl(cfg->pull_reg);
+		mask = 1 << cfg->pull_bit;
+
+		if (cfg->pull_val) {
+			if (pull_orig & mask)
+				warn = 1;
+			/* Low bit = pull enabled */
+			pull = pull_orig & ~mask;
+		} else {
+			if (!(pull_orig & mask))
+				warn = 1;
+			/* High bit = pull disabled */
+			pull = pull_orig | mask;
+		}
+
+		omap_writel(pull, cfg->pull_reg);
+	}
+
+	if (warn) {
+#ifdef CONFIG_OMAP_MUX_WARNINGS
+		printk(KERN_WARNING "MUX: initialized %s\n", cfg->name);
+#endif
+	}
+
+#ifdef CONFIG_OMAP_MUX_DEBUG
+	if (cfg->debug || warn) {
+		printk("MUX: Setting register %s\n", cfg->name);
+		printk("      %s (0x%08x) = 0x%08x -> 0x%08x\n",
+		       cfg->mux_reg_name, cfg->mux_reg, reg_orig, reg);
+
+		if (!cpu_is_omap1510()) {
+			if (cfg->pu_pd_reg && cfg->pull_val) {
+				printk("      %s (0x%08x) = 0x%08x -> 0x%08x\n",
+				       cfg->pu_pd_name, cfg->pu_pd_reg,
+				       pu_pd_orig, pu_pd);
+			}
+		}
+
+		if (cfg->pull_reg)
+			printk("      %s (0x%08x) = 0x%08x -> 0x%08x\n",
+			       cfg->pull_name, cfg->pull_reg, pull_orig, pull);
+	}
+#endif
+
+	spin_unlock_irqrestore(&mux_spin_lock, flags);
+
+#ifdef CONFIG_OMAP_MUX_ERRORS
+	return warn ? -ETXTBSY : 0;
+#else
+	return 0;
+#endif
+}
+
+EXPORT_SYMBOL(omap_cfg_reg);
+
+#endif	/* CONFIG_OMAP_MUX */
diff --git a/arch/arm/mach-omap/ocpi.c b/arch/arm/mach-omap/ocpi.c
new file mode 100644
index 0000000..c9ced13
--- /dev/null
+++ b/arch/arm/mach-omap/ocpi.c
@@ -0,0 +1,114 @@
+/*
+ * linux/arch/arm/mach-omap/ocpi.c
+ *
+ * Minimal OCP bus support for omap16xx
+ *
+ * Copyright (C) 2003 - 2005 Nokia Corporation
+ * Written by Tony Lindgren <tony@atomide.com>
+ *
+ * Modified for clock framework by Paul Mundt <paul.mundt@nokia.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.
+ *
+ * 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
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+
+#include <asm/io.h>
+#include <asm/hardware/clock.h>
+#include <asm/arch/hardware.h>
+
+#define OCPI_BASE		0xfffec320
+#define OCPI_FAULT		(OCPI_BASE + 0x00)
+#define OCPI_CMD_FAULT		(OCPI_BASE + 0x04)
+#define OCPI_SINT0		(OCPI_BASE + 0x08)
+#define OCPI_TABORT		(OCPI_BASE + 0x0c)
+#define OCPI_SINT1		(OCPI_BASE + 0x10)
+#define OCPI_PROT		(OCPI_BASE + 0x14)
+#define OCPI_SEC		(OCPI_BASE + 0x18)
+
+/* USB OHCI OCPI access error registers */
+#define HOSTUEADDR	0xfffba0e0
+#define HOSTUESTATUS	0xfffba0e4
+
+static struct clk *ocpi_ck;
+
+/*
+ * Enables device access to OMAP buses via the OCPI bridge
+ * FIXME: Add locking
+ */
+int ocpi_enable(void)
+{
+	unsigned int val;
+
+	if (!cpu_is_omap16xx())
+		return -ENODEV;
+
+	/* Make sure there's clock for OCPI */
+	clk_enable(ocpi_ck);
+
+	/* Enable access for OHCI in OCPI */
+	val = omap_readl(OCPI_PROT);
+	val &= ~0xff;
+	//val &= (1 << 0);	/* Allow access only to EMIFS */
+	omap_writel(val, OCPI_PROT);
+
+	val = omap_readl(OCPI_SEC);
+	val &= ~0xff;
+	omap_writel(val, OCPI_SEC);
+
+	return 0;
+}
+EXPORT_SYMBOL(ocpi_enable);
+
+static int __init omap_ocpi_init(void)
+{
+	if (!cpu_is_omap16xx())
+		return -ENODEV;
+
+	ocpi_ck = clk_get(NULL, "l3_ocpi_ck");
+	if (IS_ERR(ocpi_ck))
+		return PTR_ERR(ocpi_ck);
+
+	clk_use(ocpi_ck);
+	ocpi_enable();
+	printk("OMAP OCPI interconnect driver loaded\n");
+
+	return 0;
+}
+
+static void __exit omap_ocpi_exit(void)
+{
+	/* REVISIT: Disable OCPI */
+
+	if (!cpu_is_omap16xx())
+		return;
+
+	clk_unuse(ocpi_ck);
+	clk_put(ocpi_ck);
+}
+
+MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
+MODULE_DESCRIPTION("OMAP OCPI bus controller module");
+MODULE_LICENSE("GPL");
+module_init(omap_ocpi_init);
+module_exit(omap_ocpi_exit);
diff --git a/arch/arm/mach-omap/pm.c b/arch/arm/mach-omap/pm.c
new file mode 100644
index 0000000..00fac15
--- /dev/null
+++ b/arch/arm/mach-omap/pm.c
@@ -0,0 +1,628 @@
+/*
+ * linux/arch/arm/mach-omap/pm.c
+ *
+ * OMAP Power Management Routines
+ *
+ * Original code for the SA11x0:
+ * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
+ *
+ * Modified for the PXA250 by Nicolas Pitre:
+ * Copyright (c) 2002 Monta Vista Software, Inc.
+ *
+ * Modified for the OMAP1510 by David Singleton:
+ * Copyright (c) 2002 Monta Vista Software, Inc.
+ *
+ * Cleanup 2004 for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.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.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/pm.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/pm.h>
+
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/arch/omap16xx.h>
+#include <asm/arch/pm.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/tc.h>
+#include <asm/arch/tps65010.h>
+
+#include "clock.h"
+
+static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE];
+static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE];
+static unsigned int mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_SIZE];
+static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE];
+
+/*
+ * Let's power down on idle, but only if we are really
+ * idle, because once we start down the path of
+ * going idle we continue to do idle even if we get
+ * a clock tick interrupt . .
+ */
+void omap_pm_idle(void)
+{
+	int (*func_ptr)(void) = 0;
+	unsigned int mask32 = 0;
+
+	/*
+	 * If the DSP is being used let's just idle the CPU, the overhead
+	 * to wake up from Big Sleep is big, milliseconds versus micro
+	 * seconds for wait for interrupt.
+	 */
+
+	local_irq_disable();
+	local_fiq_disable();
+	if (need_resched()) {
+		local_fiq_enable();
+		local_irq_enable();
+		return;
+	}
+	mask32 = omap_readl(ARM_SYSST);
+	local_fiq_enable();
+	local_irq_enable();
+
+#if defined(CONFIG_OMAP_32K_TIMER) && defined(CONFIG_NO_IDLE_HZ)
+	/* Override timer to use VST for the next cycle */
+	omap_32k_timer_next_vst_interrupt();
+#endif
+
+	if ((mask32 & DSP_IDLE) == 0) {
+		__asm__ volatile ("mcr	p15, 0, r0, c7, c0, 4");
+	} else {
+
+		if (cpu_is_omap1510()) {
+			func_ptr = (void *)(OMAP1510_SRAM_IDLE_SUSPEND);
+		} else if (cpu_is_omap1610() || cpu_is_omap1710()) {
+			func_ptr = (void *)(OMAP1610_SRAM_IDLE_SUSPEND);
+		} else if (cpu_is_omap5912()) {
+			func_ptr = (void *)(OMAP5912_SRAM_IDLE_SUSPEND);
+		}
+
+		func_ptr();
+	}
+}
+
+/*
+ * Configuration of the wakeup event is board specific. For the
+ * moment we put it into this helper function. Later it may move
+ * to board specific files.
+ */
+static void omap_pm_wakeup_setup(void)
+{
+	/*
+	 * Enable ARM XOR clock and release peripheral from reset by
+	 * writing 1 to PER_EN bit in ARM_RSTCT2, this is required
+	 * for UART configuration to use UART2 to wake up.
+	 */
+
+	omap_writel(omap_readl(ARM_IDLECT2) | ENABLE_XORCLK, ARM_IDLECT2);
+	omap_writel(omap_readl(ARM_RSTCT2) | PER_EN, ARM_RSTCT2);
+	omap_writew(MODEM_32K_EN, ULPD_CLOCK_CTRL);
+
+	/*
+	 * Turn off all interrupts except L1-2nd level cascade,
+	 * and the L2 wakeup interrupts: keypad and UART2.
+	 */
+
+	omap_writel(~IRQ_LEVEL2, OMAP_IH1_MIR);
+
+	if (cpu_is_omap1510()) {
+		omap_writel(~(IRQ_UART2 | IRQ_KEYBOARD),  OMAP_IH2_MIR);
+	}
+
+	if (cpu_is_omap16xx()) {
+		omap_writel(~(IRQ_UART2 | IRQ_KEYBOARD), OMAP_IH2_0_MIR);
+
+		omap_writel(~0x0, OMAP_IH2_1_MIR);
+		omap_writel(~0x0, OMAP_IH2_2_MIR);
+		omap_writel(~0x0, OMAP_IH2_3_MIR);
+	}
+
+	/*  New IRQ agreement */
+ 	omap_writel(1, OMAP_IH1_CONTROL);
+
+	/* external PULL to down, bit 22 = 0 */
+	omap_writel(omap_readl(PULL_DWN_CTRL_2) & ~(1<<22), PULL_DWN_CTRL_2);
+}
+
+void omap_pm_suspend(void)
+{
+	unsigned int mask32 = 0;
+	unsigned long arg0 = 0, arg1 = 0;
+	int (*func_ptr)(unsigned short, unsigned short) = 0;
+	unsigned short save_dsp_idlect2;
+
+	printk("PM: OMAP%x is entering deep sleep now ...\n", system_rev);
+
+	if (machine_is_omap_osk()) {
+		/* Stop LED1 (D9) blink */
+		tps65010_set_led(LED1, OFF);
+	}
+
+	/*
+	 * Step 1: turn off interrupts
+	 */
+
+	local_irq_disable();
+	local_fiq_disable();
+
+	/*
+	 * Step 2: save registers
+	 *
+	 * The omap is a strange/beautiful device. The caches, memory
+	 * and register state are preserved across power saves.
+	 * We have to save and restore very little register state to
+	 * idle the omap.
+         *
+ 	 * Save interrupt, MPUI, ARM and UPLD control registers.
+	 */
+
+	if (cpu_is_omap1510()) {
+		MPUI1510_SAVE(OMAP_IH1_MIR);
+		MPUI1510_SAVE(OMAP_IH2_MIR);
+		MPUI1510_SAVE(MPUI_CTRL);
+		MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG);
+		MPUI1510_SAVE(MPUI_DSP_API_CONFIG);
+		MPUI1510_SAVE(EMIFS_CONFIG);
+		MPUI1510_SAVE(EMIFF_SDRAM_CONFIG);
+	} else if (cpu_is_omap16xx()) {
+		MPUI1610_SAVE(OMAP_IH1_MIR);
+		MPUI1610_SAVE(OMAP_IH2_0_MIR);
+		MPUI1610_SAVE(OMAP_IH2_1_MIR);
+		MPUI1610_SAVE(OMAP_IH2_2_MIR);
+		MPUI1610_SAVE(OMAP_IH2_3_MIR);
+		MPUI1610_SAVE(MPUI_CTRL);
+		MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG);
+		MPUI1610_SAVE(MPUI_DSP_API_CONFIG);
+		MPUI1610_SAVE(EMIFS_CONFIG);
+		MPUI1610_SAVE(EMIFF_SDRAM_CONFIG);
+	}
+
+	ARM_SAVE(ARM_CKCTL);
+	ARM_SAVE(ARM_IDLECT1);
+	ARM_SAVE(ARM_IDLECT2);
+	ARM_SAVE(ARM_EWUPCT);
+	ARM_SAVE(ARM_RSTCT1);
+	ARM_SAVE(ARM_RSTCT2);
+	ARM_SAVE(ARM_SYSST);
+	ULPD_SAVE(ULPD_CLOCK_CTRL);
+	ULPD_SAVE(ULPD_STATUS_REQ);
+
+	/*
+	 * Step 3: LOW_PWR signal enabling
+	 *
+	 * Allow the LOW_PWR signal to be visible on MPUIO5 ball.
+	 */
+	if (cpu_is_omap1510()) {
+		/* POWER_CTRL_REG = 0x1 (LOW_POWER is available) */
+		omap_writew(omap_readw(ULPD_POWER_CTRL) |
+			    OMAP1510_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL);
+	} else if (cpu_is_omap16xx()) {
+		/* POWER_CTRL_REG = 0x1 (LOW_POWER is available) */
+		omap_writew(omap_readw(ULPD_POWER_CTRL) |
+			    OMAP1610_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL);
+	}
+
+	/* configure LOW_PWR pin */
+	omap_cfg_reg(T20_1610_LOW_PWR);
+
+	/*
+	 * Step 4: OMAP DSP Shutdown
+	 */
+
+	/* Set DSP_RST = 1 and DSP_EN = 0, put DSP block into reset */
+	omap_writel((omap_readl(ARM_RSTCT1) | DSP_RST) & ~DSP_ENABLE,
+		    ARM_RSTCT1);
+
+	/* Set DSP boot mode to DSP-IDLE, DSP_BOOT_MODE = 0x2 */
+        omap_writel(DSP_IDLE_MODE, MPUI_DSP_BOOT_CONFIG);
+
+	/* Set EN_DSPCK = 0, stop DSP block clock */
+	omap_writel(omap_readl(ARM_CKCTL) & ~DSP_CLOCK_ENABLE, ARM_CKCTL);
+
+	/* Stop any DSP domain clocks */
+	omap_writel(omap_readl(ARM_IDLECT2) | (1<<EN_APICK), ARM_IDLECT2);
+	save_dsp_idlect2 = __raw_readw(DSP_IDLECT2);
+	__raw_writew(0, DSP_IDLECT2);
+
+	/*
+	 * Step 5: Wakeup Event Setup
+	 */
+
+	omap_pm_wakeup_setup();
+
+	/*
+	 * Step 6a: ARM and Traffic controller shutdown
+	 *
+	 * Step 6 starts here with clock and watchdog disable
+	 */
+
+	/* stop clocks */
+	mask32 = omap_readl(ARM_IDLECT2);
+	mask32 &= ~(1<<EN_WDTCK);  /* bit 0 -> 0 (WDT clock) */
+	mask32 |=  (1<<EN_XORPCK); /* bit 1 -> 1 (XORPCK clock) */
+	mask32 &= ~(1<<EN_PERCK);  /* bit 2 -> 0 (MPUPER_CK clock) */
+	mask32 &= ~(1<<EN_LCDCK);  /* bit 3 -> 0 (LCDC clock) */
+	mask32 &= ~(1<<EN_LBCK);   /* bit 4 -> 0 (local bus clock) */
+	mask32 |=  (1<<EN_APICK);  /* bit 6 -> 1 (MPUI clock) */
+	mask32 &= ~(1<<EN_TIMCK);  /* bit 7 -> 0 (MPU timer clock) */
+	mask32 &= ~(1<<DMACK_REQ); /* bit 8 -> 0 (DMAC clock) */
+	mask32 &= ~(1<<EN_GPIOCK); /* bit 9 -> 0 (GPIO clock) */
+	omap_writel(mask32, ARM_IDLECT2);
+
+	/* disable ARM watchdog */
+	omap_writel(0x00F5, OMAP_WDT_TIMER_MODE);
+	omap_writel(0x00A0, OMAP_WDT_TIMER_MODE);
+
+	/*
+	 * Step 6b: ARM and Traffic controller shutdown
+	 *
+	 * Step 6 continues here. Prepare jump to power management
+	 * assembly code in internal SRAM.
+	 *
+	 * Since the omap_cpu_suspend routine has been copied to
+	 * SRAM, we'll do an indirect procedure call to it and pass the
+	 * contents of arm_idlect1 and arm_idlect2 so it can restore
+	 * them when it wakes up and it will return.
+	 */
+
+	arg0 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT1];
+	arg1 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT2];
+
+	if (cpu_is_omap1510()) {
+		func_ptr = (void *)(OMAP1510_SRAM_API_SUSPEND);
+	} else if (cpu_is_omap1610() || cpu_is_omap1710()) {
+		func_ptr = (void *)(OMAP1610_SRAM_API_SUSPEND);
+	} else if (cpu_is_omap5912()) {
+		func_ptr = (void *)(OMAP5912_SRAM_API_SUSPEND);
+	}
+
+	/*
+	 * Step 6c: ARM and Traffic controller shutdown
+	 *
+	 * Jump to assembly code. The processor will stay there
+ 	 * until wake up.
+	 */
+
+        func_ptr(arg0, arg1);
+
+	/*
+	 * If we are here, processor is woken up!
+	 */
+
+	if (cpu_is_omap1510()) {
+		/* POWER_CTRL_REG = 0x0 (LOW_POWER is disabled) */
+		omap_writew(omap_readw(ULPD_POWER_CTRL) &
+			    ~OMAP1510_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL);
+	} else if (cpu_is_omap16xx()) {
+		/* POWER_CTRL_REG = 0x0 (LOW_POWER is disabled) */
+		omap_writew(omap_readw(ULPD_POWER_CTRL) &
+			    ~OMAP1610_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL);
+	}
+
+
+	/* Restore DSP clocks */
+	omap_writel(omap_readl(ARM_IDLECT2) | (1<<EN_APICK), ARM_IDLECT2);
+	__raw_writew(save_dsp_idlect2, DSP_IDLECT2);
+	ARM_RESTORE(ARM_IDLECT2);
+
+	/*
+	 * Restore ARM state, except ARM_IDLECT1/2 which omap_cpu_suspend did
+	 */
+
+	ARM_RESTORE(ARM_CKCTL);
+	ARM_RESTORE(ARM_EWUPCT);
+	ARM_RESTORE(ARM_RSTCT1);
+	ARM_RESTORE(ARM_RSTCT2);
+	ARM_RESTORE(ARM_SYSST);
+	ULPD_RESTORE(ULPD_CLOCK_CTRL);
+	ULPD_RESTORE(ULPD_STATUS_REQ);
+
+	if (cpu_is_omap1510()) {
+		MPUI1510_RESTORE(MPUI_CTRL);
+		MPUI1510_RESTORE(MPUI_DSP_BOOT_CONFIG);
+		MPUI1510_RESTORE(MPUI_DSP_API_CONFIG);
+		MPUI1510_RESTORE(EMIFS_CONFIG);
+		MPUI1510_RESTORE(EMIFF_SDRAM_CONFIG);
+		MPUI1510_RESTORE(OMAP_IH1_MIR);
+		MPUI1510_RESTORE(OMAP_IH2_MIR);
+	} else if (cpu_is_omap16xx()) {
+		MPUI1610_RESTORE(MPUI_CTRL);
+		MPUI1610_RESTORE(MPUI_DSP_BOOT_CONFIG);
+		MPUI1610_RESTORE(MPUI_DSP_API_CONFIG);
+		MPUI1610_RESTORE(EMIFS_CONFIG);
+		MPUI1610_RESTORE(EMIFF_SDRAM_CONFIG);
+
+		MPUI1610_RESTORE(OMAP_IH1_MIR);
+		MPUI1610_RESTORE(OMAP_IH2_0_MIR);
+		MPUI1610_RESTORE(OMAP_IH2_1_MIR);
+		MPUI1610_RESTORE(OMAP_IH2_2_MIR);
+		MPUI1610_RESTORE(OMAP_IH2_3_MIR);
+	}
+
+	/*
+	 * Reenable interrupts
+	 */
+
+	local_irq_enable();
+	local_fiq_enable();
+
+	printk("PM: OMAP%x is re-starting from deep sleep...\n", system_rev);
+
+	if (machine_is_omap_osk()) {
+		/* Let LED1 (D9) blink again */
+		tps65010_set_led(LED1, BLINK);
+	}
+}
+
+#if defined(DEBUG) && defined(CONFIG_PROC_FS)
+static int g_read_completed;
+
+/*
+ * Read system PM registers for debugging
+ */
+static int omap_pm_read_proc(
+	char *page_buffer,
+	char **my_first_byte,
+	off_t virtual_start,
+	int length,
+	int *eof,
+	void *data)
+{
+	int my_buffer_offset = 0;
+	char * const my_base = page_buffer;
+
+	ARM_SAVE(ARM_CKCTL);
+	ARM_SAVE(ARM_IDLECT1);
+	ARM_SAVE(ARM_IDLECT2);
+	ARM_SAVE(ARM_EWUPCT);
+	ARM_SAVE(ARM_RSTCT1);
+	ARM_SAVE(ARM_RSTCT2);
+	ARM_SAVE(ARM_SYSST);
+
+	ULPD_SAVE(ULPD_IT_STATUS);
+	ULPD_SAVE(ULPD_CLOCK_CTRL);
+	ULPD_SAVE(ULPD_SOFT_REQ);
+	ULPD_SAVE(ULPD_STATUS_REQ);
+	ULPD_SAVE(ULPD_DPLL_CTRL);
+	ULPD_SAVE(ULPD_POWER_CTRL);
+
+	if (cpu_is_omap1510()) {
+		MPUI1510_SAVE(MPUI_CTRL);
+		MPUI1510_SAVE(MPUI_DSP_STATUS);
+		MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG);
+		MPUI1510_SAVE(MPUI_DSP_API_CONFIG);
+		MPUI1510_SAVE(EMIFF_SDRAM_CONFIG);
+		MPUI1510_SAVE(EMIFS_CONFIG);
+	} else if (cpu_is_omap16xx()) {
+		MPUI1610_SAVE(MPUI_CTRL);
+		MPUI1610_SAVE(MPUI_DSP_STATUS);
+		MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG);
+		MPUI1610_SAVE(MPUI_DSP_API_CONFIG);
+		MPUI1610_SAVE(EMIFF_SDRAM_CONFIG);
+		MPUI1610_SAVE(EMIFS_CONFIG);
+	}
+
+	if (virtual_start == 0) {
+		g_read_completed = 0;
+
+		my_buffer_offset += sprintf(my_base + my_buffer_offset,
+		   "ARM_CKCTL_REG:            0x%-8x     \n"
+		   "ARM_IDLECT1_REG:          0x%-8x     \n"
+		   "ARM_IDLECT2_REG:          0x%-8x     \n"
+		   "ARM_EWUPCT_REG:           0x%-8x     \n"
+		   "ARM_RSTCT1_REG:           0x%-8x     \n"
+		   "ARM_RSTCT2_REG:           0x%-8x     \n"
+		   "ARM_SYSST_REG:            0x%-8x     \n"
+		   "ULPD_IT_STATUS_REG:       0x%-4x     \n"
+		   "ULPD_CLOCK_CTRL_REG:      0x%-4x     \n"
+		   "ULPD_SOFT_REQ_REG:        0x%-4x     \n"
+		   "ULPD_DPLL_CTRL_REG:       0x%-4x     \n"
+		   "ULPD_STATUS_REQ_REG:      0x%-4x     \n"
+		   "ULPD_POWER_CTRL_REG:      0x%-4x     \n",
+		   ARM_SHOW(ARM_CKCTL),
+		   ARM_SHOW(ARM_IDLECT1),
+		   ARM_SHOW(ARM_IDLECT2),
+		   ARM_SHOW(ARM_EWUPCT),
+		   ARM_SHOW(ARM_RSTCT1),
+		   ARM_SHOW(ARM_RSTCT2),
+		   ARM_SHOW(ARM_SYSST),
+		   ULPD_SHOW(ULPD_IT_STATUS),
+		   ULPD_SHOW(ULPD_CLOCK_CTRL),
+		   ULPD_SHOW(ULPD_SOFT_REQ),
+		   ULPD_SHOW(ULPD_DPLL_CTRL),
+		   ULPD_SHOW(ULPD_STATUS_REQ),
+		   ULPD_SHOW(ULPD_POWER_CTRL));
+
+		if (cpu_is_omap1510()) {
+			my_buffer_offset += sprintf(my_base + my_buffer_offset,
+			   "MPUI1510_CTRL_REG             0x%-8x \n"
+			   "MPUI1510_DSP_STATUS_REG:      0x%-8x \n"
+			   "MPUI1510_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
+		   	   "MPUI1510_DSP_API_CONFIG_REG:  0x%-8x \n"
+		   	   "MPUI1510_SDRAM_CONFIG_REG:    0x%-8x \n"
+		   	   "MPUI1510_EMIFS_CONFIG_REG:    0x%-8x \n",
+		   	   MPUI1510_SHOW(MPUI_CTRL),
+		   	   MPUI1510_SHOW(MPUI_DSP_STATUS),
+		   	   MPUI1510_SHOW(MPUI_DSP_BOOT_CONFIG),
+		   	   MPUI1510_SHOW(MPUI_DSP_API_CONFIG),
+		   	   MPUI1510_SHOW(EMIFF_SDRAM_CONFIG),
+		   	   MPUI1510_SHOW(EMIFS_CONFIG));
+		} else if (cpu_is_omap16xx()) {
+			my_buffer_offset += sprintf(my_base + my_buffer_offset,
+			   "MPUI1610_CTRL_REG             0x%-8x \n"
+			   "MPUI1610_DSP_STATUS_REG:      0x%-8x \n"
+			   "MPUI1610_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
+		   	   "MPUI1610_DSP_API_CONFIG_REG:  0x%-8x \n"
+		   	   "MPUI1610_SDRAM_CONFIG_REG:    0x%-8x \n"
+		   	   "MPUI1610_EMIFS_CONFIG_REG:    0x%-8x \n",
+		   	   MPUI1610_SHOW(MPUI_CTRL),
+		   	   MPUI1610_SHOW(MPUI_DSP_STATUS),
+		   	   MPUI1610_SHOW(MPUI_DSP_BOOT_CONFIG),
+		   	   MPUI1610_SHOW(MPUI_DSP_API_CONFIG),
+		   	   MPUI1610_SHOW(EMIFF_SDRAM_CONFIG),
+		   	   MPUI1610_SHOW(EMIFS_CONFIG));
+		}
+
+		g_read_completed++;
+	} else if (g_read_completed >= 1) {
+		 *eof = 1;
+		 return 0;
+	}
+	g_read_completed++;
+
+	*my_first_byte = page_buffer;
+	return  my_buffer_offset;
+}
+
+static void omap_pm_init_proc(void)
+{
+	struct proc_dir_entry *entry;
+
+	entry = create_proc_read_entry("driver/omap_pm",
+				       S_IWUSR | S_IRUGO, NULL,
+				       omap_pm_read_proc, 0);
+}
+
+#endif /* DEBUG && CONFIG_PROC_FS */
+
+/*
+ *	omap_pm_prepare - Do preliminary suspend work.
+ *	@state:		suspend state we're entering.
+ *
+ */
+//#include <asm/arch/hardware.h>
+
+static int omap_pm_prepare(suspend_state_t state)
+{
+	int error = 0;
+
+	switch (state)
+	{
+	case PM_SUSPEND_STANDBY:
+	case PM_SUSPEND_MEM:
+		break;
+
+	case PM_SUSPEND_DISK:
+		return -ENOTSUPP;
+
+	default:
+		return -EINVAL;
+	}
+
+	return error;
+}
+
+
+/*
+ *	omap_pm_enter - Actually enter a sleep state.
+ *	@state:		State we're entering.
+ *
+ */
+
+static int omap_pm_enter(suspend_state_t state)
+{
+	switch (state)
+	{
+	case PM_SUSPEND_STANDBY:
+	case PM_SUSPEND_MEM:
+		omap_pm_suspend();
+		break;
+
+	case PM_SUSPEND_DISK:
+		return -ENOTSUPP;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+/**
+ *	omap_pm_finish - Finish up suspend sequence.
+ *	@state:		State we're coming out of.
+ *
+ *	This is called after we wake back up (or if entering the sleep state
+ *	failed).
+ */
+
+static int omap_pm_finish(suspend_state_t state)
+{
+	return 0;
+}
+
+
+struct pm_ops omap_pm_ops ={
+	.pm_disk_mode = 0,
+        .prepare        = omap_pm_prepare,
+        .enter          = omap_pm_enter,
+        .finish         = omap_pm_finish,
+};
+
+static int __init omap_pm_init(void)
+{
+	printk("Power Management for TI OMAP.\n");
+	pm_idle = omap_pm_idle;
+	/*
+	 * We copy the assembler sleep/wakeup routines to SRAM.
+	 * These routines need to be in SRAM as that's the only
+	 * memory the MPU can see when it wakes up.
+	 */
+
+#ifdef	CONFIG_ARCH_OMAP1510
+	if (cpu_is_omap1510()) {
+		memcpy((void *)OMAP1510_SRAM_IDLE_SUSPEND,
+		       omap1510_idle_loop_suspend,
+		       omap1510_idle_loop_suspend_sz);
+		memcpy((void *)OMAP1510_SRAM_API_SUSPEND, omap1510_cpu_suspend,
+		       omap1510_cpu_suspend_sz);
+	} else
+#endif
+	if (cpu_is_omap1610() || cpu_is_omap1710()) {
+		memcpy((void *)OMAP1610_SRAM_IDLE_SUSPEND,
+		       omap1610_idle_loop_suspend,
+		       omap1610_idle_loop_suspend_sz);
+		memcpy((void *)OMAP1610_SRAM_API_SUSPEND, omap1610_cpu_suspend,
+		       omap1610_cpu_suspend_sz);
+	} else if (cpu_is_omap5912()) {
+		memcpy((void *)OMAP5912_SRAM_IDLE_SUSPEND,
+		       omap1610_idle_loop_suspend,
+		       omap1610_idle_loop_suspend_sz);
+		memcpy((void *)OMAP5912_SRAM_API_SUSPEND, omap1610_cpu_suspend,
+		       omap1610_cpu_suspend_sz);
+	}
+
+	pm_set_ops(&omap_pm_ops);
+
+#if defined(DEBUG) && defined(CONFIG_PROC_FS)
+	omap_pm_init_proc();
+#endif
+
+	return 0;
+}
+__initcall(omap_pm_init);
+
diff --git a/arch/arm/mach-omap/sleep.S b/arch/arm/mach-omap/sleep.S
new file mode 100644
index 0000000..4d426d1
--- /dev/null
+++ b/arch/arm/mach-omap/sleep.S
@@ -0,0 +1,314 @@
+/*
+ * linux/arch/arm/mach-omap/sleep.S
+ *
+ * Low-level OMAP1510/1610 sleep/wakeUp support
+ *
+ * Initial SA1110 code:
+ * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
+ *
+ * Adapted for PXA by Nicolas Pitre:
+ * Copyright (c) 2002 Monta Vista Software, Inc.
+ *
+ * Support for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.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.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/arch/io.h>
+#include <asm/arch/pm.h>
+
+		.text
+
+/*
+ * Forces OMAP into idle state
+ *
+ * omapXXXX_idle_loop_suspend()
+ *
+ * Note: This code get's copied to internal SRAM at boot. When the OMAP
+ *	 wakes up it continues execution at the point it went to sleep.
+ *
+ * Note: Because of slightly different configuration values we have
+ *       processor specific functions here.
+ */
+
+#ifdef CONFIG_ARCH_OMAP1510
+ENTRY(omap1510_idle_loop_suspend)
+
+	stmfd	sp!, {r0 - r12, lr}		@ save registers on stack
+
+	@ load base address of ARM_IDLECT1 and ARM_IDLECT2
+	mov	r4, #CLKGEN_REG_ASM_BASE & 0xff000000
+	orr	r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
+	orr	r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
+
+	@ turn off clock domains
+	@ get ARM_IDLECT2 into r2
+	ldrh	r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+	mov	r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff
+ 	orr	r5,r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
+	strh	r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+
+	@ request ARM idle
+	@ get ARM_IDLECT1 into r1
+	ldrh	r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+	orr	r3, r1, #OMAP1510_IDLE_LOOP_REQUEST & 0xffff
+	strh	r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+
+	mov	r5, #IDLE_WAIT_CYCLES & 0xff
+	orr     r5, r5, #IDLE_WAIT_CYCLES & 0xff00
+l_1510:	subs	r5, r5, #1
+	bne	l_1510
+/*
+ * Let's wait for the next clock tick to wake us up.
+ */
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c0, 4		@ wait for interrupt
+/*
+ * omap1510_idle_loop_suspend()'s resume point.
+ *
+ * It will just start executing here, so we'll restore stuff from the
+ * stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
+ */
+
+	@ restore ARM_IDLECT1 and ARM_IDLECT2 and return
+	@ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2
+	strh	r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+	strh	r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+
+	ldmfd   sp!, {r0 - r12, pc}     @ restore regs and return
+
+ENTRY(omap1510_idle_loop_suspend_sz)
+	.word	. - omap1510_idle_loop_suspend
+#endif /* CONFIG_ARCH_OMAP1510 */
+
+#if defined(CONFIG_ARCH_OMAP16XX)
+ENTRY(omap1610_idle_loop_suspend)
+
+	stmfd	sp!, {r0 - r12, lr}		@ save registers on stack
+
+	@ load base address of ARM_IDLECT1 and ARM_IDLECT2
+	mov	r4, #CLKGEN_REG_ASM_BASE & 0xff000000
+	orr	r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
+	orr	r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
+
+	@ turn off clock domains
+	@ get ARM_IDLECT2 into r2
+	ldrh	r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+	mov	r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff
+ 	orr	r5,r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff00
+	strh	r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+
+	@ request ARM idle
+	@ get ARM_IDLECT1 into r1
+	ldrh	r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+	orr	r3, r1, #OMAP1610_IDLE_LOOP_REQUEST & 0xffff
+	strh	r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+
+	mov	r5, #IDLE_WAIT_CYCLES & 0xff
+	orr     r5, r5, #IDLE_WAIT_CYCLES & 0xff00
+l_1610:	subs	r5, r5, #1
+	bne	l_1610
+/*
+ * Let's wait for the next clock tick to wake us up.
+ */
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c0, 4		@ wait for interrupt
+/*
+ * omap1610_idle_loop_suspend()'s resume point.
+ *
+ * It will just start executing here, so we'll restore stuff from the
+ * stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
+ */
+
+	@ restore ARM_IDLECT1 and ARM_IDLECT2 and return
+	@ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2
+	strh	r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+	strh	r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+
+	ldmfd   sp!, {r0 - r12, pc}     @ restore regs and return
+
+ENTRY(omap1610_idle_loop_suspend_sz)
+	.word	. - omap1610_idle_loop_suspend
+#endif /* CONFIG_ARCH_OMAP16XX */
+
+/*
+ * Forces OMAP into deep sleep state
+ *
+ * omapXXXX_cpu_suspend()
+ *
+ * The values of the registers ARM_IDLECT1 and ARM_IDLECT2 are passed
+ * as arg0 and arg1 from caller. arg0 is stored in register r0 and arg1
+ * in register r1.
+ *
+ * Note: This code get's copied to internal SRAM at boot. When the OMAP
+ *	 wakes up it continues execution at the point it went to sleep.
+ *
+ * Note: Because of errata work arounds we have processor specific functions
+ *       here. They are mostly the same, but slightly different.
+ *
+ */
+
+#ifdef CONFIG_ARCH_OMAP1510
+ENTRY(omap1510_cpu_suspend)
+
+	@ save registers on stack
+	stmfd	sp!, {r0 - r12, lr}
+
+	@ load base address of Traffic Controller
+	mov	r4, #TCMIF_ASM_BASE & 0xff000000
+	orr	r4, r4, #TCMIF_ASM_BASE & 0x00ff0000
+	orr	r4, r4, #TCMIF_ASM_BASE & 0x0000ff00
+
+	@ work around errata of OMAP1510 PDE bit for TC shut down
+	@ clear PDE bit
+	ldr	r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+	bic	r5, r5, #PDE_BIT & 0xff
+	str	r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+
+	@ set PWD_EN bit
+	and	r5, r5, #PWD_EN_BIT & 0xff
+	str	r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+
+	@ prepare to put SDRAM into self-refresh manually
+	ldr	r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
+	orr	r5, r5, #SELF_REFRESH_MODE & 0xff000000
+	orr	r5, r5, #SELF_REFRESH_MODE & 0x000000ff
+	str	r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
+
+	@ prepare to put EMIFS to Sleep
+	ldr	r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+	orr	r5, r5, #IDLE_EMIFS_REQUEST & 0xff
+	str	r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+
+	@ load base address of ARM_IDLECT1 and ARM_IDLECT2
+	mov	r4, #CLKGEN_REG_ASM_BASE & 0xff000000
+	orr	r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
+	orr	r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
+
+	@ turn off clock domains
+	mov	r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff
+ 	orr	r5,r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
+	strh	r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+
+	@ request ARM idle
+	mov	r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff
+	orr	r3, r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff00
+	strh	r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+
+	mov	r5, #IDLE_WAIT_CYCLES & 0xff
+	orr     r5, r5, #IDLE_WAIT_CYCLES & 0xff00
+l_1510_2:
+	subs	r5, r5, #1
+	bne	l_1510_2
+/*
+ * Let's wait for the next wake up event to wake us up. r0 can't be
+ * used here because r0 holds ARM_IDLECT1
+ */
+	mov	r2, #0
+	mcr	p15, 0, r2, c7, c0, 4		@ wait for interrupt
+/*
+ * omap1510_cpu_suspend()'s resume point.
+ *
+ * It will just start executing here, so we'll restore stuff from the
+ * stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
+ */
+	strh	r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+	strh	r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+
+	@ restore regs and return
+	ldmfd   sp!, {r0 - r12, pc}
+
+ENTRY(omap1510_cpu_suspend_sz)
+	.word	. - omap1510_cpu_suspend
+#endif /* CONFIG_ARCH_OMAP1510 */
+
+#if defined(CONFIG_ARCH_OMAP16XX)
+ENTRY(omap1610_cpu_suspend)
+
+	@ save registers on stack
+	stmfd	sp!, {r0 - r12, lr}
+
+	@ load base address of Traffic Controller
+	mov	r4, #TCMIF_ASM_BASE & 0xff000000
+	orr	r4, r4, #TCMIF_ASM_BASE & 0x00ff0000
+	orr	r4, r4, #TCMIF_ASM_BASE & 0x0000ff00
+
+	@ prepare to put SDRAM into self-refresh manually
+	ldr	r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
+	orr	r5, r5, #SELF_REFRESH_MODE & 0xff000000
+	orr	r5, r5, #SELF_REFRESH_MODE & 0x000000ff
+	str	r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
+
+	@ prepare to put EMIFS to Sleep
+	ldr	r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+	orr	r5, r5, #IDLE_EMIFS_REQUEST & 0xff
+	str	r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+
+	@ load base address of ARM_IDLECT1 and ARM_IDLECT2
+	mov	r4, #CLKGEN_REG_ASM_BASE & 0xff000000
+	orr	r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
+	orr	r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
+
+	@ turn off clock domains
+	mov	r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff
+ 	orr	r5,r5, #OMAP1610_IDLE_CLOCK_DOMAINS & 0xff00
+	strh	r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+
+	@ work around errata of OMAP1610/5912. Enable (!) peripheral
+	@ clock to let the chip go into deep sleep
+	ldrh	r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+ 	orr	r5,r5, #EN_PERCK_BIT & 0xff
+	strh	r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+
+	@ request ARM idle
+	mov	r3, #OMAP1610_DEEP_SLEEP_REQUEST & 0xff
+	orr	r3, r3, #OMAP1610_DEEP_SLEEP_REQUEST & 0xff00
+	strh	r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+
+	mov	r5, #IDLE_WAIT_CYCLES & 0xff
+	orr     r5, r5, #IDLE_WAIT_CYCLES & 0xff00
+l_1610_2:
+	subs	r5, r5, #1
+	bne	l_1610_2
+/*
+ * Let's wait for the next wake up event to wake us up. r0 can't be
+ * used here because r0 holds ARM_IDLECT1
+ */
+	mov	r2, #0
+	mcr	p15, 0, r2, c7, c0, 4		@ wait for interrupt
+/*
+ * omap1610_cpu_suspend()'s resume point.
+ *
+ * It will just start executing here, so we'll restore stuff from the
+ * stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
+ */
+	strh	r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+	strh	r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+
+	@ restore regs and return
+	ldmfd   sp!, {r0 - r12, pc}
+
+ENTRY(omap1610_cpu_suspend_sz)
+	.word	. - omap1610_cpu_suspend
+#endif /* CONFIG_ARCH_OMAP16XX */
diff --git a/arch/arm/mach-omap/time.c b/arch/arm/mach-omap/time.c
new file mode 100644
index 0000000..4205fdc
--- /dev/null
+++ b/arch/arm/mach-omap/time.c
@@ -0,0 +1,384 @@
+/*
+ * linux/arch/arm/mach-omap/time.c
+ *
+ * OMAP Timers
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Partial timer rewrite and additional VST timer support by
+ * Tony Lindgen <tony@atomide.com> and
+ * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ *
+ * MPU timer code based on the older MPU timer code for OMAP
+ * Copyright (C) 2000 RidgeRun, Inc.
+ * Author: Greg Lonnon <glonnon@ridgerun.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.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+
+#include <asm/system.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/leds.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+
+struct sys_timer omap_timer;
+
+#ifdef CONFIG_OMAP_MPU_TIMER
+
+/*
+ * ---------------------------------------------------------------------------
+ * MPU timer
+ * ---------------------------------------------------------------------------
+ */
+#define OMAP_MPU_TIMER1_BASE		(0xfffec500)
+#define OMAP_MPU_TIMER2_BASE		(0xfffec600)
+#define OMAP_MPU_TIMER3_BASE		(0xfffec700)
+#define OMAP_MPU_TIMER_BASE		OMAP_MPU_TIMER1_BASE
+#define OMAP_MPU_TIMER_OFFSET		0x100
+
+#define MPU_TIMER_FREE			(1 << 6)
+#define MPU_TIMER_CLOCK_ENABLE		(1 << 5)
+#define MPU_TIMER_AR			(1 << 1)
+#define MPU_TIMER_ST			(1 << 0)
+
+/* cycles to nsec conversions taken from arch/i386/kernel/timers/timer_tsc.c,
+ * converted to use kHz by Kevin Hilman */
+/* convert from cycles(64bits) => nanoseconds (64bits)
+ *  basic equation:
+ *		ns = cycles / (freq / ns_per_sec)
+ *		ns = cycles * (ns_per_sec / freq)
+ *		ns = cycles * (10^9 / (cpu_khz * 10^3))
+ *		ns = cycles * (10^6 / cpu_khz)
+ *
+ *	Then we use scaling math (suggested by george at mvista.com) to get:
+ *		ns = cycles * (10^6 * SC / cpu_khz / SC
+ *		ns = cycles * cyc2ns_scale / SC
+ *
+ *	And since SC is a constant power of two, we can convert the div
+ *  into a shift.
+ *			-johnstul at us.ibm.com "math is hard, lets go shopping!"
+ */
+static unsigned long cyc2ns_scale;
+#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
+
+static inline void set_cyc2ns_scale(unsigned long cpu_khz)
+{
+	cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR)/cpu_khz;
+}
+
+static inline unsigned long long cycles_2_ns(unsigned long long cyc)
+{
+	return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
+}
+
+/*
+ * MPU_TICKS_PER_SEC must be an even number, otherwise machinecycles_to_usecs
+ * will break. On P2, the timer count rate is 6.5 MHz after programming PTV
+ * with 0. This divides the 13MHz input by 2, and is undocumented.
+ */
+#ifdef CONFIG_MACH_OMAP_PERSEUS2
+/* REVISIT: This ifdef construct should be replaced by a query to clock
+ * framework to see if timer base frequency is 12.0, 13.0 or 19.2 MHz.
+ */
+#define MPU_TICKS_PER_SEC		(13000000 / 2)
+#else
+#define MPU_TICKS_PER_SEC		(12000000 / 2)
+#endif
+
+#define MPU_TIMER_TICK_PERIOD		((MPU_TICKS_PER_SEC / HZ) - 1)
+
+typedef struct {
+	u32 cntl;			/* CNTL_TIMER, R/W */
+	u32 load_tim;			/* LOAD_TIM,   W */
+	u32 read_tim;			/* READ_TIM,   R */
+} omap_mpu_timer_regs_t;
+
+#define omap_mpu_timer_base(n)						\
+((volatile omap_mpu_timer_regs_t*)IO_ADDRESS(OMAP_MPU_TIMER_BASE +	\
+				 (n)*OMAP_MPU_TIMER_OFFSET))
+
+static inline unsigned long omap_mpu_timer_read(int nr)
+{
+	volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+	return timer->read_tim;
+}
+
+static inline void omap_mpu_timer_start(int nr, unsigned long load_val)
+{
+	volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+
+	timer->cntl = MPU_TIMER_CLOCK_ENABLE;
+	udelay(1);
+	timer->load_tim = load_val;
+        udelay(1);
+	timer->cntl = (MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_AR | MPU_TIMER_ST);
+}
+
+unsigned long omap_mpu_timer_ticks_to_usecs(unsigned long nr_ticks)
+{
+	unsigned long long nsec;
+
+	nsec = cycles_2_ns((unsigned long long)nr_ticks);
+	return (unsigned long)nsec / 1000;
+}
+
+/*
+ * Last processed system timer interrupt
+ */
+static unsigned long omap_mpu_timer_last = 0;
+
+/*
+ * Returns elapsed usecs since last system timer interrupt
+ */
+static unsigned long omap_mpu_timer_gettimeoffset(void)
+{
+	unsigned long now = 0 - omap_mpu_timer_read(0);
+	unsigned long elapsed = now - omap_mpu_timer_last;
+
+	return omap_mpu_timer_ticks_to_usecs(elapsed);
+}
+
+/*
+ * Elapsed time between interrupts is calculated using timer0.
+ * Latency during the interrupt is calculated using timer1.
+ * Both timer0 and timer1 are counting at 6MHz (P2 6.5MHz).
+ */
+static irqreturn_t omap_mpu_timer_interrupt(int irq, void *dev_id,
+					struct pt_regs *regs)
+{
+	unsigned long now, latency;
+
+	write_seqlock(&xtime_lock);
+	now = 0 - omap_mpu_timer_read(0);
+	latency = MPU_TICKS_PER_SEC / HZ - omap_mpu_timer_read(1);
+	omap_mpu_timer_last = now - latency;
+	timer_tick(regs);
+	write_sequnlock(&xtime_lock);
+
+	return IRQ_HANDLED;
+}
+
+static struct irqaction omap_mpu_timer_irq = {
+	.name		= "mpu timer",
+	.flags		= SA_INTERRUPT,
+	.handler	= omap_mpu_timer_interrupt
+};
+
+static unsigned long omap_mpu_timer1_overflows;
+static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id,
+					     struct pt_regs *regs)
+{
+	omap_mpu_timer1_overflows++;
+	return IRQ_HANDLED;
+}
+
+static struct irqaction omap_mpu_timer1_irq = {
+	.name		= "mpu timer1 overflow",
+	.flags		= SA_INTERRUPT,
+	.handler	= omap_mpu_timer1_interrupt
+};
+
+static __init void omap_init_mpu_timer(void)
+{
+	set_cyc2ns_scale(MPU_TICKS_PER_SEC / 1000);
+	omap_timer.offset = omap_mpu_timer_gettimeoffset;
+	setup_irq(INT_TIMER1, &omap_mpu_timer1_irq);
+	setup_irq(INT_TIMER2, &omap_mpu_timer_irq);
+	omap_mpu_timer_start(0, 0xffffffff);
+	omap_mpu_timer_start(1, MPU_TIMER_TICK_PERIOD);
+}
+
+/*
+ * Scheduler clock - returns current time in nanosec units.
+ */
+unsigned long long sched_clock(void)
+{
+	unsigned long ticks = 0 - omap_mpu_timer_read(0);
+	unsigned long long ticks64;
+
+	ticks64 = omap_mpu_timer1_overflows;
+	ticks64 <<= 32;
+	ticks64 |= ticks;
+
+	return cycles_2_ns(ticks64);
+}
+#endif	/* CONFIG_OMAP_MPU_TIMER */
+
+#ifdef CONFIG_OMAP_32K_TIMER
+
+#ifdef CONFIG_ARCH_OMAP1510
+#error OMAP 32KHz timer does not currently work on 1510!
+#endif
+
+/*
+ * ---------------------------------------------------------------------------
+ * 32KHz OS timer
+ *
+ * This currently works only on 16xx, as 1510 does not have the continuous
+ * 32KHz synchronous timer. The 32KHz synchronous timer is used to keep track
+ * of time in addition to the 32KHz OS timer. Using only the 32KHz OS timer
+ * on 1510 would be possible, but the timer would not be as accurate as
+ * with the 32KHz synchronized timer.
+ * ---------------------------------------------------------------------------
+ */
+#define OMAP_32K_TIMER_BASE		0xfffb9000
+#define OMAP_32K_TIMER_CR		0x08
+#define OMAP_32K_TIMER_TVR		0x00
+#define OMAP_32K_TIMER_TCR		0x04
+
+#define OMAP_32K_TICKS_PER_HZ		(32768 / HZ)
+
+/*
+ * TRM says 1 / HZ = ( TVR + 1) / 32768, so TRV = (32768 / HZ) - 1
+ * so with HZ = 100, TVR = 327.68.
+ */
+#define OMAP_32K_TIMER_TICK_PERIOD	((32768 / HZ) - 1)
+#define MAX_SKIP_JIFFIES		25
+#define TIMER_32K_SYNCHRONIZED		0xfffbc410
+
+#define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate)			\
+				(((nr_jiffies) * (clock_rate)) / HZ)
+
+static inline void omap_32k_timer_write(int val, int reg)
+{
+	omap_writew(val, reg + OMAP_32K_TIMER_BASE);
+}
+
+static inline unsigned long omap_32k_timer_read(int reg)
+{
+	return omap_readl(reg + OMAP_32K_TIMER_BASE) & 0xffffff;
+}
+
+/*
+ * The 32KHz synchronized timer is an additional timer on 16xx.
+ * It is always running.
+ */
+static inline unsigned long omap_32k_sync_timer_read(void)
+{
+	return omap_readl(TIMER_32K_SYNCHRONIZED);
+}
+
+static inline void omap_32k_timer_start(unsigned long load_val)
+{
+	omap_32k_timer_write(load_val, OMAP_32K_TIMER_TVR);
+	omap_32k_timer_write(0x0f, OMAP_32K_TIMER_CR);
+}
+
+static inline void omap_32k_timer_stop(void)
+{
+	omap_32k_timer_write(0x0, OMAP_32K_TIMER_CR);
+}
+
+/*
+ * Rounds down to nearest usec
+ */
+static inline unsigned long omap_32k_ticks_to_usecs(unsigned long ticks_32k)
+{
+	return (ticks_32k * 5*5*5*5*5*5) >> 9;
+}
+
+static unsigned long omap_32k_last_tick = 0;
+
+/*
+ * Returns elapsed usecs since last 32k timer interrupt
+ */
+static unsigned long omap_32k_timer_gettimeoffset(void)
+{
+	unsigned long now = omap_32k_sync_timer_read();
+	return omap_32k_ticks_to_usecs(now - omap_32k_last_tick);
+}
+
+/*
+ * Timer interrupt for 32KHz timer. When dynamic tick is enabled, this
+ * function is also called from other interrupts to remove latency
+ * issues with dynamic tick. In the dynamic tick case, we need to lock
+ * with irqsave.
+ */
+static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id,
+					    struct pt_regs *regs)
+{
+	unsigned long flags;
+	unsigned long now;
+
+	write_seqlock_irqsave(&xtime_lock, flags);
+	now = omap_32k_sync_timer_read();
+
+	while (now - omap_32k_last_tick >= OMAP_32K_TICKS_PER_HZ) {
+		omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ;
+		timer_tick(regs);
+	}
+
+	/* Restart timer so we don't drift off due to modulo or dynamic tick.
+	 * By default we program the next timer to be continuous to avoid
+	 * latencies during high system load. During dynamic tick operation the
+	 * continuous timer can be overridden from pm_idle to be longer.
+	 */
+	omap_32k_timer_start(omap_32k_last_tick + OMAP_32K_TICKS_PER_HZ - now);
+	write_sequnlock_irqrestore(&xtime_lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+static struct irqaction omap_32k_timer_irq = {
+	.name		= "32KHz timer",
+	.flags		= SA_INTERRUPT,
+	.handler	= omap_32k_timer_interrupt
+};
+
+static __init void omap_init_32k_timer(void)
+{
+	setup_irq(INT_OS_TIMER, &omap_32k_timer_irq);
+	omap_timer.offset  = omap_32k_timer_gettimeoffset;
+	omap_32k_last_tick = omap_32k_sync_timer_read();
+	omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD);
+}
+#endif	/* CONFIG_OMAP_32K_TIMER */
+
+/*
+ * ---------------------------------------------------------------------------
+ * Timer initialization
+ * ---------------------------------------------------------------------------
+ */
+void __init omap_timer_init(void)
+{
+#if defined(CONFIG_OMAP_MPU_TIMER)
+	omap_init_mpu_timer();
+#elif defined(CONFIG_OMAP_32K_TIMER)
+	omap_init_32k_timer();
+#else
+#error No system timer selected in Kconfig!
+#endif
+}
+
+struct sys_timer omap_timer = {
+	.init		= omap_timer_init,
+	.offset		= NULL,		/* Initialized later */
+};
diff --git a/arch/arm/mach-omap/usb.c b/arch/arm/mach-omap/usb.c
new file mode 100644
index 0000000..6e805d4
--- /dev/null
+++ b/arch/arm/mach-omap/usb.c
@@ -0,0 +1,594 @@
+/*
+ * arch/arm/mach-omap/usb.c -- platform level USB initialization
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * 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
+ */
+
+#undef	DEBUG
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/usb_otg.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/mux.h>
+#include <asm/arch/usb.h>
+#include <asm/arch/board.h>
+
+/* These routines should handle the standard chip-specific modes
+ * for usb0/1/2 ports, covering basic mux and transceiver setup.
+ * Call omap_usb_init() once, from INIT_MACHINE().
+ *
+ * Some board-*.c files will need to set up additional mux options,
+ * like for suspend handling, vbus sensing, GPIOs, and the D+ pullup.
+ */
+
+/* TESTED ON:
+ *  - 1611B H2 (with usb1 mini-AB) using standard Mini-B or OTG cables
+ *  - 5912 OSK OHCI (with usb0 standard-A), standard A-to-B cables
+ *  - 5912 OSK UDC, with *nonstandard* A-to-A cable
+ *  - 1510 Innovator UDC with bundled usb0 cable
+ *  - 1510 Innovator OHCI with bundled usb1/usb2 cable
+ *  - 1510 Innovator OHCI with custom usb0 cable, feeding 5V VBUS
+ *  - 1710 custom development board using alternate pin group
+ *  - 1710 H3 (with usb1 mini-AB) using standard Mini-B or OTG cables
+ */
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef	CONFIG_ARCH_OMAP_OTG
+
+static struct otg_transceiver *xceiv;
+
+/**
+ * otg_get_transceiver - find the (single) OTG transceiver driver
+ *
+ * Returns the transceiver driver, after getting a refcount to it; or
+ * null if there is no such transceiver.  The caller is responsible for
+ * releasing that count.
+ */
+struct otg_transceiver *otg_get_transceiver(void)
+{
+	if (xceiv)
+		get_device(xceiv->dev);
+	return xceiv;
+}
+EXPORT_SYMBOL(otg_get_transceiver);
+
+int otg_set_transceiver(struct otg_transceiver *x)
+{
+	if (xceiv && x)
+		return -EBUSY;
+	xceiv = x;
+	return 0;
+}
+EXPORT_SYMBOL(otg_set_transceiver);
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+static u32 __init omap_usb0_init(unsigned nwires, unsigned is_device)
+{
+	u32	syscon1 = 0;
+
+	if (nwires == 0) {
+		if (!cpu_is_omap15xx()) {
+			/* pulldown D+/D- */
+			USB_TRANSCEIVER_CTRL_REG &= ~(3 << 1);
+		}
+		return 0;
+	}
+
+	if (is_device)
+		omap_cfg_reg(W4_USB_PUEN);
+
+	/* internal transceiver */
+	if (nwires == 2) {
+		// omap_cfg_reg(P9_USB_DP);
+		// omap_cfg_reg(R8_USB_DM);
+
+		if (cpu_is_omap15xx()) {
+			/* This works on 1510-Innovator */
+			return 0;
+		}
+
+		/* NOTES:
+		 *  - peripheral should configure VBUS detection!
+		 *  - only peripherals may use the internal D+/D- pulldowns
+		 *  - OTG support on this port not yet written
+		 */
+
+		USB_TRANSCEIVER_CTRL_REG &= ~(7 << 4);
+		if (!is_device)
+			USB_TRANSCEIVER_CTRL_REG |= (3 << 1);
+
+		return 3 << 16;
+	}
+
+	/* alternate pin config, external transceiver */
+	if (cpu_is_omap15xx()) {
+		printk(KERN_ERR "no usb0 alt pin config on 15xx\n");
+		return 0;
+	}
+
+	omap_cfg_reg(V6_USB0_TXD);
+	omap_cfg_reg(W9_USB0_TXEN);
+	omap_cfg_reg(W5_USB0_SE0);
+
+	/* NOTE:  SPEED and SUSP aren't configured here */
+
+	if (nwires != 3)
+		omap_cfg_reg(Y5_USB0_RCV);
+	if (nwires != 6)
+		USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB2_UNI_R;
+
+	switch (nwires) {
+	case 3:
+		syscon1 = 2;
+		break;
+	case 4:
+		syscon1 = 1;
+		break;
+	case 6:
+		syscon1 = 3;
+		omap_cfg_reg(AA9_USB0_VP);
+		omap_cfg_reg(R9_USB0_VM);
+		USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R;
+		break;
+	default:
+		printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
+			0, nwires);
+	}
+	return syscon1 << 16;
+}
+
+static u32 __init omap_usb1_init(unsigned nwires)
+{
+	u32	syscon1 = 0;
+
+	if (nwires != 6 && !cpu_is_omap15xx())
+		USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB1_UNI_R;
+	if (nwires == 0)
+		return 0;
+
+	/* external transceiver */
+	omap_cfg_reg(USB1_TXD);
+	omap_cfg_reg(USB1_TXEN);
+	if (cpu_is_omap15xx()) {
+		omap_cfg_reg(USB1_SEO);
+		omap_cfg_reg(USB1_SPEED);
+		// SUSP
+	} else if (cpu_is_omap1610() || cpu_is_omap5912()) {
+		omap_cfg_reg(W13_1610_USB1_SE0);
+		omap_cfg_reg(R13_1610_USB1_SPEED);
+		// SUSP
+	} else if (cpu_is_omap1710()) {
+		omap_cfg_reg(R13_1710_USB1_SE0);
+		// SUSP
+	} else {
+		pr_debug("usb unrecognized\n");
+	}
+	if (nwires != 3)
+		omap_cfg_reg(USB1_RCV);
+
+	switch (nwires) {
+	case 3:
+		syscon1 = 2;
+		break;
+	case 4:
+		syscon1 = 1;
+		break;
+	case 6:
+		syscon1 = 3;
+		omap_cfg_reg(USB1_VP);
+		omap_cfg_reg(USB1_VM);
+		if (!cpu_is_omap15xx())
+			USB_TRANSCEIVER_CTRL_REG |= CONF_USB1_UNI_R;
+		break;
+	default:
+		printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
+			1, nwires);
+	}
+	return syscon1 << 20;
+}
+
+static u32 __init omap_usb2_init(unsigned nwires, unsigned alt_pingroup)
+{
+	u32	syscon1 = 0;
+
+	/* NOTE erratum: must leave USB2_UNI_R set if usb0 in use */
+	if (alt_pingroup || nwires == 0)
+		return 0;
+	if (nwires != 6 && !cpu_is_omap15xx())
+		USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB2_UNI_R;
+
+	/* external transceiver */
+	if (cpu_is_omap15xx()) {
+		omap_cfg_reg(USB2_TXD);
+		omap_cfg_reg(USB2_TXEN);
+		omap_cfg_reg(USB2_SEO);
+		if (nwires != 3)
+			omap_cfg_reg(USB2_RCV);
+		/* there is no USB2_SPEED */
+	} else if (cpu_is_omap16xx()) {
+		omap_cfg_reg(V6_USB2_TXD);
+		omap_cfg_reg(W9_USB2_TXEN);
+		omap_cfg_reg(W5_USB2_SE0);
+		if (nwires != 3)
+			omap_cfg_reg(Y5_USB2_RCV);
+		// FIXME omap_cfg_reg(USB2_SPEED);
+	} else {
+		pr_debug("usb unrecognized\n");
+	}
+	// omap_cfg_reg(USB2_SUSP);
+
+	switch (nwires) {
+	case 3:
+		syscon1 = 2;
+		break;
+	case 4:
+		syscon1 = 1;
+		break;
+	case 6:
+		syscon1 = 3;
+		if (cpu_is_omap15xx()) {
+			omap_cfg_reg(USB2_VP);
+			omap_cfg_reg(USB2_VM);
+		} else {
+			omap_cfg_reg(AA9_USB2_VP);
+			omap_cfg_reg(R9_USB2_VM);
+			USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R;
+		}
+		break;
+	default:
+		printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
+			2, nwires);
+	}
+	return syscon1 << 24;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#if	defined(CONFIG_USB_GADGET_OMAP) || \
+	defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) || \
+	(defined(CONFIG_USB_OTG) && defined(CONFIG_ARCH_OMAP_OTG))
+static void usb_release(struct device *dev)
+{
+	/* normally not freed */
+}
+#endif
+
+#ifdef	CONFIG_USB_GADGET_OMAP
+
+static struct resource udc_resources[] = {
+	/* order is significant! */
+	{		/* registers */
+		.start		= IO_ADDRESS(UDC_BASE),
+		.end		= IO_ADDRESS(UDC_BASE + 0xff),
+		.flags		= IORESOURCE_MEM,
+	}, {		/* general IRQ */
+		.start		= IH2_BASE + 20,
+		.flags		= IORESOURCE_IRQ,
+	}, {		/* PIO IRQ */
+		.start		= IH2_BASE + 30,
+		.flags		= IORESOURCE_IRQ,
+	}, {		/* SOF IRQ */
+		.start		= IH2_BASE + 29,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static u64 udc_dmamask = ~(u32)0;
+
+static struct platform_device udc_device = {
+	.name		= "omap_udc",
+	.id		= -1,
+	.dev = {
+		.release		= usb_release,
+		.dma_mask		= &udc_dmamask,
+		.coherent_dma_mask	= 0xffffffff,
+	},
+	.num_resources	= ARRAY_SIZE(udc_resources),
+	.resource	= udc_resources,
+};
+
+#endif
+
+#if	defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+
+/* The dmamask must be set for OHCI to work */
+static u64 ohci_dmamask = ~(u32)0;
+
+static struct resource ohci_resources[] = {
+	{
+		.start	= OMAP_OHCI_BASE,
+		.end	= OMAP_OHCI_BASE + 4096,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= INT_USB_HHC_1,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device ohci_device = {
+	.name			= "ohci",
+	.id			= -1,
+	.dev = {
+		.release		= usb_release,
+		.dma_mask		= &ohci_dmamask,
+		.coherent_dma_mask	= 0xffffffff,
+	},
+	.num_resources	= ARRAY_SIZE(ohci_resources),
+	.resource		= ohci_resources,
+};
+
+#endif
+
+#if	defined(CONFIG_USB_OTG) && defined(CONFIG_ARCH_OMAP_OTG)
+
+static struct resource otg_resources[] = {
+	/* order is significant! */
+	{
+		.start		= IO_ADDRESS(OTG_BASE),
+		.end		= IO_ADDRESS(OTG_BASE + 0xff),
+		.flags		= IORESOURCE_MEM,
+	}, {
+		.start		= IH2_BASE + 8,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device otg_device = {
+	.name		= "omap_otg",
+	.id		= -1,
+	.dev = {
+		.release		= usb_release,
+	},
+	.num_resources	= ARRAY_SIZE(otg_resources),
+	.resource	= otg_resources,
+};
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#define ULPD_CLOCK_CTRL_REG	__REG16(ULPD_CLOCK_CTRL)
+#define ULPD_SOFT_REQ_REG	__REG16(ULPD_SOFT_REQ)
+
+
+// FIXME correct answer depends on hmc_mode,
+// as does any nonzero value for config->otg port number
+#ifdef	CONFIG_USB_GADGET_OMAP
+#define	is_usb0_device(config)	1
+#else
+#define	is_usb0_device(config)	0
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef	CONFIG_ARCH_OMAP_OTG
+
+void __init
+omap_otg_init(struct omap_usb_config *config)
+{
+	u32		syscon = OTG_SYSCON_1_REG & 0xffff;
+	int		status;
+	int		alt_pingroup = 0;
+
+	/* NOTE:  no bus or clock setup (yet?) */
+
+	syscon = OTG_SYSCON_1_REG & 0xffff;
+	if (!(syscon & OTG_RESET_DONE))
+		pr_debug("USB resets not complete?\n");
+
+	// OTG_IRQ_EN_REG = 0;
+
+	/* pin muxing and transceiver pinouts */
+	if (config->pins[0] > 2)	/* alt pingroup 2 */
+		alt_pingroup = 1;
+	syscon |= omap_usb0_init(config->pins[0], is_usb0_device(config));
+	syscon |= omap_usb1_init(config->pins[1]);
+	syscon |= omap_usb2_init(config->pins[2], alt_pingroup);
+	pr_debug("OTG_SYSCON_1_REG = %08x\n", syscon);
+	OTG_SYSCON_1_REG = syscon;
+
+	syscon = config->hmc_mode;
+	syscon |= USBX_SYNCHRO | (4 << 16) /* B_ASE0_BRST */;
+#ifdef	CONFIG_USB_OTG
+	if (config->otg)
+		syscon |= OTG_EN;
+#endif
+	pr_debug("USB_TRANSCEIVER_CTRL_REG = %03x\n", USB_TRANSCEIVER_CTRL_REG);
+	pr_debug("OTG_SYSCON_2_REG = %08x\n", syscon);
+	OTG_SYSCON_2_REG = syscon;
+
+	printk("USB: hmc %d", config->hmc_mode);
+	if (alt_pingroup)
+		printk(", usb2 alt %d wires", config->pins[2]);
+	else if (config->pins[0])
+		printk(", usb0 %d wires%s", config->pins[0],
+			is_usb0_device(config) ? " (dev)" : "");
+	if (config->pins[1])
+		printk(", usb1 %d wires", config->pins[1]);
+	if (!alt_pingroup && config->pins[2])
+		printk(", usb2 %d wires", config->pins[2]);
+	if (config->otg)
+		printk(", Mini-AB on usb%d", config->otg - 1);
+	printk("\n");
+
+	/* leave USB clocks/controllers off until needed */
+	ULPD_SOFT_REQ_REG &= ~SOFT_USB_CLK_REQ;
+	ULPD_CLOCK_CTRL_REG &= ~USB_MCLK_EN;
+	ULPD_CLOCK_CTRL_REG |= DIS_USB_PVCI_CLK;
+	syscon = OTG_SYSCON_1_REG;
+	syscon |= HST_IDLE_EN|DEV_IDLE_EN|OTG_IDLE_EN;
+
+#ifdef	CONFIG_USB_GADGET_OMAP
+	if (config->otg || config->register_dev) {
+		syscon &= ~DEV_IDLE_EN;
+		udc_device.dev.platform_data = config;
+		/* FIXME patch IRQ numbers for omap730 */
+		status = platform_device_register(&udc_device);
+		if (status)
+			pr_debug("can't register UDC device, %d\n", status);
+	}
+#endif
+
+#if	defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+	if (config->otg || config->register_host) {
+		syscon &= ~HST_IDLE_EN;
+		ohci_device.dev.platform_data = config;
+		if (cpu_is_omap730())
+			ohci_resources[1].start = INT_730_USB_HHC_1;
+		status = platform_device_register(&ohci_device);
+		if (status)
+			pr_debug("can't register OHCI device, %d\n", status);
+	}
+#endif
+
+#ifdef	CONFIG_USB_OTG
+	if (config->otg) {
+		syscon &= ~OTG_IDLE_EN;
+		otg_device.dev.platform_data = config;
+		if (cpu_is_omap730())
+			otg_resources[1].start = INT_730_USB_OTG;
+		status = platform_device_register(&otg_device);
+		if (status)
+			pr_debug("can't register OTG device, %d\n", status);
+	}
+#endif
+	pr_debug("OTG_SYSCON_1_REG = %08x\n", syscon);
+	OTG_SYSCON_1_REG = syscon;
+
+	status = 0;
+}
+
+#else
+static inline void omap_otg_init(struct omap_usb_config *config) {}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef	CONFIG_ARCH_OMAP1510
+
+#define ULPD_DPLL_CTRL_REG	__REG16(ULPD_DPLL_CTRL)
+#define DPLL_IOB		(1 << 13)
+#define DPLL_PLL_ENABLE		(1 << 4)
+#define DPLL_LOCK		(1 << 0)
+
+#define ULPD_APLL_CTRL_REG	__REG16(ULPD_APLL_CTRL)
+#define APLL_NDPLL_SWITCH	(1 << 0)
+
+
+static void __init omap_1510_usb_init(struct omap_usb_config *config)
+{
+	int status;
+	unsigned int val;
+
+	omap_usb0_init(config->pins[0], is_usb0_device(config));
+	omap_usb1_init(config->pins[1]);
+	omap_usb2_init(config->pins[2], 0);
+
+	val = omap_readl(MOD_CONF_CTRL_0) & ~(0x3f << 1);
+	val |= (config->hmc_mode << 1);
+	omap_writel(val, MOD_CONF_CTRL_0);
+
+	printk("USB: hmc %d", config->hmc_mode);
+	if (config->pins[0])
+		printk(", usb0 %d wires%s", config->pins[0],
+			is_usb0_device(config) ? " (dev)" : "");
+	if (config->pins[1])
+		printk(", usb1 %d wires", config->pins[1]);
+	if (config->pins[2])
+		printk(", usb2 %d wires", config->pins[2]);
+	printk("\n");
+
+	/* use DPLL for 48 MHz function clock */
+	pr_debug("APLL %04x DPLL %04x REQ %04x\n", ULPD_APLL_CTRL_REG,
+			ULPD_DPLL_CTRL_REG, ULPD_SOFT_REQ_REG);
+	ULPD_APLL_CTRL_REG &= ~APLL_NDPLL_SWITCH;
+	ULPD_DPLL_CTRL_REG |= DPLL_IOB | DPLL_PLL_ENABLE;
+	ULPD_SOFT_REQ_REG |= SOFT_UDC_REQ | SOFT_DPLL_REQ;
+	while (!(ULPD_DPLL_CTRL_REG & DPLL_LOCK))
+		cpu_relax();
+
+#ifdef	CONFIG_USB_GADGET_OMAP
+	if (config->register_dev) {
+		udc_device.dev.platform_data = config;
+		status = platform_device_register(&udc_device);
+		if (status)
+			pr_debug("can't register UDC device, %d\n", status);
+		/* udc driver gates 48MHz by D+ pullup */
+	}
+#endif
+
+#if	defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+	if (config->register_host) {
+		ohci_device.dev.platform_data = config;
+		status = platform_device_register(&ohci_device);
+		if (status)
+			pr_debug("can't register OHCI device, %d\n", status);
+		/* hcd explicitly gates 48MHz */
+	}
+#endif
+}
+
+#else
+static inline void omap_1510_usb_init(struct omap_usb_config *config) {}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+static struct omap_usb_config platform_data;
+
+static int __init
+omap_usb_init(void)
+{
+	const struct omap_usb_config *config;
+
+	config = omap_get_config(OMAP_TAG_USB, struct omap_usb_config);
+	if (config == NULL) {
+		printk(KERN_ERR "USB: No board-specific "
+				"platform config found\n");
+		return -ENODEV;
+	}
+	platform_data = *config;
+
+	if (cpu_is_omap730() || cpu_is_omap16xx())
+		omap_otg_init(&platform_data);
+	else if (cpu_is_omap15xx())
+		omap_1510_usb_init(&platform_data);
+	else {
+		printk(KERN_ERR "USB: No init for your chip yet\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+subsys_initcall(omap_usb_init);