Merge branch 'pm-hwmods' of ssh://master.kernel.org/pub/scm/linux/kernel/git/khilman/linux-omap-pm into omap-for-linus
diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c
index 2c9a030..63d68cf 100644
--- a/arch/arm/mach-omap1/devices.c
+++ b/arch/arm/mach-omap1/devices.c
@@ -275,3 +275,30 @@
 }
 arch_initcall(omap1_init_devices);
 
+#if defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE)
+
+static struct resource wdt_resources[] = {
+	{
+		.start		= 0xfffeb000,
+		.end		= 0xfffeb07F,
+		.flags		= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device omap_wdt_device = {
+	.name	   = "omap_wdt",
+	.id	     = -1,
+	.num_resources	= ARRAY_SIZE(wdt_resources),
+	.resource	= wdt_resources,
+};
+
+static int __init omap_init_wdt(void)
+{
+	if (!cpu_is_omap16xx())
+		return;
+
+	platform_device_register(&omap_wdt_device);
+	return 0;
+}
+subsys_initcall(omap_init_wdt);
+#endif
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 1c4b237..91dd215 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -11,9 +11,8 @@
 	select PM_RUNTIME
 	select VFP
 	select NEON if ARCH_OMAP3 || ARCH_OMAP4
-	select SERIAL_8250
-	select SERIAL_CORE_CONSOLE
-	select SERIAL_8250_CONSOLE
+	select SERIAL_OMAP
+	select SERIAL_OMAP_CONSOLE
 	select I2C
 	select I2C_OMAP
 	select MFD
@@ -222,12 +221,18 @@
 	depends on ARCH_OMAP3
 	default y
 	select OMAP_PACKAGE_CBB
+	select SERIAL_8250
+	select SERIAL_CORE_CONSOLE
+	select SERIAL_8250_CONSOLE
 
 config MACH_OMAP_ZOOM3
 	bool "OMAP3630 Zoom3 board"
 	depends on ARCH_OMAP3
 	default y
 	select OMAP_PACKAGE_CBP
+	select SERIAL_8250
+	select SERIAL_CORE_CONSOLE
+	select SERIAL_8250_CONSOLE
 
 config MACH_CM_T35
 	bool "CompuLab CM-T35 module"
diff --git a/arch/arm/mach-omap2/board-3630sdp.c b/arch/arm/mach-omap2/board-3630sdp.c
index 2b2e0ef..3ef092f 100644
--- a/arch/arm/mach-omap2/board-3630sdp.c
+++ b/arch/arm/mach-omap2/board-3630sdp.c
@@ -208,7 +208,6 @@
 static void __init omap_sdp_init(void)
 {
 	omap3_mux_init(board_mux, OMAP_PACKAGE_CBP);
-	omap_serial_init();
 	zoom_peripherals_init();
 	board_smc91x_init();
 	board_flash_init(sdp_flash_partitions, chip_sel_sdp);
diff --git a/arch/arm/mach-omap2/board-zoom-peripherals.c b/arch/arm/mach-omap2/board-zoom-peripherals.c
index 073fd9b4..239c1f0 100644
--- a/arch/arm/mach-omap2/board-zoom-peripherals.c
+++ b/arch/arm/mach-omap2/board-zoom-peripherals.c
@@ -285,4 +285,5 @@
 	omap_i2c_init();
 	usb_musb_init(&musb_board_data);
 	enable_board_wakeup_source();
+	omap_serial_init();
 }
diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c
index c73906d..ba01ec0 100644
--- a/arch/arm/mach-omap2/clock3xxx_data.c
+++ b/arch/arm/mach-omap2/clock3xxx_data.c
@@ -2465,6 +2465,16 @@
 	.recalc		= &followparent_recalc,
 };
 
+static struct clk uart4_fck = {
+	.name		= "uart4_fck",
+	.ops		= &clkops_omap2_dflt_wait,
+	.parent		= &per_48m_fck,
+	.enable_reg	= OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN),
+	.enable_bit	= OMAP3630_EN_UART4_SHIFT,
+	.clkdm_name	= "per_clkdm",
+	.recalc		= &followparent_recalc,
+};
+
 static struct clk gpt2_fck = {
 	.name		= "gpt2_fck",
 	.ops		= &clkops_omap2_dflt_wait,
@@ -2715,6 +2725,16 @@
 	.recalc		= &followparent_recalc,
 };
 
+static struct clk uart4_ick = {
+	.name		= "uart4_ick",
+	.ops		= &clkops_omap2_dflt_wait,
+	.parent		= &per_l4_ick,
+	.enable_reg	= OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_ICLKEN),
+	.enable_bit	= OMAP3630_EN_UART4_SHIFT,
+	.clkdm_name	= "per_clkdm",
+	.recalc		= &followparent_recalc,
+};
+
 static struct clk gpt9_ick = {
 	.name		= "gpt9_ick",
 	.ops		= &clkops_omap2_dflt_wait,
@@ -3349,6 +3369,7 @@
 	CLK(NULL,	"per_96m_fck",	&per_96m_fck,	CK_3XXX),
 	CLK(NULL,	"per_48m_fck",	&per_48m_fck,	CK_3XXX),
 	CLK(NULL,	"uart3_fck",	&uart3_fck,	CK_3XXX),
+	CLK(NULL,	"uart4_fck",	&uart4_fck,	CK_36XX),
 	CLK(NULL,	"gpt2_fck",	&gpt2_fck,	CK_3XXX),
 	CLK(NULL,	"gpt3_fck",	&gpt3_fck,	CK_3XXX),
 	CLK(NULL,	"gpt4_fck",	&gpt4_fck,	CK_3XXX),
@@ -3372,6 +3393,7 @@
 	CLK(NULL,	"gpio2_ick",	&gpio2_ick,	CK_3XXX),
 	CLK(NULL,	"wdt3_ick",	&wdt3_ick,	CK_3XXX),
 	CLK(NULL,	"uart3_ick",	&uart3_ick,	CK_3XXX),
+	CLK(NULL,	"uart4_ick",	&uart4_ick,	CK_36XX),
 	CLK(NULL,	"gpt9_ick",	&gpt9_ick,	CK_3XXX),
 	CLK(NULL,	"gpt8_ick",	&gpt8_ick,	CK_3XXX),
 	CLK(NULL,	"gpt7_ick",	&gpt7_ick,	CK_3XXX),
diff --git a/arch/arm/mach-omap2/cm-regbits-34xx.h b/arch/arm/mach-omap2/cm-regbits-34xx.h
index fe82b79..4f959a7 100644
--- a/arch/arm/mach-omap2/cm-regbits-34xx.h
+++ b/arch/arm/mach-omap2/cm-regbits-34xx.h
@@ -649,6 +649,8 @@
 #define OMAP3430_ST_MCBSP2_MASK				(1 << 0)
 
 /* CM_AUTOIDLE_PER */
+#define OMAP3630_AUTO_UART4_MASK			(1 << 18)
+#define OMAP3630_AUTO_UART4_SHIFT			18
 #define OMAP3430_AUTO_GPIO6_MASK			(1 << 17)
 #define OMAP3430_AUTO_GPIO6_SHIFT			17
 #define OMAP3430_AUTO_GPIO5_MASK			(1 << 16)
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index 9bd4b34..5eb0b58 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -15,6 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/clk.h>
+#include <linux/err.h>
 
 #include <mach/hardware.h>
 #include <mach/irqs.h>
@@ -28,6 +29,8 @@
 #include <mach/gpio.h>
 #include <plat/mmc.h>
 #include <plat/dma.h>
+#include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
 
 #include "mux.h"
 
@@ -930,3 +933,39 @@
 	return 0;
 }
 arch_initcall(omap2_init_devices);
+
+#if defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE)
+struct omap_device_pm_latency omap_wdt_latency[] = {
+	[0] = {
+		.deactivate_func = omap_device_idle_hwmods,
+		.activate_func   = omap_device_enable_hwmods,
+		.flags		 = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+	},
+};
+
+static int __init omap_init_wdt(void)
+{
+	int id = -1;
+	struct omap_device *od;
+	struct omap_hwmod *oh;
+	char *oh_name = "wd_timer2";
+	char *dev_name = "omap_wdt";
+
+	if (!cpu_class_is_omap2())
+		return 0;
+
+	oh = omap_hwmod_lookup(oh_name);
+	if (!oh) {
+		pr_err("Could not look up wd_timer%d hwmod\n", id);
+		return -EINVAL;
+	}
+
+	od = omap_device_build(dev_name, id, oh, NULL, 0,
+				omap_wdt_latency,
+				ARRAY_SIZE(omap_wdt_latency), 0);
+	WARN(IS_ERR(od), "Cant build omap_device for %s:%s.\n",
+				dev_name, oh->name);
+	return 0;
+}
+subsys_initcall(omap_init_wdt);
+#endif
diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
index 3cc768e..adf6e36 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
@@ -15,10 +15,12 @@
 #include <mach/irqs.h>
 #include <plat/cpu.h>
 #include <plat/dma.h>
+#include <plat/serial.h>
 
 #include "omap_hwmod_common_data.h"
 
 #include "prm-regbits-24xx.h"
+#include "cm-regbits-24xx.h"
 
 /*
  * OMAP2420 hardware module integration data
@@ -33,6 +35,7 @@
 static struct omap_hwmod omap2420_iva_hwmod;
 static struct omap_hwmod omap2420_l3_main_hwmod;
 static struct omap_hwmod omap2420_l4_core_hwmod;
+static struct omap_hwmod omap2420_wd_timer2_hwmod;
 
 /* L3 -> L4_CORE interface */
 static struct omap_hwmod_ocp_if omap2420_l3_main__l4_core = {
@@ -71,6 +74,9 @@
 };
 
 static struct omap_hwmod omap2420_l4_wkup_hwmod;
+static struct omap_hwmod omap2420_uart1_hwmod;
+static struct omap_hwmod omap2420_uart2_hwmod;
+static struct omap_hwmod omap2420_uart3_hwmod;
 
 /* L4_CORE -> L4_WKUP interface */
 static struct omap_hwmod_ocp_if omap2420_l4_core__l4_wkup = {
@@ -79,6 +85,60 @@
 	.user	= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+/* L4 CORE -> UART1 interface */
+static struct omap_hwmod_addr_space omap2420_uart1_addr_space[] = {
+	{
+		.pa_start	= OMAP2_UART1_BASE,
+		.pa_end		= OMAP2_UART1_BASE + SZ_8K - 1,
+		.flags		= ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+	},
+};
+
+static struct omap_hwmod_ocp_if omap2_l4_core__uart1 = {
+	.master		= &omap2420_l4_core_hwmod,
+	.slave		= &omap2420_uart1_hwmod,
+	.clk		= "uart1_ick",
+	.addr		= omap2420_uart1_addr_space,
+	.addr_cnt	= ARRAY_SIZE(omap2420_uart1_addr_space),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 CORE -> UART2 interface */
+static struct omap_hwmod_addr_space omap2420_uart2_addr_space[] = {
+	{
+		.pa_start	= OMAP2_UART2_BASE,
+		.pa_end		= OMAP2_UART2_BASE + SZ_1K - 1,
+		.flags		= ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+	},
+};
+
+static struct omap_hwmod_ocp_if omap2_l4_core__uart2 = {
+	.master		= &omap2420_l4_core_hwmod,
+	.slave		= &omap2420_uart2_hwmod,
+	.clk		= "uart2_ick",
+	.addr		= omap2420_uart2_addr_space,
+	.addr_cnt	= ARRAY_SIZE(omap2420_uart2_addr_space),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 PER -> UART3 interface */
+static struct omap_hwmod_addr_space omap2420_uart3_addr_space[] = {
+	{
+		.pa_start	= OMAP2_UART3_BASE,
+		.pa_end		= OMAP2_UART3_BASE + SZ_1K - 1,
+		.flags		= ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+	},
+};
+
+static struct omap_hwmod_ocp_if omap2_l4_core__uart3 = {
+	.master		= &omap2420_l4_core_hwmod,
+	.slave		= &omap2420_uart3_hwmod,
+	.clk		= "uart3_ick",
+	.addr		= omap2420_uart3_addr_space,
+	.addr_cnt	= ARRAY_SIZE(omap2420_uart3_addr_space),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
 /* Slave interfaces on the L4_CORE interconnect */
 static struct omap_hwmod_ocp_if *omap2420_l4_core_slaves[] = {
 	&omap2420_l3_main__l4_core,
@@ -87,6 +147,9 @@
 /* Master interfaces on the L4_CORE interconnect */
 static struct omap_hwmod_ocp_if *omap2420_l4_core_masters[] = {
 	&omap2420_l4_core__l4_wkup,
+	&omap2_l4_core__uart1,
+	&omap2_l4_core__uart2,
+	&omap2_l4_core__uart3,
 };
 
 /* L4 CORE */
@@ -165,12 +228,206 @@
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP2420)
 };
 
+/* l4_wkup -> wd_timer2 */
+static struct omap_hwmod_addr_space omap2420_wd_timer2_addrs[] = {
+	{
+		.pa_start	= 0x48022000,
+		.pa_end		= 0x4802207f,
+		.flags		= ADDR_TYPE_RT
+	},
+};
+
+static struct omap_hwmod_ocp_if omap2420_l4_wkup__wd_timer2 = {
+	.master		= &omap2420_l4_wkup_hwmod,
+	.slave		= &omap2420_wd_timer2_hwmod,
+	.clk		= "mpu_wdt_ick",
+	.addr		= omap2420_wd_timer2_addrs,
+	.addr_cnt	= ARRAY_SIZE(omap2420_wd_timer2_addrs),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/*
+ * 'wd_timer' class
+ * 32-bit watchdog upward counter that generates a pulse on the reset pin on
+ * overflow condition
+ */
+
+static struct omap_hwmod_class_sysconfig omap2420_wd_timer_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_EMUFREE | SYSC_HAS_SOFTRESET |
+			   SYSC_HAS_AUTOIDLE),
+	.sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap2420_wd_timer_hwmod_class = {
+	.name = "wd_timer",
+	.sysc = &omap2420_wd_timer_sysc,
+};
+
+/* wd_timer2 */
+static struct omap_hwmod_ocp_if *omap2420_wd_timer2_slaves[] = {
+	&omap2420_l4_wkup__wd_timer2,
+};
+
+static struct omap_hwmod omap2420_wd_timer2_hwmod = {
+	.name		= "wd_timer2",
+	.class		= &omap2420_wd_timer_hwmod_class,
+	.main_clk	= "mpu_wdt_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_MPU_WDT_SHIFT,
+			.module_offs = WKUP_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_ST_MPU_WDT_SHIFT,
+		},
+	},
+	.slaves		= omap2420_wd_timer2_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap2420_wd_timer2_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
+/* UART */
+
+static struct omap_hwmod_class_sysconfig uart_sysc = {
+	.rev_offs	= 0x50,
+	.sysc_offs	= 0x54,
+	.syss_offs	= 0x58,
+	.sysc_flags	= (SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+			   SYSC_HAS_AUTOIDLE),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class uart_class = {
+	.name = "uart",
+	.sysc = &uart_sysc,
+};
+
+/* UART1 */
+
+static struct omap_hwmod_irq_info uart1_mpu_irqs[] = {
+	{ .irq = INT_24XX_UART1_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart1_sdma_reqs[] = {
+	{ .name = "rx",	.dma_req = OMAP24XX_DMA_UART1_RX, },
+	{ .name = "tx",	.dma_req = OMAP24XX_DMA_UART1_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap2420_uart1_slaves[] = {
+	&omap2_l4_core__uart1,
+};
+
+static struct omap_hwmod omap2420_uart1_hwmod = {
+	.name		= "uart1",
+	.mpu_irqs	= uart1_mpu_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(uart1_mpu_irqs),
+	.sdma_reqs	= uart1_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(uart1_sdma_reqs),
+	.main_clk	= "uart1_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_UART1_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_EN_UART1_SHIFT,
+		},
+	},
+	.slaves		= omap2420_uart1_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap2420_uart1_slaves),
+	.class		= &uart_class,
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
+/* UART2 */
+
+static struct omap_hwmod_irq_info uart2_mpu_irqs[] = {
+	{ .irq = INT_24XX_UART2_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart2_sdma_reqs[] = {
+	{ .name = "rx",	.dma_req = OMAP24XX_DMA_UART2_RX, },
+	{ .name = "tx",	.dma_req = OMAP24XX_DMA_UART2_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap2420_uart2_slaves[] = {
+	&omap2_l4_core__uart2,
+};
+
+static struct omap_hwmod omap2420_uart2_hwmod = {
+	.name		= "uart2",
+	.mpu_irqs	= uart2_mpu_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(uart2_mpu_irqs),
+	.sdma_reqs	= uart2_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(uart2_sdma_reqs),
+	.main_clk	= "uart2_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_UART2_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_EN_UART2_SHIFT,
+		},
+	},
+	.slaves		= omap2420_uart2_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap2420_uart2_slaves),
+	.class		= &uart_class,
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
+/* UART3 */
+
+static struct omap_hwmod_irq_info uart3_mpu_irqs[] = {
+	{ .irq = INT_24XX_UART3_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart3_sdma_reqs[] = {
+	{ .name = "rx",	.dma_req = OMAP24XX_DMA_UART3_RX, },
+	{ .name = "tx",	.dma_req = OMAP24XX_DMA_UART3_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap2420_uart3_slaves[] = {
+	&omap2_l4_core__uart3,
+};
+
+static struct omap_hwmod omap2420_uart3_hwmod = {
+	.name		= "uart3",
+	.mpu_irqs	= uart3_mpu_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(uart3_mpu_irqs),
+	.sdma_reqs	= uart3_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(uart3_sdma_reqs),
+	.main_clk	= "uart3_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 2,
+			.module_bit = OMAP24XX_EN_UART3_SHIFT,
+			.idlest_reg_id = 2,
+			.idlest_idle_bit = OMAP24XX_EN_UART3_SHIFT,
+		},
+	},
+	.slaves		= omap2420_uart3_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap2420_uart3_slaves),
+	.class		= &uart_class,
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP2420),
+};
+
 static __initdata struct omap_hwmod *omap2420_hwmods[] = {
 	&omap2420_l3_main_hwmod,
 	&omap2420_l4_core_hwmod,
 	&omap2420_l4_wkup_hwmod,
 	&omap2420_mpu_hwmod,
 	&omap2420_iva_hwmod,
+	&omap2420_wd_timer2_hwmod,
+	&omap2420_uart1_hwmod,
+	&omap2420_uart2_hwmod,
+	&omap2420_uart3_hwmod,
 	NULL,
 };
 
diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c
index 4526628..12d939e 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c
@@ -15,10 +15,12 @@
 #include <mach/irqs.h>
 #include <plat/cpu.h>
 #include <plat/dma.h>
+#include <plat/serial.h>
 
 #include "omap_hwmod_common_data.h"
 
 #include "prm-regbits-24xx.h"
+#include "cm-regbits-24xx.h"
 
 /*
  * OMAP2430 hardware module integration data
@@ -33,6 +35,7 @@
 static struct omap_hwmod omap2430_iva_hwmod;
 static struct omap_hwmod omap2430_l3_main_hwmod;
 static struct omap_hwmod omap2430_l4_core_hwmod;
+static struct omap_hwmod omap2430_wd_timer2_hwmod;
 
 /* L3 -> L4_CORE interface */
 static struct omap_hwmod_ocp_if omap2430_l3_main__l4_core = {
@@ -71,6 +74,9 @@
 };
 
 static struct omap_hwmod omap2430_l4_wkup_hwmod;
+static struct omap_hwmod omap2430_uart1_hwmod;
+static struct omap_hwmod omap2430_uart2_hwmod;
+static struct omap_hwmod omap2430_uart3_hwmod;
 
 /* L4_CORE -> L4_WKUP interface */
 static struct omap_hwmod_ocp_if omap2430_l4_core__l4_wkup = {
@@ -79,6 +85,60 @@
 	.user	= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+/* L4 CORE -> UART1 interface */
+static struct omap_hwmod_addr_space omap2430_uart1_addr_space[] = {
+	{
+		.pa_start	= OMAP2_UART1_BASE,
+		.pa_end		= OMAP2_UART1_BASE + SZ_8K - 1,
+		.flags		= ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+	},
+};
+
+static struct omap_hwmod_ocp_if omap2_l4_core__uart1 = {
+	.master		= &omap2430_l4_core_hwmod,
+	.slave		= &omap2430_uart1_hwmod,
+	.clk		= "uart1_ick",
+	.addr		= omap2430_uart1_addr_space,
+	.addr_cnt	= ARRAY_SIZE(omap2430_uart1_addr_space),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 CORE -> UART2 interface */
+static struct omap_hwmod_addr_space omap2430_uart2_addr_space[] = {
+	{
+		.pa_start	= OMAP2_UART2_BASE,
+		.pa_end		= OMAP2_UART2_BASE + SZ_1K - 1,
+		.flags		= ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+	},
+};
+
+static struct omap_hwmod_ocp_if omap2_l4_core__uart2 = {
+	.master		= &omap2430_l4_core_hwmod,
+	.slave		= &omap2430_uart2_hwmod,
+	.clk		= "uart2_ick",
+	.addr		= omap2430_uart2_addr_space,
+	.addr_cnt	= ARRAY_SIZE(omap2430_uart2_addr_space),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 PER -> UART3 interface */
+static struct omap_hwmod_addr_space omap2430_uart3_addr_space[] = {
+	{
+		.pa_start	= OMAP2_UART3_BASE,
+		.pa_end		= OMAP2_UART3_BASE + SZ_1K - 1,
+		.flags		= ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+	},
+};
+
+static struct omap_hwmod_ocp_if omap2_l4_core__uart3 = {
+	.master		= &omap2430_l4_core_hwmod,
+	.slave		= &omap2430_uart3_hwmod,
+	.clk		= "uart3_ick",
+	.addr		= omap2430_uart3_addr_space,
+	.addr_cnt	= ARRAY_SIZE(omap2430_uart3_addr_space),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
 /* Slave interfaces on the L4_CORE interconnect */
 static struct omap_hwmod_ocp_if *omap2430_l4_core_slaves[] = {
 	&omap2430_l3_main__l4_core,
@@ -104,6 +164,9 @@
 /* Slave interfaces on the L4_WKUP interconnect */
 static struct omap_hwmod_ocp_if *omap2430_l4_wkup_slaves[] = {
 	&omap2430_l4_core__l4_wkup,
+	&omap2_l4_core__uart1,
+	&omap2_l4_core__uart2,
+	&omap2_l4_core__uart3,
 };
 
 /* Master interfaces on the L4_WKUP interconnect */
@@ -165,12 +228,206 @@
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP2430)
 };
 
+/* l4_wkup -> wd_timer2 */
+static struct omap_hwmod_addr_space omap2430_wd_timer2_addrs[] = {
+	{
+		.pa_start	= 0x49016000,
+		.pa_end		= 0x4901607f,
+		.flags		= ADDR_TYPE_RT
+	},
+};
+
+static struct omap_hwmod_ocp_if omap2430_l4_wkup__wd_timer2 = {
+	.master		= &omap2430_l4_wkup_hwmod,
+	.slave		= &omap2430_wd_timer2_hwmod,
+	.clk		= "mpu_wdt_ick",
+	.addr		= omap2430_wd_timer2_addrs,
+	.addr_cnt	= ARRAY_SIZE(omap2430_wd_timer2_addrs),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/*
+ * 'wd_timer' class
+ * 32-bit watchdog upward counter that generates a pulse on the reset pin on
+ * overflow condition
+ */
+
+static struct omap_hwmod_class_sysconfig omap2430_wd_timer_sysc = {
+	.rev_offs	= 0x0,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_EMUFREE | SYSC_HAS_SOFTRESET |
+			   SYSC_HAS_AUTOIDLE),
+	.sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap2430_wd_timer_hwmod_class = {
+	.name = "wd_timer",
+	.sysc = &omap2430_wd_timer_sysc,
+};
+
+/* wd_timer2 */
+static struct omap_hwmod_ocp_if *omap2430_wd_timer2_slaves[] = {
+	&omap2430_l4_wkup__wd_timer2,
+};
+
+static struct omap_hwmod omap2430_wd_timer2_hwmod = {
+	.name		= "wd_timer2",
+	.class		= &omap2430_wd_timer_hwmod_class,
+	.main_clk	= "mpu_wdt_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_MPU_WDT_SHIFT,
+			.module_offs = WKUP_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_ST_MPU_WDT_SHIFT,
+		},
+	},
+	.slaves		= omap2430_wd_timer2_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap2430_wd_timer2_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+/* UART */
+
+static struct omap_hwmod_class_sysconfig uart_sysc = {
+	.rev_offs	= 0x50,
+	.sysc_offs	= 0x54,
+	.syss_offs	= 0x58,
+	.sysc_flags	= (SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+			   SYSC_HAS_AUTOIDLE),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class uart_class = {
+	.name = "uart",
+	.sysc = &uart_sysc,
+};
+
+/* UART1 */
+
+static struct omap_hwmod_irq_info uart1_mpu_irqs[] = {
+	{ .irq = INT_24XX_UART1_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart1_sdma_reqs[] = {
+	{ .name = "rx",	.dma_req = OMAP24XX_DMA_UART1_RX, },
+	{ .name = "tx",	.dma_req = OMAP24XX_DMA_UART1_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap2430_uart1_slaves[] = {
+	&omap2_l4_core__uart1,
+};
+
+static struct omap_hwmod omap2430_uart1_hwmod = {
+	.name		= "uart1",
+	.mpu_irqs	= uart1_mpu_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(uart1_mpu_irqs),
+	.sdma_reqs	= uart1_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(uart1_sdma_reqs),
+	.main_clk	= "uart1_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_UART1_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_EN_UART1_SHIFT,
+		},
+	},
+	.slaves		= omap2430_uart1_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap2430_uart1_slaves),
+	.class		= &uart_class,
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+/* UART2 */
+
+static struct omap_hwmod_irq_info uart2_mpu_irqs[] = {
+	{ .irq = INT_24XX_UART2_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart2_sdma_reqs[] = {
+	{ .name = "rx",	.dma_req = OMAP24XX_DMA_UART2_RX, },
+	{ .name = "tx",	.dma_req = OMAP24XX_DMA_UART2_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap2430_uart2_slaves[] = {
+	&omap2_l4_core__uart2,
+};
+
+static struct omap_hwmod omap2430_uart2_hwmod = {
+	.name		= "uart2",
+	.mpu_irqs	= uart2_mpu_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(uart2_mpu_irqs),
+	.sdma_reqs	= uart2_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(uart2_sdma_reqs),
+	.main_clk	= "uart2_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP24XX_EN_UART2_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP24XX_EN_UART2_SHIFT,
+		},
+	},
+	.slaves		= omap2430_uart2_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap2430_uart2_slaves),
+	.class		= &uart_class,
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
+/* UART3 */
+
+static struct omap_hwmod_irq_info uart3_mpu_irqs[] = {
+	{ .irq = INT_24XX_UART3_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart3_sdma_reqs[] = {
+	{ .name = "rx",	.dma_req = OMAP24XX_DMA_UART3_RX, },
+	{ .name = "tx",	.dma_req = OMAP24XX_DMA_UART3_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap2430_uart3_slaves[] = {
+	&omap2_l4_core__uart3,
+};
+
+static struct omap_hwmod omap2430_uart3_hwmod = {
+	.name		= "uart3",
+	.mpu_irqs	= uart3_mpu_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(uart3_mpu_irqs),
+	.sdma_reqs	= uart3_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(uart3_sdma_reqs),
+	.main_clk	= "uart3_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 2,
+			.module_bit = OMAP24XX_EN_UART3_SHIFT,
+			.idlest_reg_id = 2,
+			.idlest_idle_bit = OMAP24XX_EN_UART3_SHIFT,
+		},
+	},
+	.slaves		= omap2430_uart3_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap2430_uart3_slaves),
+	.class		= &uart_class,
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP2430),
+};
+
 static __initdata struct omap_hwmod *omap2430_hwmods[] = {
 	&omap2430_l3_main_hwmod,
 	&omap2430_l4_core_hwmod,
 	&omap2430_l4_wkup_hwmod,
 	&omap2430_mpu_hwmod,
 	&omap2430_iva_hwmod,
+	&omap2430_wd_timer2_hwmod,
+	&omap2430_uart1_hwmod,
+	&omap2430_uart2_hwmod,
+	&omap2430_uart3_hwmod,
 	NULL,
 };
 
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 5d8eb58..cb97ecf 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -17,10 +17,12 @@
 #include <mach/irqs.h>
 #include <plat/cpu.h>
 #include <plat/dma.h>
+#include <plat/serial.h>
 
 #include "omap_hwmod_common_data.h"
 
 #include "prm-regbits-34xx.h"
+#include "cm-regbits-34xx.h"
 
 /*
  * OMAP3xxx hardware module integration data
@@ -36,6 +38,7 @@
 static struct omap_hwmod omap3xxx_l3_main_hwmod;
 static struct omap_hwmod omap3xxx_l4_core_hwmod;
 static struct omap_hwmod omap3xxx_l4_per_hwmod;
+static struct omap_hwmod omap3xxx_wd_timer2_hwmod;
 
 /* L3 -> L4_CORE interface */
 static struct omap_hwmod_ocp_if omap3xxx_l3_main__l4_core = {
@@ -82,6 +85,10 @@
 };
 
 static struct omap_hwmod omap3xxx_l4_wkup_hwmod;
+static struct omap_hwmod omap3xxx_uart1_hwmod;
+static struct omap_hwmod omap3xxx_uart2_hwmod;
+static struct omap_hwmod omap3xxx_uart3_hwmod;
+static struct omap_hwmod omap3xxx_uart4_hwmod;
 
 /* L4_CORE -> L4_WKUP interface */
 static struct omap_hwmod_ocp_if omap3xxx_l4_core__l4_wkup = {
@@ -90,6 +97,78 @@
 	.user	= OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+/* L4 CORE -> UART1 interface */
+static struct omap_hwmod_addr_space omap3xxx_uart1_addr_space[] = {
+	{
+		.pa_start	= OMAP3_UART1_BASE,
+		.pa_end		= OMAP3_UART1_BASE + SZ_8K - 1,
+		.flags		= ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+	},
+};
+
+static struct omap_hwmod_ocp_if omap3_l4_core__uart1 = {
+	.master		= &omap3xxx_l4_core_hwmod,
+	.slave		= &omap3xxx_uart1_hwmod,
+	.clk		= "uart1_ick",
+	.addr		= omap3xxx_uart1_addr_space,
+	.addr_cnt	= ARRAY_SIZE(omap3xxx_uart1_addr_space),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 CORE -> UART2 interface */
+static struct omap_hwmod_addr_space omap3xxx_uart2_addr_space[] = {
+	{
+		.pa_start	= OMAP3_UART2_BASE,
+		.pa_end		= OMAP3_UART2_BASE + SZ_1K - 1,
+		.flags		= ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+	},
+};
+
+static struct omap_hwmod_ocp_if omap3_l4_core__uart2 = {
+	.master		= &omap3xxx_l4_core_hwmod,
+	.slave		= &omap3xxx_uart2_hwmod,
+	.clk		= "uart2_ick",
+	.addr		= omap3xxx_uart2_addr_space,
+	.addr_cnt	= ARRAY_SIZE(omap3xxx_uart2_addr_space),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 PER -> UART3 interface */
+static struct omap_hwmod_addr_space omap3xxx_uart3_addr_space[] = {
+	{
+		.pa_start	= OMAP3_UART3_BASE,
+		.pa_end		= OMAP3_UART3_BASE + SZ_1K - 1,
+		.flags		= ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+	},
+};
+
+static struct omap_hwmod_ocp_if omap3_l4_per__uart3 = {
+	.master		= &omap3xxx_l4_per_hwmod,
+	.slave		= &omap3xxx_uart3_hwmod,
+	.clk		= "uart3_ick",
+	.addr		= omap3xxx_uart3_addr_space,
+	.addr_cnt	= ARRAY_SIZE(omap3xxx_uart3_addr_space),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 PER -> UART4 interface */
+static struct omap_hwmod_addr_space omap3xxx_uart4_addr_space[] = {
+	{
+		.pa_start	= OMAP3_UART4_BASE,
+		.pa_end		= OMAP3_UART4_BASE + SZ_1K - 1,
+		.flags		= ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+	},
+};
+
+static struct omap_hwmod_ocp_if omap3_l4_per__uart4 = {
+	.master		= &omap3xxx_l4_per_hwmod,
+	.slave		= &omap3xxx_uart4_hwmod,
+	.clk		= "uart4_ick",
+	.addr		= omap3xxx_uart4_addr_space,
+	.addr_cnt	= ARRAY_SIZE(omap3xxx_uart4_addr_space),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
 /* Slave interfaces on the L4_CORE interconnect */
 static struct omap_hwmod_ocp_if *omap3xxx_l4_core_slaves[] = {
 	&omap3xxx_l3_main__l4_core,
@@ -98,6 +177,8 @@
 /* Master interfaces on the L4_CORE interconnect */
 static struct omap_hwmod_ocp_if *omap3xxx_l4_core_masters[] = {
 	&omap3xxx_l4_core__l4_wkup,
+	&omap3_l4_core__uart1,
+	&omap3_l4_core__uart2,
 };
 
 /* L4 CORE */
@@ -119,6 +200,8 @@
 
 /* Master interfaces on the L4_PER interconnect */
 static struct omap_hwmod_ocp_if *omap3xxx_l4_per_masters[] = {
+	&omap3_l4_per__uart3,
+	&omap3_l4_per__uart4,
 };
 
 /* L4 PER */
@@ -197,6 +280,235 @@
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430)
 };
 
+/* l4_wkup -> wd_timer2 */
+static struct omap_hwmod_addr_space omap3xxx_wd_timer2_addrs[] = {
+	{
+		.pa_start	= 0x48314000,
+		.pa_end		= 0x4831407f,
+		.flags		= ADDR_TYPE_RT
+	},
+};
+
+static struct omap_hwmod_ocp_if omap3xxx_l4_wkup__wd_timer2 = {
+	.master		= &omap3xxx_l4_wkup_hwmod,
+	.slave		= &omap3xxx_wd_timer2_hwmod,
+	.clk		= "wdt2_ick",
+	.addr		= omap3xxx_wd_timer2_addrs,
+	.addr_cnt	= ARRAY_SIZE(omap3xxx_wd_timer2_addrs),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/*
+ * 'wd_timer' class
+ * 32-bit watchdog upward counter that generates a pulse on the reset pin on
+ * overflow condition
+ */
+
+static struct omap_hwmod_class_sysconfig omap3xxx_wd_timer_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_EMUFREE |
+			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+			   SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap3xxx_wd_timer_hwmod_class = {
+	.name = "wd_timer",
+	.sysc = &omap3xxx_wd_timer_sysc,
+};
+
+/* wd_timer2 */
+static struct omap_hwmod_ocp_if *omap3xxx_wd_timer2_slaves[] = {
+	&omap3xxx_l4_wkup__wd_timer2,
+};
+
+static struct omap_hwmod omap3xxx_wd_timer2_hwmod = {
+	.name		= "wd_timer2",
+	.class		= &omap3xxx_wd_timer_hwmod_class,
+	.main_clk	= "wdt2_fck",
+	.prcm		= {
+		.omap2 = {
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_WDT2_SHIFT,
+			.module_offs = WKUP_MOD,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_ST_WDT2_SHIFT,
+		},
+	},
+	.slaves		= omap3xxx_wd_timer2_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap3xxx_wd_timer2_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* UART common */
+
+static struct omap_hwmod_class_sysconfig uart_sysc = {
+	.rev_offs	= 0x50,
+	.sysc_offs	= 0x54,
+	.syss_offs	= 0x58,
+	.sysc_flags	= (SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+			   SYSC_HAS_AUTOIDLE),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class uart_class = {
+	.name = "uart",
+	.sysc = &uart_sysc,
+};
+
+/* UART1 */
+
+static struct omap_hwmod_irq_info uart1_mpu_irqs[] = {
+	{ .irq = INT_24XX_UART1_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart1_sdma_reqs[] = {
+	{ .name = "tx",	.dma_req = OMAP24XX_DMA_UART1_TX, },
+	{ .name = "rx",	.dma_req = OMAP24XX_DMA_UART1_RX, },
+};
+
+static struct omap_hwmod_ocp_if *omap3xxx_uart1_slaves[] = {
+	&omap3_l4_core__uart1,
+};
+
+static struct omap_hwmod omap3xxx_uart1_hwmod = {
+	.name		= "uart1",
+	.mpu_irqs	= uart1_mpu_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(uart1_mpu_irqs),
+	.sdma_reqs	= uart1_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(uart1_sdma_reqs),
+	.main_clk	= "uart1_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_UART1_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_EN_UART1_SHIFT,
+		},
+	},
+	.slaves		= omap3xxx_uart1_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap3xxx_uart1_slaves),
+	.class		= &uart_class,
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* UART2 */
+
+static struct omap_hwmod_irq_info uart2_mpu_irqs[] = {
+	{ .irq = INT_24XX_UART2_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart2_sdma_reqs[] = {
+	{ .name = "tx",	.dma_req = OMAP24XX_DMA_UART2_TX, },
+	{ .name = "rx",	.dma_req = OMAP24XX_DMA_UART2_RX, },
+};
+
+static struct omap_hwmod_ocp_if *omap3xxx_uart2_slaves[] = {
+	&omap3_l4_core__uart2,
+};
+
+static struct omap_hwmod omap3xxx_uart2_hwmod = {
+	.name		= "uart2",
+	.mpu_irqs	= uart2_mpu_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(uart2_mpu_irqs),
+	.sdma_reqs	= uart2_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(uart2_sdma_reqs),
+	.main_clk	= "uart2_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = CORE_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_UART2_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_EN_UART2_SHIFT,
+		},
+	},
+	.slaves		= omap3xxx_uart2_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap3xxx_uart2_slaves),
+	.class		= &uart_class,
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* UART3 */
+
+static struct omap_hwmod_irq_info uart3_mpu_irqs[] = {
+	{ .irq = INT_24XX_UART3_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart3_sdma_reqs[] = {
+	{ .name = "tx",	.dma_req = OMAP24XX_DMA_UART3_TX, },
+	{ .name = "rx",	.dma_req = OMAP24XX_DMA_UART3_RX, },
+};
+
+static struct omap_hwmod_ocp_if *omap3xxx_uart3_slaves[] = {
+	&omap3_l4_per__uart3,
+};
+
+static struct omap_hwmod omap3xxx_uart3_hwmod = {
+	.name		= "uart3",
+	.mpu_irqs	= uart3_mpu_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(uart3_mpu_irqs),
+	.sdma_reqs	= uart3_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(uart3_sdma_reqs),
+	.main_clk	= "uart3_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = OMAP3430_PER_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3430_EN_UART3_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3430_EN_UART3_SHIFT,
+		},
+	},
+	.slaves		= omap3xxx_uart3_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap3xxx_uart3_slaves),
+	.class		= &uart_class,
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
+/* UART4 */
+
+static struct omap_hwmod_irq_info uart4_mpu_irqs[] = {
+	{ .irq = INT_36XX_UART4_IRQ, },
+};
+
+static struct omap_hwmod_dma_info uart4_sdma_reqs[] = {
+	{ .name = "rx",	.dma_req = OMAP36XX_DMA_UART4_RX, },
+	{ .name = "tx",	.dma_req = OMAP36XX_DMA_UART4_TX, },
+};
+
+static struct omap_hwmod_ocp_if *omap3xxx_uart4_slaves[] = {
+	&omap3_l4_per__uart4,
+};
+
+static struct omap_hwmod omap3xxx_uart4_hwmod = {
+	.name		= "uart4",
+	.mpu_irqs	= uart4_mpu_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(uart4_mpu_irqs),
+	.sdma_reqs	= uart4_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(uart4_sdma_reqs),
+	.main_clk	= "uart4_fck",
+	.prcm		= {
+		.omap2 = {
+			.module_offs = OMAP3430_PER_MOD,
+			.prcm_reg_id = 1,
+			.module_bit = OMAP3630_EN_UART4_SHIFT,
+			.idlest_reg_id = 1,
+			.idlest_idle_bit = OMAP3630_EN_UART4_SHIFT,
+		},
+	},
+	.slaves		= omap3xxx_uart4_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap3xxx_uart4_slaves),
+	.class		= &uart_class,
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3630ES1),
+};
+
 static __initdata struct omap_hwmod *omap3xxx_hwmods[] = {
 	&omap3xxx_l3_main_hwmod,
 	&omap3xxx_l4_core_hwmod,
@@ -204,6 +516,11 @@
 	&omap3xxx_l4_wkup_hwmod,
 	&omap3xxx_mpu_hwmod,
 	&omap3xxx_iva_hwmod,
+	&omap3xxx_wd_timer2_hwmod,
+	&omap3xxx_uart1_hwmod,
+	&omap3xxx_uart2_hwmod,
+	&omap3xxx_uart3_hwmod,
+	&omap3xxx_uart4_hwmod,
 	NULL,
 };
 
@@ -211,5 +528,3 @@
 {
 	return omap_hwmod_init(omap3xxx_hwmods);
 }
-
-
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index e20b0ee..7274db4d 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -452,6 +452,365 @@
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
 };
 
+/*
+ * 'wd_timer' class
+ * 32-bit watchdog upward counter that generates a pulse on the reset pin on
+ * overflow condition
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_wd_timer_sysc = {
+	.rev_offs	= 0x0000,
+	.sysc_offs	= 0x0010,
+	.syss_offs	= 0x0014,
+	.sysc_flags	= (SYSC_HAS_SIDLEMODE | SYSC_HAS_EMUFREE |
+			   SYSC_HAS_SOFTRESET),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+/*
+ * 'uart' class
+ * universal asynchronous receiver/transmitter (uart)
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_uart_sysc = {
+	.rev_offs	= 0x0050,
+	.sysc_offs	= 0x0054,
+	.syss_offs	= 0x0058,
+	.sysc_flags	= (SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
+			   SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE),
+	.idlemodes	= (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+	.sysc_fields	= &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_wd_timer_hwmod_class = {
+	.name = "wd_timer",
+	.sysc = &omap44xx_wd_timer_sysc,
+};
+
+/* wd_timer2 */
+static struct omap_hwmod omap44xx_wd_timer2_hwmod;
+static struct omap_hwmod_irq_info omap44xx_wd_timer2_irqs[] = {
+	{ .irq = 80 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_wd_timer2_addrs[] = {
+	{
+		.pa_start	= 0x4a314000,
+		.pa_end		= 0x4a31407f,
+		.flags		= ADDR_TYPE_RT
+	},
+};
+
+static struct omap_hwmod_class omap44xx_uart_hwmod_class = {
+	.name = "uart",
+	.sysc = &omap44xx_uart_sysc,
+};
+
+/* uart1 */
+static struct omap_hwmod omap44xx_uart1_hwmod;
+static struct omap_hwmod_irq_info omap44xx_uart1_irqs[] = {
+	{ .irq = 72 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_uart1_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = 48 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx", .dma_req = 49 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_uart1_addrs[] = {
+	{
+		.pa_start	= 0x4806a000,
+		.pa_end		= 0x4806a0ff,
+		.flags		= ADDR_TYPE_RT
+	},
+};
+
+/* l4_per -> uart1 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__uart1 = {
+	.master		= &omap44xx_l4_per_hwmod,
+	.slave		= &omap44xx_uart1_hwmod,
+	.clk		= "l4_div_ck",
+	.addr		= omap44xx_uart1_addrs,
+	.addr_cnt	= ARRAY_SIZE(omap44xx_uart1_addrs),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* uart1 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_uart1_slaves[] = {
+	&omap44xx_l4_per__uart1,
+};
+
+static struct omap_hwmod omap44xx_uart1_hwmod = {
+	.name		= "uart1",
+	.class		= &omap44xx_uart_hwmod_class,
+	.mpu_irqs	= omap44xx_uart1_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(omap44xx_uart1_irqs),
+	.sdma_reqs	= omap44xx_uart1_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(omap44xx_uart1_sdma_reqs),
+	.main_clk	= "uart1_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_reg = OMAP4430_CM_L4PER_UART1_CLKCTRL,
+		},
+	},
+	.slaves		= omap44xx_uart1_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap44xx_uart1_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* uart2 */
+static struct omap_hwmod omap44xx_uart2_hwmod;
+static struct omap_hwmod_irq_info omap44xx_uart2_irqs[] = {
+	{ .irq = 73 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_uart2_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = 50 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx", .dma_req = 51 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_uart2_addrs[] = {
+	{
+		.pa_start	= 0x4806c000,
+		.pa_end		= 0x4806c0ff,
+		.flags		= ADDR_TYPE_RT
+	},
+};
+
+/* l4_wkup -> wd_timer2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_wkup__wd_timer2 = {
+	.master		= &omap44xx_l4_wkup_hwmod,
+	.slave		= &omap44xx_wd_timer2_hwmod,
+	.clk		= "l4_wkup_clk_mux_ck",
+	.addr		= omap44xx_wd_timer2_addrs,
+	.addr_cnt	= ARRAY_SIZE(omap44xx_wd_timer2_addrs),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* wd_timer2 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_wd_timer2_slaves[] = {
+	&omap44xx_l4_wkup__wd_timer2,
+};
+
+static struct omap_hwmod omap44xx_wd_timer2_hwmod = {
+	.name		= "wd_timer2",
+	.class		= &omap44xx_wd_timer_hwmod_class,
+	.mpu_irqs	= omap44xx_wd_timer2_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(omap44xx_wd_timer2_irqs),
+	.main_clk	= "wd_timer2_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_reg = OMAP4430_CM_WKUP_WDT2_CLKCTRL,
+		},
+	},
+	.slaves		= omap44xx_wd_timer2_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap44xx_wd_timer2_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* wd_timer3 */
+static struct omap_hwmod omap44xx_wd_timer3_hwmod;
+static struct omap_hwmod_irq_info omap44xx_wd_timer3_irqs[] = {
+	{ .irq = 36 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_wd_timer3_addrs[] = {
+	{
+		.pa_start	= 0x40130000,
+		.pa_end		= 0x4013007f,
+		.flags		= ADDR_TYPE_RT
+	},
+};
+
+/* l4_per -> uart2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__uart2 = {
+	.master		= &omap44xx_l4_per_hwmod,
+	.slave		= &omap44xx_uart2_hwmod,
+	.clk		= "l4_div_ck",
+	.addr		= omap44xx_uart2_addrs,
+	.addr_cnt	= ARRAY_SIZE(omap44xx_uart2_addrs),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* uart2 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_uart2_slaves[] = {
+	&omap44xx_l4_per__uart2,
+};
+
+static struct omap_hwmod omap44xx_uart2_hwmod = {
+	.name		= "uart2",
+	.class		= &omap44xx_uart_hwmod_class,
+	.mpu_irqs	= omap44xx_uart2_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(omap44xx_uart2_irqs),
+	.sdma_reqs	= omap44xx_uart2_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(omap44xx_uart2_sdma_reqs),
+	.main_clk	= "uart2_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_reg = OMAP4430_CM_L4PER_UART2_CLKCTRL,
+		},
+	},
+	.slaves		= omap44xx_uart2_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap44xx_uart2_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* uart3 */
+static struct omap_hwmod omap44xx_uart3_hwmod;
+static struct omap_hwmod_irq_info omap44xx_uart3_irqs[] = {
+	{ .irq = 74 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_uart3_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = 52 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx", .dma_req = 53 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_uart3_addrs[] = {
+	{
+		.pa_start	= 0x48020000,
+		.pa_end		= 0x480200ff,
+		.flags		= ADDR_TYPE_RT
+	},
+};
+
+/* l4_abe -> wd_timer3 */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__wd_timer3 = {
+	.master		= &omap44xx_l4_abe_hwmod,
+	.slave		= &omap44xx_wd_timer3_hwmod,
+	.clk		= "ocp_abe_iclk",
+	.addr		= omap44xx_wd_timer3_addrs,
+	.addr_cnt	= ARRAY_SIZE(omap44xx_wd_timer3_addrs),
+	.user		= OCP_USER_MPU,
+};
+
+/* l4_abe -> wd_timer3 (dma) */
+static struct omap_hwmod_addr_space omap44xx_wd_timer3_dma_addrs[] = {
+	{
+		.pa_start	= 0x49030000,
+		.pa_end		= 0x4903007f,
+		.flags		= ADDR_TYPE_RT
+	},
+};
+
+/* l4_per -> uart3 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__uart3 = {
+	.master		= &omap44xx_l4_per_hwmod,
+	.slave		= &omap44xx_uart3_hwmod,
+	.clk		= "l4_div_ck",
+	.addr		= omap44xx_uart3_addrs,
+	.addr_cnt	= ARRAY_SIZE(omap44xx_uart3_addrs),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* uart3 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_uart3_slaves[] = {
+	&omap44xx_l4_per__uart3,
+};
+
+static struct omap_hwmod omap44xx_uart3_hwmod = {
+	.name		= "uart3",
+	.class		= &omap44xx_uart_hwmod_class,
+	.flags		= (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET),
+	.mpu_irqs	= omap44xx_uart3_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(omap44xx_uart3_irqs),
+	.sdma_reqs	= omap44xx_uart3_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(omap44xx_uart3_sdma_reqs),
+	.main_clk	= "uart3_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_reg = OMAP4430_CM_L4PER_UART3_CLKCTRL,
+		},
+	},
+	.slaves		= omap44xx_uart3_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap44xx_uart3_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* uart4 */
+static struct omap_hwmod omap44xx_uart4_hwmod;
+static struct omap_hwmod_irq_info omap44xx_uart4_irqs[] = {
+	{ .irq = 70 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_dma_info omap44xx_uart4_sdma_reqs[] = {
+	{ .name = "tx", .dma_req = 54 + OMAP44XX_DMA_REQ_START },
+	{ .name = "rx", .dma_req = 55 + OMAP44XX_DMA_REQ_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_uart4_addrs[] = {
+	{
+		.pa_start	= 0x4806e000,
+		.pa_end		= 0x4806e0ff,
+		.flags		= ADDR_TYPE_RT
+	},
+};
+
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__wd_timer3_dma = {
+	.master		= &omap44xx_l4_abe_hwmod,
+	.slave		= &omap44xx_wd_timer3_hwmod,
+	.clk		= "ocp_abe_iclk",
+	.addr		= omap44xx_wd_timer3_dma_addrs,
+	.addr_cnt	= ARRAY_SIZE(omap44xx_wd_timer3_dma_addrs),
+	.user		= OCP_USER_SDMA,
+};
+
+/* wd_timer3 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_wd_timer3_slaves[] = {
+	&omap44xx_l4_abe__wd_timer3,
+	&omap44xx_l4_abe__wd_timer3_dma,
+};
+
+static struct omap_hwmod omap44xx_wd_timer3_hwmod = {
+	.name		= "wd_timer3",
+	.class		= &omap44xx_wd_timer_hwmod_class,
+	.mpu_irqs	= omap44xx_wd_timer3_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(omap44xx_wd_timer3_irqs),
+	.main_clk	= "wd_timer3_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_reg = OMAP4430_CM1_ABE_WDT3_CLKCTRL,
+		},
+	},
+	.slaves		= omap44xx_wd_timer3_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap44xx_wd_timer3_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
+/* l4_per -> uart4 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__uart4 = {
+	.master		= &omap44xx_l4_per_hwmod,
+	.slave		= &omap44xx_uart4_hwmod,
+	.clk		= "l4_div_ck",
+	.addr		= omap44xx_uart4_addrs,
+	.addr_cnt	= ARRAY_SIZE(omap44xx_uart4_addrs),
+	.user		= OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* uart4 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_uart4_slaves[] = {
+	&omap44xx_l4_per__uart4,
+};
+
+static struct omap_hwmod omap44xx_uart4_hwmod = {
+	.name		= "uart4",
+	.class		= &omap44xx_uart_hwmod_class,
+	.mpu_irqs	= omap44xx_uart4_irqs,
+	.mpu_irqs_cnt	= ARRAY_SIZE(omap44xx_uart4_irqs),
+	.sdma_reqs	= omap44xx_uart4_sdma_reqs,
+	.sdma_reqs_cnt	= ARRAY_SIZE(omap44xx_uart4_sdma_reqs),
+	.main_clk	= "uart4_fck",
+	.prcm = {
+		.omap4 = {
+			.clkctrl_reg = OMAP4430_CM_L4PER_UART4_CLKCTRL,
+		},
+	},
+	.slaves		= omap44xx_uart4_slaves,
+	.slaves_cnt	= ARRAY_SIZE(omap44xx_uart4_slaves),
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP4430),
+};
+
 static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
 	/* dmm class */
 	&omap44xx_dmm_hwmod,
@@ -472,6 +831,15 @@
 
 	/* mpu class */
 	&omap44xx_mpu_hwmod,
+	/* wd_timer class */
+	&omap44xx_wd_timer2_hwmod,
+	&omap44xx_wd_timer3_hwmod,
+
+	/* uart class */
+	&omap44xx_uart1_hwmod,
+	&omap44xx_uart2_hwmod,
+	&omap44xx_uart3_hwmod,
+	&omap44xx_uart4_hwmod,
 	NULL,
 };
 
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index ac572aa..e57c9ae 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -388,6 +388,7 @@
 	/* PER */
 	if (per_next_state < PWRDM_POWER_ON) {
 		omap_uart_prepare_idle(2);
+		omap_uart_prepare_idle(3);
 		omap2_gpio_prepare_for_idle(per_next_state);
 		if (per_next_state == PWRDM_POWER_OFF)
 				omap3_per_save_context();
@@ -459,6 +460,7 @@
 		if (per_prev_state == PWRDM_POWER_OFF)
 			omap3_per_restore_context();
 		omap_uart_resume_idle(2);
+		omap_uart_resume_idle(3);
 	}
 
 	/* Disable IO-PAD and IO-CHAIN wakeup */
@@ -676,6 +678,14 @@
 
 static void __init prcm_setup_regs(void)
 {
+	u32 omap3630_auto_uart4_mask = cpu_is_omap3630() ?
+					OMAP3630_AUTO_UART4_MASK : 0;
+	u32 omap3630_en_uart4_mask = cpu_is_omap3630() ?
+					OMAP3630_EN_UART4_MASK : 0;
+	u32 omap3630_grpsel_uart4_mask = cpu_is_omap3630() ?
+					OMAP3630_GRPSEL_UART4_MASK : 0;
+
+
 	/* XXX Reset all wkdeps. This should be done when initializing
 	 * powerdomains */
 	prm_write_mod_reg(0, OMAP3430_IVA2_MOD, PM_WKDEP);
@@ -762,6 +772,7 @@
 		CM_AUTOIDLE);
 
 	cm_write_mod_reg(
+		omap3630_auto_uart4_mask |
 		OMAP3430_AUTO_GPIO6_MASK |
 		OMAP3430_AUTO_GPIO5_MASK |
 		OMAP3430_AUTO_GPIO4_MASK |
@@ -838,14 +849,16 @@
 				OMAP3430_DSS_MOD, PM_WKEN);
 
 	/* Enable wakeups in PER */
-	prm_write_mod_reg(OMAP3430_EN_GPIO2_MASK | OMAP3430_EN_GPIO3_MASK |
+	prm_write_mod_reg(omap3630_en_uart4_mask |
+			  OMAP3430_EN_GPIO2_MASK | OMAP3430_EN_GPIO3_MASK |
 			  OMAP3430_EN_GPIO4_MASK | OMAP3430_EN_GPIO5_MASK |
 			  OMAP3430_EN_GPIO6_MASK | OMAP3430_EN_UART3_MASK |
 			  OMAP3430_EN_MCBSP2_MASK | OMAP3430_EN_MCBSP3_MASK |
 			  OMAP3430_EN_MCBSP4_MASK,
 			  OMAP3430_PER_MOD, PM_WKEN);
 	/* and allow them to wake up MPU */
-	prm_write_mod_reg(OMAP3430_GRPSEL_GPIO2_MASK |
+	prm_write_mod_reg(omap3630_grpsel_uart4_mask |
+			  OMAP3430_GRPSEL_GPIO2_MASK |
 			  OMAP3430_GRPSEL_GPIO3_MASK |
 			  OMAP3430_GRPSEL_GPIO4_MASK |
 			  OMAP3430_GRPSEL_GPIO5_MASK |
diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h
index 995b7ed..298a22a 100644
--- a/arch/arm/mach-omap2/prcm-common.h
+++ b/arch/arm/mach-omap2/prcm-common.h
@@ -382,6 +382,9 @@
 #define OMAP3430_EN_MPU_SHIFT				1
 
 /* CM_FCLKEN_PER, CM_ICLKEN_PER, PM_WKEN_PER shared bits */
+
+#define OMAP3630_EN_UART4_MASK				(1 << 18)
+#define OMAP3630_EN_UART4_SHIFT				18
 #define OMAP3430_EN_GPIO6_MASK				(1 << 17)
 #define OMAP3430_EN_GPIO6_SHIFT				17
 #define OMAP3430_EN_GPIO5_MASK				(1 << 16)
@@ -422,6 +425,8 @@
 #define OMAP3430_EN_MCBSP2_SHIFT			0
 
 /* CM_IDLEST_PER, PM_WKST_PER shared bits */
+#define OMAP3630_ST_UART4_SHIFT				18
+#define OMAP3630_ST_UART4_MASK				(1 << 18)
 #define OMAP3430_ST_GPIO6_SHIFT				17
 #define OMAP3430_ST_GPIO6_MASK				(1 << 17)
 #define OMAP3430_ST_GPIO5_SHIFT				16
diff --git a/arch/arm/mach-omap2/prm-regbits-34xx.h b/arch/arm/mach-omap2/prm-regbits-34xx.h
index 7fd6023..9e63cb7 100644
--- a/arch/arm/mach-omap2/prm-regbits-34xx.h
+++ b/arch/arm/mach-omap2/prm-regbits-34xx.h
@@ -122,6 +122,7 @@
 #define OMAP3430_MEMRETSTATE_MASK			(1 << 8)
 
 /* PM_MPUGRPSEL_PER, PM_IVA2GRPSEL_PER shared bits */
+#define OMAP3630_GRPSEL_UART4_MASK			(1 << 18)
 #define OMAP3430_GRPSEL_GPIO6_MASK			(1 << 17)
 #define OMAP3430_GRPSEL_GPIO5_MASK			(1 << 16)
 #define OMAP3430_GRPSEL_GPIO4_MASK			(1 << 15)
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 566e991..0bcc9df 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -19,19 +19,30 @@
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/serial_8250.h>
 #include <linux/serial_reg.h>
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/serial_8250.h>
+#include <linux/pm_runtime.h>
+
+#ifdef CONFIG_SERIAL_OMAP
+#include <plat/omap-serial.h>
+#endif
 
 #include <plat/common.h>
 #include <plat/board.h>
 #include <plat/clock.h>
 #include <plat/control.h>
+#include <plat/dma.h>
+#include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
 
 #include "prm.h"
 #include "pm.h"
+#include "cm.h"
 #include "prm-regbits-34xx.h"
 
 #define UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV	0x52
@@ -48,6 +59,8 @@
  */
 #define DEFAULT_TIMEOUT 0
 
+#define MAX_UART_HWMOD_NAME_LEN		16
+
 struct omap_uart_state {
 	int num;
 	int can_sleep;
@@ -58,14 +71,21 @@
 	void __iomem *wk_en;
 	u32 wk_mask;
 	u32 padconf;
+	u32 dma_enabled;
 
 	struct clk *ick;
 	struct clk *fck;
 	int clocked;
 
-	struct plat_serial8250_port *p;
+	int irq;
+	int regshift;
+	int irqflags;
+	void __iomem *membase;
+	resource_size_t mapbase;
+
 	struct list_head node;
-	struct platform_device pdev;
+	struct omap_hwmod *oh;
+	struct platform_device *pdev;
 
 	u32 errata;
 #if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
@@ -83,75 +103,47 @@
 };
 
 static LIST_HEAD(uart_list);
+static u8 num_uarts;
 
-static struct plat_serial8250_port serial_platform_data0[] = {
-	{
-		.irq		= 72,
-		.flags		= UPF_BOOT_AUTOCONF,
-		.iotype		= UPIO_MEM,
-		.regshift	= 2,
-		.uartclk	= OMAP24XX_BASE_BAUD * 16,
-	}, {
-		.flags		= 0
-	}
-};
-
-static struct plat_serial8250_port serial_platform_data1[] = {
-	{
-		.irq		= 73,
-		.flags		= UPF_BOOT_AUTOCONF,
-		.iotype		= UPIO_MEM,
-		.regshift	= 2,
-		.uartclk	= OMAP24XX_BASE_BAUD * 16,
-	}, {
-		.flags		= 0
-	}
-};
-
-static struct plat_serial8250_port serial_platform_data2[] = {
-	{
-		.irq		= 74,
-		.flags		= UPF_BOOT_AUTOCONF,
-		.iotype		= UPIO_MEM,
-		.regshift	= 2,
-		.uartclk	= OMAP24XX_BASE_BAUD * 16,
-	}, {
-		.flags		= 0
-	}
-};
-
-static struct plat_serial8250_port serial_platform_data3[] = {
-	{
-		.irq		= 70,
-		.flags		= UPF_BOOT_AUTOCONF,
-		.iotype		= UPIO_MEM,
-		.regshift	= 2,
-		.uartclk	= OMAP24XX_BASE_BAUD * 16,
-	}, {
-		.flags		= 0
-	}
-};
-
-void __init omap2_set_globals_uart(struct omap_globals *omap2_globals)
+/*
+ * Since these idle/enable hooks are used in the idle path itself
+ * which has interrupts disabled, use the non-locking versions of
+ * the hwmod enable/disable functions.
+ */
+static int uart_idle_hwmod(struct omap_device *od)
 {
-	serial_platform_data0[0].mapbase = omap2_globals->uart1_phys;
-	serial_platform_data1[0].mapbase = omap2_globals->uart2_phys;
-	serial_platform_data2[0].mapbase = omap2_globals->uart3_phys;
-	serial_platform_data3[0].mapbase = omap2_globals->uart4_phys;
+	_omap_hwmod_idle(od->hwmods[0]);
+
+	return 0;
 }
 
+static int uart_enable_hwmod(struct omap_device *od)
+{
+	_omap_hwmod_enable(od->hwmods[0]);
+
+	return 0;
+}
+
+static struct omap_device_pm_latency omap_uart_latency[] = {
+	{
+		.deactivate_func = uart_idle_hwmod,
+		.activate_func	 = uart_enable_hwmod,
+		.flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+	},
+};
+
 static inline unsigned int __serial_read_reg(struct uart_port *up,
-					   int offset)
+					     int offset)
 {
 	offset <<= up->regshift;
 	return (unsigned int)__raw_readb(up->membase + offset);
 }
 
-static inline unsigned int serial_read_reg(struct plat_serial8250_port *up,
+static inline unsigned int serial_read_reg(struct omap_uart_state *uart,
 					   int offset)
 {
-	offset <<= up->regshift;
-	return (unsigned int)__raw_readb(up->membase + offset);
+	offset <<= uart->regshift;
+	return (unsigned int)__raw_readb(uart->membase + offset);
 }
 
 static inline void __serial_write_reg(struct uart_port *up, int offset,
@@ -161,11 +153,11 @@
 	__raw_writeb(value, up->membase + offset);
 }
 
-static inline void serial_write_reg(struct plat_serial8250_port *p, int offset,
+static inline void serial_write_reg(struct omap_uart_state *uart, int offset,
 				    int value)
 {
-	offset <<= p->regshift;
-	__raw_writeb(value, p->membase + offset);
+	offset <<= uart->regshift;
+	__raw_writeb(value, uart->membase + offset);
 }
 
 /*
@@ -173,14 +165,12 @@
  * properly. Note that the TX watermark initialization may not be needed
  * once the 8250.c watermark handling code is merged.
  */
+
 static inline void __init omap_uart_reset(struct omap_uart_state *uart)
 {
-	struct plat_serial8250_port *p = uart->p;
-
-	serial_write_reg(p, UART_OMAP_MDR1, 0x07);
-	serial_write_reg(p, UART_OMAP_SCR, 0x08);
-	serial_write_reg(p, UART_OMAP_MDR1, 0x00);
-	serial_write_reg(p, UART_OMAP_SYSC, (0x02 << 3) | (1 << 2) | (1 << 0));
+	serial_write_reg(uart, UART_OMAP_MDR1, 0x07);
+	serial_write_reg(uart, UART_OMAP_SCR, 0x08);
+	serial_write_reg(uart, UART_OMAP_MDR1, 0x00);
 }
 
 #if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3)
@@ -197,24 +187,23 @@
 static void omap_uart_mdr1_errataset(struct omap_uart_state *uart, u8 mdr1_val,
 		u8 fcr_val)
 {
-	struct plat_serial8250_port *p = uart->p;
 	u8 timeout = 255;
 
-	serial_write_reg(p, UART_OMAP_MDR1, mdr1_val);
+	serial_write_reg(uart, UART_OMAP_MDR1, mdr1_val);
 	udelay(2);
-	serial_write_reg(p, UART_FCR, fcr_val | UART_FCR_CLEAR_XMIT |
+	serial_write_reg(uart, UART_FCR, fcr_val | UART_FCR_CLEAR_XMIT |
 			UART_FCR_CLEAR_RCVR);
 	/*
 	 * Wait for FIFO to empty: when empty, RX_FIFO_E bit is 0 and
 	 * TX_FIFO_E bit is 1.
 	 */
-	while (UART_LSR_THRE != (serial_read_reg(p, UART_LSR) &
+	while (UART_LSR_THRE != (serial_read_reg(uart, UART_LSR) &
 				(UART_LSR_THRE | UART_LSR_DR))) {
 		timeout--;
 		if (!timeout) {
 			/* Should *never* happen. we warn and carry on */
-			dev_crit(&uart->pdev.dev, "Errata i202: timedout %x\n",
-				serial_read_reg(p, UART_LSR));
+			dev_crit(&uart->pdev->dev, "Errata i202: timedout %x\n",
+			serial_read_reg(uart, UART_LSR));
 			break;
 		}
 		udelay(1);
@@ -224,23 +213,22 @@
 static void omap_uart_save_context(struct omap_uart_state *uart)
 {
 	u16 lcr = 0;
-	struct plat_serial8250_port *p = uart->p;
 
 	if (!enable_off_mode)
 		return;
 
-	lcr = serial_read_reg(p, UART_LCR);
-	serial_write_reg(p, UART_LCR, 0xBF);
-	uart->dll = serial_read_reg(p, UART_DLL);
-	uart->dlh = serial_read_reg(p, UART_DLM);
-	serial_write_reg(p, UART_LCR, lcr);
-	uart->ier = serial_read_reg(p, UART_IER);
-	uart->sysc = serial_read_reg(p, UART_OMAP_SYSC);
-	uart->scr = serial_read_reg(p, UART_OMAP_SCR);
-	uart->wer = serial_read_reg(p, UART_OMAP_WER);
-	serial_write_reg(p, UART_LCR, 0x80);
-	uart->mcr = serial_read_reg(p, UART_MCR);
-	serial_write_reg(p, UART_LCR, lcr);
+	lcr = serial_read_reg(uart, UART_LCR);
+	serial_write_reg(uart, UART_LCR, 0xBF);
+	uart->dll = serial_read_reg(uart, UART_DLL);
+	uart->dlh = serial_read_reg(uart, UART_DLM);
+	serial_write_reg(uart, UART_LCR, lcr);
+	uart->ier = serial_read_reg(uart, UART_IER);
+	uart->sysc = serial_read_reg(uart, UART_OMAP_SYSC);
+	uart->scr = serial_read_reg(uart, UART_OMAP_SCR);
+	uart->wer = serial_read_reg(uart, UART_OMAP_WER);
+	serial_write_reg(uart, UART_LCR, 0x80);
+	uart->mcr = serial_read_reg(uart, UART_MCR);
+	serial_write_reg(uart, UART_LCR, lcr);
 
 	uart->context_valid = 1;
 }
@@ -248,7 +236,6 @@
 static void omap_uart_restore_context(struct omap_uart_state *uart)
 {
 	u16 efr = 0;
-	struct plat_serial8250_port *p = uart->p;
 
 	if (!enable_off_mode)
 		return;
@@ -261,29 +248,30 @@
 	if (uart->errata & UART_ERRATA_i202_MDR1_ACCESS)
 		omap_uart_mdr1_errataset(uart, 0x07, 0xA0);
 	else
-		serial_write_reg(p, UART_OMAP_MDR1, 0x7);
-	serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
-	efr = serial_read_reg(p, UART_EFR);
-	serial_write_reg(p, UART_EFR, UART_EFR_ECB);
-	serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */
-	serial_write_reg(p, UART_IER, 0x0);
-	serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
-	serial_write_reg(p, UART_DLL, uart->dll);
-	serial_write_reg(p, UART_DLM, uart->dlh);
-	serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */
-	serial_write_reg(p, UART_IER, uart->ier);
-	serial_write_reg(p, UART_LCR, 0x80);
-	serial_write_reg(p, UART_MCR, uart->mcr);
-	serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
-	serial_write_reg(p, UART_EFR, efr);
-	serial_write_reg(p, UART_LCR, UART_LCR_WLEN8);
-	serial_write_reg(p, UART_OMAP_SCR, uart->scr);
-	serial_write_reg(p, UART_OMAP_WER, uart->wer);
-	serial_write_reg(p, UART_OMAP_SYSC, uart->sysc);
+		serial_write_reg(uart, UART_OMAP_MDR1, 0x7);
+	serial_write_reg(uart, UART_LCR, 0xBF); /* Config B mode */
+	efr = serial_read_reg(uart, UART_EFR);
+	serial_write_reg(uart, UART_EFR, UART_EFR_ECB);
+	serial_write_reg(uart, UART_LCR, 0x0); /* Operational mode */
+	serial_write_reg(uart, UART_IER, 0x0);
+	serial_write_reg(uart, UART_LCR, 0xBF); /* Config B mode */
+	serial_write_reg(uart, UART_DLL, uart->dll);
+	serial_write_reg(uart, UART_DLM, uart->dlh);
+	serial_write_reg(uart, UART_LCR, 0x0); /* Operational mode */
+	serial_write_reg(uart, UART_IER, uart->ier);
+	serial_write_reg(uart, UART_LCR, 0x80);
+	serial_write_reg(uart, UART_MCR, uart->mcr);
+	serial_write_reg(uart, UART_LCR, 0xBF); /* Config B mode */
+	serial_write_reg(uart, UART_EFR, efr);
+	serial_write_reg(uart, UART_LCR, UART_LCR_WLEN8);
+	serial_write_reg(uart, UART_OMAP_SCR, uart->scr);
+	serial_write_reg(uart, UART_OMAP_WER, uart->wer);
+	serial_write_reg(uart, UART_OMAP_SYSC, uart->sysc);
 	if (uart->errata & UART_ERRATA_i202_MDR1_ACCESS)
 		omap_uart_mdr1_errataset(uart, 0x00, 0xA1);
 	else
-		serial_write_reg(p, UART_OMAP_MDR1, 0x00); /* UART 16x mode */
+		/* UART 16x mode */
+		serial_write_reg(uart, UART_OMAP_MDR1, 0x00);
 }
 #else
 static inline void omap_uart_save_context(struct omap_uart_state *uart) {}
@@ -295,8 +283,7 @@
 	if (uart->clocked)
 		return;
 
-	clk_enable(uart->ick);
-	clk_enable(uart->fck);
+	omap_device_enable(uart->pdev);
 	uart->clocked = 1;
 	omap_uart_restore_context(uart);
 }
@@ -310,8 +297,7 @@
 
 	omap_uart_save_context(uart);
 	uart->clocked = 0;
-	clk_disable(uart->ick);
-	clk_disable(uart->fck);
+	omap_device_idle(uart->pdev);
 }
 
 static void omap_uart_enable_wakeup(struct omap_uart_state *uart)
@@ -349,18 +335,24 @@
 }
 
 static void omap_uart_smart_idle_enable(struct omap_uart_state *uart,
-					  int enable)
+					       int enable)
 {
-	struct plat_serial8250_port *p = uart->p;
-	u16 sysc;
+	u8 idlemode;
 
-	sysc = serial_read_reg(p, UART_OMAP_SYSC) & 0x7;
-	if (enable)
-		sysc |= 0x2 << 3;
-	else
-		sysc |= 0x1 << 3;
+	if (enable) {
+		/**
+		 * Errata 2.15: [UART]:Cannot Acknowledge Idle Requests
+		 * in Smartidle Mode When Configured for DMA Operations.
+		 */
+		if (uart->dma_enabled)
+			idlemode = HWMOD_IDLEMODE_FORCE;
+		else
+			idlemode = HWMOD_IDLEMODE_SMART;
+	} else {
+		idlemode = HWMOD_IDLEMODE_NO;
+	}
 
-	serial_write_reg(p, UART_OMAP_SYSC, sysc);
+	omap_hwmod_set_slave_idlemode(uart->oh, idlemode);
 }
 
 static void omap_uart_block_sleep(struct omap_uart_state *uart)
@@ -377,7 +369,7 @@
 
 static void omap_uart_allow_sleep(struct omap_uart_state *uart)
 {
-	if (device_may_wakeup(&uart->pdev.dev))
+	if (device_may_wakeup(&uart->pdev->dev))
 		omap_uart_enable_wakeup(uart);
 	else
 		omap_uart_disable_wakeup(uart);
@@ -472,6 +464,7 @@
  * UART will not idle or sleep for its timeout period.
  *
  **/
+/* static int first_interrupt; */
 static irqreturn_t omap_uart_interrupt(int irq, void *dev_id)
 {
 	struct omap_uart_state *uart = dev_id;
@@ -483,7 +476,6 @@
 
 static void omap_uart_idle_init(struct omap_uart_state *uart)
 {
-	struct plat_serial8250_port *p = uart->p;
 	int ret;
 
 	uart->can_sleep = 0;
@@ -495,7 +487,7 @@
 	omap_uart_smart_idle_enable(uart, 0);
 
 	if (cpu_is_omap34xx()) {
-		u32 mod = (uart->num == 2) ? OMAP3430_PER_MOD : CORE_MOD;
+		u32 mod = (uart->num > 1) ? OMAP3430_PER_MOD : CORE_MOD;
 		u32 wk_mask = 0;
 		u32 padconf = 0;
 
@@ -514,6 +506,10 @@
 			wk_mask = OMAP3430_ST_UART3_MASK;
 			padconf = 0x19e;
 			break;
+		case 3:
+			wk_mask = OMAP3630_ST_UART4_MASK;
+			padconf = 0x0d2;
+			break;
 		}
 		uart->wk_mask = wk_mask;
 		uart->padconf = padconf;
@@ -546,9 +542,9 @@
 		uart->padconf = 0;
 	}
 
-	p->irqflags |= IRQF_SHARED;
-	ret = request_irq(p->irq, omap_uart_interrupt, IRQF_SHARED,
-			  "serial idle", (void *)uart);
+	uart->irqflags |= IRQF_SHARED;
+	ret = request_threaded_irq(uart->irq, NULL, omap_uart_interrupt,
+				   IRQF_SHARED, "serial idle", (void *)uart);
 	WARN_ON(ret);
 }
 
@@ -558,11 +554,17 @@
 	struct omap_uart_state *uart;
 
 	list_for_each_entry(uart, &uart_list, node) {
-		if (enable)
-			ret = request_irq(uart->p->irq, omap_uart_interrupt,
-				IRQF_SHARED, "serial idle", (void *)uart);
-		else
-			free_irq(uart->p->irq, (void *)uart);
+		if (enable) {
+			pm_runtime_put_sync(&uart->pdev->dev);
+			ret = request_threaded_irq(uart->irq, NULL,
+						   omap_uart_interrupt,
+						   IRQF_SHARED,
+						   "serial idle",
+						   (void *)uart);
+		} else {
+			pm_runtime_get_noresume(&uart->pdev->dev);
+			free_irq(uart->irq, (void *)uart);
+		}
 	}
 }
 
@@ -570,10 +572,9 @@
 				  struct device_attribute *attr,
 				  char *buf)
 {
-	struct platform_device *pdev = container_of(dev,
-					struct platform_device, dev);
-	struct omap_uart_state *uart = container_of(pdev,
-					struct omap_uart_state, pdev);
+	struct platform_device *pdev = to_platform_device(dev);
+	struct omap_device *odev = to_omap_device(pdev);
+	struct omap_uart_state *uart = odev->hwmods[0]->dev_attr;
 
 	return sprintf(buf, "%u\n", uart->timeout / HZ);
 }
@@ -582,10 +583,9 @@
 				   struct device_attribute *attr,
 				   const char *buf, size_t n)
 {
-	struct platform_device *pdev = container_of(dev,
-					struct platform_device, dev);
-	struct omap_uart_state *uart = container_of(pdev,
-					struct omap_uart_state, pdev);
+	struct platform_device *pdev = to_platform_device(dev);
+	struct omap_device *odev = to_omap_device(pdev);
+	struct omap_uart_state *uart = odev->hwmods[0]->dev_attr;
 	unsigned int value;
 
 	if (sscanf(buf, "%u", &value) != 1) {
@@ -608,48 +608,11 @@
 #define DEV_CREATE_FILE(dev, attr) WARN_ON(device_create_file(dev, attr))
 #else
 static inline void omap_uart_idle_init(struct omap_uart_state *uart) {}
+static void omap_uart_block_sleep(struct omap_uart_state *uart) {}
 #define DEV_CREATE_FILE(dev, attr)
 #endif /* CONFIG_PM */
 
-static struct omap_uart_state omap_uart[] = {
-	{
-		.pdev = {
-			.name			= "serial8250",
-			.id			= PLAT8250_DEV_PLATFORM,
-			.dev			= {
-				.platform_data	= serial_platform_data0,
-			},
-		},
-	}, {
-		.pdev = {
-			.name			= "serial8250",
-			.id			= PLAT8250_DEV_PLATFORM1,
-			.dev			= {
-				.platform_data	= serial_platform_data1,
-			},
-		},
-	}, {
-		.pdev = {
-			.name			= "serial8250",
-			.id			= PLAT8250_DEV_PLATFORM2,
-			.dev			= {
-				.platform_data	= serial_platform_data2,
-			},
-		},
-	},
-#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
-	{
-		.pdev = {
-			.name			= "serial8250",
-			.id			= 3,
-			.dev			= {
-				.platform_data	= serial_platform_data3,
-			},
-		},
-	},
-#endif
-};
-
+#ifndef CONFIG_SERIAL_OMAP
 /*
  * Override the default 8250 read handler: mem_serial_in()
  * Empty RX fifo read causes an abort on omap3630 and omap4
@@ -682,71 +645,44 @@
 	}
 	__serial_write_reg(up, offset, value);
 }
+#endif
+
 void __init omap_serial_early_init(void)
 {
-	int i, nr_ports;
-	char name[16];
+	int i = 0;
 
-	if (!(cpu_is_omap3630() || cpu_is_omap4430()))
-		nr_ports = 3;
-	else
-		nr_ports = ARRAY_SIZE(omap_uart);
+	do {
+		char oh_name[MAX_UART_HWMOD_NAME_LEN];
+		struct omap_hwmod *oh;
+		struct omap_uart_state *uart;
 
-	/*
-	 * 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.
-	 */
+		snprintf(oh_name, MAX_UART_HWMOD_NAME_LEN,
+			 "uart%d", i + 1);
+		oh = omap_hwmod_lookup(oh_name);
+		if (!oh)
+			break;
 
-	for (i = 0; i < nr_ports; i++) {
-		struct omap_uart_state *uart = &omap_uart[i];
-		struct platform_device *pdev = &uart->pdev;
-		struct device *dev = &pdev->dev;
-		struct plat_serial8250_port *p = dev->platform_data;
+		uart = kzalloc(sizeof(struct omap_uart_state), GFP_KERNEL);
+		if (WARN_ON(!uart))
+			return;
 
-		/* Don't map zero-based physical address */
-		if (p->mapbase == 0) {
-			dev_warn(dev, "no physical address for uart#%d,"
-				 " so skipping early_init...\n", i);
-			continue;
-		}
+		uart->oh = oh;
+		uart->num = i++;
+		list_add_tail(&uart->node, &uart_list);
+		num_uarts++;
+
 		/*
-		 * Module 4KB + L4 interconnect 4KB
-		 * Static mapping, never released
+		 * NOTE: omap_hwmod_init() has not yet been called,
+		 *       so no hwmod functions will work yet.
 		 */
-		p->membase = ioremap(p->mapbase, SZ_8K);
-		if (!p->membase) {
-			dev_err(dev, "ioremap failed for uart%i\n", i + 1);
-			continue;
-		}
 
-		sprintf(name, "uart%d_ick", i + 1);
-		uart->ick = clk_get(NULL, name);
-		if (IS_ERR(uart->ick)) {
-			dev_err(dev, "Could not get uart%d_ick\n", i + 1);
-			uart->ick = NULL;
-		}
-
-		sprintf(name, "uart%d_fck", i+1);
-		uart->fck = clk_get(NULL, name);
-		if (IS_ERR(uart->fck)) {
-			dev_err(dev, "Could not get uart%d_fck\n", i + 1);
-			uart->fck = NULL;
-		}
-
-		/* FIXME: Remove this once the clkdev is ready */
-		if (!cpu_is_omap44xx()) {
-			if (!uart->ick || !uart->fck)
-				continue;
-		}
-
-		uart->num = i;
-		p->private_data = uart;
-		uart->p = p;
-
-		if (cpu_is_omap44xx())
-			p->irq += 32;
-	}
+		/*
+		 * During UART early init, device need to be probed
+		 * to determine SoC specific init before omap_device
+		 * is ready.  Therefore, don't allow idle here
+		 */
+		uart->oh->flags |= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET;
+	} while (1);
 }
 
 /**
@@ -763,53 +699,135 @@
 void __init omap_serial_init_port(int port)
 {
 	struct omap_uart_state *uart;
-	struct platform_device *pdev;
-	struct device *dev;
+	struct omap_hwmod *oh;
+	struct omap_device *od;
+	void *pdata = NULL;
+	u32 pdata_size = 0;
+	char *name;
+#ifndef CONFIG_SERIAL_OMAP
+	struct plat_serial8250_port ports[2] = {
+		{},
+		{.flags = 0},
+	};
+	struct plat_serial8250_port *p = &ports[0];
+#else
+	struct omap_uart_port_info omap_up;
+#endif
 
-	BUG_ON(port < 0);
-	BUG_ON(port >= ARRAY_SIZE(omap_uart));
-
-	uart = &omap_uart[port];
-	pdev = &uart->pdev;
-	dev = &pdev->dev;
-
-	/* Don't proceed if there's no clocks available */
-	if (unlikely(!uart->ick || !uart->fck)) {
-		WARN(1, "%s: can't init uart%d, no clocks available\n",
-		     kobject_name(&dev->kobj), port);
+	if (WARN_ON(port < 0))
 		return;
-	}
-
-	omap_uart_enable_clocks(uart);
-
-	omap_uart_reset(uart);
-	omap_uart_idle_init(uart);
-
-	list_add_tail(&uart->node, &uart_list);
-
-	if (WARN_ON(platform_device_register(pdev)))
+	if (WARN_ON(port >= num_uarts))
 		return;
 
-	if ((cpu_is_omap34xx() && uart->padconf) ||
-	    (uart->wk_en && uart->wk_mask)) {
-		device_init_wakeup(dev, true);
-		DEV_CREATE_FILE(dev, &dev_attr_sleep_timeout);
-	}
+	list_for_each_entry(uart, &uart_list, node)
+		if (port == uart->num)
+			break;
+
+	oh = uart->oh;
+	uart->dma_enabled = 0;
+#ifndef CONFIG_SERIAL_OMAP
+	name = "serial8250";
+
+	/*
+	 * !! 8250 driver does not use standard IORESOURCE* It
+	 * has it's own custom pdata that can be taken from
+	 * the hwmod resource data.  But, this needs to be
+	 * done after the build.
+	 *
+	 * ?? does it have to be done before the register ??
+	 * YES, because platform_device_data_add() copies
+	 * pdata, it does not use a pointer.
+	 */
+	p->flags = UPF_BOOT_AUTOCONF;
+	p->iotype = UPIO_MEM;
+	p->regshift = 2;
+	p->uartclk = OMAP24XX_BASE_BAUD * 16;
+	p->irq = oh->mpu_irqs[0].irq;
+	p->mapbase = oh->slaves[0]->addr->pa_start;
+	p->membase = omap_hwmod_get_mpu_rt_va(oh);
+	p->irqflags = IRQF_SHARED;
+	p->private_data = uart;
 
 	/*
 	 * omap44xx: Never read empty UART fifo
 	 * omap3xxx: Never read empty UART fifo on UARTs
 	 * with IP rev >=0x52
 	 */
+	uart->regshift = p->regshift;
+	uart->membase = p->membase;
 	if (cpu_is_omap44xx())
 		uart->errata |= UART_ERRATA_FIFO_FULL_ABORT;
-	else if ((serial_read_reg(uart->p, UART_OMAP_MVER) & 0xFF)
+	else if ((serial_read_reg(uart, UART_OMAP_MVER) & 0xFF)
 			>= UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV)
 		uart->errata |= UART_ERRATA_FIFO_FULL_ABORT;
 
 	if (uart->errata & UART_ERRATA_FIFO_FULL_ABORT) {
-		uart->p->serial_in = serial_in_override;
-		uart->p->serial_out = serial_out_override;
+		p->serial_in = serial_in_override;
+		p->serial_out = serial_out_override;
+	}
+
+	pdata = &ports[0];
+	pdata_size = 2 * sizeof(struct plat_serial8250_port);
+#else
+
+	name = DRIVER_NAME;
+
+	omap_up.dma_enabled = uart->dma_enabled;
+	omap_up.uartclk = OMAP24XX_BASE_BAUD * 16;
+	omap_up.mapbase = oh->slaves[0]->addr->pa_start;
+	omap_up.membase = omap_hwmod_get_mpu_rt_va(oh);
+	omap_up.irqflags = IRQF_SHARED;
+	omap_up.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+
+	pdata = &omap_up;
+	pdata_size = sizeof(struct omap_uart_port_info);
+#endif
+
+	if (WARN_ON(!oh))
+		return;
+
+	od = omap_device_build(name, uart->num, oh, pdata, pdata_size,
+			       omap_uart_latency,
+			       ARRAY_SIZE(omap_uart_latency), false);
+	WARN(IS_ERR(od), "Could not build omap_device for %s: %s.\n",
+	     name, oh->name);
+
+	uart->irq = oh->mpu_irqs[0].irq;
+	uart->regshift = 2;
+	uart->mapbase = oh->slaves[0]->addr->pa_start;
+	uart->membase = omap_hwmod_get_mpu_rt_va(oh);
+	uart->pdev = &od->pdev;
+
+	oh->dev_attr = uart;
+
+	/*
+	 * Because of early UART probing, UART did not get idled
+	 * on init.  Now that omap_device is ready, ensure full idle
+	 * before doing omap_device_enable().
+	 */
+	omap_hwmod_idle(uart->oh);
+
+	omap_device_enable(uart->pdev);
+	omap_uart_idle_init(uart);
+	omap_uart_reset(uart);
+	omap_hwmod_enable_wakeup(uart->oh);
+	omap_device_idle(uart->pdev);
+
+	/*
+	 * Need to block sleep long enough for interrupt driven
+	 * driver to start.  Console driver is in polling mode
+	 * so device needs to be kept enabled while polling driver
+	 * is in use.
+	 */
+	if (uart->timeout)
+		uart->timeout = (30 * HZ);
+	omap_uart_block_sleep(uart);
+	uart->timeout = DEFAULT_TIMEOUT;
+
+	if ((cpu_is_omap34xx() && uart->padconf) ||
+	    (uart->wk_en && uart->wk_mask)) {
+		device_init_wakeup(&od->pdev.dev, true);
+		DEV_CREATE_FILE(&od->pdev.dev, &dev_attr_sleep_timeout);
 	}
 
 	/* Enable the MDR1 errata for OMAP3 */
@@ -826,13 +844,8 @@
  */
 void __init omap_serial_init(void)
 {
-	int i, nr_ports;
+	struct omap_uart_state *uart;
 
-	if (!(cpu_is_omap3630() || cpu_is_omap4430()))
-		nr_ports = 3;
-	else
-		nr_ports = ARRAY_SIZE(omap_uart);
-
-	for (i = 0; i < nr_ports; i++)
-		omap_serial_init_port(i);
+	list_for_each_entry(uart, &uart_list, node)
+		omap_serial_init_port(uart->num);
 }
diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c
index 7d668b3..947de3f 100644
--- a/arch/arm/plat-omap/common.c
+++ b/arch/arm/plat-omap/common.c
@@ -257,7 +257,6 @@
 	omap2_set_globals_sdrc(omap2_globals);
 	omap2_set_globals_control(omap2_globals);
 	omap2_set_globals_prcm(omap2_globals);
-	omap2_set_globals_uart(omap2_globals);
 }
 
 #endif
@@ -272,9 +271,6 @@
 	.ctrl	= OMAP2420_CTRL_BASE,
 	.prm	= OMAP2420_PRM_BASE,
 	.cm	= OMAP2420_CM_BASE,
-	.uart1_phys	= OMAP2_UART1_BASE,
-	.uart2_phys	= OMAP2_UART2_BASE,
-	.uart3_phys	= OMAP2_UART3_BASE,
 };
 
 void __init omap2_set_globals_242x(void)
@@ -293,9 +289,6 @@
 	.ctrl	= OMAP243X_CTRL_BASE,
 	.prm	= OMAP2430_PRM_BASE,
 	.cm	= OMAP2430_CM_BASE,
-	.uart1_phys	= OMAP2_UART1_BASE,
-	.uart2_phys	= OMAP2_UART2_BASE,
-	.uart3_phys	= OMAP2_UART3_BASE,
 };
 
 void __init omap2_set_globals_243x(void)
@@ -314,10 +307,6 @@
 	.ctrl	= OMAP343X_CTRL_BASE,
 	.prm	= OMAP3430_PRM_BASE,
 	.cm	= OMAP3430_CM_BASE,
-	.uart1_phys	= OMAP3_UART1_BASE,
-	.uart2_phys	= OMAP3_UART2_BASE,
-	.uart3_phys	= OMAP3_UART3_BASE,
-	.uart4_phys	= OMAP3_UART4_BASE,	/* Only on 3630 */
 };
 
 void __init omap2_set_globals_3xxx(void)
@@ -341,10 +330,6 @@
 	.prm	= OMAP4430_PRM_BASE,
 	.cm	= OMAP4430_CM_BASE,
 	.cm2	= OMAP4430_CM2_BASE,
-	.uart1_phys	= OMAP4_UART1_BASE,
-	.uart2_phys	= OMAP4_UART2_BASE,
-	.uart3_phys	= OMAP4_UART3_BASE,
-	.uart4_phys	= OMAP4_UART4_BASE,
 };
 
 void __init omap2_set_globals_443x(void)
@@ -352,7 +337,6 @@
 	omap2_set_globals_tap(&omap4_globals);
 	omap2_set_globals_control(&omap4_globals);
 	omap2_set_globals_prcm(&omap4_globals);
-	omap2_set_globals_uart(&omap4_globals);
 }
 #endif
 
diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c
index d1920be..8e88e0e 100644
--- a/arch/arm/plat-omap/devices.c
+++ b/arch/arm/plat-omap/devices.c
@@ -232,46 +232,6 @@
 static inline void omap_init_uwire(void) {}
 #endif
 
-/*-------------------------------------------------------------------------*/
-
-#if	defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE)
-
-static struct resource wdt_resources[] = {
-	{
-		.flags		= IORESOURCE_MEM,
-	},
-};
-
-static struct platform_device omap_wdt_device = {
-	.name	   = "omap_wdt",
-	.id	     = -1,
-	.num_resources	= ARRAY_SIZE(wdt_resources),
-	.resource	= wdt_resources,
-};
-
-static void omap_init_wdt(void)
-{
-	if (cpu_is_omap16xx())
-		wdt_resources[0].start = 0xfffeb000;
-	else if (cpu_is_omap2420())
-		wdt_resources[0].start = 0x48022000; /* WDT2 */
-	else if (cpu_is_omap2430())
-		wdt_resources[0].start = 0x49016000; /* WDT2 */
-	else if (cpu_is_omap343x())
-		wdt_resources[0].start = 0x48314000; /* WDT2 */
-	else if (cpu_is_omap44xx())
-		wdt_resources[0].start = 0x4a314000;
-	else
-		return;
-
-	wdt_resources[0].end = wdt_resources[0].start + 0x4f;
-
-	(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):
@@ -300,7 +260,6 @@
 	omap_init_rng();
 	omap_init_mcpdm();
 	omap_init_uwire();
-	omap_init_wdt();
 	return 0;
 }
 arch_initcall(omap_init_devices);
diff --git a/arch/arm/plat-omap/include/plat/common.h b/arch/arm/plat-omap/include/plat/common.h
index 2d8f98d..a9d69a0 100644
--- a/arch/arm/plat-omap/include/plat/common.h
+++ b/arch/arm/plat-omap/include/plat/common.h
@@ -67,7 +67,6 @@
 void omap2_set_globals_sdrc(struct omap_globals *);
 void omap2_set_globals_control(struct omap_globals *);
 void omap2_set_globals_prcm(struct omap_globals *);
-void omap2_set_globals_uart(struct omap_globals *);
 
 void omap3_map_io(void);
 
diff --git a/arch/arm/plat-omap/include/plat/dma.h b/arch/arm/plat-omap/include/plat/dma.h
index af3a039..098f154 100644
--- a/arch/arm/plat-omap/include/plat/dma.h
+++ b/arch/arm/plat-omap/include/plat/dma.h
@@ -319,6 +319,8 @@
 #define OMAP34XX_DMA_USIM_TX		79	/* S_DMA_78 */
 #define OMAP34XX_DMA_USIM_RX		80	/* S_DMA_79 */
 
+#define OMAP36XX_DMA_UART4_TX		81	/* S_DMA_80 */
+#define OMAP36XX_DMA_UART4_RX		82	/* S_DMA_81 */
 /*----------------------------------------------------------------------------*/
 
 #define OMAP1_DMA_TOUT_IRQ		(1 << 0)
diff --git a/arch/arm/plat-omap/include/plat/irqs.h b/arch/arm/plat-omap/include/plat/irqs.h
index c01d9f0..65e20a6 100644
--- a/arch/arm/plat-omap/include/plat/irqs.h
+++ b/arch/arm/plat-omap/include/plat/irqs.h
@@ -345,6 +345,8 @@
 #define INT_34XX_MMC3_IRQ	94
 #define INT_34XX_GPT12_IRQ	95
 
+#define INT_36XX_UART4_IRQ	80
+
 #define INT_35XX_HECC0_IRQ		24
 #define INT_35XX_HECC1_IRQ		28
 #define INT_35XX_EMAC_C0_RXTHRESH_IRQ	67
diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
new file mode 100644
index 0000000..0d6f076
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/omap-serial.h
@@ -0,0 +1,129 @@
+/*
+ * Driver for OMAP-UART controller.
+ * Based on drivers/serial/8250.c
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * Authors:
+ *	Govindraj R	<govindraj.raja@ti.com>
+ *	Thara Gopinath	<thara@ti.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.
+ */
+
+#ifndef __OMAP_SERIAL_H__
+#define __OMAP_SERIAL_H__
+
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+
+#include <plat/control.h>
+#include <plat/mux.h>
+
+#define DRIVER_NAME	"omap-hsuart"
+
+/*
+ * Use tty device name as ttyO, [O -> OMAP]
+ * in bootargs we specify as console=ttyO0 if uart1
+ * is used as console uart.
+ */
+#define OMAP_SERIAL_NAME	"ttyO"
+
+#define OMAP_MDR1_DISABLE	0x07
+#define OMAP_MDR1_MODE13X	0x03
+#define OMAP_MDR1_MODE16X	0x00
+#define OMAP_MODE13X_SPEED	230400
+
+/*
+ * LCR = 0XBF: Switch to Configuration Mode B.
+ * In configuration mode b allow access
+ * to EFR,DLL,DLH.
+ * Reference OMAP TRM Chapter 17
+ * Section: 1.4.3 Mode Selection
+ */
+#define OMAP_UART_LCR_CONF_MDB	0XBF
+
+/* WER = 0x7F
+ * Enable module level wakeup in WER reg
+ */
+#define OMAP_UART_WER_MOD_WKUP	0X7F
+
+/* Enable XON/XOFF flow control on output */
+#define OMAP_UART_SW_TX		0x04
+
+/* Enable XON/XOFF flow control on input */
+#define OMAP_UART_SW_RX		0x04
+
+#define OMAP_UART_SYSC_RESET	0X07
+#define OMAP_UART_TCR_TRIG	0X0F
+#define OMAP_UART_SW_CLR	0XF0
+#define OMAP_UART_FIFO_CLR	0X06
+
+#define OMAP_UART_DMA_CH_FREE	-1
+
+#define RX_TIMEOUT		(3 * HZ)
+#define OMAP_MAX_HSUART_PORTS	4
+
+#define MSR_SAVE_FLAGS		UART_MSR_ANY_DELTA
+
+struct omap_uart_port_info {
+	bool			dma_enabled;	/* To specify DMA Mode */
+	unsigned int		uartclk;	/* UART clock rate */
+	void __iomem		*membase;	/* ioremap cookie or NULL */
+	resource_size_t		mapbase;	/* resource base */
+	unsigned long		irqflags;	/* request_irq flags */
+	upf_t			flags;		/* UPF_* flags */
+};
+
+struct uart_omap_dma {
+	u8			uart_dma_tx;
+	u8			uart_dma_rx;
+	int			rx_dma_channel;
+	int			tx_dma_channel;
+	dma_addr_t		rx_buf_dma_phys;
+	dma_addr_t		tx_buf_dma_phys;
+	unsigned int		uart_base;
+	/*
+	 * Buffer for rx dma.It is not required for tx because the buffer
+	 * comes from port structure.
+	 */
+	unsigned char		*rx_buf;
+	unsigned int		prev_rx_dma_pos;
+	int			tx_buf_size;
+	int			tx_dma_used;
+	int			rx_dma_used;
+	spinlock_t		tx_lock;
+	spinlock_t		rx_lock;
+	/* timer to poll activity on rx dma */
+	struct timer_list	rx_timer;
+	int			rx_buf_size;
+	int			rx_timeout;
+};
+
+struct uart_omap_port {
+	struct uart_port	port;
+	struct uart_omap_dma	uart_dma;
+	struct platform_device	*pdev;
+
+	unsigned char		ier;
+	unsigned char		lcr;
+	unsigned char		mcr;
+	unsigned char		fcr;
+	unsigned char		efr;
+
+	int			use_dma;
+	/*
+	 * Some bits in registers are cleared on a read, so they must
+	 * be saved whenever the register is read but the bits will not
+	 * be immediately processed.
+	 */
+	unsigned int		lsr_break_flag;
+	unsigned char		msr_saved_flags;
+	char			name[20];
+	unsigned long		port_activity;
+};
+
+#endif /* __OMAP_SERIAL_H__ */
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 12900f7..8d8b975 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1416,6 +1416,33 @@
 	  Currently, only 8250 compatible ports are supported, but
 	  others can easily be added.
 
+config SERIAL_OMAP
+	tristate "OMAP serial port support"
+	depends on ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4
+	select SERIAL_CORE
+	help
+	  If you have a machine based on an Texas Instruments OMAP CPU you
+	  can enable its onboard serial ports by enabling this option.
+
+	  By enabling this option you take advantage of dma feature available
+	  with the omap-serial driver. DMA support can be enabled from platform
+	  data.
+
+config SERIAL_OMAP_CONSOLE
+	bool "Console on OMAP serial port"
+	depends on SERIAL_OMAP
+	select SERIAL_CORE_CONSOLE
+	help
+	  Select this option if you would like to use omap serial port as
+	  console.
+
+	  Even if you say Y here, the currently visible virtual console
+	  (/dev/tty0) will still be used as the system console by default, but
+	  you can alter that using a kernel command line option such as
+	  "console=ttyOx". (Try "man bootparam" or see the documentation of
+	  your boot loader about how to pass options to the kernel at
+	  boot time.)
+
 config SERIAL_OF_PLATFORM_NWPSERIAL
 	tristate "NWP serial port driver"
 	depends on PPC_OF && PPC_DCR
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 1ca4fd5..c570576 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -88,3 +88,4 @@
 obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o
 obj-$(CONFIG_SERIAL_MRST_MAX3110)	+= mrst_max3110.o
 obj-$(CONFIG_SERIAL_MFD_HSU)	+= mfd.o
+obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o
diff --git a/drivers/serial/omap-serial.c b/drivers/serial/omap-serial.c
new file mode 100644
index 0000000..2ee1d32
--- /dev/null
+++ b/drivers/serial/omap-serial.c
@@ -0,0 +1,1333 @@
+/*
+ * Driver for OMAP-UART controller.
+ * Based on drivers/serial/8250.c
+ *
+ * Copyright (C) 2010 Texas Instruments.
+ *
+ * Authors:
+ *	Govindraj R	<govindraj.raja@ti.com>
+ *	Thara Gopinath	<thara@ti.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.
+ *
+ * Note: This driver is made seperate from 8250 driver as we cannot
+ * over load 8250 driver with omap platform specific configuration for
+ * features like DMA, it makes easier to implement features like DMA and
+ * hardware flow control and software flow control configuration with
+ * this driver as required for the omap-platform.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/serial_reg.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/serial_core.h>
+#include <linux/irq.h>
+
+#include <plat/dma.h>
+#include <plat/dmtimer.h>
+#include <plat/omap-serial.h>
+
+static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
+
+/* Forward declaration of functions */
+static void uart_tx_dma_callback(int lch, u16 ch_status, void *data);
+static void serial_omap_rx_timeout(unsigned long uart_no);
+static int serial_omap_start_rxdma(struct uart_omap_port *up);
+
+static inline unsigned int serial_in(struct uart_omap_port *up, int offset)
+{
+	offset <<= up->port.regshift;
+	return readw(up->port.membase + offset);
+}
+
+static inline void serial_out(struct uart_omap_port *up, int offset, int value)
+{
+	offset <<= up->port.regshift;
+	writew(value, up->port.membase + offset);
+}
+
+static inline void serial_omap_clear_fifos(struct uart_omap_port *up)
+{
+	serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+	serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+		       UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+	serial_out(up, UART_FCR, 0);
+}
+
+/*
+ * serial_omap_get_divisor - calculate divisor value
+ * @port: uart port info
+ * @baud: baudrate for which divisor needs to be calculated.
+ *
+ * We have written our own function to get the divisor so as to support
+ * 13x mode. 3Mbps Baudrate as an different divisor.
+ * Reference OMAP TRM Chapter 17:
+ * Table 17-1. UART Mode Baud Rates, Divisor Values, and Error Rates
+ * referring to oversampling - divisor value
+ * baudrate 460,800 to 3,686,400 all have divisor 13
+ * except 3,000,000 which has divisor value 16
+ */
+static unsigned int
+serial_omap_get_divisor(struct uart_port *port, unsigned int baud)
+{
+	unsigned int divisor;
+
+	if (baud > OMAP_MODE13X_SPEED && baud != 3000000)
+		divisor = 13;
+	else
+		divisor = 16;
+	return port->uartclk/(baud * divisor);
+}
+
+static void serial_omap_stop_rxdma(struct uart_omap_port *up)
+{
+	if (up->uart_dma.rx_dma_used) {
+		del_timer(&up->uart_dma.rx_timer);
+		omap_stop_dma(up->uart_dma.rx_dma_channel);
+		omap_free_dma(up->uart_dma.rx_dma_channel);
+		up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
+		up->uart_dma.rx_dma_used = false;
+	}
+}
+
+static void serial_omap_enable_ms(struct uart_port *port)
+{
+	struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+	dev_dbg(up->port.dev, "serial_omap_enable_ms+%d\n", up->pdev->id);
+	up->ier |= UART_IER_MSI;
+	serial_out(up, UART_IER, up->ier);
+}
+
+static void serial_omap_stop_tx(struct uart_port *port)
+{
+	struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+	if (up->use_dma &&
+		up->uart_dma.tx_dma_channel != OMAP_UART_DMA_CH_FREE) {
+		/*
+		 * Check if dma is still active. If yes do nothing,
+		 * return. Else stop dma
+		 */
+		if (omap_get_dma_active_status(up->uart_dma.tx_dma_channel))
+			return;
+		omap_stop_dma(up->uart_dma.tx_dma_channel);
+		omap_free_dma(up->uart_dma.tx_dma_channel);
+		up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE;
+	}
+
+	if (up->ier & UART_IER_THRI) {
+		up->ier &= ~UART_IER_THRI;
+		serial_out(up, UART_IER, up->ier);
+	}
+}
+
+static void serial_omap_stop_rx(struct uart_port *port)
+{
+	struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+	if (up->use_dma)
+		serial_omap_stop_rxdma(up);
+	up->ier &= ~UART_IER_RLSI;
+	up->port.read_status_mask &= ~UART_LSR_DR;
+	serial_out(up, UART_IER, up->ier);
+}
+
+static inline void receive_chars(struct uart_omap_port *up, int *status)
+{
+	struct tty_struct *tty = up->port.state->port.tty;
+	unsigned int flag;
+	unsigned char ch, lsr = *status;
+	int max_count = 256;
+
+	do {
+		if (likely(lsr & UART_LSR_DR))
+			ch = serial_in(up, UART_RX);
+		flag = TTY_NORMAL;
+		up->port.icount.rx++;
+
+		if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
+			/*
+			 * For statistics only
+			 */
+			if (lsr & UART_LSR_BI) {
+				lsr &= ~(UART_LSR_FE | UART_LSR_PE);
+				up->port.icount.brk++;
+				/*
+				 * We do the SysRQ and SAK checking
+				 * here because otherwise the break
+				 * may get masked by ignore_status_mask
+				 * or read_status_mask.
+				 */
+				if (uart_handle_break(&up->port))
+					goto ignore_char;
+			} else if (lsr & UART_LSR_PE) {
+				up->port.icount.parity++;
+			} else if (lsr & UART_LSR_FE) {
+				up->port.icount.frame++;
+			}
+
+			if (lsr & UART_LSR_OE)
+				up->port.icount.overrun++;
+
+			/*
+			 * Mask off conditions which should be ignored.
+			 */
+			lsr &= up->port.read_status_mask;
+
+#ifdef CONFIG_SERIAL_OMAP_CONSOLE
+			if (up->port.line == up->port.cons->index) {
+				/* Recover the break flag from console xmit */
+				lsr |= up->lsr_break_flag;
+				up->lsr_break_flag = 0;
+			}
+#endif
+			if (lsr & UART_LSR_BI)
+				flag = TTY_BREAK;
+			else if (lsr & UART_LSR_PE)
+				flag = TTY_PARITY;
+			else if (lsr & UART_LSR_FE)
+				flag = TTY_FRAME;
+		}
+
+		if (uart_handle_sysrq_char(&up->port, ch))
+			goto ignore_char;
+		uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);
+ignore_char:
+		lsr = serial_in(up, UART_LSR);
+	} while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0));
+	spin_unlock(&up->port.lock);
+	tty_flip_buffer_push(tty);
+	spin_lock(&up->port.lock);
+}
+
+static void transmit_chars(struct uart_omap_port *up)
+{
+	struct circ_buf *xmit = &up->port.state->xmit;
+	int count;
+
+	if (up->port.x_char) {
+		serial_out(up, UART_TX, up->port.x_char);
+		up->port.icount.tx++;
+		up->port.x_char = 0;
+		return;
+	}
+	if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+		serial_omap_stop_tx(&up->port);
+		return;
+	}
+	count = up->port.fifosize / 4;
+	do {
+		serial_out(up, UART_TX, xmit->buf[xmit->tail]);
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		up->port.icount.tx++;
+		if (uart_circ_empty(xmit))
+			break;
+	} while (--count > 0);
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(&up->port);
+
+	if (uart_circ_empty(xmit))
+		serial_omap_stop_tx(&up->port);
+}
+
+static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up)
+{
+	if (!(up->ier & UART_IER_THRI)) {
+		up->ier |= UART_IER_THRI;
+		serial_out(up, UART_IER, up->ier);
+	}
+}
+
+static void serial_omap_start_tx(struct uart_port *port)
+{
+	struct uart_omap_port *up = (struct uart_omap_port *)port;
+	struct circ_buf *xmit;
+	unsigned int start;
+	int ret = 0;
+
+	if (!up->use_dma) {
+		serial_omap_enable_ier_thri(up);
+		return;
+	}
+
+	if (up->uart_dma.tx_dma_used)
+		return;
+
+	xmit = &up->port.state->xmit;
+
+	if (up->uart_dma.tx_dma_channel == OMAP_UART_DMA_CH_FREE) {
+		ret = omap_request_dma(up->uart_dma.uart_dma_tx,
+				"UART Tx DMA",
+				(void *)uart_tx_dma_callback, up,
+				&(up->uart_dma.tx_dma_channel));
+
+		if (ret < 0) {
+			serial_omap_enable_ier_thri(up);
+			return;
+		}
+	}
+	spin_lock(&(up->uart_dma.tx_lock));
+	up->uart_dma.tx_dma_used = true;
+	spin_unlock(&(up->uart_dma.tx_lock));
+
+	start = up->uart_dma.tx_buf_dma_phys +
+				(xmit->tail & (UART_XMIT_SIZE - 1));
+
+	up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit);
+	/*
+	 * It is a circular buffer. See if the buffer has wounded back.
+	 * If yes it will have to be transferred in two separate dma
+	 * transfers
+	 */
+	if (start + up->uart_dma.tx_buf_size >=
+			up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE)
+		up->uart_dma.tx_buf_size =
+			(up->uart_dma.tx_buf_dma_phys +
+			UART_XMIT_SIZE) - start;
+
+	omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0,
+				OMAP_DMA_AMODE_CONSTANT,
+				up->uart_dma.uart_base, 0, 0);
+	omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0,
+				OMAP_DMA_AMODE_POST_INC, start, 0, 0);
+	omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel,
+				OMAP_DMA_DATA_TYPE_S8,
+				up->uart_dma.tx_buf_size, 1,
+				OMAP_DMA_SYNC_ELEMENT,
+				up->uart_dma.uart_dma_tx, 0);
+	/* FIXME: Cache maintenance needed here? */
+	omap_start_dma(up->uart_dma.tx_dma_channel);
+}
+
+static unsigned int check_modem_status(struct uart_omap_port *up)
+{
+	unsigned int status;
+
+	status = serial_in(up, UART_MSR);
+	status |= up->msr_saved_flags;
+	up->msr_saved_flags = 0;
+	if ((status & UART_MSR_ANY_DELTA) == 0)
+		return status;
+
+	if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&
+	    up->port.state != NULL) {
+		if (status & UART_MSR_TERI)
+			up->port.icount.rng++;
+		if (status & UART_MSR_DDSR)
+			up->port.icount.dsr++;
+		if (status & UART_MSR_DDCD)
+			uart_handle_dcd_change
+				(&up->port, status & UART_MSR_DCD);
+		if (status & UART_MSR_DCTS)
+			uart_handle_cts_change
+				(&up->port, status & UART_MSR_CTS);
+		wake_up_interruptible(&up->port.state->port.delta_msr_wait);
+	}
+
+	return status;
+}
+
+/**
+ * serial_omap_irq() - This handles the interrupt from one port
+ * @irq: uart port irq number
+ * @dev_id: uart port info
+ */
+static inline irqreturn_t serial_omap_irq(int irq, void *dev_id)
+{
+	struct uart_omap_port *up = dev_id;
+	unsigned int iir, lsr;
+	unsigned long flags;
+
+	iir = serial_in(up, UART_IIR);
+	if (iir & UART_IIR_NO_INT)
+		return IRQ_NONE;
+
+	spin_lock_irqsave(&up->port.lock, flags);
+	lsr = serial_in(up, UART_LSR);
+	if (iir & UART_IIR_RLSI) {
+		if (!up->use_dma) {
+			if (lsr & UART_LSR_DR)
+				receive_chars(up, &lsr);
+		} else {
+			up->ier &= ~(UART_IER_RDI | UART_IER_RLSI);
+			serial_out(up, UART_IER, up->ier);
+			if ((serial_omap_start_rxdma(up) != 0) &&
+					(lsr & UART_LSR_DR))
+				receive_chars(up, &lsr);
+		}
+	}
+
+	check_modem_status(up);
+	if ((lsr & UART_LSR_THRE) && (iir & UART_IIR_THRI))
+		transmit_chars(up);
+
+	spin_unlock_irqrestore(&up->port.lock, flags);
+	up->port_activity = jiffies;
+	return IRQ_HANDLED;
+}
+
+static unsigned int serial_omap_tx_empty(struct uart_port *port)
+{
+	struct uart_omap_port *up = (struct uart_omap_port *)port;
+	unsigned long flags = 0;
+	unsigned int ret = 0;
+
+	dev_dbg(up->port.dev, "serial_omap_tx_empty+%d\n", up->pdev->id);
+	spin_lock_irqsave(&up->port.lock, flags);
+	ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+	spin_unlock_irqrestore(&up->port.lock, flags);
+
+	return ret;
+}
+
+static unsigned int serial_omap_get_mctrl(struct uart_port *port)
+{
+	struct uart_omap_port *up = (struct uart_omap_port *)port;
+	unsigned char status;
+	unsigned int ret = 0;
+
+	status = check_modem_status(up);
+	dev_dbg(up->port.dev, "serial_omap_get_mctrl+%d\n", up->pdev->id);
+
+	if (status & UART_MSR_DCD)
+		ret |= TIOCM_CAR;
+	if (status & UART_MSR_RI)
+		ret |= TIOCM_RNG;
+	if (status & UART_MSR_DSR)
+		ret |= TIOCM_DSR;
+	if (status & UART_MSR_CTS)
+		ret |= TIOCM_CTS;
+	return ret;
+}
+
+static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	struct uart_omap_port *up = (struct uart_omap_port *)port;
+	unsigned char mcr = 0;
+
+	dev_dbg(up->port.dev, "serial_omap_set_mctrl+%d\n", up->pdev->id);
+	if (mctrl & TIOCM_RTS)
+		mcr |= UART_MCR_RTS;
+	if (mctrl & TIOCM_DTR)
+		mcr |= UART_MCR_DTR;
+	if (mctrl & TIOCM_OUT1)
+		mcr |= UART_MCR_OUT1;
+	if (mctrl & TIOCM_OUT2)
+		mcr |= UART_MCR_OUT2;
+	if (mctrl & TIOCM_LOOP)
+		mcr |= UART_MCR_LOOP;
+
+	mcr |= up->mcr;
+	serial_out(up, UART_MCR, mcr);
+}
+
+static void serial_omap_break_ctl(struct uart_port *port, int break_state)
+{
+	struct uart_omap_port *up = (struct uart_omap_port *)port;
+	unsigned long flags = 0;
+
+	dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->pdev->id);
+	spin_lock_irqsave(&up->port.lock, flags);
+	if (break_state == -1)
+		up->lcr |= UART_LCR_SBC;
+	else
+		up->lcr &= ~UART_LCR_SBC;
+	serial_out(up, UART_LCR, up->lcr);
+	spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static int serial_omap_startup(struct uart_port *port)
+{
+	struct uart_omap_port *up = (struct uart_omap_port *)port;
+	unsigned long flags = 0;
+	int retval;
+
+	/*
+	 * Allocate the IRQ
+	 */
+	retval = request_irq(up->port.irq, serial_omap_irq, up->port.irqflags,
+				up->name, up);
+	if (retval)
+		return retval;
+
+	dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->pdev->id);
+
+	/*
+	 * Clear the FIFO buffers and disable them.
+	 * (they will be reenabled in set_termios())
+	 */
+	serial_omap_clear_fifos(up);
+	/* For Hardware flow control */
+	serial_out(up, UART_MCR, UART_MCR_RTS);
+
+	/*
+	 * Clear the interrupt registers.
+	 */
+	(void) serial_in(up, UART_LSR);
+	if (serial_in(up, UART_LSR) & UART_LSR_DR)
+		(void) serial_in(up, UART_RX);
+	(void) serial_in(up, UART_IIR);
+	(void) serial_in(up, UART_MSR);
+
+	/*
+	 * Now, initialize the UART
+	 */
+	serial_out(up, UART_LCR, UART_LCR_WLEN8);
+	spin_lock_irqsave(&up->port.lock, flags);
+	/*
+	 * Most PC uarts need OUT2 raised to enable interrupts.
+	 */
+	up->port.mctrl |= TIOCM_OUT2;
+	serial_omap_set_mctrl(&up->port, up->port.mctrl);
+	spin_unlock_irqrestore(&up->port.lock, flags);
+
+	up->msr_saved_flags = 0;
+	if (up->use_dma) {
+		free_page((unsigned long)up->port.state->xmit.buf);
+		up->port.state->xmit.buf = dma_alloc_coherent(NULL,
+			UART_XMIT_SIZE,
+			(dma_addr_t *)&(up->uart_dma.tx_buf_dma_phys),
+			0);
+		init_timer(&(up->uart_dma.rx_timer));
+		up->uart_dma.rx_timer.function = serial_omap_rx_timeout;
+		up->uart_dma.rx_timer.data = up->pdev->id;
+		/* Currently the buffer size is 4KB. Can increase it */
+		up->uart_dma.rx_buf = dma_alloc_coherent(NULL,
+			up->uart_dma.rx_buf_size,
+			(dma_addr_t *)&(up->uart_dma.rx_buf_dma_phys), 0);
+	}
+	/*
+	 * Finally, enable interrupts. Note: Modem status interrupts
+	 * are set via set_termios(), which will be occurring imminently
+	 * anyway, so we don't enable them here.
+	 */
+	up->ier = UART_IER_RLSI | UART_IER_RDI;
+	serial_out(up, UART_IER, up->ier);
+
+	up->port_activity = jiffies;
+	return 0;
+}
+
+static void serial_omap_shutdown(struct uart_port *port)
+{
+	struct uart_omap_port *up = (struct uart_omap_port *)port;
+	unsigned long flags = 0;
+
+	dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->pdev->id);
+	/*
+	 * Disable interrupts from this port
+	 */
+	up->ier = 0;
+	serial_out(up, UART_IER, 0);
+
+	spin_lock_irqsave(&up->port.lock, flags);
+	up->port.mctrl &= ~TIOCM_OUT2;
+	serial_omap_set_mctrl(&up->port, up->port.mctrl);
+	spin_unlock_irqrestore(&up->port.lock, flags);
+
+	/*
+	 * Disable break condition and FIFOs
+	 */
+	serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
+	serial_omap_clear_fifos(up);
+
+	/*
+	 * Read data port to reset things, and then free the irq
+	 */
+	if (serial_in(up, UART_LSR) & UART_LSR_DR)
+		(void) serial_in(up, UART_RX);
+	if (up->use_dma) {
+		dma_free_coherent(up->port.dev,
+			UART_XMIT_SIZE,	up->port.state->xmit.buf,
+			up->uart_dma.tx_buf_dma_phys);
+		up->port.state->xmit.buf = NULL;
+		serial_omap_stop_rx(port);
+		dma_free_coherent(up->port.dev,
+			up->uart_dma.rx_buf_size, up->uart_dma.rx_buf,
+			up->uart_dma.rx_buf_dma_phys);
+		up->uart_dma.rx_buf = NULL;
+	}
+	free_irq(up->port.irq, up);
+}
+
+static inline void
+serial_omap_configure_xonxoff
+		(struct uart_omap_port *up, struct ktermios *termios)
+{
+	unsigned char efr = 0;
+
+	up->lcr = serial_in(up, UART_LCR);
+	serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+	up->efr = serial_in(up, UART_EFR);
+	serial_out(up, UART_EFR, up->efr & ~UART_EFR_ECB);
+
+	serial_out(up, UART_XON1, termios->c_cc[VSTART]);
+	serial_out(up, UART_XOFF1, termios->c_cc[VSTOP]);
+
+	/* clear SW control mode bits */
+	efr = up->efr;
+	efr &= OMAP_UART_SW_CLR;
+
+	/*
+	 * IXON Flag:
+	 * Enable XON/XOFF flow control on output.
+	 * Transmit XON1, XOFF1
+	 */
+	if (termios->c_iflag & IXON)
+		efr |= OMAP_UART_SW_TX;
+
+	/*
+	 * IXOFF Flag:
+	 * Enable XON/XOFF flow control on input.
+	 * Receiver compares XON1, XOFF1.
+	 */
+	if (termios->c_iflag & IXOFF)
+		efr |= OMAP_UART_SW_RX;
+
+	serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+	serial_out(up, UART_LCR, UART_LCR_DLAB);
+
+	up->mcr = serial_in(up, UART_MCR);
+
+	/*
+	 * IXANY Flag:
+	 * Enable any character to restart output.
+	 * Operation resumes after receiving any
+	 * character after recognition of the XOFF character
+	 */
+	if (termios->c_iflag & IXANY)
+		up->mcr |= UART_MCR_XONANY;
+
+	serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
+	serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+	serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
+	/* Enable special char function UARTi.EFR_REG[5] and
+	 * load the new software flow control mode IXON or IXOFF
+	 * and restore the UARTi.EFR_REG[4] ENHANCED_EN value.
+	 */
+	serial_out(up, UART_EFR, efr | UART_EFR_SCD);
+	serial_out(up, UART_LCR, UART_LCR_DLAB);
+
+	serial_out(up, UART_MCR, up->mcr & ~UART_MCR_TCRTLR);
+	serial_out(up, UART_LCR, up->lcr);
+}
+
+static void
+serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
+			struct ktermios *old)
+{
+	struct uart_omap_port *up = (struct uart_omap_port *)port;
+	unsigned char cval = 0;
+	unsigned char efr = 0;
+	unsigned long flags = 0;
+	unsigned int baud, quot;
+
+	switch (termios->c_cflag & CSIZE) {
+	case CS5:
+		cval = UART_LCR_WLEN5;
+		break;
+	case CS6:
+		cval = UART_LCR_WLEN6;
+		break;
+	case CS7:
+		cval = UART_LCR_WLEN7;
+		break;
+	default:
+	case CS8:
+		cval = UART_LCR_WLEN8;
+		break;
+	}
+
+	if (termios->c_cflag & CSTOPB)
+		cval |= UART_LCR_STOP;
+	if (termios->c_cflag & PARENB)
+		cval |= UART_LCR_PARITY;
+	if (!(termios->c_cflag & PARODD))
+		cval |= UART_LCR_EPAR;
+
+	/*
+	 * Ask the core to calculate the divisor for us.
+	 */
+
+	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/13);
+	quot = serial_omap_get_divisor(port, baud);
+
+	up->fcr = UART_FCR_R_TRIG_01 | UART_FCR_T_TRIG_01 |
+			UART_FCR_ENABLE_FIFO;
+	if (up->use_dma)
+		up->fcr |= UART_FCR_DMA_SELECT;
+
+	/*
+	 * Ok, we're now changing the port state. Do it with
+	 * interrupts disabled.
+	 */
+	spin_lock_irqsave(&up->port.lock, flags);
+
+	/*
+	 * Update the per-port timeout.
+	 */
+	uart_update_timeout(port, termios->c_cflag, baud);
+
+	up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+	if (termios->c_iflag & INPCK)
+		up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+	if (termios->c_iflag & (BRKINT | PARMRK))
+		up->port.read_status_mask |= UART_LSR_BI;
+
+	/*
+	 * Characters to ignore
+	 */
+	up->port.ignore_status_mask = 0;
+	if (termios->c_iflag & IGNPAR)
+		up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+	if (termios->c_iflag & IGNBRK) {
+		up->port.ignore_status_mask |= UART_LSR_BI;
+		/*
+		 * If we're ignoring parity and break indicators,
+		 * ignore overruns too (for real raw support).
+		 */
+		if (termios->c_iflag & IGNPAR)
+			up->port.ignore_status_mask |= UART_LSR_OE;
+	}
+
+	/*
+	 * ignore all characters if CREAD is not set
+	 */
+	if ((termios->c_cflag & CREAD) == 0)
+		up->port.ignore_status_mask |= UART_LSR_DR;
+
+	/*
+	 * Modem status interrupts
+	 */
+	up->ier &= ~UART_IER_MSI;
+	if (UART_ENABLE_MS(&up->port, termios->c_cflag))
+		up->ier |= UART_IER_MSI;
+	serial_out(up, UART_IER, up->ier);
+	serial_out(up, UART_LCR, cval);		/* reset DLAB */
+
+	/* FIFOs and DMA Settings */
+
+	/* FCR can be changed only when the
+	 * baud clock is not running
+	 * DLL_REG and DLH_REG set to 0.
+	 */
+	serial_out(up, UART_LCR, UART_LCR_DLAB);
+	serial_out(up, UART_DLL, 0);
+	serial_out(up, UART_DLM, 0);
+	serial_out(up, UART_LCR, 0);
+
+	serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+
+	up->efr = serial_in(up, UART_EFR);
+	serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+
+	serial_out(up, UART_LCR, UART_LCR_DLAB);
+	up->mcr = serial_in(up, UART_MCR);
+	serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
+	/* FIFO ENABLE, DMA MODE */
+	serial_out(up, UART_FCR, up->fcr);
+	serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+
+	if (up->use_dma) {
+		serial_out(up, UART_TI752_TLR, 0);
+		serial_out(up, UART_OMAP_SCR,
+			(UART_FCR_TRIGGER_4 | UART_FCR_TRIGGER_8));
+	}
+
+	serial_out(up, UART_EFR, up->efr);
+	serial_out(up, UART_LCR, UART_LCR_DLAB);
+	serial_out(up, UART_MCR, up->mcr);
+
+	/* Protocol, Baud Rate, and Interrupt Settings */
+
+	serial_out(up, UART_OMAP_MDR1, OMAP_MDR1_DISABLE);
+	serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+
+	up->efr = serial_in(up, UART_EFR);
+	serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+
+	serial_out(up, UART_LCR, 0);
+	serial_out(up, UART_IER, 0);
+	serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+
+	serial_out(up, UART_DLL, quot & 0xff);          /* LS of divisor */
+	serial_out(up, UART_DLM, quot >> 8);            /* MS of divisor */
+
+	serial_out(up, UART_LCR, 0);
+	serial_out(up, UART_IER, up->ier);
+	serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+
+	serial_out(up, UART_EFR, up->efr);
+	serial_out(up, UART_LCR, cval);
+
+	if (baud > 230400 && baud != 3000000)
+		serial_out(up, UART_OMAP_MDR1, OMAP_MDR1_MODE13X);
+	else
+		serial_out(up, UART_OMAP_MDR1, OMAP_MDR1_MODE16X);
+
+	/* Hardware Flow Control Configuration */
+
+	if (termios->c_cflag & CRTSCTS) {
+		efr |= (UART_EFR_CTS | UART_EFR_RTS);
+		serial_out(up, UART_LCR, UART_LCR_DLAB);
+
+		up->mcr = serial_in(up, UART_MCR);
+		serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
+
+		serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+		up->efr = serial_in(up, UART_EFR);
+		serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+
+		serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
+		serial_out(up, UART_EFR, efr); /* Enable AUTORTS and AUTOCTS */
+		serial_out(up, UART_LCR, UART_LCR_DLAB);
+		serial_out(up, UART_MCR, up->mcr | UART_MCR_RTS);
+		serial_out(up, UART_LCR, cval);
+	}
+
+	serial_omap_set_mctrl(&up->port, up->port.mctrl);
+	/* Software Flow Control Configuration */
+	if (termios->c_iflag & (IXON | IXOFF))
+		serial_omap_configure_xonxoff(up, termios);
+
+	spin_unlock_irqrestore(&up->port.lock, flags);
+	dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->pdev->id);
+}
+
+static void
+serial_omap_pm(struct uart_port *port, unsigned int state,
+	       unsigned int oldstate)
+{
+	struct uart_omap_port *up = (struct uart_omap_port *)port;
+	unsigned char efr;
+
+	dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->pdev->id);
+	serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+	efr = serial_in(up, UART_EFR);
+	serial_out(up, UART_EFR, efr | UART_EFR_ECB);
+	serial_out(up, UART_LCR, 0);
+
+	serial_out(up, UART_IER, (state != 0) ? UART_IERX_SLEEP : 0);
+	serial_out(up, UART_LCR, OMAP_UART_LCR_CONF_MDB);
+	serial_out(up, UART_EFR, efr);
+	serial_out(up, UART_LCR, 0);
+	/* Enable module level wake up */
+	serial_out(up, UART_OMAP_WER,
+		(state != 0) ? OMAP_UART_WER_MOD_WKUP : 0);
+}
+
+static void serial_omap_release_port(struct uart_port *port)
+{
+	dev_dbg(port->dev, "serial_omap_release_port+\n");
+}
+
+static int serial_omap_request_port(struct uart_port *port)
+{
+	dev_dbg(port->dev, "serial_omap_request_port+\n");
+	return 0;
+}
+
+static void serial_omap_config_port(struct uart_port *port, int flags)
+{
+	struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+	dev_dbg(up->port.dev, "serial_omap_config_port+%d\n",
+							up->pdev->id);
+	up->port.type = PORT_OMAP;
+}
+
+static int
+serial_omap_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+	/* we don't want the core code to modify any port params */
+	dev_dbg(port->dev, "serial_omap_verify_port+\n");
+	return -EINVAL;
+}
+
+static const char *
+serial_omap_type(struct uart_port *port)
+{
+	struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+	dev_dbg(up->port.dev, "serial_omap_type+%d\n", up->pdev->id);
+	return up->name;
+}
+
+#ifdef CONFIG_SERIAL_OMAP_CONSOLE
+
+static struct uart_omap_port *serial_omap_console_ports[4];
+
+static struct uart_driver serial_omap_reg;
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+static inline void wait_for_xmitr(struct uart_omap_port *up)
+{
+	unsigned int status, tmout = 10000;
+
+	/* Wait up to 10ms for the character(s) to be sent. */
+	do {
+		status = serial_in(up, UART_LSR);
+
+		if (status & UART_LSR_BI)
+			up->lsr_break_flag = UART_LSR_BI;
+
+		if (--tmout == 0)
+			break;
+		udelay(1);
+	} while ((status & BOTH_EMPTY) != BOTH_EMPTY);
+
+	/* Wait up to 1s for flow control if necessary */
+	if (up->port.flags & UPF_CONS_FLOW) {
+		tmout = 1000000;
+		for (tmout = 1000000; tmout; tmout--) {
+			unsigned int msr = serial_in(up, UART_MSR);
+
+			up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
+			if (msr & UART_MSR_CTS)
+				break;
+
+			udelay(1);
+		}
+	}
+}
+
+static void serial_omap_console_putchar(struct uart_port *port, int ch)
+{
+	struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+	wait_for_xmitr(up);
+	serial_out(up, UART_TX, ch);
+}
+
+static void
+serial_omap_console_write(struct console *co, const char *s,
+		unsigned int count)
+{
+	struct uart_omap_port *up = serial_omap_console_ports[co->index];
+	unsigned long flags;
+	unsigned int ier;
+	int locked = 1;
+
+	local_irq_save(flags);
+	if (up->port.sysrq)
+		locked = 0;
+	else if (oops_in_progress)
+		locked = spin_trylock(&up->port.lock);
+	else
+		spin_lock(&up->port.lock);
+
+	/*
+	 * First save the IER then disable the interrupts
+	 */
+	ier = serial_in(up, UART_IER);
+	serial_out(up, UART_IER, 0);
+
+	uart_console_write(&up->port, s, count, serial_omap_console_putchar);
+
+	/*
+	 * Finally, wait for transmitter to become empty
+	 * and restore the IER
+	 */
+	wait_for_xmitr(up);
+	serial_out(up, UART_IER, ier);
+	/*
+	 * The receive handling will happen properly because the
+	 * receive ready bit will still be set; it is not cleared
+	 * on read.  However, modem control will not, we must
+	 * call it if we have saved something in the saved flags
+	 * while processing with interrupts off.
+	 */
+	if (up->msr_saved_flags)
+		check_modem_status(up);
+
+	if (locked)
+		spin_unlock(&up->port.lock);
+	local_irq_restore(flags);
+}
+
+static int __init
+serial_omap_console_setup(struct console *co, char *options)
+{
+	struct uart_omap_port *up;
+	int baud = 115200;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	if (serial_omap_console_ports[co->index] == NULL)
+		return -ENODEV;
+	up = serial_omap_console_ports[co->index];
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	return uart_set_options(&up->port, co, baud, parity, bits, flow);
+}
+
+static struct console serial_omap_console = {
+	.name		= OMAP_SERIAL_NAME,
+	.write		= serial_omap_console_write,
+	.device		= uart_console_device,
+	.setup		= serial_omap_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+	.data		= &serial_omap_reg,
+};
+
+static void serial_omap_add_console_port(struct uart_omap_port *up)
+{
+	serial_omap_console_ports[up->pdev->id] = up;
+}
+
+#define OMAP_CONSOLE	(&serial_omap_console)
+
+#else
+
+#define OMAP_CONSOLE	NULL
+
+static inline void serial_omap_add_console_port(struct uart_omap_port *up)
+{}
+
+#endif
+
+static struct uart_ops serial_omap_pops = {
+	.tx_empty	= serial_omap_tx_empty,
+	.set_mctrl	= serial_omap_set_mctrl,
+	.get_mctrl	= serial_omap_get_mctrl,
+	.stop_tx	= serial_omap_stop_tx,
+	.start_tx	= serial_omap_start_tx,
+	.stop_rx	= serial_omap_stop_rx,
+	.enable_ms	= serial_omap_enable_ms,
+	.break_ctl	= serial_omap_break_ctl,
+	.startup	= serial_omap_startup,
+	.shutdown	= serial_omap_shutdown,
+	.set_termios	= serial_omap_set_termios,
+	.pm		= serial_omap_pm,
+	.type		= serial_omap_type,
+	.release_port	= serial_omap_release_port,
+	.request_port	= serial_omap_request_port,
+	.config_port	= serial_omap_config_port,
+	.verify_port	= serial_omap_verify_port,
+};
+
+static struct uart_driver serial_omap_reg = {
+	.owner		= THIS_MODULE,
+	.driver_name	= "OMAP-SERIAL",
+	.dev_name	= OMAP_SERIAL_NAME,
+	.nr		= OMAP_MAX_HSUART_PORTS,
+	.cons		= OMAP_CONSOLE,
+};
+
+static int
+serial_omap_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct uart_omap_port *up = platform_get_drvdata(pdev);
+
+	if (up)
+		uart_suspend_port(&serial_omap_reg, &up->port);
+	return 0;
+}
+
+static int serial_omap_resume(struct platform_device *dev)
+{
+	struct uart_omap_port *up = platform_get_drvdata(dev);
+
+	if (up)
+		uart_resume_port(&serial_omap_reg, &up->port);
+	return 0;
+}
+
+static void serial_omap_rx_timeout(unsigned long uart_no)
+{
+	struct uart_omap_port *up = ui[uart_no];
+	unsigned int curr_dma_pos, curr_transmitted_size;
+	unsigned int ret = 0;
+
+	curr_dma_pos = omap_get_dma_dst_pos(up->uart_dma.rx_dma_channel);
+	if ((curr_dma_pos == up->uart_dma.prev_rx_dma_pos) ||
+			     (curr_dma_pos == 0)) {
+		if (jiffies_to_msecs(jiffies - up->port_activity) <
+							RX_TIMEOUT) {
+			mod_timer(&up->uart_dma.rx_timer, jiffies +
+				usecs_to_jiffies(up->uart_dma.rx_timeout));
+		} else {
+			serial_omap_stop_rxdma(up);
+			up->ier |= (UART_IER_RDI | UART_IER_RLSI);
+			serial_out(up, UART_IER, up->ier);
+		}
+		return;
+	}
+
+	curr_transmitted_size = curr_dma_pos -
+					up->uart_dma.prev_rx_dma_pos;
+	up->port.icount.rx += curr_transmitted_size;
+	tty_insert_flip_string(up->port.state->port.tty,
+			up->uart_dma.rx_buf +
+			(up->uart_dma.prev_rx_dma_pos -
+			up->uart_dma.rx_buf_dma_phys),
+			curr_transmitted_size);
+	tty_flip_buffer_push(up->port.state->port.tty);
+	up->uart_dma.prev_rx_dma_pos = curr_dma_pos;
+	if (up->uart_dma.rx_buf_size +
+			up->uart_dma.rx_buf_dma_phys == curr_dma_pos) {
+		ret = serial_omap_start_rxdma(up);
+		if (ret < 0) {
+			serial_omap_stop_rxdma(up);
+			up->ier |= (UART_IER_RDI | UART_IER_RLSI);
+			serial_out(up, UART_IER, up->ier);
+		}
+	} else  {
+		mod_timer(&up->uart_dma.rx_timer, jiffies +
+			usecs_to_jiffies(up->uart_dma.rx_timeout));
+	}
+	up->port_activity = jiffies;
+}
+
+static void uart_rx_dma_callback(int lch, u16 ch_status, void *data)
+{
+	return;
+}
+
+static int serial_omap_start_rxdma(struct uart_omap_port *up)
+{
+	int ret = 0;
+
+	if (up->uart_dma.rx_dma_channel == -1) {
+		ret = omap_request_dma(up->uart_dma.uart_dma_rx,
+				"UART Rx DMA",
+				(void *)uart_rx_dma_callback, up,
+				&(up->uart_dma.rx_dma_channel));
+		if (ret < 0)
+			return ret;
+
+		omap_set_dma_src_params(up->uart_dma.rx_dma_channel, 0,
+				OMAP_DMA_AMODE_CONSTANT,
+				up->uart_dma.uart_base, 0, 0);
+		omap_set_dma_dest_params(up->uart_dma.rx_dma_channel, 0,
+				OMAP_DMA_AMODE_POST_INC,
+				up->uart_dma.rx_buf_dma_phys, 0, 0);
+		omap_set_dma_transfer_params(up->uart_dma.rx_dma_channel,
+				OMAP_DMA_DATA_TYPE_S8,
+				up->uart_dma.rx_buf_size, 1,
+				OMAP_DMA_SYNC_ELEMENT,
+				up->uart_dma.uart_dma_rx, 0);
+	}
+	up->uart_dma.prev_rx_dma_pos = up->uart_dma.rx_buf_dma_phys;
+	/* FIXME: Cache maintenance needed here? */
+	omap_start_dma(up->uart_dma.rx_dma_channel);
+	mod_timer(&up->uart_dma.rx_timer, jiffies +
+				usecs_to_jiffies(up->uart_dma.rx_timeout));
+	up->uart_dma.rx_dma_used = true;
+	return ret;
+}
+
+static void serial_omap_continue_tx(struct uart_omap_port *up)
+{
+	struct circ_buf *xmit = &up->port.state->xmit;
+	unsigned int start = up->uart_dma.tx_buf_dma_phys
+			+ (xmit->tail & (UART_XMIT_SIZE - 1));
+
+	if (uart_circ_empty(xmit))
+		return;
+
+	up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit);
+	/*
+	 * It is a circular buffer. See if the buffer has wounded back.
+	 * If yes it will have to be transferred in two separate dma
+	 * transfers
+	 */
+	if (start + up->uart_dma.tx_buf_size >=
+			up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE)
+		up->uart_dma.tx_buf_size =
+			(up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE) - start;
+	omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0,
+				OMAP_DMA_AMODE_CONSTANT,
+				up->uart_dma.uart_base, 0, 0);
+	omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0,
+				OMAP_DMA_AMODE_POST_INC, start, 0, 0);
+	omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel,
+				OMAP_DMA_DATA_TYPE_S8,
+				up->uart_dma.tx_buf_size, 1,
+				OMAP_DMA_SYNC_ELEMENT,
+				up->uart_dma.uart_dma_tx, 0);
+	/* FIXME: Cache maintenance needed here? */
+	omap_start_dma(up->uart_dma.tx_dma_channel);
+}
+
+static void uart_tx_dma_callback(int lch, u16 ch_status, void *data)
+{
+	struct uart_omap_port *up = (struct uart_omap_port *)data;
+	struct circ_buf *xmit = &up->port.state->xmit;
+
+	xmit->tail = (xmit->tail + up->uart_dma.tx_buf_size) & \
+			(UART_XMIT_SIZE - 1);
+	up->port.icount.tx += up->uart_dma.tx_buf_size;
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(&up->port);
+
+	if (uart_circ_empty(xmit)) {
+		spin_lock(&(up->uart_dma.tx_lock));
+		serial_omap_stop_tx(&up->port);
+		up->uart_dma.tx_dma_used = false;
+		spin_unlock(&(up->uart_dma.tx_lock));
+	} else {
+		omap_stop_dma(up->uart_dma.tx_dma_channel);
+		serial_omap_continue_tx(up);
+	}
+	up->port_activity = jiffies;
+	return;
+}
+
+static int serial_omap_probe(struct platform_device *pdev)
+{
+	struct uart_omap_port	*up;
+	struct resource		*mem, *irq, *dma_tx, *dma_rx;
+	struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data;
+	int ret = -ENOSPC;
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem) {
+		dev_err(&pdev->dev, "no mem resource?\n");
+		return -ENODEV;
+	}
+
+	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!irq) {
+		dev_err(&pdev->dev, "no irq resource?\n");
+		return -ENODEV;
+	}
+
+	if (!request_mem_region(mem->start, (mem->end - mem->start) + 1,
+				     pdev->dev.driver->name)) {
+		dev_err(&pdev->dev, "memory region already claimed\n");
+		return -EBUSY;
+	}
+
+	dma_rx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
+	if (!dma_rx) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	dma_tx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
+	if (!dma_tx) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	up = kzalloc(sizeof(*up), GFP_KERNEL);
+	if (up == NULL) {
+		ret = -ENOMEM;
+		goto do_release_region;
+	}
+	sprintf(up->name, "OMAP UART%d", pdev->id);
+	up->pdev = pdev;
+	up->port.dev = &pdev->dev;
+	up->port.type = PORT_OMAP;
+	up->port.iotype = UPIO_MEM;
+	up->port.irq = irq->start;
+
+	up->port.regshift = 2;
+	up->port.fifosize = 64;
+	up->port.ops = &serial_omap_pops;
+	up->port.line = pdev->id;
+
+	up->port.membase = omap_up_info->membase;
+	up->port.mapbase = omap_up_info->mapbase;
+	up->port.flags = omap_up_info->flags;
+	up->port.irqflags = omap_up_info->irqflags;
+	up->port.uartclk = omap_up_info->uartclk;
+	up->uart_dma.uart_base = mem->start;
+
+	if (omap_up_info->dma_enabled) {
+		up->uart_dma.uart_dma_tx = dma_tx->start;
+		up->uart_dma.uart_dma_rx = dma_rx->start;
+		up->use_dma = 1;
+		up->uart_dma.rx_buf_size = 4096;
+		up->uart_dma.rx_timeout = 2;
+		spin_lock_init(&(up->uart_dma.tx_lock));
+		spin_lock_init(&(up->uart_dma.rx_lock));
+		up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE;
+		up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE;
+	}
+
+	ui[pdev->id] = up;
+	serial_omap_add_console_port(up);
+
+	ret = uart_add_one_port(&serial_omap_reg, &up->port);
+	if (ret != 0)
+		goto do_release_region;
+
+	platform_set_drvdata(pdev, up);
+	return 0;
+err:
+	dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n",
+				pdev->id, __func__, ret);
+do_release_region:
+	release_mem_region(mem->start, (mem->end - mem->start) + 1);
+	return ret;
+}
+
+static int serial_omap_remove(struct platform_device *dev)
+{
+	struct uart_omap_port *up = platform_get_drvdata(dev);
+
+	platform_set_drvdata(dev, NULL);
+	if (up) {
+		uart_remove_one_port(&serial_omap_reg, &up->port);
+		kfree(up);
+	}
+	return 0;
+}
+
+static struct platform_driver serial_omap_driver = {
+	.probe          = serial_omap_probe,
+	.remove         = serial_omap_remove,
+
+	.suspend	= serial_omap_suspend,
+	.resume		= serial_omap_resume,
+	.driver		= {
+		.name	= DRIVER_NAME,
+	},
+};
+
+static int __init serial_omap_init(void)
+{
+	int ret;
+
+	ret = uart_register_driver(&serial_omap_reg);
+	if (ret != 0)
+		return ret;
+	ret = platform_driver_register(&serial_omap_driver);
+	if (ret != 0)
+		uart_unregister_driver(&serial_omap_reg);
+	return ret;
+}
+
+static void __exit serial_omap_exit(void)
+{
+	platform_driver_unregister(&serial_omap_driver);
+	uart_unregister_driver(&serial_omap_reg);
+}
+
+module_init(serial_omap_init);
+module_exit(serial_omap_exit);
+
+MODULE_DESCRIPTION("OMAP High Speed UART driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Texas Instruments Inc");
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index 76b58ab..dbbc580 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -38,11 +38,11 @@
 #include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/moduleparam.h>
-#include <linux/clk.h>
 #include <linux/bitops.h>
 #include <linux/io.h>
 #include <linux/uaccess.h>
 #include <linux/slab.h>
+#include <linux/pm_runtime.h>
 #include <mach/hardware.h>
 #include <plat/prcm.h>
 
@@ -61,8 +61,6 @@
 	void __iomem    *base;          /* physical */
 	struct device   *dev;
 	int             omap_wdt_users;
-	struct clk      *ick;
-	struct clk      *fck;
 	struct resource *mem;
 	struct miscdevice omap_wdt_miscdev;
 };
@@ -146,8 +144,7 @@
 	if (test_and_set_bit(1, (unsigned long *)&(wdev->omap_wdt_users)))
 		return -EBUSY;
 
-	clk_enable(wdev->ick);    /* Enable the interface clock */
-	clk_enable(wdev->fck);    /* Enable the functional clock */
+	pm_runtime_get_sync(wdev->dev);
 
 	/* initialize prescaler */
 	while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
@@ -177,8 +174,7 @@
 
 	omap_wdt_disable(wdev);
 
-	clk_disable(wdev->ick);
-	clk_disable(wdev->fck);
+	pm_runtime_put_sync(wdev->dev);
 #else
 	printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n");
 #endif
@@ -292,19 +288,7 @@
 
 	wdev->omap_wdt_users = 0;
 	wdev->mem = mem;
-
-	wdev->ick = clk_get(&pdev->dev, "ick");
-	if (IS_ERR(wdev->ick)) {
-		ret = PTR_ERR(wdev->ick);
-		wdev->ick = NULL;
-		goto err_clk;
-	}
-	wdev->fck = clk_get(&pdev->dev, "fck");
-	if (IS_ERR(wdev->fck)) {
-		ret = PTR_ERR(wdev->fck);
-		wdev->fck = NULL;
-		goto err_clk;
-	}
+	wdev->dev = &pdev->dev;
 
 	wdev->base = ioremap(res->start, resource_size(res));
 	if (!wdev->base) {
@@ -314,8 +298,8 @@
 
 	platform_set_drvdata(pdev, wdev);
 
-	clk_enable(wdev->ick);
-	clk_enable(wdev->fck);
+	pm_runtime_enable(wdev->dev);
+	pm_runtime_get_sync(wdev->dev);
 
 	omap_wdt_disable(wdev);
 	omap_wdt_adjust_timeout(timer_margin);
@@ -333,11 +317,7 @@
 		__raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF,
 		timer_margin);
 
-	/* autogate OCP interface clock */
-	__raw_writel(0x01, wdev->base + OMAP_WATCHDOG_SYS_CONFIG);
-
-	clk_disable(wdev->ick);
-	clk_disable(wdev->fck);
+	pm_runtime_put_sync(wdev->dev);
 
 	omap_wdt_dev = pdev;
 
@@ -349,12 +329,6 @@
 
 err_ioremap:
 	wdev->base = NULL;
-
-err_clk:
-	if (wdev->ick)
-		clk_put(wdev->ick);
-	if (wdev->fck)
-		clk_put(wdev->fck);
 	kfree(wdev);
 
 err_kzalloc:
@@ -386,8 +360,6 @@
 	release_mem_region(res->start, resource_size(res));
 	platform_set_drvdata(pdev, NULL);
 
-	clk_put(wdev->ick);
-	clk_put(wdev->fck);
 	iounmap(wdev->base);
 
 	kfree(wdev);
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 563e234..295e898 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -196,6 +196,9 @@
 /* High Speed UART for Medfield */
 #define PORT_MFD	95
 
+/* TI OMAP-UART */
+#define PORT_OMAP	96
+
 #ifdef __KERNEL__
 
 #include <linux/compiler.h>