[ARM] 2890/1: OMAP 1/4: Update omap1 specific files, take 2

Patch from Tony Lindgren

This patch syncs the mainline kernel with linux-omap tree.
The highlights of the patch are:
- Convert more drivers to register resources in board-*.c to take
  advantage of the driver model by David Brownell and Ladislav Michl
- Use set_irq_type() for GPIO interrupts instead of
  omap_set_gpio_edge_ctrl() by David Brownell
- Add minimal support for handling optional add-on boards, such as
  OSK Mistral board with LCD and keypad, by David Brownell
- Minimal support for loading functions to SRAM by Tony Lindgren
- Wake up from serial port by muxing RX lines temporarily into GPIO
  interrupts by Tony Lindgren
- 32KHz sched_clock by Tony Lindgren and Juha Yrjola

Signed-off-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig
index 7408ac9..27fc2e8 100644
--- a/arch/arm/mach-omap1/Kconfig
+++ b/arch/arm/mach-omap1/Kconfig
@@ -47,6 +47,14 @@
 	  TI OMAP 5912 OSK (OMAP Starter Kit) board support. Say Y here
           if you have such a board.
 
+config OMAP_OSK_MISTRAL
+	bool "Mistral QVGA board Support"
+	depends on MACH_OMAP_OSK
+    	help
+	  The OSK supports an optional add-on board with a Quarter-VGA
+	  touchscreen, PDA-ish buttons, a resume button, bicolor LED,
+	  and camera connector.  Say Y here if you have this board.
+
 config MACH_OMAP_PERSEUS2
 	bool "TI Perseus2"
 	depends on ARCH_OMAP1 && ARCH_OMAP730
diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile
index d386fd9..181a93d 100644
--- a/arch/arm/mach-omap1/Makefile
+++ b/arch/arm/mach-omap1/Makefile
@@ -3,7 +3,7 @@
 #
 
 # Common support
-obj-y := io.o id.o irq.o time.o serial.o
+obj-y := io.o id.o irq.o time.o serial.o devices.o
 led-y := leds.o
 
 # Specific board support
@@ -23,6 +23,7 @@
 
 # LEDs support
 led-$(CONFIG_MACH_OMAP_H2)		+= leds-h2p2-debug.o
+led-$(CONFIG_MACH_OMAP_H3)		+= leds-h2p2-debug.o
 led-$(CONFIG_MACH_OMAP_INNOVATOR)	+= leds-innovator.o
 led-$(CONFIG_MACH_OMAP_PERSEUS2)	+= leds-h2p2-debug.o
 led-$(CONFIG_MACH_OMAP_OSK)		+= leds-osk.o
diff --git a/arch/arm/mach-omap1/board-generic.c b/arch/arm/mach-omap1/board-generic.c
index 122796e..c209c71 100644
--- a/arch/arm/mach-omap1/board-generic.c
+++ b/arch/arm/mach-omap1/board-generic.c
@@ -48,19 +48,43 @@
 
 #if defined(CONFIG_ARCH_OMAP16XX)
 static struct omap_usb_config generic1610_usb_config __initdata = {
+#ifdef CONFIG_USB_OTG
+	.otg		= 1,
+#endif
 	.register_host	= 1,
 	.register_dev	= 1,
 	.hmc_mode	= 16,
 	.pins[0]	= 6,
 };
+
+static struct omap_mmc_config generic_mmc_config __initdata = {
+	.mmc [0] = {
+		.enabled 	= 0,
+		.wire4		= 0,
+		.wp_pin		= -1,
+		.power_pin	= -1,
+		.switch_pin	= -1,
+	},
+	.mmc [1] = {
+		.enabled 	= 0,
+		.wire4		= 0,
+		.wp_pin		= -1,
+		.power_pin	= -1,
+		.switch_pin	= -1,
+	},
+};
+
 #endif
 
 static struct omap_board_config_kernel generic_config[] = {
 	{ OMAP_TAG_USB,           NULL },
+	{ OMAP_TAG_MMC,           &generic_mmc_config },
 };
 
 static void __init omap_generic_init(void)
 {
+	const struct omap_uart_config *uart_conf;
+
 	/*
 	 * Make sure the serial ports are muxed on at this point.
 	 * You have to mux them off in device drivers later on
@@ -76,6 +100,18 @@
 		generic_config[0].data = &generic1610_usb_config;
 	}
 #endif
+
+	uart_conf = omap_get_config(OMAP_TAG_UART, struct omap_uart_config);
+	if (uart_conf != NULL) {
+		unsigned int enabled_ports, i;
+
+		enabled_ports = uart_conf->enabled_uarts;
+		for (i = 0; i < 3; i++) {
+			if (!(enabled_ports & (1 << i)))
+				generic_serial_ports[i] = 0;
+		}
+	}
+
 	omap_board_config = generic_config;
 	omap_board_config_size = ARRAY_SIZE(generic_config);
 	omap_serial_init(generic_serial_ports);
@@ -83,7 +119,7 @@
 
 static void __init omap_generic_map_io(void)
 {
-	omap_map_common_io()
+	omap_map_common_io();
 }
 
 MACHINE_START(OMAP_GENERIC, "Generic OMAP1510/1610/1710")
diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
index f4983ee..d46a7006 100644
--- a/arch/arm/mach-omap1/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -33,6 +33,7 @@
 #include <asm/mach/map.h>
 
 #include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
 #include <asm/arch/tc.h>
 #include <asm/arch/usb.h>
 #include <asm/arch/common.h>
@@ -80,8 +81,7 @@
 };
 
 static struct resource h2_flash_resource = {
-	.start		= OMAP_CS2B_PHYS,
-	.end		= OMAP_CS2B_PHYS + OMAP_CS2B_SIZE - 1,
+	/* This is on CS3, wherever it's mapped */
 	.flags		= IORESOURCE_MEM,
 };
 
@@ -126,10 +126,9 @@
 		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)
+static void __init h2_init_irq(void)
 {
 	omap_init_irq();
 	omap_gpio_init();
@@ -152,9 +151,13 @@
 };
 
 static struct omap_mmc_config h2_mmc_config __initdata = {
-	.mmc_blocks		= 1,
-	.mmc1_power_pin		= -1,	/* tps65010 gpio3 */
-	.mmc1_switch_pin	= OMAP_MPUIO(1),
+	.mmc [0] = {
+		.enabled 	= 1,
+		.wire4		= 1,
+		.wp_pin		= OMAP_MPUIO(3),
+		.power_pin	= -1,	/* tps65010 gpio3 */
+		.switch_pin	= OMAP_MPUIO(1),
+	},
 };
 
 static struct omap_board_config_kernel h2_config[] = {
@@ -164,6 +167,16 @@
 
 static void __init h2_init(void)
 {
+	/* NOTE: revC boards support NAND-boot, which can put NOR on CS2B
+	 * and NAND (either 16bit or 8bit) on CS3.
+	 */
+	h2_flash_resource.end = h2_flash_resource.start = omap_cs3_phys();
+	h2_flash_resource.end += SZ_32M - 1;
+
+	/* MMC:  card detect and WP */
+	// omap_cfg_reg(U19_ARMIO1);		/* CD */
+	omap_cfg_reg(BALLOUT_V8_ARMIO3);	/* WP */
+
 	platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices));
 	omap_board_config = h2_config;
 	omap_board_config_size = ARRAY_SIZE(h2_config);
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index 7cd419d..2798613 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -82,8 +82,7 @@
 };
 
 static struct resource h3_flash_resource = {
-	.start		= OMAP_CS2B_PHYS,
-	.end		= OMAP_CS2B_PHYS + OMAP_CS2B_SIZE - 1,
+	/* This is on CS3, wherever it's mapped */
 	.flags		= IORESOURCE_MEM,
 };
 
@@ -161,13 +160,26 @@
 	.pins[1]	= 3,
 };
 
+static struct omap_mmc_config h3_mmc_config __initdata = {
+	.mmc[0] = {
+		.enabled 	= 1,
+		.power_pin	= -1,   /* tps65010 GPIO4 */
+		.switch_pin	= OMAP_MPUIO(1),
+	},
+};
+
 static struct omap_board_config_kernel h3_config[] = {
 	{ OMAP_TAG_USB,	 &h3_usb_config },
+	{ OMAP_TAG_MMC,  &h3_mmc_config },
 };
 
 static void __init h3_init(void)
 {
+	h3_flash_resource.end = h3_flash_resource.start = omap_cs3_phys();
+	h3_flash_resource.end += OMAP_CS3_SIZE - 1;
 	(void) platform_add_devices(devices, ARRAY_SIZE(devices));
+	omap_board_config = h3_config;
+	omap_board_config_size = ARRAY_SIZE(h3_config);
 }
 
 static void __init h3_init_smc91x(void)
@@ -177,7 +189,6 @@
 		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)
diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c
index 91de60a..df0312b 100644
--- a/arch/arm/mach-omap1/board-innovator.c
+++ b/arch/arm/mach-omap1/board-innovator.c
@@ -29,6 +29,7 @@
 #include <asm/mach/flash.h>
 #include <asm/mach/map.h>
 
+#include <asm/arch/mux.h>
 #include <asm/arch/fpga.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/tc.h>
@@ -173,7 +174,6 @@
 			printk("Error requesting gpio 0 for smc91x irq\n");
 			return;
 		}
-		omap_set_gpio_edge_ctrl(0, OMAP_GPIO_RISING_EDGE);
 	}
 }
 
@@ -220,8 +220,19 @@
 };
 #endif
 
+static struct omap_mmc_config innovator_mmc_config __initdata = {
+	.mmc [0] = {
+		.enabled 	= 1,
+		.wire4		= 1,
+		.wp_pin		= OMAP_MPUIO(3),
+		.power_pin	= -1,	/* FPGA F3 UIO42 */
+		.switch_pin	= -1,	/* FPGA F4 UIO43 */
+	},
+};
+
 static struct omap_board_config_kernel innovator_config[] = {
 	{ OMAP_TAG_USB,         NULL },
+	{ OMAP_TAG_MMC,		&innovator_mmc_config },
 };
 
 static void __init innovator_init(void)
diff --git a/arch/arm/mach-omap1/board-netstar.c b/arch/arm/mach-omap1/board-netstar.c
index 6750b20..d904e64 100644
--- a/arch/arm/mach-omap1/board-netstar.c
+++ b/arch/arm/mach-omap1/board-netstar.c
@@ -75,16 +75,15 @@
 	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);
+	set_irq_type(OMAP_GPIO_IRQ(12), IRQT_FALLING);
+	set_irq_type(OMAP_GPIO_IRQ(13), IRQT_FALLING);
+	set_irq_type(OMAP_GPIO_IRQ(14), IRQT_FALLING);
+	set_irq_type(OMAP_GPIO_IRQ(15), IRQT_FALLING);
 
 	platform_add_devices(netstar_devices, ARRAY_SIZE(netstar_devices));
 
diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c
index 6844e53..21103df 100644
--- a/arch/arm/mach-omap1/board-osk.c
+++ b/arch/arm/mach-omap1/board-osk.c
@@ -29,11 +29,16 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/interrupt.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/map.h>
+#include <asm/mach/flash.h>
 
 #include <asm/arch/gpio.h>
 #include <asm/arch/usb.h>
@@ -41,12 +46,56 @@
 #include <asm/arch/tc.h>
 #include <asm/arch/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 mtd_partition osk_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,
+	}, {
+	      .name		= "kernel",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= SZ_2M,
+	      .mask_flags	= 0
+	}, {
+	      .name		= "filesystem",
+	      .offset		= MTDPART_OFS_APPEND,
+	      .size		= MTDPART_SIZ_FULL,
+	      .mask_flags	= 0
+	}
 };
 
-static int __initdata osk_serial_ports[OMAP_MAX_NR_PORTS] = {1, 0, 0};
+static struct flash_platform_data osk_flash_data = {
+	.map_name	= "cfi_probe",
+	.width		= 2,
+	.parts		= osk_partitions,
+	.nr_parts	= ARRAY_SIZE(osk_partitions),
+};
+
+static struct resource osk_flash_resource = {
+	/* this is on CS3, wherever it's mapped */
+	.flags		= IORESOURCE_MEM,
+};
+
+static struct platform_device osk5912_flash_device = {
+	.name		= "omapflash",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &osk_flash_data,
+	},
+	.num_resources	= 1,
+	.resource	= &osk_flash_resource,
+};
 
 static struct resource osk5912_smc91x_resources[] = {
 	[0] = {
@@ -86,9 +135,16 @@
 	.resource	= osk5912_cf_resources,
 };
 
+static struct platform_device osk5912_mcbsp1_device = {
+	.name		= "omap_mcbsp",
+	.id		= 1,
+};
+
 static struct platform_device *osk5912_devices[] __initdata = {
+	&osk5912_flash_device,
 	&osk5912_smc91x_device,
 	&osk5912_cf_device,
+	&osk5912_mcbsp1_device,
 };
 
 static void __init osk_init_smc91x(void)
@@ -97,7 +153,6 @@
 		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;
@@ -110,11 +165,11 @@
 		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);
+	/* the CF I/O IRQ is really active-low */
+	set_irq_type(OMAP_GPIO_IRQ(62), IRQT_FALLING);
 }
 
-void osk_init_irq(void)
+static void __init osk_init_irq(void)
 {
 	omap_init_irq();
 	omap_gpio_init();
@@ -142,18 +197,69 @@
 	{ OMAP_TAG_USB,           &osk_usb_config },
 };
 
+#ifdef	CONFIG_OMAP_OSK_MISTRAL
+
+#ifdef	CONFIG_PM
+static irqreturn_t
+osk_mistral_wake_interrupt(int irq, void *ignored, struct pt_regs *regs)
+{
+	return IRQ_HANDLED;
+}
+#endif
+
+static void __init osk_mistral_init(void)
+{
+	/* FIXME here's where to feed in framebuffer, touchpad, and
+	 * keyboard setup ...  not in the drivers for those devices!
+	 *
+	 * NOTE:  we could actually tell if there's a Mistral board
+	 * attached, e.g. by trying to read something from the ads7846.
+	 * But this is too early for that...
+	 */
+
+	/* the sideways button (SW1) is for use as a "wakeup" button */
+	omap_cfg_reg(N15_1610_MPUIO2);
+	if (omap_request_gpio(OMAP_MPUIO(2)) == 0) {
+		int ret = 0;
+		omap_set_gpio_direction(OMAP_MPUIO(2), 1);
+		set_irq_type(OMAP_GPIO_IRQ(OMAP_MPUIO(2)), IRQT_RISING);
+#ifdef	CONFIG_PM
+		/* share the IRQ in case someone wants to use the
+		 * button for more than wakeup from system sleep.
+		 */
+		ret = request_irq(OMAP_GPIO_IRQ(OMAP_MPUIO(2)),
+				&osk_mistral_wake_interrupt,
+				SA_SHIRQ, "mistral_wakeup",
+				&osk_mistral_wake_interrupt);
+		if (ret != 0) {
+			omap_free_gpio(OMAP_MPUIO(2));
+			printk(KERN_ERR "OSK+Mistral: no wakeup irq, %d?\n",
+				ret);
+		} else
+			enable_irq_wake(OMAP_GPIO_IRQ(OMAP_MPUIO(2)));
+#endif
+	} else
+		printk(KERN_ERR "OSK+Mistral: wakeup button is awol\n");
+}
+#else
+static void __init osk_mistral_init(void) { }
+#endif
+
 static void __init osk_init(void)
 {
+	osk_flash_resource.end = osk_flash_resource.start = omap_cs3_phys();
+	osk_flash_resource.end += SZ_32M - 1;
 	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);
+
+	osk_mistral_init();
 }
 
 static void __init osk_map_io(void)
 {
 	omap_map_common_io();
-	iotable_init(osk5912_io_desc, ARRAY_SIZE(osk5912_io_desc));
 	omap_serial_init(osk_serial_ports);
 }
 
diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c
index 2133173..107c68c 100644
--- a/arch/arm/mach-omap1/board-perseus2.c
+++ b/arch/arm/mach-omap1/board-perseus2.c
@@ -24,6 +24,7 @@
 #include <asm/mach/flash.h>
 #include <asm/mach/map.h>
 
+#include <asm/arch/tc.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/mux.h>
 #include <asm/arch/fpga.h>
@@ -83,8 +84,8 @@
 };
 
 static struct resource p2_flash_resource = {
-	.start		= OMAP_FLASH_0_START,
-	.end		= OMAP_FLASH_0_START + OMAP_FLASH_0_SIZE - 1,
+	.start		= OMAP_CS0_PHYS,
+	.end		= OMAP_CS0_PHYS + SZ_32M - 1,
 	.flags		= IORESOURCE_MEM,
 };
 
diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c
index e4228198..209d79e 100644
--- a/arch/arm/mach-omap1/board-voiceblue.c
+++ b/arch/arm/mach-omap1/board-voiceblue.c
@@ -25,13 +25,14 @@
 #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/mux.h>
-#include <asm/arch/usb.h>
 #include <asm/arch/common.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/tc.h>
+#include <asm/arch/usb.h>
 
 extern void omap_init_time(void);
 extern int omap_gpio_init(void);
@@ -86,6 +87,27 @@
 }
 arch_initcall(ext_uart_init);
 
+static struct flash_platform_data voiceblue_flash_data = {
+	.map_name	= "cfi_probe",
+	.width		= 2,
+};
+
+static struct resource voiceblue_flash_resource = {
+	.start	= OMAP_CS0_PHYS,
+	.end	= OMAP_CS0_PHYS + SZ_32M - 1,
+	.flags	= IORESOURCE_MEM,
+};
+
+static struct platform_device voiceblue_flash_device = {
+	.name		= "omapflash",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &voiceblue_flash_data,
+	},
+	.num_resources	= 1,
+	.resource	= &voiceblue_flash_resource,
+};
+
 static struct resource voiceblue_smc91x_resources[] = {
 	[0] = {
 		.start	= OMAP_CS2_PHYS + 0x300,
@@ -107,6 +129,7 @@
 };
 
 static struct platform_device *voiceblue_devices[] __initdata = {
+	&voiceblue_flash_device,
 	&voiceblue_smc91x_device,
 };
 
@@ -119,8 +142,17 @@
 	.pins[2]	= 6,
 };
 
+static struct omap_mmc_config voiceblue_mmc_config __initdata = {
+	.mmc[0] = {
+		.enabled	= 1,
+		.power_pin	= 2,
+		.switch_pin	= -1,
+	},
+};
+
 static struct omap_board_config_kernel voiceblue_config[] = {
 	{ OMAP_TAG_USB, &voiceblue_usb_config },
+	{ OMAP_TAG_MMC, &voiceblue_mmc_config },
 };
 
 static void __init voiceblue_init_irq(void)
@@ -131,9 +163,6 @@
 
 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 */
@@ -145,7 +174,6 @@
 	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);
@@ -155,14 +183,19 @@
 	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);
+	set_irq_type(OMAP_GPIO_IRQ(12), IRQT_RISING);
+	set_irq_type(OMAP_GPIO_IRQ(13), IRQT_RISING);
+	set_irq_type(OMAP_GPIO_IRQ(14), IRQT_RISING);
+	set_irq_type(OMAP_GPIO_IRQ(15), IRQT_RISING);
 
 	platform_add_devices(voiceblue_devices, ARRAY_SIZE(voiceblue_devices));
 	omap_board_config = voiceblue_config;
 	omap_board_config_size = ARRAY_SIZE(voiceblue_config);
+
+	/* There is a good chance board is going up, so enable power LED
+	 * (it is connected through invertor) */
+	omap_writeb(0x00, OMAP_LPG1_LCR);
+	omap_writeb(0x00, OMAP_LPG1_PMR);	/* Disable clock */
 }
 
 static int __initdata omap_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
@@ -184,9 +217,9 @@
 	if (test_and_set_bit(MACHINE_PANICED, &machine_state))
 		return NOTIFY_DONE;
 
-	/* Flash Power LED
-	 * (TODO: Enable clock right way (enabled in bootloader already)) */
+	/* Flash power LED */
 	omap_writeb(0x78, OMAP_LPG1_LCR);
+	omap_writeb(0x01, OMAP_LPG1_PMR);	/* Enable clock */
 
 	return NOTIFY_DONE;
 }
@@ -195,15 +228,14 @@
 	.notifier_call	= panic_event,
 };
 
-static int __init setup_notifier(void)
+static int __init voiceblue_setup(void)
 {
 	/* Setup panic notifier */
 	notifier_chain_register(&panic_notifier_list, &panic_block);
 
 	return 0;
 }
-
-postcore_initcall(setup_notifier);
+postcore_initcall(voiceblue_setup);
 
 static int wdt_gpio_state;
 
diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c
new file mode 100644
index 0000000..e8b3981
--- /dev/null
+++ b/arch/arm/mach-omap1/devices.c
@@ -0,0 +1,351 @@
+/*
+ * linux/arch/arm/mach-omap1/devices.c
+ *
+ * OMAP1 platform device setup/initialization
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/tc.h>
+#include <asm/arch/board.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/gpio.h>
+
+
+static void omap_nop_release(struct device *dev)
+{
+        /* Nothing */
+}
+
+/*-------------------------------------------------------------------------*/
+
+#if	defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
+
+#define	OMAP_I2C_BASE		0xfffb3800
+
+static struct resource i2c_resources[] = {
+	{
+		.start		= OMAP_I2C_BASE,
+		.end		= OMAP_I2C_BASE + 0x3f,
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= INT_I2C,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+/* DMA not used; works around erratum writing to non-empty i2c fifo */
+
+static struct platform_device omap_i2c_device = {
+        .name           = "i2c_omap",
+        .id             = -1,
+        .dev = {
+                .release        = omap_nop_release,
+        },
+	.num_resources	= ARRAY_SIZE(i2c_resources),
+	.resource	= i2c_resources,
+};
+
+static void omap_init_i2c(void)
+{
+	/* FIXME define and use a boot tag, in case of boards that
+	 * either don't wire up I2C, or chips that mux it differently...
+	 * it can include clocking and address info, maybe more.
+	 */
+	omap_cfg_reg(I2C_SCL);
+	omap_cfg_reg(I2C_SDA);
+
+	(void) platform_device_register(&omap_i2c_device);
+}
+#else
+static inline void omap_init_i2c(void) {}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#if	defined(CONFIG_OMAP1610_IR) || defined(CONFIG_OMAP161O_IR_MODULE)
+
+static u64 irda_dmamask = 0xffffffff;
+
+static struct platform_device omap1610ir_device = {
+	.name = "omap1610-ir",
+	.id = -1,
+	.dev = {
+		.release	= omap_nop_release,
+		.dma_mask	= &irda_dmamask,
+	},
+};
+
+static void omap_init_irda(void)
+{
+	/* FIXME define and use a boot tag, members something like:
+	 *  u8		uart;		// uart1, or uart3
+	 * ... but driver only handles uart3 for now
+	 *  s16		fir_sel;	// gpio for SIR vs FIR
+	 * ... may prefer a callback for SIR/MIR/FIR mode select;
+	 * while h2 uses a GPIO, H3 uses a gpio expander
+	 */
+	if (machine_is_omap_h2()
+			|| machine_is_omap_h3())
+		(void) platform_device_register(&omap1610ir_device);
+}
+#else
+static inline void omap_init_irda(void) {}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#if	defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
+
+#define	OMAP_MMC1_BASE		0xfffb7800
+#define	OMAP_MMC2_BASE		0xfffb7c00	/* omap16xx only */
+
+static struct omap_mmc_conf mmc1_conf;
+
+static u64 mmc1_dmamask = 0xffffffff;
+
+static struct resource mmc1_resources[] = {
+	{
+		.start		= IO_ADDRESS(OMAP_MMC1_BASE),
+		.end		= IO_ADDRESS(OMAP_MMC1_BASE) + 0x7f,
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= INT_MMC,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device mmc_omap_device1 = {
+	.name		= "mmci-omap",
+	.id		= 1,
+	.dev = {
+		.release	= omap_nop_release,
+		.dma_mask	= &mmc1_dmamask,
+		.platform_data	= &mmc1_conf,
+	},
+	.num_resources	= ARRAY_SIZE(mmc1_resources),
+	.resource	= mmc1_resources,
+};
+
+#ifdef	CONFIG_ARCH_OMAP16XX
+
+static struct omap_mmc_conf mmc2_conf;
+
+static u64 mmc2_dmamask = 0xffffffff;
+
+static struct resource mmc2_resources[] = {
+	{
+		.start		= IO_ADDRESS(OMAP_MMC2_BASE),
+		.end		= IO_ADDRESS(OMAP_MMC2_BASE) + 0x7f,
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= INT_1610_MMC2,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device mmc_omap_device2 = {
+	.name		= "mmci-omap",
+	.id		= 2,
+	.dev = {
+		.release	= omap_nop_release,
+		.dma_mask	= &mmc2_dmamask,
+		.platform_data	= &mmc2_conf,
+	},
+	.num_resources	= ARRAY_SIZE(mmc2_resources),
+	.resource	= mmc2_resources,
+};
+#endif
+
+static void __init omap_init_mmc(void)
+{
+	const struct omap_mmc_config	*mmc_conf;
+	const struct omap_mmc_conf	*mmc;
+
+	/* NOTE:  assumes MMC was never (wrongly) enabled */
+	mmc_conf = omap_get_config(OMAP_TAG_MMC, struct omap_mmc_config);
+	if (!mmc_conf)
+		return;
+
+	/* block 1 is always available and has just one pinout option */
+	mmc = &mmc_conf->mmc[0];
+	if (mmc->enabled) {
+		omap_cfg_reg(MMC_CMD);
+		omap_cfg_reg(MMC_CLK);
+		omap_cfg_reg(MMC_DAT0);
+		if (cpu_is_omap1710()) {
+	              omap_cfg_reg(M15_1710_MMC_CLKI);
+	              omap_cfg_reg(P19_1710_MMC_CMDDIR);
+	              omap_cfg_reg(P20_1710_MMC_DATDIR0);
+	        }
+		if (mmc->wire4) {
+			omap_cfg_reg(MMC_DAT1);
+			/* NOTE:  DAT2 can be on W10 (here) or M15 */
+			if (!mmc->nomux)
+				omap_cfg_reg(MMC_DAT2);
+			omap_cfg_reg(MMC_DAT3);
+		}
+		mmc1_conf = *mmc;
+		(void) platform_device_register(&mmc_omap_device1);
+	}
+
+#ifdef	CONFIG_ARCH_OMAP16XX
+	/* block 2 is on newer chips, and has many pinout options */
+	mmc = &mmc_conf->mmc[1];
+	if (mmc->enabled) {
+		if (!mmc->nomux) {
+			omap_cfg_reg(Y8_1610_MMC2_CMD);
+			omap_cfg_reg(Y10_1610_MMC2_CLK);
+			omap_cfg_reg(R18_1610_MMC2_CLKIN);
+			omap_cfg_reg(W8_1610_MMC2_DAT0);
+			if (mmc->wire4) {
+				omap_cfg_reg(V8_1610_MMC2_DAT1);
+				omap_cfg_reg(W15_1610_MMC2_DAT2);
+				omap_cfg_reg(R10_1610_MMC2_DAT3);
+			}
+
+			/* These are needed for the level shifter */
+			omap_cfg_reg(V9_1610_MMC2_CMDDIR);
+			omap_cfg_reg(V5_1610_MMC2_DATDIR0);
+			omap_cfg_reg(W19_1610_MMC2_DATDIR1);
+		}
+
+		/* Feedback clock must be set on OMAP-1710 MMC2 */
+		if (cpu_is_omap1710())
+			omap_writel(omap_readl(MOD_CONF_CTRL_1) | (1 << 24),
+				     MOD_CONF_CTRL_1);
+		mmc2_conf = *mmc;
+		(void) platform_device_register(&mmc_omap_device2);
+	}
+#endif
+	return;
+}
+#else
+static inline void omap_init_mmc(void) {}
+#endif
+
+#if	defined(CONFIG_OMAP_RTC) || defined(CONFIG_OMAP_RTC)
+
+#define	OMAP_RTC_BASE		0xfffb4800
+
+static struct resource rtc_resources[] = {
+	{
+		.start		= OMAP_RTC_BASE,
+		.end		= OMAP_RTC_BASE + 0x5f,
+		.flags		= IORESOURCE_MEM,
+	},
+	{
+		.start		= INT_RTC_TIMER,
+		.flags		= IORESOURCE_IRQ,
+	},
+	{
+		.start		= INT_RTC_ALARM,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device omap_rtc_device = {
+	.name           = "omap_rtc",
+	.id             = -1,
+	.dev = {
+		.release        = omap_nop_release,
+	},
+	.num_resources	= ARRAY_SIZE(rtc_resources),
+	.resource	= rtc_resources,
+};
+
+static void omap_init_rtc(void)
+{
+	(void) platform_device_register(&omap_rtc_device);
+}
+#else
+static inline void omap_init_rtc(void) {}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#if	defined(CONFIG_OMAP16XX_WATCHDOG) || defined(CONFIG_OMAP16XX_WATCHDOG_MODULE)
+
+#define	OMAP_WDT_BASE		0xfffeb000
+
+static struct resource wdt_resources[] = {
+	{
+		.start		= OMAP_WDT_BASE,
+		.end		= OMAP_WDT_BASE + 0x4f,
+		.flags		= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device omap_wdt_device = {
+	.name	   = "omap1610_wdt",
+	.id	     = -1,
+	.dev = {
+		.release	= omap_nop_release,
+	},
+	.num_resources	= ARRAY_SIZE(wdt_resources),
+	.resource	= wdt_resources,
+};
+
+static void omap_init_wdt(void)
+{
+	(void) platform_device_register(&omap_wdt_device);
+}
+#else
+static inline void omap_init_wdt(void) {}
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * This gets called after board-specific INIT_MACHINE, and initializes most
+ * on-chip peripherals accessible on this board (except for few like USB):
+ *
+ *  (a) Does any "standard config" pin muxing needed.  Board-specific
+ *	code will have muxed GPIO pins and done "nonstandard" setup;
+ *	that code could live in the boot loader.
+ *  (b) Populating board-specific platform_data with the data drivers
+ *	rely on to handle wiring variations.
+ *  (c) Creating platform devices as meaningful on this board and
+ *	with this kernel configuration.
+ *
+ * Claiming GPIOs, and setting their direction and initial values, is the
+ * responsibility of the device drivers.  So is responding to probe().
+ *
+ * Board-specific knowlege like creating devices or pin setup is to be
+ * kept out of drivers as much as possible.  In particular, pin setup
+ * may be handled by the boot loader, and drivers should expect it will
+ * normally have been done by the time they're probed.
+ */
+static int __init omap_init_devices(void)
+{
+	/* please keep these calls, and their implementations above,
+	 * in alphabetical order so they're easier to sort through.
+	 */
+	omap_init_i2c();
+	omap_init_irda();
+	omap_init_mmc();
+	omap_init_rtc();
+	omap_init_wdt();
+
+	return 0;
+}
+arch_initcall(omap_init_devices);
+
diff --git a/arch/arm/mach-omap1/fpga.c b/arch/arm/mach-omap1/fpga.c
index c12a783..aca2a12 100644
--- a/arch/arm/mach-omap1/fpga.c
+++ b/arch/arm/mach-omap1/fpga.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-omap/fpga.c
+ * linux/arch/arm/mach-omap1/fpga.c
  *
  * Interrupt handler for OMAP-1510 Innovator FPGA
  *
@@ -181,7 +181,7 @@
 	 */
 	omap_request_gpio(13);
 	omap_set_gpio_direction(13, 1);
-	omap_set_gpio_edge_ctrl(13, OMAP_GPIO_RISING_EDGE);
+	set_irq_type(OMAP_GPIO_IRQ(13), IRQT_RISING);
 	set_irq_chained_handler(OMAP1510_INT_FPGA, innovator_fpga_IRQ_demux);
 }
 
diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c
index 207df0f..eb8261d 100644
--- a/arch/arm/mach-omap1/io.c
+++ b/arch/arm/mach-omap1/io.c
@@ -19,6 +19,7 @@
 
 extern int clk_init(void);
 extern void omap_check_revision(void);
+extern void omap_sram_init(void);
 
 /*
  * The machine specific code may provide the extra mapping besides the
@@ -32,7 +33,6 @@
 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
 
@@ -40,27 +40,13 @@
 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 = {
+static struct map_desc omap16xx_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
 
@@ -86,14 +72,13 @@
 	}
 #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));
+	if (cpu_is_omap16xx()) {
+		iotable_init(omap16xx_io_desc, ARRAY_SIZE(omap16xx_io_desc));
 	}
 #endif
 
+	omap_sram_init();
+
 	/* REVISIT: Refer to OMAP5910 Errata, Advisory SYS_1: "Timeout Abort
 	 * on a Posted Write in the TIPB Bridge".
 	 */
@@ -108,8 +93,9 @@
 /*
  * This should only get called from board specific init
  */
-void omap_map_common_io(void)
+void __init omap_map_common_io(void)
 {
 	if (!initialized)
 		_omap_map_io();
 }
+
diff --git a/arch/arm/mach-omap1/irq.c b/arch/arm/mach-omap1/irq.c
index afd5d67..192ce60 100644
--- a/arch/arm/mach-omap1/irq.c
+++ b/arch/arm/mach-omap1/irq.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-omap/irq.c
+ * linux/arch/arm/mach-omap1/irq.c
  *
  * Interrupt handler for all OMAP boards
  *
diff --git a/arch/arm/mach-omap1/leds-h2p2-debug.c b/arch/arm/mach-omap1/leds-h2p2-debug.c
index ec0d828..be283cd 100644
--- a/arch/arm/mach-omap1/leds-h2p2-debug.c
+++ b/arch/arm/mach-omap1/leds-h2p2-debug.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-omap/leds-h2p2-debug.c
+ * linux/arch/arm/mach-omap1/leds-h2p2-debug.c
  *
  * Copyright 2003 by Texas Instruments Incorporated
  *
@@ -13,6 +13,7 @@
 #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>
diff --git a/arch/arm/mach-omap1/leds-innovator.c b/arch/arm/mach-omap1/leds-innovator.c
index 8043b7d..c8ffd1d 100644
--- a/arch/arm/mach-omap1/leds-innovator.c
+++ b/arch/arm/mach-omap1/leds-innovator.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-omap/leds-innovator.c
+ * linux/arch/arm/mach-omap1/leds-innovator.c
  */
 #include <linux/config.h>
 #include <linux/init.h>
diff --git a/arch/arm/mach-omap1/leds-osk.c b/arch/arm/mach-omap1/leds-osk.c
index 4a0e8b9..2c8bda8 100644
--- a/arch/arm/mach-omap1/leds-osk.c
+++ b/arch/arm/mach-omap1/leds-osk.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-omap/leds-osk.c
+ * linux/arch/arm/mach-omap1/leds-osk.c
  *
  * LED driver for OSK, and optionally Mistral QVGA, boards
  */
@@ -64,7 +64,7 @@
 
 static DECLARE_WORK(work, tps_work, NULL);
 
-#ifdef	CONFIG_FB_OMAP
+#ifdef	CONFIG_OMAP_OSK_MISTRAL
 
 /* For now, all system indicators require the Mistral board, since that
  * LED can be manipulated without a task context.  This LED is either red,
@@ -127,7 +127,7 @@
 		hw_led_state = 0;
 		break;
 
-#ifdef	CONFIG_FB_OMAP
+#ifdef	CONFIG_OMAP_OSK_MISTRAL
 
 	case led_timer:
 		hw_led_state ^= TIMER_LED;
@@ -144,7 +144,7 @@
 		mistral_setled();
 		break;
 
-#endif	/* CONFIG_FB_OMAP */
+#endif	/* CONFIG_OMAP_OSK_MISTRAL */
 
 	/* "green" == tps LED1 (leftmost, normally power-good)
 	 * works only with DC adapter, not on battery power!
diff --git a/arch/arm/mach-omap1/leds.c b/arch/arm/mach-omap1/leds.c
index 8ab21fe..5c6b1bb 100644
--- a/arch/arm/mach-omap1/leds.c
+++ b/arch/arm/mach-omap1/leds.c
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-omap/leds.c
+ * linux/arch/arm/mach-omap1/leds.c
  *
  * OMAP LEDs dispatcher
  */
@@ -20,7 +20,9 @@
 	if (machine_is_omap_innovator())
 		leds_event = innovator_leds_event;
 
-	else if (machine_is_omap_h2() || machine_is_omap_perseus2())
+	else if (machine_is_omap_h2()
+			|| machine_is_omap_h3()
+			|| machine_is_omap_perseus2())
 		leds_event = h2p2_dbg_leds_event;
 
 	else if (machine_is_omap_osk())
@@ -30,8 +32,12 @@
 		return -1;
 
 	if (machine_is_omap_h2()
+			|| machine_is_omap_h3()
 			|| machine_is_omap_perseus2()
-			|| machine_is_omap_osk()) {
+#ifdef	CONFIG_OMAP_OSK_MISTRAL
+			|| machine_is_omap_osk()
+#endif
+			) {
 
 		/* LED1/LED2 pins can be used as GPIO (as done here), or by
 		 * the LPG (works even in deep sleep!), to drive a bicolor
diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c
index 214e5d1..e702e0c 100644
--- a/arch/arm/mach-omap1/serial.c
+++ b/arch/arm/mach-omap1/serial.c
@@ -24,7 +24,11 @@
 
 #include <asm/arch/board.h>
 #include <asm/arch/mux.h>
+#include <asm/arch/gpio.h>
 #include <asm/arch/fpga.h>
+#ifdef CONFIG_PM
+#include <asm/arch/pm.h>
+#endif
 
 static struct clk * uart1_ck = NULL;
 static struct clk * uart2_ck = NULL;
@@ -193,6 +197,86 @@
 	}
 }
 
+#ifdef CONFIG_OMAP_SERIAL_WAKE
+
+static irqreturn_t omap_serial_wake_interrupt(int irq, void *dev_id,
+					      struct pt_regs *regs)
+{
+	/* Need to do something with serial port right after wake-up? */
+	return IRQ_HANDLED;
+}
+
+/*
+ * Reroutes serial RX lines to GPIO lines for the duration of
+ * sleep to allow waking up the device from serial port even
+ * in deep sleep.
+ */
+void omap_serial_wake_trigger(int enable)
+{
+	if (!cpu_is_omap16xx())
+		return;
+
+	if (uart1_ck != NULL) {
+		if (enable)
+			omap_cfg_reg(V14_16XX_GPIO37);
+		else
+			omap_cfg_reg(V14_16XX_UART1_RX);
+	}
+	if (uart2_ck != NULL) {
+		if (enable)
+			omap_cfg_reg(R9_16XX_GPIO18);
+		else
+			omap_cfg_reg(R9_16XX_UART2_RX);
+	}
+	if (uart3_ck != NULL) {
+		if (enable)
+			omap_cfg_reg(L14_16XX_GPIO49);
+		else
+			omap_cfg_reg(L14_16XX_UART3_RX);
+	}
+}
+
+static void __init omap_serial_set_port_wakeup(int gpio_nr)
+{
+	int ret;
+
+	ret = omap_request_gpio(gpio_nr);
+	if (ret < 0) {
+		printk(KERN_ERR "Could not request UART wake GPIO: %i\n",
+		       gpio_nr);
+		return;
+	}
+	omap_set_gpio_direction(gpio_nr, 1);
+	set_irq_type(OMAP_GPIO_IRQ(gpio_nr), IRQT_RISING);
+	ret = request_irq(OMAP_GPIO_IRQ(gpio_nr), &omap_serial_wake_interrupt,
+			  0, "serial wakeup", NULL);
+	if (ret) {
+		omap_free_gpio(gpio_nr);
+		printk(KERN_ERR "No interrupt for UART wake GPIO: %i\n",
+		       gpio_nr);
+		return;
+	}
+	enable_irq_wake(OMAP_GPIO_IRQ(gpio_nr));
+}
+
+static int __init omap_serial_wakeup_init(void)
+{
+	if (!cpu_is_omap16xx())
+		return 0;
+
+	if (uart1_ck != NULL)
+		omap_serial_set_port_wakeup(37);
+	if (uart2_ck != NULL)
+		omap_serial_set_port_wakeup(18);
+	if (uart3_ck != NULL)
+		omap_serial_set_port_wakeup(49);
+
+	return 0;
+}
+late_initcall(omap_serial_wakeup_init);
+
+#endif	/* CONFIG_OMAP_SERIAL_WAKE */
+
 static int __init omap_init(void)
 {
 	return platform_device_register(&serial_device);
diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c
index d540539..191a9b1 100644
--- a/arch/arm/mach-omap1/time.c
+++ b/arch/arm/mach-omap1/time.c
@@ -247,13 +247,6 @@
 #define OMAP_32K_TIMER_TCR		0x04
 
 #define OMAP_32K_TICKS_PER_HZ		(32768 / HZ)
-#if (32768 % HZ) != 0
-/* We cannot ignore modulo.
- * Potential error can be as high as several percent.
- */
-#define OMAP_32K_TICK_MODULO		(32768 % HZ)
-static unsigned modulo_count = 0; /* Counts 1/HZ units */
-#endif
 
 /*
  * TRM says 1 / HZ = ( TVR + 1) / 32768, so TRV = (32768 / HZ) - 1
@@ -296,13 +289,22 @@
 }
 
 /*
- * Rounds down to nearest usec
+ * Rounds down to nearest usec. Note that this will overflow for larger values.
  */
 static inline unsigned long omap_32k_ticks_to_usecs(unsigned long ticks_32k)
 {
 	return (ticks_32k * 5*5*5*5*5*5) >> 9;
 }
 
+/*
+ * Rounds down to nearest nsec.
+ */
+static inline unsigned long long
+omap_32k_ticks_to_nsecs(unsigned long ticks_32k)
+{
+	return (unsigned long long) ticks_32k * 1000 * 5*5*5*5*5*5 >> 9;
+}
+
 static unsigned long omap_32k_last_tick = 0;
 
 /*
@@ -315,6 +317,15 @@
 }
 
 /*
+ * Returns current time from boot in nsecs. It's OK for this to wrap
+ * around for now, as it's just a relative time stamp.
+ */
+unsigned long long sched_clock(void)
+{
+	return omap_32k_ticks_to_nsecs(omap_32k_sync_timer_read());
+}
+
+/*
  * 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
@@ -330,19 +341,6 @@
 	now = omap_32k_sync_timer_read();
 
 	while (now - omap_32k_last_tick >= OMAP_32K_TICKS_PER_HZ) {
-#ifdef OMAP_32K_TICK_MODULO
-		/* Modulo addition may put omap_32k_last_tick ahead of now
-		 * and cause unwanted repetition of the while loop.
-		 */
-		if (unlikely(now - omap_32k_last_tick == ~0))
-			break;
-
-		modulo_count += OMAP_32K_TICK_MODULO;
-		if (modulo_count > HZ) {
-			++omap_32k_last_tick;
-			modulo_count -= HZ;
-		}
-#endif
 		omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ;
 		timer_tick(regs);
 	}