--- a/arch/arm/mach-omap2/board-n8x0.c
+++ b/arch/arm/mach-omap2/board-n8x0.c
@@ -23,6 +23,9 @@
 #include <linux/spi/spi.h>
 #include <linux/usb/musb.h>
 #include <sound/tlv320aic3x.h>
+#include <linux/input.h>
+#include <linux/i2c/lm8323.h>
+#include <linux/spi/tsc2005.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach-types.h>
@@ -36,6 +39,7 @@
 #include <plat/mmc.h>
 #include <plat/serial.h>
 #include <plat/cbus.h>
+#include <plat/gpio-switch.h>
 
 #include "mux.h"
 
@@ -43,6 +47,221 @@ static int slot1_cover_open;
 static int slot2_cover_open;
 static struct device *mmc_device;
 
+/* We map the FN key as LALT to workaround an X keycode problem.
+ * The XKB map needs to be adjusted to support this. */
+#define MAP_FN_AS_LEFTALT
+
+static s16 rx44_keymap[LM8323_KEYMAP_SIZE] = {
+	[0x01] = KEY_Q,
+	[0x02] = KEY_K,
+	[0x03] = KEY_O,
+	[0x04] = KEY_P,
+	[0x05] = KEY_BACKSPACE,
+	[0x06] = KEY_A,
+	[0x07] = KEY_S,
+	[0x08] = KEY_D,
+	[0x09] = KEY_F,
+	[0x0a] = KEY_G,
+	[0x0b] = KEY_H,
+	[0x0c] = KEY_J,
+
+	[0x11] = KEY_W,
+	[0x12] = KEY_F4,
+	[0x13] = KEY_L,
+	[0x14] = KEY_APOSTROPHE,
+	[0x16] = KEY_Z,
+	[0x17] = KEY_X,
+	[0x18] = KEY_C,
+	[0x19] = KEY_V,
+	[0x1a] = KEY_B,
+	[0x1b] = KEY_N,
+	[0x1c] = KEY_LEFTSHIFT, /* Actually, this is both shift keys */
+	[0x1f] = KEY_F7,
+
+	[0x21] = KEY_E,
+	[0x22] = KEY_SEMICOLON,
+	[0x23] = KEY_MINUS,
+	[0x24] = KEY_EQUAL,
+#ifdef MAP_FN_AS_LEFTALT
+	[0x2b] = KEY_LEFTALT,
+#else
+	[0x2b] = KEY_FN,
+#endif
+	[0x2c] = KEY_M,
+	[0x2f] = KEY_F8,
+
+	[0x31] = KEY_R,
+	[0x32] = KEY_RIGHTCTRL,
+	[0x34] = KEY_SPACE,
+	[0x35] = KEY_COMMA,
+	[0x37] = KEY_UP,
+	[0x3c] = KEY_COMPOSE,
+	[0x3f] = KEY_F6,
+
+	[0x41] = KEY_T,
+	[0x44] = KEY_DOT,
+	[0x46] = KEY_RIGHT,
+	[0x4f] = KEY_F5,
+	[0x51] = KEY_Y,
+	[0x53] = KEY_DOWN,
+	[0x55] = KEY_ENTER,
+	[0x5f] = KEY_ESC,
+
+	[0x61] = KEY_U,
+	[0x64] = KEY_LEFT,
+
+	[0x71] = KEY_I,
+	[0x75] = KEY_KPENTER,
+};
+
+static struct lm8323_platform_data lm8323_pdata = {
+	.repeat		= 0, /* Repeat is handled in userspace for now. */
+	.keymap		= rx44_keymap,
+	.size_x		= 8,
+	.size_y		= 12,
+	.debounce_time	= 12,
+	.active_time	= 500,
+
+	.name		= "Internal keyboard",
+	.pwm_names[0] 	= "n810::keyboard",
+	.pwm_names[1] 	= "n810::cover",
+};
+
+#define OMAP_TAG_NOKIA_BT	0x4e01
+
+struct omap_bluetooth_config {
+	u8    chip_type;
+	u8    bt_wakeup_gpio;
+	u8    host_wakeup_gpio;
+	u8    reset_gpio;
+	u8    bt_uart;
+	u8    bd_addr[6];
+	u8    bt_sysclk;
+};
+
+static struct platform_device n8x0_bt_device = {
+	.name           = "hci_h4p",
+	.id             = -1,
+	.num_resources  = 0,
+};
+
+void __init n8x0_bt_init(void)
+{
+	const struct omap_bluetooth_config *bt_config;
+
+	bt_config = (void *) omap_get_config(OMAP_TAG_NOKIA_BT,
+					     struct omap_bluetooth_config);
+	n8x0_bt_device.dev.platform_data = (void *) bt_config;
+	if (platform_device_register(&n8x0_bt_device) < 0)
+		BUG();
+}
+
+#define	RX51_TSC2005_RESET_GPIO	94
+#define	RX51_TSC2005_IRQ_GPIO	106
+
+#ifdef CONFIG_TOUCHSCREEN_TSC2005
+static struct tsc2005_platform_data tsc2005_config;
+static void rx51_tsc2005_set_reset(bool enable)
+{
+	gpio_set_value(RX51_TSC2005_RESET_GPIO, enable);
+}
+
+static struct omap2_mcspi_device_config tsc2005_mcspi_config = {
+	.turbo_mode	= 0,
+	.single_channel = 1,
+};
+#endif
+
+static void __init tsc2005_set_config(void)
+{
+	const struct omap_lcd_config *conf;
+
+	conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
+	if (conf != NULL) {
+#ifdef CONFIG_TOUCHSCREEN_TSC2005
+		if (strcmp(conf->panel_name, "lph8923") == 0) {
+			tsc2005_config.ts_x_plate_ohm = 180;
+			tsc2005_config.ts_hw_avg = 0;
+			tsc2005_config.ts_ignore_last = 0;
+			tsc2005_config.ts_touch_pressure = 1500;
+			tsc2005_config.ts_stab_time = 100;
+			tsc2005_config.ts_pressure_max = 2048;
+			tsc2005_config.ts_pressure_fudge = 2;
+			tsc2005_config.ts_x_max = 4096;
+			tsc2005_config.ts_x_fudge = 4;
+			tsc2005_config.ts_y_max = 4096;
+			tsc2005_config.ts_y_fudge = 7;
+			tsc2005_config.set_reset = rx51_tsc2005_set_reset;
+		} else if (strcmp(conf->panel_name, "ls041y3") == 0) {
+			tsc2005_config.ts_x_plate_ohm = 280;
+			tsc2005_config.ts_hw_avg = 0;
+			tsc2005_config.ts_ignore_last = 0;
+			tsc2005_config.ts_touch_pressure = 1500;
+			tsc2005_config.ts_stab_time = 1000;
+			tsc2005_config.ts_pressure_max = 2048;
+			tsc2005_config.ts_pressure_fudge = 2;
+			tsc2005_config.ts_x_max = 4096;
+			tsc2005_config.ts_x_fudge = 4;
+			tsc2005_config.ts_y_max = 4096;
+			tsc2005_config.ts_y_fudge = 7;
+			tsc2005_config.set_reset = rx51_tsc2005_set_reset;
+		} else {
+			printk(KERN_ERR "Unknown panel type, set default "
+			       "touchscreen configuration\n");
+			tsc2005_config.ts_x_plate_ohm = 200;
+			tsc2005_config.ts_stab_time = 100;
+		}
+#endif
+	}
+}
+
+static struct omap2_mcspi_device_config mipid_mcspi_config = {
+	.turbo_mode	= 0,
+	.single_channel	= 1,
+};
+
+extern struct mipid_platform_data n8x0_mipid_platform_data;
+
+extern void n8x0_mipid_init(void);
+extern void n8x0_blizzard_init(void);
+
+static struct omap_gpio_switch n8x0_gpio_switches[] __initdata = {
+	{
+		.name			= "headphone",
+		.gpio			= -1,
+		.debounce_rising	= 200,
+		.debounce_falling	= 200,
+	}, {
+		.name			= "cam_act",
+		.gpio			= -1,
+		.debounce_rising	= 200,
+		.debounce_falling	= 200,
+	}, {
+		.name			= "cam_turn",
+		.gpio			= -1,
+		.debounce_rising	= 100,
+		.debounce_falling	= 100,
+	}, {
+		.name			= "slide",
+		.gpio			= -1,
+		.debounce_rising	= 200,
+		.debounce_falling	= 200,
+	}, {
+		.name			= "kb_lock",
+		.gpio			= -1,
+		.debounce_rising	= 200,
+		.debounce_falling	= 200,
+	},
+};
+
+static void __init n8x0_gpio_switches_init(void)
+{
+	/* The switches are actually registered through ATAG mechanism.
+	 * This just updates the parameters (thus .gpio is -1) */
+	omap_register_gpio_switches(n8x0_gpio_switches,
+				    ARRAY_SIZE(n8x0_gpio_switches));
+}
+
 #define TUSB6010_ASYNC_CS	1
 #define TUSB6010_SYNC_CS	4
 #define TUSB6010_GPIO_INT	58
@@ -146,12 +365,29 @@ static struct omap2_mcspi_device_config
 
 static struct spi_board_info n800_spi_board_info[] __initdata = {
 	{
+		.modalias	= "lcd_mipid",
+		.bus_num	= 1,
+		.chip_select	= 1,
+		.max_speed_hz	= 4000000,
+		.controller_data= &mipid_mcspi_config,
+		.platform_data	= &n8x0_mipid_platform_data,
+	},
+	{
 		.modalias	= "p54spi",
 		.bus_num	= 2,
 		.chip_select	= 0,
 		.max_speed_hz   = 48000000,
 		.controller_data = &p54spi_mcspi_config,
 	},
+	{
+		.modalias	 = "tsc2005",
+		.bus_num	 = 1,
+		.chip_select	 = 0,
+		.irq		 = OMAP_GPIO_IRQ(RX51_TSC2005_IRQ_GPIO),
+		.max_speed_hz    = 6000000,
+		.controller_data = &tsc2005_mcspi_config,
+		.platform_data   = &tsc2005_config,
+	},
 };
 
 #if defined(CONFIG_MTD_ONENAND_OMAP2) || \
@@ -727,6 +963,11 @@ static struct aic3x_pdata n810_aic33_dat
 };
 
 static struct i2c_board_info n810_i2c_board_info_2[] __initdata = {
+ 	{
+		I2C_BOARD_INFO("lm8323", 0x45),
+		.irq		= OMAP_GPIO_IRQ(109),
+		.platform_data	= &lm8323_pdata,
+	},
 	{
 		I2C_BOARD_INFO("tlv320aic3x", 0x18),
 		.platform_data = &n810_aic33_data,
@@ -796,9 +1037,12 @@ static inline void board_serial_init(voi
 static void __init n8x0_init_machine(void)
 {
 	omap2420_mux_init(board_mux, OMAP_PACKAGE_ZAC);
+	n8x0_gpio_switches_init();
 	n8x0_cbus_init();
+	n8x0_bt_init();
 
 	/* FIXME: add n810 spi devices */
+	tsc2005_set_config();
 	spi_register_board_info(n800_spi_board_info,
 				ARRAY_SIZE(n800_spi_board_info));
 	omap_register_i2c_bus(1, 400, n8x0_i2c_board_info_1,
@@ -808,6 +1052,8 @@ static void __init n8x0_init_machine(voi
 		i2c_register_board_info(2, n810_i2c_board_info_2,
 					ARRAY_SIZE(n810_i2c_board_info_2));
 	board_serial_init();
+	n8x0_mipid_init();
+	n8x0_blizzard_init();
 	gpmc_onenand_init(board_onenand_data);
 	n8x0_mmc_init();
 	n8x0_usb_init();
--- /dev/null
+++ b/arch/arm/mach-omap2/board-n8x0-lcd.c
@@ -0,0 +1,141 @@
+/*
+ * linux/arch/arm/mach-omap2/board-n8x0.c
+ *
+ * Copyright (C) 2005-2009 Nokia Corporation
+ * Author: Juha Yrjola <juha.yrjola@nokia.com>
+ *
+ * Modified from mach-omap2/board-generic.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/omapfb.h>
+
+#include <plat/lcd_mipid.h>
+#include <plat/blizzard.h>
+
+#include <../drivers/cbus/tahvo.h>
+
+#define N8X0_BLIZZARD_POWERDOWN_GPIO	15
+
+// MIPID LCD Panel
+
+static void mipid_shutdown(struct mipid_platform_data *pdata)
+{
+	if (pdata->nreset_gpio != -1) {
+		pr_info("shutdown LCD\n");
+		gpio_set_value(pdata->nreset_gpio, 0);
+		msleep(120);
+	}
+}
+
+struct mipid_platform_data n8x0_mipid_platform_data = {
+	.shutdown = mipid_shutdown,
+};
+
+void __init n8x0_mipid_init(void)
+{
+	const struct omap_lcd_config *conf;
+	int err;
+
+	conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
+	if (conf != NULL) {
+		n8x0_mipid_platform_data.nreset_gpio = conf->nreset_gpio;
+		n8x0_mipid_platform_data.data_lines = conf->data_lines;
+		if (conf->nreset_gpio != -1) {
+			err = gpio_request(conf->nreset_gpio, "MIPID nreset");
+			if (err) {
+				printk(KERN_ERR "N8x0 MIPID failed to request nreset GPIO %d\n",
+				       conf->nreset_gpio);
+			} else {
+				err = gpio_direction_output(conf->nreset_gpio, 1);
+				if (err) {
+					printk(KERN_ERR "N8x0 MIPID failed to set nreset GPIO %d\n",
+					       conf->nreset_gpio);
+				}
+			}
+		}
+		printk(KERN_INFO "N8x0 MIPID config loaded");
+	}
+	else
+		printk(KERN_INFO "N8x0 MIPID config not provided");
+}
+
+
+// Epson Blizzard LCD Controller
+
+static struct {
+	struct clk *sys_ck;
+} blizzard;
+
+static int blizzard_get_clocks(void)
+{
+	blizzard.sys_ck = clk_get(0, "osc_ck");
+	if (IS_ERR(blizzard.sys_ck)) {
+		printk(KERN_ERR "can't get Blizzard clock\n");
+		return PTR_ERR(blizzard.sys_ck);
+	}
+	return 0;
+}
+
+static unsigned long blizzard_get_clock_rate(struct device *dev)
+{
+	return clk_get_rate(blizzard.sys_ck);
+}
+
+static void blizzard_enable_clocks(int enable)
+{
+	if (enable)
+		clk_enable(blizzard.sys_ck);
+	else
+		clk_disable(blizzard.sys_ck);
+}
+
+static void blizzard_power_up(struct device *dev)
+{
+	/* Vcore to 1.475V */
+	tahvo_set_clear_reg_bits(0x07, 0, 0xf);
+	msleep(10);
+
+	blizzard_enable_clocks(1);
+	gpio_set_value(N8X0_BLIZZARD_POWERDOWN_GPIO, 1);
+}
+
+static void blizzard_power_down(struct device *dev)
+{
+	gpio_set_value(N8X0_BLIZZARD_POWERDOWN_GPIO, 0);
+	blizzard_enable_clocks(0);
+
+	/* Vcore to 1.005V */
+	tahvo_set_clear_reg_bits(0x07, 0xf, 0);
+}
+
+static struct blizzard_platform_data n8x0_blizzard_data = {
+	.power_up	= blizzard_power_up,
+	.power_down	= blizzard_power_down,
+	.get_clock_rate	= blizzard_get_clock_rate,
+	.te_connected	= 1,
+};
+
+void __init n8x0_blizzard_init(void)
+{
+	int r;
+
+	r = gpio_request(N8X0_BLIZZARD_POWERDOWN_GPIO, "Blizzard pd");
+	if (r < 0)
+	{
+		printk(KERN_ERR "Can't get N8x0 Blizzard powerdown GPIO %d\n", N8X0_BLIZZARD_POWERDOWN_GPIO);
+		return;
+	}
+	gpio_direction_output(N8X0_BLIZZARD_POWERDOWN_GPIO, 1);
+
+	blizzard_get_clocks();
+	omapfb_set_ctrl_platform_data(&n8x0_blizzard_data);
+
+	printk(KERN_INFO "N8x0 Blizzard initialized");
+}
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -177,6 +177,7 @@ obj-$(CONFIG_MACH_OMAP_3430SDP)		+= boar
 					   hsmmc.o \
 					   board-flash.o
 obj-$(CONFIG_MACH_NOKIA_N8X0)		+= board-n8x0.o
+obj-$(CONFIG_MACH_NOKIA_N8X0)		+= board-n8x0-lcd.o
 obj-$(CONFIG_MACH_NOKIA_RM680)		+= board-rm680.o \
 					   sdram-nokia.o \
 					   hsmmc.o
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/cbus.h
@@ -0,0 +1,40 @@
+/*
+ * cbus.h - CBUS platform_data definition
+ *
+ * Copyright (C) 2004 - 2009 Nokia Corporation
+ *
+ * Written by Felipe Balbi <felipe.balbi@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __PLAT_CBUS_H
+#define __PLAT_CBUS_H
+
+#define CBUS_RETU_DEVICE_ID	0x01
+#define CBUS_TAHVO_DEVICE_ID	0x02
+
+struct cbus_host_platform_data {
+	int	dat_gpio;
+	int	clk_gpio;
+	int	sel_gpio;
+};
+
+struct cbus_retu_platform_data {
+	int	irq_base;
+	int	irq_end;
+	int	devid;
+};
+
+#endif /* __PLAT_CBUS_H */
--- a/arch/arm/plat-omap/include/plat/irqs.h
+++ b/arch/arm/plat-omap/include/plat/irqs.h
@@ -411,7 +411,20 @@
 #define TWL_IRQ_END		TWL6030_IRQ_END
 #endif
 
-#define NR_IRQS			TWL_IRQ_END
+/* GPMC related */
+#define OMAP_GPMC_IRQ_BASE	(TWL_IRQ_END)
+#define OMAP_GPMC_NR_IRQS	7
+#define OMAP_GPMC_IRQ_END	(OMAP_GPMC_IRQ_BASE + OMAP_GPMC_NR_IRQS)
+
+#define CBUS_RETU_IRQ_BASE	OMAP_GPMC_IRQ_END
+#ifdef CONFIG_CBUS_RETU
+#define CBUS_RETU_NR_IRQS	16
+#else
+#define CBUS_RETU_NR_IRQS	0
+#endif
+#define CBUS_RETU_IRQ_END	(CBUS_RETU_IRQ_BASE + CBUS_RETU_NR_IRQS)
+
+#define NR_IRQS			CBUS_RETU_IRQ_END
 
 #define OMAP_IRQ_BIT(irq)	(1 << ((irq) % 32))
 
--- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
@@ -673,6 +673,7 @@ static struct omap_hwmod_ocp_if *omap242
 
 static struct omap_hwmod omap2420_gpio1_hwmod = {
 	.name		= "gpio1",
+	.flags		= HWMOD_INIT_NO_RESET, /* Workaround: Don't reset the n810 MIPID */
 	.mpu_irqs	= omap242x_gpio1_irqs,
 	.mpu_irqs_cnt	= ARRAY_SIZE(omap242x_gpio1_irqs),
 	.main_clk	= "gpios_fck",
