Merge git://git.kernel.org/pub/scm/linux/kernel/git/agk/linux-2.6-dm

* git://git.kernel.org/pub/scm/linux/kernel/git/agk/linux-2.6-dm: (33 commits)
  dm mpath: support discard
  dm stripe: support discards
  dm: split discard requests on target boundaries
  dm stripe: optimize sector division
  dm stripe: move sector translation to a function
  dm: error return error for discards
  dm delay: support discard
  dm: zero silently drop discards
  dm: use dm_target_offset macro
  dm: factor out max_io_len_target_boundary
  dm: use common __issue_target_request for flush and discard support
  dm: linear support discard
  dm crypt: simplify crypt_ctr
  dm crypt: simplify crypt_config destruction logic
  dm: allow autoloading of dm mod
  dm: rename map_info flush_request to target_request_nr
  dm ioctl: refactor dm_table_complete
  dm snapshot: implement merge
  dm: do not initialise full request queue when bio based
  dm ioctl: make bio or request based device type immutable
  ...
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX
index 9e642c5..8dfc670 100644
--- a/Documentation/00-INDEX
+++ b/Documentation/00-INDEX
@@ -232,6 +232,8 @@
 	- info on typical Linux memory problems.
 mips/
 	- directory with info about Linux on MIPS architecture.
+mmc/
+	- directory with info about the MMC subsystem
 mono.txt
 	- how to execute Mono-based .NET binaries with the help of BINFMT_MISC.
 mutex-design.txt
diff --git a/Documentation/cpu-hotplug.txt b/Documentation/cpu-hotplug.txt
index a99d703..45d5a21 100644
--- a/Documentation/cpu-hotplug.txt
+++ b/Documentation/cpu-hotplug.txt
@@ -2,7 +2,7 @@
 
 		Maintainers:
 		CPU Hotplug Core:
-			Rusty Russell <rusty@rustycorp.com.au>
+			Rusty Russell <rusty@rustcorp.com.au>
 			Srivatsa Vaddagiri <vatsa@in.ibm.com>
 		i386:
 			Zwane Mwaikambo <zwane@arm.linux.org.uk>
diff --git a/Documentation/i2c/instantiating-devices b/Documentation/i2c/instantiating-devices
index e894902..87da405 100644
--- a/Documentation/i2c/instantiating-devices
+++ b/Documentation/i2c/instantiating-devices
@@ -102,7 +102,7 @@
 	memset(&i2c_info, 0, sizeof(struct i2c_board_info));
 	strlcpy(i2c_info.name, "isp1301_pnx", I2C_NAME_SIZE);
 	isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info,
-						   normal_i2c);
+						   normal_i2c, NULL);
 	i2c_put_adapter(i2c_adap);
 	(...)
 }
diff --git a/Documentation/mmc/00-INDEX b/Documentation/mmc/00-INDEX
new file mode 100644
index 0000000..fca586f
--- /dev/null
+++ b/Documentation/mmc/00-INDEX
@@ -0,0 +1,4 @@
+00-INDEX
+        - this file
+mmc-dev-attrs.txt
+        - info on SD and MMC device attributes
diff --git a/Documentation/mmc/mmc-dev-attrs.txt b/Documentation/mmc/mmc-dev-attrs.txt
new file mode 100644
index 0000000..ff2bd68
--- /dev/null
+++ b/Documentation/mmc/mmc-dev-attrs.txt
@@ -0,0 +1,56 @@
+SD and MMC Device Attributes
+============================
+
+All attributes are read-only.
+
+	cid			Card Identifaction Register
+	csd			Card Specific Data Register
+	scr			SD Card Configuration Register (SD only)
+	date			Manufacturing Date (from CID Register)
+	fwrev			Firmware/Product Revision (from CID Register) (SD and MMCv1 only)
+	hwrev			Hardware/Product Revision (from CID Register) (SD and MMCv1 only)
+	manfid			Manufacturer ID (from CID Register)
+	name			Product Name (from CID Register)
+	oemid			OEM/Application ID (from CID Register)
+	serial			Product Serial Number (from CID Register)
+	erase_size		Erase group size
+	preferred_erase_size	Preferred erase size
+
+Note on Erase Size and Preferred Erase Size:
+
+	"erase_size" is the  minimum size, in bytes, of an erase
+	operation.  For MMC, "erase_size" is the erase group size
+	reported by the card.  Note that "erase_size" does not apply
+	to trim or secure trim operations where the minimum size is
+	always one 512 byte sector.  For SD, "erase_size" is 512
+	if the card is block-addressed, 0 otherwise.
+
+	SD/MMC cards can erase an arbitrarily large area up to and
+	including the whole card.  When erasing a large area it may
+	be desirable to do it in smaller chunks for three reasons:
+		1. A single erase command will make all other I/O on
+		the card wait.  This is not a problem if the whole card
+		is being erased, but erasing one partition will make
+		I/O for another partition on the same card wait for the
+		duration of the erase - which could be a several
+		minutes.
+		2. To be able to inform the user of erase progress.
+		3. The erase timeout becomes too large to be very
+		useful.  Because the erase timeout contains a margin
+		which is multiplied by the size of the erase area,
+		the value can end up being several minutes for large
+		areas.
+
+	"erase_size" is not the most efficient unit to erase
+	(especially for SD where it is just one sector),
+	hence "preferred_erase_size" provides a good chunk
+	size for erasing large areas.
+
+	For MMC, "preferred_erase_size" is the high-capacity
+	erase size if a card specifies one, otherwise it is
+	based on the capacity of the card.
+
+	For SD, "preferred_erase_size" is the allocation unit
+	size specified by the card.
+
+	"preferred_erase_size" is in bytes.
diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt
index 03771d7..ce46fa1 100644
--- a/Documentation/sound/alsa/HD-Audio-Models.txt
+++ b/Documentation/sound/alsa/HD-Audio-Models.txt
@@ -83,8 +83,8 @@
 ======
   basic		Basic preset
   quanta	Quanta FL1
-  eeepc-p703	ASUS Eeepc P703 P900A
-  eeepc-p901	ASUS Eeepc P901 S101
+  laptop-amic	Laptops with analog-mic input
+  laptop-dmic	Laptops with digital-mic input
   fujitsu	FSC Amilo
   lifebook	Fujitsu Lifebook S6420
   auto		auto-config reading BIOS (default)
@@ -109,6 +109,8 @@
   asus-mode4	ASUS
   asus-mode5	ASUS
   asus-mode6	ASUS
+  asus-mode7	ASUS
+  asus-mode8	ASUS
   dell		Dell with ALC272
   dell-zm1	Dell ZM1 with ALC272
   samsung-nc10	Samsung NC10 mini notebook
@@ -295,8 +297,10 @@
 =============
   laptop	Basic Laptop config (default)
   dell-laptop	Dell laptops
+  dell-vostro	Dell Vostro
   olpc-xo-1_5	OLPC XO 1.5
   ideapad       Lenovo IdeaPad U150
+  thinkpad	Lenovo Thinkpad
 
 STAC9200
 ========
@@ -404,6 +408,7 @@
   mic-ref	Reference board with power management for ports
   dell-s14	Dell laptop
   hp		HP laptops with (inverted) mute-LED
+  hp-dv7-4000	HP dv-7 4000
   auto		BIOS setup (default)
 
 STAC9872
@@ -416,3 +421,7 @@
   mbp55		MacBook Pro 5,5
   imac27	IMac 27 Inch
   auto		BIOS setup (default)
+
+VIA VT17xx/VT18xx/VT20xx
+========================
+  auto		BIOS setup (default)
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 7ff8020..7046106 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -15,7 +15,7 @@
 obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o
 obj-$(CONFIG_MSM_SMD) += last_radio_log.o
 
-obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o devices-msm7x00.o
+obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o board-trout-mmc.o devices-msm7x00.o
 obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o devices-msm7x00.o
 obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30.o devices-msm7x30.o
 obj-$(CONFIG_ARCH_QSD8X50) += board-qsd8x50.o devices-qsd8x50.o
diff --git a/arch/arm/mach-msm/acpuclock-arm11.c b/arch/arm/mach-msm/acpuclock-arm11.c
index f060a39..7ffbd98 100644
--- a/arch/arm/mach-msm/acpuclock-arm11.c
+++ b/arch/arm/mach-msm/acpuclock-arm11.c
@@ -17,7 +17,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/list.h>
diff --git a/arch/arm/mach-msm/board-trout-gpio.c b/arch/arm/mach-msm/board-trout-gpio.c
index 523d213..c50f3af 100644
--- a/arch/arm/mach-msm/board-trout-gpio.c
+++ b/arch/arm/mach-msm/board-trout-gpio.c
@@ -15,10 +15,20 @@
 #include <linux/module.h>
 #include <linux/io.h>
 #include <linux/irq.h>
+#include <linux/interrupt.h>
 #include <linux/gpio.h>
 
 #include "board-trout.h"
 
+static uint8_t trout_int_mask[2] = {
+	[0] = 0xff, /* mask all interrupts */
+	[1] = 0xff,
+};
+static uint8_t trout_sleep_int_mask[] = {
+	[0] = 0xff,
+	[1] = 0xff,
+};
+
 struct msm_gpio_chip {
 	struct gpio_chip	chip;
 	void __iomem		*reg;	/* Base of register bank */
@@ -95,16 +105,121 @@
 	TROUT_GPIO_BANK("VIRTUAL", 0x12, TROUT_GPIO_VIRTUAL_BASE, 0),
 };
 
+static void trout_gpio_irq_ack(unsigned int irq)
+{
+	int bank = TROUT_INT_TO_BANK(irq);
+	uint8_t mask = TROUT_INT_TO_MASK(irq);
+	int reg = TROUT_BANK_TO_STAT_REG(bank);
+	/*printk(KERN_INFO "trout_gpio_irq_ack irq %d\n", irq);*/
+	writeb(mask, TROUT_CPLD_BASE + reg);
+}
+
+static void trout_gpio_irq_mask(unsigned int irq)
+{
+	unsigned long flags;
+	uint8_t reg_val;
+	int bank = TROUT_INT_TO_BANK(irq);
+	uint8_t mask = TROUT_INT_TO_MASK(irq);
+	int reg = TROUT_BANK_TO_MASK_REG(bank);
+
+	local_irq_save(flags);
+	reg_val = trout_int_mask[bank] |= mask;
+	/*printk(KERN_INFO "trout_gpio_irq_mask irq %d => %d:%02x\n",
+	       irq, bank, reg_val);*/
+	writeb(reg_val, TROUT_CPLD_BASE + reg);
+	local_irq_restore(flags);
+}
+
+static void trout_gpio_irq_unmask(unsigned int irq)
+{
+	unsigned long flags;
+	uint8_t reg_val;
+	int bank = TROUT_INT_TO_BANK(irq);
+	uint8_t mask = TROUT_INT_TO_MASK(irq);
+	int reg = TROUT_BANK_TO_MASK_REG(bank);
+
+	local_irq_save(flags);
+	reg_val = trout_int_mask[bank] &= ~mask;
+	/*printk(KERN_INFO "trout_gpio_irq_unmask irq %d => %d:%02x\n",
+	       irq, bank, reg_val);*/
+	writeb(reg_val, TROUT_CPLD_BASE + reg);
+	local_irq_restore(flags);
+}
+
+int trout_gpio_irq_set_wake(unsigned int irq, unsigned int on)
+{
+	unsigned long flags;
+	int bank = TROUT_INT_TO_BANK(irq);
+	uint8_t mask = TROUT_INT_TO_MASK(irq);
+
+	local_irq_save(flags);
+	if(on)
+		trout_sleep_int_mask[bank] &= ~mask;
+	else
+		trout_sleep_int_mask[bank] |= mask;
+	local_irq_restore(flags);
+	return 0;
+}
+
+static void trout_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	int j, m;
+	unsigned v;
+	int bank;
+	int stat_reg;
+	int int_base = TROUT_INT_START;
+	uint8_t int_mask;
+
+	for (bank = 0; bank < 2; bank++) {
+		stat_reg = TROUT_BANK_TO_STAT_REG(bank);
+		v = readb(TROUT_CPLD_BASE + stat_reg);
+		int_mask = trout_int_mask[bank];
+		if (v & int_mask) {
+			writeb(v & int_mask, TROUT_CPLD_BASE + stat_reg);
+			printk(KERN_ERR "trout_gpio_irq_handler: got masked "
+			       "interrupt: %d:%02x\n", bank, v & int_mask);
+		}
+		v &= ~int_mask;
+		while (v) {
+			m = v & -v;
+			j = fls(m) - 1;
+			/*printk(KERN_INFO "msm_gpio_irq_handler %d:%02x %02x b"
+			       "it %d irq %d\n", bank, v, m, j, int_base + j);*/
+			v &= ~m;
+			generic_handle_irq(int_base + j);
+		}
+		int_base += TROUT_INT_BANK0_COUNT;
+	}
+	desc->chip->ack(irq);
+}
+
+static struct irq_chip trout_gpio_irq_chip = {
+	.name      = "troutgpio",
+	.ack       = trout_gpio_irq_ack,
+	.mask      = trout_gpio_irq_mask,
+	.unmask    = trout_gpio_irq_unmask,
+	.set_wake  = trout_gpio_irq_set_wake,
+};
+
 /*
  * Called from the processor-specific init to enable GPIO pin support.
  */
 int __init trout_init_gpio(void)
 {
 	int i;
+	for(i = TROUT_INT_START; i <= TROUT_INT_END; i++) {
+		set_irq_chip(i, &trout_gpio_irq_chip);
+		set_irq_handler(i, handle_edge_irq);
+		set_irq_flags(i, IRQF_VALID);
+	}
 
 	for (i = 0; i < ARRAY_SIZE(msm_gpio_banks); i++)
 		gpiochip_add(&msm_gpio_banks[i].chip);
 
+	set_irq_type(MSM_GPIO_TO_INT(17), IRQF_TRIGGER_HIGH);
+	set_irq_chained_handler(MSM_GPIO_TO_INT(17), trout_gpio_irq_handler);
+	set_irq_wake(MSM_GPIO_TO_INT(17), 1);
+
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/board-trout-mmc.c b/arch/arm/mach-msm/board-trout-mmc.c
new file mode 100644
index 0000000..44be846
--- /dev/null
+++ b/arch/arm/mach-msm/board-trout-mmc.c
@@ -0,0 +1,186 @@
+/* linux/arch/arm/mach-msm/board-trout-mmc.c
+** Author: Brian Swetland <swetland@google.com>
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/err.h>
+#include <linux/debugfs.h>
+
+#include <asm/gpio.h>
+#include <asm/io.h>
+
+#include <mach/vreg.h>
+
+#include <mach/mmc.h>
+
+#include "devices.h"
+
+#include "board-trout.h"
+
+#include "proc_comm.h"
+
+#define DEBUG_SDSLOT_VDD 1
+
+/* ---- COMMON ---- */
+static void config_gpio_table(uint32_t *table, int len)
+{
+	int n;
+	unsigned id;
+	for(n = 0; n < len; n++) {
+		id = table[n];
+		msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
+	}
+}
+
+/* ---- SDCARD ---- */
+
+static uint32_t sdcard_on_gpio_table[] = {
+	PCOM_GPIO_CFG(62, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CLK */
+	PCOM_GPIO_CFG(63, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* CMD */
+	PCOM_GPIO_CFG(64, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT3 */
+	PCOM_GPIO_CFG(65, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT2 */
+	PCOM_GPIO_CFG(66, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT1 */
+	PCOM_GPIO_CFG(67, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT0 */
+};
+
+static uint32_t sdcard_off_gpio_table[] = {
+	PCOM_GPIO_CFG(62, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CLK */
+	PCOM_GPIO_CFG(63, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CMD */
+	PCOM_GPIO_CFG(64, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */
+	PCOM_GPIO_CFG(65, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */
+	PCOM_GPIO_CFG(66, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */
+	PCOM_GPIO_CFG(67, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */
+};
+
+static uint opt_disable_sdcard;
+
+static int __init trout_disablesdcard_setup(char *str)
+{
+	int cal = simple_strtol(str, NULL, 0);
+	
+	opt_disable_sdcard = cal;
+	return 1;
+}
+
+__setup("board_trout.disable_sdcard=", trout_disablesdcard_setup);
+
+static struct vreg *vreg_sdslot;	/* SD slot power */
+
+struct mmc_vdd_xlat {
+	int mask;
+	int level;
+};
+
+static struct mmc_vdd_xlat mmc_vdd_table[] = {
+	{ MMC_VDD_165_195,	1800 },
+	{ MMC_VDD_20_21,	2050 },
+	{ MMC_VDD_21_22,	2150 },
+	{ MMC_VDD_22_23,	2250 },
+	{ MMC_VDD_23_24,	2350 },
+	{ MMC_VDD_24_25,	2450 },
+	{ MMC_VDD_25_26,	2550 },
+	{ MMC_VDD_26_27,	2650 },
+	{ MMC_VDD_27_28,	2750 },
+	{ MMC_VDD_28_29,	2850 },
+	{ MMC_VDD_29_30,	2950 },
+};
+
+static unsigned int sdslot_vdd = 0xffffffff;
+static unsigned int sdslot_vreg_enabled;
+
+static uint32_t trout_sdslot_switchvdd(struct device *dev, unsigned int vdd)
+{
+	int i, rc;
+
+	BUG_ON(!vreg_sdslot);
+
+	if (vdd == sdslot_vdd)
+		return 0;
+
+	sdslot_vdd = vdd;
+
+	if (vdd == 0) {
+#if DEBUG_SDSLOT_VDD
+		printk("%s: Disabling SD slot power\n", __func__);
+#endif
+		config_gpio_table(sdcard_off_gpio_table,
+				  ARRAY_SIZE(sdcard_off_gpio_table));
+		vreg_disable(vreg_sdslot);
+		sdslot_vreg_enabled = 0;
+		return 0;
+	}
+
+	if (!sdslot_vreg_enabled) {
+		rc = vreg_enable(vreg_sdslot);
+		if (rc) {
+			printk(KERN_ERR "%s: Error enabling vreg (%d)\n",
+			       __func__, rc);
+		}
+		config_gpio_table(sdcard_on_gpio_table,
+				  ARRAY_SIZE(sdcard_on_gpio_table));
+		sdslot_vreg_enabled = 1;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(mmc_vdd_table); i++) {
+		if (mmc_vdd_table[i].mask == (1 << vdd)) {
+#if DEBUG_SDSLOT_VDD
+			printk("%s: Setting level to %u\n",
+			        __func__, mmc_vdd_table[i].level);
+#endif
+			rc = vreg_set_level(vreg_sdslot,
+					    mmc_vdd_table[i].level);
+			if (rc) {
+				printk(KERN_ERR
+				       "%s: Error setting vreg level (%d)\n",
+				       __func__, rc);
+			}
+			return 0;
+		}
+	}
+
+	printk(KERN_ERR "%s: Invalid VDD %d specified\n", __func__, vdd);
+	return 0;
+}
+
+static unsigned int trout_sdslot_status(struct device *dev)
+{
+	unsigned int status;
+
+	status = (unsigned int) gpio_get_value(TROUT_GPIO_SDMC_CD_N);
+	return (!status);
+}
+
+#define TROUT_MMC_VDD	MMC_VDD_165_195 | MMC_VDD_20_21 | MMC_VDD_21_22 \
+			| MMC_VDD_22_23 | MMC_VDD_23_24 | MMC_VDD_24_25 \
+			| MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 \
+			| MMC_VDD_28_29 | MMC_VDD_29_30
+
+static struct msm_mmc_platform_data trout_sdslot_data = {
+	.ocr_mask	= TROUT_MMC_VDD,
+	.status		= trout_sdslot_status,
+	.translate_vdd	= trout_sdslot_switchvdd,
+};
+
+int __init trout_init_mmc(unsigned int sys_rev)
+{
+	sdslot_vreg_enabled = 0;
+
+	vreg_sdslot = vreg_get(0, "gp6");
+	if (IS_ERR(vreg_sdslot))
+		return PTR_ERR(vreg_sdslot);
+
+	set_irq_wake(TROUT_GPIO_TO_INT(TROUT_GPIO_SDMC_CD_N), 1);
+
+	if (!opt_disable_sdcard)
+		msm_add_sdcc(2, &trout_sdslot_data,
+			     TROUT_GPIO_TO_INT(TROUT_GPIO_SDMC_CD_N), 0);
+	else
+		printk(KERN_INFO "trout: SD-Card interface disabled\n");
+	return 0;
+}
+
diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c
index e69a150..469e0be 100644
--- a/arch/arm/mach-msm/board-trout.c
+++ b/arch/arm/mach-msm/board-trout.c
@@ -30,6 +30,8 @@
 #include "devices.h"
 #include "board-trout.h"
 
+extern int trout_init_mmc(unsigned int);
+
 static struct platform_device *devices[] __initdata = {
 	&msm_device_uart3,
 	&msm_device_smd,
@@ -55,7 +57,16 @@
 
 static void __init trout_init(void)
 {
+	int rc;
+
 	platform_add_devices(devices, ARRAY_SIZE(devices));
+
+#ifdef CONFIG_MMC
+        rc = trout_init_mmc(system_rev);
+        if (rc)
+                printk(KERN_CRIT "%s: MMC init failure (%d)\n", __func__, rc);
+#endif
+
 }
 
 static struct map_desc trout_io_desc[] __initdata = {
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 9cb1276..c57210f 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -14,7 +14,6 @@
  *
  */
 
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
diff --git a/arch/arm/mach-msm/devices-msm7x00.c b/arch/arm/mach-msm/devices-msm7x00.c
index fde9d8f..4e8c0bc 100644
--- a/arch/arm/mach-msm/devices-msm7x00.c
+++ b/arch/arm/mach-msm/devices-msm7x00.c
@@ -322,7 +322,8 @@
 	&msm_device_sdc4,
 };
 
-int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat,
+int __init msm_add_sdcc(unsigned int controller,
+			struct msm_mmc_platform_data *plat,
 			unsigned int stat_irq, unsigned long stat_irq_flags)
 {
 	struct platform_device	*pdev;
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index e302fbd..5a79bcf 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -18,6 +18,7 @@
 #define __ASM_ARCH_MSM_BOARD_H
 
 #include <linux/types.h>
+#include <mach/mmc.h>
 
 /* platform device data structures */
 
@@ -40,5 +41,8 @@
 void __init msm_init_gpio(void);
 void __init msm_clock_init(struct clk *clock_tbl, unsigned num_clocks);
 void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *);
+int __init msm_add_sdcc(unsigned int controller,
+			struct msm_mmc_platform_data *plat,
+			unsigned int stat_irq, unsigned long stat_irq_flags);
 
 #endif
diff --git a/arch/arm/mach-msm/include/mach/mmc.h b/arch/arm/mach-msm/include/mach/mmc.h
index 0ecf254..d54b6b0 100644
--- a/arch/arm/mach-msm/include/mach/mmc.h
+++ b/arch/arm/mach-msm/include/mach/mmc.h
@@ -15,7 +15,7 @@
 	int num_funcs;
 };
 
-struct mmc_platform_data {
+struct msm_mmc_platform_data {
 	unsigned int ocr_mask;			/* available voltages */
 	u32 (*translate_vdd)(struct device *, unsigned int);
 	unsigned int (*status)(struct device *);
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index cf11d41..f07dc7c 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -997,7 +997,7 @@
 	return 0;
 }
 
-static int __init msm_smd_probe(struct platform_device *pdev)
+static int __devinit msm_smd_probe(struct platform_device *pdev)
 {
 	pr_info("smd_init()\n");
 
diff --git a/arch/ia64/include/asm/rwsem.h b/arch/ia64/include/asm/rwsem.h
index e876268..215d545 100644
--- a/arch/ia64/include/asm/rwsem.h
+++ b/arch/ia64/include/asm/rwsem.h
@@ -40,9 +40,9 @@
 };
 
 #define RWSEM_UNLOCKED_VALUE		__IA64_UL_CONST(0x0000000000000000)
-#define RWSEM_ACTIVE_BIAS		__IA64_UL_CONST(0x0000000000000001)
-#define RWSEM_ACTIVE_MASK		__IA64_UL_CONST(0x00000000ffffffff)
-#define RWSEM_WAITING_BIAS		-__IA64_UL_CONST(0x0000000100000000)
+#define RWSEM_ACTIVE_BIAS		(1L)
+#define RWSEM_ACTIVE_MASK		(0xffffffffL)
+#define RWSEM_WAITING_BIAS		(-0x100000000L)
 #define RWSEM_ACTIVE_READ_BIAS		RWSEM_ACTIVE_BIAS
 #define RWSEM_ACTIVE_WRITE_BIAS		(RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
 
diff --git a/arch/mn10300/boot/compressed/misc.c b/arch/mn10300/boot/compressed/misc.c
index f673383..42cbd77 100644
--- a/arch/mn10300/boot/compressed/misc.c
+++ b/arch/mn10300/boot/compressed/misc.c
@@ -167,6 +167,7 @@
 static char *vidmem = (char *)0xb8000;
 static int lines, cols;
 
+#define BOOTLOADER_INFLATE
 #include "../../../../lib/inflate.c"
 
 static inline void scroll(void)
diff --git a/arch/mn10300/include/asm/gdb-stub.h b/arch/mn10300/include/asm/gdb-stub.h
index 556cce9..41ed2676 100644
--- a/arch/mn10300/include/asm/gdb-stub.h
+++ b/arch/mn10300/include/asm/gdb-stub.h
@@ -157,25 +157,25 @@
 #ifdef CONFIG_GDBSTUB_DEBUG_ENTRY
 #define gdbstub_entry(FMT, ...) gdbstub_printk(FMT, ##__VA_ARGS__)
 #else
-#define gdbstub_entry(FMT, ...) ({ 0; })
+#define gdbstub_entry(FMT, ...) no_printk(FMT, ##__VA_ARGS__)
 #endif
 
 #ifdef CONFIG_GDBSTUB_DEBUG_PROTOCOL
 #define gdbstub_proto(FMT, ...) gdbstub_printk(FMT, ##__VA_ARGS__)
 #else
-#define gdbstub_proto(FMT, ...) ({ 0; })
+#define gdbstub_proto(FMT, ...) no_printk(FMT, ##__VA_ARGS__)
 #endif
 
 #ifdef CONFIG_GDBSTUB_DEBUG_IO
 #define gdbstub_io(FMT, ...) gdbstub_printk(FMT, ##__VA_ARGS__)
 #else
-#define gdbstub_io(FMT, ...) ({ 0; })
+#define gdbstub_io(FMT, ...) no_printk(FMT, ##__VA_ARGS__)
 #endif
 
 #ifdef CONFIG_GDBSTUB_DEBUG_BREAKPOINT
 #define gdbstub_bkpt(FMT, ...) gdbstub_printk(FMT, ##__VA_ARGS__)
 #else
-#define gdbstub_bkpt(FMT, ...) ({ 0; })
+#define gdbstub_bkpt(FMT, ...) no_printk(FMT, ##__VA_ARGS__)
 #endif
 
 #endif /* !__ASSEMBLY__ */
diff --git a/arch/mn10300/include/asm/posix_types.h b/arch/mn10300/include/asm/posix_types.h
index 077567c..56ffbc1 100644
--- a/arch/mn10300/include/asm/posix_types.h
+++ b/arch/mn10300/include/asm/posix_types.h
@@ -25,8 +25,13 @@
 typedef unsigned short	__kernel_ipc_pid_t;
 typedef unsigned short	__kernel_uid_t;
 typedef unsigned short	__kernel_gid_t;
+#if __GNUC__ == 4
+typedef unsigned int	__kernel_size_t;
+typedef signed int	__kernel_ssize_t;
+#else
 typedef unsigned long	__kernel_size_t;
-typedef long		__kernel_ssize_t;
+typedef signed long	__kernel_ssize_t;
+#endif
 typedef int		__kernel_ptrdiff_t;
 typedef long		__kernel_time_t;
 typedef long		__kernel_suseconds_t;
diff --git a/arch/mn10300/kernel/mn10300-serial.c b/arch/mn10300/kernel/mn10300-serial.c
index ef34d5a..9d49073 100644
--- a/arch/mn10300/kernel/mn10300-serial.c
+++ b/arch/mn10300/kernel/mn10300-serial.c
@@ -44,11 +44,6 @@
 #include <unit/timex.h>
 #include "mn10300-serial.h"
 
-static inline __attribute__((format(printf, 1, 2)))
-void no_printk(const char *fmt, ...)
-{
-}
-
 #define kenter(FMT, ...) \
 	printk(KERN_DEBUG "-->%s(" FMT ")\n", __func__, ##__VA_ARGS__)
 #define _enter(FMT, ...) \
diff --git a/arch/mn10300/kernel/rtc.c b/arch/mn10300/kernel/rtc.c
index 815a933..4eef0e7 100644
--- a/arch/mn10300/kernel/rtc.c
+++ b/arch/mn10300/kernel/rtc.c
@@ -20,9 +20,6 @@
 DEFINE_SPINLOCK(rtc_lock);
 EXPORT_SYMBOL(rtc_lock);
 
-/* last time the RTC got updated */
-static long last_rtc_update;
-
 /* time for RTC to update itself in ioclks */
 static unsigned long mn10300_rtc_update_period;
 
@@ -110,7 +107,7 @@
 
 int update_persistent_clock(struct timespec now)
 {
-	return set_rtc_mms(now.tv_sec);
+	return set_rtc_mmss(now.tv_sec);
 }
 
 /*
diff --git a/arch/parisc/mm/ioremap.c b/arch/parisc/mm/ioremap.c
index 92d496a..838d025 100644
--- a/arch/parisc/mm/ioremap.c
+++ b/arch/parisc/mm/ioremap.c
@@ -71,7 +71,7 @@
 	 */
 	offset = phys_addr & ~PAGE_MASK;
 	phys_addr &= PAGE_MASK;
-	size = PAGE_ALIGN(last_addr) - phys_addr;
+	size = PAGE_ALIGN(last_addr + 1) - phys_addr;
 
 	/*
 	 * Ok, go for it..
diff --git a/arch/powerpc/platforms/83xx/mpc837x_mds.c b/arch/powerpc/platforms/83xx/mpc837x_mds.c
index 51df7e75..f9751c8 100644
--- a/arch/powerpc/platforms/83xx/mpc837x_mds.c
+++ b/arch/powerpc/platforms/83xx/mpc837x_mds.c
@@ -102,7 +102,7 @@
 
 static int __init mpc837x_declare_of_platform_devices(void)
 {
-	/* Publish of_device */
+	/* Publish platform_device */
 	of_platform_bus_probe(NULL, mpc837x_ids, NULL);
 
 	return 0;
diff --git a/arch/powerpc/platforms/83xx/mpc837x_rdb.c b/arch/powerpc/platforms/83xx/mpc837x_rdb.c
index e00801c..910caa6 100644
--- a/arch/powerpc/platforms/83xx/mpc837x_rdb.c
+++ b/arch/powerpc/platforms/83xx/mpc837x_rdb.c
@@ -78,7 +78,7 @@
 
 static int __init mpc837x_declare_of_platform_devices(void)
 {
-	/* Publish of_device */
+	/* Publish platform_device */
 	of_platform_bus_probe(NULL, mpc837x_ids, NULL);
 
 	return 0;
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c
index 8bd8653..6425abe 100644
--- a/arch/powerpc/sysdev/fsl_rio.c
+++ b/arch/powerpc/sysdev/fsl_rio.c
@@ -1332,7 +1332,7 @@
 
 /**
  * fsl_rio_setup - Setup Freescale PowerPC RapidIO interface
- * @dev: of_device pointer
+ * @dev: platform_device pointer
  *
  * Initializes MPC85xx RapidIO hardware interface, configures
  * master port with system-specific info, and registers the
diff --git a/arch/score/mm/tlb-score.c b/arch/score/mm/tlb-score.c
index 4fa5aa5..6fdb1002 100644
--- a/arch/score/mm/tlb-score.c
+++ b/arch/score/mm/tlb-score.c
@@ -158,7 +158,7 @@
 
 void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
 {
-	if (!vma || vma->vm_mm->context != 0) {
+	if (vma && vma->vm_mm->context != 0) {
 		unsigned long flags;
 		int oldpid, newpid, idx;
 		unsigned long vma_ASID = vma->vm_mm->context;
diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c
index 68142df..0c46e39 100644
--- a/arch/um/drivers/hostaudio_kern.c
+++ b/arch/um/drivers/hostaudio_kern.c
@@ -187,7 +187,9 @@
 	int ret;
 
 #ifdef DEBUG
+	kparam_block_sysfs_write(dsp);
 	printk(KERN_DEBUG "hostaudio: open called (host: %s)\n", dsp);
+	kparam_unblock_sysfs_write(dsp);
 #endif
 
 	state = kmalloc(sizeof(struct hostaudio_state), GFP_KERNEL);
@@ -199,9 +201,11 @@
 	if (file->f_mode & FMODE_WRITE)
 		w = 1;
 
+	kparam_block_sysfs_write(dsp);
 	lock_kernel();
 	ret = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0);
 	unlock_kernel();
+	kparam_unblock_sysfs_write(dsp);
 
 	if (ret < 0) {
 		kfree(state);
@@ -258,13 +262,17 @@
 	if (file->f_mode & FMODE_WRITE)
 		w = 1;
 
+	kparam_block_sysfs_write(mixer);
 	lock_kernel();
 	ret = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0);
 	unlock_kernel();
+	kparam_unblock_sysfs_write(mixer);
 
 	if (ret < 0) {
+		kparam_block_sysfs_write(dsp);
 		printk(KERN_ERR "hostaudio_open_mixdev failed to open '%s', "
 		       "err = %d\n", dsp, -ret);
+		kparam_unblock_sysfs_write(dsp);
 		kfree(state);
 		return ret;
 	}
@@ -320,8 +328,10 @@
 
 static int __init hostaudio_init_module(void)
 {
+	__kernel_param_lock();
 	printk(KERN_INFO "UML Audio Relay (host dsp = %s, host mixer = %s)\n",
 	       dsp, mixer);
+	__kernel_param_unlock();
 
 	module_data.dev_audio = register_sound_dsp(&hostaudio_fops, -1);
 	if (module_data.dev_audio < 0) {
diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h
index 018a0a4..bf5f7d3 100644
--- a/arch/x86/include/asm/xen/page.h
+++ b/arch/x86/include/asm/xen/page.h
@@ -112,13 +112,9 @@
  */
 static inline unsigned long mfn_to_local_pfn(unsigned long mfn)
 {
-	extern unsigned long max_mapnr;
 	unsigned long pfn = mfn_to_pfn(mfn);
-	if ((pfn < max_mapnr)
-	    && !xen_feature(XENFEAT_auto_translated_physmap)
-	    && (get_phys_to_machine(pfn) != mfn))
-		return max_mapnr; /* force !pfn_valid() */
-	/* XXX fixme; not true with sparsemem */
+	if (get_phys_to_machine(pfn) != mfn)
+		return -1; /* force !pfn_valid() */
 	return pfn;
 }
 
diff --git a/arch/x86/include/asm/xen/swiotlb-xen.h b/arch/x86/include/asm/xen/swiotlb-xen.h
new file mode 100644
index 0000000..1be1ab7
--- /dev/null
+++ b/arch/x86/include/asm/xen/swiotlb-xen.h
@@ -0,0 +1,14 @@
+#ifndef _ASM_X86_SWIOTLB_XEN_H
+#define _ASM_X86_SWIOTLB_XEN_H
+
+#ifdef CONFIG_SWIOTLB_XEN
+extern int xen_swiotlb;
+extern int __init pci_xen_swiotlb_detect(void);
+extern void __init pci_xen_swiotlb_init(void);
+#else
+#define xen_swiotlb (0)
+static inline int __init pci_xen_swiotlb_detect(void) { return 0; }
+static inline void __init pci_xen_swiotlb_init(void) { }
+#endif
+
+#endif /* _ASM_X86_SWIOTLB_XEN_H */
diff --git a/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c
index a36de5b..994230d 100644
--- a/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c
+++ b/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c
@@ -110,7 +110,7 @@
 	u32 output_offset;
 };
 
-static struct pcc_cpu *pcc_cpu_info;
+static struct pcc_cpu __percpu *pcc_cpu_info;
 
 static int pcc_cpufreq_verify(struct cpufreq_policy *policy)
 {
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index 33dbcc4..351f9c0 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -582,7 +582,7 @@
 	 * scaled math multiplication factor for nanosecond to hpet tick
 	 * conversion.
 	 */
-	hpet_freq = 1000000000000000ULL;
+	hpet_freq = FSEC_PER_SEC;
 	do_div(hpet_freq, hpet_period);
 	evt->mult = div_sc((unsigned long) hpet_freq,
 				      NSEC_PER_SEC, evt->shift);
@@ -837,7 +837,7 @@
 	 * cyc/sec = FSEC_PER_SEC/hpet_period(fsec/cyc)
 	 * cyc/sec = (FSEC_PER_NSEC * NSEC_PER_SEC)/hpet_period
 	 */
-	hpet_freq = FSEC_PER_NSEC * NSEC_PER_SEC;
+	hpet_freq = FSEC_PER_SEC;
 	do_div(hpet_freq, hpet_period);
 	clocksource_register_hz(&clocksource_hpet, (u32)hpet_freq);
 
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
index 4b7e3d8..9f07cfc 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -13,6 +13,7 @@
 #include <asm/calgary.h>
 #include <asm/amd_iommu.h>
 #include <asm/x86_init.h>
+#include <asm/xen/swiotlb-xen.h>
 
 static int forbid_dac __read_mostly;
 
@@ -132,7 +133,7 @@
 	/* free the range so iommu could get some range less than 4G */
 	dma32_free_bootmem();
 
-	if (pci_swiotlb_detect())
+	if (pci_xen_swiotlb_detect() || pci_swiotlb_detect())
 		goto out;
 
 	gart_iommu_hole_init();
@@ -144,6 +145,8 @@
 	/* needs to be called after gart_iommu_hole_init */
 	amd_iommu_detect();
 out:
+	pci_xen_swiotlb_init();
+
 	pci_swiotlb_init();
 }
 
@@ -296,7 +299,7 @@
 #endif
 	x86_init.iommu.iommu_init();
 
-	if (swiotlb) {
+	if (swiotlb || xen_swiotlb) {
 		printk(KERN_INFO "PCI-DMA: "
 		       "Using software bounce buffering for IO (SWIOTLB)\n");
 		swiotlb_print_info();
diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile
index 9309546..7793851 100644
--- a/arch/x86/xen/Makefile
+++ b/arch/x86/xen/Makefile
@@ -18,3 +18,4 @@
 obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o
 obj-$(CONFIG_XEN_DEBUG_FS)	+= debugfs.o
 
+obj-$(CONFIG_SWIOTLB_XEN)	+= pci-swiotlb-xen.o
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index d4ff5e8..7d46c84 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -1172,6 +1172,10 @@
 
 	pgd = (pgd_t *)xen_start_info->pt_base;
 
+	if (!xen_initial_domain())
+		__supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD);
+
+	__supported_pte_mask |= _PAGE_IOMAP;
 	/* Don't do the full vcpu_info placement stuff until we have a
 	   possible map and a non-dummy shared_info. */
 	per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0];
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 413b19b..42086ac 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -42,6 +42,7 @@
 #include <linux/highmem.h>
 #include <linux/debugfs.h>
 #include <linux/bug.h>
+#include <linux/vmalloc.h>
 #include <linux/module.h>
 #include <linux/gfp.h>
 
@@ -51,15 +52,19 @@
 #include <asm/mmu_context.h>
 #include <asm/setup.h>
 #include <asm/paravirt.h>
+#include <asm/e820.h>
 #include <asm/linkage.h>
+#include <asm/page.h>
 
 #include <asm/xen/hypercall.h>
 #include <asm/xen/hypervisor.h>
 
+#include <xen/xen.h>
 #include <xen/page.h>
 #include <xen/interface/xen.h>
 #include <xen/interface/hvm/hvm_op.h>
 #include <xen/interface/version.h>
+#include <xen/interface/memory.h>
 #include <xen/hvc-console.h>
 
 #include "multicalls.h"
@@ -68,6 +73,13 @@
 
 #define MMU_UPDATE_HISTO	30
 
+/*
+ * Protects atomic reservation decrease/increase against concurrent increases.
+ * Also protects non-atomic updates of current_pages and driver_pages, and
+ * balloon lists.
+ */
+DEFINE_SPINLOCK(xen_reservation_lock);
+
 #ifdef CONFIG_XEN_DEBUG_FS
 
 static struct {
@@ -378,6 +390,28 @@
 	return PagePinned(page);
 }
 
+static bool xen_iomap_pte(pte_t pte)
+{
+	return pte_flags(pte) & _PAGE_IOMAP;
+}
+
+static void xen_set_iomap_pte(pte_t *ptep, pte_t pteval)
+{
+	struct multicall_space mcs;
+	struct mmu_update *u;
+
+	mcs = xen_mc_entry(sizeof(*u));
+	u = mcs.args;
+
+	/* ptep might be kmapped when using 32-bit HIGHPTE */
+	u->ptr = arbitrary_virt_to_machine(ptep).maddr;
+	u->val = pte_val_ma(pteval);
+
+	MULTI_mmu_update(mcs.mc, mcs.args, 1, NULL, DOMID_IO);
+
+	xen_mc_issue(PARAVIRT_LAZY_MMU);
+}
+
 static void xen_extend_mmu_update(const struct mmu_update *update)
 {
 	struct multicall_space mcs;
@@ -454,6 +488,11 @@
 void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
 		    pte_t *ptep, pte_t pteval)
 {
+	if (xen_iomap_pte(pteval)) {
+		xen_set_iomap_pte(ptep, pteval);
+		goto out;
+	}
+
 	ADD_STATS(set_pte_at, 1);
 //	ADD_STATS(set_pte_at_pinned, xen_page_pinned(ptep));
 	ADD_STATS(set_pte_at_current, mm == current->mm);
@@ -524,8 +563,25 @@
 	return val;
 }
 
+static pteval_t iomap_pte(pteval_t val)
+{
+	if (val & _PAGE_PRESENT) {
+		unsigned long pfn = (val & PTE_PFN_MASK) >> PAGE_SHIFT;
+		pteval_t flags = val & PTE_FLAGS_MASK;
+
+		/* We assume the pte frame number is a MFN, so
+		   just use it as-is. */
+		val = ((pteval_t)pfn << PAGE_SHIFT) | flags;
+	}
+
+	return val;
+}
+
 pteval_t xen_pte_val(pte_t pte)
 {
+	if (xen_initial_domain() && (pte.pte & _PAGE_IOMAP))
+		return pte.pte;
+
 	return pte_mfn_to_pfn(pte.pte);
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_pte_val);
@@ -538,7 +594,22 @@
 
 pte_t xen_make_pte(pteval_t pte)
 {
-	pte = pte_pfn_to_mfn(pte);
+	phys_addr_t addr = (pte & PTE_PFN_MASK);
+
+	/*
+	 * Unprivileged domains are allowed to do IOMAPpings for
+	 * PCI passthrough, but not map ISA space.  The ISA
+	 * mappings are just dummy local mappings to keep other
+	 * parts of the kernel happy.
+	 */
+	if (unlikely(pte & _PAGE_IOMAP) &&
+	    (xen_initial_domain() || addr >= ISA_END_ADDRESS)) {
+		pte = iomap_pte(pte);
+	} else {
+		pte &= ~_PAGE_IOMAP;
+		pte = pte_pfn_to_mfn(pte);
+	}
+
 	return native_make_pte(pte);
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte);
@@ -594,6 +665,11 @@
 
 void xen_set_pte(pte_t *ptep, pte_t pte)
 {
+	if (xen_iomap_pte(pte)) {
+		xen_set_iomap_pte(ptep, pte);
+		return;
+	}
+
 	ADD_STATS(pte_update, 1);
 //	ADD_STATS(pte_update_pinned, xen_page_pinned(ptep));
 	ADD_STATS(pte_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
@@ -610,6 +686,11 @@
 #ifdef CONFIG_X86_PAE
 void xen_set_pte_atomic(pte_t *ptep, pte_t pte)
 {
+	if (xen_iomap_pte(pte)) {
+		xen_set_iomap_pte(ptep, pte);
+		return;
+	}
+
 	set_64bit((u64 *)ptep, native_pte_val(pte));
 }
 
@@ -936,8 +1017,6 @@
    read-only, and can be pinned. */
 static void __xen_pgd_pin(struct mm_struct *mm, pgd_t *pgd)
 {
-	vm_unmap_aliases();
-
 	xen_mc_batch();
 
 	if (__xen_pgd_walk(mm, pgd, xen_pin_page, USER_LIMIT)) {
@@ -1501,7 +1580,6 @@
 	if (PagePinned(virt_to_page(mm->pgd))) {
 		SetPagePinned(page);
 
-		vm_unmap_aliases();
 		if (!PageHighMem(page)) {
 			make_lowmem_page_readonly(__va(PFN_PHYS((unsigned long)pfn)));
 			if (level == PT_PTE && USE_SPLIT_PTLOCKS)
@@ -1812,9 +1890,16 @@
 		pte = pfn_pte(phys, prot);
 		break;
 
-	default:
+	case FIX_PARAVIRT_BOOTMAP:
+		/* This is an MFN, but it isn't an IO mapping from the
+		   IO domain */
 		pte = mfn_pte(phys, prot);
 		break;
+
+	default:
+		/* By default, set_fixmap is used for hardware mappings */
+		pte = mfn_pte(phys, __pgprot(pgprot_val(prot) | _PAGE_IOMAP));
+		break;
 	}
 
 	__native_set_fixmap(idx, pte);
@@ -1940,8 +2025,206 @@
 	x86_init.paging.pagetable_setup_start = xen_pagetable_setup_start;
 	x86_init.paging.pagetable_setup_done = xen_pagetable_setup_done;
 	pv_mmu_ops = xen_mmu_ops;
+
+	vmap_lazy_unmap = false;
 }
 
+/* Protected by xen_reservation_lock. */
+#define MAX_CONTIG_ORDER 9 /* 2MB */
+static unsigned long discontig_frames[1<<MAX_CONTIG_ORDER];
+
+#define VOID_PTE (mfn_pte(0, __pgprot(0)))
+static void xen_zap_pfn_range(unsigned long vaddr, unsigned int order,
+				unsigned long *in_frames,
+				unsigned long *out_frames)
+{
+	int i;
+	struct multicall_space mcs;
+
+	xen_mc_batch();
+	for (i = 0; i < (1UL<<order); i++, vaddr += PAGE_SIZE) {
+		mcs = __xen_mc_entry(0);
+
+		if (in_frames)
+			in_frames[i] = virt_to_mfn(vaddr);
+
+		MULTI_update_va_mapping(mcs.mc, vaddr, VOID_PTE, 0);
+		set_phys_to_machine(virt_to_pfn(vaddr), INVALID_P2M_ENTRY);
+
+		if (out_frames)
+			out_frames[i] = virt_to_pfn(vaddr);
+	}
+	xen_mc_issue(0);
+}
+
+/*
+ * Update the pfn-to-mfn mappings for a virtual address range, either to
+ * point to an array of mfns, or contiguously from a single starting
+ * mfn.
+ */
+static void xen_remap_exchanged_ptes(unsigned long vaddr, int order,
+				     unsigned long *mfns,
+				     unsigned long first_mfn)
+{
+	unsigned i, limit;
+	unsigned long mfn;
+
+	xen_mc_batch();
+
+	limit = 1u << order;
+	for (i = 0; i < limit; i++, vaddr += PAGE_SIZE) {
+		struct multicall_space mcs;
+		unsigned flags;
+
+		mcs = __xen_mc_entry(0);
+		if (mfns)
+			mfn = mfns[i];
+		else
+			mfn = first_mfn + i;
+
+		if (i < (limit - 1))
+			flags = 0;
+		else {
+			if (order == 0)
+				flags = UVMF_INVLPG | UVMF_ALL;
+			else
+				flags = UVMF_TLB_FLUSH | UVMF_ALL;
+		}
+
+		MULTI_update_va_mapping(mcs.mc, vaddr,
+				mfn_pte(mfn, PAGE_KERNEL), flags);
+
+		set_phys_to_machine(virt_to_pfn(vaddr), mfn);
+	}
+
+	xen_mc_issue(0);
+}
+
+/*
+ * Perform the hypercall to exchange a region of our pfns to point to
+ * memory with the required contiguous alignment.  Takes the pfns as
+ * input, and populates mfns as output.
+ *
+ * Returns a success code indicating whether the hypervisor was able to
+ * satisfy the request or not.
+ */
+static int xen_exchange_memory(unsigned long extents_in, unsigned int order_in,
+			       unsigned long *pfns_in,
+			       unsigned long extents_out,
+			       unsigned int order_out,
+			       unsigned long *mfns_out,
+			       unsigned int address_bits)
+{
+	long rc;
+	int success;
+
+	struct xen_memory_exchange exchange = {
+		.in = {
+			.nr_extents   = extents_in,
+			.extent_order = order_in,
+			.extent_start = pfns_in,
+			.domid        = DOMID_SELF
+		},
+		.out = {
+			.nr_extents   = extents_out,
+			.extent_order = order_out,
+			.extent_start = mfns_out,
+			.address_bits = address_bits,
+			.domid        = DOMID_SELF
+		}
+	};
+
+	BUG_ON(extents_in << order_in != extents_out << order_out);
+
+	rc = HYPERVISOR_memory_op(XENMEM_exchange, &exchange);
+	success = (exchange.nr_exchanged == extents_in);
+
+	BUG_ON(!success && ((exchange.nr_exchanged != 0) || (rc == 0)));
+	BUG_ON(success && (rc != 0));
+
+	return success;
+}
+
+int xen_create_contiguous_region(unsigned long vstart, unsigned int order,
+				 unsigned int address_bits)
+{
+	unsigned long *in_frames = discontig_frames, out_frame;
+	unsigned long  flags;
+	int            success;
+
+	/*
+	 * Currently an auto-translated guest will not perform I/O, nor will
+	 * it require PAE page directories below 4GB. Therefore any calls to
+	 * this function are redundant and can be ignored.
+	 */
+
+	if (xen_feature(XENFEAT_auto_translated_physmap))
+		return 0;
+
+	if (unlikely(order > MAX_CONTIG_ORDER))
+		return -ENOMEM;
+
+	memset((void *) vstart, 0, PAGE_SIZE << order);
+
+	spin_lock_irqsave(&xen_reservation_lock, flags);
+
+	/* 1. Zap current PTEs, remembering MFNs. */
+	xen_zap_pfn_range(vstart, order, in_frames, NULL);
+
+	/* 2. Get a new contiguous memory extent. */
+	out_frame = virt_to_pfn(vstart);
+	success = xen_exchange_memory(1UL << order, 0, in_frames,
+				      1, order, &out_frame,
+				      address_bits);
+
+	/* 3. Map the new extent in place of old pages. */
+	if (success)
+		xen_remap_exchanged_ptes(vstart, order, NULL, out_frame);
+	else
+		xen_remap_exchanged_ptes(vstart, order, in_frames, 0);
+
+	spin_unlock_irqrestore(&xen_reservation_lock, flags);
+
+	return success ? 0 : -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(xen_create_contiguous_region);
+
+void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order)
+{
+	unsigned long *out_frames = discontig_frames, in_frame;
+	unsigned long  flags;
+	int success;
+
+	if (xen_feature(XENFEAT_auto_translated_physmap))
+		return;
+
+	if (unlikely(order > MAX_CONTIG_ORDER))
+		return;
+
+	memset((void *) vstart, 0, PAGE_SIZE << order);
+
+	spin_lock_irqsave(&xen_reservation_lock, flags);
+
+	/* 1. Find start MFN of contiguous extent. */
+	in_frame = virt_to_mfn(vstart);
+
+	/* 2. Zap current PTEs. */
+	xen_zap_pfn_range(vstart, order, NULL, out_frames);
+
+	/* 3. Do the exchange for non-contiguous MFNs. */
+	success = xen_exchange_memory(1, order, &in_frame, 1UL << order,
+					0, out_frames, 0);
+
+	/* 4. Map new pages in place of old pages. */
+	if (success)
+		xen_remap_exchanged_ptes(vstart, order, out_frames, 0);
+	else
+		xen_remap_exchanged_ptes(vstart, order, NULL, in_frame);
+
+	spin_unlock_irqrestore(&xen_reservation_lock, flags);
+}
+EXPORT_SYMBOL_GPL(xen_destroy_contiguous_region);
+
 #ifdef CONFIG_XEN_PVHVM
 static void xen_hvm_exit_mmap(struct mm_struct *mm)
 {
diff --git a/arch/x86/xen/pci-swiotlb-xen.c b/arch/x86/xen/pci-swiotlb-xen.c
new file mode 100644
index 0000000..a013ec9
--- /dev/null
+++ b/arch/x86/xen/pci-swiotlb-xen.c
@@ -0,0 +1,58 @@
+/* Glue code to lib/swiotlb-xen.c */
+
+#include <linux/dma-mapping.h>
+#include <xen/swiotlb-xen.h>
+
+#include <asm/xen/hypervisor.h>
+#include <xen/xen.h>
+
+int xen_swiotlb __read_mostly;
+
+static struct dma_map_ops xen_swiotlb_dma_ops = {
+	.mapping_error = xen_swiotlb_dma_mapping_error,
+	.alloc_coherent = xen_swiotlb_alloc_coherent,
+	.free_coherent = xen_swiotlb_free_coherent,
+	.sync_single_for_cpu = xen_swiotlb_sync_single_for_cpu,
+	.sync_single_for_device = xen_swiotlb_sync_single_for_device,
+	.sync_sg_for_cpu = xen_swiotlb_sync_sg_for_cpu,
+	.sync_sg_for_device = xen_swiotlb_sync_sg_for_device,
+	.map_sg = xen_swiotlb_map_sg_attrs,
+	.unmap_sg = xen_swiotlb_unmap_sg_attrs,
+	.map_page = xen_swiotlb_map_page,
+	.unmap_page = xen_swiotlb_unmap_page,
+	.dma_supported = xen_swiotlb_dma_supported,
+};
+
+/*
+ * pci_xen_swiotlb_detect - set xen_swiotlb to 1 if necessary
+ *
+ * This returns non-zero if we are forced to use xen_swiotlb (by the boot
+ * option).
+ */
+int __init pci_xen_swiotlb_detect(void)
+{
+
+	/* If running as PV guest, either iommu=soft, or swiotlb=force will
+	 * activate this IOMMU. If running as PV privileged, activate it
+	 * irregardlesss.
+	 */
+	if ((xen_initial_domain() || swiotlb || swiotlb_force) &&
+	    (xen_pv_domain()))
+		xen_swiotlb = 1;
+
+	/* If we are running under Xen, we MUST disable the native SWIOTLB.
+	 * Don't worry about swiotlb_force flag activating the native, as
+	 * the 'swiotlb' flag is the only one turning it on. */
+	if (xen_pv_domain())
+		swiotlb = 0;
+
+	return xen_swiotlb;
+}
+
+void __init pci_xen_swiotlb_init(void)
+{
+	if (xen_swiotlb) {
+		xen_swiotlb_init(1);
+		dma_ops = &xen_swiotlb_dma_ops;
+	}
+}
diff --git a/block/blk-core.c b/block/blk-core.c
index 7da630e..ee1a1e7 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -1514,7 +1514,10 @@
 		if (bio_check_eod(bio, nr_sectors))
 			goto end_io;
 
-		if ((bio->bi_rw & REQ_DISCARD) && !blk_queue_discard(q)) {
+		if ((bio->bi_rw & REQ_DISCARD) &&
+		    (!blk_queue_discard(q) ||
+		     ((bio->bi_rw & REQ_SECURE) &&
+		      !blk_queue_secdiscard(q)))) {
 			err = -EOPNOTSUPP;
 			goto end_io;
 		}
diff --git a/block/blk-lib.c b/block/blk-lib.c
index c1fc55a..c392029 100644
--- a/block/blk-lib.c
+++ b/block/blk-lib.c
@@ -62,6 +62,12 @@
 		max_discard_sectors &= ~(disc_sects - 1);
 	}
 
+	if (flags & BLKDEV_IFL_SECURE) {
+		if (!blk_queue_secdiscard(q))
+			return -EOPNOTSUPP;
+		type |= DISCARD_SECURE;
+	}
+
 	while (nr_sects && !ret) {
 		bio = bio_alloc(gfp_mask, 1);
 		if (!bio) {
diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
index d530856..119f07b 100644
--- a/block/compat_ioctl.c
+++ b/block/compat_ioctl.c
@@ -703,6 +703,7 @@
 	case BLKFLSBUF:
 	case BLKROSET:
 	case BLKDISCARD:
+	case BLKSECDISCARD:
 	/*
 	 * the ones below are implemented in blkdev_locked_ioctl,
 	 * but we call blkdev_ioctl, which gets the lock for us
diff --git a/block/elevator.c b/block/elevator.c
index 816a7c8..ec585c9 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -83,6 +83,12 @@
 		return 0;
 
 	/*
+	 * Don't merge discard requests and secure discard requests
+	 */
+	if ((bio->bi_rw & REQ_SECURE) != (rq->bio->bi_rw & REQ_SECURE))
+		return 0;
+
+	/*
 	 * different data direction or already started, don't merge
 	 */
 	if (bio_data_dir(bio) != rq_data_dir(rq))
diff --git a/block/ioctl.c b/block/ioctl.c
index 09fd7f1..d8052f0 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -114,8 +114,10 @@
 }
 
 static int blk_ioctl_discard(struct block_device *bdev, uint64_t start,
-			     uint64_t len)
+			     uint64_t len, int secure)
 {
+	unsigned long flags = BLKDEV_IFL_WAIT;
+
 	if (start & 511)
 		return -EINVAL;
 	if (len & 511)
@@ -125,8 +127,9 @@
 
 	if (start + len > (bdev->bd_inode->i_size >> 9))
 		return -EINVAL;
-	return blkdev_issue_discard(bdev, start, len, GFP_KERNEL,
-				    BLKDEV_IFL_WAIT);
+	if (secure)
+		flags |= BLKDEV_IFL_SECURE;
+	return blkdev_issue_discard(bdev, start, len, GFP_KERNEL, flags);
 }
 
 static int put_ushort(unsigned long arg, unsigned short val)
@@ -213,7 +216,8 @@
 		set_device_ro(bdev, n);
 		return 0;
 
-	case BLKDISCARD: {
+	case BLKDISCARD:
+	case BLKSECDISCARD: {
 		uint64_t range[2];
 
 		if (!(mode & FMODE_WRITE))
@@ -222,7 +226,8 @@
 		if (copy_from_user(range, (void __user *)arg, sizeof(range)))
 			return -EFAULT;
 
-		return blk_ioctl_discard(bdev, range[0], range[1]);
+		return blk_ioctl_discard(bdev, range[0], range[1],
+					 cmd == BLKSECDISCARD);
 	}
 
 	case HDIO_GETGEO: {
diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c
index 864dd46..18645f4 100644
--- a/drivers/acpi/apei/erst.c
+++ b/drivers/acpi/apei/erst.c
@@ -33,6 +33,7 @@
 #include <linux/uaccess.h>
 #include <linux/cper.h>
 #include <linux/nmi.h>
+#include <linux/hardirq.h>
 #include <acpi/apei.h>
 
 #include "apei-internal.h"
diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c
index 146135e..295dbfa 100644
--- a/drivers/acpi/debug.c
+++ b/drivers/acpi/debug.c
@@ -96,7 +96,8 @@
 /* --------------------------------------------------------------------------
                               FS Interface (/sys)
    -------------------------------------------------------------------------- */
-static int param_get_debug_layer(char *buffer, struct kernel_param *kp) {
+static int param_get_debug_layer(char *buffer, const struct kernel_param *kp)
+{
 	int result = 0;
 	int i;
 
@@ -118,7 +119,8 @@
 	return result;
 }
 
-static int param_get_debug_level(char *buffer, struct kernel_param *kp) {
+static int param_get_debug_level(char *buffer, const struct kernel_param *kp)
+{
 	int result = 0;
 	int i;
 
@@ -137,8 +139,18 @@
 	return result;
 }
 
-module_param_call(debug_layer, param_set_uint, param_get_debug_layer, &acpi_dbg_layer, 0644);
-module_param_call(debug_level, param_set_uint, param_get_debug_level, &acpi_dbg_level, 0644);
+static struct kernel_param_ops acpi_debug_layer_ops = {
+	.set = param_set_uint,
+	.get = param_get_debug_layer,
+};
+
+static struct kernel_param_ops acpi_debug_level_ops = {
+	.set = param_set_uint,
+	.get = param_get_debug_level,
+};
+
+module_param_cb(debug_layer, &acpi_debug_layer_ops, &acpi_dbg_layer, 0644);
+module_param_cb(debug_level, &acpi_debug_level_ops, &acpi_dbg_level, 0644);
 
 static char trace_method_name[6];
 module_param_string(trace_method_name, trace_method_name, 6, 0644);
@@ -147,7 +159,7 @@
 static unsigned int trace_debug_level;
 module_param(trace_debug_level, uint, 0644);
 
-static int param_set_trace_state(const char *val, struct kernel_param *kp)
+static int param_set_trace_state(const char *val, const struct kernel_param *kp)
 {
 	int result = 0;
 
@@ -181,7 +193,7 @@
 	return result;
 }
 
-static int param_get_trace_state(char *buffer, struct kernel_param *kp)
+static int param_get_trace_state(char *buffer, const struct kernel_param *kp)
 {
 	if (!acpi_gbl_trace_method_name)
 		return sprintf(buffer, "disable");
@@ -194,8 +206,12 @@
 	return 0;
 }
 
-module_param_call(trace_state, param_set_trace_state, param_get_trace_state,
-		  NULL, 0644);
+static struct kernel_param_ops param_ops_trace_state = {
+	.set = param_set_trace_state,
+	.get = param_get_trace_state,
+};
+
+module_param_cb(trace_state, &param_ops_trace_state, NULL, 0644);
 
 /* --------------------------------------------------------------------------
 				DebugFS Interface
diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
index f087ab5..8cc536e 100644
--- a/drivers/ata/pata_mpc52xx.c
+++ b/drivers/ata/pata_mpc52xx.c
@@ -680,7 +680,7 @@
 /* ======================================================================== */
 
 static int __devinit
-mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match)
+mpc52xx_ata_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	unsigned int ipb_freq;
 	struct resource res_mem;
@@ -821,7 +821,7 @@
 }
 
 static int
-mpc52xx_ata_remove(struct of_device *op)
+mpc52xx_ata_remove(struct platform_device *op)
 {
 	struct mpc52xx_ata_priv *priv;
 	int task_irq;
@@ -848,7 +848,7 @@
 #ifdef CONFIG_PM
 
 static int
-mpc52xx_ata_suspend(struct of_device *op, pm_message_t state)
+mpc52xx_ata_suspend(struct platform_device *op, pm_message_t state)
 {
 	struct ata_host *host = dev_get_drvdata(&op->dev);
 
@@ -856,7 +856,7 @@
 }
 
 static int
-mpc52xx_ata_resume(struct of_device *op)
+mpc52xx_ata_resume(struct platform_device *op)
 {
 	struct ata_host *host = dev_get_drvdata(&op->dev);
 	struct mpc52xx_ata_priv *priv = host->private_data;
diff --git a/drivers/ata/pata_of_platform.c b/drivers/ata/pata_of_platform.c
index 5a1b82c..480e043 100644
--- a/drivers/ata/pata_of_platform.c
+++ b/drivers/ata/pata_of_platform.c
@@ -14,7 +14,7 @@
 #include <linux/of_platform.h>
 #include <linux/ata_platform.h>
 
-static int __devinit pata_of_platform_probe(struct of_device *ofdev,
+static int __devinit pata_of_platform_probe(struct platform_device *ofdev,
 					    const struct of_device_id *match)
 {
 	int ret;
@@ -78,7 +78,7 @@
 				     reg_shift, pio_mask);
 }
 
-static int __devexit pata_of_platform_remove(struct of_device *ofdev)
+static int __devexit pata_of_platform_remove(struct platform_device *ofdev)
 {
 	return __pata_platform_remove(&ofdev->dev);
 }
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index 18c986d..7325f77 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -1296,7 +1296,7 @@
 	 },
 };
 
-static int sata_fsl_probe(struct of_device *ofdev,
+static int sata_fsl_probe(struct platform_device *ofdev,
 			const struct of_device_id *match)
 {
 	int retval = -ENXIO;
@@ -1370,7 +1370,7 @@
 	return retval;
 }
 
-static int sata_fsl_remove(struct of_device *ofdev)
+static int sata_fsl_remove(struct platform_device *ofdev)
 {
 	struct ata_host *host = dev_get_drvdata(&ofdev->dev);
 	struct sata_fsl_host_priv *host_priv = host->private_data;
@@ -1387,13 +1387,13 @@
 }
 
 #ifdef CONFIG_PM
-static int sata_fsl_suspend(struct of_device *op, pm_message_t state)
+static int sata_fsl_suspend(struct platform_device *op, pm_message_t state)
 {
 	struct ata_host *host = dev_get_drvdata(&op->dev);
 	return ata_host_suspend(host, state);
 }
 
-static int sata_fsl_resume(struct of_device *op)
+static int sata_fsl_resume(struct platform_device *op)
 {
 	struct ata_host *host = dev_get_drvdata(&op->dev);
 	struct sata_fsl_host_priv *host_priv = host->private_data;
diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
index b7385e0..c8fc69c 100644
--- a/drivers/atm/fore200e.c
+++ b/drivers/atm/fore200e.c
@@ -674,7 +674,7 @@
 
 static u32 fore200e_sba_dma_map(struct fore200e *fore200e, void* virt_addr, int size, int direction)
 {
-	struct of_device *op = fore200e->bus_dev;
+	struct platform_device *op = fore200e->bus_dev;
 	u32 dma_addr;
 
 	dma_addr = dma_map_single(&op->dev, virt_addr, size, direction);
@@ -687,7 +687,7 @@
 
 static void fore200e_sba_dma_unmap(struct fore200e *fore200e, u32 dma_addr, int size, int direction)
 {
-	struct of_device *op = fore200e->bus_dev;
+	struct platform_device *op = fore200e->bus_dev;
 
 	DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d,\n",
 		dma_addr, size, direction);
@@ -697,7 +697,7 @@
 
 static void fore200e_sba_dma_sync_for_cpu(struct fore200e *fore200e, u32 dma_addr, int size, int direction)
 {
-	struct of_device *op = fore200e->bus_dev;
+	struct platform_device *op = fore200e->bus_dev;
 
 	DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
     
@@ -706,7 +706,7 @@
 
 static void fore200e_sba_dma_sync_for_device(struct fore200e *fore200e, u32 dma_addr, int size, int direction)
 {
-	struct of_device *op = fore200e->bus_dev;
+	struct platform_device *op = fore200e->bus_dev;
 
 	DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
 
@@ -719,7 +719,7 @@
 static int fore200e_sba_dma_chunk_alloc(struct fore200e *fore200e, struct chunk *chunk,
 					int size, int nbr, int alignment)
 {
-	struct of_device *op = fore200e->bus_dev;
+	struct platform_device *op = fore200e->bus_dev;
 
 	chunk->alloc_size = chunk->align_size = size * nbr;
 
@@ -738,7 +738,7 @@
 /* free a DVMA consistent chunk of memory */
 static void fore200e_sba_dma_chunk_free(struct fore200e *fore200e, struct chunk *chunk)
 {
-	struct of_device *op = fore200e->bus_dev;
+	struct platform_device *op = fore200e->bus_dev;
 
 	dma_free_coherent(&op->dev, chunk->alloc_size,
 			  chunk->alloc_addr, chunk->dma_addr);
@@ -770,7 +770,7 @@
 
 static int __init fore200e_sba_map(struct fore200e *fore200e)
 {
-	struct of_device *op = fore200e->bus_dev;
+	struct platform_device *op = fore200e->bus_dev;
 	unsigned int bursts;
 
 	/* gain access to the SBA specific registers  */
@@ -800,7 +800,7 @@
 
 static void fore200e_sba_unmap(struct fore200e *fore200e)
 {
-	struct of_device *op = fore200e->bus_dev;
+	struct platform_device *op = fore200e->bus_dev;
 
 	of_iounmap(&op->resource[0], fore200e->regs.sba.hcr, SBA200E_HCR_LENGTH);
 	of_iounmap(&op->resource[1], fore200e->regs.sba.bsr, SBA200E_BSR_LENGTH);
@@ -816,7 +816,7 @@
 
 static int __init fore200e_sba_prom_read(struct fore200e *fore200e, struct prom_data *prom)
 {
-	struct of_device *op = fore200e->bus_dev;
+	struct platform_device *op = fore200e->bus_dev;
 	const u8 *prop;
 	int len;
 
@@ -840,7 +840,7 @@
 
 static int fore200e_sba_proc_read(struct fore200e *fore200e, char *page)
 {
-	struct of_device *op = fore200e->bus_dev;
+	struct platform_device *op = fore200e->bus_dev;
 	const struct linux_prom_registers *regs;
 
 	regs = of_get_property(op->dev.of_node, "reg", NULL);
@@ -2513,7 +2513,7 @@
 	device = &((struct pci_dev *) fore200e->bus_dev)->dev;
 #ifdef CONFIG_SBUS
     else if (strcmp(fore200e->bus->model_name, "SBA-200E") == 0)
-	device = &((struct of_device *) fore200e->bus_dev)->dev;
+	device = &((struct platform_device *) fore200e->bus_dev)->dev;
 #endif
     else
 	return err;
@@ -2643,7 +2643,7 @@
 }
 
 #ifdef CONFIG_SBUS
-static int __devinit fore200e_sba_probe(struct of_device *op,
+static int __devinit fore200e_sba_probe(struct platform_device *op,
 					const struct of_device_id *match)
 {
 	const struct fore200e_bus *bus = match->data;
@@ -2675,7 +2675,7 @@
 	return 0;
 }
 
-static int __devexit fore200e_sba_remove(struct of_device *op)
+static int __devexit fore200e_sba_remove(struct platform_device *op)
 {
 	struct fore200e *fore200e = dev_get_drvdata(&op->dev);
 
diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c
index b71888b..2982b3e 100644
--- a/drivers/block/xsysace.c
+++ b/drivers/block/xsysace.c
@@ -1194,7 +1194,7 @@
 
 #if defined(CONFIG_OF)
 static int __devinit
-ace_of_probe(struct of_device *op, const struct of_device_id *match)
+ace_of_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	struct resource res;
 	resource_size_t physaddr;
@@ -1226,7 +1226,7 @@
 	return ace_alloc(&op->dev, id ? *id : 0, physaddr, irq, bus_width);
 }
 
-static int __devexit ace_of_remove(struct of_device *op)
+static int __devexit ace_of_remove(struct platform_device *op)
 {
 	ace_free(&op->dev);
 	return 0;
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 7cfcc62..3d44ec7 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -1002,7 +1002,7 @@
 
 config PC8736x_GPIO
 	tristate "NatSemi PC8736x GPIO Support"
-	depends on X86
+	depends on X86_32
 	default SCx200_GPIO	# mostly N
 	select NSC_GPIO		# needed for support routines
 	help
diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c
index 5a80ad6..7b01bc6 100644
--- a/drivers/char/hvc_iucv.c
+++ b/drivers/char/hvc_iucv.c
@@ -1149,7 +1149,7 @@
  * Note: If it is called early in the boot process, @val is stored and
  *	 parsed later in hvc_iucv_init().
  */
-static int param_set_vmidfilter(const char *val, struct kernel_param *kp)
+static int param_set_vmidfilter(const char *val, const struct kernel_param *kp)
 {
 	int rc;
 
@@ -1176,7 +1176,7 @@
  * The function stores the filter as a comma-separated list of z/VM user IDs
  * in @buffer. Typically, sysfs routines call this function for attr show.
  */
-static int param_get_vmidfilter(char *buffer, struct kernel_param *kp)
+static int param_get_vmidfilter(char *buffer, const struct kernel_param *kp)
 {
 	int rc;
 	size_t index, len;
@@ -1203,6 +1203,11 @@
 
 #define param_check_vmidfilter(name, p) __param_check(name, p, void)
 
+static struct kernel_param_ops param_ops_vmidfilter = {
+	.set = param_set_vmidfilter,
+	.get = param_get_vmidfilter,
+};
+
 /**
  * hvc_iucv_init() - z/VM IUCV HVC device driver initialization
  */
diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c
index 7a4f080..1acdb25 100644
--- a/drivers/char/hw_random/n2-drv.c
+++ b/drivers/char/hw_random/n2-drv.c
@@ -619,7 +619,7 @@
 		pr_info("%s", version);
 }
 
-static int __devinit n2rng_probe(struct of_device *op,
+static int __devinit n2rng_probe(struct platform_device *op,
 				 const struct of_device_id *match)
 {
 	int victoria_falls = (match->data != NULL);
@@ -714,7 +714,7 @@
 	return err;
 }
 
-static int __devexit n2rng_remove(struct of_device *op)
+static int __devexit n2rng_remove(struct platform_device *op)
 {
 	struct n2rng *np = dev_get_drvdata(&op->dev);
 
diff --git a/drivers/char/hw_random/n2rng.h b/drivers/char/hw_random/n2rng.h
index a2b81e7..4bea07f 100644
--- a/drivers/char/hw_random/n2rng.h
+++ b/drivers/char/hw_random/n2rng.h
@@ -65,7 +65,7 @@
 };
 
 struct n2rng {
-	struct of_device	*op;
+	struct platform_device	*op;
 
 	unsigned long		flags;
 #define N2RNG_FLAG_VF		0x00000001 /* Victoria Falls RNG, else N2 */
diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c
index 261ba8f..a31c830 100644
--- a/drivers/char/hw_random/pasemi-rng.c
+++ b/drivers/char/hw_random/pasemi-rng.c
@@ -94,7 +94,7 @@
 	.data_read	= pasemi_rng_data_read,
 };
 
-static int __devinit rng_probe(struct of_device *ofdev,
+static int __devinit rng_probe(struct platform_device *ofdev,
 			       const struct of_device_id *match)
 {
 	void __iomem *rng_regs;
@@ -123,7 +123,7 @@
 	return err;
 }
 
-static int __devexit rng_remove(struct of_device *dev)
+static int __devexit rng_remove(struct platform_device *dev)
 {
 	void __iomem *rng_regs = (void __iomem *)pasemi_rng.priv;
 
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 48330e0f..3822b4f 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -2528,7 +2528,7 @@
 
 
 #ifdef CONFIG_PPC_OF
-static int __devinit ipmi_of_probe(struct of_device *dev,
+static int __devinit ipmi_of_probe(struct platform_device *dev,
 			 const struct of_device_id *match)
 {
 	struct smi_info *info;
@@ -2607,7 +2607,7 @@
 	return 0;
 }
 
-static int __devexit ipmi_of_remove(struct of_device *dev)
+static int __devexit ipmi_of_remove(struct platform_device *dev)
 {
 	cleanup_one_si(dev_get_drvdata(&dev->dev));
 	return 0;
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index 82bcdb2..654d566 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -196,7 +196,7 @@
  */
 static int start_now;
 
-static int set_param_int(const char *val, struct kernel_param *kp)
+static int set_param_timeout(const char *val, const struct kernel_param *kp)
 {
 	char *endp;
 	int  l;
@@ -215,10 +215,11 @@
 	return rv;
 }
 
-static int get_param_int(char *buffer, struct kernel_param *kp)
-{
-	return sprintf(buffer, "%i", *((int *)kp->arg));
-}
+static struct kernel_param_ops param_ops_timeout = {
+	.set = set_param_timeout,
+	.get = param_get_int,
+};
+#define param_check_timeout param_check_int
 
 typedef int (*action_fn)(const char *intval, char *outval);
 
@@ -227,7 +228,7 @@
 static int preop_op(const char *inval, char *outval);
 static void check_parms(void);
 
-static int set_param_str(const char *val, struct kernel_param *kp)
+static int set_param_str(const char *val, const struct kernel_param *kp)
 {
 	action_fn  fn = (action_fn) kp->arg;
 	int        rv = 0;
@@ -251,7 +252,7 @@
 	return rv;
 }
 
-static int get_param_str(char *buffer, struct kernel_param *kp)
+static int get_param_str(char *buffer, const struct kernel_param *kp)
 {
 	action_fn fn = (action_fn) kp->arg;
 	int       rv;
@@ -263,7 +264,7 @@
 }
 
 
-static int set_param_wdog_ifnum(const char *val, struct kernel_param *kp)
+static int set_param_wdog_ifnum(const char *val, const struct kernel_param *kp)
 {
 	int rv = param_set_int(val, kp);
 	if (rv)
@@ -276,27 +277,38 @@
 	return 0;
 }
 
-module_param_call(ifnum_to_use, set_param_wdog_ifnum, get_param_int,
-		  &ifnum_to_use, 0644);
+static struct kernel_param_ops param_ops_wdog_ifnum = {
+	.set = set_param_wdog_ifnum,
+	.get = param_get_int,
+};
+
+#define param_check_wdog_ifnum param_check_int
+
+static struct kernel_param_ops param_ops_str = {
+	.set = set_param_str,
+	.get = get_param_str,
+};
+
+module_param(ifnum_to_use, wdog_ifnum, 0644);
 MODULE_PARM_DESC(ifnum_to_use, "The interface number to use for the watchdog "
 		 "timer.  Setting to -1 defaults to the first registered "
 		 "interface");
 
-module_param_call(timeout, set_param_int, get_param_int, &timeout, 0644);
+module_param(timeout, timeout, 0644);
 MODULE_PARM_DESC(timeout, "Timeout value in seconds.");
 
-module_param_call(pretimeout, set_param_int, get_param_int, &pretimeout, 0644);
+module_param(pretimeout, timeout, 0644);
 MODULE_PARM_DESC(pretimeout, "Pretimeout value in seconds.");
 
-module_param_call(action, set_param_str, get_param_str, action_op, 0644);
+module_param_cb(action, &param_ops_str, action_op, 0644);
 MODULE_PARM_DESC(action, "Timeout action. One of: "
 		 "reset, none, power_cycle, power_off.");
 
-module_param_call(preaction, set_param_str, get_param_str, preaction_op, 0644);
+module_param_cb(preaction, &param_ops_str, preaction_op, 0644);
 MODULE_PARM_DESC(preaction, "Pretimeout action.  One of: "
 		 "pre_none, pre_smi, pre_nmi, pre_int.");
 
-module_param_call(preop, set_param_str, get_param_str, preop_op, 0644);
+module_param_cb(preop, &param_ops_str, preop_op, 0644);
 MODULE_PARM_DESC(preop, "Pretimeout driver operation.  One of: "
 		 "preop_none, preop_panic, preop_give_data.");
 
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 95acb8c..dfa8b30 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -961,7 +961,7 @@
 #endif
 #ifdef CONFIG_SPARC32
 	struct device_node *ebus_dp;
-	struct of_device *op;
+	struct platform_device *op;
 #else
 	void *r;
 #ifdef RTC_IRQ
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
index ed8a9ce..0ed763c 100644
--- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c
+++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
@@ -761,7 +761,7 @@
 
 #if defined(CONFIG_OF)
 static int __devinit
-hwicap_of_probe(struct of_device *op, const struct of_device_id *match)
+hwicap_of_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	struct resource res;
 	const unsigned int *id;
@@ -798,7 +798,7 @@
 			regs);
 }
 
-static int __devexit hwicap_of_remove(struct of_device *op)
+static int __devexit hwicap_of_remove(struct platform_device *op)
 {
 	return hwicap_remove(&op->dev);
 }
diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
index 983530b..2b1baee 100644
--- a/drivers/crypto/amcc/crypto4xx_core.c
+++ b/drivers/crypto/amcc/crypto4xx_core.c
@@ -1150,7 +1150,7 @@
 /**
  * Module Initialization Routine
  */
-static int __init crypto4xx_probe(struct of_device *ofdev,
+static int __init crypto4xx_probe(struct platform_device *ofdev,
 				  const struct of_device_id *match)
 {
 	int rc;
@@ -1258,7 +1258,7 @@
 	return rc;
 }
 
-static int __exit crypto4xx_remove(struct of_device *ofdev)
+static int __exit crypto4xx_remove(struct platform_device *ofdev)
 {
 	struct device *dev = &ofdev->dev;
 	struct crypto4xx_core_device *core_dev = dev_get_drvdata(dev);
diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h
index da9cbe3..bac0bde 100644
--- a/drivers/crypto/amcc/crypto4xx_core.h
+++ b/drivers/crypto/amcc/crypto4xx_core.h
@@ -104,7 +104,7 @@
 
 struct crypto4xx_core_device {
 	struct device *device;
-	struct of_device *ofdev;
+	struct platform_device *ofdev;
 	struct crypto4xx_device *dev;
 	u32 int_status;
 	u32 irq;
diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c
index 26af2dd..88ee015 100644
--- a/drivers/crypto/n2_core.c
+++ b/drivers/crypto/n2_core.c
@@ -1552,7 +1552,7 @@
 
 /* To map CWQ queues to interrupt sources, the hypervisor API provides
  * a devino.  This isn't very useful to us because all of the
- * interrupts listed in the of_device node have been translated to
+ * interrupts listed in the device_node have been translated to
  * Linux virtual IRQ cookie numbers.
  *
  * So we have to back-translate, going through the 'intr' and 'ino'
@@ -1560,7 +1560,7 @@
  * 'interrupts' property entries, in order to to figure out which
  * devino goes to which already-translated IRQ.
  */
-static int find_devino_index(struct of_device *dev, struct spu_mdesc_info *ip,
+static int find_devino_index(struct platform_device *dev, struct spu_mdesc_info *ip,
 			     unsigned long dev_ino)
 {
 	const unsigned int *dev_intrs;
@@ -1580,7 +1580,7 @@
 	if (!dev_intrs)
 		return -ENODEV;
 
-	for (i = 0; i < dev->num_irqs; i++) {
+	for (i = 0; i < dev->archdata.num_irqs; i++) {
 		if (dev_intrs[i] == intr)
 			return i;
 	}
@@ -1588,7 +1588,7 @@
 	return -ENODEV;
 }
 
-static int spu_map_ino(struct of_device *dev, struct spu_mdesc_info *ip,
+static int spu_map_ino(struct platform_device *dev, struct spu_mdesc_info *ip,
 		       const char *irq_name, struct spu_queue *p,
 		       irq_handler_t handler)
 {
@@ -1603,7 +1603,7 @@
 	if (index < 0)
 		return index;
 
-	p->irq = dev->irqs[index];
+	p->irq = dev->archdata.irqs[index];
 
 	sprintf(p->irq_name, "%s-%d", irq_name, index);
 
@@ -1736,7 +1736,7 @@
  * gathering cpu membership information.
  */
 static int spu_mdesc_walk_arcs(struct mdesc_handle *mdesc,
-			       struct of_device *dev,
+			       struct platform_device *dev,
 			       u64 node, struct spu_queue *p,
 			       struct spu_queue **table)
 {
@@ -1763,7 +1763,7 @@
 
 /* Process an 'exec-unit' MDESC node of type 'cwq'.  */
 static int handle_exec_unit(struct spu_mdesc_info *ip, struct list_head *list,
-			    struct of_device *dev, struct mdesc_handle *mdesc,
+			    struct platform_device *dev, struct mdesc_handle *mdesc,
 			    u64 node, const char *iname, unsigned long q_type,
 			    irq_handler_t handler, struct spu_queue **table)
 {
@@ -1794,7 +1794,7 @@
 	return spu_map_ino(dev, ip, iname, p, handler);
 }
 
-static int spu_mdesc_scan(struct mdesc_handle *mdesc, struct of_device *dev,
+static int spu_mdesc_scan(struct mdesc_handle *mdesc, struct platform_device *dev,
 			  struct spu_mdesc_info *ip, struct list_head *list,
 			  const char *exec_name, unsigned long q_type,
 			  irq_handler_t handler, struct spu_queue **table)
@@ -1855,7 +1855,7 @@
 }
 
 static int __devinit grab_mdesc_irq_props(struct mdesc_handle *mdesc,
-					  struct of_device *dev,
+					  struct platform_device *dev,
 					  struct spu_mdesc_info *ip,
 					  const char *node_name)
 {
@@ -2004,7 +2004,7 @@
 		pr_info("%s", version);
 }
 
-static int __devinit n2_crypto_probe(struct of_device *dev,
+static int __devinit n2_crypto_probe(struct platform_device *dev,
 				     const struct of_device_id *match)
 {
 	struct mdesc_handle *mdesc;
@@ -2081,7 +2081,7 @@
 	return err;
 }
 
-static int __devexit n2_crypto_remove(struct of_device *dev)
+static int __devexit n2_crypto_remove(struct platform_device *dev)
 {
 	struct n2_crypto *np = dev_get_drvdata(&dev->dev);
 
@@ -2116,7 +2116,7 @@
 	kfree(mp);
 }
 
-static int __devinit n2_mau_probe(struct of_device *dev,
+static int __devinit n2_mau_probe(struct platform_device *dev,
 				     const struct of_device_id *match)
 {
 	struct mdesc_handle *mdesc;
@@ -2184,7 +2184,7 @@
 	return err;
 }
 
-static int __devexit n2_mau_remove(struct of_device *dev)
+static int __devexit n2_mau_remove(struct platform_device *dev)
 {
 	struct n2_mau *mp = dev_get_drvdata(&dev->dev);
 
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index 97f4af1..4bcd825 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -118,7 +118,7 @@
 
 struct talitos_private {
 	struct device *dev;
-	struct of_device *ofdev;
+	struct platform_device *ofdev;
 	void __iomem *reg;
 	int irq;
 
@@ -2308,7 +2308,7 @@
 	return ret;
 }
 
-static int talitos_remove(struct of_device *ofdev)
+static int talitos_remove(struct platform_device *ofdev)
 {
 	struct device *dev = &ofdev->dev;
 	struct talitos_private *priv = dev_get_drvdata(dev);
@@ -2401,7 +2401,7 @@
 	return t_alg;
 }
 
-static int talitos_probe(struct of_device *ofdev,
+static int talitos_probe(struct platform_device *ofdev,
 			 const struct of_device_id *match)
 {
 	struct device *dev = &ofdev->dev;
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index f0fd6db..cea08be 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -1297,7 +1297,7 @@
 	kfree(chan);
 }
 
-static int __devinit fsldma_of_probe(struct of_device *op,
+static int __devinit fsldma_of_probe(struct platform_device *op,
 			const struct of_device_id *match)
 {
 	struct fsldma_device *fdev;
@@ -1382,7 +1382,7 @@
 	return err;
 }
 
-static int fsldma_of_remove(struct of_device *op)
+static int fsldma_of_remove(struct platform_device *op)
 {
 	struct fsldma_device *fdev;
 	unsigned int i;
diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
index 14a8c0f..4e9cbf3 100644
--- a/drivers/dma/mpc512x_dma.c
+++ b/drivers/dma/mpc512x_dma.c
@@ -627,7 +627,7 @@
 	return &mdesc->desc;
 }
 
-static int __devinit mpc_dma_probe(struct of_device *op,
+static int __devinit mpc_dma_probe(struct platform_device *op,
 					const struct of_device_id *match)
 {
 	struct device_node *dn = op->dev.of_node;
@@ -753,7 +753,7 @@
 	return retval;
 }
 
-static int __devexit mpc_dma_remove(struct of_device *op)
+static int __devexit mpc_dma_remove(struct platform_device *op)
 {
 	struct device *dev = &op->dev;
 	struct mpc_dma *mdma = dev_get_drvdata(dev);
diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c
index 7c37479..0d58a4a 100644
--- a/drivers/dma/ppc4xx/adma.c
+++ b/drivers/dma/ppc4xx/adma.c
@@ -4257,11 +4257,11 @@
 				     struct ppc440spe_adma_chan *chan,
 				     int *initcode)
 {
-	struct of_device *ofdev;
+	struct platform_device *ofdev;
 	struct device_node *np;
 	int ret;
 
-	ofdev = container_of(adev->dev, struct of_device, dev);
+	ofdev = container_of(adev->dev, struct platform_device, dev);
 	np = ofdev->dev.of_node;
 	if (adev->id != PPC440SPE_XOR_ID) {
 		adev->err_irq = irq_of_parse_and_map(np, 1);
@@ -4393,7 +4393,7 @@
 /**
  * ppc440spe_adma_probe - probe the asynch device
  */
-static int __devinit ppc440spe_adma_probe(struct of_device *ofdev,
+static int __devinit ppc440spe_adma_probe(struct platform_device *ofdev,
 					  const struct of_device_id *match)
 {
 	struct device_node *np = ofdev->dev.of_node;
@@ -4625,7 +4625,7 @@
 /**
  * ppc440spe_adma_remove - remove the asynch device
  */
-static int __devexit ppc440spe_adma_remove(struct of_device *ofdev)
+static int __devexit ppc440spe_adma_remove(struct platform_device *ofdev)
 {
 	struct ppc440spe_adma_device *adev = dev_get_drvdata(&ofdev->dev);
 	struct device_node *np = ofdev->dev.of_node;
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
index af75e27..b123bb3 100644
--- a/drivers/edac/mpc85xx_edac.c
+++ b/drivers/edac/mpc85xx_edac.c
@@ -200,7 +200,7 @@
 	return IRQ_HANDLED;
 }
 
-static int __devinit mpc85xx_pci_err_probe(struct of_device *op,
+static int __devinit mpc85xx_pci_err_probe(struct platform_device *op,
 					   const struct of_device_id *match)
 {
 	struct edac_pci_ctl_info *pci;
@@ -305,7 +305,7 @@
 	return res;
 }
 
-static int mpc85xx_pci_err_remove(struct of_device *op)
+static int mpc85xx_pci_err_remove(struct platform_device *op)
 {
 	struct edac_pci_ctl_info *pci = dev_get_drvdata(&op->dev);
 	struct mpc85xx_pci_pdata *pdata = pci->pvt_info;
@@ -503,7 +503,7 @@
 	return IRQ_HANDLED;
 }
 
-static int __devinit mpc85xx_l2_err_probe(struct of_device *op,
+static int __devinit mpc85xx_l2_err_probe(struct platform_device *op,
 					  const struct of_device_id *match)
 {
 	struct edac_device_ctl_info *edac_dev;
@@ -613,7 +613,7 @@
 	return res;
 }
 
-static int mpc85xx_l2_err_remove(struct of_device *op)
+static int mpc85xx_l2_err_remove(struct platform_device *op)
 {
 	struct edac_device_ctl_info *edac_dev = dev_get_drvdata(&op->dev);
 	struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info;
@@ -956,7 +956,7 @@
 	}
 }
 
-static int __devinit mpc85xx_mc_err_probe(struct of_device *op,
+static int __devinit mpc85xx_mc_err_probe(struct platform_device *op,
 					  const struct of_device_id *match)
 {
 	struct mem_ctl_info *mci;
@@ -1088,7 +1088,7 @@
 	return res;
 }
 
-static int mpc85xx_mc_err_remove(struct of_device *op)
+static int mpc85xx_mc_err_remove(struct platform_device *op)
 {
 	struct mem_ctl_info *mci = dev_get_drvdata(&op->dev);
 	struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c
index e78839e..070cea4 100644
--- a/drivers/edac/ppc4xx_edac.c
+++ b/drivers/edac/ppc4xx_edac.c
@@ -184,9 +184,9 @@
 
 /* Function Prototypes */
 
-static int ppc4xx_edac_probe(struct of_device *device,
+static int ppc4xx_edac_probe(struct platform_device *device,
 			     const struct of_device_id *device_id);
-static int ppc4xx_edac_remove(struct of_device *device);
+static int ppc4xx_edac_remove(struct platform_device *device);
 
 /* Global Variables */
 
@@ -1014,7 +1014,7 @@
  */
 static int __devinit
 ppc4xx_edac_mc_init(struct mem_ctl_info *mci,
-		    struct of_device *op,
+		    struct platform_device *op,
 		    const struct of_device_id *match,
 		    const dcr_host_t *dcr_host,
 		    u32 mcopt1)
@@ -1108,7 +1108,7 @@
  * mapped and assigned.
  */
 static int __devinit
-ppc4xx_edac_register_irq(struct of_device *op, struct mem_ctl_info *mci)
+ppc4xx_edac_register_irq(struct platform_device *op, struct mem_ctl_info *mci)
 {
 	int status = 0;
 	int ded_irq, sec_irq;
@@ -1238,7 +1238,7 @@
  * driver; otherwise, < 0 on error.
  */
 static int __devinit
-ppc4xx_edac_probe(struct of_device *op, const struct of_device_id *match)
+ppc4xx_edac_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	int status = 0;
 	u32 mcopt1, memcheck;
@@ -1359,7 +1359,7 @@
  * Unconditionally returns 0.
  */
 static int
-ppc4xx_edac_remove(struct of_device *op)
+ppc4xx_edac_remove(struct platform_device *op)
 {
 	struct mem_ctl_info *mci = dev_get_drvdata(&op->dev);
 	struct ppc4xx_edac_pdata *pdata = mci->pvt_info;
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index f623953..510aa20 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -206,6 +206,13 @@
 	  8 bits:  sx1508q
 	  16 bits: sx1509q
 
+config GPIO_STMPE
+	bool "STMPE GPIOs"
+	depends on MFD_STMPE
+	help
+	  This enables support for the GPIOs found on the STMPE I/O
+	  Expanders.
+
 config GPIO_TC35892
 	bool "TC35892 GPIOs"
 	depends on MFD_TC35892
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index a69e060..fc6019d 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -20,6 +20,7 @@
 obj-$(CONFIG_GPIO_PCA953X)	+= pca953x.o
 obj-$(CONFIG_GPIO_PCF857X)	+= pcf857x.o
 obj-$(CONFIG_GPIO_PL061)	+= pl061.o
+obj-$(CONFIG_GPIO_STMPE)	+= stmpe-gpio.o
 obj-$(CONFIG_GPIO_TC35892)	+= tc35892-gpio.o
 obj-$(CONFIG_GPIO_TIMBERDALE)	+= timbgpio.o
 obj-$(CONFIG_GPIO_TWL4030)	+= twl4030-gpio.o
diff --git a/drivers/gpio/stmpe-gpio.c b/drivers/gpio/stmpe-gpio.c
new file mode 100644
index 0000000..4e1f1b9
--- /dev/null
+++ b/drivers/gpio/stmpe-gpio.c
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License, version 2
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/stmpe.h>
+
+/*
+ * These registers are modified under the irq bus lock and cached to avoid
+ * unnecessary writes in bus_sync_unlock.
+ */
+enum { REG_RE, REG_FE, REG_IE };
+
+#define CACHE_NR_REGS	3
+#define CACHE_NR_BANKS	(STMPE_NR_GPIOS / 8)
+
+struct stmpe_gpio {
+	struct gpio_chip chip;
+	struct stmpe *stmpe;
+	struct device *dev;
+	struct mutex irq_lock;
+
+	int irq_base;
+
+	/* Caches of interrupt control registers for bus_lock */
+	u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS];
+	u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS];
+};
+
+static inline struct stmpe_gpio *to_stmpe_gpio(struct gpio_chip *chip)
+{
+	return container_of(chip, struct stmpe_gpio, chip);
+}
+
+static int stmpe_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
+	struct stmpe *stmpe = stmpe_gpio->stmpe;
+	u8 reg = stmpe->regs[STMPE_IDX_GPMR_LSB] - (offset / 8);
+	u8 mask = 1 << (offset % 8);
+	int ret;
+
+	ret = stmpe_reg_read(stmpe, reg);
+	if (ret < 0)
+		return ret;
+
+	return ret & mask;
+}
+
+static void stmpe_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
+{
+	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
+	struct stmpe *stmpe = stmpe_gpio->stmpe;
+	int which = val ? STMPE_IDX_GPSR_LSB : STMPE_IDX_GPCR_LSB;
+	u8 reg = stmpe->regs[which] - (offset / 8);
+	u8 mask = 1 << (offset % 8);
+
+	stmpe_reg_write(stmpe, reg, mask);
+}
+
+static int stmpe_gpio_direction_output(struct gpio_chip *chip,
+					 unsigned offset, int val)
+{
+	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
+	struct stmpe *stmpe = stmpe_gpio->stmpe;
+	u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8);
+	u8 mask = 1 << (offset % 8);
+
+	stmpe_gpio_set(chip, offset, val);
+
+	return stmpe_set_bits(stmpe, reg, mask, mask);
+}
+
+static int stmpe_gpio_direction_input(struct gpio_chip *chip,
+					unsigned offset)
+{
+	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
+	struct stmpe *stmpe = stmpe_gpio->stmpe;
+	u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8);
+	u8 mask = 1 << (offset % 8);
+
+	return stmpe_set_bits(stmpe, reg, mask, 0);
+}
+
+static int stmpe_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
+
+	return stmpe_gpio->irq_base + offset;
+}
+
+static int stmpe_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+	struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
+	struct stmpe *stmpe = stmpe_gpio->stmpe;
+
+	return stmpe_set_altfunc(stmpe, 1 << offset, STMPE_BLOCK_GPIO);
+}
+
+static struct gpio_chip template_chip = {
+	.label			= "stmpe",
+	.owner			= THIS_MODULE,
+	.direction_input	= stmpe_gpio_direction_input,
+	.get			= stmpe_gpio_get,
+	.direction_output	= stmpe_gpio_direction_output,
+	.set			= stmpe_gpio_set,
+	.to_irq			= stmpe_gpio_to_irq,
+	.request		= stmpe_gpio_request,
+	.can_sleep		= 1,
+};
+
+static int stmpe_gpio_irq_set_type(unsigned int irq, unsigned int type)
+{
+	struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq);
+	int offset = irq - stmpe_gpio->irq_base;
+	int regoffset = offset / 8;
+	int mask = 1 << (offset % 8);
+
+	if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH)
+		return -EINVAL;
+
+	if (type == IRQ_TYPE_EDGE_RISING)
+		stmpe_gpio->regs[REG_RE][regoffset] |= mask;
+	else
+		stmpe_gpio->regs[REG_RE][regoffset] &= ~mask;
+
+	if (type == IRQ_TYPE_EDGE_FALLING)
+		stmpe_gpio->regs[REG_FE][regoffset] |= mask;
+	else
+		stmpe_gpio->regs[REG_FE][regoffset] &= ~mask;
+
+	return 0;
+}
+
+static void stmpe_gpio_irq_lock(unsigned int irq)
+{
+	struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq);
+
+	mutex_lock(&stmpe_gpio->irq_lock);
+}
+
+static void stmpe_gpio_irq_sync_unlock(unsigned int irq)
+{
+	struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq);
+	struct stmpe *stmpe = stmpe_gpio->stmpe;
+	int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
+	static const u8 regmap[] = {
+		[REG_RE]	= STMPE_IDX_GPRER_LSB,
+		[REG_FE]	= STMPE_IDX_GPFER_LSB,
+		[REG_IE]	= STMPE_IDX_IEGPIOR_LSB,
+	};
+	int i, j;
+
+	for (i = 0; i < CACHE_NR_REGS; i++) {
+		for (j = 0; j < num_banks; j++) {
+			u8 old = stmpe_gpio->oldregs[i][j];
+			u8 new = stmpe_gpio->regs[i][j];
+
+			if (new == old)
+				continue;
+
+			stmpe_gpio->oldregs[i][j] = new;
+			stmpe_reg_write(stmpe, stmpe->regs[regmap[i]] - j, new);
+		}
+	}
+
+	mutex_unlock(&stmpe_gpio->irq_lock);
+}
+
+static void stmpe_gpio_irq_mask(unsigned int irq)
+{
+	struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq);
+	int offset = irq - stmpe_gpio->irq_base;
+	int regoffset = offset / 8;
+	int mask = 1 << (offset % 8);
+
+	stmpe_gpio->regs[REG_IE][regoffset] &= ~mask;
+}
+
+static void stmpe_gpio_irq_unmask(unsigned int irq)
+{
+	struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq);
+	int offset = irq - stmpe_gpio->irq_base;
+	int regoffset = offset / 8;
+	int mask = 1 << (offset % 8);
+
+	stmpe_gpio->regs[REG_IE][regoffset] |= mask;
+}
+
+static struct irq_chip stmpe_gpio_irq_chip = {
+	.name			= "stmpe-gpio",
+	.bus_lock		= stmpe_gpio_irq_lock,
+	.bus_sync_unlock	= stmpe_gpio_irq_sync_unlock,
+	.mask			= stmpe_gpio_irq_mask,
+	.unmask			= stmpe_gpio_irq_unmask,
+	.set_type		= stmpe_gpio_irq_set_type,
+};
+
+static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
+{
+	struct stmpe_gpio *stmpe_gpio = dev;
+	struct stmpe *stmpe = stmpe_gpio->stmpe;
+	u8 statmsbreg = stmpe->regs[STMPE_IDX_ISGPIOR_MSB];
+	int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
+	u8 status[num_banks];
+	int ret;
+	int i;
+
+	ret = stmpe_block_read(stmpe, statmsbreg, num_banks, status);
+	if (ret < 0)
+		return IRQ_NONE;
+
+	for (i = 0; i < num_banks; i++) {
+		int bank = num_banks - i - 1;
+		unsigned int enabled = stmpe_gpio->regs[REG_IE][bank];
+		unsigned int stat = status[i];
+
+		stat &= enabled;
+		if (!stat)
+			continue;
+
+		while (stat) {
+			int bit = __ffs(stat);
+			int line = bank * 8 + bit;
+
+			handle_nested_irq(stmpe_gpio->irq_base + line);
+			stat &= ~(1 << bit);
+		}
+
+		stmpe_reg_write(stmpe, statmsbreg + i, status[i]);
+		stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_GPEDR_MSB] + i,
+				status[i]);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio)
+{
+	int base = stmpe_gpio->irq_base;
+	int irq;
+
+	for (irq = base; irq < base + stmpe_gpio->chip.ngpio; irq++) {
+		set_irq_chip_data(irq, stmpe_gpio);
+		set_irq_chip_and_handler(irq, &stmpe_gpio_irq_chip,
+					 handle_simple_irq);
+		set_irq_nested_thread(irq, 1);
+#ifdef CONFIG_ARM
+		set_irq_flags(irq, IRQF_VALID);
+#else
+		set_irq_noprobe(irq);
+#endif
+	}
+
+	return 0;
+}
+
+static void stmpe_gpio_irq_remove(struct stmpe_gpio *stmpe_gpio)
+{
+	int base = stmpe_gpio->irq_base;
+	int irq;
+
+	for (irq = base; irq < base + stmpe_gpio->chip.ngpio; irq++) {
+#ifdef CONFIG_ARM
+		set_irq_flags(irq, 0);
+#endif
+		set_irq_chip_and_handler(irq, NULL, NULL);
+		set_irq_chip_data(irq, NULL);
+	}
+}
+
+static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
+{
+	struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
+	struct stmpe_gpio_platform_data *pdata;
+	struct stmpe_gpio *stmpe_gpio;
+	int ret;
+	int irq;
+
+	pdata = stmpe->pdata->gpio;
+	if (!pdata)
+		return -ENODEV;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	stmpe_gpio = kzalloc(sizeof(struct stmpe_gpio), GFP_KERNEL);
+	if (!stmpe_gpio)
+		return -ENOMEM;
+
+	mutex_init(&stmpe_gpio->irq_lock);
+
+	stmpe_gpio->dev = &pdev->dev;
+	stmpe_gpio->stmpe = stmpe;
+
+	stmpe_gpio->chip = template_chip;
+	stmpe_gpio->chip.ngpio = stmpe->num_gpios;
+	stmpe_gpio->chip.dev = &pdev->dev;
+	stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1;
+
+	stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0);
+
+	ret = stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
+	if (ret)
+		return ret;
+
+	ret = stmpe_gpio_irq_init(stmpe_gpio);
+	if (ret)
+		goto out_free;
+
+	ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq, IRQF_ONESHOT,
+				   "stmpe-gpio", stmpe_gpio);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
+		goto out_removeirq;
+	}
+
+	ret = gpiochip_add(&stmpe_gpio->chip);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
+		goto out_freeirq;
+	}
+
+	if (pdata && pdata->setup)
+		pdata->setup(stmpe, stmpe_gpio->chip.base);
+
+	platform_set_drvdata(pdev, stmpe_gpio);
+
+	return 0;
+
+out_freeirq:
+	free_irq(irq, stmpe_gpio);
+out_removeirq:
+	stmpe_gpio_irq_remove(stmpe_gpio);
+out_free:
+	kfree(stmpe_gpio);
+	return ret;
+}
+
+static int __devexit stmpe_gpio_remove(struct platform_device *pdev)
+{
+	struct stmpe_gpio *stmpe_gpio = platform_get_drvdata(pdev);
+	struct stmpe *stmpe = stmpe_gpio->stmpe;
+	struct stmpe_gpio_platform_data *pdata = stmpe->pdata->gpio;
+	int irq = platform_get_irq(pdev, 0);
+	int ret;
+
+	if (pdata && pdata->remove)
+		pdata->remove(stmpe, stmpe_gpio->chip.base);
+
+	ret = gpiochip_remove(&stmpe_gpio->chip);
+	if (ret < 0) {
+		dev_err(stmpe_gpio->dev,
+			"unable to remove gpiochip: %d\n", ret);
+		return ret;
+	}
+
+	stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
+
+	free_irq(irq, stmpe_gpio);
+	stmpe_gpio_irq_remove(stmpe_gpio);
+	platform_set_drvdata(pdev, NULL);
+	kfree(stmpe_gpio);
+
+	return 0;
+}
+
+static struct platform_driver stmpe_gpio_driver = {
+	.driver.name	= "stmpe-gpio",
+	.driver.owner	= THIS_MODULE,
+	.probe		= stmpe_gpio_probe,
+	.remove		= __devexit_p(stmpe_gpio_remove),
+};
+
+static int __init stmpe_gpio_init(void)
+{
+	return platform_driver_register(&stmpe_gpio_driver);
+}
+subsys_initcall(stmpe_gpio_init);
+
+static void __exit stmpe_gpio_exit(void)
+{
+	platform_driver_unregister(&stmpe_gpio_driver);
+}
+module_exit(stmpe_gpio_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("STMPExxxx GPIO driver");
+MODULE_AUTHOR("Rabin Vincent <rabin.vincent@stericsson.com>");
diff --git a/drivers/gpio/wm831x-gpio.c b/drivers/gpio/wm831x-gpio.c
index 1fa449a1..309644c 100644
--- a/drivers/gpio/wm831x-gpio.c
+++ b/drivers/gpio/wm831x-gpio.c
@@ -108,6 +108,37 @@
 	return wm831x->irq_base + WM831X_IRQ_GPIO_1 + offset;
 }
 
+static int wm831x_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
+				    unsigned debounce)
+{
+	struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
+	struct wm831x *wm831x = wm831x_gpio->wm831x;
+	int reg = WM831X_GPIO1_CONTROL + offset;
+	int ret, fn;
+
+	ret = wm831x_reg_read(wm831x, reg);
+	if (ret < 0)
+		return ret;
+
+	switch (ret & WM831X_GPN_FN_MASK) {
+	case 0:
+	case 1:
+		break;
+	default:
+		/* Not in GPIO mode */
+		return -EBUSY;
+	}
+
+	if (debounce >= 32 && debounce <= 64)
+		fn = 0;
+	else if (debounce >= 4000 && debounce <= 8000)
+		fn = 1;
+	else
+		return -EINVAL;
+
+	return wm831x_set_bits(wm831x, reg, WM831X_GPN_FN_MASK, fn);
+}
+
 #ifdef CONFIG_DEBUG_FS
 static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 {
@@ -208,6 +239,7 @@
 	.direction_output	= wm831x_gpio_direction_out,
 	.set			= wm831x_gpio_set,
 	.to_irq			= wm831x_gpio_to_irq,
+	.set_debounce		= wm831x_gpio_set_debounce,
 	.dbg_show		= wm831x_gpio_dbg_show,
 	.can_sleep		= 1,
 };
diff --git a/drivers/gpu/drm/ati_pcigart.c b/drivers/gpu/drm/ati_pcigart.c
index 17be051..1c36492 100644
--- a/drivers/gpu/drm/ati_pcigart.c
+++ b/drivers/gpu/drm/ati_pcigart.c
@@ -152,7 +152,7 @@
 		/* we need to support large memory configurations */
 		entry->busaddr[i] = pci_map_page(dev->pdev, entry->pagelist[i],
 						 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
-		if (entry->busaddr[i] == 0) {
+		if (pci_dma_mapping_error(dev->pdev, entry->busaddr[i])) {
 			DRM_ERROR("unable to map PCIGART pages!\n");
 			drm_ati_pcigart_cleanup(dev, gart_info);
 			address = NULL;
diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c
index a5c9ce9..3e257a5 100644
--- a/drivers/gpu/drm/drm_bufs.c
+++ b/drivers/gpu/drm/drm_bufs.c
@@ -328,14 +328,13 @@
 		return -EINVAL;
 	}
 
-	list = kmalloc(sizeof(*list), GFP_KERNEL);
+	list = kzalloc(sizeof(*list), GFP_KERNEL);
 	if (!list) {
 		if (map->type == _DRM_REGISTERS)
 			iounmap(map->handle);
 		kfree(map);
 		return -EINVAL;
 	}
-	memset(list, 0, sizeof(*list));
 	list->map = map;
 
 	mutex_lock(&dev->struct_mutex);
@@ -678,13 +677,12 @@
 		return -EINVAL;
 	}
 
-	entry->buflist = kmalloc(count * sizeof(*entry->buflist), GFP_KERNEL);
+	entry->buflist = kzalloc(count * sizeof(*entry->buflist), GFP_KERNEL);
 	if (!entry->buflist) {
 		mutex_unlock(&dev->struct_mutex);
 		atomic_dec(&dev->buf_alloc);
 		return -ENOMEM;
 	}
-	memset(entry->buflist, 0, count * sizeof(*entry->buflist));
 
 	entry->buf_size = size;
 	entry->page_order = page_order;
@@ -708,7 +706,7 @@
 		buf->file_priv = NULL;
 
 		buf->dev_priv_size = dev->driver->dev_priv_size;
-		buf->dev_private = kmalloc(buf->dev_priv_size, GFP_KERNEL);
+		buf->dev_private = kzalloc(buf->dev_priv_size, GFP_KERNEL);
 		if (!buf->dev_private) {
 			/* Set count correctly so we free the proper amount. */
 			entry->buf_count = count;
@@ -717,7 +715,6 @@
 			atomic_dec(&dev->buf_alloc);
 			return -ENOMEM;
 		}
-		memset(buf->dev_private, 0, buf->dev_priv_size);
 
 		DRM_DEBUG("buffer %d @ %p\n", entry->buf_count, buf->address);
 
@@ -832,22 +829,20 @@
 		return -EINVAL;
 	}
 
-	entry->buflist = kmalloc(count * sizeof(*entry->buflist), GFP_KERNEL);
+	entry->buflist = kzalloc(count * sizeof(*entry->buflist), GFP_KERNEL);
 	if (!entry->buflist) {
 		mutex_unlock(&dev->struct_mutex);
 		atomic_dec(&dev->buf_alloc);
 		return -ENOMEM;
 	}
-	memset(entry->buflist, 0, count * sizeof(*entry->buflist));
 
-	entry->seglist = kmalloc(count * sizeof(*entry->seglist), GFP_KERNEL);
+	entry->seglist = kzalloc(count * sizeof(*entry->seglist), GFP_KERNEL);
 	if (!entry->seglist) {
 		kfree(entry->buflist);
 		mutex_unlock(&dev->struct_mutex);
 		atomic_dec(&dev->buf_alloc);
 		return -ENOMEM;
 	}
-	memset(entry->seglist, 0, count * sizeof(*entry->seglist));
 
 	/* Keep the original pagelist until we know all the allocations
 	 * have succeeded
@@ -911,8 +906,8 @@
 			buf->file_priv = NULL;
 
 			buf->dev_priv_size = dev->driver->dev_priv_size;
-			buf->dev_private = kmalloc(buf->dev_priv_size,
-						  GFP_KERNEL);
+			buf->dev_private = kzalloc(buf->dev_priv_size,
+						GFP_KERNEL);
 			if (!buf->dev_private) {
 				/* Set count correctly so we free the proper amount. */
 				entry->buf_count = count;
@@ -923,7 +918,6 @@
 				atomic_dec(&dev->buf_alloc);
 				return -ENOMEM;
 			}
-			memset(buf->dev_private, 0, buf->dev_priv_size);
 
 			DRM_DEBUG("buffer %d @ %p\n",
 				  entry->buf_count, buf->address);
@@ -1048,14 +1042,13 @@
 		return -EINVAL;
 	}
 
-	entry->buflist = kmalloc(count * sizeof(*entry->buflist),
+	entry->buflist = kzalloc(count * sizeof(*entry->buflist),
 				GFP_KERNEL);
 	if (!entry->buflist) {
 		mutex_unlock(&dev->struct_mutex);
 		atomic_dec(&dev->buf_alloc);
 		return -ENOMEM;
 	}
-	memset(entry->buflist, 0, count * sizeof(*entry->buflist));
 
 	entry->buf_size = size;
 	entry->page_order = page_order;
@@ -1080,7 +1073,7 @@
 		buf->file_priv = NULL;
 
 		buf->dev_priv_size = dev->driver->dev_priv_size;
-		buf->dev_private = kmalloc(buf->dev_priv_size, GFP_KERNEL);
+		buf->dev_private = kzalloc(buf->dev_priv_size, GFP_KERNEL);
 		if (!buf->dev_private) {
 			/* Set count correctly so we free the proper amount. */
 			entry->buf_count = count;
@@ -1090,8 +1083,6 @@
 			return -ENOMEM;
 		}
 
-		memset(buf->dev_private, 0, buf->dev_priv_size);
-
 		DRM_DEBUG("buffer %d @ %p\n", entry->buf_count, buf->address);
 
 		offset += alignment;
@@ -1209,14 +1200,13 @@
 		return -EINVAL;
 	}
 
-	entry->buflist = kmalloc(count * sizeof(*entry->buflist),
+	entry->buflist = kzalloc(count * sizeof(*entry->buflist),
 				GFP_KERNEL);
 	if (!entry->buflist) {
 		mutex_unlock(&dev->struct_mutex);
 		atomic_dec(&dev->buf_alloc);
 		return -ENOMEM;
 	}
-	memset(entry->buflist, 0, count * sizeof(*entry->buflist));
 
 	entry->buf_size = size;
 	entry->page_order = page_order;
@@ -1240,7 +1230,7 @@
 		buf->file_priv = NULL;
 
 		buf->dev_priv_size = dev->driver->dev_priv_size;
-		buf->dev_private = kmalloc(buf->dev_priv_size, GFP_KERNEL);
+		buf->dev_private = kzalloc(buf->dev_priv_size, GFP_KERNEL);
 		if (!buf->dev_private) {
 			/* Set count correctly so we free the proper amount. */
 			entry->buf_count = count;
@@ -1249,7 +1239,6 @@
 			atomic_dec(&dev->buf_alloc);
 			return -ENOMEM;
 		}
-		memset(buf->dev_private, 0, buf->dev_priv_size);
 
 		DRM_DEBUG("buffer %d @ %p\n", entry->buf_count, buf->address);
 
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 4c68f76..37e0b4f 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1682,9 +1682,9 @@
 	/* TODO setup destructor callback */
 
 	fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
-	if (!fb) {
+	if (IS_ERR(fb)) {
 		DRM_ERROR("could not create framebuffer\n");
-		ret = -EINVAL;
+		ret = PTR_ERR(fb);
 		goto out;
 	}
 
@@ -2541,7 +2541,7 @@
 		goto out;
 	}
 
-	crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, crtc->gamma_size);
+	crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
 
 out:
 	mutex_unlock(&dev->mode_config.mutex);
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index b9e4dbf..7e31d43 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -817,12 +817,12 @@
 				if (encoder_funcs->dpms)
 					(*encoder_funcs->dpms) (encoder,
 								drm_helper_choose_encoder_dpms(encoder));
-
-				crtc_funcs = crtc->helper_private;
-				if (crtc_funcs->dpms)
-					(*crtc_funcs->dpms) (crtc,
-							     drm_helper_choose_crtc_dpms(crtc));
 			}
+
+			crtc_funcs = crtc->helper_private;
+			if (crtc_funcs->dpms)
+				(*crtc_funcs->dpms) (crtc,
+						     drm_helper_choose_crtc_dpms(crtc));
 		}
 	}
 	/* disable the unused connectors while restoring the modesetting */
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index dce5c4a..96e9631 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -33,6 +33,11 @@
 #include <linux/i2c-algo-bit.h>
 #include "drmP.h"
 #include "drm_edid.h"
+#include "drm_edid_modes.h"
+
+#define version_greater(edid, maj, min) \
+	(((edid)->version > (maj)) || \
+	 ((edid)->version == (maj) && (edid)->revision > (min)))
 
 #define EDID_EST_TIMINGS 16
 #define EDID_STD_TIMINGS 8
@@ -62,6 +67,13 @@
 /* use +hsync +vsync for detailed mode */
 #define EDID_QUIRK_DETAILED_SYNC_PP		(1 << 6)
 
+struct detailed_mode_closure {
+	struct drm_connector *connector;
+	struct edid *edid;
+	bool preferred;
+	u32 quirks;
+	int modes;
+};
 
 #define LEVEL_DMT	0
 #define LEVEL_GTF	1
@@ -375,7 +387,6 @@
 #define MODE_SIZE(m) ((m)->hdisplay * (m)->vdisplay)
 #define MODE_REFRESH_DIFF(m,r) (abs((m)->vrefresh - target_refresh))
 
-
 /**
  * edid_fixup_preferred - set preferred modes based on quirk list
  * @connector: has mode list to fix up
@@ -422,245 +433,6 @@
 	preferred_mode->type |= DRM_MODE_TYPE_PREFERRED;
 }
 
-/*
- * Add the Autogenerated from the DMT spec.
- * This table is copied from xfree86/modes/xf86EdidModes.c.
- * But the mode with Reduced blank feature is deleted.
- */
-static struct drm_display_mode drm_dmt_modes[] = {
-	/* 640x350@85Hz */
-	{ DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 31500, 640, 672,
-		   736, 832, 0, 350, 382, 385, 445, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
-	/* 640x400@85Hz */
-	{ DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 31500, 640, 672,
-		   736, 832, 0, 400, 401, 404, 445, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 720x400@85Hz */
-	{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 756,
-		   828, 936, 0, 400, 401, 404, 446, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 640x480@60Hz */
-	{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
-		   752, 800, 0, 480, 489, 492, 525, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-	/* 640x480@72Hz */
-	{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664,
-		   704, 832, 0, 480, 489, 492, 520, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-	/* 640x480@75Hz */
-	{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656,
-		   720, 840, 0, 480, 481, 484, 500, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-	/* 640x480@85Hz */
-	{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 36000, 640, 696,
-		   752, 832, 0, 480, 481, 484, 509, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-	/* 800x600@56Hz */
-	{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824,
-		   896, 1024, 0, 600, 601, 603, 625, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 800x600@60Hz */
-	{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
-		   968, 1056, 0, 600, 601, 605, 628, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 800x600@72Hz */
-	{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856,
-		   976, 1040, 0, 600, 637, 643, 666, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 800x600@75Hz */
-	{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816,
-		   896, 1056, 0, 600, 601, 604, 625, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 800x600@85Hz */
-	{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 56250, 800, 832,
-		   896, 1048, 0, 600, 601, 604, 631, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 848x480@60Hz */
-	{ DRM_MODE("848x480", DRM_MODE_TYPE_DRIVER, 33750, 848, 864,
-		   976, 1088, 0, 480, 486, 494, 517, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1024x768@43Hz, interlace */
-	{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 44900, 1024, 1032,
-		   1208, 1264, 0, 768, 768, 772, 817, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
-			DRM_MODE_FLAG_INTERLACE) },
-	/* 1024x768@60Hz */
-	{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
-		   1184, 1344, 0, 768, 771, 777, 806, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-	/* 1024x768@70Hz */
-	{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048,
-		   1184, 1328, 0, 768, 771, 777, 806, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-	/* 1024x768@75Hz */
-	{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78750, 1024, 1040,
-		   1136, 1312, 0, 768, 769, 772, 800, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1024x768@85Hz */
-	{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 94500, 1024, 1072,
-		   1168, 1376, 0, 768, 769, 772, 808, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1152x864@75Hz */
-	{ DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
-		   1344, 1600, 0, 864, 865, 868, 900, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1280x768@60Hz */
-	{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 79500, 1280, 1344,
-		   1472, 1664, 0, 768, 771, 778, 798, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1280x768@75Hz */
-	{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 102250, 1280, 1360,
-		   1488, 1696, 0, 768, 771, 778, 805, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
-	/* 1280x768@85Hz */
-	{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 117500, 1280, 1360,
-		   1496, 1712, 0, 768, 771, 778, 809, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1280x800@60Hz */
-	{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 83500, 1280, 1352,
-		   1480, 1680, 0, 800, 803, 809, 831, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
-	/* 1280x800@75Hz */
-	{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 106500, 1280, 1360,
-		   1488, 1696, 0, 800, 803, 809, 838, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1280x800@85Hz */
-	{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 122500, 1280, 1360,
-		   1496, 1712, 0, 800, 803, 809, 843, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1280x960@60Hz */
-	{ DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1376,
-		   1488, 1800, 0, 960, 961, 964, 1000, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1280x960@85Hz */
-	{ DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1344,
-		   1504, 1728, 0, 960, 961, 964, 1011, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1280x1024@60Hz */
-	{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1328,
-		   1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1280x1024@75Hz */
-	{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296,
-		   1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1280x1024@85Hz */
-	{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 157500, 1280, 1344,
-		   1504, 1728, 0, 1024, 1025, 1028, 1072, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1360x768@60Hz */
-	{ DRM_MODE("1360x768", DRM_MODE_TYPE_DRIVER, 85500, 1360, 1424,
-		   1536, 1792, 0, 768, 771, 777, 795, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1440x1050@60Hz */
-	{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 121750, 1400, 1488,
-		   1632, 1864, 0, 1050, 1053, 1057, 1089, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1440x1050@75Hz */
-	{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 156000, 1400, 1504,
-		   1648, 1896, 0, 1050, 1053, 1057, 1099, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1440x1050@85Hz */
-	{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 179500, 1400, 1504,
-		   1656, 1912, 0, 1050, 1053, 1057, 1105, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1440x900@60Hz */
-	{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 106500, 1440, 1520,
-		   1672, 1904, 0, 900, 903, 909, 934, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1440x900@75Hz */
-	{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 136750, 1440, 1536,
-		   1688, 1936, 0, 900, 903, 909, 942, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1440x900@85Hz */
-	{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 157000, 1440, 1544,
-		   1696, 1952, 0, 900, 903, 909, 948, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1600x1200@60Hz */
-	{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600, 1664,
-		   1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1600x1200@65Hz */
-	{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 175500, 1600, 1664,
-		   1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1600x1200@70Hz */
-	{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 189000, 1600, 1664,
-		   1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1600x1200@75Hz */
-	{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 202500, 1600, 1664,
-		   1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1600x1200@85Hz */
-	{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 229500, 1600, 1664,
-		   1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1680x1050@60Hz */
-	{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 146250, 1680, 1784,
-		   1960, 2240, 0, 1050, 1053, 1059, 1089, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1680x1050@75Hz */
-	{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 187000, 1680, 1800,
-		   1976, 2272, 0, 1050, 1053, 1059, 1099, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1680x1050@85Hz */
-	{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 214750, 1680, 1808,
-		   1984, 2288, 0, 1050, 1053, 1059, 1105, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1792x1344@60Hz */
-	{ DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 204750, 1792, 1920,
-		   2120, 2448, 0, 1344, 1345, 1348, 1394, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1729x1344@75Hz */
-	{ DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 261000, 1792, 1888,
-		   2104, 2456, 0, 1344, 1345, 1348, 1417, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1853x1392@60Hz */
-	{ DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 218250, 1856, 1952,
-		   2176, 2528, 0, 1392, 1393, 1396, 1439, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1856x1392@75Hz */
-	{ DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 288000, 1856, 1984,
-		   2208, 2560, 0, 1392, 1395, 1399, 1500, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1920x1200@60Hz */
-	{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 193250, 1920, 2056,
-		   2256, 2592, 0, 1200, 1203, 1209, 1245, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1920x1200@75Hz */
-	{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 245250, 1920, 2056,
-		   2264, 2608, 0, 1200, 1203, 1209, 1255, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1920x1200@85Hz */
-	{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 281250, 1920, 2064,
-		   2272, 2624, 0, 1200, 1203, 1209, 1262, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1920x1440@60Hz */
-	{ DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 234000, 1920, 2048,
-		   2256, 2600, 0, 1440, 1441, 1444, 1500, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 1920x1440@75Hz */
-	{ DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2064,
-		   2288, 2640, 0, 1440, 1441, 1444, 1500, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 2560x1600@60Hz */
-	{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 348500, 2560, 2752,
-		   3032, 3504, 0, 1600, 1603, 1609, 1658, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 2560x1600@75HZ */
-	{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 443250, 2560, 2768,
-		   3048, 3536, 0, 1600, 1603, 1609, 1672, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-	/* 2560x1600@85HZ */
-	{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 505250, 2560, 2768,
-		   3048, 3536, 0, 1600, 1603, 1609, 1682, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
-};
-static const int drm_num_dmt_modes =
-	sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode);
-
 struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
 					   int hsize, int vsize, int fresh)
 {
@@ -685,6 +457,46 @@
 typedef void detailed_cb(struct detailed_timing *timing, void *closure);
 
 static void
+cea_for_each_detailed_block(u8 *ext, detailed_cb *cb, void *closure)
+{
+	int i, n = 0;
+	u8 rev = ext[0x01], d = ext[0x02];
+	u8 *det_base = ext + d;
+
+	switch (rev) {
+	case 0:
+		/* can't happen */
+		return;
+	case 1:
+		/* have to infer how many blocks we have, check pixel clock */
+		for (i = 0; i < 6; i++)
+			if (det_base[18*i] || det_base[18*i+1])
+				n++;
+		break;
+	default:
+		/* explicit count */
+		n = min(ext[0x03] & 0x0f, 6);
+		break;
+	}
+
+	for (i = 0; i < n; i++)
+		cb((struct detailed_timing *)(det_base + 18 * i), closure);
+}
+
+static void
+vtb_for_each_detailed_block(u8 *ext, detailed_cb *cb, void *closure)
+{
+	unsigned int i, n = min((int)ext[0x02], 6);
+	u8 *det_base = ext + 5;
+
+	if (ext[0x01] != 1)
+		return; /* unknown version */
+
+	for (i = 0; i < n; i++)
+		cb((struct detailed_timing *)(det_base + 18 * i), closure);
+}
+
+static void
 drm_for_each_detailed_block(u8 *raw_edid, detailed_cb *cb, void *closure)
 {
 	int i;
@@ -696,7 +508,19 @@
 	for (i = 0; i < EDID_DETAILED_TIMINGS; i++)
 		cb(&(edid->detailed_timings[i]), closure);
 
-	/* XXX extension block walk */
+	for (i = 1; i <= raw_edid[0x7e]; i++) {
+		u8 *ext = raw_edid + (i * EDID_LENGTH);
+		switch (*ext) {
+		case CEA_EXT:
+			cea_for_each_detailed_block(ext, cb, closure);
+			break;
+		case VTB_EXT:
+			vtb_for_each_detailed_block(ext, cb, closure);
+			break;
+		default:
+			break;
+		}
+	}
 }
 
 static void
@@ -1047,117 +871,6 @@
 	return mode;
 }
 
-/*
- * Detailed mode info for the EDID "established modes" data to use.
- */
-static struct drm_display_mode edid_est_modes[] = {
-	{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
-		   968, 1056, 0, 600, 601, 605, 628, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@60Hz */
-	{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824,
-		   896, 1024, 0, 600, 601, 603,  625, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@56Hz */
-	{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656,
-		   720, 840, 0, 480, 481, 484, 500, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@75Hz */
-	{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664,
-		   704,  832, 0, 480, 489, 491, 520, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@72Hz */
-	{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 30240, 640, 704,
-		   768,  864, 0, 480, 483, 486, 525, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@67Hz */
-	{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25200, 640, 656,
-		   752, 800, 0, 480, 490, 492, 525, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@60Hz */
-	{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 738,
-		   846, 900, 0, 400, 421, 423,  449, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 720x400@88Hz */
-	{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 28320, 720, 738,
-		   846,  900, 0, 400, 412, 414, 449, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 720x400@70Hz */
-	{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296,
-		   1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1280x1024@75Hz */
-	{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78800, 1024, 1040,
-		   1136, 1312, 0,  768, 769, 772, 800, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1024x768@75Hz */
-	{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048,
-		   1184, 1328, 0,  768, 771, 777, 806, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@70Hz */
-	{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
-		   1184, 1344, 0,  768, 771, 777, 806, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@60Hz */
-	{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032,
-		   1208, 1264, 0, 768, 768, 776, 817, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 1024x768@43Hz */
-	{ DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 57284, 832, 864,
-		   928, 1152, 0, 624, 625, 628, 667, 0,
-		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 832x624@75Hz */
-	{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816,
-		   896, 1056, 0, 600, 601, 604,  625, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@75Hz */
-	{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856,
-		   976, 1040, 0, 600, 637, 643, 666, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@72Hz */
-	{ DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
-		   1344, 1600, 0,  864, 865, 868, 900, 0,
-		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1152x864@75Hz */
-};
-
-/**
- * add_established_modes - get est. modes from EDID and add them
- * @edid: EDID block to scan
- *
- * Each EDID block contains a bitmap of the supported "established modes" list
- * (defined above).  Tease them out and add them to the global modes list.
- */
-static int add_established_modes(struct drm_connector *connector, struct edid *edid)
-{
-	struct drm_device *dev = connector->dev;
-	unsigned long est_bits = edid->established_timings.t1 |
-		(edid->established_timings.t2 << 8) |
-		((edid->established_timings.mfg_rsvd & 0x80) << 9);
-	int i, modes = 0;
-
-	for (i = 0; i <= EDID_EST_TIMINGS; i++)
-		if (est_bits & (1<<i)) {
-			struct drm_display_mode *newmode;
-			newmode = drm_mode_duplicate(dev, &edid_est_modes[i]);
-			if (newmode) {
-				drm_mode_probed_add(connector, newmode);
-				modes++;
-			}
-		}
-
-	return modes;
-}
-
-/**
- * add_standard_modes - get std. modes from EDID and add them
- * @edid: EDID block to scan
- *
- * Standard modes can be calculated using the CVT standard.  Grab them from
- * @edid, calculate them, and add them to the list.
- */
-static int add_standard_modes(struct drm_connector *connector, struct edid *edid)
-{
-	int i, modes = 0;
-
-	for (i = 0; i < EDID_STD_TIMINGS; i++) {
-		struct drm_display_mode *newmode;
-
-		newmode = drm_mode_std(connector, edid,
-				       &edid->standard_timings[i],
-				       edid->revision);
-		if (newmode) {
-			drm_mode_probed_add(connector, newmode);
-			modes++;
-		}
-	}
-
-	return modes;
-}
-
 static bool
 mode_is_rb(struct drm_display_mode *mode)
 {
@@ -1267,6 +980,170 @@
 	return modes;
 }
 
+static void
+do_inferred_modes(struct detailed_timing *timing, void *c)
+{
+	struct detailed_mode_closure *closure = c;
+	struct detailed_non_pixel *data = &timing->data.other_data;
+	int gtf = (closure->edid->features & DRM_EDID_FEATURE_DEFAULT_GTF);
+
+	if (gtf && data->type == EDID_DETAIL_MONITOR_RANGE)
+		closure->modes += drm_gtf_modes_for_range(closure->connector,
+							  closure->edid,
+							  timing);
+}
+
+static int
+add_inferred_modes(struct drm_connector *connector, struct edid *edid)
+{
+	struct detailed_mode_closure closure = {
+		connector, edid, 0, 0, 0
+	};
+
+	if (version_greater(edid, 1, 0))
+		drm_for_each_detailed_block((u8 *)edid, do_inferred_modes,
+					    &closure);
+
+	return closure.modes;
+}
+
+static int
+drm_est3_modes(struct drm_connector *connector, struct detailed_timing *timing)
+{
+	int i, j, m, modes = 0;
+	struct drm_display_mode *mode;
+	u8 *est = ((u8 *)timing) + 5;
+
+	for (i = 0; i < 6; i++) {
+		for (j = 7; j > 0; j--) {
+			m = (i * 8) + (7 - j);
+			if (m >= ARRAY_SIZE(est3_modes))
+				break;
+			if (est[i] & (1 << j)) {
+				mode = drm_mode_find_dmt(connector->dev,
+							 est3_modes[m].w,
+							 est3_modes[m].h,
+							 est3_modes[m].r
+							 /*, est3_modes[m].rb */);
+				if (mode) {
+					drm_mode_probed_add(connector, mode);
+					modes++;
+				}
+			}
+		}
+	}
+
+	return modes;
+}
+
+static void
+do_established_modes(struct detailed_timing *timing, void *c)
+{
+	struct detailed_mode_closure *closure = c;
+	struct detailed_non_pixel *data = &timing->data.other_data;
+
+	if (data->type == EDID_DETAIL_EST_TIMINGS)
+		closure->modes += drm_est3_modes(closure->connector, timing);
+}
+
+/**
+ * add_established_modes - get est. modes from EDID and add them
+ * @edid: EDID block to scan
+ *
+ * Each EDID block contains a bitmap of the supported "established modes" list
+ * (defined above).  Tease them out and add them to the global modes list.
+ */
+static int
+add_established_modes(struct drm_connector *connector, struct edid *edid)
+{
+	struct drm_device *dev = connector->dev;
+	unsigned long est_bits = edid->established_timings.t1 |
+		(edid->established_timings.t2 << 8) |
+		((edid->established_timings.mfg_rsvd & 0x80) << 9);
+	int i, modes = 0;
+	struct detailed_mode_closure closure = {
+		connector, edid, 0, 0, 0
+	};
+
+	for (i = 0; i <= EDID_EST_TIMINGS; i++) {
+		if (est_bits & (1<<i)) {
+			struct drm_display_mode *newmode;
+			newmode = drm_mode_duplicate(dev, &edid_est_modes[i]);
+			if (newmode) {
+				drm_mode_probed_add(connector, newmode);
+				modes++;
+			}
+		}
+	}
+
+	if (version_greater(edid, 1, 0))
+		    drm_for_each_detailed_block((u8 *)edid,
+						do_established_modes, &closure);
+
+	return modes + closure.modes;
+}
+
+static void
+do_standard_modes(struct detailed_timing *timing, void *c)
+{
+	struct detailed_mode_closure *closure = c;
+	struct detailed_non_pixel *data = &timing->data.other_data;
+	struct drm_connector *connector = closure->connector;
+	struct edid *edid = closure->edid;
+
+	if (data->type == EDID_DETAIL_STD_MODES) {
+		int i;
+		for (i = 0; i < 6; i++) {
+			struct std_timing *std;
+			struct drm_display_mode *newmode;
+
+			std = &data->data.timings[i];
+			newmode = drm_mode_std(connector, edid, std,
+					       edid->revision);
+			if (newmode) {
+				drm_mode_probed_add(connector, newmode);
+				closure->modes++;
+			}
+		}
+	}
+}
+
+/**
+ * add_standard_modes - get std. modes from EDID and add them
+ * @edid: EDID block to scan
+ *
+ * Standard modes can be calculated using the appropriate standard (DMT,
+ * GTF or CVT. Grab them from @edid and add them to the list.
+ */
+static int
+add_standard_modes(struct drm_connector *connector, struct edid *edid)
+{
+	int i, modes = 0;
+	struct detailed_mode_closure closure = {
+		connector, edid, 0, 0, 0
+	};
+
+	for (i = 0; i < EDID_STD_TIMINGS; i++) {
+		struct drm_display_mode *newmode;
+
+		newmode = drm_mode_std(connector, edid,
+				       &edid->standard_timings[i],
+				       edid->revision);
+		if (newmode) {
+			drm_mode_probed_add(connector, newmode);
+			modes++;
+		}
+	}
+
+	if (version_greater(edid, 1, 0))
+		drm_for_each_detailed_block((u8 *)edid, do_standard_modes,
+					    &closure);
+
+	/* XXX should also look for standard codes in VTB blocks */
+
+	return modes + closure.modes;
+}
+
 static int drm_cvt_modes(struct drm_connector *connector,
 			 struct detailed_timing *timing)
 {
@@ -1316,235 +1193,78 @@
 	return modes;
 }
 
-static const struct {
-	short w;
-	short h;
-	short r;
-	short rb;
-} est3_modes[] = {
-	/* byte 6 */
-	{ 640, 350, 85, 0 },
-	{ 640, 400, 85, 0 },
-	{ 720, 400, 85, 0 },
-	{ 640, 480, 85, 0 },
-	{ 848, 480, 60, 0 },
-	{ 800, 600, 85, 0 },
-	{ 1024, 768, 85, 0 },
-	{ 1152, 864, 75, 0 },
-	/* byte 7 */
-	{ 1280, 768, 60, 1 },
-	{ 1280, 768, 60, 0 },
-	{ 1280, 768, 75, 0 },
-	{ 1280, 768, 85, 0 },
-	{ 1280, 960, 60, 0 },
-	{ 1280, 960, 85, 0 },
-	{ 1280, 1024, 60, 0 },
-	{ 1280, 1024, 85, 0 },
-	/* byte 8 */
-	{ 1360, 768, 60, 0 },
-	{ 1440, 900, 60, 1 },
-	{ 1440, 900, 60, 0 },
-	{ 1440, 900, 75, 0 },
-	{ 1440, 900, 85, 0 },
-	{ 1400, 1050, 60, 1 },
-	{ 1400, 1050, 60, 0 },
-	{ 1400, 1050, 75, 0 },
-	/* byte 9 */
-	{ 1400, 1050, 85, 0 },
-	{ 1680, 1050, 60, 1 },
-	{ 1680, 1050, 60, 0 },
-	{ 1680, 1050, 75, 0 },
-	{ 1680, 1050, 85, 0 },
-	{ 1600, 1200, 60, 0 },
-	{ 1600, 1200, 65, 0 },
-	{ 1600, 1200, 70, 0 },
-	/* byte 10 */
-	{ 1600, 1200, 75, 0 },
-	{ 1600, 1200, 85, 0 },
-	{ 1792, 1344, 60, 0 },
-	{ 1792, 1344, 85, 0 },
-	{ 1856, 1392, 60, 0 },
-	{ 1856, 1392, 75, 0 },
-	{ 1920, 1200, 60, 1 },
-	{ 1920, 1200, 60, 0 },
-	/* byte 11 */
-	{ 1920, 1200, 75, 0 },
-	{ 1920, 1200, 85, 0 },
-	{ 1920, 1440, 60, 0 },
-	{ 1920, 1440, 75, 0 },
-};
+static void
+do_cvt_mode(struct detailed_timing *timing, void *c)
+{
+	struct detailed_mode_closure *closure = c;
+	struct detailed_non_pixel *data = &timing->data.other_data;
+
+	if (data->type == EDID_DETAIL_CVT_3BYTE)
+		closure->modes += drm_cvt_modes(closure->connector, timing);
+}
 
 static int
-drm_est3_modes(struct drm_connector *connector, struct detailed_timing *timing)
-{
-	int i, j, m, modes = 0;
-	struct drm_display_mode *mode;
-	u8 *est = ((u8 *)timing) + 5;
+add_cvt_modes(struct drm_connector *connector, struct edid *edid)
+{	
+	struct detailed_mode_closure closure = {
+		connector, edid, 0, 0, 0
+	};
 
-	for (i = 0; i < 6; i++) {
-		for (j = 7; j > 0; j--) {
-			m = (i * 8) + (7 - j);
-			if (m >= ARRAY_SIZE(est3_modes))
-				break;
-			if (est[i] & (1 << j)) {
-				mode = drm_mode_find_dmt(connector->dev,
-							 est3_modes[m].w,
-							 est3_modes[m].h,
-							 est3_modes[m].r
-							 /*, est3_modes[m].rb */);
-				if (mode) {
-					drm_mode_probed_add(connector, mode);
-					modes++;
-				}
-			}
-		}
-	}
+	if (version_greater(edid, 1, 2))
+		drm_for_each_detailed_block((u8 *)edid, do_cvt_mode, &closure);
 
-	return modes;
+	/* XXX should also look for CVT codes in VTB blocks */
+
+	return closure.modes;
 }
 
-static int add_detailed_modes(struct drm_connector *connector,
-			      struct detailed_timing *timing,
-			      struct edid *edid, u32 quirks, int preferred)
+static void
+do_detailed_mode(struct detailed_timing *timing, void *c)
 {
-	int i, modes = 0;
-	struct detailed_non_pixel *data = &timing->data.other_data;
-	int gtf = (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF);
+	struct detailed_mode_closure *closure = c;
 	struct drm_display_mode *newmode;
-	struct drm_device *dev = connector->dev;
 
 	if (timing->pixel_clock) {
-		newmode = drm_mode_detailed(dev, edid, timing, quirks);
+		newmode = drm_mode_detailed(closure->connector->dev,
+					    closure->edid, timing,
+					    closure->quirks);
 		if (!newmode)
-			return 0;
+			return;
 
-		if (preferred)
+		if (closure->preferred)
 			newmode->type |= DRM_MODE_TYPE_PREFERRED;
 
-		drm_mode_probed_add(connector, newmode);
-		return 1;
+		drm_mode_probed_add(closure->connector, newmode);
+		closure->modes++;
+		closure->preferred = 0;
 	}
-
-	/* other timing types */
-	switch (data->type) {
-	case EDID_DETAIL_MONITOR_RANGE:
-		if (gtf)
-			modes += drm_gtf_modes_for_range(connector, edid,
-							 timing);
-		break;
-	case EDID_DETAIL_STD_MODES:
-		/* Six modes per detailed section */
-		for (i = 0; i < 6; i++) {
-			struct std_timing *std;
-			struct drm_display_mode *newmode;
-
-			std = &data->data.timings[i];
-			newmode = drm_mode_std(connector, edid, std,
-					       edid->revision);
-			if (newmode) {
-				drm_mode_probed_add(connector, newmode);
-				modes++;
-			}
-		}
-		break;
-	case EDID_DETAIL_CVT_3BYTE:
-		modes += drm_cvt_modes(connector, timing);
-		break;
-	case EDID_DETAIL_EST_TIMINGS:
-		modes += drm_est3_modes(connector, timing);
-		break;
-	default:
-		break;
-	}
-
-	return modes;
 }
 
-/**
- * add_detailed_info - get detailed mode info from EDID data
+/*
+ * add_detailed_modes - Add modes from detailed timings
  * @connector: attached connector
  * @edid: EDID block to scan
  * @quirks: quirks to apply
- *
- * Some of the detailed timing sections may contain mode information.  Grab
- * it and add it to the list.
  */
-static int add_detailed_info(struct drm_connector *connector,
-			     struct edid *edid, u32 quirks)
+static int
+add_detailed_modes(struct drm_connector *connector, struct edid *edid,
+		   u32 quirks)
 {
-	int i, modes = 0;
+	struct detailed_mode_closure closure = {
+		connector,
+		edid,
+		1,
+		quirks,
+		0
+	};
 
-	for (i = 0; i < EDID_DETAILED_TIMINGS; i++) {
-		struct detailed_timing *timing = &edid->detailed_timings[i];
-		int preferred = (i == 0);
+	if (closure.preferred && !version_greater(edid, 1, 3))
+		closure.preferred =
+		    (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING);
 
-		if (preferred && edid->version == 1 && edid->revision < 4)
-			preferred = (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING);
+	drm_for_each_detailed_block((u8 *)edid, do_detailed_mode, &closure);
 
-		/* In 1.0, only timings are allowed */
-		if (!timing->pixel_clock && edid->version == 1 &&
-			edid->revision == 0)
-			continue;
-
-		modes += add_detailed_modes(connector, timing, edid, quirks,
-					    preferred);
-	}
-
-	return modes;
-}
-
-/**
- * add_detailed_mode_eedid - get detailed mode info from addtional timing
- * 			EDID block
- * @connector: attached connector
- * @edid: EDID block to scan(It is only to get addtional timing EDID block)
- * @quirks: quirks to apply
- *
- * Some of the detailed timing sections may contain mode information.  Grab
- * it and add it to the list.
- */
-static int add_detailed_info_eedid(struct drm_connector *connector,
-			     struct edid *edid, u32 quirks)
-{
-	int i, modes = 0;
-	char *edid_ext = NULL;
-	struct detailed_timing *timing;
-	int start_offset, end_offset;
-
-	if (edid->version == 1 && edid->revision < 3)
-		return 0;
-	if (!edid->extensions)
-		return 0;
-
-	/* Find CEA extension */
-	for (i = 0; i < edid->extensions; i++) {
-		edid_ext = (char *)edid + EDID_LENGTH * (i + 1);
-		if (edid_ext[0] == 0x02)
-			break;
-	}
-
-	if (i == edid->extensions)
-		return 0;
-
-	/* Get the start offset of detailed timing block */
-	start_offset = edid_ext[2];
-	if (start_offset == 0) {
-		/* If the start_offset is zero, it means that neither detailed
-		 * info nor data block exist. In such case it is also
-		 * unnecessary to parse the detailed timing info.
-		 */
-		return 0;
-	}
-
-	end_offset = EDID_LENGTH;
-	end_offset -= sizeof(struct detailed_timing);
-	for (i = start_offset; i < end_offset;
-			i += sizeof(struct detailed_timing)) {
-		timing = (struct detailed_timing *)(edid_ext + i);
-		modes += add_detailed_modes(connector, timing, edid, quirks, 0);
-	}
-
-	return modes;
+	return closure.modes;
 }
 
 #define HDMI_IDENTIFIER 0x000C03
@@ -1640,35 +1360,21 @@
 	 * - established timing codes
 	 * - modes inferred from GTF or CVT range information
 	 *
-	 * We don't quite implement this yet, but we're close.
+	 * We get this pretty much right.
 	 *
 	 * XXX order for additional mode types in extension blocks?
 	 */
-	num_modes += add_detailed_info(connector, edid, quirks);
-	num_modes += add_detailed_info_eedid(connector, edid, quirks);
+	num_modes += add_detailed_modes(connector, edid, quirks);
+	num_modes += add_cvt_modes(connector, edid);
 	num_modes += add_standard_modes(connector, edid);
 	num_modes += add_established_modes(connector, edid);
+	num_modes += add_inferred_modes(connector, edid);
 
 	if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
 		edid_fixup_preferred(connector, quirks);
 
-	connector->display_info.serration_vsync = (edid->input & DRM_EDID_INPUT_SERRATION_VSYNC) ? 1 : 0;
-	connector->display_info.sync_on_green = (edid->input & DRM_EDID_INPUT_SYNC_ON_GREEN) ? 1 : 0;
-	connector->display_info.composite_sync = (edid->input & DRM_EDID_INPUT_COMPOSITE_SYNC) ? 1 : 0;
-	connector->display_info.separate_syncs = (edid->input & DRM_EDID_INPUT_SEPARATE_SYNCS) ? 1 : 0;
-	connector->display_info.blank_to_black = (edid->input & DRM_EDID_INPUT_BLANK_TO_BLACK) ? 1 : 0;
-	connector->display_info.video_level = (edid->input & DRM_EDID_INPUT_VIDEO_LEVEL) >> 5;
-	connector->display_info.digital = (edid->input & DRM_EDID_INPUT_DIGITAL) ? 1 : 0;
 	connector->display_info.width_mm = edid->width_cm * 10;
 	connector->display_info.height_mm = edid->height_cm * 10;
-	connector->display_info.gamma = edid->gamma;
-	connector->display_info.gtf_supported = (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) ? 1 : 0;
-	connector->display_info.standard_color = (edid->features & DRM_EDID_FEATURE_STANDARD_COLOR) ? 1 : 0;
-	connector->display_info.display_type = (edid->features & DRM_EDID_FEATURE_DISPLAY_TYPE) >> 3;
-	connector->display_info.active_off_supported = (edid->features & DRM_EDID_FEATURE_PM_ACTIVE_OFF) ? 1 : 0;
-	connector->display_info.suspend_supported = (edid->features & DRM_EDID_FEATURE_PM_SUSPEND) ? 1 : 0;
-	connector->display_info.standby_supported = (edid->features & DRM_EDID_FEATURE_PM_STANDBY) ? 1 : 0;
-	connector->display_info.gamma = edid->gamma;
 
 	return num_modes;
 }
diff --git a/drivers/gpu/drm/drm_edid_modes.h b/drivers/gpu/drm/drm_edid_modes.h
new file mode 100644
index 0000000..6eb7592
--- /dev/null
+++ b/drivers/gpu/drm/drm_edid_modes.h
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 2007-2008 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ * Copyright 2010 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include "drmP.h"
+#include "drm_edid.h"
+
+/*
+ * Autogenerated from the DMT spec.
+ * This table is copied from xfree86/modes/xf86EdidModes.c.
+ * But the mode with Reduced blank feature is deleted.
+ */
+static struct drm_display_mode drm_dmt_modes[] = {
+	/* 640x350@85Hz */
+	{ DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 31500, 640, 672,
+		   736, 832, 0, 350, 382, 385, 445, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+	/* 640x400@85Hz */
+	{ DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 31500, 640, 672,
+		   736, 832, 0, 400, 401, 404, 445, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 720x400@85Hz */
+	{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 756,
+		   828, 936, 0, 400, 401, 404, 446, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 640x480@60Hz */
+	{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
+		   752, 800, 0, 480, 489, 492, 525, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+	/* 640x480@72Hz */
+	{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664,
+		   704, 832, 0, 480, 489, 492, 520, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+	/* 640x480@75Hz */
+	{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656,
+		   720, 840, 0, 480, 481, 484, 500, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+	/* 640x480@85Hz */
+	{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 36000, 640, 696,
+		   752, 832, 0, 480, 481, 484, 509, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+	/* 800x600@56Hz */
+	{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824,
+		   896, 1024, 0, 600, 601, 603, 625, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 800x600@60Hz */
+	{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
+		   968, 1056, 0, 600, 601, 605, 628, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 800x600@72Hz */
+	{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856,
+		   976, 1040, 0, 600, 637, 643, 666, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 800x600@75Hz */
+	{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816,
+		   896, 1056, 0, 600, 601, 604, 625, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 800x600@85Hz */
+	{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 56250, 800, 832,
+		   896, 1048, 0, 600, 601, 604, 631, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 848x480@60Hz */
+	{ DRM_MODE("848x480", DRM_MODE_TYPE_DRIVER, 33750, 848, 864,
+		   976, 1088, 0, 480, 486, 494, 517, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1024x768@43Hz, interlace */
+	{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 44900, 1024, 1032,
+		   1208, 1264, 0, 768, 768, 772, 817, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
+			DRM_MODE_FLAG_INTERLACE) },
+	/* 1024x768@60Hz */
+	{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
+		   1184, 1344, 0, 768, 771, 777, 806, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+	/* 1024x768@70Hz */
+	{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048,
+		   1184, 1328, 0, 768, 771, 777, 806, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
+	/* 1024x768@75Hz */
+	{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78750, 1024, 1040,
+		   1136, 1312, 0, 768, 769, 772, 800, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1024x768@85Hz */
+	{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 94500, 1024, 1072,
+		   1168, 1376, 0, 768, 769, 772, 808, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1152x864@75Hz */
+	{ DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
+		   1344, 1600, 0, 864, 865, 868, 900, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1280x768@60Hz */
+	{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 79500, 1280, 1344,
+		   1472, 1664, 0, 768, 771, 778, 798, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1280x768@75Hz */
+	{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 102250, 1280, 1360,
+		   1488, 1696, 0, 768, 771, 778, 805, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+	/* 1280x768@85Hz */
+	{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 117500, 1280, 1360,
+		   1496, 1712, 0, 768, 771, 778, 809, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1280x800@60Hz */
+	{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 83500, 1280, 1352,
+		   1480, 1680, 0, 800, 803, 809, 831, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+	/* 1280x800@75Hz */
+	{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 106500, 1280, 1360,
+		   1488, 1696, 0, 800, 803, 809, 838, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1280x800@85Hz */
+	{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 122500, 1280, 1360,
+		   1496, 1712, 0, 800, 803, 809, 843, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1280x960@60Hz */
+	{ DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1376,
+		   1488, 1800, 0, 960, 961, 964, 1000, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1280x960@85Hz */
+	{ DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1344,
+		   1504, 1728, 0, 960, 961, 964, 1011, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1280x1024@60Hz */
+	{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1328,
+		   1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1280x1024@75Hz */
+	{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296,
+		   1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1280x1024@85Hz */
+	{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 157500, 1280, 1344,
+		   1504, 1728, 0, 1024, 1025, 1028, 1072, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1360x768@60Hz */
+	{ DRM_MODE("1360x768", DRM_MODE_TYPE_DRIVER, 85500, 1360, 1424,
+		   1536, 1792, 0, 768, 771, 777, 795, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1440x1050@60Hz */
+	{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 121750, 1400, 1488,
+		   1632, 1864, 0, 1050, 1053, 1057, 1089, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1440x1050@75Hz */
+	{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 156000, 1400, 1504,
+		   1648, 1896, 0, 1050, 1053, 1057, 1099, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1440x1050@85Hz */
+	{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 179500, 1400, 1504,
+		   1656, 1912, 0, 1050, 1053, 1057, 1105, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1440x900@60Hz */
+	{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 106500, 1440, 1520,
+		   1672, 1904, 0, 900, 903, 909, 934, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1440x900@75Hz */
+	{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 136750, 1440, 1536,
+		   1688, 1936, 0, 900, 903, 909, 942, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1440x900@85Hz */
+	{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 157000, 1440, 1544,
+		   1696, 1952, 0, 900, 903, 909, 948, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1600x1200@60Hz */
+	{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600, 1664,
+		   1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1600x1200@65Hz */
+	{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 175500, 1600, 1664,
+		   1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1600x1200@70Hz */
+	{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 189000, 1600, 1664,
+		   1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1600x1200@75Hz */
+	{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 202500, 1600, 1664,
+		   1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1600x1200@85Hz */
+	{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 229500, 1600, 1664,
+		   1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1680x1050@60Hz */
+	{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 146250, 1680, 1784,
+		   1960, 2240, 0, 1050, 1053, 1059, 1089, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1680x1050@75Hz */
+	{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 187000, 1680, 1800,
+		   1976, 2272, 0, 1050, 1053, 1059, 1099, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1680x1050@85Hz */
+	{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 214750, 1680, 1808,
+		   1984, 2288, 0, 1050, 1053, 1059, 1105, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1792x1344@60Hz */
+	{ DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 204750, 1792, 1920,
+		   2120, 2448, 0, 1344, 1345, 1348, 1394, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1729x1344@75Hz */
+	{ DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 261000, 1792, 1888,
+		   2104, 2456, 0, 1344, 1345, 1348, 1417, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1853x1392@60Hz */
+	{ DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 218250, 1856, 1952,
+		   2176, 2528, 0, 1392, 1393, 1396, 1439, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1856x1392@75Hz */
+	{ DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 288000, 1856, 1984,
+		   2208, 2560, 0, 1392, 1395, 1399, 1500, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1920x1200@60Hz */
+	{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 193250, 1920, 2056,
+		   2256, 2592, 0, 1200, 1203, 1209, 1245, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1920x1200@75Hz */
+	{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 245250, 1920, 2056,
+		   2264, 2608, 0, 1200, 1203, 1209, 1255, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1920x1200@85Hz */
+	{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 281250, 1920, 2064,
+		   2272, 2624, 0, 1200, 1203, 1209, 1262, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1920x1440@60Hz */
+	{ DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 234000, 1920, 2048,
+		   2256, 2600, 0, 1440, 1441, 1444, 1500, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 1920x1440@75Hz */
+	{ DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2064,
+		   2288, 2640, 0, 1440, 1441, 1444, 1500, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 2560x1600@60Hz */
+	{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 348500, 2560, 2752,
+		   3032, 3504, 0, 1600, 1603, 1609, 1658, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 2560x1600@75HZ */
+	{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 443250, 2560, 2768,
+		   3048, 3536, 0, 1600, 1603, 1609, 1672, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+	/* 2560x1600@85HZ */
+	{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 505250, 2560, 2768,
+		   3048, 3536, 0, 1600, 1603, 1609, 1682, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+};
+static const int drm_num_dmt_modes =
+	sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode);
+
+static struct drm_display_mode edid_est_modes[] = {
+	{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
+		   968, 1056, 0, 600, 601, 605, 628, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@60Hz */
+	{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824,
+		   896, 1024, 0, 600, 601, 603,  625, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@56Hz */
+	{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656,
+		   720, 840, 0, 480, 481, 484, 500, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@75Hz */
+	{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664,
+		   704,  832, 0, 480, 489, 491, 520, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@72Hz */
+	{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 30240, 640, 704,
+		   768,  864, 0, 480, 483, 486, 525, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@67Hz */
+	{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25200, 640, 656,
+		   752, 800, 0, 480, 490, 492, 525, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@60Hz */
+	{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 738,
+		   846, 900, 0, 400, 421, 423,  449, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 720x400@88Hz */
+	{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 28320, 720, 738,
+		   846,  900, 0, 400, 412, 414, 449, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 720x400@70Hz */
+	{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296,
+		   1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1280x1024@75Hz */
+	{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78800, 1024, 1040,
+		   1136, 1312, 0,  768, 769, 772, 800, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1024x768@75Hz */
+	{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048,
+		   1184, 1328, 0,  768, 771, 777, 806, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@70Hz */
+	{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
+		   1184, 1344, 0,  768, 771, 777, 806, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@60Hz */
+	{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032,
+		   1208, 1264, 0, 768, 768, 776, 817, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 1024x768@43Hz */
+	{ DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 57284, 832, 864,
+		   928, 1152, 0, 624, 625, 628, 667, 0,
+		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 832x624@75Hz */
+	{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816,
+		   896, 1056, 0, 600, 601, 604,  625, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@75Hz */
+	{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856,
+		   976, 1040, 0, 600, 637, 643, 666, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@72Hz */
+	{ DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
+		   1344, 1600, 0,  864, 865, 868, 900, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1152x864@75Hz */
+};
+
+static const struct {
+	short w;
+	short h;
+	short r;
+	short rb;
+} est3_modes[] = {
+	/* byte 6 */
+	{ 640, 350, 85, 0 },
+	{ 640, 400, 85, 0 },
+	{ 720, 400, 85, 0 },
+	{ 640, 480, 85, 0 },
+	{ 848, 480, 60, 0 },
+	{ 800, 600, 85, 0 },
+	{ 1024, 768, 85, 0 },
+	{ 1152, 864, 75, 0 },
+	/* byte 7 */
+	{ 1280, 768, 60, 1 },
+	{ 1280, 768, 60, 0 },
+	{ 1280, 768, 75, 0 },
+	{ 1280, 768, 85, 0 },
+	{ 1280, 960, 60, 0 },
+	{ 1280, 960, 85, 0 },
+	{ 1280, 1024, 60, 0 },
+	{ 1280, 1024, 85, 0 },
+	/* byte 8 */
+	{ 1360, 768, 60, 0 },
+	{ 1440, 900, 60, 1 },
+	{ 1440, 900, 60, 0 },
+	{ 1440, 900, 75, 0 },
+	{ 1440, 900, 85, 0 },
+	{ 1400, 1050, 60, 1 },
+	{ 1400, 1050, 60, 0 },
+	{ 1400, 1050, 75, 0 },
+	/* byte 9 */
+	{ 1400, 1050, 85, 0 },
+	{ 1680, 1050, 60, 1 },
+	{ 1680, 1050, 60, 0 },
+	{ 1680, 1050, 75, 0 },
+	{ 1680, 1050, 85, 0 },
+	{ 1600, 1200, 60, 0 },
+	{ 1600, 1200, 65, 0 },
+	{ 1600, 1200, 70, 0 },
+	/* byte 10 */
+	{ 1600, 1200, 75, 0 },
+	{ 1600, 1200, 85, 0 },
+	{ 1792, 1344, 60, 0 },
+	{ 1792, 1344, 85, 0 },
+	{ 1856, 1392, 60, 0 },
+	{ 1856, 1392, 75, 0 },
+	{ 1920, 1200, 60, 1 },
+	{ 1920, 1200, 60, 0 },
+	/* byte 11 */
+	{ 1920, 1200, 75, 0 },
+	{ 1920, 1200, 85, 0 },
+	{ 1920, 1440, 60, 0 },
+	{ 1920, 1440, 75, 0 },
+};
+static const int num_est3_modes = sizeof(est3_modes) / sizeof(est3_modes[0]);
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 2ca8df8..3a652a6 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -135,15 +135,9 @@
 	retcode = drm_open_helper(inode, filp, dev);
 	if (!retcode) {
 		atomic_inc(&dev->counts[_DRM_STAT_OPENS]);
-		spin_lock(&dev->count_lock);
-		if (!dev->open_count++) {
-			spin_unlock(&dev->count_lock);
+		if (!dev->open_count++)
 			retcode = drm_setup(dev);
-			goto out;
-		}
-		spin_unlock(&dev->count_lock);
 	}
-out:
 	if (!retcode) {
 		mutex_lock(&dev->struct_mutex);
 		if (minor->type == DRM_MINOR_LEGACY) {
@@ -570,18 +564,14 @@
 	 */
 
 	atomic_inc(&dev->counts[_DRM_STAT_CLOSES]);
-	spin_lock(&dev->count_lock);
 	if (!--dev->open_count) {
 		if (atomic_read(&dev->ioctl_count)) {
 			DRM_ERROR("Device busy: %d\n",
 				  atomic_read(&dev->ioctl_count));
 			retcode = -EBUSY;
-			goto out;
-		}
-		retcode = drm_lastclose(dev);
+		} else
+			retcode = drm_lastclose(dev);
 	}
-out:
-	spin_unlock(&dev->count_lock);
 	mutex_unlock(&drm_global_mutex);
 
 	return retcode;
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index 4f1b867..bf92d07 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -322,7 +322,7 @@
 
 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
 	if (obj == NULL)
-		return -EBADF;
+		return -ENOENT;
 
 again:
 	if (idr_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0) {
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index 7b03b19..47db4df 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -392,6 +392,7 @@
 		if (sv->drm_di_minor >= 1) {
 			/*
 			 * Version 1.1 includes tying of DRM to specific device
+			 * Version 1.4 has proper PCI domain support
 			 */
 			retcode = drm_set_busid(dev, file_priv);
 			if (retcode)
diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c
index 833b35f..08792a7 100644
--- a/drivers/gpu/drm/i2c/ch7006_drv.c
+++ b/drivers/gpu/drm/i2c/ch7006_drv.c
@@ -470,6 +470,7 @@
 	priv->hmargin = 50;
 	priv->vmargin = 50;
 	priv->last_dpms = -1;
+	priv->chip_version = ch7006_read(client, CH7006_VERSION_ID);
 
 	if (ch7006_tv_norm) {
 		for (i = 0; i < NUM_TV_NORMS; i++) {
diff --git a/drivers/gpu/drm/i2c/ch7006_mode.c b/drivers/gpu/drm/i2c/ch7006_mode.c
index e447dfb..c860f24 100644
--- a/drivers/gpu/drm/i2c/ch7006_mode.c
+++ b/drivers/gpu/drm/i2c/ch7006_mode.c
@@ -316,7 +316,10 @@
 		}
 
 	} else {
-		*power |= bitfs(CH7006_POWER_LEVEL, FULL_POWER_OFF);
+		if (priv->chip_version >= 0x20)
+			*power |= bitfs(CH7006_POWER_LEVEL, FULL_POWER_OFF);
+		else
+			*power |= bitfs(CH7006_POWER_LEVEL, POWER_OFF);
 	}
 }
 
diff --git a/drivers/gpu/drm/i2c/ch7006_priv.h b/drivers/gpu/drm/i2c/ch7006_priv.h
index 1c6d2e3..17667b7 100644
--- a/drivers/gpu/drm/i2c/ch7006_priv.h
+++ b/drivers/gpu/drm/i2c/ch7006_priv.h
@@ -95,6 +95,7 @@
 	int flicker;
 	int scale;
 
+	int chip_version;
 	int last_dpms;
 };
 
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 2a4ed7c..0758c78 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -456,7 +456,7 @@
 
 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
 	if (obj == NULL)
-		return -EBADF;
+		return -ENOENT;
 	obj_priv = to_intel_bo(obj);
 
 	/* Bounds check source.
@@ -919,7 +919,7 @@
 
 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
 	if (obj == NULL)
-		return -EBADF;
+		return -ENOENT;
 	obj_priv = to_intel_bo(obj);
 
 	/* Bounds check destination.
@@ -1002,7 +1002,7 @@
 
 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
 	if (obj == NULL)
-		return -EBADF;
+		return -ENOENT;
 	obj_priv = to_intel_bo(obj);
 
 	mutex_lock(&dev->struct_mutex);
@@ -1060,7 +1060,7 @@
 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
 	if (obj == NULL) {
 		mutex_unlock(&dev->struct_mutex);
-		return -EBADF;
+		return -ENOENT;
 	}
 
 #if WATCH_BUF
@@ -1099,7 +1099,7 @@
 
 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
 	if (obj == NULL)
-		return -EBADF;
+		return -ENOENT;
 
 	offset = args->offset;
 
@@ -1373,7 +1373,7 @@
 
 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
 	if (obj == NULL)
-		return -EBADF;
+		return -ENOENT;
 
 	mutex_lock(&dev->struct_mutex);
 
@@ -3364,7 +3364,7 @@
 						   reloc->target_handle);
 		if (target_obj == NULL) {
 			i915_gem_object_unpin(obj);
-			return -EBADF;
+			return -ENOENT;
 		}
 		target_obj_priv = to_intel_bo(target_obj);
 
@@ -3781,7 +3781,7 @@
 				   exec_list[i].handle, i);
 			/* prevent error path from reading uninitialized data */
 			args->buffer_count = i + 1;
-			ret = -EBADF;
+			ret = -ENOENT;
 			goto err;
 		}
 
@@ -3791,7 +3791,7 @@
 				   object_list[i]);
 			/* prevent error path from reading uninitialized data */
 			args->buffer_count = i + 1;
-			ret = -EBADF;
+			ret = -EINVAL;
 			goto err;
 		}
 		obj_priv->in_execbuffer = true;
@@ -4265,7 +4265,7 @@
 		DRM_ERROR("Bad handle in i915_gem_pin_ioctl(): %d\n",
 			  args->handle);
 		mutex_unlock(&dev->struct_mutex);
-		return -EBADF;
+		return -ENOENT;
 	}
 	obj_priv = to_intel_bo(obj);
 
@@ -4321,7 +4321,7 @@
 		DRM_ERROR("Bad handle in i915_gem_unpin_ioctl(): %d\n",
 			  args->handle);
 		mutex_unlock(&dev->struct_mutex);
-		return -EBADF;
+		return -ENOENT;
 	}
 
 	obj_priv = to_intel_bo(obj);
@@ -4355,7 +4355,7 @@
 	if (obj == NULL) {
 		DRM_ERROR("Bad handle in i915_gem_busy_ioctl(): %d\n",
 			  args->handle);
-		return -EBADF;
+		return -ENOENT;
 	}
 
 	mutex_lock(&dev->struct_mutex);
@@ -4408,7 +4408,7 @@
 	if (obj == NULL) {
 		DRM_ERROR("Bad handle in i915_gem_madvise_ioctl(): %d\n",
 			  args->handle);
-		return -EBADF;
+		return -ENOENT;
 	}
 
 	mutex_lock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
index 155719e..710eca7 100644
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -275,7 +275,7 @@
 
 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
 	if (obj == NULL)
-		return -EINVAL;
+		return -ENOENT;
 	obj_priv = to_intel_bo(obj);
 
 	if (!i915_tiling_ok(dev, args->stride, obj->size, args->tiling_mode)) {
@@ -362,7 +362,7 @@
 
 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
 	if (obj == NULL)
-		return -EINVAL;
+		return -ENOENT;
 	obj_priv = to_intel_bo(obj);
 
 	mutex_lock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 1e5e0d3..5ec10e0 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4429,15 +4429,12 @@
 }
 
 static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
-				 u16 *blue, uint32_t size)
+				 u16 *blue, uint32_t start, uint32_t size)
 {
+	int end = (start + size > 256) ? 256 : start + size, i;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	int i;
 
-	if (size != 256)
-		return;
-
-	for (i = 0; i < 256; i++) {
+	for (i = start; i < end; i++) {
 		intel_crtc->lut_r[i] = red[i] >> 8;
 		intel_crtc->lut_g[i] = green[i] >> 8;
 		intel_crtc->lut_b[i] = blue[i] >> 8;
@@ -5412,18 +5409,18 @@
 
 	obj = drm_gem_object_lookup(dev, filp, mode_cmd->handle);
 	if (!obj)
-		return NULL;
+		return ERR_PTR(-ENOENT);
 
 	intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
 	if (!intel_fb)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
 	ret = intel_framebuffer_init(dev, intel_fb,
 				     mode_cmd, obj);
 	if (ret) {
 		drm_gem_object_unreference_unlocked(obj);
 		kfree(intel_fb);
-		return NULL;
+		return ERR_PTR(ret);
 	}
 
 	return &intel_fb->base;
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index a79525f..7bdc962 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -121,7 +121,9 @@
 
 	info->par = ifbdev;
 
-	intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, fbo);
+	ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, fbo);
+	if (ret)
+		goto out_unpin;
 
 	fb = &ifbdev->ifb.base;
 
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index 2405d5e..e9b06e4 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -12,12 +12,12 @@
              nouveau_dp.o \
              nv04_timer.o \
              nv04_mc.o nv40_mc.o nv50_mc.o \
-             nv04_fb.o nv10_fb.o nv30_fb.o nv40_fb.o nv50_fb.o \
-             nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o \
+             nv04_fb.o nv10_fb.o nv30_fb.o nv40_fb.o nv50_fb.o nvc0_fb.o \
+             nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o nvc0_fifo.o \
              nv04_graph.o nv10_graph.o nv20_graph.o \
-             nv40_graph.o nv50_graph.o \
+             nv40_graph.o nv50_graph.o nvc0_graph.o \
              nv40_grctx.o nv50_grctx.o \
-             nv04_instmem.o nv50_instmem.o \
+             nv04_instmem.o nv50_instmem.o nvc0_instmem.o \
              nv50_crtc.o nv50_dac.o nv50_sor.o \
              nv50_cursor.o nv50_display.o nv50_fbcon.o \
              nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index 7369b5e..0b69a96 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -1928,6 +1928,31 @@
 }
 
 static int
+init_ltime(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
+{
+	/*
+	 * INIT_LTIME   opcode: 0x57 ('V')
+	 *
+	 * offset      (8  bit): opcode
+	 * offset + 1  (16 bit): time
+	 *
+	 * Sleep for "time" miliseconds.
+	 */
+
+	unsigned time = ROM16(bios->data[offset + 1]);
+
+	if (!iexec->execute)
+		return 3;
+
+	BIOSLOG(bios, "0x%04X: Sleeping for 0x%04X miliseconds\n",
+		offset, time);
+
+	msleep(time);
+
+	return 3;
+}
+
+static int
 init_zm_reg_sequence(struct nvbios *bios, uint16_t offset,
 		     struct init_exec *iexec)
 {
@@ -1995,6 +2020,64 @@
 }
 
 static int
+init_i2c_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
+{
+	/*
+	 * INIT_I2C_IF   opcode: 0x5E ('^')
+	 *
+	 * offset      (8 bit): opcode
+	 * offset + 1  (8 bit): DCB I2C table entry index
+	 * offset + 2  (8 bit): I2C slave address
+	 * offset + 3  (8 bit): I2C register
+	 * offset + 4  (8 bit): mask
+	 * offset + 5  (8 bit): data
+	 *
+	 * Read the register given by "I2C register" on the device addressed
+	 * by "I2C slave address" on the I2C bus given by "DCB I2C table
+	 * entry index". Compare the result AND "mask" to "data".
+	 * If they're not equal, skip subsequent opcodes until condition is
+	 * inverted (INIT_NOT), or we hit INIT_RESUME
+	 */
+
+	uint8_t i2c_index = bios->data[offset + 1];
+	uint8_t i2c_address = bios->data[offset + 2] >> 1;
+	uint8_t reg = bios->data[offset + 3];
+	uint8_t mask = bios->data[offset + 4];
+	uint8_t data = bios->data[offset + 5];
+	struct nouveau_i2c_chan *chan;
+	union i2c_smbus_data val;
+	int ret;
+
+	/* no execute check by design */
+
+	BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X\n",
+		offset, i2c_index, i2c_address);
+
+	chan = init_i2c_device_find(bios->dev, i2c_index);
+	if (!chan)
+		return -ENODEV;
+
+	ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0,
+			     I2C_SMBUS_READ, reg,
+			     I2C_SMBUS_BYTE_DATA, &val);
+	if (ret < 0) {
+		BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Value: [no device], "
+			      "Mask: 0x%02X, Data: 0x%02X\n",
+			offset, reg, mask, data);
+		iexec->execute = 0;
+		return 6;
+	}
+
+	BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Value: 0x%02X, "
+		      "Mask: 0x%02X, Data: 0x%02X\n",
+		offset, reg, val.byte, mask, data);
+
+	iexec->execute = ((val.byte & mask) == data);
+
+	return 6;
+}
+
+static int
 init_copy_nv_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
 	/*
@@ -2083,9 +2166,10 @@
 	uint32_t val = 0;
 
 	if (off < pci_resource_len(dev->pdev, 1)) {
-		uint32_t __iomem *p = io_mapping_map_atomic_wc(fb, off, KM_USER0);
+		uint32_t __iomem *p =
+			io_mapping_map_atomic_wc(fb, off & PAGE_MASK, KM_USER0);
 
-		val = ioread32(p);
+		val = ioread32(p + (off & ~PAGE_MASK));
 
 		io_mapping_unmap_atomic(p, KM_USER0);
 	}
@@ -2098,9 +2182,10 @@
 	uint32_t off, uint32_t val)
 {
 	if (off < pci_resource_len(dev->pdev, 1)) {
-		uint32_t __iomem *p = io_mapping_map_atomic_wc(fb, off, KM_USER0);
+		uint32_t __iomem *p =
+			io_mapping_map_atomic_wc(fb, off & PAGE_MASK, KM_USER0);
 
-		iowrite32(val, p);
+		iowrite32(val, p + (off & ~PAGE_MASK));
 		wmb();
 
 		io_mapping_unmap_atomic(p, KM_USER0);
@@ -2165,7 +2250,7 @@
 			  NV04_PFB_BOOT_0_RAM_AMOUNT,
 			  NV04_PFB_BOOT_0_RAM_AMOUNT_4MB);
 
-	} else if (peek_fb(dev, fb, 0) == patt) {
+	} else if (peek_fb(dev, fb, 0) != patt) {
 		if (read_back_fb(dev, fb, 0x800000, patt))
 			bios_md32(bios, NV04_PFB_BOOT_0,
 				  NV04_PFB_BOOT_0_RAM_AMOUNT,
@@ -2593,7 +2678,7 @@
 	/* no iexec->execute check by design */
 
 	uint32_t straps = bios_rd32(bios, NV_PEXTDEV_BOOT_0);
-	uint8_t cr3c = ((straps << 2) & 0xf0) | (straps & (1 << 6));
+	uint8_t cr3c = ((straps << 2) & 0xf0) | (straps & 0x40) >> 6;
 
 	if (bios->major_version > 2)
 		return 0;
@@ -3140,7 +3225,7 @@
 	const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c };
 	int i;
 
-	if (dev_priv->card_type != NV_50) {
+	if (dev_priv->card_type < NV_50) {
 		NV_ERROR(bios->dev, "INIT_GPIO on unsupported chipset\n");
 		return 1;
 	}
@@ -3490,6 +3575,69 @@
 	return len;
 }
 
+static int
+init_i2c_long_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
+{
+	/*
+	 * INIT_I2C_LONG_IF   opcode: 0x9A ('')
+	 *
+	 * offset      (8 bit): opcode
+	 * offset + 1  (8 bit): DCB I2C table entry index
+	 * offset + 2  (8 bit): I2C slave address
+	 * offset + 3  (16 bit): I2C register
+	 * offset + 5  (8 bit): mask
+	 * offset + 6  (8 bit): data
+	 *
+	 * Read the register given by "I2C register" on the device addressed
+	 * by "I2C slave address" on the I2C bus given by "DCB I2C table
+	 * entry index". Compare the result AND "mask" to "data".
+	 * If they're not equal, skip subsequent opcodes until condition is
+	 * inverted (INIT_NOT), or we hit INIT_RESUME
+	 */
+
+	uint8_t i2c_index = bios->data[offset + 1];
+	uint8_t i2c_address = bios->data[offset + 2] >> 1;
+	uint8_t reglo = bios->data[offset + 3];
+	uint8_t reghi = bios->data[offset + 4];
+	uint8_t mask = bios->data[offset + 5];
+	uint8_t data = bios->data[offset + 6];
+	struct nouveau_i2c_chan *chan;
+	uint8_t buf0[2] = { reghi, reglo };
+	uint8_t buf1[1];
+	struct i2c_msg msg[2] = {
+		{ i2c_address, 0, 1, buf0 },
+		{ i2c_address, I2C_M_RD, 1, buf1 },
+	};
+	int ret;
+
+	/* no execute check by design */
+
+	BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X\n",
+		offset, i2c_index, i2c_address);
+
+	chan = init_i2c_device_find(bios->dev, i2c_index);
+	if (!chan)
+		return -ENODEV;
+
+
+	ret = i2c_transfer(&chan->adapter, msg, 2);
+	if (ret < 0) {
+		BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X:0x%02X, Value: [no device], "
+			      "Mask: 0x%02X, Data: 0x%02X\n",
+			offset, reghi, reglo, mask, data);
+		iexec->execute = 0;
+		return 7;
+	}
+
+	BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X:0x%02X, Value: 0x%02X, "
+		      "Mask: 0x%02X, Data: 0x%02X\n",
+		offset, reghi, reglo, buf1[0], mask, data);
+
+	iexec->execute = ((buf1[0] & mask) == data);
+
+	return 7;
+}
+
 static struct init_tbl_entry itbl_entry[] = {
 	/* command name                       , id  , length  , offset  , mult    , command handler                 */
 	/* INIT_PROG (0x31, 15, 10, 4) removed due to no example of use */
@@ -3516,9 +3664,11 @@
 	{ "INIT_ZM_CR"                        , 0x53, init_zm_cr                      },
 	{ "INIT_ZM_CR_GROUP"                  , 0x54, init_zm_cr_group                },
 	{ "INIT_CONDITION_TIME"               , 0x56, init_condition_time             },
+	{ "INIT_LTIME"                        , 0x57, init_ltime                      },
 	{ "INIT_ZM_REG_SEQUENCE"              , 0x58, init_zm_reg_sequence            },
 	/* INIT_INDIRECT_REG (0x5A, 7, 0, 0) removed due to no example of use */
 	{ "INIT_SUB_DIRECT"                   , 0x5B, init_sub_direct                 },
+	{ "INIT_I2C_IF"                       , 0x5E, init_i2c_if                     },
 	{ "INIT_COPY_NV_REG"                  , 0x5F, init_copy_nv_reg                },
 	{ "INIT_ZM_INDEX_IO"                  , 0x62, init_zm_index_io                },
 	{ "INIT_COMPUTE_MEM"                  , 0x63, init_compute_mem                },
@@ -3552,6 +3702,7 @@
 	{ "INIT_97"                           , 0x97, init_97                         },
 	{ "INIT_AUXCH"                        , 0x98, init_auxch                      },
 	{ "INIT_ZM_AUXCH"                     , 0x99, init_zm_auxch                   },
+	{ "INIT_I2C_LONG_IF"                  , 0x9A, init_i2c_long_if                },
 	{ NULL                                , 0   , NULL                            }
 };
 
@@ -4410,7 +4561,7 @@
 					  bios->display.script_table_ptr,
 					  table[2], table[3], table[0] >= 0x21);
 	if (!otable) {
-		NV_ERROR(dev, "Couldn't find matching output script table\n");
+		NV_DEBUG_KMS(dev, "failed to match any output table\n");
 		return 1;
 	}
 
@@ -4467,7 +4618,7 @@
 		if (script)
 			script = clkcmptable(bios, script, pxclk);
 		if (!script) {
-			NV_ERROR(dev, "clock script 0 not found\n");
+			NV_DEBUG_KMS(dev, "clock script 0 not found\n");
 			return 1;
 		}
 
@@ -4826,7 +4977,7 @@
 		pll_lim->min_p = record[12];
 		pll_lim->max_p = record[13];
 		/* where did this go to?? */
-		if (limit_match == 0x00614100 || limit_match == 0x00614900)
+		if ((entry[0] & 0xf0) == 0x80)
 			pll_lim->refclk = 27000;
 		else
 			pll_lim->refclk = 100000;
@@ -5852,7 +6003,7 @@
 	entry->i2c_index = i2c;
 	entry->heads = heads;
 	entry->location = DCB_LOC_ON_CHIP;
-	/* "or" mostly unused in early gen crt modesetting, 0 is fine */
+	entry->or = 1;
 }
 
 static void fabricate_dvi_i_output(struct dcb_table *dcb, bool twoHeads)
@@ -5980,7 +6131,13 @@
 		}
 		break;
 	case OUTPUT_TMDS:
-		entry->tmdsconf.sor.link = (conf & 0x00000030) >> 4;
+		if (dcb->version >= 0x40)
+			entry->tmdsconf.sor.link = (conf & 0x00000030) >> 4;
+		else if (dcb->version >= 0x30)
+			entry->tmdsconf.slave_addr = (conf & 0x00000700) >> 8;
+		else if (dcb->version >= 0x22)
+			entry->tmdsconf.slave_addr = (conf & 0x00000070) >> 4;
+
 		break;
 	case 0xe:
 		/* weird g80 mobile type that "nv" treats as a terminator */
@@ -6270,6 +6427,19 @@
 		dcb->i2c_table = &bios->data[i2ctabptr];
 		if (dcb->version >= 0x30)
 			dcb->i2c_default_indices = dcb->i2c_table[4];
+
+		/*
+		 * Parse the "management" I2C bus, used for hardware
+		 * monitoring and some external TMDS transmitters.
+		 */
+		if (dcb->version >= 0x22) {
+			int idx = (dcb->version >= 0x40 ?
+				   dcb->i2c_default_indices & 0xf :
+				   2);
+
+			read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table,
+					   idx, &dcb->i2c[idx]);
+		}
 	}
 
 	if (entries > DCB_MAX_NUM_ENTRIES)
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h
index 024458a..fd14dfd 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.h
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.h
@@ -131,6 +131,7 @@
 		} dpconf;
 		struct {
 			struct sor_conf sor;
+			int slave_addr;
 		} tmdsconf;
 	};
 	bool i2c_upper_default;
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 3ca8343..84f8518 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -51,9 +51,6 @@
 	if (nvbo->tile)
 		nv10_mem_expire_tiling(dev, nvbo->tile, NULL);
 
-	spin_lock(&dev_priv->ttm.bo_list_lock);
-	list_del(&nvbo->head);
-	spin_unlock(&dev_priv->ttm.bo_list_lock);
 	kfree(nvbo);
 }
 
@@ -166,9 +163,6 @@
 	}
 	nvbo->channel = NULL;
 
-	spin_lock(&dev_priv->ttm.bo_list_lock);
-	list_add_tail(&nvbo->head, &dev_priv->ttm.bo_list);
-	spin_unlock(&dev_priv->ttm.bo_list_lock);
 	*pnvbo = nvbo;
 	return 0;
 }
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 734e926..b1b22ba 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -37,12 +37,6 @@
 #include "nouveau_connector.h"
 #include "nouveau_hw.h"
 
-static inline struct drm_encoder_slave_funcs *
-get_slave_funcs(struct nouveau_encoder *enc)
-{
-	return to_encoder_slave(to_drm_encoder(enc))->slave_funcs;
-}
-
 static struct nouveau_encoder *
 find_encoder_by_type(struct drm_connector *connector, int type)
 {
@@ -360,6 +354,7 @@
 {
 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
 	struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
+	struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
 	struct drm_device *dev = connector->dev;
 	int ret;
 
@@ -432,8 +427,8 @@
 	}
 
 	if (nv_encoder && nv_encoder->dcb->type == OUTPUT_TV)
-		return get_slave_funcs(nv_encoder)->
-			set_property(to_drm_encoder(nv_encoder), connector, property, value);
+		return get_slave_funcs(encoder)->set_property(
+			encoder, connector, property, value);
 
 	return -EINVAL;
 }
@@ -545,6 +540,7 @@
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
 	struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
+	struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
 	int ret = 0;
 
 	/* destroy the native mode, the attached monitor could have changed.
@@ -580,8 +576,7 @@
 	}
 
 	if (nv_encoder->dcb->type == OUTPUT_TV)
-		ret = get_slave_funcs(nv_encoder)->
-			get_modes(to_drm_encoder(nv_encoder), connector);
+		ret = get_slave_funcs(encoder)->get_modes(encoder, connector);
 
 	if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS ||
 	    nv_connector->dcb->type == DCB_CONNECTOR_eDP)
@@ -597,6 +592,7 @@
 	struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
 	struct nouveau_connector *nv_connector = nouveau_connector(connector);
 	struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
+	struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
 	unsigned min_clock = 25000, max_clock = min_clock;
 	unsigned clock = mode->clock;
 
@@ -623,8 +619,7 @@
 			max_clock = 350000;
 		break;
 	case OUTPUT_TV:
-		return get_slave_funcs(nv_encoder)->
-			mode_valid(to_drm_encoder(nv_encoder), mode);
+		return get_slave_funcs(encoder)->mode_valid(encoder, mode);
 	case OUTPUT_DP:
 		if (nv_encoder->dp.link_bw == DP_LINK_BW_2_7)
 			max_clock = nv_encoder->dp.link_nr * 270000;
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 74e6b4e..2e11fd6 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -84,16 +84,16 @@
 
 	gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle);
 	if (!gem)
-		return NULL;
+		return ERR_PTR(-ENOENT);
 
 	nouveau_fb = kzalloc(sizeof(struct nouveau_framebuffer), GFP_KERNEL);
 	if (!nouveau_fb)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
 	ret = nouveau_framebuffer_init(dev, nouveau_fb, mode_cmd, nouveau_gem_object(gem));
 	if (ret) {
 		drm_gem_object_unreference(gem);
-		return NULL;
+		return ERR_PTR(ret);
 	}
 
 	return &nouveau_fb->base;
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index 33742b1..8a1b188 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -572,47 +572,64 @@
 	return ret ? ret : (stat & NV50_AUXCH_STAT_REPLY);
 }
 
-int
-nouveau_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
-		      uint8_t write_byte, uint8_t *read_byte)
+static int
+nouveau_dp_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 {
-	struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
-	struct nouveau_i2c_chan *auxch = (struct nouveau_i2c_chan *)adapter;
+	struct nouveau_i2c_chan *auxch = (struct nouveau_i2c_chan *)adap;
 	struct drm_device *dev = auxch->dev;
-	int ret = 0, cmd, addr = algo_data->address;
-	uint8_t *buf;
+	struct i2c_msg *msg = msgs;
+	int ret, mcnt = num;
 
-	if (mode == MODE_I2C_READ) {
-		cmd = AUX_I2C_READ;
-		buf = read_byte;
-	} else {
-		cmd = (mode & MODE_I2C_READ) ? AUX_I2C_READ : AUX_I2C_WRITE;
-		buf = &write_byte;
-	}
+	while (mcnt--) {
+		u8 remaining = msg->len;
+		u8 *ptr = msg->buf;
 
-	if (!(mode & MODE_I2C_STOP))
-		cmd |= AUX_I2C_MOT;
+		while (remaining) {
+			u8 cnt = (remaining > 16) ? 16 : remaining;
+			u8 cmd;
 
-	if (mode & MODE_I2C_START)
-		return 1;
+			if (msg->flags & I2C_M_RD)
+				cmd = AUX_I2C_READ;
+			else
+				cmd = AUX_I2C_WRITE;
 
-	for (;;) {
-		ret = nouveau_dp_auxch(auxch, cmd, addr, buf, 1);
-		if (ret < 0)
-			return ret;
+			if (mcnt || remaining > 16)
+				cmd |= AUX_I2C_MOT;
 
-		switch (ret & NV50_AUXCH_STAT_REPLY_I2C) {
-		case NV50_AUXCH_STAT_REPLY_I2C_ACK:
-			return 1;
-		case NV50_AUXCH_STAT_REPLY_I2C_NACK:
-			return -EREMOTEIO;
-		case NV50_AUXCH_STAT_REPLY_I2C_DEFER:
-			udelay(100);
-			break;
-		default:
-			NV_ERROR(dev, "invalid auxch status: 0x%08x\n", ret);
-			return -EREMOTEIO;
+			ret = nouveau_dp_auxch(auxch, cmd, msg->addr, ptr, cnt);
+			if (ret < 0)
+				return ret;
+
+			switch (ret & NV50_AUXCH_STAT_REPLY_I2C) {
+			case NV50_AUXCH_STAT_REPLY_I2C_ACK:
+				break;
+			case NV50_AUXCH_STAT_REPLY_I2C_NACK:
+				return -EREMOTEIO;
+			case NV50_AUXCH_STAT_REPLY_I2C_DEFER:
+				udelay(100);
+				continue;
+			default:
+				NV_ERROR(dev, "bad auxch reply: 0x%08x\n", ret);
+				return -EREMOTEIO;
+			}
+
+			ptr += cnt;
+			remaining -= cnt;
 		}
+
+		msg++;
 	}
+
+	return num;
 }
 
+static u32
+nouveau_dp_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+const struct i2c_algorithm nouveau_dp_i2c_algo = {
+	.master_xfer = nouveau_dp_i2c_xfer,
+	.functionality = nouveau_dp_i2c_func
+};
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index e15db15..e424bf7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -410,7 +410,7 @@
 
 struct nv04_crtc_reg {
 	unsigned char MiscOutReg;     /* */
-	uint8_t CRTC[0x9f];
+	uint8_t CRTC[0xa0];
 	uint8_t CR58[0x10];
 	uint8_t Sequencer[5];
 	uint8_t Graphics[9];
@@ -509,6 +509,7 @@
 	NV_30      = 0x30,
 	NV_40      = 0x40,
 	NV_50      = 0x50,
+	NV_C0      = 0xc0,
 };
 
 struct drm_nouveau_private {
@@ -536,8 +537,6 @@
 		struct drm_global_reference mem_global_ref;
 		struct ttm_bo_global_ref bo_global_ref;
 		struct ttm_bo_device bdev;
-		spinlock_t bo_list_lock;
-		struct list_head bo_list;
 		atomic_t validate_sequence;
 	} ttm;
 
@@ -931,6 +930,10 @@
 extern int  nv50_fb_init(struct drm_device *);
 extern void nv50_fb_takedown(struct drm_device *);
 
+/* nvc0_fb.c */
+extern int  nvc0_fb_init(struct drm_device *);
+extern void nvc0_fb_takedown(struct drm_device *);
+
 /* nv04_fifo.c */
 extern int  nv04_fifo_init(struct drm_device *);
 extern void nv04_fifo_disable(struct drm_device *);
@@ -968,6 +971,20 @@
 extern int  nv50_fifo_load_context(struct nouveau_channel *);
 extern int  nv50_fifo_unload_context(struct drm_device *);
 
+/* nvc0_fifo.c */
+extern int  nvc0_fifo_init(struct drm_device *);
+extern void nvc0_fifo_takedown(struct drm_device *);
+extern void nvc0_fifo_disable(struct drm_device *);
+extern void nvc0_fifo_enable(struct drm_device *);
+extern bool nvc0_fifo_reassign(struct drm_device *, bool);
+extern bool nvc0_fifo_cache_flush(struct drm_device *);
+extern bool nvc0_fifo_cache_pull(struct drm_device *, bool);
+extern int  nvc0_fifo_channel_id(struct drm_device *);
+extern int  nvc0_fifo_create_context(struct nouveau_channel *);
+extern void nvc0_fifo_destroy_context(struct nouveau_channel *);
+extern int  nvc0_fifo_load_context(struct nouveau_channel *);
+extern int  nvc0_fifo_unload_context(struct drm_device *);
+
 /* nv04_graph.c */
 extern struct nouveau_pgraph_object_class nv04_graph_grclass[];
 extern int  nv04_graph_init(struct drm_device *);
@@ -1032,6 +1049,16 @@
 extern void nv50_graph_context_switch(struct drm_device *);
 extern int  nv50_grctx_init(struct nouveau_grctx *);
 
+/* nvc0_graph.c */
+extern int  nvc0_graph_init(struct drm_device *);
+extern void nvc0_graph_takedown(struct drm_device *);
+extern void nvc0_graph_fifo_access(struct drm_device *, bool);
+extern struct nouveau_channel *nvc0_graph_channel(struct drm_device *);
+extern int  nvc0_graph_create_context(struct nouveau_channel *);
+extern void nvc0_graph_destroy_context(struct nouveau_channel *);
+extern int  nvc0_graph_load_context(struct nouveau_channel *);
+extern int  nvc0_graph_unload_context(struct drm_device *);
+
 /* nv04_instmem.c */
 extern int  nv04_instmem_init(struct drm_device *);
 extern void nv04_instmem_takedown(struct drm_device *);
@@ -1058,6 +1085,18 @@
 extern void nv84_instmem_flush(struct drm_device *);
 extern void nv50_vm_flush(struct drm_device *, int engine);
 
+/* nvc0_instmem.c */
+extern int  nvc0_instmem_init(struct drm_device *);
+extern void nvc0_instmem_takedown(struct drm_device *);
+extern int  nvc0_instmem_suspend(struct drm_device *);
+extern void nvc0_instmem_resume(struct drm_device *);
+extern int  nvc0_instmem_populate(struct drm_device *, struct nouveau_gpuobj *,
+				  uint32_t *size);
+extern void nvc0_instmem_clear(struct drm_device *, struct nouveau_gpuobj *);
+extern int  nvc0_instmem_bind(struct drm_device *, struct nouveau_gpuobj *);
+extern int  nvc0_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *);
+extern void nvc0_instmem_flush(struct drm_device *);
+
 /* nv04_mc.c */
 extern int  nv04_mc_init(struct drm_device *);
 extern void nv04_mc_takedown(struct drm_device *);
diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h
index a1a0d48..7c82d68 100644
--- a/drivers/gpu/drm/nouveau/nouveau_encoder.h
+++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h
@@ -71,6 +71,12 @@
 	return &enc->base.base;
 }
 
+static inline struct drm_encoder_slave_funcs *
+get_slave_funcs(struct drm_encoder *enc)
+{
+	return to_encoder_slave(enc)->slave_funcs;
+}
+
 struct nouveau_connector *
 nouveau_encoder_connector_get(struct nouveau_encoder *encoder);
 int nv50_sor_create(struct drm_connector *, struct dcb_entry *);
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 099f637..dbd30b2 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -281,6 +281,8 @@
 
 	if (dev_priv->channel && !nouveau_nofbaccel) {
 		switch (dev_priv->card_type) {
+		case NV_C0:
+			break;
 		case NV_50:
 			nv50_fbcon_accel_init(info);
 			info->fbops = &nv50_fbcon_ops;
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index 547f2c2..0f417ac 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -284,7 +284,7 @@
 		if (!gem) {
 			NV_ERROR(dev, "Unknown handle 0x%08x\n", b->handle);
 			validate_fini(op, NULL);
-			return -EINVAL;
+			return -ENOENT;
 		}
 		nvbo = gem->driver_private;
 
@@ -759,7 +759,7 @@
 
 	gem = drm_gem_object_lookup(dev, file_priv, req->handle);
 	if (!gem)
-		return ret;
+		return -ENOENT;
 	nvbo = nouveau_gem_object(gem);
 
 	if (nvbo->cpu_filp) {
@@ -797,7 +797,7 @@
 
 	gem = drm_gem_object_lookup(dev, file_priv, req->handle);
 	if (!gem)
-		return ret;
+		return -ENOENT;
 	nvbo = nouveau_gem_object(gem);
 
 	if (nvbo->cpu_filp != file_priv)
@@ -822,7 +822,7 @@
 
 	gem = drm_gem_object_lookup(dev, file_priv, req->handle);
 	if (!gem)
-		return -EINVAL;
+		return -ENOENT;
 
 	ret = nouveau_gem_info(gem, req);
 	drm_gem_object_unreference_unlocked(gem);
diff --git a/drivers/gpu/drm/nouveau/nouveau_hw.c b/drivers/gpu/drm/nouveau/nouveau_hw.c
index 7855b35..7b61368 100644
--- a/drivers/gpu/drm/nouveau/nouveau_hw.c
+++ b/drivers/gpu/drm/nouveau/nouveau_hw.c
@@ -865,8 +865,12 @@
 	rd_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX);
 	rd_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX);
 	rd_cio_state(dev, head, regp, NV_CIO_CRE_21);
-	if (dev_priv->card_type >= NV_30)
+
+	if (dev_priv->card_type >= NV_30) {
 		rd_cio_state(dev, head, regp, NV_CIO_CRE_47);
+		rd_cio_state(dev, head, regp, 0x9f);
+	}
+
 	rd_cio_state(dev, head, regp, NV_CIO_CRE_49);
 	rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX);
 	rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR1_INDEX);
@@ -971,8 +975,11 @@
 	wr_cio_state(dev, head, regp, NV_CIO_CRE_ENH_INDEX);
 	wr_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX);
 	wr_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX);
-	if (dev_priv->card_type >= NV_30)
+
+	if (dev_priv->card_type >= NV_30) {
 		wr_cio_state(dev, head, regp, NV_CIO_CRE_47);
+		wr_cio_state(dev, head, regp, 0x9f);
+	}
 
 	wr_cio_state(dev, head, regp, NV_CIO_CRE_49);
 	wr_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX);
diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c
index cb0cb34..0bd407c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_i2c.c
+++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c
@@ -163,7 +163,7 @@
 	if (entry->chan)
 		return -EEXIST;
 
-	if (dev_priv->card_type == NV_50 && entry->read >= NV50_I2C_PORTS) {
+	if (dev_priv->card_type == NV_C0 && entry->read >= NV50_I2C_PORTS) {
 		NV_ERROR(dev, "unknown i2c port %d\n", entry->read);
 		return -EINVAL;
 	}
@@ -174,26 +174,26 @@
 
 	switch (entry->port_type) {
 	case 0:
-		i2c->algo.bit.setsda = nv04_i2c_setsda;
-		i2c->algo.bit.setscl = nv04_i2c_setscl;
-		i2c->algo.bit.getsda = nv04_i2c_getsda;
-		i2c->algo.bit.getscl = nv04_i2c_getscl;
+		i2c->bit.setsda = nv04_i2c_setsda;
+		i2c->bit.setscl = nv04_i2c_setscl;
+		i2c->bit.getsda = nv04_i2c_getsda;
+		i2c->bit.getscl = nv04_i2c_getscl;
 		i2c->rd = entry->read;
 		i2c->wr = entry->write;
 		break;
 	case 4:
-		i2c->algo.bit.setsda = nv4e_i2c_setsda;
-		i2c->algo.bit.setscl = nv4e_i2c_setscl;
-		i2c->algo.bit.getsda = nv4e_i2c_getsda;
-		i2c->algo.bit.getscl = nv4e_i2c_getscl;
+		i2c->bit.setsda = nv4e_i2c_setsda;
+		i2c->bit.setscl = nv4e_i2c_setscl;
+		i2c->bit.getsda = nv4e_i2c_getsda;
+		i2c->bit.getscl = nv4e_i2c_getscl;
 		i2c->rd = 0x600800 + entry->read;
 		i2c->wr = 0x600800 + entry->write;
 		break;
 	case 5:
-		i2c->algo.bit.setsda = nv50_i2c_setsda;
-		i2c->algo.bit.setscl = nv50_i2c_setscl;
-		i2c->algo.bit.getsda = nv50_i2c_getsda;
-		i2c->algo.bit.getscl = nv50_i2c_getscl;
+		i2c->bit.setsda = nv50_i2c_setsda;
+		i2c->bit.setscl = nv50_i2c_setscl;
+		i2c->bit.getsda = nv50_i2c_getsda;
+		i2c->bit.getscl = nv50_i2c_getscl;
 		i2c->rd = nv50_i2c_port[entry->read];
 		i2c->wr = i2c->rd;
 		break;
@@ -216,17 +216,14 @@
 	i2c_set_adapdata(&i2c->adapter, i2c);
 
 	if (entry->port_type < 6) {
-		i2c->adapter.algo_data = &i2c->algo.bit;
-		i2c->algo.bit.udelay = 40;
-		i2c->algo.bit.timeout = usecs_to_jiffies(5000);
-		i2c->algo.bit.data = i2c;
+		i2c->adapter.algo_data = &i2c->bit;
+		i2c->bit.udelay = 40;
+		i2c->bit.timeout = usecs_to_jiffies(5000);
+		i2c->bit.data = i2c;
 		ret = i2c_bit_add_bus(&i2c->adapter);
 	} else {
-		i2c->adapter.algo_data = &i2c->algo.dp;
-		i2c->algo.dp.running = false;
-		i2c->algo.dp.address = 0;
-		i2c->algo.dp.aux_ch = nouveau_dp_i2c_aux_ch;
-		ret = i2c_dp_aux_add_bus(&i2c->adapter);
+		i2c->adapter.algo = &nouveau_dp_i2c_algo;
+		ret = i2c_add_adapter(&i2c->adapter);
 	}
 
 	if (ret) {
diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.h b/drivers/gpu/drm/nouveau/nouveau_i2c.h
index 6dd2f87..f71cb32 100644
--- a/drivers/gpu/drm/nouveau/nouveau_i2c.h
+++ b/drivers/gpu/drm/nouveau/nouveau_i2c.h
@@ -33,10 +33,7 @@
 struct nouveau_i2c_chan {
 	struct i2c_adapter adapter;
 	struct drm_device *dev;
-	union {
-		struct i2c_algo_bit_data bit;
-		struct i2c_algo_dp_aux_data dp;
-	} algo;
+	struct i2c_algo_bit_data bit;
 	unsigned rd;
 	unsigned wr;
 	unsigned data;
@@ -49,7 +46,6 @@
 int nouveau_i2c_identify(struct drm_device *dev, const char *what,
 			 struct i2c_board_info *info, int index);
 
-int nouveau_dp_i2c_aux_ch(struct i2c_adapter *, int mode, uint8_t write_byte,
-			  uint8_t *read_byte);
+extern const struct i2c_algorithm nouveau_dp_i2c_algo;
 
 #endif /* __NOUVEAU_I2C_H__ */
diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c
index 53360f1..794b0ee 100644
--- a/drivers/gpu/drm/nouveau/nouveau_irq.c
+++ b/drivers/gpu/drm/nouveau/nouveau_irq.c
@@ -49,7 +49,7 @@
 	/* Master disable */
 	nv_wr32(dev, NV03_PMC_INTR_EN_0, 0);
 
-	if (dev_priv->card_type == NV_50) {
+	if (dev_priv->card_type >= NV_50) {
 		INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh);
 		INIT_WORK(&dev_priv->hpd_work, nv50_display_irq_hotplug_bh);
 		INIT_LIST_HEAD(&dev_priv->vbl_waiting);
@@ -586,11 +586,11 @@
 		}
 
 		if (status & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
-			nouveau_pgraph_intr_context_switch(dev);
-
 			status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
 			nv_wr32(dev, NV03_PGRAPH_INTR,
 				 NV_PGRAPH_INTR_CONTEXT_SWITCH);
+
+			nouveau_pgraph_intr_context_switch(dev);
 		}
 
 		if (status) {
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
index a9f36ab..9689d414 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
@@ -320,7 +320,8 @@
 	if (dev_priv->card_type < NV_50) {
 		dev_priv->vram_size  = nv_rd32(dev, NV04_PFB_FIFO_DATA);
 		dev_priv->vram_size &= NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK;
-	} else {
+	} else
+	if (dev_priv->card_type < NV_C0) {
 		dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA);
 		dev_priv->vram_size |= (dev_priv->vram_size & 0xff) << 32;
 		dev_priv->vram_size &= 0xffffffff00ll;
@@ -328,6 +329,9 @@
 			dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10);
 			dev_priv->vram_sys_base <<= 12;
 		}
+	} else {
+		dev_priv->vram_size  = nv_rd32(dev, 0x10f20c) << 20;
+		dev_priv->vram_size *= nv_rd32(dev, 0x121c74);
 	}
 
 	NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20));
@@ -351,7 +355,7 @@
 	/* First of all, disable fast writes, otherwise if it's
 	 * already enabled in the AGP bridge and we disable the card's
 	 * AGP controller we might be locking ourselves out of it. */
-	if (dev->agp->acquired) {
+	if (nv_rd32(dev, NV04_PBUS_PCI_NV_19) & PCI_AGP_COMMAND_FW) {
 		struct drm_agp_info info;
 		struct drm_agp_mode mode;
 
@@ -359,7 +363,7 @@
 		if (ret)
 			return ret;
 
-		mode.mode = info.mode & ~0x10;
+		mode.mode = info.mode & ~PCI_AGP_COMMAND_FW;
 		ret = drm_agp_enable(dev, mode);
 		if (ret)
 			return ret;
@@ -405,6 +409,8 @@
 		}
 	}
 
+	nouveau_mem_reset_agp(dev);
+
 	ret = drm_agp_info(dev, &info);
 	if (ret) {
 		NV_ERROR(dev, "Unable to get AGP info: %d\n", ret);
@@ -459,8 +465,6 @@
 		return ret;
 	}
 
-	INIT_LIST_HEAD(&dev_priv->ttm.bo_list);
-	spin_lock_init(&dev_priv->ttm.bo_list_lock);
 	spin_lock_init(&dev_priv->tile.lock);
 
 	dev_priv->fb_available_size = dev_priv->vram_size;
@@ -494,7 +498,6 @@
 	/* GART */
 #if !defined(__powerpc__) && !defined(__ia64__)
 	if (drm_device_is_agp(dev) && dev->agp && !nouveau_noagp) {
-		nouveau_mem_reset_agp(dev);
 		ret = nouveau_mem_init_agp(dev);
 		if (ret)
 			NV_ERROR(dev, "Error initialising AGP: %d\n", ret);
diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h
index 9c1056c..21a6e45 100644
--- a/drivers/gpu/drm/nouveau/nouveau_reg.h
+++ b/drivers/gpu/drm/nouveau/nouveau_reg.h
@@ -220,28 +220,21 @@
 #    define NV_PGRAPH_INTR_ERROR                              (1<<20)
 #define NV10_PGRAPH_CTX_CONTROL                            0x00400144
 #define NV10_PGRAPH_CTX_USER                               0x00400148
-#define NV10_PGRAPH_CTX_SWITCH1                            0x0040014C
-#define NV10_PGRAPH_CTX_SWITCH2                            0x00400150
-#define NV10_PGRAPH_CTX_SWITCH3                            0x00400154
-#define NV10_PGRAPH_CTX_SWITCH4                            0x00400158
-#define NV10_PGRAPH_CTX_SWITCH5                            0x0040015C
+#define NV10_PGRAPH_CTX_SWITCH(i)                         (0x0040014C + 0x4*(i))
 #define NV04_PGRAPH_CTX_SWITCH1                            0x00400160
-#define NV10_PGRAPH_CTX_CACHE1                             0x00400160
+#define NV10_PGRAPH_CTX_CACHE(i, j)                       (0x00400160	\
+							   + 0x4*(i) + 0x20*(j))
 #define NV04_PGRAPH_CTX_SWITCH2                            0x00400164
 #define NV04_PGRAPH_CTX_SWITCH3                            0x00400168
 #define NV04_PGRAPH_CTX_SWITCH4                            0x0040016C
 #define NV04_PGRAPH_CTX_CONTROL                            0x00400170
 #define NV04_PGRAPH_CTX_USER                               0x00400174
 #define NV04_PGRAPH_CTX_CACHE1                             0x00400180
-#define NV10_PGRAPH_CTX_CACHE2                             0x00400180
 #define NV03_PGRAPH_CTX_CONTROL                            0x00400190
 #define NV03_PGRAPH_CTX_USER                               0x00400194
 #define NV04_PGRAPH_CTX_CACHE2                             0x004001A0
-#define NV10_PGRAPH_CTX_CACHE3                             0x004001A0
 #define NV04_PGRAPH_CTX_CACHE3                             0x004001C0
-#define NV10_PGRAPH_CTX_CACHE4                             0x004001C0
 #define NV04_PGRAPH_CTX_CACHE4                             0x004001E0
-#define NV10_PGRAPH_CTX_CACHE5                             0x004001E0
 #define NV40_PGRAPH_CTXCTL_0304                            0x00400304
 #define NV40_PGRAPH_CTXCTL_0304_XFER_CTX                   0x00000001
 #define NV40_PGRAPH_CTXCTL_UCODE_STAT                      0x00400308
@@ -356,9 +349,12 @@
 #define NV04_PGRAPH_FFINTFC_ST2                            0x00400754
 #define NV10_PGRAPH_RDI_DATA                               0x00400754
 #define NV04_PGRAPH_DMA_PITCH                              0x00400760
-#define NV10_PGRAPH_FFINTFC_ST2                            0x00400764
+#define NV10_PGRAPH_FFINTFC_FIFO_PTR                       0x00400760
 #define NV04_PGRAPH_DVD_COLORFMT                           0x00400764
+#define NV10_PGRAPH_FFINTFC_ST2                            0x00400764
 #define NV04_PGRAPH_SCALED_FORMAT                          0x00400768
+#define NV10_PGRAPH_FFINTFC_ST2_DL                         0x00400768
+#define NV10_PGRAPH_FFINTFC_ST2_DH                         0x0040076c
 #define NV10_PGRAPH_DMA_PITCH                              0x00400770
 #define NV10_PGRAPH_DVD_COLORFMT                           0x00400774
 #define NV10_PGRAPH_SCALED_FORMAT                          0x00400778
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index ee3729e..989322b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -359,6 +359,54 @@
 		engine->gpio.set		= nv50_gpio_set;
 		engine->gpio.irq_enable		= nv50_gpio_irq_enable;
 		break;
+	case 0xC0:
+		engine->instmem.init		= nvc0_instmem_init;
+		engine->instmem.takedown	= nvc0_instmem_takedown;
+		engine->instmem.suspend		= nvc0_instmem_suspend;
+		engine->instmem.resume		= nvc0_instmem_resume;
+		engine->instmem.populate	= nvc0_instmem_populate;
+		engine->instmem.clear		= nvc0_instmem_clear;
+		engine->instmem.bind		= nvc0_instmem_bind;
+		engine->instmem.unbind		= nvc0_instmem_unbind;
+		engine->instmem.flush		= nvc0_instmem_flush;
+		engine->mc.init			= nv50_mc_init;
+		engine->mc.takedown		= nv50_mc_takedown;
+		engine->timer.init		= nv04_timer_init;
+		engine->timer.read		= nv04_timer_read;
+		engine->timer.takedown		= nv04_timer_takedown;
+		engine->fb.init			= nvc0_fb_init;
+		engine->fb.takedown		= nvc0_fb_takedown;
+		engine->graph.grclass		= NULL;  //nvc0_graph_grclass;
+		engine->graph.init		= nvc0_graph_init;
+		engine->graph.takedown		= nvc0_graph_takedown;
+		engine->graph.fifo_access	= nvc0_graph_fifo_access;
+		engine->graph.channel		= nvc0_graph_channel;
+		engine->graph.create_context	= nvc0_graph_create_context;
+		engine->graph.destroy_context	= nvc0_graph_destroy_context;
+		engine->graph.load_context	= nvc0_graph_load_context;
+		engine->graph.unload_context	= nvc0_graph_unload_context;
+		engine->fifo.channels		= 128;
+		engine->fifo.init		= nvc0_fifo_init;
+		engine->fifo.takedown		= nvc0_fifo_takedown;
+		engine->fifo.disable		= nvc0_fifo_disable;
+		engine->fifo.enable		= nvc0_fifo_enable;
+		engine->fifo.reassign		= nvc0_fifo_reassign;
+		engine->fifo.channel_id		= nvc0_fifo_channel_id;
+		engine->fifo.create_context	= nvc0_fifo_create_context;
+		engine->fifo.destroy_context	= nvc0_fifo_destroy_context;
+		engine->fifo.load_context	= nvc0_fifo_load_context;
+		engine->fifo.unload_context	= nvc0_fifo_unload_context;
+		engine->display.early_init	= nv50_display_early_init;
+		engine->display.late_takedown	= nv50_display_late_takedown;
+		engine->display.create		= nv50_display_create;
+		engine->display.init		= nv50_display_init;
+		engine->display.destroy		= nv50_display_destroy;
+		engine->gpio.init		= nv50_gpio_init;
+		engine->gpio.takedown		= nouveau_stub_takedown;
+		engine->gpio.get		= nv50_gpio_get;
+		engine->gpio.set		= nv50_gpio_set;
+		engine->gpio.irq_enable		= nv50_gpio_irq_enable;
+		break;
 	default:
 		NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset);
 		return 1;
@@ -739,8 +787,10 @@
 	int ret;
 
 	dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL);
-	if (!dev_priv)
-		return -ENOMEM;
+	if (!dev_priv) {
+		ret = -ENOMEM;
+		goto err_out;
+	}
 	dev->dev_private = dev_priv;
 	dev_priv->dev = dev;
 
@@ -750,8 +800,10 @@
 		 dev->pci_vendor, dev->pci_device, dev->pdev->class);
 
 	dev_priv->wq = create_workqueue("nouveau");
-	if (!dev_priv->wq)
-		return -EINVAL;
+	if (!dev_priv->wq) {
+		ret = -EINVAL;
+		goto err_priv;
+	}
 
 	/* resource 0 is mmio regs */
 	/* resource 1 is linear FB */
@@ -764,7 +816,8 @@
 	if (!dev_priv->mmio) {
 		NV_ERROR(dev, "Unable to initialize the mmio mapping. "
 			 "Please report your setup to " DRIVER_EMAIL "\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err_wq;
 	}
 	NV_DEBUG(dev, "regs mapped ok at 0x%llx\n",
 					(unsigned long long)mmio_start_offs);
@@ -810,9 +863,13 @@
 	case 0xa0:
 		dev_priv->card_type = NV_50;
 		break;
+	case 0xc0:
+		dev_priv->card_type = NV_C0;
+		break;
 	default:
 		NV_INFO(dev, "Unsupported chipset 0x%08x\n", reg0);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err_mmio;
 	}
 
 	NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n",
@@ -820,7 +877,7 @@
 
 	ret = nouveau_remove_conflicting_drivers(dev);
 	if (ret)
-		return ret;
+		goto err_mmio;
 
 	/* Map PRAMIN BAR, or on older cards, the aperture withing BAR0 */
 	if (dev_priv->card_type >= NV_40) {
@@ -834,7 +891,8 @@
 				dev_priv->ramin_size);
 		if (!dev_priv->ramin) {
 			NV_ERROR(dev, "Failed to PRAMIN BAR");
-			return -ENOMEM;
+			ret = -ENOMEM;
+			goto err_mmio;
 		}
 	} else {
 		dev_priv->ramin_size = 1 * 1024 * 1024;
@@ -842,7 +900,8 @@
 					  dev_priv->ramin_size);
 		if (!dev_priv->ramin) {
 			NV_ERROR(dev, "Failed to map BAR0 PRAMIN.\n");
-			return -ENOMEM;
+			ret = -ENOMEM;
+			goto err_mmio;
 		}
 	}
 
@@ -857,9 +916,21 @@
 	/* For kernel modesetting, init card now and bring up fbcon */
 	ret = nouveau_card_init(dev);
 	if (ret)
-		return ret;
+		goto err_ramin;
 
 	return 0;
+
+err_ramin:
+	iounmap(dev_priv->ramin);
+err_mmio:
+	iounmap(dev_priv->mmio);
+err_wq:
+	destroy_workqueue(dev_priv->wq);
+err_priv:
+	kfree(dev_priv);
+	dev->dev_private = NULL;
+err_out:
+	return ret;
 }
 
 void nouveau_lastclose(struct drm_device *dev)
diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c
index 1c20c08..497df87 100644
--- a/drivers/gpu/drm/nouveau/nv04_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv04_crtc.c
@@ -542,6 +542,9 @@
 	 * 1 << 30 on 0x60.830), for no apparent reason */
 	regp->CRTC[NV_CIO_CRE_59] = off_chip_digital;
 
+	if (dev_priv->card_type >= NV_30)
+		regp->CRTC[0x9f] = off_chip_digital ? 0x11 : 0x1;
+
 	regp->crtc_830 = mode->crtc_vdisplay - 3;
 	regp->crtc_834 = mode->crtc_vdisplay - 1;
 
@@ -739,15 +742,13 @@
 }
 
 static void
-nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t size)
+nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t start,
+		  uint32_t size)
 {
+	int end = (start + size > 256) ? 256 : start + size, i;
 	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-	int i;
 
-	if (size != 256)
-		return;
-
-	for (i = 0; i < 256; i++) {
+	for (i = start; i < end; i++) {
 		nv_crtc->lut.r[i] = r[i];
 		nv_crtc->lut.g[i] = g[i];
 		nv_crtc->lut.b[i] = b[i];
@@ -914,7 +915,7 @@
 
 	gem = drm_gem_object_lookup(dev, file_priv, buffer_handle);
 	if (!gem)
-		return -EINVAL;
+		return -ENOENT;
 	cursor = nouveau_gem_object(gem);
 
 	ret = nouveau_bo_map(cursor);
diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c
index 3311f3a..a5dcf768 100644
--- a/drivers/gpu/drm/nouveau/nv04_dfp.c
+++ b/drivers/gpu/drm/nouveau/nv04_dfp.c
@@ -34,6 +34,8 @@
 #include "nouveau_hw.h"
 #include "nvreg.h"
 
+#include "i2c/sil164.h"
+
 #define FP_TG_CONTROL_ON  (NV_PRAMDAC_FP_TG_CONTROL_DISPEN_POS |	\
 			   NV_PRAMDAC_FP_TG_CONTROL_HSYNC_POS |		\
 			   NV_PRAMDAC_FP_TG_CONTROL_VSYNC_POS)
@@ -144,6 +146,36 @@
 	}
 }
 
+static struct drm_encoder *get_tmds_slave(struct drm_encoder *encoder)
+{
+	struct drm_device *dev = encoder->dev;
+	struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
+	struct drm_encoder *slave;
+
+	if (dcb->type != OUTPUT_TMDS || dcb->location == DCB_LOC_ON_CHIP)
+		return NULL;
+
+	/* Some BIOSes (e.g. the one in a Quadro FX1000) report several
+	 * TMDS transmitters at the same I2C address, in the same I2C
+	 * bus. This can still work because in that case one of them is
+	 * always hard-wired to a reasonable configuration using straps,
+	 * and the other one needs to be programmed.
+	 *
+	 * I don't think there's a way to know which is which, even the
+	 * blob programs the one exposed via I2C for *both* heads, so
+	 * let's do the same.
+	 */
+	list_for_each_entry(slave, &dev->mode_config.encoder_list, head) {
+		struct dcb_entry *slave_dcb = nouveau_encoder(slave)->dcb;
+
+		if (slave_dcb->type == OUTPUT_TMDS && get_slave_funcs(slave) &&
+		    slave_dcb->tmdsconf.slave_addr == dcb->tmdsconf.slave_addr)
+			return slave;
+	}
+
+	return NULL;
+}
+
 static bool nv04_dfp_mode_fixup(struct drm_encoder *encoder,
 				struct drm_display_mode *mode,
 				struct drm_display_mode *adjusted_mode)
@@ -429,6 +461,11 @@
 	else
 		NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0x00100000);
 
+	/* Init external transmitters */
+	if (get_tmds_slave(encoder))
+		get_slave_funcs(get_tmds_slave(encoder))->mode_set(
+			encoder, &nv_encoder->mode, &nv_encoder->mode);
+
 	helper->dpms(encoder, DRM_MODE_DPMS_ON);
 
 	NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n",
@@ -550,10 +587,42 @@
 
 	NV_DEBUG_KMS(encoder->dev, "\n");
 
+	if (get_slave_funcs(encoder))
+		get_slave_funcs(encoder)->destroy(encoder);
+
 	drm_encoder_cleanup(encoder);
 	kfree(nv_encoder);
 }
 
+static void nv04_tmds_slave_init(struct drm_encoder *encoder)
+{
+	struct drm_device *dev = encoder->dev;
+	struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
+	struct nouveau_i2c_chan *i2c = nouveau_i2c_find(dev, 2);
+	struct i2c_board_info info[] = {
+		{
+			.type = "sil164",
+			.addr = (dcb->tmdsconf.slave_addr == 0x7 ? 0x3a : 0x38),
+			.platform_data = &(struct sil164_encoder_params) {
+				SIL164_INPUT_EDGE_RISING
+			}
+		},
+		{ }
+	};
+	int type;
+
+	if (!nv_gf4_disp_arch(dev) || !i2c ||
+	    get_tmds_slave(encoder))
+		return;
+
+	type = nouveau_i2c_identify(dev, "TMDS transmitter", info, 2);
+	if (type < 0)
+		return;
+
+	drm_i2c_encoder_init(dev, to_encoder_slave(encoder),
+			     &i2c->adapter, &info[type]);
+}
+
 static const struct drm_encoder_helper_funcs nv04_lvds_helper_funcs = {
 	.dpms = nv04_lvds_dpms,
 	.save = nv04_dfp_save,
@@ -616,6 +685,10 @@
 	encoder->possible_crtcs = entry->heads;
 	encoder->possible_clones = 0;
 
+	if (entry->type == OUTPUT_TMDS &&
+	    entry->location != DCB_LOC_ON_CHIP)
+		nv04_tmds_slave_init(encoder);
+
 	drm_mode_connector_attach_encoder(connector, encoder);
 	return 0;
 }
diff --git a/drivers/gpu/drm/nouveau/nv04_tv.c b/drivers/gpu/drm/nouveau/nv04_tv.c
index 94e299c..0b5d012 100644
--- a/drivers/gpu/drm/nouveau/nv04_tv.c
+++ b/drivers/gpu/drm/nouveau/nv04_tv.c
@@ -89,7 +89,7 @@
 
 	NVWriteRAMDAC(dev, 0, NV_PRAMDAC_PLL_COEFF_SELECT, state->pllsel);
 
-	to_encoder_slave(encoder)->slave_funcs->dpms(encoder, mode);
+	get_slave_funcs(encoder)->dpms(encoder, mode);
 }
 
 static void nv04_tv_bind(struct drm_device *dev, int head, bool bind)
@@ -152,7 +152,7 @@
 	regp->tv_vskew = 1;
 	regp->tv_vsync_delay = 1;
 
-	to_encoder_slave(encoder)->slave_funcs->mode_set(encoder, mode, adjusted_mode);
+	get_slave_funcs(encoder)->mode_set(encoder, mode, adjusted_mode);
 }
 
 static void nv04_tv_commit(struct drm_encoder *encoder)
@@ -171,8 +171,7 @@
 
 static void nv04_tv_destroy(struct drm_encoder *encoder)
 {
-	to_encoder_slave(encoder)->slave_funcs->destroy(encoder);
-
+	get_slave_funcs(encoder)->destroy(encoder);
 	drm_encoder_cleanup(encoder);
 
 	kfree(encoder->helper_private);
@@ -229,7 +228,7 @@
 		goto fail_cleanup;
 
 	/* Fill the function pointers */
-	sfuncs = to_encoder_slave(encoder)->slave_funcs;
+	sfuncs = get_slave_funcs(encoder);
 
 	*hfuncs = (struct drm_encoder_helper_funcs) {
 		.dpms = nv04_tv_dpms,
@@ -243,7 +242,6 @@
 	};
 
 	/* Attach it to the specified connector. */
-	sfuncs->set_config(encoder, nv04_tv_encoder_info[type].platform_data);
 	sfuncs->create_resources(encoder, connector);
 	drm_mode_connector_attach_encoder(connector, encoder);
 
diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c
index fcf2cdd..b2f6a57 100644
--- a/drivers/gpu/drm/nouveau/nv10_graph.c
+++ b/drivers/gpu/drm/nouveau/nv10_graph.c
@@ -43,51 +43,51 @@
 };
 
 static int nv10_graph_ctx_regs[] = {
-	NV10_PGRAPH_CTX_SWITCH1,
-	NV10_PGRAPH_CTX_SWITCH2,
-	NV10_PGRAPH_CTX_SWITCH3,
-	NV10_PGRAPH_CTX_SWITCH4,
-	NV10_PGRAPH_CTX_SWITCH5,
-	NV10_PGRAPH_CTX_CACHE1,	/* 8 values from 0x400160 to 0x40017c */
-	NV10_PGRAPH_CTX_CACHE2,	/* 8 values from 0x400180 to 0x40019c */
-	NV10_PGRAPH_CTX_CACHE3,	/* 8 values from 0x4001a0 to 0x4001bc */
-	NV10_PGRAPH_CTX_CACHE4,	/* 8 values from 0x4001c0 to 0x4001dc */
-	NV10_PGRAPH_CTX_CACHE5,	/* 8 values from 0x4001e0 to 0x4001fc */
-	0x00400164,
-	0x00400184,
-	0x004001a4,
-	0x004001c4,
-	0x004001e4,
-	0x00400168,
-	0x00400188,
-	0x004001a8,
-	0x004001c8,
-	0x004001e8,
-	0x0040016c,
-	0x0040018c,
-	0x004001ac,
-	0x004001cc,
-	0x004001ec,
-	0x00400170,
-	0x00400190,
-	0x004001b0,
-	0x004001d0,
-	0x004001f0,
-	0x00400174,
-	0x00400194,
-	0x004001b4,
-	0x004001d4,
-	0x004001f4,
-	0x00400178,
-	0x00400198,
-	0x004001b8,
-	0x004001d8,
-	0x004001f8,
-	0x0040017c,
-	0x0040019c,
-	0x004001bc,
-	0x004001dc,
-	0x004001fc,
+	NV10_PGRAPH_CTX_SWITCH(0),
+	NV10_PGRAPH_CTX_SWITCH(1),
+	NV10_PGRAPH_CTX_SWITCH(2),
+	NV10_PGRAPH_CTX_SWITCH(3),
+	NV10_PGRAPH_CTX_SWITCH(4),
+	NV10_PGRAPH_CTX_CACHE(0, 0),
+	NV10_PGRAPH_CTX_CACHE(0, 1),
+	NV10_PGRAPH_CTX_CACHE(0, 2),
+	NV10_PGRAPH_CTX_CACHE(0, 3),
+	NV10_PGRAPH_CTX_CACHE(0, 4),
+	NV10_PGRAPH_CTX_CACHE(1, 0),
+	NV10_PGRAPH_CTX_CACHE(1, 1),
+	NV10_PGRAPH_CTX_CACHE(1, 2),
+	NV10_PGRAPH_CTX_CACHE(1, 3),
+	NV10_PGRAPH_CTX_CACHE(1, 4),
+	NV10_PGRAPH_CTX_CACHE(2, 0),
+	NV10_PGRAPH_CTX_CACHE(2, 1),
+	NV10_PGRAPH_CTX_CACHE(2, 2),
+	NV10_PGRAPH_CTX_CACHE(2, 3),
+	NV10_PGRAPH_CTX_CACHE(2, 4),
+	NV10_PGRAPH_CTX_CACHE(3, 0),
+	NV10_PGRAPH_CTX_CACHE(3, 1),
+	NV10_PGRAPH_CTX_CACHE(3, 2),
+	NV10_PGRAPH_CTX_CACHE(3, 3),
+	NV10_PGRAPH_CTX_CACHE(3, 4),
+	NV10_PGRAPH_CTX_CACHE(4, 0),
+	NV10_PGRAPH_CTX_CACHE(4, 1),
+	NV10_PGRAPH_CTX_CACHE(4, 2),
+	NV10_PGRAPH_CTX_CACHE(4, 3),
+	NV10_PGRAPH_CTX_CACHE(4, 4),
+	NV10_PGRAPH_CTX_CACHE(5, 0),
+	NV10_PGRAPH_CTX_CACHE(5, 1),
+	NV10_PGRAPH_CTX_CACHE(5, 2),
+	NV10_PGRAPH_CTX_CACHE(5, 3),
+	NV10_PGRAPH_CTX_CACHE(5, 4),
+	NV10_PGRAPH_CTX_CACHE(6, 0),
+	NV10_PGRAPH_CTX_CACHE(6, 1),
+	NV10_PGRAPH_CTX_CACHE(6, 2),
+	NV10_PGRAPH_CTX_CACHE(6, 3),
+	NV10_PGRAPH_CTX_CACHE(6, 4),
+	NV10_PGRAPH_CTX_CACHE(7, 0),
+	NV10_PGRAPH_CTX_CACHE(7, 1),
+	NV10_PGRAPH_CTX_CACHE(7, 2),
+	NV10_PGRAPH_CTX_CACHE(7, 3),
+	NV10_PGRAPH_CTX_CACHE(7, 4),
 	NV10_PGRAPH_CTX_USER,
 	NV04_PGRAPH_DMA_START_0,
 	NV04_PGRAPH_DMA_START_1,
@@ -653,6 +653,78 @@
 	return -1;
 }
 
+static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
+				       uint32_t inst)
+{
+	struct drm_device *dev = chan->dev;
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+	uint32_t st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4];
+	uint32_t ctx_user, ctx_switch[5];
+	int i, subchan = -1;
+
+	/* NV10TCL_DMA_VTXBUF (method 0x18c) modifies hidden state
+	 * that cannot be restored via MMIO. Do it through the FIFO
+	 * instead.
+	 */
+
+	/* Look for a celsius object */
+	for (i = 0; i < 8; i++) {
+		int class = nv_rd32(dev, NV10_PGRAPH_CTX_CACHE(i, 0)) & 0xfff;
+
+		if (class == 0x56 || class == 0x96 || class == 0x99) {
+			subchan = i;
+			break;
+		}
+	}
+
+	if (subchan < 0 || !inst)
+		return;
+
+	/* Save the current ctx object */
+	ctx_user = nv_rd32(dev, NV10_PGRAPH_CTX_USER);
+	for (i = 0; i < 5; i++)
+		ctx_switch[i] = nv_rd32(dev, NV10_PGRAPH_CTX_SWITCH(i));
+
+	/* Save the FIFO state */
+	st2 = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2);
+	st2_dl = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2_DL);
+	st2_dh = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2_DH);
+	fifo_ptr = nv_rd32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR);
+
+	for (i = 0; i < ARRAY_SIZE(fifo); i++)
+		fifo[i] = nv_rd32(dev, 0x4007a0 + 4 * i);
+
+	/* Switch to the celsius subchannel */
+	for (i = 0; i < 5; i++)
+		nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(i),
+			nv_rd32(dev, NV10_PGRAPH_CTX_CACHE(subchan, i)));
+	nv_mask(dev, NV10_PGRAPH_CTX_USER, 0xe000, subchan << 13);
+
+	/* Inject NV10TCL_DMA_VTXBUF */
+	nv_wr32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR, 0);
+	nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2,
+		0x2c000000 | chan->id << 20 | subchan << 16 | 0x18c);
+	nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, inst);
+	nv_mask(dev, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000);
+	pgraph->fifo_access(dev, true);
+	pgraph->fifo_access(dev, false);
+
+	/* Restore the FIFO state */
+	for (i = 0; i < ARRAY_SIZE(fifo); i++)
+		nv_wr32(dev, 0x4007a0 + 4 * i, fifo[i]);
+
+	nv_wr32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR, fifo_ptr);
+	nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2, st2);
+	nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, st2_dl);
+	nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DH, st2_dh);
+
+	/* Restore the current ctx object */
+	for (i = 0; i < 5; i++)
+		nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(i), ctx_switch[i]);
+	nv_wr32(dev, NV10_PGRAPH_CTX_USER, ctx_user);
+}
+
 int nv10_graph_load_context(struct nouveau_channel *chan)
 {
 	struct drm_device *dev = chan->dev;
@@ -670,6 +742,8 @@
 	}
 
 	nv10_graph_load_pipe(chan);
+	nv10_graph_load_dma_vtxbuf(chan, (nv_rd32(dev, NV10_PGRAPH_GLOBALSTATE1)
+					  & 0xffff));
 
 	nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
 	tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER);
@@ -856,11 +930,12 @@
 	for (i = 0; i < NV10_PFB_TILE__SIZE; i++)
 		nv10_graph_set_region_tiling(dev, i, 0, 0, 0);
 
-	nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH1, 0x00000000);
-	nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH2, 0x00000000);
-	nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH3, 0x00000000);
-	nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH4, 0x00000000);
-	nv_wr32(dev, NV10_PGRAPH_STATE      , 0xFFFFFFFF);
+	nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000);
+	nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000);
+	nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000);
+	nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(3), 0x00000000);
+	nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(4), 0x00000000);
+	nv_wr32(dev, NV10_PGRAPH_STATE, 0xFFFFFFFF);
 
 	tmp  = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff;
 	tmp |= (dev_priv->engine.fifo.channels - 1) << 24;
diff --git a/drivers/gpu/drm/nouveau/nv30_fb.c b/drivers/gpu/drm/nouveau/nv30_fb.c
index 9d35c8b..4a3f2f0 100644
--- a/drivers/gpu/drm/nouveau/nv30_fb.c
+++ b/drivers/gpu/drm/nouveau/nv30_fb.c
@@ -30,15 +30,25 @@
 #include "nouveau_drm.h"
 
 static int
-calc_ref(int b, int l, int i)
+calc_bias(struct drm_device *dev, int k, int i, int j)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	int b = (dev_priv->chipset > 0x30 ?
+		 nv_rd32(dev, 0x122c + 0x10 * k + 0x4 * j) >> (4 * (i ^ 1)) :
+		 0) & 0xf;
+
+	return 2 * (b & 0x8 ? b - 0x10 : b);
+}
+
+static int
+calc_ref(struct drm_device *dev, int l, int k, int i)
 {
 	int j, x = 0;
 
 	for (j = 0; j < 4; j++) {
-		int n = (b >> (8 * j) & 0xf);
-		int m = (l >> (8 * i) & 0xff) + 2 * (n & 0x8 ? n - 0x10 : n);
+		int m = (l >> (8 * i) & 0xff) + calc_bias(dev, k, i, j);
 
-		x |= (0x80 | (m & 0x1f)) << (8 * j);
+		x |= (0x80 | clamp(m, 0, 0x1f)) << (8 * j);
 	}
 
 	return x;
@@ -63,18 +73,16 @@
 	    dev_priv->chipset == 0x35) {
 		/* Related to ROP count */
 		int n = (dev_priv->chipset == 0x31 ? 2 : 4);
-		int b = (dev_priv->chipset > 0x30 ?
-			 nv_rd32(dev, 0x122c) & 0xf : 0);
 		int l = nv_rd32(dev, 0x1003d0);
 
 		for (i = 0; i < n; i++) {
 			for (j = 0; j < 3; j++)
 				nv_wr32(dev, 0x10037c + 0xc * i + 0x4 * j,
-					calc_ref(b, l, j));
+					calc_ref(dev, l, 0, j));
 
 			for (j = 0; j < 2; j++)
 				nv_wr32(dev, 0x1003ac + 0x8 * i + 0x4 * j,
-					calc_ref(b, l, j));
+					calc_ref(dev, l, 1, j));
 		}
 	}
 
diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
index 5d11ea1..bfd4ca2 100644
--- a/drivers/gpu/drm/nouveau/nv50_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
@@ -264,11 +264,16 @@
 int
 nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
 {
-	uint32_t reg = NV50_PDISPLAY_CRTC_CLK_CTRL1(head);
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	struct pll_lims pll;
-	uint32_t reg1, reg2;
+	uint32_t reg, reg1, reg2;
 	int ret, N1, M1, N2, M2, P;
 
+	if (dev_priv->chipset < NV_C0)
+		reg = NV50_PDISPLAY_CRTC_CLK_CTRL1(head);
+	else
+		reg = 0x614140 + (head * 0x800);
+
 	ret = get_pll_limits(dev, reg, &pll);
 	if (ret)
 		return ret;
@@ -286,7 +291,8 @@
 		nv_wr32(dev, reg, 0x10000611);
 		nv_wr32(dev, reg + 4, reg1 | (M1 << 16) | N1);
 		nv_wr32(dev, reg + 8, reg2 | (P << 28) | (M2 << 16) | N2);
-	} else {
+	} else
+	if (dev_priv->chipset < NV_C0) {
 		ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P);
 		if (ret <= 0)
 			return 0;
@@ -298,6 +304,17 @@
 		nv_wr32(dev, reg, 0x50000610);
 		nv_wr32(dev, reg + 4, reg1 | (P << 16) | (M1 << 8) | N1);
 		nv_wr32(dev, reg + 8, N2);
+	} else {
+		ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P);
+		if (ret <= 0)
+			return 0;
+
+		NV_DEBUG(dev, "pclk %d out %d N %d fN 0x%04x M %d P %d\n",
+			 pclk, ret, N1, N2, M1, P);
+
+		nv_mask(dev, reg + 0x0c, 0x00000000, 0x00000100);
+		nv_wr32(dev, reg + 0x04, (P << 16) | (N1 << 8) | M1);
+		nv_wr32(dev, reg + 0x10, N2 << 16);
 	}
 
 	return 0;
@@ -348,7 +365,7 @@
 
 	gem = drm_gem_object_lookup(dev, file_priv, buffer_handle);
 	if (!gem)
-		return -EINVAL;
+		return -ENOENT;
 	cursor = nouveau_gem_object(gem);
 
 	ret = nouveau_bo_map(cursor);
@@ -381,15 +398,12 @@
 
 static void
 nv50_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
-		    uint32_t size)
+		    uint32_t start, uint32_t size)
 {
+	int end = (start + size > 256) ? 256 : start + size, i;
 	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
-	int i;
 
-	if (size != 256)
-		return;
-
-	for (i = 0; i < 256; i++) {
+	for (i = start; i < end; i++) {
 		nv_crtc->lut.r[i] = r[i];
 		nv_crtc->lut.g[i] = g[i];
 		nv_crtc->lut.b[i] = b[i];
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index f13ad0d..612fa6d 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -76,7 +76,10 @@
 	nv_wo32(dev, obj, 2, offset);
 	nv_wo32(dev, obj, 3, 0x00000000);
 	nv_wo32(dev, obj, 4, 0x00000000);
-	nv_wo32(dev, obj, 5, 0x00010000);
+	if (dev_priv->card_type < NV_C0)
+		nv_wo32(dev, obj, 5, 0x00010000);
+	else
+		nv_wo32(dev, obj, 5, 0x00020000);
 	dev_priv->engine.instmem.flush(dev);
 
 	return 0;
diff --git a/drivers/gpu/drm/nouveau/nvc0_fb.c b/drivers/gpu/drm/nouveau/nvc0_fb.c
new file mode 100644
index 0000000..26a9960
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvc0_fb.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+
+int
+nvc0_fb_init(struct drm_device *dev)
+{
+	return 0;
+}
+
+void
+nvc0_fb_takedown(struct drm_device *dev)
+{
+}
diff --git a/drivers/gpu/drm/nouveau/nvc0_fifo.c b/drivers/gpu/drm/nouveau/nvc0_fifo.c
new file mode 100644
index 0000000..d643758
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvc0_fifo.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+
+void
+nvc0_fifo_disable(struct drm_device *dev)
+{
+}
+
+void
+nvc0_fifo_enable(struct drm_device *dev)
+{
+}
+
+bool
+nvc0_fifo_reassign(struct drm_device *dev, bool enable)
+{
+	return false;
+}
+
+bool
+nvc0_fifo_cache_flush(struct drm_device *dev)
+{
+	return true;
+}
+
+bool
+nvc0_fifo_cache_pull(struct drm_device *dev, bool enable)
+{
+	return false;
+}
+
+int
+nvc0_fifo_channel_id(struct drm_device *dev)
+{
+	return 127;
+}
+
+int
+nvc0_fifo_create_context(struct nouveau_channel *chan)
+{
+	return 0;
+}
+
+void
+nvc0_fifo_destroy_context(struct nouveau_channel *chan)
+{
+}
+
+int
+nvc0_fifo_load_context(struct nouveau_channel *chan)
+{
+	return 0;
+}
+
+int
+nvc0_fifo_unload_context(struct drm_device *dev)
+{
+	return 0;
+}
+
+void
+nvc0_fifo_takedown(struct drm_device *dev)
+{
+}
+
+int
+nvc0_fifo_init(struct drm_device *dev)
+{
+	return 0;
+}
+
diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c
new file mode 100644
index 0000000..717a517
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvc0_graph.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+
+void
+nvc0_graph_fifo_access(struct drm_device *dev, bool enabled)
+{
+}
+
+struct nouveau_channel *
+nvc0_graph_channel(struct drm_device *dev)
+{
+	return NULL;
+}
+
+int
+nvc0_graph_create_context(struct nouveau_channel *chan)
+{
+	return 0;
+}
+
+void
+nvc0_graph_destroy_context(struct nouveau_channel *chan)
+{
+}
+
+int
+nvc0_graph_load_context(struct nouveau_channel *chan)
+{
+	return 0;
+}
+
+int
+nvc0_graph_unload_context(struct drm_device *dev)
+{
+	return 0;
+}
+
+void
+nvc0_graph_takedown(struct drm_device *dev)
+{
+}
+
+int
+nvc0_graph_init(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	dev_priv->engine.graph.accel_blocked = true;
+	return 0;
+}
+
diff --git a/drivers/gpu/drm/nouveau/nvc0_instmem.c b/drivers/gpu/drm/nouveau/nvc0_instmem.c
new file mode 100644
index 0000000..3ab3cdc
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvc0_instmem.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+
+int
+nvc0_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
+		      uint32_t *size)
+{
+	int ret;
+
+	*size = ALIGN(*size, 4096);
+	if (*size == 0)
+		return -EINVAL;
+
+	ret = nouveau_bo_new(dev, NULL, *size, 0, TTM_PL_FLAG_VRAM, 0, 0x0000,
+			     true, false, &gpuobj->im_backing);
+	if (ret) {
+		NV_ERROR(dev, "error getting PRAMIN backing pages: %d\n", ret);
+		return ret;
+	}
+
+	ret = nouveau_bo_pin(gpuobj->im_backing, TTM_PL_FLAG_VRAM);
+	if (ret) {
+		NV_ERROR(dev, "error pinning PRAMIN backing VRAM: %d\n", ret);
+		nouveau_bo_ref(NULL, &gpuobj->im_backing);
+		return ret;
+	}
+
+	gpuobj->im_backing_start = gpuobj->im_backing->bo.mem.mm_node->start;
+	gpuobj->im_backing_start <<= PAGE_SHIFT;
+	return 0;
+}
+
+void
+nvc0_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+	if (gpuobj && gpuobj->im_backing) {
+		if (gpuobj->im_bound)
+			dev_priv->engine.instmem.unbind(dev, gpuobj);
+		nouveau_bo_unpin(gpuobj->im_backing);
+		nouveau_bo_ref(NULL, &gpuobj->im_backing);
+		gpuobj->im_backing = NULL;
+	}
+}
+
+int
+nvc0_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	uint32_t pte, pte_end;
+	uint64_t vram;
+
+	if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound)
+		return -EINVAL;
+
+	NV_DEBUG(dev, "st=0x%lx sz=0x%lx\n",
+		 gpuobj->im_pramin->start, gpuobj->im_pramin->size);
+
+	pte     = gpuobj->im_pramin->start >> 12;
+	pte_end = (gpuobj->im_pramin->size >> 12) + pte;
+	vram    = gpuobj->im_backing_start;
+
+	NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n",
+		 gpuobj->im_pramin->start, pte, pte_end);
+	NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start);
+
+	while (pte < pte_end) {
+		nv_wr32(dev, 0x702000 + (pte * 8), (vram >> 8) | 1);
+		nv_wr32(dev, 0x702004 + (pte * 8), 0);
+		vram += 4096;
+		pte++;
+	}
+	dev_priv->engine.instmem.flush(dev);
+
+	if (1) {
+		u32 chan = nv_rd32(dev, 0x1700) << 16;
+		nv_wr32(dev, 0x100cb8, (chan + 0x1000) >> 8);
+		nv_wr32(dev, 0x100cbc, 0x80000005);
+	}
+
+	gpuobj->im_bound = 1;
+	return 0;
+}
+
+int
+nvc0_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	uint32_t pte, pte_end;
+
+	if (gpuobj->im_bound == 0)
+		return -EINVAL;
+
+	pte     = gpuobj->im_pramin->start >> 12;
+	pte_end = (gpuobj->im_pramin->size >> 12) + pte;
+	while (pte < pte_end) {
+		nv_wr32(dev, 0x702000 + (pte * 8), 0);
+		nv_wr32(dev, 0x702004 + (pte * 8), 0);
+		pte++;
+	}
+	dev_priv->engine.instmem.flush(dev);
+
+	gpuobj->im_bound = 0;
+	return 0;
+}
+
+void
+nvc0_instmem_flush(struct drm_device *dev)
+{
+	nv_wr32(dev, 0x070000, 1);
+	if (!nv_wait(0x070000, 0x00000002, 0x00000000))
+		NV_ERROR(dev, "PRAMIN flush timeout\n");
+}
+
+int
+nvc0_instmem_suspend(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	int i;
+
+	dev_priv->susres.ramin_copy = vmalloc(65536);
+	if (!dev_priv->susres.ramin_copy)
+		return -ENOMEM;
+
+	for (i = 0x700000; i < 0x710000; i += 4)
+		dev_priv->susres.ramin_copy[i/4] = nv_rd32(dev, i);
+	return 0;
+}
+
+void
+nvc0_instmem_resume(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	u64 chan;
+	int i;
+
+	chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram;
+	nv_wr32(dev, 0x001700, chan >> 16);
+
+	for (i = 0x700000; i < 0x710000; i += 4)
+		nv_wr32(dev, i, dev_priv->susres.ramin_copy[i/4]);
+	vfree(dev_priv->susres.ramin_copy);
+	dev_priv->susres.ramin_copy = NULL;
+
+	nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12));
+}
+
+int
+nvc0_instmem_init(struct drm_device *dev)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	u64 chan, pgt3, imem, lim3 = dev_priv->ramin_size - 1;
+	int ret, i;
+
+	dev_priv->ramin_rsvd_vram = 1 * 1024 * 1024;
+	chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram;
+	imem = 4096 + 4096 + 32768;
+
+	nv_wr32(dev, 0x001700, chan >> 16);
+
+	/* channel setup */
+	nv_wr32(dev, 0x700200, lower_32_bits(chan + 0x1000));
+	nv_wr32(dev, 0x700204, upper_32_bits(chan + 0x1000));
+	nv_wr32(dev, 0x700208, lower_32_bits(lim3));
+	nv_wr32(dev, 0x70020c, upper_32_bits(lim3));
+
+	/* point pgd -> pgt */
+	nv_wr32(dev, 0x701000, 0);
+	nv_wr32(dev, 0x701004, ((chan + 0x2000) >> 8) | 1);
+
+	/* point pgt -> physical vram for channel */
+	pgt3 = 0x2000;
+	for (i = 0; i < dev_priv->ramin_rsvd_vram; i += 4096, pgt3 += 8) {
+		nv_wr32(dev, 0x700000 + pgt3, ((chan + i) >> 8) | 1);
+		nv_wr32(dev, 0x700004 + pgt3, 0);
+	}
+
+	/* clear rest of pgt */
+	for (; i < dev_priv->ramin_size; i += 4096, pgt3 += 8) {
+		nv_wr32(dev, 0x700000 + pgt3, 0);
+		nv_wr32(dev, 0x700004 + pgt3, 0);
+	}
+
+	/* point bar3 at the channel */
+	nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12));
+
+	/* Global PRAMIN heap */
+	ret = drm_mm_init(&dev_priv->ramin_heap, imem,
+			  dev_priv->ramin_size - imem);
+	if (ret) {
+		NV_ERROR(dev, "Failed to init RAMIN heap\n");
+		return -ENOMEM;
+	}
+
+	/*XXX: incorrect, but needed to make hash func "work" */
+	dev_priv->ramht_offset = 0x10000;
+	dev_priv->ramht_bits   = 9;
+	dev_priv->ramht_size   = (1 << dev_priv->ramht_bits);
+	return 0;
+}
+
+void
+nvc0_instmem_takedown(struct drm_device *dev)
+{
+}
+
diff --git a/drivers/gpu/drm/radeon/r600_cp.c b/drivers/gpu/drm/radeon/r600_cp.c
index 68e6f43..4f4cd8b 100644
--- a/drivers/gpu/drm/radeon/r600_cp.c
+++ b/drivers/gpu/drm/radeon/r600_cp.c
@@ -200,7 +200,7 @@
 						 entry->pagelist[i], 0,
 						 PAGE_SIZE,
 						 PCI_DMA_BIDIRECTIONAL);
-		if (entry->busaddr[i] == 0) {
+		if (pci_dma_mapping_error(dev->pdev, entry->busaddr[i])) {
 			DRM_ERROR("unable to map PCIGART pages!\n");
 			r600_page_table_cleanup(dev, gart_info);
 			goto done;
diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c
index c3ea212..d886494 100644
--- a/drivers/gpu/drm/radeon/r600_cs.c
+++ b/drivers/gpu/drm/radeon/r600_cs.c
@@ -133,6 +133,7 @@
 	case V_038004_FMT_GB_GR:
 	case V_038004_FMT_BG_RG:
 	case V_038004_COLOR_INVALID:
+	default:
 		*bpe = 16;
 		return -EINVAL;
 	}
@@ -174,7 +175,7 @@
 		dev_warn(p->dev, "FMASK or CMASK buffer are not supported by this kernel\n");
 		return -EINVAL;
 	}
-	size = radeon_bo_size(track->cb_color_bo[i]);
+	size = radeon_bo_size(track->cb_color_bo[i]) - track->cb_color_bo_offset[i];
 	if (r600_bpe_from_format(&bpe, G_0280A0_FORMAT(track->cb_color_info[i]))) {
 		dev_warn(p->dev, "%s:%d cb invalid format %d for %d (0x%08X)\n",
 			 __func__, __LINE__, G_0280A0_FORMAT(track->cb_color_info[i]),
@@ -327,7 +328,6 @@
 				dev_warn(p->dev, "z/stencil buffer size not set\n");
 				return -EINVAL;
 			}
-			printk_once(KERN_WARNING "You have old & broken userspace please consider updating mesa\n");
 			tmp = radeon_bo_size(track->db_bo) - track->db_offset;
 			tmp = (tmp / bpe) >> 6;
 			if (!tmp) {
@@ -882,8 +882,6 @@
 				return -EINVAL;
 			}
 			ib[idx] = track->cb_color_base_last[tmp];
-			printk_once(KERN_WARNING "You have old & broken userspace "
-					"please consider updating mesa & xf86-video-ati\n");
 			track->cb_color_frag_bo[tmp] = track->cb_color_bo[tmp];
 		} else {
 			r = r600_cs_packet_next_reloc(p, &reloc);
@@ -910,8 +908,6 @@
 				return -EINVAL;
 			}
 			ib[idx] = track->cb_color_base_last[tmp];
-			printk_once(KERN_WARNING "You have old & broken userspace "
-					"please consider updating mesa & xf86-video-ati\n");
 			track->cb_color_tile_bo[tmp] = track->cb_color_bo[tmp];
 		} else {
 			r = r600_cs_packet_next_reloc(p, &reloc);
@@ -938,7 +934,7 @@
 			return -EINVAL;
 		}
 		tmp = (reg - CB_COLOR0_BASE) / 4;
-		track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx);
+		track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx) << 8;
 		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
 		track->cb_color_base_last[tmp] = ib[idx];
 		track->cb_color_bo[tmp] = reloc->robj;
@@ -950,7 +946,7 @@
 					"0x%04X\n", reg);
 			return -EINVAL;
 		}
-		track->db_offset = radeon_get_ib_value(p, idx);
+		track->db_offset = radeon_get_ib_value(p, idx) << 8;
 		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
 		track->db_bo = reloc->robj;
 		break;
@@ -1055,10 +1051,10 @@
 	}
 	*l0_size = ALIGN((w0 * bpe), pitch_align) * h0 * d0;
 	*mipmap_size = offset;
-	if (!blevel)
-		*mipmap_size -= *l0_size;
 	if (!nlevels)
 		*mipmap_size = *l0_size;
+	if (!blevel)
+		*mipmap_size -= *l0_size;
 }
 
 /**
@@ -1165,14 +1161,14 @@
 			  (pitch_align * bpe),
 			  &l0_size, &mipmap_size);
 	/* using get ib will give us the offset into the texture bo */
-	word0 = radeon_get_ib_value(p, idx + 2);
+	word0 = radeon_get_ib_value(p, idx + 2) << 8;
 	if ((l0_size + word0) > radeon_bo_size(texture)) {
 		dev_warn(p->dev, "texture bo too small (%d %d %d %d -> %d have %ld)\n",
 			w0, h0, bpe, word0, l0_size, radeon_bo_size(texture));
 		return -EINVAL;
 	}
 	/* using get ib will give us the offset into the mipmap bo */
-	word0 = radeon_get_ib_value(p, idx + 3);
+	word0 = radeon_get_ib_value(p, idx + 3) << 8;
 	if ((mipmap_size + word0) > radeon_bo_size(mipmap)) {
 		dev_warn(p->dev, "mipmap bo too small (%d %d %d %d %d %d -> %d have %ld)\n",
 			w0, h0, bpe, blevel, nlevels, word0, mipmap_size, radeon_bo_size(texture));
@@ -1366,7 +1362,7 @@
 		}
 		for (i = 0; i < (pkt->count / 7); i++) {
 			struct radeon_bo *texture, *mipmap;
-			u32 size, offset;
+			u32 size, offset, base_offset, mip_offset;
 
 			switch (G__SQ_VTX_CONSTANT_TYPE(radeon_get_ib_value(p, idx+(i*7)+6+1))) {
 			case SQ_TEX_VTX_VALID_TEXTURE:
@@ -1376,7 +1372,7 @@
 					DRM_ERROR("bad SET_RESOURCE\n");
 					return -EINVAL;
 				}
-				ib[idx+1+(i*7)+2] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+				base_offset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
 				if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
 					ib[idx+1+(i*7)+0] |= S_038000_TILE_MODE(V_038000_ARRAY_2D_TILED_THIN1);
 				else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
@@ -1388,12 +1384,14 @@
 					DRM_ERROR("bad SET_RESOURCE\n");
 					return -EINVAL;
 				}
-				ib[idx+1+(i*7)+3] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+				mip_offset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
 				mipmap = reloc->robj;
 				r = r600_check_texture_resource(p,  idx+(i*7)+1,
 								texture, mipmap, reloc->lobj.tiling_flags);
 				if (r)
 					return r;
+				ib[idx+1+(i*7)+2] += base_offset;
+				ib[idx+1+(i*7)+3] += mip_offset;
 				break;
 			case SQ_TEX_VTX_VALID_BUFFER:
 				/* vtx base */
@@ -1403,10 +1401,11 @@
 					return -EINVAL;
 				}
 				offset = radeon_get_ib_value(p, idx+1+(i*7)+0);
-				size = radeon_get_ib_value(p, idx+1+(i*7)+1);
+				size = radeon_get_ib_value(p, idx+1+(i*7)+1) + 1;
 				if (p->rdev && (size + offset) > radeon_bo_size(reloc->robj)) {
 					/* force size to size of the buffer */
-					dev_warn(p->dev, "vbo resource seems too big for the bo\n");
+					dev_warn(p->dev, "vbo resource seems too big (%d) for the bo (%ld)\n",
+						 size + offset, radeon_bo_size(reloc->robj));
 					ib[idx+1+(i*7)+1] = radeon_bo_size(reloc->robj);
 				}
 				ib[idx+1+(i*7)+0] += (u32)((reloc->lobj.gpu_offset) & 0xffffffff);
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 3cd1c47..3dfcfa3 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1100,6 +1100,8 @@
 	struct notifier_block acpi_nb;
 	/* only one userspace can use Hyperz features at a time */
 	struct drm_file *hyperz_filp;
+	/* i2c buses */
+	struct radeon_i2c_chan *i2c_bus[RADEON_MAX_I2C_BUS];
 };
 
 int radeon_device_init(struct radeon_device *rdev,
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index 3bc2bcd..6d30868 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -48,7 +48,8 @@
 			  struct radeon_i2c_bus_rec *i2c_bus,
 			  bool linkb, uint32_t igp_lane_info,
 			  uint16_t connector_object_id,
-			  struct radeon_hpd *hpd);
+			  struct radeon_hpd *hpd,
+			  struct radeon_router *router);
 
 /* from radeon_legacy_encoder.c */
 extern void
@@ -114,7 +115,8 @@
 
 				i2c.i2c_id = gpio->sucI2cId.ucAccess;
 
-				i2c.valid = true;
+				if (i2c.mask_clk_reg)
+					i2c.valid = true;
 				break;
 			}
 		}
@@ -123,6 +125,66 @@
 	return i2c;
 }
 
+void radeon_atombios_i2c_init(struct radeon_device *rdev)
+{
+	struct atom_context *ctx = rdev->mode_info.atom_context;
+	ATOM_GPIO_I2C_ASSIGMENT *gpio;
+	struct radeon_i2c_bus_rec i2c;
+	int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info);
+	struct _ATOM_GPIO_I2C_INFO *i2c_info;
+	uint16_t data_offset, size;
+	int i, num_indices;
+	char stmp[32];
+
+	memset(&i2c, 0, sizeof(struct radeon_i2c_bus_rec));
+
+	if (atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) {
+		i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset);
+
+		num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+			sizeof(ATOM_GPIO_I2C_ASSIGMENT);
+
+		for (i = 0; i < num_indices; i++) {
+			gpio = &i2c_info->asGPIO_Info[i];
+			i2c.valid = false;
+			i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4;
+			i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4;
+			i2c.en_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex) * 4;
+			i2c.en_data_reg = le16_to_cpu(gpio->usDataEnRegisterIndex) * 4;
+			i2c.y_clk_reg = le16_to_cpu(gpio->usClkY_RegisterIndex) * 4;
+			i2c.y_data_reg = le16_to_cpu(gpio->usDataY_RegisterIndex) * 4;
+			i2c.a_clk_reg = le16_to_cpu(gpio->usClkA_RegisterIndex) * 4;
+			i2c.a_data_reg = le16_to_cpu(gpio->usDataA_RegisterIndex) * 4;
+			i2c.mask_clk_mask = (1 << gpio->ucClkMaskShift);
+			i2c.mask_data_mask = (1 << gpio->ucDataMaskShift);
+			i2c.en_clk_mask = (1 << gpio->ucClkEnShift);
+			i2c.en_data_mask = (1 << gpio->ucDataEnShift);
+			i2c.y_clk_mask = (1 << gpio->ucClkY_Shift);
+			i2c.y_data_mask = (1 << gpio->ucDataY_Shift);
+			i2c.a_clk_mask = (1 << gpio->ucClkA_Shift);
+			i2c.a_data_mask = (1 << gpio->ucDataA_Shift);
+
+			if (gpio->sucI2cId.sbfAccess.bfHW_Capable)
+				i2c.hw_capable = true;
+			else
+				i2c.hw_capable = false;
+
+			if (gpio->sucI2cId.ucAccess == 0xa0)
+				i2c.mm_i2c = true;
+			else
+				i2c.mm_i2c = false;
+
+			i2c.i2c_id = gpio->sucI2cId.ucAccess;
+
+			if (i2c.mask_clk_reg) {
+				i2c.valid = true;
+				sprintf(stmp, "0x%x", i2c.i2c_id);
+				rdev->i2c_bus[i] = radeon_i2c_create(rdev->ddev, &i2c, stmp);
+			}
+		}
+	}
+}
+
 static inline struct radeon_gpio_rec radeon_lookup_gpio(struct radeon_device *rdev,
 							u8 id)
 {
@@ -206,6 +268,7 @@
 				     uint16_t *line_mux,
 				     struct radeon_hpd *hpd)
 {
+	struct radeon_device *rdev = dev->dev_private;
 
 	/* Asus M2A-VM HDMI board lists the DVI port as HDMI */
 	if ((dev->pdev->device == 0x791e) &&
@@ -308,13 +371,22 @@
 		}
 	}
 
-	/* Acer laptop reports DVI-D as DVI-I */
+	/* Acer laptop reports DVI-D as DVI-I and hpd pins reversed */
 	if ((dev->pdev->device == 0x95c4) &&
 	    (dev->pdev->subsystem_vendor == 0x1025) &&
 	    (dev->pdev->subsystem_device == 0x013c)) {
+		struct radeon_gpio_rec gpio;
+
 		if ((*connector_type == DRM_MODE_CONNECTOR_DVII) &&
-		    (supported_device == ATOM_DEVICE_DFP1_SUPPORT))
+		    (supported_device == ATOM_DEVICE_DFP1_SUPPORT)) {
+			gpio = radeon_lookup_gpio(rdev, 6);
+			*hpd = radeon_atom_get_hpd_info_from_gpio(rdev, &gpio);
 			*connector_type = DRM_MODE_CONNECTOR_DVID;
+		} else if ((*connector_type == DRM_MODE_CONNECTOR_HDMIA) &&
+			   (supported_device == ATOM_DEVICE_DFP1_SUPPORT)) {
+			gpio = radeon_lookup_gpio(rdev, 7);
+			*hpd = radeon_atom_get_hpd_info_from_gpio(rdev, &gpio);
+		}
 	}
 
 	/* XFX Pine Group device rv730 reports no VGA DDC lines
@@ -399,13 +471,15 @@
 	u16 size, data_offset;
 	u8 frev, crev;
 	ATOM_CONNECTOR_OBJECT_TABLE *con_obj;
+	ATOM_OBJECT_TABLE *router_obj;
 	ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj;
 	ATOM_OBJECT_HEADER *obj_header;
-	int i, j, path_size, device_support;
+	int i, j, k, path_size, device_support;
 	int connector_type;
 	u16 igp_lane_info, conn_id, connector_object_id;
 	bool linkb;
 	struct radeon_i2c_bus_rec ddc_bus;
+	struct radeon_router router;
 	struct radeon_gpio_rec gpio;
 	struct radeon_hpd hpd;
 
@@ -415,6 +489,8 @@
 	if (crev < 2)
 		return false;
 
+	router.valid = false;
+
 	obj_header = (ATOM_OBJECT_HEADER *) (ctx->bios + data_offset);
 	path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *)
 	    (ctx->bios + data_offset +
@@ -422,6 +498,9 @@
 	con_obj = (ATOM_CONNECTOR_OBJECT_TABLE *)
 	    (ctx->bios + data_offset +
 	     le16_to_cpu(obj_header->usConnectorObjectTableOffset));
+	router_obj = (ATOM_OBJECT_TABLE *)
+		(ctx->bios + data_offset +
+		 le16_to_cpu(obj_header->usRouterObjectTableOffset));
 	device_support = le16_to_cpu(obj_header->usDeviceSupport);
 
 	path_size = 0;
@@ -508,33 +587,86 @@
 			if (connector_type == DRM_MODE_CONNECTOR_Unknown)
 				continue;
 
-			for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2);
-			     j++) {
-				uint8_t enc_obj_id, enc_obj_num, enc_obj_type;
+			for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2); j++) {
+				uint8_t grph_obj_id, grph_obj_num, grph_obj_type;
 
-				enc_obj_id =
+				grph_obj_id =
 				    (le16_to_cpu(path->usGraphicObjIds[j]) &
 				     OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
-				enc_obj_num =
+				grph_obj_num =
 				    (le16_to_cpu(path->usGraphicObjIds[j]) &
 				     ENUM_ID_MASK) >> ENUM_ID_SHIFT;
-				enc_obj_type =
+				grph_obj_type =
 				    (le16_to_cpu(path->usGraphicObjIds[j]) &
 				     OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
 
-				/* FIXME: add support for router objects */
-				if (enc_obj_type == GRAPH_OBJECT_TYPE_ENCODER) {
-					if (enc_obj_num == 2)
+				if (grph_obj_type == GRAPH_OBJECT_TYPE_ENCODER) {
+					if (grph_obj_num == 2)
 						linkb = true;
 					else
 						linkb = false;
 
 					radeon_add_atom_encoder(dev,
-								enc_obj_id,
+								grph_obj_id,
 								le16_to_cpu
 								(path->
 								 usDeviceTag));
 
+				} else if (grph_obj_type == GRAPH_OBJECT_TYPE_ROUTER) {
+					router.valid = false;
+					for (k = 0; k < router_obj->ucNumberOfObjects; k++) {
+						u16 router_obj_id = le16_to_cpu(router_obj->asObjects[j].usObjectID);
+						if (le16_to_cpu(path->usGraphicObjIds[j]) == router_obj_id) {
+							ATOM_COMMON_RECORD_HEADER *record = (ATOM_COMMON_RECORD_HEADER *)
+								(ctx->bios + data_offset +
+								 le16_to_cpu(router_obj->asObjects[k].usRecordOffset));
+							ATOM_I2C_RECORD *i2c_record;
+							ATOM_I2C_ID_CONFIG_ACCESS *i2c_config;
+							ATOM_ROUTER_DDC_PATH_SELECT_RECORD *ddc_path;
+							ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *router_src_dst_table =
+								(ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT *)
+								(ctx->bios + data_offset +
+								 le16_to_cpu(router_obj->asObjects[k].usSrcDstTableOffset));
+							int enum_id;
+
+							router.router_id = router_obj_id;
+							for (enum_id = 0; enum_id < router_src_dst_table->ucNumberOfDst;
+							     enum_id++) {
+								if (le16_to_cpu(path->usConnObjectId) ==
+								    le16_to_cpu(router_src_dst_table->usDstObjectID[enum_id]))
+									break;
+							}
+
+							while (record->ucRecordType > 0 &&
+							       record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) {
+								switch (record->ucRecordType) {
+								case ATOM_I2C_RECORD_TYPE:
+									i2c_record =
+										(ATOM_I2C_RECORD *)
+										record;
+									i2c_config =
+										(ATOM_I2C_ID_CONFIG_ACCESS *)
+										&i2c_record->sucI2cId;
+									router.i2c_info =
+										radeon_lookup_i2c_gpio(rdev,
+												       i2c_config->
+												       ucAccess);
+									router.i2c_addr = i2c_record->ucI2CAddr >> 1;
+									break;
+								case ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE:
+									ddc_path = (ATOM_ROUTER_DDC_PATH_SELECT_RECORD *)
+										record;
+									router.valid = true;
+									router.mux_type = ddc_path->ucMuxType;
+									router.mux_control_pin = ddc_path->ucMuxControlPin;
+									router.mux_state = ddc_path->ucMuxState[enum_id];
+									break;
+								}
+								record = (ATOM_COMMON_RECORD_HEADER *)
+									((char *)record + record->ucRecordSize);
+							}
+						}
+					}
 				}
 			}
 
@@ -614,7 +746,8 @@
 						  connector_type, &ddc_bus,
 						  linkb, igp_lane_info,
 						  connector_object_id,
-						  &hpd);
+						  &hpd,
+						  &router);
 
 		}
 	}
@@ -691,6 +824,9 @@
 	int i, j, max_device;
 	struct bios_connector *bios_connectors;
 	size_t bc_size = sizeof(*bios_connectors) * ATOM_MAX_SUPPORTED_DEVICE;
+	struct radeon_router router;
+
+	router.valid = false;
 
 	bios_connectors = kzalloc(bc_size, GFP_KERNEL);
 	if (!bios_connectors)
@@ -862,7 +998,8 @@
 						  &bios_connectors[i].ddc_bus,
 						  false, 0,
 						  connector_object_id,
-						  &bios_connectors[i].hpd);
+						  &bios_connectors[i].hpd,
+						  &router);
 		}
 	}
 
@@ -1521,7 +1658,7 @@
 					 thermal_controller_names[power_info->info.ucOverdriveThermalController],
 					 power_info->info.ucOverdriveControllerAddress >> 1);
 				i2c_bus = radeon_lookup_i2c_gpio(rdev, power_info->info.ucOverdriveI2cLine);
-				rdev->pm.i2c_bus = radeon_i2c_create(rdev->ddev, &i2c_bus, "Thermal");
+				rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
 				if (rdev->pm.i2c_bus) {
 					struct i2c_board_info info = { };
 					const char *name = thermal_controller_names[power_info->info.
@@ -1814,7 +1951,7 @@
 						 (controller->ucFanParameters &
 						  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
 					i2c_bus = radeon_lookup_i2c_gpio(rdev, controller->ucI2cLine);
-					rdev->pm.i2c_bus = radeon_i2c_create(rdev->ddev, &i2c_bus, "Thermal");
+					rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
 					if (rdev->pm.i2c_bus) {
 						struct i2c_board_info info = { };
 						const char *name = pp_lib_thermal_controller_names[controller->ucType];
@@ -1927,6 +2064,11 @@
 						rdev->pm.power_state[state_index].type =
 							POWER_STATE_TYPE_PERFORMANCE;
 						break;
+					case ATOM_PPLIB_CLASSIFICATION_UI_NONE:
+						if (misc2 & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
+							rdev->pm.power_state[state_index].type =
+								POWER_STATE_TYPE_PERFORMANCE;
+						break;
 					}
 					rdev->pm.power_state[state_index].flags = 0;
 					if (misc & ATOM_PPLIB_SINGLE_DISPLAY_ONLY)
diff --git a/drivers/gpu/drm/radeon/radeon_clocks.c b/drivers/gpu/drm/radeon/radeon_clocks.c
index f64936c..14448a7 100644
--- a/drivers/gpu/drm/radeon/radeon_clocks.c
+++ b/drivers/gpu/drm/radeon/radeon_clocks.c
@@ -91,6 +91,85 @@
 	return mclk;
 }
 
+#ifdef CONFIG_OF
+/*
+ * Read XTAL (ref clock), SCLK and MCLK from Open Firmware device
+ * tree. Hopefully, ATI OF driver is kind enough to fill these
+ */
+static bool __devinit radeon_read_clocks_OF(struct drm_device *dev)
+{
+	struct radeon_device *rdev = dev->dev_private;
+	struct device_node *dp = rdev->pdev->dev.of_node;
+	const u32 *val;
+	struct radeon_pll *p1pll = &rdev->clock.p1pll;
+	struct radeon_pll *p2pll = &rdev->clock.p2pll;
+	struct radeon_pll *spll = &rdev->clock.spll;
+	struct radeon_pll *mpll = &rdev->clock.mpll;
+
+	if (dp == NULL)
+		return false;
+	val = of_get_property(dp, "ATY,RefCLK", NULL);
+	if (!val || !*val) {
+		printk(KERN_WARNING "radeonfb: No ATY,RefCLK property !\n");
+		return false;
+	}
+	p1pll->reference_freq = p2pll->reference_freq = (*val) / 10;
+	p1pll->reference_div = RREG32_PLL(RADEON_PPLL_REF_DIV) & 0x3ff;
+	if (p1pll->reference_div < 2)
+		p1pll->reference_div = 12;
+	p2pll->reference_div = p1pll->reference_div;	
+
+	/* These aren't in the device-tree */
+	if (rdev->family >= CHIP_R420) {
+		p1pll->pll_in_min = 100;
+		p1pll->pll_in_max = 1350;
+		p1pll->pll_out_min = 20000;
+		p1pll->pll_out_max = 50000;
+		p2pll->pll_in_min = 100;
+		p2pll->pll_in_max = 1350;
+		p2pll->pll_out_min = 20000;
+		p2pll->pll_out_max = 50000;
+	} else {
+		p1pll->pll_in_min = 40;
+		p1pll->pll_in_max = 500;
+		p1pll->pll_out_min = 12500;
+		p1pll->pll_out_max = 35000;
+		p2pll->pll_in_min = 40;
+		p2pll->pll_in_max = 500;
+		p2pll->pll_out_min = 12500;
+		p2pll->pll_out_max = 35000;
+	}
+
+	spll->reference_freq = mpll->reference_freq = p1pll->reference_freq;
+	spll->reference_div = mpll->reference_div =
+		RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV) &
+			    RADEON_M_SPLL_REF_DIV_MASK;
+
+	val = of_get_property(dp, "ATY,SCLK", NULL);
+	if (val && *val)
+		rdev->clock.default_sclk = (*val) / 10;
+	else
+		rdev->clock.default_sclk =
+			radeon_legacy_get_engine_clock(rdev);
+			
+	val = of_get_property(dp, "ATY,MCLK", NULL);
+	if (val && *val)
+		rdev->clock.default_mclk = (*val) / 10;
+	else
+		rdev->clock.default_mclk =
+			radeon_legacy_get_memory_clock(rdev);
+
+	DRM_INFO("Using device-tree clock info\n");
+	
+	return true;
+}
+#else
+static bool __devinit radeon_read_clocks_OF(struct drm_device *dev)
+{
+	return false;
+}
+#endif /* CONFIG_OF */
+
 void radeon_get_clock_info(struct drm_device *dev)
 {
 	struct radeon_device *rdev = dev->dev_private;
@@ -105,6 +184,8 @@
 		ret = radeon_atom_get_clock_info(dev);
 	else
 		ret = radeon_combios_get_clock_info(dev);
+	if (!ret)
+		ret = radeon_read_clocks_OF(dev);
 
 	if (ret) {
 		if (p1pll->reference_div < 2) {
diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c
index 5e1474c..885dcfa 100644
--- a/drivers/gpu/drm/radeon/radeon_combios.c
+++ b/drivers/gpu/drm/radeon/radeon_combios.c
@@ -480,9 +480,66 @@
 }
 
 static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rdev,
-						       int ddc_line)
+						       enum radeon_combios_ddc ddc,
+						       u32 clk_mask,
+						       u32 data_mask)
 {
 	struct radeon_i2c_bus_rec i2c;
+	int ddc_line = 0;
+
+	/* ddc id            = mask reg
+	 * DDC_NONE_DETECTED = none
+	 * DDC_DVI           = RADEON_GPIO_DVI_DDC
+	 * DDC_VGA           = RADEON_GPIO_VGA_DDC
+	 * DDC_LCD           = RADEON_GPIOPAD_MASK
+	 * DDC_GPIO          = RADEON_MDGPIO_MASK
+	 * r1xx/r2xx
+	 * DDC_MONID         = RADEON_GPIO_MONID
+	 * DDC_CRT2          = RADEON_GPIO_CRT2_DDC
+	 * r3xx
+	 * DDC_MONID         = RADEON_GPIO_MONID
+	 * DDC_CRT2          = RADEON_GPIO_DVI_DDC
+	 * rs3xx/rs4xx
+	 * DDC_MONID         = RADEON_GPIOPAD_MASK
+	 * DDC_CRT2          = RADEON_GPIO_MONID
+	 */
+	switch (ddc) {
+	case DDC_NONE_DETECTED:
+	default:
+		ddc_line = 0;
+		break;
+	case DDC_DVI:
+		ddc_line = RADEON_GPIO_DVI_DDC;
+		break;
+	case DDC_VGA:
+		ddc_line = RADEON_GPIO_VGA_DDC;
+		break;
+	case DDC_LCD:
+		ddc_line = RADEON_GPIOPAD_MASK;
+		break;
+	case DDC_GPIO:
+		ddc_line = RADEON_MDGPIO_MASK;
+		break;
+	case DDC_MONID:
+		if (rdev->family == CHIP_RS300 ||
+		    rdev->family == CHIP_RS400 ||
+		    rdev->family == CHIP_RS480)
+			ddc_line = RADEON_GPIOPAD_MASK;
+		else
+			ddc_line = RADEON_GPIO_MONID;
+		break;
+	case DDC_CRT2:
+		if (rdev->family == CHIP_RS300 ||
+		    rdev->family == CHIP_RS400 ||
+		    rdev->family == CHIP_RS480)
+			ddc_line = RADEON_GPIO_MONID;
+		else if (rdev->family >= CHIP_R300) {
+			ddc_line = RADEON_GPIO_DVI_DDC;
+			ddc = DDC_DVI;
+		} else
+			ddc_line = RADEON_GPIO_CRT2_DDC;
+		break;
+	}
 
 	if (ddc_line == RADEON_GPIOPAD_MASK) {
 		i2c.mask_clk_reg = RADEON_GPIOPAD_MASK;
@@ -503,15 +560,6 @@
 		i2c.y_clk_reg = RADEON_MDGPIO_Y;
 		i2c.y_data_reg = RADEON_MDGPIO_Y;
 	} else {
-		i2c.mask_clk_mask = RADEON_GPIO_EN_1;
-		i2c.mask_data_mask = RADEON_GPIO_EN_0;
-		i2c.a_clk_mask = RADEON_GPIO_A_1;
-		i2c.a_data_mask = RADEON_GPIO_A_0;
-		i2c.en_clk_mask = RADEON_GPIO_EN_1;
-		i2c.en_data_mask = RADEON_GPIO_EN_0;
-		i2c.y_clk_mask = RADEON_GPIO_Y_1;
-		i2c.y_data_mask = RADEON_GPIO_Y_0;
-
 		i2c.mask_clk_reg = ddc_line;
 		i2c.mask_data_reg = ddc_line;
 		i2c.a_clk_reg = ddc_line;
@@ -522,6 +570,26 @@
 		i2c.y_data_reg = ddc_line;
 	}
 
+	if (clk_mask && data_mask) {
+		i2c.mask_clk_mask = clk_mask;
+		i2c.mask_data_mask = data_mask;
+		i2c.a_clk_mask = clk_mask;
+		i2c.a_data_mask = data_mask;
+		i2c.en_clk_mask = clk_mask;
+		i2c.en_data_mask = data_mask;
+		i2c.y_clk_mask = clk_mask;
+		i2c.y_data_mask = data_mask;
+	} else {
+		i2c.mask_clk_mask = RADEON_GPIO_EN_1;
+		i2c.mask_data_mask = RADEON_GPIO_EN_0;
+		i2c.a_clk_mask = RADEON_GPIO_A_1;
+		i2c.a_data_mask = RADEON_GPIO_A_0;
+		i2c.en_clk_mask = RADEON_GPIO_EN_1;
+		i2c.en_data_mask = RADEON_GPIO_EN_0;
+		i2c.y_clk_mask = RADEON_GPIO_Y_1;
+		i2c.y_data_mask = RADEON_GPIO_Y_0;
+	}
+
 	switch (rdev->family) {
 	case CHIP_R100:
 	case CHIP_RV100:
@@ -599,7 +667,8 @@
 		break;
 	}
 	i2c.mm_i2c = false;
-	i2c.i2c_id = 0;
+
+	i2c.i2c_id = ddc;
 	i2c.hpd = RADEON_HPD_NONE;
 
 	if (ddc_line)
@@ -610,6 +679,62 @@
 	return i2c;
 }
 
+void radeon_combios_i2c_init(struct radeon_device *rdev)
+{
+	struct drm_device *dev = rdev->ddev;
+	struct radeon_i2c_bus_rec i2c;
+
+
+	i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
+	rdev->i2c_bus[0] = radeon_i2c_create(dev, &i2c, "DVI_DDC");
+
+	i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
+	rdev->i2c_bus[1] = radeon_i2c_create(dev, &i2c, "VGA_DDC");
+
+	i2c.valid = true;
+	i2c.hw_capable = true;
+	i2c.mm_i2c = true;
+	i2c.i2c_id = 0xa0;
+	rdev->i2c_bus[2] = radeon_i2c_create(dev, &i2c, "MM_I2C");
+
+	if (rdev->family == CHIP_RS300 ||
+	    rdev->family == CHIP_RS400 ||
+	    rdev->family == CHIP_RS480) {
+		u16 offset;
+		u8 id, blocks, clk, data;
+		int i;
+
+		i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0);
+		rdev->i2c_bus[3] = radeon_i2c_create(dev, &i2c, "MONID");
+
+		offset = combios_get_table_offset(dev, COMBIOS_I2C_INFO_TABLE);
+		if (offset) {
+			blocks = RBIOS8(offset + 2);
+			for (i = 0; i < blocks; i++) {
+				id = RBIOS8(offset + 3 + (i * 5) + 0);
+				if (id == 136) {
+					clk = RBIOS8(offset + 3 + (i * 5) + 3);
+					data = RBIOS8(offset + 3 + (i * 5) + 4);
+					i2c = combios_setup_i2c_bus(rdev, DDC_MONID,
+								    clk, data);
+					rdev->i2c_bus[4] = radeon_i2c_create(dev, &i2c, "GPIOPAD_MASK");
+					break;
+				}
+			}
+		}
+
+	} else if (rdev->family >= CHIP_R300) {
+		i2c = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0);
+		rdev->i2c_bus[3] = radeon_i2c_create(dev, &i2c, "MONID");
+	} else {
+		i2c = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0);
+		rdev->i2c_bus[3] = radeon_i2c_create(dev, &i2c, "MONID");
+
+		i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0);
+		rdev->i2c_bus[4] = radeon_i2c_create(dev, &i2c, "CRT2_DDC");
+	}
+}
+
 bool radeon_combios_get_clock_info(struct drm_device *dev)
 {
 	struct radeon_device *rdev = dev->dev_private;
@@ -1247,8 +1372,8 @@
 	struct radeon_i2c_bus_rec i2c_bus;
 
 	/* default for macs */
-	i2c_bus = combios_setup_i2c_bus(rdev, RADEON_GPIO_MONID);
-	tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
+	i2c_bus = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0);
+	tmds->i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
 
 	/* XXX some macs have duallink chips */
 	switch (rdev->mode_info.connector_table) {
@@ -1269,47 +1394,16 @@
 	struct drm_device *dev = encoder->base.dev;
 	struct radeon_device *rdev = dev->dev_private;
 	uint16_t offset;
-	uint8_t ver, id, blocks, clk, data;
-	int i;
+	uint8_t ver;
 	enum radeon_combios_ddc gpio;
 	struct radeon_i2c_bus_rec i2c_bus;
 
 	tmds->i2c_bus = NULL;
 	if (rdev->flags & RADEON_IS_IGP) {
-		offset = combios_get_table_offset(dev, COMBIOS_I2C_INFO_TABLE);
-		if (offset) {
-			ver = RBIOS8(offset);
-			DRM_INFO("GPIO Table revision: %d\n", ver);
-			blocks = RBIOS8(offset + 2);
-			for (i = 0; i < blocks; i++) {
-				id = RBIOS8(offset + 3 + (i * 5) + 0);
-				if (id == 136) {
-					clk = RBIOS8(offset + 3 + (i * 5) + 3);
-					data = RBIOS8(offset + 3 + (i * 5) + 4);
-					i2c_bus.valid = true;
-					i2c_bus.mask_clk_mask = (1 << clk);
-					i2c_bus.mask_data_mask = (1 << data);
-					i2c_bus.a_clk_mask = (1 << clk);
-					i2c_bus.a_data_mask = (1 << data);
-					i2c_bus.en_clk_mask = (1 << clk);
-					i2c_bus.en_data_mask = (1 << data);
-					i2c_bus.y_clk_mask = (1 << clk);
-					i2c_bus.y_data_mask = (1 << data);
-					i2c_bus.mask_clk_reg = RADEON_GPIOPAD_MASK;
-					i2c_bus.mask_data_reg = RADEON_GPIOPAD_MASK;
-					i2c_bus.a_clk_reg = RADEON_GPIOPAD_A;
-					i2c_bus.a_data_reg = RADEON_GPIOPAD_A;
-					i2c_bus.en_clk_reg = RADEON_GPIOPAD_EN;
-					i2c_bus.en_data_reg = RADEON_GPIOPAD_EN;
-					i2c_bus.y_clk_reg = RADEON_GPIOPAD_Y;
-					i2c_bus.y_data_reg = RADEON_GPIOPAD_Y;
-					tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
-					tmds->dvo_chip = DVO_SIL164;
-					tmds->slave_addr = 0x70 >> 1; /* 7 bit addressing */
-					break;
-				}
-			}
-		}
+		i2c_bus = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0);
+		tmds->i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
+		tmds->dvo_chip = DVO_SIL164;
+		tmds->slave_addr = 0x70 >> 1; /* 7 bit addressing */
 	} else {
 		offset = combios_get_table_offset(dev, COMBIOS_EXT_TMDS_INFO_TABLE);
 		if (offset) {
@@ -1318,37 +1412,15 @@
 			tmds->slave_addr = RBIOS8(offset + 4 + 2);
 			tmds->slave_addr >>= 1; /* 7 bit addressing */
 			gpio = RBIOS8(offset + 4 + 3);
-			switch (gpio) {
-			case DDC_MONID:
-				i2c_bus = combios_setup_i2c_bus(rdev, RADEON_GPIO_MONID);
-				tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
-				break;
-			case DDC_DVI:
-				i2c_bus = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
-				tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
-				break;
-			case DDC_VGA:
-				i2c_bus = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
-				tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
-				break;
-			case DDC_CRT2:
-				/* R3xx+ chips don't have GPIO_CRT2_DDC gpio pad */
-				if (rdev->family >= CHIP_R300)
-					i2c_bus = combios_setup_i2c_bus(rdev, RADEON_GPIO_MONID);
-				else
-					i2c_bus = combios_setup_i2c_bus(rdev, RADEON_GPIO_CRT2_DDC);
-				tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
-				break;
-			case DDC_LCD: /* MM i2c */
+			if (gpio == DDC_LCD) {
+				/* MM i2c */
 				i2c_bus.valid = true;
 				i2c_bus.hw_capable = true;
 				i2c_bus.mm_i2c = true;
-				tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
-				break;
-			default:
-				DRM_ERROR("Unsupported gpio %d\n", gpio);
-				break;
-			}
+				i2c_bus.i2c_id = 0xa0;
+			} else
+				i2c_bus = combios_setup_i2c_bus(rdev, gpio, 0, 0);
+			tmds->i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
 		}
 	}
 
@@ -1430,7 +1502,7 @@
 		/* these are the most common settings */
 		if (rdev->flags & RADEON_SINGLE_CRTC) {
 			/* VGA - primary dac */
-			ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
+			ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
 			hpd.hpd = RADEON_HPD_NONE;
 			radeon_add_legacy_encoder(dev,
 						  radeon_get_encoder_id(dev,
@@ -1445,7 +1517,7 @@
 						    &hpd);
 		} else if (rdev->flags & RADEON_IS_MOBILITY) {
 			/* LVDS */
-			ddc_i2c = combios_setup_i2c_bus(rdev, 0);
+			ddc_i2c = combios_setup_i2c_bus(rdev, DDC_NONE_DETECTED, 0, 0);
 			hpd.hpd = RADEON_HPD_NONE;
 			radeon_add_legacy_encoder(dev,
 						  radeon_get_encoder_id(dev,
@@ -1460,7 +1532,7 @@
 						    &hpd);
 
 			/* VGA - primary dac */
-			ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
+			ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
 			hpd.hpd = RADEON_HPD_NONE;
 			radeon_add_legacy_encoder(dev,
 						  radeon_get_encoder_id(dev,
@@ -1475,7 +1547,7 @@
 						    &hpd);
 		} else {
 			/* DVI-I - tv dac, int tmds */
-			ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
+			ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
 			hpd.hpd = RADEON_HPD_1;
 			radeon_add_legacy_encoder(dev,
 						  radeon_get_encoder_id(dev,
@@ -1496,7 +1568,7 @@
 						    &hpd);
 
 			/* VGA - primary dac */
-			ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
+			ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
 			hpd.hpd = RADEON_HPD_NONE;
 			radeon_add_legacy_encoder(dev,
 						  radeon_get_encoder_id(dev,
@@ -1532,7 +1604,7 @@
 		DRM_INFO("Connector Table: %d (ibook)\n",
 			 rdev->mode_info.connector_table);
 		/* LVDS */
-		ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
+		ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
 		hpd.hpd = RADEON_HPD_NONE;
 		radeon_add_legacy_encoder(dev,
 					  radeon_get_encoder_id(dev,
@@ -1544,7 +1616,7 @@
 					    CONNECTOR_OBJECT_ID_LVDS,
 					    &hpd);
 		/* VGA - TV DAC */
-		ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
+		ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
 		hpd.hpd = RADEON_HPD_NONE;
 		radeon_add_legacy_encoder(dev,
 					  radeon_get_encoder_id(dev,
@@ -1573,7 +1645,7 @@
 		DRM_INFO("Connector Table: %d (powerbook external tmds)\n",
 			 rdev->mode_info.connector_table);
 		/* LVDS */
-		ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
+		ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
 		hpd.hpd = RADEON_HPD_NONE;
 		radeon_add_legacy_encoder(dev,
 					  radeon_get_encoder_id(dev,
@@ -1585,7 +1657,7 @@
 					    CONNECTOR_OBJECT_ID_LVDS,
 					    &hpd);
 		/* DVI-I - primary dac, ext tmds */
-		ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
+		ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
 		hpd.hpd = RADEON_HPD_2; /* ??? */
 		radeon_add_legacy_encoder(dev,
 					  radeon_get_encoder_id(dev,
@@ -1622,7 +1694,7 @@
 		DRM_INFO("Connector Table: %d (powerbook internal tmds)\n",
 			 rdev->mode_info.connector_table);
 		/* LVDS */
-		ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
+		ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
 		hpd.hpd = RADEON_HPD_NONE;
 		radeon_add_legacy_encoder(dev,
 					  radeon_get_encoder_id(dev,
@@ -1634,7 +1706,7 @@
 					    CONNECTOR_OBJECT_ID_LVDS,
 					    &hpd);
 		/* DVI-I - primary dac, int tmds */
-		ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
+		ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
 		hpd.hpd = RADEON_HPD_1; /* ??? */
 		radeon_add_legacy_encoder(dev,
 					  radeon_get_encoder_id(dev,
@@ -1670,7 +1742,7 @@
 		DRM_INFO("Connector Table: %d (powerbook vga)\n",
 			 rdev->mode_info.connector_table);
 		/* LVDS */
-		ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
+		ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
 		hpd.hpd = RADEON_HPD_NONE;
 		radeon_add_legacy_encoder(dev,
 					  radeon_get_encoder_id(dev,
@@ -1682,7 +1754,7 @@
 					    CONNECTOR_OBJECT_ID_LVDS,
 					    &hpd);
 		/* VGA - primary dac */
-		ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
+		ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
 		hpd.hpd = RADEON_HPD_NONE;
 		radeon_add_legacy_encoder(dev,
 					  radeon_get_encoder_id(dev,
@@ -1711,7 +1783,7 @@
 		DRM_INFO("Connector Table: %d (mini external tmds)\n",
 			 rdev->mode_info.connector_table);
 		/* DVI-I - tv dac, ext tmds */
-		ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_CRT2_DDC);
+		ddc_i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0);
 		hpd.hpd = RADEON_HPD_2; /* ??? */
 		radeon_add_legacy_encoder(dev,
 					  radeon_get_encoder_id(dev,
@@ -1748,7 +1820,7 @@
 		DRM_INFO("Connector Table: %d (mini internal tmds)\n",
 			 rdev->mode_info.connector_table);
 		/* DVI-I - tv dac, int tmds */
-		ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_CRT2_DDC);
+		ddc_i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0);
 		hpd.hpd = RADEON_HPD_1; /* ??? */
 		radeon_add_legacy_encoder(dev,
 					  radeon_get_encoder_id(dev,
@@ -1784,7 +1856,7 @@
 		DRM_INFO("Connector Table: %d (imac g5 isight)\n",
 			 rdev->mode_info.connector_table);
 		/* DVI-D - int tmds */
-		ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_MONID);
+		ddc_i2c = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0);
 		hpd.hpd = RADEON_HPD_1; /* ??? */
 		radeon_add_legacy_encoder(dev,
 					  radeon_get_encoder_id(dev,
@@ -1796,7 +1868,7 @@
 					    CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D,
 					    &hpd);
 		/* VGA - tv dac */
-		ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
+		ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
 		hpd.hpd = RADEON_HPD_NONE;
 		radeon_add_legacy_encoder(dev,
 					  radeon_get_encoder_id(dev,
@@ -1825,7 +1897,7 @@
 		DRM_INFO("Connector Table: %d (emac)\n",
 			 rdev->mode_info.connector_table);
 		/* VGA - primary dac */
-		ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
+		ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
 		hpd.hpd = RADEON_HPD_NONE;
 		radeon_add_legacy_encoder(dev,
 					  radeon_get_encoder_id(dev,
@@ -1837,7 +1909,7 @@
 					    CONNECTOR_OBJECT_ID_VGA,
 					    &hpd);
 		/* VGA - tv dac */
-		ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_CRT2_DDC);
+		ddc_i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0);
 		hpd.hpd = RADEON_HPD_NONE;
 		radeon_add_legacy_encoder(dev,
 					  radeon_get_encoder_id(dev,
@@ -1866,7 +1938,7 @@
 		DRM_INFO("Connector Table: %d (rn50-power)\n",
 			 rdev->mode_info.connector_table);
 		/* VGA - primary dac */
-		ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
+		ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
 		hpd.hpd = RADEON_HPD_NONE;
 		radeon_add_legacy_encoder(dev,
 					  radeon_get_encoder_id(dev,
@@ -1877,7 +1949,7 @@
 					    DRM_MODE_CONNECTOR_VGA, &ddc_i2c,
 					    CONNECTOR_OBJECT_ID_VGA,
 					    &hpd);
-		ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_CRT2_DDC);
+		ddc_i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0);
 		hpd.hpd = RADEON_HPD_NONE;
 		radeon_add_legacy_encoder(dev,
 					  radeon_get_encoder_id(dev,
@@ -1907,31 +1979,6 @@
 				       struct radeon_i2c_bus_rec *ddc_i2c,
 				       struct radeon_hpd *hpd)
 {
-	struct radeon_device *rdev = dev->dev_private;
-
-	/* XPRESS DDC quirks */
-	if ((rdev->family == CHIP_RS400 ||
-	     rdev->family == CHIP_RS480) &&
-	    ddc_i2c->mask_clk_reg == RADEON_GPIO_CRT2_DDC)
-		*ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_MONID);
-	else if ((rdev->family == CHIP_RS400 ||
-		  rdev->family == CHIP_RS480) &&
-		 ddc_i2c->mask_clk_reg == RADEON_GPIO_MONID) {
-		*ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIOPAD_MASK);
-		ddc_i2c->mask_clk_mask = (0x20 << 8);
-		ddc_i2c->mask_data_mask = 0x80;
-		ddc_i2c->a_clk_mask = (0x20 << 8);
-		ddc_i2c->a_data_mask = 0x80;
-		ddc_i2c->en_clk_mask = (0x20 << 8);
-		ddc_i2c->en_data_mask = 0x80;
-		ddc_i2c->y_clk_mask = (0x20 << 8);
-		ddc_i2c->y_data_mask = 0x80;
-	}
-
-	/* R3xx+ chips don't have GPIO_CRT2_DDC gpio pad */
-	if ((rdev->family >= CHIP_R300) &&
-	    ddc_i2c->mask_clk_reg == RADEON_GPIO_CRT2_DDC)
-		*ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
 
 	/* Certain IBM chipset RN50s have a BIOS reporting two VGAs,
 	   one with VGA DDC and one with CRT2 DDC. - kill the CRT2 DDC one */
@@ -2035,27 +2082,7 @@
 			connector = (tmp >> 12) & 0xf;
 
 			ddc_type = (tmp >> 8) & 0xf;
-			switch (ddc_type) {
-			case DDC_MONID:
-				ddc_i2c =
-					combios_setup_i2c_bus(rdev, RADEON_GPIO_MONID);
-				break;
-			case DDC_DVI:
-				ddc_i2c =
-					combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
-				break;
-			case DDC_VGA:
-				ddc_i2c =
-					combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
-				break;
-			case DDC_CRT2:
-				ddc_i2c =
-					combios_setup_i2c_bus(rdev, RADEON_GPIO_CRT2_DDC);
-				break;
-			default:
-				ddc_i2c.valid = false;
-				break;
-			}
+			ddc_i2c = combios_setup_i2c_bus(rdev, ddc_type, 0, 0);
 
 			switch (connector) {
 			case CONNECTOR_PROPRIETARY_LEGACY:
@@ -2225,7 +2252,7 @@
 									0),
 						  ATOM_DEVICE_DFP1_SUPPORT);
 
-			ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
+			ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
 			hpd.hpd = RADEON_HPD_1;
 			radeon_add_legacy_connector(dev,
 						    0,
@@ -2245,7 +2272,7 @@
 										ATOM_DEVICE_CRT1_SUPPORT,
 										1),
 							  ATOM_DEVICE_CRT1_SUPPORT);
-				ddc_i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
+				ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
 				hpd.hpd = RADEON_HPD_NONE;
 				radeon_add_legacy_connector(dev,
 							    0,
@@ -2278,70 +2305,25 @@
 			if (lcd_ddc_info) {
 				ddc_type = RBIOS8(lcd_ddc_info + 2);
 				switch (ddc_type) {
-				case DDC_MONID:
-					ddc_i2c =
-					    combios_setup_i2c_bus
-						(rdev, RADEON_GPIO_MONID);
-					break;
-				case DDC_DVI:
-					ddc_i2c =
-					    combios_setup_i2c_bus
-						(rdev, RADEON_GPIO_DVI_DDC);
-					break;
-				case DDC_VGA:
-					ddc_i2c =
-					    combios_setup_i2c_bus
-						(rdev, RADEON_GPIO_VGA_DDC);
-					break;
-				case DDC_CRT2:
-					ddc_i2c =
-					    combios_setup_i2c_bus
-						(rdev, RADEON_GPIO_CRT2_DDC);
-					break;
 				case DDC_LCD:
 					ddc_i2c =
-					    combios_setup_i2c_bus
-						(rdev, RADEON_GPIOPAD_MASK);
-					ddc_i2c.mask_clk_mask =
-					    RBIOS32(lcd_ddc_info + 3);
-					ddc_i2c.mask_data_mask =
-					    RBIOS32(lcd_ddc_info + 7);
-					ddc_i2c.a_clk_mask =
-					    RBIOS32(lcd_ddc_info + 3);
-					ddc_i2c.a_data_mask =
-					    RBIOS32(lcd_ddc_info + 7);
-					ddc_i2c.en_clk_mask =
-					    RBIOS32(lcd_ddc_info + 3);
-					ddc_i2c.en_data_mask =
-					    RBIOS32(lcd_ddc_info + 7);
-					ddc_i2c.y_clk_mask =
-					    RBIOS32(lcd_ddc_info + 3);
-					ddc_i2c.y_data_mask =
-					    RBIOS32(lcd_ddc_info + 7);
+						combios_setup_i2c_bus(rdev,
+								      DDC_LCD,
+								      RBIOS32(lcd_ddc_info + 3),
+								      RBIOS32(lcd_ddc_info + 7));
+					radeon_i2c_add(rdev, &ddc_i2c, "LCD");
 					break;
 				case DDC_GPIO:
 					ddc_i2c =
-					    combios_setup_i2c_bus
-						(rdev, RADEON_MDGPIO_MASK);
-					ddc_i2c.mask_clk_mask =
-					    RBIOS32(lcd_ddc_info + 3);
-					ddc_i2c.mask_data_mask =
-					    RBIOS32(lcd_ddc_info + 7);
-					ddc_i2c.a_clk_mask =
-					    RBIOS32(lcd_ddc_info + 3);
-					ddc_i2c.a_data_mask =
-					    RBIOS32(lcd_ddc_info + 7);
-					ddc_i2c.en_clk_mask =
-					    RBIOS32(lcd_ddc_info + 3);
-					ddc_i2c.en_data_mask =
-					    RBIOS32(lcd_ddc_info + 7);
-					ddc_i2c.y_clk_mask =
-					    RBIOS32(lcd_ddc_info + 3);
-					ddc_i2c.y_data_mask =
-					    RBIOS32(lcd_ddc_info + 7);
+						combios_setup_i2c_bus(rdev,
+								      DDC_GPIO,
+								      RBIOS32(lcd_ddc_info + 3),
+								      RBIOS32(lcd_ddc_info + 7));
+					radeon_i2c_add(rdev, &ddc_i2c, "LCD");
 					break;
 				default:
-					ddc_i2c.valid = false;
+					ddc_i2c =
+						combios_setup_i2c_bus(rdev, ddc_type, 0, 0);
 					break;
 				}
 				DRM_DEBUG_KMS("LCD DDC Info Table found!\n");
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 2395c86..47c4b27 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -518,8 +518,6 @@
 {
 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
 
-	if (radeon_connector->ddc_bus)
-		radeon_i2c_destroy(radeon_connector->ddc_bus);
 	if (radeon_connector->edid)
 		kfree(radeon_connector->edid);
 	kfree(radeon_connector->con_priv);
@@ -955,8 +953,6 @@
 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
 	struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
 
-	if (radeon_connector->ddc_bus)
-		radeon_i2c_destroy(radeon_connector->ddc_bus);
 	if (radeon_connector->edid)
 		kfree(radeon_connector->edid);
 	if (radeon_dig_connector->dp_i2c_bus)
@@ -1044,7 +1040,8 @@
 			  bool linkb,
 			  uint32_t igp_lane_info,
 			  uint16_t connector_object_id,
-			  struct radeon_hpd *hpd)
+			  struct radeon_hpd *hpd,
+			  struct radeon_router *router)
 {
 	struct radeon_device *rdev = dev->dev_private;
 	struct drm_connector *connector;
@@ -1069,6 +1066,11 @@
 				radeon_connector->shared_ddc = true;
 				shared_ddc = true;
 			}
+			if (radeon_connector->router_bus && router->valid &&
+			    (radeon_connector->router.router_id == router->router_id)) {
+				radeon_connector->shared_ddc = false;
+				shared_ddc = false;
+			}
 		}
 	}
 
@@ -1083,12 +1085,18 @@
 	radeon_connector->shared_ddc = shared_ddc;
 	radeon_connector->connector_object_id = connector_object_id;
 	radeon_connector->hpd = *hpd;
+	radeon_connector->router = *router;
+	if (router->valid) {
+		radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info);
+		if (!radeon_connector->router_bus)
+			goto failed;
+	}
 	switch (connector_type) {
 	case DRM_MODE_CONNECTOR_VGA:
 		drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
 		drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
 		if (i2c_bus->valid) {
-			radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "VGA");
+			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
 			if (!radeon_connector->ddc_bus)
 				goto failed;
 		}
@@ -1104,7 +1112,7 @@
 		drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
 		drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
 		if (i2c_bus->valid) {
-			radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
+			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
 			if (!radeon_connector->ddc_bus)
 				goto failed;
 		}
@@ -1126,7 +1134,7 @@
 		drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
 		drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
 		if (i2c_bus->valid) {
-			radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
+			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
 			if (!radeon_connector->ddc_bus)
 				goto failed;
 		}
@@ -1156,7 +1164,7 @@
 		drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
 		drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
 		if (i2c_bus->valid) {
-			radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "HDMI");
+			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
 			if (!radeon_connector->ddc_bus)
 				goto failed;
 		}
@@ -1187,10 +1195,7 @@
 				radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch");
 			if (!radeon_dig_connector->dp_i2c_bus)
 				goto failed;
-			if (connector_type == DRM_MODE_CONNECTOR_eDP)
-				radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "eDP");
-			else
-				radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DP");
+			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
 			if (!radeon_connector->ddc_bus)
 				goto failed;
 		}
@@ -1230,7 +1235,7 @@
 		drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
 		drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
 		if (i2c_bus->valid) {
-			radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "LVDS");
+			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
 			if (!radeon_connector->ddc_bus)
 				goto failed;
 		}
@@ -1252,8 +1257,6 @@
 	return;
 
 failed:
-	if (radeon_connector->ddc_bus)
-		radeon_i2c_destroy(radeon_connector->ddc_bus);
 	drm_connector_cleanup(connector);
 	kfree(connector);
 }
@@ -1300,7 +1303,7 @@
 		drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
 		drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
 		if (i2c_bus->valid) {
-			radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "VGA");
+			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
 			if (!radeon_connector->ddc_bus)
 				goto failed;
 		}
@@ -1316,7 +1319,7 @@
 		drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
 		drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
 		if (i2c_bus->valid) {
-			radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
+			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
 			if (!radeon_connector->ddc_bus)
 				goto failed;
 		}
@@ -1332,7 +1335,7 @@
 		drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
 		drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
 		if (i2c_bus->valid) {
-			radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
+			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
 			if (!radeon_connector->ddc_bus)
 				goto failed;
 		}
@@ -1372,7 +1375,7 @@
 		drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
 		drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
 		if (i2c_bus->valid) {
-			radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "LVDS");
+			radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
 			if (!radeon_connector->ddc_bus)
 				goto failed;
 		}
@@ -1393,8 +1396,6 @@
 	return;
 
 failed:
-	if (radeon_connector->ddc_bus)
-		radeon_i2c_destroy(radeon_connector->ddc_bus);
 	drm_connector_cleanup(connector);
 	kfree(connector);
 }
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c
index ae0fb73..fcc79b5 100644
--- a/drivers/gpu/drm/radeon/radeon_cs.c
+++ b/drivers/gpu/drm/radeon/radeon_cs.c
@@ -72,7 +72,7 @@
 			if (p->relocs[i].gobj == NULL) {
 				DRM_ERROR("gem object lookup failed 0x%x\n",
 					  r->handle);
-				return -EINVAL;
+				return -ENOENT;
 			}
 			p->relocs_ptr[i] = &p->relocs[i];
 			p->relocs[i].robj = p->relocs[i].gobj->driver_private;
diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c
index 4eb67c0..5731fc9 100644
--- a/drivers/gpu/drm/radeon/radeon_cursor.c
+++ b/drivers/gpu/drm/radeon/radeon_cursor.c
@@ -170,7 +170,7 @@
 	obj = drm_gem_object_lookup(crtc->dev, file_priv, handle);
 	if (!obj) {
 		DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id);
-		return -EINVAL;
+		return -ENOENT;
 	}
 
 	ret = radeon_gem_object_pin(obj, RADEON_GEM_DOMAIN_VRAM, &gpu_addr);
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index a64811a..4f7a170 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -347,7 +347,8 @@
 		return -ENOMEM;
 	rdev->dummy_page.addr = pci_map_page(rdev->pdev, rdev->dummy_page.page,
 					0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
-	if (!rdev->dummy_page.addr) {
+	if (pci_dma_mapping_error(rdev->pdev, rdev->dummy_page.addr)) {
+		dev_err(&rdev->pdev->dev, "Failed to DMA MAP the dummy page\n");
 		__free_page(rdev->dummy_page.page);
 		rdev->dummy_page.page = NULL;
 		return -ENOMEM;
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 74dac96..5764f4d 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -161,17 +161,13 @@
 }
 
 static void radeon_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
-				  u16 *blue, uint32_t size)
+				  u16 *blue, uint32_t start, uint32_t size)
 {
 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
-	int i;
-
-	if (size != 256) {
-		return;
-	}
+	int end = (start + size > 256) ? 256 : start + size, i;
 
 	/* userspace palettes are always correct as is */
-	for (i = 0; i < 256; i++) {
+	for (i = start; i < end; i++) {
 		radeon_crtc->lut_r[i] = red[i] >> 6;
 		radeon_crtc->lut_g[i] = green[i] >> 6;
 		radeon_crtc->lut_b[i] = blue[i] >> 6;
@@ -319,6 +315,10 @@
 				 radeon_connector->ddc_bus->rec.en_data_reg,
 				 radeon_connector->ddc_bus->rec.y_clk_reg,
 				 radeon_connector->ddc_bus->rec.y_data_reg);
+			if (radeon_connector->router_bus)
+				DRM_INFO("  DDC Router 0x%x/0x%x\n",
+					 radeon_connector->router.mux_control_pin,
+					 radeon_connector->router.mux_state);
 		} else {
 			if (connector->connector_type == DRM_MODE_CONNECTOR_VGA ||
 			    connector->connector_type == DRM_MODE_CONNECTOR_DVII ||
@@ -395,6 +395,10 @@
 	struct radeon_device *rdev = dev->dev_private;
 	int ret = 0;
 
+	/* on hw with routers, select right port */
+	if (radeon_connector->router.valid)
+		radeon_router_select_port(radeon_connector);
+
 	if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
 	    (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) {
 		struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
@@ -425,6 +429,10 @@
 	struct radeon_connector *radeon_connector = to_radeon_connector(connector);
 	int ret = 0;
 
+	/* on hw with routers, select right port */
+	if (radeon_connector->router.valid)
+		radeon_router_select_port(radeon_connector);
+
 	if (!radeon_connector->ddc_bus)
 		return -1;
 	edid = drm_get_edid(connector, &radeon_connector->ddc_bus->adapter);
@@ -876,13 +884,12 @@
 	if (obj ==  NULL) {
 		dev_err(&dev->pdev->dev, "No GEM object associated to handle 0x%08X, "
 			"can't create framebuffer\n", mode_cmd->handle);
-		return NULL;
+		return ERR_PTR(-ENOENT);
 	}
 
 	radeon_fb = kzalloc(sizeof(*radeon_fb), GFP_KERNEL);
-	if (radeon_fb == NULL) {
-		return NULL;
-	}
+	if (radeon_fb == NULL)
+		return ERR_PTR(-ENOMEM);
 
 	radeon_framebuffer_init(dev, radeon_fb, mode_cmd, obj);
 
@@ -1040,6 +1047,9 @@
 		return ret;
 	}
 
+	/* init i2c buses */
+	radeon_i2c_init(rdev);
+
 	/* check combios for a valid hardcoded EDID - Sun servers */
 	if (!rdev->is_atom_bios) {
 		/* check for hardcoded EDID in BIOS */
@@ -1080,6 +1090,8 @@
 		drm_mode_config_cleanup(rdev->ddev);
 		rdev->mode_info.mode_config_initialized = false;
 	}
+	/* free i2c buses */
+	radeon_i2c_fini(rdev);
 }
 
 bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c
index a72a3ee..c578f26 100644
--- a/drivers/gpu/drm/radeon/radeon_gem.c
+++ b/drivers/gpu/drm/radeon/radeon_gem.c
@@ -226,7 +226,7 @@
 	/* just do a BO wait for now */
 	gobj = drm_gem_object_lookup(dev, filp, args->handle);
 	if (gobj == NULL) {
-		return -EINVAL;
+		return -ENOENT;
 	}
 	robj = gobj->driver_private;
 
@@ -245,7 +245,7 @@
 
 	gobj = drm_gem_object_lookup(dev, filp, args->handle);
 	if (gobj == NULL) {
-		return -EINVAL;
+		return -ENOENT;
 	}
 	robj = gobj->driver_private;
 	args->addr_ptr = radeon_bo_mmap_offset(robj);
@@ -264,7 +264,7 @@
 
 	gobj = drm_gem_object_lookup(dev, filp, args->handle);
 	if (gobj == NULL) {
-		return -EINVAL;
+		return -ENOENT;
 	}
 	robj = gobj->driver_private;
 	r = radeon_bo_wait(robj, &cur_placement, true);
@@ -294,7 +294,7 @@
 
 	gobj = drm_gem_object_lookup(dev, filp, args->handle);
 	if (gobj == NULL) {
-		return -EINVAL;
+		return -ENOENT;
 	}
 	robj = gobj->driver_private;
 	r = radeon_bo_wait(robj, NULL, false);
@@ -316,7 +316,7 @@
 	DRM_DEBUG("%d \n", args->handle);
 	gobj = drm_gem_object_lookup(dev, filp, args->handle);
 	if (gobj == NULL)
-		return -EINVAL;
+		return -ENOENT;
 	robj = gobj->driver_private;
 	r = radeon_bo_set_tiling_flags(robj, args->tiling_flags, args->pitch);
 	drm_gem_object_unreference_unlocked(gobj);
@@ -334,7 +334,7 @@
 	DRM_DEBUG("\n");
 	gobj = drm_gem_object_lookup(dev, filp, args->handle);
 	if (gobj == NULL)
-		return -EINVAL;
+		return -ENOENT;
 	rbo = gobj->driver_private;
 	r = radeon_bo_reserve(rbo, false);
 	if (unlikely(r != 0))
diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c
index 5def6f5..bfd2ce5 100644
--- a/drivers/gpu/drm/radeon/radeon_i2c.c
+++ b/drivers/gpu/drm/radeon/radeon_i2c.c
@@ -52,6 +52,10 @@
 		}
 	};
 
+	/* on hw with routers, select right port */
+	if (radeon_connector->router.valid)
+		radeon_router_select_port(radeon_connector);
+
 	ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2);
 	if (ret == 2)
 		return true;
@@ -960,6 +964,59 @@
 	kfree(i2c);
 }
 
+/* Add the default buses */
+void radeon_i2c_init(struct radeon_device *rdev)
+{
+	if (rdev->is_atom_bios)
+		radeon_atombios_i2c_init(rdev);
+	else
+		radeon_combios_i2c_init(rdev);
+}
+
+/* remove all the buses */
+void radeon_i2c_fini(struct radeon_device *rdev)
+{
+	int i;
+
+	for (i = 0; i < RADEON_MAX_I2C_BUS; i++) {
+		if (rdev->i2c_bus[i]) {
+			radeon_i2c_destroy(rdev->i2c_bus[i]);
+			rdev->i2c_bus[i] = NULL;
+		}
+	}
+}
+
+/* Add additional buses */
+void radeon_i2c_add(struct radeon_device *rdev,
+		    struct radeon_i2c_bus_rec *rec,
+		    const char *name)
+{
+	struct drm_device *dev = rdev->ddev;
+	int i;
+
+	for (i = 0; i < RADEON_MAX_I2C_BUS; i++) {
+		if (!rdev->i2c_bus[i]) {
+			rdev->i2c_bus[i] = radeon_i2c_create(dev, rec, name);
+			return;
+		}
+	}
+}
+
+/* looks up bus based on id */
+struct radeon_i2c_chan *radeon_i2c_lookup(struct radeon_device *rdev,
+					  struct radeon_i2c_bus_rec *i2c_bus)
+{
+	int i;
+
+	for (i = 0; i < RADEON_MAX_I2C_BUS; i++) {
+		if (rdev->i2c_bus[i] &&
+		    (rdev->i2c_bus[i]->rec.i2c_id == i2c_bus->i2c_id)) {
+			return rdev->i2c_bus[i];
+		}
+	}
+	return NULL;
+}
+
 struct drm_encoder *radeon_best_encoder(struct drm_connector *connector)
 {
 	return NULL;
@@ -1020,3 +1077,28 @@
 			  addr, val);
 }
 
+/* router switching */
+void radeon_router_select_port(struct radeon_connector *radeon_connector)
+{
+	u8 val;
+
+	if (!radeon_connector->router.valid)
+		return;
+
+	radeon_i2c_get_byte(radeon_connector->router_bus,
+			    radeon_connector->router.i2c_addr,
+			    0x3, &val);
+	val &= radeon_connector->router.mux_control_pin;
+	radeon_i2c_put_byte(radeon_connector->router_bus,
+			    radeon_connector->router.i2c_addr,
+			    0x3, val);
+	radeon_i2c_get_byte(radeon_connector->router_bus,
+			    radeon_connector->router.i2c_addr,
+			    0x1, &val);
+	val &= radeon_connector->router.mux_control_pin;
+	val |= radeon_connector->router.mux_state;
+	radeon_i2c_put_byte(radeon_connector->router_bus,
+			    radeon_connector->router.i2c_addr,
+			    0x1, val);
+}
+
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index ddcd3b1..b1c8ace 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -112,7 +112,9 @@
 
 	info = data;
 	value_ptr = (uint32_t *)((unsigned long)info->value);
-	value = *value_ptr;
+	if (DRM_COPY_FROM_USER(&value, value_ptr, sizeof(value)))
+		return -EFAULT;
+
 	switch (info->request) {
 	case RADEON_INFO_DEVICE_ID:
 		value = dev->pci_device;
@@ -160,13 +162,27 @@
 			return -EINVAL;
 		}
 	case RADEON_INFO_WANT_HYPERZ:
-		mutex_lock(&dev->struct_mutex);
-		if (rdev->hyperz_filp)
-			value = 0;
-		else {
-			rdev->hyperz_filp = filp;
-			value = 1;
+		/* The "value" here is both an input and output parameter.
+		 * If the input value is 1, filp requests hyper-z access.
+		 * If the input value is 0, filp revokes its hyper-z access.
+		 *
+		 * When returning, the value is 1 if filp owns hyper-z access,
+		 * 0 otherwise. */
+		if (value >= 2) {
+			DRM_DEBUG_KMS("WANT_HYPERZ: invalid value %d\n", value);
+			return -EINVAL;
 		}
+		mutex_lock(&dev->struct_mutex);
+		if (value == 1) {
+			/* wants hyper-z */
+			if (!rdev->hyperz_filp)
+				rdev->hyperz_filp = filp;
+		} else if (value == 0) {
+			/* revokes hyper-z */
+			if (rdev->hyperz_filp == filp)
+				rdev->hyperz_filp = NULL;
+		}
+		value = rdev->hyperz_filp == filp ?  1 : 0;
 		mutex_unlock(&dev->struct_mutex);
 		break;
 	default:
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 71aea40..5bbc086 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -82,6 +82,8 @@
 	RADEON_HPD_NONE = 0xff,
 };
 
+#define RADEON_MAX_I2C_BUS 16
+
 /* radeon gpio-based i2c
  * 1. "mask" reg and bits
  *    grabs the gpio pins for software use
@@ -398,6 +400,16 @@
 	struct radeon_gpio_rec gpio;
 };
 
+struct radeon_router {
+	bool valid;
+	u32 router_id;
+	struct radeon_i2c_bus_rec i2c_info;
+	u8 i2c_addr;
+	u8 mux_type;
+	u8 mux_control_pin;
+	u8 mux_state;
+};
+
 struct radeon_connector {
 	struct drm_connector base;
 	uint32_t connector_id;
@@ -413,6 +425,8 @@
 	bool dac_load_detect;
 	uint16_t connector_object_id;
 	struct radeon_hpd hpd;
+	struct radeon_router router;
+	struct radeon_i2c_chan *router_bus;
 };
 
 struct radeon_framebuffer {
@@ -445,6 +459,15 @@
 extern int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
 				uint8_t write_byte, uint8_t *read_byte);
 
+extern void radeon_i2c_init(struct radeon_device *rdev);
+extern void radeon_i2c_fini(struct radeon_device *rdev);
+extern void radeon_combios_i2c_init(struct radeon_device *rdev);
+extern void radeon_atombios_i2c_init(struct radeon_device *rdev);
+extern void radeon_i2c_add(struct radeon_device *rdev,
+			   struct radeon_i2c_bus_rec *rec,
+			   const char *name);
+extern struct radeon_i2c_chan *radeon_i2c_lookup(struct radeon_device *rdev,
+						 struct radeon_i2c_bus_rec *i2c_bus);
 extern struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev,
 						    struct radeon_i2c_bus_rec *rec,
 						    const char *name);
@@ -460,6 +483,7 @@
 				u8 slave_addr,
 				u8 addr,
 				u8 val);
+extern void radeon_router_select_port(struct radeon_connector *radeon_connector);
 extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector);
 extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector);
 
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 95f8b3a..58038f5c 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -472,9 +472,9 @@
 	.attrs = hwmon_attributes,
 };
 
-static void radeon_hwmon_init(struct radeon_device *rdev)
+static int radeon_hwmon_init(struct radeon_device *rdev)
 {
-	int err;
+	int err = 0;
 
 	rdev->pm.int_hwmon_dev = NULL;
 
@@ -483,15 +483,26 @@
 	case THERMAL_TYPE_RV770:
 	case THERMAL_TYPE_EVERGREEN:
 		rdev->pm.int_hwmon_dev = hwmon_device_register(rdev->dev);
+		if (IS_ERR(rdev->pm.int_hwmon_dev)) {
+			err = PTR_ERR(rdev->pm.int_hwmon_dev);
+			dev_err(rdev->dev,
+				"Unable to register hwmon device: %d\n", err);
+			break;
+		}
 		dev_set_drvdata(rdev->pm.int_hwmon_dev, rdev->ddev);
 		err = sysfs_create_group(&rdev->pm.int_hwmon_dev->kobj,
 					 &hwmon_attrgroup);
-		if (err)
-			DRM_ERROR("Unable to create hwmon sysfs file: %d\n", err);
+		if (err) {
+			dev_err(rdev->dev,
+				"Unable to create hwmon sysfs file: %d\n", err);
+			hwmon_device_unregister(rdev->dev);
+		}
 		break;
 	default:
 		break;
 	}
+
+	return err;
 }
 
 static void radeon_hwmon_fini(struct radeon_device *rdev)
@@ -540,6 +551,7 @@
 int radeon_pm_init(struct radeon_device *rdev)
 {
 	int ret;
+
 	/* default to profile method */
 	rdev->pm.pm_method = PM_METHOD_PROFILE;
 	rdev->pm.profile = PM_PROFILE_DEFAULT;
@@ -561,7 +573,9 @@
 	}
 
 	/* set up the internal thermal sensor if applicable */
-	radeon_hwmon_init(rdev);
+	ret = radeon_hwmon_init(rdev);
+	if (ret)
+		return ret;
 	if (rdev->pm.num_power_states > 1) {
 		/* where's the best place to put these? */
 		ret = device_create_file(rdev->dev, &dev_attr_power_profile);
diff --git a/drivers/gpu/drm/radeon/reg_srcs/rv515 b/drivers/gpu/drm/radeon/reg_srcs/rv515
index 8293855..b3f9f1d 100644
--- a/drivers/gpu/drm/radeon/reg_srcs/rv515
+++ b/drivers/gpu/drm/radeon/reg_srcs/rv515
@@ -316,6 +316,7 @@
 0x4BD0 FG_FOG_COLOR_B
 0x4BD4 FG_ALPHA_FUNC
 0x4BD8 FG_DEPTH_SRC
+0x4BE0 FG_ALPHA_VALUE
 0x4C00 US_ALU_CONST_R_0
 0x4C04 US_ALU_CONST_G_0
 0x4C08 US_ALU_CONST_B_0
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 437ac78..64d7f47 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -737,7 +737,7 @@
 
 	if (ret) {
 		DRM_ERROR("failed to create vmw_framebuffer: %i\n", ret);
-		return NULL;
+		return ERR_PTR(ret);
 	}
 	return &vfb->base;
 
@@ -747,7 +747,7 @@
 	ret = vmw_user_dmabuf_lookup(tfile, mode_cmd->handle, &bo);
 	if (ret) {
 		DRM_ERROR("failed to find buffer: %i\n", ret);
-		return NULL;
+		return ERR_PTR(-ENOENT);
 	}
 
 	ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, bo, &vfb,
@@ -758,7 +758,7 @@
 
 	if (ret) {
 		DRM_ERROR("failed to create vmw_framebuffer: %i\n", ret);
-		return NULL;
+		return ERR_PTR(ret);
 	}
 
 	return &vfb->base;
@@ -768,7 +768,7 @@
 	/* vmw_user_surface_lookup takes one ref */
 	vmw_surface_unreference(&surface);
 
-	return NULL;
+	return ERR_PTR(-EINVAL);
 }
 
 static struct drm_mode_config_funcs vmw_kms_funcs = {
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index cfaf690..2ff5cf7 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -79,7 +79,7 @@
 
 static void vmw_ldu_crtc_gamma_set(struct drm_crtc *crtc,
 				   u16 *r, u16 *g, u16 *b,
-				   uint32_t size)
+				   uint32_t start, uint32_t size)
 {
 }
 
diff --git a/drivers/hwmon/ams/ams.h b/drivers/hwmon/ams/ams.h
index b28d7e2..90f094d 100644
--- a/drivers/hwmon/ams/ams.h
+++ b/drivers/hwmon/ams/ams.h
@@ -23,7 +23,7 @@
 
 	/* General properties */
 	struct device_node *of_node;
-	struct of_device *of_dev;
+	struct platform_device *of_dev;
 	char has_device;
 	char vflag;
 	u32 orient1;
diff --git a/drivers/hwmon/mc13783-adc.c b/drivers/hwmon/mc13783-adc.c
index ce3c7bc..d5226c9 100644
--- a/drivers/hwmon/mc13783-adc.c
+++ b/drivers/hwmon/mc13783-adc.c
@@ -18,7 +18,7 @@
  * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-#include <linux/mfd/mc13783-private.h>
+#include <linux/mfd/mc13783.h>
 #include <linux/platform_device.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/kernel.h>
@@ -144,6 +144,14 @@
 	.attrs = mc13783_attr_ts,
 };
 
+static int mc13783_adc_use_touchscreen(struct platform_device *pdev)
+{
+	struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
+	unsigned flags = mc13783_get_flags(priv->mc13783);
+
+	return flags & MC13783_USE_TOUCHSCREEN;
+}
+
 static int __init mc13783_adc_probe(struct platform_device *pdev)
 {
 	struct mc13783_adc_priv *priv;
@@ -162,10 +170,11 @@
 	if (ret)
 		goto out_err_create1;
 
-	if (!(priv->mc13783->flags & MC13783_USE_TOUCHSCREEN))
+	if (!mc13783_adc_use_touchscreen(pdev)) {
 		ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_ts);
 		if (ret)
 			goto out_err_create2;
+	}
 
 	priv->hwmon_dev = hwmon_device_register(&pdev->dev);
 	if (IS_ERR(priv->hwmon_dev)) {
@@ -180,7 +189,7 @@
 
 out_err_register:
 
-	if (!(priv->mc13783->flags & MC13783_USE_TOUCHSCREEN))
+	if (!mc13783_adc_use_touchscreen(pdev))
 		sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts);
 out_err_create2:
 
@@ -199,7 +208,7 @@
 
 	hwmon_device_unregister(priv->hwmon_dev);
 
-	if (!(priv->mc13783->flags & MC13783_USE_TOUCHSCREEN))
+	if (!mc13783_adc_use_touchscreen(pdev))
 		sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts);
 
 	sysfs_remove_group(&pdev->dev.kobj, &mc13783_group);
diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c
index 8964326..d863e13 100644
--- a/drivers/hwmon/ultra45_env.c
+++ b/drivers/hwmon/ultra45_env.c
@@ -234,7 +234,7 @@
 	.attrs = env_attributes,
 };
 
-static int __devinit env_probe(struct of_device *op,
+static int __devinit env_probe(struct platform_device *op,
 			       const struct of_device_id *match)
 {
 	struct env *p = kzalloc(sizeof(*p), GFP_KERNEL);
@@ -276,7 +276,7 @@
 	goto out;
 }
 
-static int __devexit env_remove(struct of_device *op)
+static int __devexit env_remove(struct platform_device *op)
 {
 	struct env *p = dev_get_drvdata(&op->dev);
 
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index d06083f..30f06e9 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -47,6 +47,19 @@
 	  This support is also available as a module.  If so, the module 
 	  will be called i2c-dev.
 
+config I2C_MUX
+	tristate "I2C bus multiplexing support"
+	depends on EXPERIMENTAL
+	help
+	  Say Y here if you want the I2C core to support the ability to
+	  handle multiplexed I2C bus topologies, by presenting each
+	  multiplexed segment as a I2C adapter.
+
+	  This support is also available as a module.  If so, the module
+	  will be called i2c-mux.
+
+source drivers/i2c/muxes/Kconfig
+
 config I2C_HELPER_AUTO
 	bool "Autoselect pertinent helper modules"
 	default y
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index a7d9b4be9..c00fd66 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -6,7 +6,8 @@
 obj-$(CONFIG_I2C)		+= i2c-core.o
 obj-$(CONFIG_I2C_SMBUS)		+= i2c-smbus.o
 obj-$(CONFIG_I2C_CHARDEV)	+= i2c-dev.o
-obj-y				+= algos/ busses/
+obj-$(CONFIG_I2C_MUX)		+= i2c-mux.o
+obj-y				+= algos/ busses/ muxes/
 
 ifeq ($(CONFIG_I2C_DEBUG_CORE),y)
 EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c
index e591de1..f7bd261 100644
--- a/drivers/i2c/busses/i2c-cpm.c
+++ b/drivers/i2c/busses/i2c-cpm.c
@@ -105,7 +105,7 @@
 
 struct cpm_i2c {
 	char *base;
-	struct of_device *ofdev;
+	struct platform_device *ofdev;
 	struct i2c_adapter adap;
 	uint dp_addr;
 	int version; /* CPM1=1, CPM2=2 */
@@ -428,7 +428,7 @@
 
 static int __devinit cpm_i2c_setup(struct cpm_i2c *cpm)
 {
-	struct of_device *ofdev = cpm->ofdev;
+	struct platform_device *ofdev = cpm->ofdev;
 	const u32 *data;
 	int len, ret, i;
 	void __iomem *i2c_base;
@@ -634,7 +634,7 @@
 		cpm_muram_free(cpm->i2c_addr);
 }
 
-static int __devinit cpm_i2c_probe(struct of_device *ofdev,
+static int __devinit cpm_i2c_probe(struct platform_device *ofdev,
 			 const struct of_device_id *match)
 {
 	int result, len;
@@ -687,7 +687,7 @@
 	return result;
 }
 
-static int __devexit cpm_i2c_remove(struct of_device *ofdev)
+static int __devexit cpm_i2c_remove(struct platform_device *ofdev)
 {
 	struct cpm_i2c *cpm = dev_get_drvdata(&ofdev->dev);
 
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
index 1168d61..43ca32f 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.c
+++ b/drivers/i2c/busses/i2c-ibm_iic.c
@@ -661,7 +661,7 @@
 	return (u8)((opb + 9) / 10 - 1);
 }
 
-static int __devinit iic_request_irq(struct of_device *ofdev,
+static int __devinit iic_request_irq(struct platform_device *ofdev,
 				     struct ibm_iic_private *dev)
 {
 	struct device_node *np = ofdev->dev.of_node;
@@ -692,7 +692,7 @@
 /*
  * Register single IIC interface
  */
-static int __devinit iic_probe(struct of_device *ofdev,
+static int __devinit iic_probe(struct platform_device *ofdev,
 			       const struct of_device_id *match)
 {
 	struct device_node *np = ofdev->dev.of_node;
@@ -780,7 +780,7 @@
 /*
  * Cleanup initialized IIC interface
  */
-static int __devexit iic_remove(struct of_device *ofdev)
+static int __devexit iic_remove(struct platform_device *ofdev)
 {
 	struct ibm_iic_private *dev = dev_get_drvdata(&ofdev->dev);
 
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 6545d1c..a1c419a 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -560,7 +560,7 @@
 	.timeout = HZ,
 };
 
-static int __devinit fsl_i2c_probe(struct of_device *op,
+static int __devinit fsl_i2c_probe(struct platform_device *op,
 				   const struct of_device_id *match)
 {
 	struct mpc_i2c *i2c;
@@ -646,7 +646,7 @@
 	return result;
 };
 
-static int __devexit fsl_i2c_remove(struct of_device *op)
+static int __devexit fsl_i2c_remove(struct platform_device *op)
 {
 	struct mpc_i2c *i2c = dev_get_drvdata(&op->dev);
 
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index df937df..6649176 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -20,7 +20,9 @@
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>.
    All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl>
    SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> and
-   Jean Delvare <khali@linux-fr.org> */
+   Jean Delvare <khali@linux-fr.org>
+   Mux support by Rodolfo Giometti <giometti@enneenne.com> and
+   Michael Lawnick <michael.lawnick.ext@nsn.com> */
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -423,13 +425,89 @@
 	return 0;
 }
 
+/* walk up mux tree */
+static int i2c_check_mux_parents(struct i2c_adapter *adapter, int addr)
+{
+	int result;
+
+	result = device_for_each_child(&adapter->dev, &addr,
+					__i2c_check_addr_busy);
+
+	if (!result && i2c_parent_is_i2c_adapter(adapter))
+		result = i2c_check_mux_parents(
+				    to_i2c_adapter(adapter->dev.parent), addr);
+
+	return result;
+}
+
+/* recurse down mux tree */
+static int i2c_check_mux_children(struct device *dev, void *addrp)
+{
+	int result;
+
+	if (dev->type == &i2c_adapter_type)
+		result = device_for_each_child(dev, addrp,
+						i2c_check_mux_children);
+	else
+		result = __i2c_check_addr_busy(dev, addrp);
+
+	return result;
+}
+
 static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr)
 {
-	return device_for_each_child(&adapter->dev, &addr,
-				     __i2c_check_addr_busy);
+	int result = 0;
+
+	if (i2c_parent_is_i2c_adapter(adapter))
+		result = i2c_check_mux_parents(
+				    to_i2c_adapter(adapter->dev.parent), addr);
+
+	if (!result)
+		result = device_for_each_child(&adapter->dev, &addr,
+						i2c_check_mux_children);
+
+	return result;
 }
 
 /**
+ * i2c_lock_adapter - Get exclusive access to an I2C bus segment
+ * @adapter: Target I2C bus segment
+ */
+void i2c_lock_adapter(struct i2c_adapter *adapter)
+{
+	if (i2c_parent_is_i2c_adapter(adapter))
+		i2c_lock_adapter(to_i2c_adapter(adapter->dev.parent));
+	else
+		rt_mutex_lock(&adapter->bus_lock);
+}
+EXPORT_SYMBOL_GPL(i2c_lock_adapter);
+
+/**
+ * i2c_trylock_adapter - Try to get exclusive access to an I2C bus segment
+ * @adapter: Target I2C bus segment
+ */
+static int i2c_trylock_adapter(struct i2c_adapter *adapter)
+{
+	if (i2c_parent_is_i2c_adapter(adapter))
+		return i2c_trylock_adapter(to_i2c_adapter(adapter->dev.parent));
+	else
+		return rt_mutex_trylock(&adapter->bus_lock);
+}
+
+/**
+ * i2c_unlock_adapter - Release exclusive access to an I2C bus segment
+ * @adapter: Target I2C bus segment
+ */
+void i2c_unlock_adapter(struct i2c_adapter *adapter)
+{
+	if (i2c_parent_is_i2c_adapter(adapter))
+		i2c_unlock_adapter(to_i2c_adapter(adapter->dev.parent));
+	else
+		rt_mutex_unlock(&adapter->bus_lock);
+}
+EXPORT_SYMBOL_GPL(i2c_unlock_adapter);
+
+/**
  * i2c_new_device - instantiate an i2c device
  * @adap: the adapter managing the device
  * @info: describes one I2C device; bus_num is ignored
@@ -633,9 +711,9 @@
 		return -EINVAL;
 
 	/* Keep track of the added device */
-	i2c_lock_adapter(adap);
+	mutex_lock(&adap->userspace_clients_lock);
 	list_add_tail(&client->detected, &adap->userspace_clients);
-	i2c_unlock_adapter(adap);
+	mutex_unlock(&adap->userspace_clients_lock);
 	dev_info(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device",
 		 info.type, info.addr);
 
@@ -674,7 +752,7 @@
 
 	/* Make sure the device was added through sysfs */
 	res = -ENOENT;
-	i2c_lock_adapter(adap);
+	mutex_lock(&adap->userspace_clients_lock);
 	list_for_each_entry_safe(client, next, &adap->userspace_clients,
 				 detected) {
 		if (client->addr == addr) {
@@ -687,7 +765,7 @@
 			break;
 		}
 	}
-	i2c_unlock_adapter(adap);
+	mutex_unlock(&adap->userspace_clients_lock);
 
 	if (res < 0)
 		dev_err(dev, "%s: Can't find device in list\n",
@@ -714,10 +792,11 @@
 	NULL
 };
 
-static struct device_type i2c_adapter_type = {
+struct device_type i2c_adapter_type = {
 	.groups		= i2c_adapter_attr_groups,
 	.release	= i2c_adapter_dev_release,
 };
+EXPORT_SYMBOL_GPL(i2c_adapter_type);
 
 #ifdef CONFIG_I2C_COMPAT
 static struct class_compat *i2c_adapter_compat_class;
@@ -760,7 +839,7 @@
 
 static int i2c_register_adapter(struct i2c_adapter *adap)
 {
-	int res = 0, dummy;
+	int res = 0;
 
 	/* Can't register until after driver model init */
 	if (unlikely(WARN_ON(!i2c_bus_type.p))) {
@@ -769,6 +848,7 @@
 	}
 
 	rt_mutex_init(&adap->bus_lock);
+	mutex_init(&adap->userspace_clients_lock);
 	INIT_LIST_HEAD(&adap->userspace_clients);
 
 	/* Set default timeout to 1 second if not already set */
@@ -801,8 +881,7 @@
 
 	/* Notify drivers */
 	mutex_lock(&core_lock);
-	dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,
-				 __process_new_adapter);
+	bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
 	mutex_unlock(&core_lock);
 
 	return 0;
@@ -975,7 +1054,7 @@
 		return res;
 
 	/* Remove devices instantiated from sysfs */
-	i2c_lock_adapter(adap);
+	mutex_lock(&adap->userspace_clients_lock);
 	list_for_each_entry_safe(client, next, &adap->userspace_clients,
 				 detected) {
 		dev_dbg(&adap->dev, "Removing %s at 0x%x\n", client->name,
@@ -983,7 +1062,7 @@
 		list_del(&client->detected);
 		i2c_unregister_device(client);
 	}
-	i2c_unlock_adapter(adap);
+	mutex_unlock(&adap->userspace_clients_lock);
 
 	/* Detach any active clients. This can't fail, thus we do not
 	   checking the returned value. */
@@ -1238,12 +1317,12 @@
 #endif
 
 		if (in_atomic() || irqs_disabled()) {
-			ret = rt_mutex_trylock(&adap->bus_lock);
+			ret = i2c_trylock_adapter(adap);
 			if (!ret)
 				/* I2C activity is ongoing. */
 				return -EAGAIN;
 		} else {
-			rt_mutex_lock(&adap->bus_lock);
+			i2c_lock_adapter(adap);
 		}
 
 		/* Retry automatically on arbitration loss */
@@ -1255,7 +1334,7 @@
 			if (time_after(jiffies, orig_jiffies + adap->timeout))
 				break;
 		}
-		rt_mutex_unlock(&adap->bus_lock);
+		i2c_unlock_adapter(adap);
 
 		return ret;
 	} else {
@@ -1350,13 +1429,17 @@
 				     I2C_SMBUS_BYTE_DATA, &dummy);
 	else
 #endif
-	if ((addr & ~0x07) == 0x30 || (addr & ~0x0f) == 0x50
-	 || !i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK))
-		err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0,
-				     I2C_SMBUS_BYTE, &dummy);
-	else
+	if (!((addr & ~0x07) == 0x30 || (addr & ~0x0f) == 0x50)
+	 && i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK))
 		err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_WRITE, 0,
 				     I2C_SMBUS_QUICK, NULL);
+	else if (i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE))
+		err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0,
+				     I2C_SMBUS_BYTE, &dummy);
+	else {
+		dev_warn(&adap->dev, "No suitable probing method supported\n");
+		err = -EOPNOTSUPP;
+	}
 
 	return err >= 0;
 }
@@ -1437,16 +1520,6 @@
 	if (!(adapter->class & driver->class))
 		goto exit_free;
 
-	/* Stop here if the bus doesn't support probing */
-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE)) {
-		if (address_list[0] == I2C_CLIENT_END)
-			goto exit_free;
-
-		dev_warn(&adapter->dev, "Probing not supported\n");
-		err = -EOPNOTSUPP;
-		goto exit_free;
-	}
-
 	for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) {
 		dev_dbg(&adapter->dev, "found normal entry for adapter %d, "
 			"addr 0x%02x\n", adap_id, address_list[i]);
@@ -1461,18 +1534,23 @@
 	return err;
 }
 
+int i2c_probe_func_quick_read(struct i2c_adapter *adap, unsigned short addr)
+{
+	return i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0,
+			      I2C_SMBUS_QUICK, NULL) >= 0;
+}
+EXPORT_SYMBOL_GPL(i2c_probe_func_quick_read);
+
 struct i2c_client *
 i2c_new_probed_device(struct i2c_adapter *adap,
 		      struct i2c_board_info *info,
-		      unsigned short const *addr_list)
+		      unsigned short const *addr_list,
+		      int (*probe)(struct i2c_adapter *, unsigned short addr))
 {
 	int i;
 
-	/* Stop here if the bus doesn't support probing */
-	if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE)) {
-		dev_err(&adap->dev, "Probing not supported\n");
-		return NULL;
-	}
+	if (!probe)
+		probe = i2c_default_probe;
 
 	for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) {
 		/* Check address validity */
@@ -1490,7 +1568,7 @@
 		}
 
 		/* Test address responsiveness */
-		if (i2c_default_probe(adap, addr_list[i]))
+		if (probe(adap, addr_list[i]))
 			break;
 	}
 
@@ -2002,7 +2080,7 @@
 	flags &= I2C_M_TEN | I2C_CLIENT_PEC;
 
 	if (adapter->algo->smbus_xfer) {
-		rt_mutex_lock(&adapter->bus_lock);
+		i2c_lock_adapter(adapter);
 
 		/* Retry automatically on arbitration loss */
 		orig_jiffies = jiffies;
@@ -2016,7 +2094,7 @@
 				       orig_jiffies + adapter->timeout))
 				break;
 		}
-		rt_mutex_unlock(&adapter->bus_lock);
+		i2c_unlock_adapter(adapter);
 	} else
 		res = i2c_smbus_xfer_emulated(adapter, addr, flags, read_write,
 					      command, protocol, data);
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index e0694e4..5f3a52d 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -167,13 +167,9 @@
 	if (count > 8192)
 		count = 8192;
 
-	tmp = kmalloc(count, GFP_KERNEL);
-	if (tmp == NULL)
-		return -ENOMEM;
-	if (copy_from_user(tmp, buf, count)) {
-		kfree(tmp);
-		return -EFAULT;
-	}
+	tmp = memdup_user(buf, count);
+	if (IS_ERR(tmp))
+		return PTR_ERR(tmp);
 
 	pr_debug("i2c-dev: i2c-%d writing %zu bytes.\n",
 		iminor(file->f_path.dentry->d_inode), count);
@@ -193,12 +189,50 @@
 	return dev->driver ? -EBUSY : 0;
 }
 
+/* walk up mux tree */
+static int i2cdev_check_mux_parents(struct i2c_adapter *adapter, int addr)
+{
+	int result;
+
+	result = device_for_each_child(&adapter->dev, &addr, i2cdev_check);
+
+	if (!result && i2c_parent_is_i2c_adapter(adapter))
+		result = i2cdev_check_mux_parents(
+				    to_i2c_adapter(adapter->dev.parent), addr);
+
+	return result;
+}
+
+/* recurse down mux tree */
+static int i2cdev_check_mux_children(struct device *dev, void *addrp)
+{
+	int result;
+
+	if (dev->type == &i2c_adapter_type)
+		result = device_for_each_child(dev, addrp,
+						i2cdev_check_mux_children);
+	else
+		result = i2cdev_check(dev, addrp);
+
+	return result;
+}
+
 /* This address checking function differs from the one in i2c-core
    in that it considers an address with a registered device, but no
    driver bound to it, as NOT busy. */
 static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
 {
-	return device_for_each_child(&adapter->dev, &addr, i2cdev_check);
+	int result = 0;
+
+	if (i2c_parent_is_i2c_adapter(adapter))
+		result = i2cdev_check_mux_parents(
+				    to_i2c_adapter(adapter->dev.parent), addr);
+
+	if (!result)
+		result = device_for_each_child(&adapter->dev, &addr,
+						i2cdev_check_mux_children);
+
+	return result;
 }
 
 static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
@@ -219,9 +253,7 @@
 	if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
 		return -EINVAL;
 
-	rdwr_pa = (struct i2c_msg *)
-		kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg),
-		GFP_KERNEL);
+	rdwr_pa = kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), GFP_KERNEL);
 	if (!rdwr_pa)
 		return -ENOMEM;
 
@@ -247,15 +279,9 @@
 			break;
 		}
 		data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf;
-		rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL);
-		if (rdwr_pa[i].buf == NULL) {
-			res = -ENOMEM;
-			break;
-		}
-		if (copy_from_user(rdwr_pa[i].buf, data_ptrs[i],
-				   rdwr_pa[i].len)) {
-				++i; /* Needs to be kfreed too */
-				res = -EFAULT;
+		rdwr_pa[i].buf = memdup_user(data_ptrs[i], rdwr_pa[i].len);
+		if (IS_ERR(rdwr_pa[i].buf)) {
+			res = PTR_ERR(rdwr_pa[i].buf);
 			break;
 		}
 	}
diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
new file mode 100644
index 0000000..d32a484
--- /dev/null
+++ b/drivers/i2c/i2c-mux.c
@@ -0,0 +1,165 @@
+/*
+ * Multiplexed I2C bus driver.
+ *
+ * Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it>
+ * Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it>
+ * Copyright (c) 2009-2010 NSN GmbH & Co KG <michael.lawnick.ext@nsn.com>
+ *
+ * Simplifies access to complex multiplexed I2C bus topologies, by presenting
+ * each multiplexed bus segment as an additional I2C adapter.
+ * Supports multi-level mux'ing (mux behind a mux).
+ *
+ * Based on:
+ *	i2c-virt.c from Kumar Gala <galak@kernel.crashing.org>
+ *	i2c-virtual.c from Ken Harrenstien, Copyright (c) 2004 Google, Inc.
+ *	i2c-virtual.c from Brian Kuschak <bkuschak@yahoo.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-mux.h>
+
+/* multiplexer per channel data */
+struct i2c_mux_priv {
+	struct i2c_adapter adap;
+	struct i2c_algorithm algo;
+
+	struct i2c_adapter *parent;
+	void *mux_dev;	/* the mux chip/device */
+	u32  chan_id;	/* the channel id */
+
+	int (*select)(struct i2c_adapter *, void *mux_dev, u32 chan_id);
+	int (*deselect)(struct i2c_adapter *, void *mux_dev, u32 chan_id);
+};
+
+static int i2c_mux_master_xfer(struct i2c_adapter *adap,
+			       struct i2c_msg msgs[], int num)
+{
+	struct i2c_mux_priv *priv = adap->algo_data;
+	struct i2c_adapter *parent = priv->parent;
+	int ret;
+
+	/* Switch to the right mux port and perform the transfer. */
+
+	ret = priv->select(parent, priv->mux_dev, priv->chan_id);
+	if (ret >= 0)
+		ret = parent->algo->master_xfer(parent, msgs, num);
+	if (priv->deselect)
+		priv->deselect(parent, priv->mux_dev, priv->chan_id);
+
+	return ret;
+}
+
+static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
+			      u16 addr, unsigned short flags,
+			      char read_write, u8 command,
+			      int size, union i2c_smbus_data *data)
+{
+	struct i2c_mux_priv *priv = adap->algo_data;
+	struct i2c_adapter *parent = priv->parent;
+	int ret;
+
+	/* Select the right mux port and perform the transfer. */
+
+	ret = priv->select(parent, priv->mux_dev, priv->chan_id);
+	if (ret >= 0)
+		ret = parent->algo->smbus_xfer(parent, addr, flags,
+					read_write, command, size, data);
+	if (priv->deselect)
+		priv->deselect(parent, priv->mux_dev, priv->chan_id);
+
+	return ret;
+}
+
+/* Return the parent's functionality */
+static u32 i2c_mux_functionality(struct i2c_adapter *adap)
+{
+	struct i2c_mux_priv *priv = adap->algo_data;
+	struct i2c_adapter *parent = priv->parent;
+
+	return parent->algo->functionality(parent);
+}
+
+struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
+				void *mux_dev, u32 force_nr, u32 chan_id,
+				int (*select) (struct i2c_adapter *,
+					       void *, u32),
+				int (*deselect) (struct i2c_adapter *,
+						 void *, u32))
+{
+	struct i2c_mux_priv *priv;
+	int ret;
+
+	priv = kzalloc(sizeof(struct i2c_mux_priv), GFP_KERNEL);
+	if (!priv)
+		return NULL;
+
+	/* Set up private adapter data */
+	priv->parent = parent;
+	priv->mux_dev = mux_dev;
+	priv->chan_id = chan_id;
+	priv->select = select;
+	priv->deselect = deselect;
+
+	/* Need to do algo dynamically because we don't know ahead
+	 * of time what sort of physical adapter we'll be dealing with.
+	 */
+	if (parent->algo->master_xfer)
+		priv->algo.master_xfer = i2c_mux_master_xfer;
+	if (parent->algo->smbus_xfer)
+		priv->algo.smbus_xfer = i2c_mux_smbus_xfer;
+	priv->algo.functionality = i2c_mux_functionality;
+
+	/* Now fill out new adapter structure */
+	snprintf(priv->adap.name, sizeof(priv->adap.name),
+		 "i2c-%d-mux (chan_id %d)", i2c_adapter_id(parent), chan_id);
+	priv->adap.owner = THIS_MODULE;
+	priv->adap.id = parent->id;
+	priv->adap.algo = &priv->algo;
+	priv->adap.algo_data = priv;
+	priv->adap.dev.parent = &parent->dev;
+
+	if (force_nr) {
+		priv->adap.nr = force_nr;
+		ret = i2c_add_numbered_adapter(&priv->adap);
+	} else {
+		ret = i2c_add_adapter(&priv->adap);
+	}
+	if (ret < 0) {
+		dev_err(&parent->dev,
+			"failed to add mux-adapter (error=%d)\n",
+			ret);
+		kfree(priv);
+		return NULL;
+	}
+
+	dev_info(&parent->dev, "Added multiplexed i2c bus %d\n",
+		 i2c_adapter_id(&priv->adap));
+
+	return &priv->adap;
+}
+EXPORT_SYMBOL_GPL(i2c_add_mux_adapter);
+
+int i2c_del_mux_adapter(struct i2c_adapter *adap)
+{
+	struct i2c_mux_priv *priv = adap->algo_data;
+	int ret;
+
+	ret = i2c_del_adapter(adap);
+	if (ret < 0)
+		return ret;
+	kfree(priv);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(i2c_del_mux_adapter);
+
+MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
+MODULE_DESCRIPTION("I2C driver for multiplexed I2C busses");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
new file mode 100644
index 0000000..4c9a99c
--- /dev/null
+++ b/drivers/i2c/muxes/Kconfig
@@ -0,0 +1,18 @@
+#
+# Multiplexer I2C chip drivers configuration
+#
+
+menu "Multiplexer I2C Chip support"
+	depends on I2C_MUX
+
+config I2C_MUX_PCA954x
+	tristate "Philips PCA954x I2C Mux/switches"
+	depends on EXPERIMENTAL
+	help
+	  If you say yes here you get support for the Philips PCA954x
+	  I2C mux/switch devices.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called pca954x.
+
+endmenu
diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile
new file mode 100644
index 0000000..bd83b527
--- /dev/null
+++ b/drivers/i2c/muxes/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for multiplexer I2C chip drivers.
+
+obj-$(CONFIG_I2C_MUX_PCA954x)	+= pca954x.o
+
+ifeq ($(CONFIG_I2C_DEBUG_BUS),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff --git a/drivers/i2c/muxes/pca954x.c b/drivers/i2c/muxes/pca954x.c
new file mode 100644
index 0000000..6f9accf
--- /dev/null
+++ b/drivers/i2c/muxes/pca954x.c
@@ -0,0 +1,301 @@
+/*
+ * I2C multiplexer
+ *
+ * Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it>
+ * Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it>
+ *
+ * This module supports the PCA954x series of I2C multiplexer/switch chips
+ * made by Philips Semiconductors.
+ * This includes the:
+ *	 PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, PCA9547
+ *	 and PCA9548.
+ *
+ * These chips are all controlled via the I2C bus itself, and all have a
+ * single 8-bit register. The upstream "parent" bus fans out to two,
+ * four, or eight downstream busses or channels; which of these
+ * are selected is determined by the chip type and register contents. A
+ * mux can select only one sub-bus at a time; a switch can select any
+ * combination simultaneously.
+ *
+ * Based on:
+ *	pca954x.c from Kumar Gala <galak@kernel.crashing.org>
+ * Copyright (C) 2006
+ *
+ * Based on:
+ *	pca954x.c from Ken Harrenstien
+ * Copyright (C) 2004 Google, Inc. (Ken Harrenstien)
+ *
+ * Based on:
+ *	i2c-virtual_cb.c from Brian Kuschak <bkuschak@yahoo.com>
+ * and
+ *	pca9540.c from Jean Delvare <khali@linux-fr.org>.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/i2c-mux.h>
+
+#include <linux/i2c/pca954x.h>
+
+#define PCA954X_MAX_NCHANS 8
+
+enum pca_type {
+	pca_9540,
+	pca_9542,
+	pca_9543,
+	pca_9544,
+	pca_9545,
+	pca_9546,
+	pca_9547,
+	pca_9548,
+};
+
+struct pca954x {
+	enum pca_type type;
+	struct i2c_adapter *virt_adaps[PCA954X_MAX_NCHANS];
+
+	u8 last_chan;		/* last register value */
+};
+
+struct chip_desc {
+	u8 nchans;
+	u8 enable;	/* used for muxes only */
+	enum muxtype {
+		pca954x_ismux = 0,
+		pca954x_isswi
+	} muxtype;
+};
+
+/* Provide specs for the PCA954x types we know about */
+static const struct chip_desc chips[] = {
+	[pca_9540] = {
+		.nchans = 2,
+		.enable = 0x4,
+		.muxtype = pca954x_ismux,
+	},
+	[pca_9543] = {
+		.nchans = 2,
+		.muxtype = pca954x_isswi,
+	},
+	[pca_9544] = {
+		.nchans = 4,
+		.enable = 0x4,
+		.muxtype = pca954x_ismux,
+	},
+	[pca_9545] = {
+		.nchans = 4,
+		.muxtype = pca954x_isswi,
+	},
+	[pca_9547] = {
+		.nchans = 8,
+		.enable = 0x8,
+		.muxtype = pca954x_ismux,
+	},
+	[pca_9548] = {
+		.nchans = 8,
+		.muxtype = pca954x_isswi,
+	},
+};
+
+static const struct i2c_device_id pca954x_id[] = {
+	{ "pca9540", pca_9540 },
+	{ "pca9542", pca_9540 },
+	{ "pca9543", pca_9543 },
+	{ "pca9544", pca_9544 },
+	{ "pca9545", pca_9545 },
+	{ "pca9546", pca_9545 },
+	{ "pca9547", pca_9547 },
+	{ "pca9548", pca_9548 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, pca954x_id);
+
+/* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer()
+   for this as they will try to lock adapter a second time */
+static int pca954x_reg_write(struct i2c_adapter *adap,
+			     struct i2c_client *client, u8 val)
+{
+	int ret = -ENODEV;
+
+	if (adap->algo->master_xfer) {
+		struct i2c_msg msg;
+		char buf[1];
+
+		msg.addr = client->addr;
+		msg.flags = 0;
+		msg.len = 1;
+		buf[0] = val;
+		msg.buf = buf;
+		ret = adap->algo->master_xfer(adap, &msg, 1);
+	} else {
+		union i2c_smbus_data data;
+		ret = adap->algo->smbus_xfer(adap, client->addr,
+					     client->flags,
+					     I2C_SMBUS_WRITE,
+					     val, I2C_SMBUS_BYTE, &data);
+	}
+
+	return ret;
+}
+
+static int pca954x_select_chan(struct i2c_adapter *adap,
+			       void *client, u32 chan)
+{
+	struct pca954x *data = i2c_get_clientdata(client);
+	const struct chip_desc *chip = &chips[data->type];
+	u8 regval;
+	int ret = 0;
+
+	/* we make switches look like muxes, not sure how to be smarter */
+	if (chip->muxtype == pca954x_ismux)
+		regval = chan | chip->enable;
+	else
+		regval = 1 << chan;
+
+	/* Only select the channel if its different from the last channel */
+	if (data->last_chan != regval) {
+		ret = pca954x_reg_write(adap, client, regval);
+		data->last_chan = regval;
+	}
+
+	return ret;
+}
+
+static int pca954x_deselect_mux(struct i2c_adapter *adap,
+				void *client, u32 chan)
+{
+	struct pca954x *data = i2c_get_clientdata(client);
+
+	/* Deselect active channel */
+	data->last_chan = 0;
+	return pca954x_reg_write(adap, client, data->last_chan);
+}
+
+/*
+ * I2C init/probing/exit functions
+ */
+static int __devinit pca954x_probe(struct i2c_client *client,
+				   const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
+	struct pca954x_platform_data *pdata = client->dev.platform_data;
+	int num, force;
+	struct pca954x *data;
+	int ret = -ENODEV;
+
+	if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
+		goto err;
+
+	data = kzalloc(sizeof(struct pca954x), GFP_KERNEL);
+	if (!data) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	i2c_set_clientdata(client, data);
+
+	/* Read the mux register at addr to verify
+	 * that the mux is in fact present.
+	 */
+	if (i2c_smbus_read_byte(client) < 0) {
+		dev_warn(&client->dev, "probe failed\n");
+		goto exit_free;
+	}
+
+	data->type = id->driver_data;
+	data->last_chan = 0;		   /* force the first selection */
+
+	/* Now create an adapter for each channel */
+	for (num = 0; num < chips[data->type].nchans; num++) {
+		force = 0;			  /* dynamic adap number */
+		if (pdata) {
+			if (num < pdata->num_modes)
+				/* force static number */
+				force = pdata->modes[num].adap_id;
+			else
+				/* discard unconfigured channels */
+				break;
+		}
+
+		data->virt_adaps[num] =
+			i2c_add_mux_adapter(adap, client,
+				force, num, pca954x_select_chan,
+				(pdata && pdata->modes[num].deselect_on_exit)
+					? pca954x_deselect_mux : NULL);
+
+		if (data->virt_adaps[num] == NULL) {
+			ret = -ENODEV;
+			dev_err(&client->dev,
+				"failed to register multiplexed adapter"
+				" %d as bus %d\n", num, force);
+			goto virt_reg_failed;
+		}
+	}
+
+	dev_info(&client->dev,
+		 "registered %d multiplexed busses for I2C %s %s\n",
+		 num, chips[data->type].muxtype == pca954x_ismux
+				? "mux" : "switch", client->name);
+
+	return 0;
+
+virt_reg_failed:
+	for (num--; num >= 0; num--)
+		i2c_del_mux_adapter(data->virt_adaps[num]);
+exit_free:
+	kfree(data);
+err:
+	return ret;
+}
+
+static int __devexit pca954x_remove(struct i2c_client *client)
+{
+	struct pca954x *data = i2c_get_clientdata(client);
+	const struct chip_desc *chip = &chips[data->type];
+	int i, err;
+
+	for (i = 0; i < chip->nchans; ++i)
+		if (data->virt_adaps[i]) {
+			err = i2c_del_mux_adapter(data->virt_adaps[i]);
+			if (err)
+				return err;
+			data->virt_adaps[i] = NULL;
+		}
+
+	kfree(data);
+	return 0;
+}
+
+static struct i2c_driver pca954x_driver = {
+	.driver		= {
+		.name	= "pca954x",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= pca954x_probe,
+	.remove		= __devexit_p(pca954x_remove),
+	.id_table	= pca954x_id,
+};
+
+static int __init pca954x_init(void)
+{
+	return i2c_add_driver(&pca954x_driver);
+}
+
+static void __exit pca954x_exit(void)
+{
+	i2c_del_driver(&pca954x_driver);
+}
+
+module_init(pca954x_init);
+module_exit(pca954x_exit);
+
+MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
+MODULE_DESCRIPTION("PCA954x I2C mux/switch driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 3cb9c4e..fa89621 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -177,7 +177,7 @@
 module_param_named(pci_clock, ide_pci_clk, int, 0);
 MODULE_PARM_DESC(pci_clock, "PCI bus clock frequency (in MHz)");
 
-static int ide_set_dev_param_mask(const char *s, struct kernel_param *kp)
+static int ide_set_dev_param_mask(const char *s, const struct kernel_param *kp)
 {
 	int a, b, i, j = 1;
 	unsigned int *dev_param_mask = (unsigned int *)kp->arg;
@@ -200,34 +200,40 @@
 	return 0;
 }
 
+static struct kernel_param_ops param_ops_ide_dev_mask = {
+	.set = ide_set_dev_param_mask
+};
+
+#define param_check_ide_dev_mask(name, p) param_check_uint(name, p)
+
 static unsigned int ide_nodma;
 
-module_param_call(nodma, ide_set_dev_param_mask, NULL, &ide_nodma, 0);
+module_param_named(nodma, ide_nodma, ide_dev_mask, 0);
 MODULE_PARM_DESC(nodma, "disallow DMA for a device");
 
 static unsigned int ide_noflush;
 
-module_param_call(noflush, ide_set_dev_param_mask, NULL, &ide_noflush, 0);
+module_param_named(noflush, ide_noflush, ide_dev_mask, 0);
 MODULE_PARM_DESC(noflush, "disable flush requests for a device");
 
 static unsigned int ide_nohpa;
 
-module_param_call(nohpa, ide_set_dev_param_mask, NULL, &ide_nohpa, 0);
+module_param_named(nohpa, ide_nohpa, ide_dev_mask, 0);
 MODULE_PARM_DESC(nohpa, "disable Host Protected Area for a device");
 
 static unsigned int ide_noprobe;
 
-module_param_call(noprobe, ide_set_dev_param_mask, NULL, &ide_noprobe, 0);
+module_param_named(noprobe, ide_noprobe, ide_dev_mask, 0);
 MODULE_PARM_DESC(noprobe, "skip probing for a device");
 
 static unsigned int ide_nowerr;
 
-module_param_call(nowerr, ide_set_dev_param_mask, NULL, &ide_nowerr, 0);
+module_param_named(nowerr, ide_nowerr, ide_dev_mask, 0);
 MODULE_PARM_DESC(nowerr, "ignore the ATA_DF bit for a device");
 
 static unsigned int ide_cdroms;
 
-module_param_call(cdrom, ide_set_dev_param_mask, NULL, &ide_cdroms, 0);
+module_param_named(cdrom, ide_cdroms, ide_dev_mask, 0);
 MODULE_PARM_DESC(cdrom, "force device as a CD-ROM");
 
 struct chs_geom {
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
index 0136abd..aaf6023 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -112,7 +112,7 @@
 
 struct ehca_shca {
 	struct ib_device ib_device;
-	struct of_device *ofdev;
+	struct platform_device *ofdev;
 	u8 num_ports;
 	int hw_level;
 	struct list_head shca_list;
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index cfc4de7..c240e99 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -713,7 +713,7 @@
 	.attrs = ehca_dev_attrs
 };
 
-static int __devinit ehca_probe(struct of_device *dev,
+static int __devinit ehca_probe(struct platform_device *dev,
 				const struct of_device_id *id)
 {
 	struct ehca_shca *shca;
@@ -879,7 +879,7 @@
 	return -EINVAL;
 }
 
-static int __devexit ehca_remove(struct of_device *dev)
+static int __devexit ehca_remove(struct platform_device *dev)
 {
 	struct ehca_shca *shca = dev_get_drvdata(&dev->dev);
 	unsigned long flags;
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index b171f63..9cc488d2 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -395,6 +395,16 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called sh_keysc.
 
+config KEYBOARD_STMPE
+	tristate "STMPE keypad support"
+	depends on MFD_STMPE
+	help
+	  Say Y here if you want to use the keypad controller on STMPE I/O
+	  expanders.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called stmpe-keypad.
+
 config KEYBOARD_DAVINCI
 	tristate "TI DaVinci Key Scan"
 	depends on ARCH_DAVINCI_DM365
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 1a66d5f..504b591 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -35,6 +35,7 @@
 obj-$(CONFIG_KEYBOARD_QT2160)		+= qt2160.o
 obj-$(CONFIG_KEYBOARD_SAMSUNG)		+= samsung-keypad.o
 obj-$(CONFIG_KEYBOARD_SH_KEYSC)		+= sh_keysc.o
+obj-$(CONFIG_KEYBOARD_STMPE)		+= stmpe-keypad.o
 obj-$(CONFIG_KEYBOARD_STOWAWAY)		+= stowaway.o
 obj-$(CONFIG_KEYBOARD_SUNKBD)		+= sunkbd.o
 obj-$(CONFIG_KEYBOARD_TWL4030)		+= twl4030_keypad.o
diff --git a/drivers/input/keyboard/stmpe-keypad.c b/drivers/input/keyboard/stmpe-keypad.c
new file mode 100644
index 0000000..ab7610c
--- /dev/null
+++ b/drivers/input/keyboard/stmpe-keypad.c
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License, version 2
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/mfd/stmpe.h>
+
+/* These are at the same addresses in all STMPE variants */
+#define STMPE_KPC_COL			0x60
+#define STMPE_KPC_ROW_MSB		0x61
+#define STMPE_KPC_ROW_LSB		0x62
+#define STMPE_KPC_CTRL_MSB		0x63
+#define STMPE_KPC_CTRL_LSB		0x64
+#define STMPE_KPC_COMBI_KEY_0		0x65
+#define STMPE_KPC_COMBI_KEY_1		0x66
+#define STMPE_KPC_COMBI_KEY_2		0x67
+#define STMPE_KPC_DATA_BYTE0		0x68
+#define STMPE_KPC_DATA_BYTE1		0x69
+#define STMPE_KPC_DATA_BYTE2		0x6a
+#define STMPE_KPC_DATA_BYTE3		0x6b
+#define STMPE_KPC_DATA_BYTE4		0x6c
+
+#define STMPE_KPC_CTRL_LSB_SCAN		(0x1 << 0)
+#define STMPE_KPC_CTRL_LSB_DEBOUNCE	(0x7f << 1)
+#define STMPE_KPC_CTRL_MSB_SCAN_COUNT	(0xf << 4)
+
+#define STMPE_KPC_ROW_MSB_ROWS		0xff
+
+#define STMPE_KPC_DATA_UP		(0x1 << 7)
+#define STMPE_KPC_DATA_ROW		(0xf << 3)
+#define STMPE_KPC_DATA_COL		(0x7 << 0)
+#define STMPE_KPC_DATA_NOKEY_MASK	0x78
+
+#define STMPE_KEYPAD_MAX_DEBOUNCE	127
+#define STMPE_KEYPAD_MAX_SCAN_COUNT	15
+
+#define STMPE_KEYPAD_MAX_ROWS		8
+#define STMPE_KEYPAD_MAX_COLS		8
+#define STMPE_KEYPAD_ROW_SHIFT		3
+#define STMPE_KEYPAD_KEYMAP_SIZE	\
+	(STMPE_KEYPAD_MAX_ROWS * STMPE_KEYPAD_MAX_COLS)
+
+/**
+ * struct stmpe_keypad_variant - model-specific attributes
+ * @auto_increment: whether the KPC_DATA_BYTE register address
+ *		    auto-increments on multiple read
+ * @num_data: number of data bytes
+ * @num_normal_data: number of normal keys' data bytes
+ * @max_cols: maximum number of columns supported
+ * @max_rows: maximum number of rows supported
+ * @col_gpios: bitmask of gpios which can be used for columns
+ * @row_gpios: bitmask of gpios which can be used for rows
+ */
+struct stmpe_keypad_variant {
+	bool		auto_increment;
+	int		num_data;
+	int		num_normal_data;
+	int		max_cols;
+	int		max_rows;
+	unsigned int	col_gpios;
+	unsigned int	row_gpios;
+};
+
+static const struct stmpe_keypad_variant stmpe_keypad_variants[] = {
+	[STMPE1601] = {
+		.auto_increment		= true,
+		.num_data		= 5,
+		.num_normal_data	= 3,
+		.max_cols		= 8,
+		.max_rows		= 8,
+		.col_gpios		= 0x000ff,	/* GPIO 0 - 7 */
+		.row_gpios		= 0x0ff00,	/* GPIO 8 - 15 */
+	},
+	[STMPE2401] = {
+		.auto_increment		= false,
+		.num_data		= 3,
+		.num_normal_data	= 2,
+		.max_cols		= 8,
+		.max_rows		= 12,
+		.col_gpios		= 0x0000ff,	/* GPIO 0 - 7*/
+		.row_gpios		= 0x1fef00,	/* GPIO 8-14, 16-20 */
+	},
+	[STMPE2403] = {
+		.auto_increment		= true,
+		.num_data		= 5,
+		.num_normal_data	= 3,
+		.max_cols		= 8,
+		.max_rows		= 12,
+		.col_gpios		= 0x0000ff,	/* GPIO 0 - 7*/
+		.row_gpios		= 0x1fef00,	/* GPIO 8-14, 16-20 */
+	},
+};
+
+struct stmpe_keypad {
+	struct stmpe *stmpe;
+	struct input_dev *input;
+	const struct stmpe_keypad_variant *variant;
+	const struct stmpe_keypad_platform_data *plat;
+
+	unsigned int rows;
+	unsigned int cols;
+
+	unsigned short keymap[STMPE_KEYPAD_KEYMAP_SIZE];
+};
+
+static int stmpe_keypad_read_data(struct stmpe_keypad *keypad, u8 *data)
+{
+	const struct stmpe_keypad_variant *variant = keypad->variant;
+	struct stmpe *stmpe = keypad->stmpe;
+	int ret;
+	int i;
+
+	if (variant->auto_increment)
+		return stmpe_block_read(stmpe, STMPE_KPC_DATA_BYTE0,
+					variant->num_data, data);
+
+	for (i = 0; i < variant->num_data; i++) {
+		ret = stmpe_reg_read(stmpe, STMPE_KPC_DATA_BYTE0 + i);
+		if (ret < 0)
+			return ret;
+
+		data[i] = ret;
+	}
+
+	return 0;
+}
+
+static irqreturn_t stmpe_keypad_irq(int irq, void *dev)
+{
+	struct stmpe_keypad *keypad = dev;
+	struct input_dev *input = keypad->input;
+	const struct stmpe_keypad_variant *variant = keypad->variant;
+	u8 fifo[variant->num_data];
+	int ret;
+	int i;
+
+	ret = stmpe_keypad_read_data(keypad, fifo);
+	if (ret < 0)
+		return IRQ_NONE;
+
+	for (i = 0; i < variant->num_normal_data; i++) {
+		u8 data = fifo[i];
+		int row = (data & STMPE_KPC_DATA_ROW) >> 3;
+		int col = data & STMPE_KPC_DATA_COL;
+		int code = MATRIX_SCAN_CODE(row, col, STMPE_KEYPAD_ROW_SHIFT);
+		bool up = data & STMPE_KPC_DATA_UP;
+
+		if ((data & STMPE_KPC_DATA_NOKEY_MASK)
+			== STMPE_KPC_DATA_NOKEY_MASK)
+			continue;
+
+		input_event(input, EV_MSC, MSC_SCAN, code);
+		input_report_key(input, keypad->keymap[code], !up);
+		input_sync(input);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit stmpe_keypad_altfunc_init(struct stmpe_keypad *keypad)
+{
+	const struct stmpe_keypad_variant *variant = keypad->variant;
+	unsigned int col_gpios = variant->col_gpios;
+	unsigned int row_gpios = variant->row_gpios;
+	struct stmpe *stmpe = keypad->stmpe;
+	unsigned int pins = 0;
+	int i;
+
+	/*
+	 * Figure out which pins need to be set to the keypad alternate
+	 * function.
+	 *
+	 * {cols,rows}_gpios are bitmasks of which pins on the chip can be used
+	 * for the keypad.
+	 *
+	 * keypad->{cols,rows} are a bitmask of which pins (of the ones useable
+	 * for the keypad) are used on the board.
+	 */
+
+	for (i = 0; i < variant->max_cols; i++) {
+		int num = __ffs(col_gpios);
+
+		if (keypad->cols & (1 << i))
+			pins |= 1 << num;
+
+		col_gpios &= ~(1 << num);
+	}
+
+	for (i = 0; i < variant->max_rows; i++) {
+		int num = __ffs(row_gpios);
+
+		if (keypad->rows & (1 << i))
+			pins |= 1 << num;
+
+		row_gpios &= ~(1 << num);
+	}
+
+	return stmpe_set_altfunc(stmpe, pins, STMPE_BLOCK_KEYPAD);
+}
+
+static int __devinit stmpe_keypad_chip_init(struct stmpe_keypad *keypad)
+{
+	const struct stmpe_keypad_platform_data *plat = keypad->plat;
+	const struct stmpe_keypad_variant *variant = keypad->variant;
+	struct stmpe *stmpe = keypad->stmpe;
+	int ret;
+
+	if (plat->debounce_ms > STMPE_KEYPAD_MAX_DEBOUNCE)
+		return -EINVAL;
+
+	if (plat->scan_count > STMPE_KEYPAD_MAX_SCAN_COUNT)
+		return -EINVAL;
+
+	ret = stmpe_enable(stmpe, STMPE_BLOCK_KEYPAD);
+	if (ret < 0)
+		return ret;
+
+	ret = stmpe_keypad_altfunc_init(keypad);
+	if (ret < 0)
+		return ret;
+
+	ret = stmpe_reg_write(stmpe, STMPE_KPC_COL, keypad->cols);
+	if (ret < 0)
+		return ret;
+
+	ret = stmpe_reg_write(stmpe, STMPE_KPC_ROW_LSB, keypad->rows);
+	if (ret < 0)
+		return ret;
+
+	if (variant->max_rows > 8) {
+		ret = stmpe_set_bits(stmpe, STMPE_KPC_ROW_MSB,
+				     STMPE_KPC_ROW_MSB_ROWS,
+				     keypad->rows >> 8);
+		if (ret < 0)
+			return ret;
+	}
+
+	ret = stmpe_set_bits(stmpe, STMPE_KPC_CTRL_MSB,
+			     STMPE_KPC_CTRL_MSB_SCAN_COUNT,
+			     plat->scan_count << 4);
+	if (ret < 0)
+		return ret;
+
+	return stmpe_set_bits(stmpe, STMPE_KPC_CTRL_LSB,
+			      STMPE_KPC_CTRL_LSB_SCAN |
+			      STMPE_KPC_CTRL_LSB_DEBOUNCE,
+			      STMPE_KPC_CTRL_LSB_SCAN |
+			      (plat->debounce_ms << 1));
+}
+
+static int __devinit stmpe_keypad_probe(struct platform_device *pdev)
+{
+	struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
+	struct stmpe_keypad_platform_data *plat;
+	struct stmpe_keypad *keypad;
+	struct input_dev *input;
+	int ret;
+	int irq;
+	int i;
+
+	plat = stmpe->pdata->keypad;
+	if (!plat)
+		return -ENODEV;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	keypad = kzalloc(sizeof(struct stmpe_keypad), GFP_KERNEL);
+	if (!keypad)
+		return -ENOMEM;
+
+	input = input_allocate_device();
+	if (!input) {
+		ret = -ENOMEM;
+		goto out_freekeypad;
+	}
+
+	input->name = "STMPE keypad";
+	input->id.bustype = BUS_I2C;
+	input->dev.parent = &pdev->dev;
+
+	input_set_capability(input, EV_MSC, MSC_SCAN);
+
+	__set_bit(EV_KEY, input->evbit);
+	if (!plat->no_autorepeat)
+		__set_bit(EV_REP, input->evbit);
+
+	input->keycode = keypad->keymap;
+	input->keycodesize = sizeof(keypad->keymap[0]);
+	input->keycodemax = ARRAY_SIZE(keypad->keymap);
+
+	matrix_keypad_build_keymap(plat->keymap_data, STMPE_KEYPAD_ROW_SHIFT,
+				   input->keycode, input->keybit);
+
+	for (i = 0; i < plat->keymap_data->keymap_size; i++) {
+		unsigned int key = plat->keymap_data->keymap[i];
+
+		keypad->cols |= 1 << KEY_COL(key);
+		keypad->rows |= 1 << KEY_ROW(key);
+	}
+
+	keypad->stmpe = stmpe;
+	keypad->plat = plat;
+	keypad->input = input;
+	keypad->variant = &stmpe_keypad_variants[stmpe->partnum];
+
+	ret = stmpe_keypad_chip_init(keypad);
+	if (ret < 0)
+		goto out_freeinput;
+
+	ret = input_register_device(input);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"unable to register input device: %d\n", ret);
+		goto out_freeinput;
+	}
+
+	ret = request_threaded_irq(irq, NULL, stmpe_keypad_irq, IRQF_ONESHOT,
+				   "stmpe-keypad", keypad);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
+		goto out_unregisterinput;
+	}
+
+	platform_set_drvdata(pdev, keypad);
+
+	return 0;
+
+out_unregisterinput:
+	input_unregister_device(input);
+	input = NULL;
+out_freeinput:
+	input_free_device(input);
+out_freekeypad:
+	kfree(keypad);
+	return ret;
+}
+
+static int __devexit stmpe_keypad_remove(struct platform_device *pdev)
+{
+	struct stmpe_keypad *keypad = platform_get_drvdata(pdev);
+	struct stmpe *stmpe = keypad->stmpe;
+	int irq = platform_get_irq(pdev, 0);
+
+	stmpe_disable(stmpe, STMPE_BLOCK_KEYPAD);
+
+	free_irq(irq, keypad);
+	input_unregister_device(keypad->input);
+	platform_set_drvdata(pdev, NULL);
+	kfree(keypad);
+
+	return 0;
+}
+
+static struct platform_driver stmpe_keypad_driver = {
+	.driver.name	= "stmpe-keypad",
+	.driver.owner	= THIS_MODULE,
+	.probe		= stmpe_keypad_probe,
+	.remove		= __devexit_p(stmpe_keypad_remove),
+};
+
+static int __init stmpe_keypad_init(void)
+{
+	return platform_driver_register(&stmpe_keypad_driver);
+}
+module_init(stmpe_keypad_init);
+
+static void __exit stmpe_keypad_exit(void)
+{
+	platform_driver_unregister(&stmpe_keypad_driver);
+}
+module_exit(stmpe_keypad_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("STMPExxxx keypad driver");
+MODULE_AUTHOR("Rabin Vincent <rabin.vincent@stericsson.com>");
diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c
index e148749..2325765 100644
--- a/drivers/input/misc/ati_remote2.c
+++ b/drivers/input/misc/ati_remote2.c
@@ -38,7 +38,8 @@
 };
 
 static int ati_remote2_set_mask(const char *val,
-				struct kernel_param *kp, unsigned int max)
+				const struct kernel_param *kp,
+				unsigned int max)
 {
 	unsigned long mask;
 	int ret;
@@ -59,28 +60,31 @@
 }
 
 static int ati_remote2_set_channel_mask(const char *val,
-					struct kernel_param *kp)
+					const struct kernel_param *kp)
 {
 	pr_debug("%s()\n", __func__);
 
 	return ati_remote2_set_mask(val, kp, ATI_REMOTE2_MAX_CHANNEL_MASK);
 }
 
-static int ati_remote2_get_channel_mask(char *buffer, struct kernel_param *kp)
+static int ati_remote2_get_channel_mask(char *buffer,
+					const struct kernel_param *kp)
 {
 	pr_debug("%s()\n", __func__);
 
 	return sprintf(buffer, "0x%04x", *(unsigned int *)kp->arg);
 }
 
-static int ati_remote2_set_mode_mask(const char *val, struct kernel_param *kp)
+static int ati_remote2_set_mode_mask(const char *val,
+				     const struct kernel_param *kp)
 {
 	pr_debug("%s()\n", __func__);
 
 	return ati_remote2_set_mask(val, kp, ATI_REMOTE2_MAX_MODE_MASK);
 }
 
-static int ati_remote2_get_mode_mask(char *buffer, struct kernel_param *kp)
+static int ati_remote2_get_mode_mask(char *buffer,
+				     const struct kernel_param *kp)
 {
 	pr_debug("%s()\n", __func__);
 
@@ -89,15 +93,19 @@
 
 static unsigned int channel_mask = ATI_REMOTE2_MAX_CHANNEL_MASK;
 #define param_check_channel_mask(name, p) __param_check(name, p, unsigned int)
-#define param_set_channel_mask ati_remote2_set_channel_mask
-#define param_get_channel_mask ati_remote2_get_channel_mask
+static struct kernel_param_ops param_ops_channel_mask = {
+	.set = ati_remote2_set_channel_mask,
+	.get = ati_remote2_get_channel_mask,
+};
 module_param(channel_mask, channel_mask, 0644);
 MODULE_PARM_DESC(channel_mask, "Bitmask of channels to accept <15:Channel16>...<1:Channel2><0:Channel1>");
 
 static unsigned int mode_mask = ATI_REMOTE2_MAX_MODE_MASK;
 #define param_check_mode_mask(name, p) __param_check(name, p, unsigned int)
-#define param_set_mode_mask ati_remote2_set_mode_mask
-#define param_get_mode_mask ati_remote2_get_mode_mask
+static struct kernel_param_ops param_ops_mode_mask = {
+	.set = ati_remote2_set_mode_mask,
+	.get = ati_remote2_get_mode_mask,
+};
 module_param(mode_mask, mode_mask, 0644);
 MODULE_PARM_DESC(mode_mask, "Bitmask of modes to accept <4:PC><3:AUX4><2:AUX3><1:AUX2><0:AUX1>");
 
diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c
index f3bb92e..8e130bf 100644
--- a/drivers/input/misc/sparcspkr.c
+++ b/drivers/input/misc/sparcspkr.c
@@ -173,7 +173,7 @@
 	return 0;
 }
 
-static int sparcspkr_shutdown(struct of_device *dev)
+static int sparcspkr_shutdown(struct platform_device *dev)
 {
 	struct sparcspkr_state *state = dev_get_drvdata(&dev->dev);
 	struct input_dev *input_dev = state->input_dev;
@@ -184,7 +184,7 @@
 	return 0;
 }
 
-static int __devinit bbc_beep_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit bbc_beep_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	struct sparcspkr_state *state;
 	struct bbc_beep_info *info;
@@ -231,7 +231,7 @@
 	return err;
 }
 
-static int __devexit bbc_remove(struct of_device *op)
+static int __devexit bbc_remove(struct platform_device *op)
 {
 	struct sparcspkr_state *state = dev_get_drvdata(&op->dev);
 	struct input_dev *input_dev = state->input_dev;
@@ -269,7 +269,7 @@
 	.shutdown	= sparcspkr_shutdown,
 };
 
-static int __devinit grover_beep_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit grover_beep_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	struct sparcspkr_state *state;
 	struct grover_beep_info *info;
@@ -312,7 +312,7 @@
 	return err;
 }
 
-static int __devexit grover_remove(struct of_device *op)
+static int __devexit grover_remove(struct platform_device *op)
 {
 	struct sparcspkr_state *state = dev_get_drvdata(&op->dev);
 	struct grover_beep_info *info = &state->u.grover;
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 979c502..73a7af2 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -39,11 +39,13 @@
 MODULE_LICENSE("GPL");
 
 static unsigned int psmouse_max_proto = PSMOUSE_AUTO;
-static int psmouse_set_maxproto(const char *val, struct kernel_param *kp);
-static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp);
+static int psmouse_set_maxproto(const char *val, const struct kernel_param *);
+static int psmouse_get_maxproto(char *buffer, const struct kernel_param *kp);
+static struct kernel_param_ops param_ops_proto_abbrev = {
+	.set = psmouse_set_maxproto,
+	.get = psmouse_get_maxproto,
+};
 #define param_check_proto_abbrev(name, p)	__param_check(name, p, unsigned int)
-#define param_set_proto_abbrev			psmouse_set_maxproto
-#define param_get_proto_abbrev			psmouse_get_maxproto
 module_param_named(proto, psmouse_max_proto, proto_abbrev, 0644);
 MODULE_PARM_DESC(proto, "Highest protocol extension to probe (bare, imps, exps, any). Useful for KVM switches.");
 
@@ -1679,7 +1681,7 @@
 }
 
 
-static int psmouse_set_maxproto(const char *val, struct kernel_param *kp)
+static int psmouse_set_maxproto(const char *val, const struct kernel_param *kp)
 {
 	const struct psmouse_protocol *proto;
 
@@ -1696,7 +1698,7 @@
 	return 0;
 }
 
-static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp)
+static int psmouse_get_maxproto(char *buffer, const struct kernel_param *kp)
 {
 	int type = *((unsigned int *)kp->arg);
 
diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h
index cb2a24b..c5cc450 100644
--- a/drivers/input/serio/i8042-sparcio.h
+++ b/drivers/input/serio/i8042-sparcio.h
@@ -49,7 +49,7 @@
 #define OBP_PS2MS_NAME1		"kdmouse"
 #define OBP_PS2MS_NAME2		"mouse"
 
-static int __devinit sparc_i8042_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit sparc_i8042_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	struct device_node *dp = op->dev.of_node;
 
@@ -57,7 +57,7 @@
 	while (dp) {
 		if (!strcmp(dp->name, OBP_PS2KBD_NAME1) ||
 		    !strcmp(dp->name, OBP_PS2KBD_NAME2)) {
-			struct of_device *kbd = of_find_device_by_node(dp);
+			struct platform_device *kbd = of_find_device_by_node(dp);
 			unsigned int irq = kbd->archdata.irqs[0];
 			if (irq == 0xffffffff)
 				irq = op->archdata.irqs[0];
@@ -67,7 +67,7 @@
 			kbd_res = &kbd->resource[0];
 		} else if (!strcmp(dp->name, OBP_PS2MS_NAME1) ||
 			   !strcmp(dp->name, OBP_PS2MS_NAME2)) {
-			struct of_device *ms = of_find_device_by_node(dp);
+			struct platform_device *ms = of_find_device_by_node(dp);
 			unsigned int irq = ms->archdata.irqs[0];
 			if (irq == 0xffffffff)
 				irq = op->archdata.irqs[0];
@@ -80,7 +80,7 @@
 	return 0;
 }
 
-static int __devexit sparc_i8042_remove(struct of_device *op)
+static int __devexit sparc_i8042_remove(struct platform_device *op)
 {
 	of_iounmap(kbd_res, kbd_iobase, 8);
 
diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c
index e2c028d..bb14449 100644
--- a/drivers/input/serio/xilinx_ps2.c
+++ b/drivers/input/serio/xilinx_ps2.c
@@ -232,7 +232,7 @@
  * It returns 0, if the driver is bound to the PS/2 device, or a negative
  * value if there is an error.
  */
-static int __devinit xps2_of_probe(struct of_device *ofdev,
+static int __devinit xps2_of_probe(struct platform_device *ofdev,
 				   const struct of_device_id *match)
 {
 	struct resource r_irq; /* Interrupt resources */
@@ -332,7 +332,7 @@
  * if the driver module is being unloaded. It frees any resources allocated to
  * the device.
  */
-static int __devexit xps2_of_remove(struct of_device *of_dev)
+static int __devexit xps2_of_remove(struct platform_device *of_dev)
 {
 	struct device *dev = &of_dev->dev;
 	struct xps2data *drvdata = dev_get_drvdata(dev);
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 61f3518..0069d97 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -628,4 +628,14 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called tps6507x_ts.
 
+config TOUCHSCREEN_STMPE
+	tristate "STMicroelectronics STMPE touchscreens"
+	depends on MFD_STMPE
+	help
+	  Say Y here if you want support for STMicroelectronics
+	  STMPE touchscreen controllers.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called stmpe-ts.
+
 endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index bd6f30b4..28217e1 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -36,6 +36,7 @@
 obj-$(CONFIG_TOUCHSCREEN_PENMOUNT)	+= penmount.o
 obj-$(CONFIG_TOUCHSCREEN_QT602240)	+= qt602240_ts.o
 obj-$(CONFIG_TOUCHSCREEN_S3C2410)	+= s3c2410_ts.o
+obj-$(CONFIG_TOUCHSCREEN_STMPE)		+= stmpe-ts.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213)	+= touchit213.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)	+= touchright.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN)	+= touchwin.o
diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c
new file mode 100644
index 0000000..656148e
--- /dev/null
+++ b/drivers/input/touchscreen/stmpe-ts.c
@@ -0,0 +1,397 @@
+/* STMicroelectronics STMPE811 Touchscreen Driver
+ *
+ * (C) 2010 Luotao Fu <l.fu@pengutronix.de>
+ * All rights reserved.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+
+#include <linux/mfd/stmpe.h>
+
+/* Register layouts and functionalities are identical on all stmpexxx variants
+ * with touchscreen controller
+ */
+#define STMPE_REG_INT_STA		0x0B
+#define STMPE_REG_ADC_CTRL1		0x20
+#define STMPE_REG_ADC_CTRL2		0x21
+#define STMPE_REG_TSC_CTRL		0x40
+#define STMPE_REG_TSC_CFG		0x41
+#define STMPE_REG_FIFO_TH		0x4A
+#define STMPE_REG_FIFO_STA		0x4B
+#define STMPE_REG_FIFO_SIZE		0x4C
+#define STMPE_REG_TSC_DATA_XYZ		0x52
+#define STMPE_REG_TSC_FRACTION_Z	0x56
+#define STMPE_REG_TSC_I_DRIVE		0x58
+
+#define OP_MOD_XYZ			0
+
+#define STMPE_TSC_CTRL_TSC_EN		(1<<0)
+
+#define STMPE_FIFO_STA_RESET		(1<<0)
+
+#define STMPE_IRQ_TOUCH_DET		0
+
+#define SAMPLE_TIME(x)			((x & 0xf) << 4)
+#define MOD_12B(x)			((x & 0x1) << 3)
+#define REF_SEL(x)			((x & 0x1) << 1)
+#define ADC_FREQ(x)			(x & 0x3)
+#define AVE_CTRL(x)			((x & 0x3) << 6)
+#define DET_DELAY(x)			((x & 0x7) << 3)
+#define SETTLING(x)			(x & 0x7)
+#define FRACTION_Z(x)			(x & 0x7)
+#define I_DRIVE(x)			(x & 0x1)
+#define OP_MODE(x)			((x & 0x7) << 1)
+
+#define STMPE_TS_NAME			"stmpe-ts"
+#define XY_MASK				0xfff
+
+struct stmpe_touch {
+	struct stmpe *stmpe;
+	struct input_dev *idev;
+	struct delayed_work work;
+	struct device *dev;
+	u8 sample_time;
+	u8 mod_12b;
+	u8 ref_sel;
+	u8 adc_freq;
+	u8 ave_ctrl;
+	u8 touch_det_delay;
+	u8 settling;
+	u8 fraction_z;
+	u8 i_drive;
+};
+
+static int __stmpe_reset_fifo(struct stmpe *stmpe)
+{
+	int ret;
+
+	ret = stmpe_set_bits(stmpe, STMPE_REG_FIFO_STA,
+			STMPE_FIFO_STA_RESET, STMPE_FIFO_STA_RESET);
+	if (ret)
+		return ret;
+
+	return stmpe_set_bits(stmpe, STMPE_REG_FIFO_STA,
+			STMPE_FIFO_STA_RESET, 0);
+}
+
+static void stmpe_work(struct work_struct *work)
+{
+	int int_sta;
+	u32 timeout = 40;
+
+	struct stmpe_touch *ts =
+	    container_of(work, struct stmpe_touch, work.work);
+
+	int_sta = stmpe_reg_read(ts->stmpe, STMPE_REG_INT_STA);
+
+	/*
+	 * touch_det sometimes get desasserted or just get stuck. This appears
+	 * to be a silicon bug, We still have to clearify this with the
+	 * manufacture. As a workaround We release the key anyway if the
+	 * touch_det keeps coming in after 4ms, while the FIFO contains no value
+	 * during the whole time.
+	 */
+	while ((int_sta & (1 << STMPE_IRQ_TOUCH_DET)) && (timeout > 0)) {
+		timeout--;
+		int_sta = stmpe_reg_read(ts->stmpe, STMPE_REG_INT_STA);
+		udelay(100);
+	}
+
+	/* reset the FIFO before we report release event */
+	__stmpe_reset_fifo(ts->stmpe);
+
+	input_report_abs(ts->idev, ABS_PRESSURE, 0);
+	input_sync(ts->idev);
+}
+
+static irqreturn_t stmpe_ts_handler(int irq, void *data)
+{
+	u8 data_set[4];
+	int x, y, z;
+	struct stmpe_touch *ts = data;
+
+	/*
+	 * Cancel scheduled polling for release if we have new value
+	 * available. Wait if the polling is already running.
+	 */
+	cancel_delayed_work_sync(&ts->work);
+
+	/*
+	 * The FIFO sometimes just crashes and stops generating interrupts. This
+	 * appears to be a silicon bug. We still have to clearify this with
+	 * the manufacture. As a workaround we disable the TSC while we are
+	 * collecting data and flush the FIFO after reading
+	 */
+	stmpe_set_bits(ts->stmpe, STMPE_REG_TSC_CTRL,
+				STMPE_TSC_CTRL_TSC_EN, 0);
+
+	stmpe_block_read(ts->stmpe, STMPE_REG_TSC_DATA_XYZ, 4, data_set);
+
+	x = (data_set[0] << 4) | (data_set[1] >> 4);
+	y = ((data_set[1] & 0xf) << 8) | data_set[2];
+	z = data_set[3];
+
+	input_report_abs(ts->idev, ABS_X, x);
+	input_report_abs(ts->idev, ABS_Y, y);
+	input_report_abs(ts->idev, ABS_PRESSURE, z);
+	input_sync(ts->idev);
+
+       /* flush the FIFO after we have read out our values. */
+	__stmpe_reset_fifo(ts->stmpe);
+
+	/* reenable the tsc */
+	stmpe_set_bits(ts->stmpe, STMPE_REG_TSC_CTRL,
+			STMPE_TSC_CTRL_TSC_EN, STMPE_TSC_CTRL_TSC_EN);
+
+	/* start polling for touch_det to detect release */
+	schedule_delayed_work(&ts->work, HZ / 50);
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit stmpe_init_hw(struct stmpe_touch *ts)
+{
+	int ret;
+	u8 adc_ctrl1, adc_ctrl1_mask, tsc_cfg, tsc_cfg_mask;
+	struct stmpe *stmpe = ts->stmpe;
+	struct device *dev = ts->dev;
+
+	ret = stmpe_enable(stmpe, STMPE_BLOCK_TOUCHSCREEN | STMPE_BLOCK_ADC);
+	if (ret) {
+		dev_err(dev, "Could not enable clock for ADC and TS\n");
+		return ret;
+	}
+
+	adc_ctrl1 = SAMPLE_TIME(ts->sample_time) | MOD_12B(ts->mod_12b) |
+		REF_SEL(ts->ref_sel);
+	adc_ctrl1_mask = SAMPLE_TIME(0xff) | MOD_12B(0xff) | REF_SEL(0xff);
+
+	ret = stmpe_set_bits(stmpe, STMPE_REG_ADC_CTRL1,
+			adc_ctrl1_mask, adc_ctrl1);
+	if (ret) {
+		dev_err(dev, "Could not setup ADC\n");
+		return ret;
+	}
+
+	ret = stmpe_set_bits(stmpe, STMPE_REG_ADC_CTRL2,
+			ADC_FREQ(0xff), ADC_FREQ(ts->adc_freq));
+	if (ret) {
+		dev_err(dev, "Could not setup ADC\n");
+		return ret;
+	}
+
+	tsc_cfg = AVE_CTRL(ts->ave_ctrl) | DET_DELAY(ts->touch_det_delay) |
+			SETTLING(ts->settling);
+	tsc_cfg_mask = AVE_CTRL(0xff) | DET_DELAY(0xff) | SETTLING(0xff);
+
+	ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_CFG, tsc_cfg_mask, tsc_cfg);
+	if (ret) {
+		dev_err(dev, "Could not config touch\n");
+		return ret;
+	}
+
+	ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_FRACTION_Z,
+			FRACTION_Z(0xff), FRACTION_Z(ts->fraction_z));
+	if (ret) {
+		dev_err(dev, "Could not config touch\n");
+		return ret;
+	}
+
+	ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_I_DRIVE,
+			I_DRIVE(0xff), I_DRIVE(ts->i_drive));
+	if (ret) {
+		dev_err(dev, "Could not config touch\n");
+		return ret;
+	}
+
+	/* set FIFO to 1 for single point reading */
+	ret = stmpe_reg_write(stmpe, STMPE_REG_FIFO_TH, 1);
+	if (ret) {
+		dev_err(dev, "Could not set FIFO\n");
+		return ret;
+	}
+
+	ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_CTRL,
+			OP_MODE(0xff), OP_MODE(OP_MOD_XYZ));
+	if (ret) {
+		dev_err(dev, "Could not set mode\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int stmpe_ts_open(struct input_dev *dev)
+{
+	struct stmpe_touch *ts = input_get_drvdata(dev);
+	int ret = 0;
+
+	ret = __stmpe_reset_fifo(ts->stmpe);
+	if (ret)
+		return ret;
+
+	return stmpe_set_bits(ts->stmpe, STMPE_REG_TSC_CTRL,
+			STMPE_TSC_CTRL_TSC_EN, STMPE_TSC_CTRL_TSC_EN);
+}
+
+static void stmpe_ts_close(struct input_dev *dev)
+{
+	struct stmpe_touch *ts = input_get_drvdata(dev);
+
+	cancel_delayed_work_sync(&ts->work);
+
+	stmpe_set_bits(ts->stmpe, STMPE_REG_TSC_CTRL,
+			STMPE_TSC_CTRL_TSC_EN, 0);
+}
+
+static int __devinit stmpe_input_probe(struct platform_device *pdev)
+{
+	struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
+	struct stmpe_platform_data *pdata = stmpe->pdata;
+	struct stmpe_touch *ts;
+	struct input_dev *idev;
+	struct stmpe_ts_platform_data *ts_pdata = NULL;
+	int ret = 0;
+	int ts_irq;
+
+	ts_irq = platform_get_irq_byname(pdev, "FIFO_TH");
+	if (ts_irq < 0)
+		return ts_irq;
+
+	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+	if (!ts)
+		goto err_out;
+
+	idev = input_allocate_device();
+	if (!idev)
+		goto err_free_ts;
+
+	platform_set_drvdata(pdev, ts);
+	ts->stmpe = stmpe;
+	ts->idev = idev;
+	ts->dev = &pdev->dev;
+
+	if (pdata)
+		ts_pdata = pdata->ts;
+
+	if (ts_pdata) {
+		ts->sample_time = ts_pdata->sample_time;
+		ts->mod_12b = ts_pdata->mod_12b;
+		ts->ref_sel = ts_pdata->ref_sel;
+		ts->adc_freq = ts_pdata->adc_freq;
+		ts->ave_ctrl = ts_pdata->ave_ctrl;
+		ts->touch_det_delay = ts_pdata->touch_det_delay;
+		ts->settling = ts_pdata->settling;
+		ts->fraction_z = ts_pdata->fraction_z;
+		ts->i_drive = ts_pdata->i_drive;
+	}
+
+	INIT_DELAYED_WORK(&ts->work, stmpe_work);
+
+	ret = request_threaded_irq(ts_irq, NULL, stmpe_ts_handler,
+			IRQF_ONESHOT, STMPE_TS_NAME, ts);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to request IRQ %d\n", ts_irq);
+		goto err_free_input;
+	}
+
+	ret = stmpe_init_hw(ts);
+	if (ret)
+		goto err_free_irq;
+
+	idev->name = STMPE_TS_NAME;
+	idev->id.bustype = BUS_I2C;
+	idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+	idev->open = stmpe_ts_open;
+	idev->close = stmpe_ts_close;
+
+	input_set_drvdata(idev, ts);
+
+	input_set_abs_params(idev, ABS_X, 0, XY_MASK, 0, 0);
+	input_set_abs_params(idev, ABS_Y, 0, XY_MASK, 0, 0);
+	input_set_abs_params(idev, ABS_PRESSURE, 0x0, 0xff, 0, 0);
+
+	ret = input_register_device(idev);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not register input device\n");
+		goto err_free_irq;
+	}
+
+	return ret;
+
+err_free_irq:
+	free_irq(ts_irq, ts);
+err_free_input:
+	input_free_device(idev);
+	platform_set_drvdata(pdev, NULL);
+err_free_ts:
+	kfree(ts);
+err_out:
+	return ret;
+}
+
+static int __devexit stmpe_ts_remove(struct platform_device *pdev)
+{
+	struct stmpe_touch *ts = platform_get_drvdata(pdev);
+	unsigned int ts_irq = platform_get_irq_byname(pdev, "FIFO_TH");
+
+	stmpe_disable(ts->stmpe, STMPE_BLOCK_TOUCHSCREEN);
+
+	free_irq(ts_irq, ts);
+
+	platform_set_drvdata(pdev, NULL);
+
+	input_unregister_device(ts->idev);
+	input_free_device(ts->idev);
+
+	kfree(ts);
+
+	return 0;
+}
+
+static struct platform_driver stmpe_ts_driver = {
+	.driver = {
+		   .name = STMPE_TS_NAME,
+		   .owner = THIS_MODULE,
+		   },
+	.probe = stmpe_input_probe,
+	.remove = __devexit_p(stmpe_ts_remove),
+};
+
+static int __init stmpe_ts_init(void)
+{
+	return platform_driver_register(&stmpe_ts_driver);
+}
+
+module_init(stmpe_ts_init);
+
+static void __exit stmpe_ts_exit(void)
+{
+	platform_driver_unregister(&stmpe_ts_driver);
+}
+
+module_exit(stmpe_ts_exit);
+
+MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
+MODULE_DESCRIPTION("STMPEXXX touchscreen driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" STMPE_TS_NAME);
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index cc22eee..ea57e05 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -224,7 +224,7 @@
 	struct gpio_led_data led_data[];
 };
 
-static int __devinit of_gpio_leds_probe(struct of_device *ofdev,
+static int __devinit of_gpio_leds_probe(struct platform_device *ofdev,
 					const struct of_device_id *match)
 {
 	struct device_node *np = ofdev->dev.of_node, *child;
@@ -283,7 +283,7 @@
 	return ret;
 }
 
-static int __devexit of_gpio_leds_remove(struct of_device *ofdev)
+static int __devexit of_gpio_leds_remove(struct platform_device *ofdev)
 {
 	struct gpio_led_of_platform_data *pdata = dev_get_drvdata(&ofdev->dev);
 	int i;
diff --git a/drivers/macintosh/macio_sysfs.c b/drivers/macintosh/macio_sysfs.c
index 6024038..8eb40af 100644
--- a/drivers/macintosh/macio_sysfs.c
+++ b/drivers/macintosh/macio_sysfs.c
@@ -15,7 +15,7 @@
 static ssize_t
 compatible_show (struct device *dev, struct device_attribute *attr, char *buf)
 {
-	struct of_device *of;
+	struct platform_device *of;
 	const char *compat;
 	int cplen;
 	int length = 0;
@@ -52,9 +52,9 @@
 static ssize_t devspec_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
-	struct of_device *ofdev;
+	struct platform_device *ofdev;
 
-	ofdev = to_of_device(dev);
+	ofdev = to_platform_device(dev);
 	return sprintf(buf, "%s\n", ofdev->dev.of_node->full_name);
 }
 
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index 2506c95..e58c3d3 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -75,7 +75,7 @@
 struct smu_device {
 	spinlock_t		lock;
 	struct device_node	*of_node;
-	struct of_device	*of_dev;
+	struct platform_device	*of_dev;
 	int			doorbell;	/* doorbell gpio */
 	u32 __iomem		*db_buf;	/* doorbell buffer */
 	struct device_node	*db_node;
@@ -645,7 +645,7 @@
 
 static DECLARE_WORK(smu_expose_childs_work, smu_expose_childs);
 
-static int smu_platform_probe(struct of_device* dev,
+static int smu_platform_probe(struct platform_device* dev,
 			      const struct of_device_id *match)
 {
 	if (!smu)
@@ -695,7 +695,7 @@
 
 device_initcall(smu_init_sysfs);
 
-struct of_device *smu_get_ofdev(void)
+struct platform_device *smu_get_ofdev(void)
 {
 	if (!smu)
 		return NULL;
diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
index c42eeb4..d0d2213 100644
--- a/drivers/macintosh/therm_adt746x.c
+++ b/drivers/macintosh/therm_adt746x.c
@@ -84,7 +84,7 @@
 
 static enum {ADT7460, ADT7467} therm_type;
 static int therm_bus, therm_address;
-static struct of_device * of_dev;
+static struct platform_device * of_dev;
 static struct thermostat* thermostat;
 static struct task_struct *thread_therm = NULL;
 
diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c
index e60605b..4454927 100644
--- a/drivers/macintosh/therm_pm72.c
+++ b/drivers/macintosh/therm_pm72.c
@@ -148,7 +148,7 @@
  * Driver statics
  */
 
-static struct of_device *		of_dev;
+static struct platform_device *		of_dev;
 static struct i2c_adapter *		u3_0;
 static struct i2c_adapter *		u3_1;
 static struct i2c_adapter *		k2;
@@ -2210,7 +2210,7 @@
 	}
 }
 
-static int fcu_of_probe(struct of_device* dev, const struct of_device_id *match)
+static int fcu_of_probe(struct platform_device* dev, const struct of_device_id *match)
 {
 	state = state_detached;
 
@@ -2221,7 +2221,7 @@
 	return i2c_add_driver(&therm_pm72_driver);
 }
 
-static int fcu_of_remove(struct of_device* dev)
+static int fcu_of_remove(struct platform_device* dev)
 {
 	i2c_del_driver(&therm_pm72_driver);
 
diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c
index 5c9367a..c89f396 100644
--- a/drivers/macintosh/therm_windtunnel.c
+++ b/drivers/macintosh/therm_windtunnel.c
@@ -52,7 +52,7 @@
 	struct task_struct	*poll_task;
 	
 	struct mutex	 	lock;
-	struct of_device	*of_dev;
+	struct platform_device	*of_dev;
 	
 	struct i2c_client	*thermostat;
 	struct i2c_client	*fan;
@@ -322,10 +322,10 @@
 
 		memset(&info, 0, sizeof(struct i2c_board_info));
 		strlcpy(info.type, "therm_ds1775", I2C_NAME_SIZE);
-		i2c_new_probed_device(adapter, &info, scan_ds1775);
+		i2c_new_probed_device(adapter, &info, scan_ds1775, NULL);
 
 		strlcpy(info.type, "therm_adm1030", I2C_NAME_SIZE);
-		i2c_new_probed_device(adapter, &info, scan_adm1030);
+		i2c_new_probed_device(adapter, &info, scan_adm1030, NULL);
 
 		if( x.thermostat && x.fan ) {
 			x.running = 1;
@@ -444,13 +444,13 @@
 /************************************************************************/
 
 static int
-therm_of_probe( struct of_device *dev, const struct of_device_id *match )
+therm_of_probe( struct platform_device *dev, const struct of_device_id *match )
 {
 	return i2c_add_driver( &g4fan_driver );
 }
 
 static int
-therm_of_remove( struct of_device *dev )
+therm_of_remove( struct platform_device *dev )
 {
 	i2c_del_driver( &g4fan_driver );
 	return 0;
diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c
index 407fa61..685d659 100644
--- a/drivers/media/video/bt8xx/bttv-i2c.c
+++ b/drivers/media/video/bt8xx/bttv-i2c.c
@@ -411,7 +411,7 @@
 
 		memset(&info, 0, sizeof(struct i2c_board_info));
 		strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
-		i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list);
+		i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list, NULL);
 	}
 }
 
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c
index 809f7d3..73ce90c 100644
--- a/drivers/media/video/cx18/cx18-i2c.c
+++ b/drivers/media/video/cx18/cx18-i2c.c
@@ -117,7 +117,8 @@
 		break;
 	}
 
-	return i2c_new_probed_device(adap, &info, addr_list) == NULL ? -1 : 0;
+	return i2c_new_probed_device(adap, &info, addr_list, NULL) == NULL ?
+	       -1 : 0;
 }
 
 int cx18_i2c_register(struct cx18 *cx, unsigned idx)
diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c
index 1a39148..ed3d8f5 100644
--- a/drivers/media/video/cx23885/cx23885-i2c.c
+++ b/drivers/media/video/cx23885/cx23885-i2c.c
@@ -364,17 +364,10 @@
 
 		memset(&info, 0, sizeof(struct i2c_board_info));
 		strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
-		/*
-		 * We can't call i2c_new_probed_device() because it uses
-		 * quick writes for probing and the IR receiver device only
-		 * replies to reads.
-		 */
-		if (i2c_smbus_xfer(&bus->i2c_adap, addr_list[0], 0,
-				   I2C_SMBUS_READ, 0, I2C_SMBUS_QUICK,
-				   NULL) >= 0) {
-			info.addr = addr_list[0];
-			i2c_new_device(&bus->i2c_adap, &info);
-		}
+		/* Use quick read command for probe, some IR chips don't
+		 * support writes */
+		i2c_new_probed_device(&bus->i2c_adap, &info, addr_list,
+				      i2c_probe_func_quick_read);
 	}
 
 	return bus->i2c_rc;
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index 375ad53..82db555 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -193,24 +193,13 @@
 			0x18, 0x6b, 0x71,
 			I2C_CLIENT_END
 		};
-		const unsigned short *addrp;
 
 		memset(&info, 0, sizeof(struct i2c_board_info));
 		strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
-		/*
-		 * We can't call i2c_new_probed_device() because it uses
-		 * quick writes for probing and at least some R receiver
-		 * devices only reply to reads.
-		 */
-		for (addrp = addr_list; *addrp != I2C_CLIENT_END; addrp++) {
-			if (i2c_smbus_xfer(&core->i2c_adap, *addrp, 0,
-					   I2C_SMBUS_READ, 0,
-					   I2C_SMBUS_QUICK, NULL) >= 0) {
-				info.addr = *addrp;
-				i2c_new_device(&core->i2c_adap, &info);
-				break;
-			}
-		}
+		/* Use quick read command for probe, some IR chips don't
+		 * support writes */
+		i2c_new_probed_device(&core->i2c_adap, &info, addr_list,
+				      i2c_probe_func_quick_read);
 	}
 }
 
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index ffbe544..e7efb4b 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -2385,7 +2385,7 @@
 
 	if (dev->init_data.name)
 		info.platform_data = &dev->init_data;
-	i2c_new_probed_device(&dev->i2c_adap, &info, addr_list);
+	i2c_new_probed_device(&dev->i2c_adap, &info, addr_list, NULL);
 }
 
 void em28xx_card_setup(struct em28xx *dev)
diff --git a/drivers/media/video/fsl-viu.c b/drivers/media/video/fsl-viu.c
index 8f1c94f..43d208f 100644
--- a/drivers/media/video/fsl-viu.c
+++ b/drivers/media/video/fsl-viu.c
@@ -1418,7 +1418,7 @@
 	.current_norm   = V4L2_STD_NTSC_M,
 };
 
-static int __devinit viu_of_probe(struct of_device *op,
+static int __devinit viu_of_probe(struct platform_device *op,
 				  const struct of_device_id *match)
 {
 	struct viu_dev *viu_dev;
@@ -1549,7 +1549,7 @@
 	return ret;
 }
 
-static int __devexit viu_of_remove(struct of_device *op)
+static int __devexit viu_of_remove(struct platform_device *op)
 {
 	struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev);
 	struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
@@ -1570,7 +1570,7 @@
 }
 
 #ifdef CONFIG_PM
-static int viu_suspend(struct of_device *op, pm_message_t state)
+static int viu_suspend(struct platform_device *op, pm_message_t state)
 {
 	struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev);
 	struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
@@ -1579,7 +1579,7 @@
 	return 0;
 }
 
-static int viu_resume(struct of_device *op)
+static int viu_resume(struct platform_device *op)
 {
 	struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev);
 	struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index d391bbd..a74fa09 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -183,8 +183,8 @@
 			return -1;
 		memset(&info, 0, sizeof(struct i2c_board_info));
 		strlcpy(info.type, type, I2C_NAME_SIZE);
-		return i2c_new_probed_device(adap, &info, addr_list) == NULL
-								     ? -1 : 0;
+		return i2c_new_probed_device(adap, &info, addr_list, NULL)
+							   == NULL ? -1 : 0;
 	}
 
 	/* Only allow one IR receiver to be registered per board */
@@ -221,7 +221,8 @@
 	info.platform_data = init_data;
 	strlcpy(info.type, type, I2C_NAME_SIZE);
 
-	return i2c_new_probed_device(adap, &info, addr_list) == NULL ? -1 : 0;
+	return i2c_new_probed_device(adap, &info, addr_list, NULL) == NULL ?
+	       -1 : 0;
 }
 
 /* Instantiate the IR receiver device using probing -- undesirable */
@@ -249,7 +250,7 @@
 
 	memset(&info, 0, sizeof(struct i2c_board_info));
 	strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
-	return i2c_new_probed_device(&itv->i2c_adap, &info, addr_list);
+	return i2c_new_probed_device(&itv->i2c_adap, &info, addr_list, NULL);
 }
 
 int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 3ce7c64..8ee1179 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -381,7 +381,8 @@
 
 	/* Create the i2c client */
 	if (info->addr == 0 && probe_addrs)
-		client = i2c_new_probed_device(adapter, info, probe_addrs);
+		client = i2c_new_probed_device(adapter, info, probe_addrs,
+					       NULL);
 	else
 		client = i2c_new_device(adapter, info);
 
diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c
index eef78a0..d3f1a08 100644
--- a/drivers/memstick/core/mspro_block.c
+++ b/drivers/memstick/core/mspro_block.c
@@ -1048,6 +1048,7 @@
 			snprintf(s_attr->name, sizeof(s_attr->name),
 				 "attr_x%02x", attr->entries[cnt].id);
 
+		sysfs_attr_init(&s_attr->dev_attr.attr);
 		s_attr->dev_attr.attr.name = s_attr->name;
 		s_attr->dev_attr.attr.mode = S_IRUGO;
 		s_attr->dev_attr.show = mspro_block_attr_show(s_attr->id);
@@ -1338,13 +1339,14 @@
 	struct mspro_block_data *msb = memstick_get_drvdata(card);
 	unsigned long flags;
 
-	del_gendisk(msb->disk);
-	dev_dbg(&card->dev, "mspro block remove\n");
 	spin_lock_irqsave(&msb->q_lock, flags);
 	msb->eject = 1;
 	blk_start_queue(msb->queue);
 	spin_unlock_irqrestore(&msb->q_lock, flags);
 
+	del_gendisk(msb->disk);
+	dev_dbg(&card->dev, "mspro block remove\n");
+
 	blk_cleanup_queue(msb->queue);
 	msb->queue = NULL;
 
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index c54674c..b8f1719 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -110,8 +110,7 @@
 
 int mpt_fwfault_debug;
 EXPORT_SYMBOL(mpt_fwfault_debug);
-module_param_call(mpt_fwfault_debug, param_set_int, param_get_int,
-	  &mpt_fwfault_debug, 0600);
+module_param(mpt_fwfault_debug, int, 0600);
 MODULE_PARM_DESC(mpt_fwfault_debug, "Enable detection of Firmware fault"
 	" and halt Firmware on fault - (default=0)");
 
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c
index 2c65a2c57..07933f3 100644
--- a/drivers/mfd/88pm860x-core.c
+++ b/drivers/mfd/88pm860x-core.c
@@ -74,12 +74,12 @@
 }
 
 static struct resource led_resources[] = {
-	PM8606_LED_RESOURCE(PM8606_LED1_RED, RGB2B),
-	PM8606_LED_RESOURCE(PM8606_LED1_GREEN, RGB2C),
-	PM8606_LED_RESOURCE(PM8606_LED1_BLUE, RGB2D),
-	PM8606_LED_RESOURCE(PM8606_LED2_RED, RGB1B),
-	PM8606_LED_RESOURCE(PM8606_LED2_GREEN, RGB1C),
-	PM8606_LED_RESOURCE(PM8606_LED2_BLUE, RGB1D),
+	PM8606_LED_RESOURCE(PM8606_LED1_RED, RGB1B),
+	PM8606_LED_RESOURCE(PM8606_LED1_GREEN, RGB1C),
+	PM8606_LED_RESOURCE(PM8606_LED1_BLUE, RGB1D),
+	PM8606_LED_RESOURCE(PM8606_LED2_RED, RGB2B),
+	PM8606_LED_RESOURCE(PM8606_LED2_GREEN, RGB2C),
+	PM8606_LED_RESOURCE(PM8606_LED2_BLUE, RGB2D),
 };
 
 #define PM8606_LED_DEVS(_i)				\
@@ -428,52 +428,44 @@
 {
 	struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \
 				: chip->companion;
-	int use_gpadc = 0, data, ret;
+	int data;
+	int ret;
 
 	/* initialize GPADC without activating it */
 
-	if (pdata && pdata->touch) {
-		/* set GPADC MISC1 register */
-		data = 0;
-		data |= (pdata->touch->gpadc_prebias << 1)
-			& PM8607_GPADC_PREBIAS_MASK;
-		data |= (pdata->touch->slot_cycle << 3)
-			& PM8607_GPADC_SLOT_CYCLE_MASK;
-		data |= (pdata->touch->off_scale << 5)
-			& PM8607_GPADC_OFF_SCALE_MASK;
-		data |= (pdata->touch->sw_cal << 7)
-			& PM8607_GPADC_SW_CAL_MASK;
-		if (data) {
-			ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data);
-			if (ret < 0)
-				goto out;
-		}
-		/* set tsi prebias time */
-		if (pdata->touch->tsi_prebias) {
-			data = pdata->touch->tsi_prebias;
-			ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data);
-			if (ret < 0)
-				goto out;
-		}
-		/* set prebias & prechg time of pen detect */
-		data = 0;
-		data |= pdata->touch->pen_prebias & PM8607_PD_PREBIAS_MASK;
-		data |= (pdata->touch->pen_prechg << 5)
-			& PM8607_PD_PRECHG_MASK;
-		if (data) {
-			ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data);
-			if (ret < 0)
-				goto out;
-		}
+	if (!pdata || !pdata->touch)
+		return -EINVAL;
 
-		use_gpadc = 1;
+	/* set GPADC MISC1 register */
+	data = 0;
+	data |= (pdata->touch->gpadc_prebias << 1) & PM8607_GPADC_PREBIAS_MASK;
+	data |= (pdata->touch->slot_cycle << 3) & PM8607_GPADC_SLOT_CYCLE_MASK;
+	data |= (pdata->touch->off_scale << 5) & PM8607_GPADC_OFF_SCALE_MASK;
+	data |= (pdata->touch->sw_cal << 7) & PM8607_GPADC_SW_CAL_MASK;
+	if (data) {
+		ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data);
+		if (ret < 0)
+			goto out;
+	}
+	/* set tsi prebias time */
+	if (pdata->touch->tsi_prebias) {
+		data = pdata->touch->tsi_prebias;
+		ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data);
+		if (ret < 0)
+			goto out;
+	}
+	/* set prebias & prechg time of pen detect */
+	data = 0;
+	data |= pdata->touch->pen_prebias & PM8607_PD_PREBIAS_MASK;
+	data |= (pdata->touch->pen_prechg << 5) & PM8607_PD_PRECHG_MASK;
+	if (data) {
+		ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data);
+		if (ret < 0)
+			goto out;
 	}
 
-	/* turn on GPADC */
-	if (use_gpadc) {
-		ret = pm860x_set_bits(i2c, PM8607_GPADC_MISC1,
-				      PM8607_GPADC_EN, PM8607_GPADC_EN);
-	}
+	ret = pm860x_set_bits(i2c, PM8607_GPADC_MISC1,
+			      PM8607_GPADC_EN, PM8607_GPADC_EN);
 out:
 	return ret;
 }
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 9da0e50..db51ea1 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -7,7 +7,16 @@
 	depends on HAS_IOMEM
 	default y
 	help
-	  Configure MFD device drivers.
+	  Multifunction devices embed several functions (e.g. GPIOs,
+	  touchscreens, keyboards, current regulators, power management chips,
+	  etc...) in one single integrated circuit. They usually talk to the
+	  main CPU through one or more IRQ lines and low speed data busses (SPI,
+	  I2C, etc..). They appear as one single device to the main system
+	  through the data bus and the MFD framework allows for sub devices
+	  (a.k.a. functions) to appear as discrete platform devices.
+	  MFDs are typically found on embedded platforms.
+
+	  This option alone does not add any kernel code.
 
 if MFD_SUPPORT
 
@@ -177,6 +186,38 @@
 	select MFD_CORE
 	default n
 
+config TWL6030_PWM
+	tristate "TWL6030 PWM (Pulse Width Modulator) Support"
+	depends on TWL4030_CORE
+	select HAVE_PWM
+	default n
+	help
+	  Say yes here if you want support for TWL6030 PWM.
+	  This is used to control charging LED brightness.
+
+config MFD_STMPE
+	bool "Support STMicroelectronics STMPE"
+	depends on I2C=y && GENERIC_HARDIRQS
+	select MFD_CORE
+	help
+	  Support for the STMPE family of I/O Expanders from
+	  STMicroelectronics.
+
+	  Currently supported devices are:
+
+		STMPE811: GPIO, Touchscreen
+		STMPE1601: GPIO, Keypad
+		STMPE2401: GPIO, Keypad
+		STMPE2403: GPIO, Keypad
+
+	  This driver provides common support for accessing the device,
+	  additional drivers must be enabled in order to use the functionality
+	  of the device.  Currently available sub drivers are:
+
+		GPIO: stmpe-gpio
+		Keypad: stmpe-keypad
+		Touchscreen: stmpe-ts
+
 config MFD_TC35892
 	bool "Support Toshiba TC35892"
 	depends on I2C=y && GENERIC_HARDIRQS
@@ -252,6 +293,16 @@
 	  accessing the device, additional drivers must be enabled in order
 	  to use the functionality of the device.
 
+config MFD_MAX8998
+	bool "Maxim Semiconductor MAX8998 PMIC Support"
+	depends on I2C=y
+	select MFD_CORE
+	help
+	  Say yes here to support for Maxim Semiconductor MAX8998. This is
+	  a Power Management IC. This driver provies common support for
+	  accessing the device, additional drivers must be enabled in order
+	  to use the functionality of the device.
+
 config MFD_WM8400
 	tristate "Support Wolfson Microelectronics WM8400"
 	select MFD_CORE
@@ -482,6 +533,28 @@
 	  host many different types of MODULbus daughterboards, including
 	  CAN and GPIO controllers.
 
+config MFD_JZ4740_ADC
+	tristate "Support for the JZ4740 SoC ADC core"
+	select MFD_CORE
+	depends on MACH_JZ4740
+	help
+	  Say yes here if you want support for the ADC unit in the JZ4740 SoC.
+	  This driver is necessary for jz4740-battery and jz4740-hwmon driver.
+
+config MFD_TPS6586X
+	tristate "TPS6586x Power Management chips"
+	depends on I2C && GPIOLIB
+	select MFD_CORE
+	help
+	  If you say yes here you get support for the TPS6586X series of
+	  Power Management chips.
+	  This driver provides common support for accessing the device,
+	  additional drivers must be enabled in order to use the
+	  functionality of the device.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called tps6586x.
+
 endif # MFD_SUPPORT
 
 menu "Multimedia Capabilities Port drivers"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index fb503e7..feaeeae 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -15,6 +15,7 @@
 obj-$(CONFIG_MFD_DAVINCI_VOICECODEC)	+= davinci_voicecodec.o
 obj-$(CONFIG_MFD_DM355EVM_MSP)	+= dm355evm_msp.o
 
+obj-$(CONFIG_MFD_STMPE)		+= stmpe.o
 obj-$(CONFIG_MFD_TC35892)	+= tc35892.o
 obj-$(CONFIG_MFD_T7L66XB)	+= t7l66xb.o tmio_core.o
 obj-$(CONFIG_MFD_TC6387XB)	+= tc6387xb.o tmio_core.o
@@ -36,6 +37,7 @@
 obj-$(CONFIG_TWL4030_CORE)	+= twl-core.o twl4030-irq.o twl6030-irq.o
 obj-$(CONFIG_TWL4030_POWER)    += twl4030-power.o
 obj-$(CONFIG_TWL4030_CODEC)	+= twl4030-codec.o
+obj-$(CONFIG_TWL6030_PWM)	+= twl6030-pwm.o
 
 obj-$(CONFIG_MFD_MC13783)	+= mc13783-core.o
 
@@ -56,6 +58,7 @@
 obj-$(CONFIG_PMIC_DA903X)	+= da903x.o
 max8925-objs			:= max8925-core.o max8925-i2c.o
 obj-$(CONFIG_MFD_MAX8925)	+= max8925.o
+obj-$(CONFIG_MFD_MAX8998)	+= max8998.o
 
 pcf50633-objs			:= pcf50633-core.o pcf50633-irq.o
 obj-$(CONFIG_MFD_PCF50633)	+= pcf50633.o
@@ -71,3 +74,5 @@
 obj-$(CONFIG_LPC_SCH)		+= lpc_sch.o
 obj-$(CONFIG_MFD_RDC321X)	+= rdc321x-southbridge.o
 obj-$(CONFIG_MFD_JANZ_CMODIO)	+= janz-cmodio.o
+obj-$(CONFIG_MFD_JZ4740_ADC)	+= jz4740-adc.o
+obj-$(CONFIG_MFD_TPS6586X)	+= tps6586x.o
diff --git a/drivers/mfd/ab3100-otp.c b/drivers/mfd/ab3100-otp.c
index 63d2b72..8440010 100644
--- a/drivers/mfd/ab3100-otp.c
+++ b/drivers/mfd/ab3100-otp.c
@@ -199,7 +199,7 @@
 
 	err = ab3100_otp_read(otp);
 	if (err)
-		return err;
+		goto err_otp_read;
 
 	dev_info(&pdev->dev, "AB3100 OTP readout registered\n");
 
@@ -208,21 +208,21 @@
 		err = device_create_file(&pdev->dev,
 					 &ab3100_otp_attrs[i]);
 		if (err)
-			goto out_no_sysfs;
+			goto err_create_file;
 	}
 
 	/* debugfs entries */
 	err = ab3100_otp_init_debugfs(&pdev->dev, otp);
 	if (err)
-		goto out_no_debugfs;
+		goto err_init_debugfs;
 
 	return 0;
 
-out_no_sysfs:
-	for (i = 0; i < ARRAY_SIZE(ab3100_otp_attrs); i++)
-		device_remove_file(&pdev->dev,
-				   &ab3100_otp_attrs[i]);
-out_no_debugfs:
+err_init_debugfs:
+err_create_file:
+	while (--i >= 0)
+		device_remove_file(&pdev->dev, &ab3100_otp_attrs[i]);
+err_otp_read:
 	kfree(otp);
 	return err;
 }
diff --git a/drivers/mfd/ab3550-core.c b/drivers/mfd/ab3550-core.c
index f54ab62..8a98739 100644
--- a/drivers/mfd/ab3550-core.c
+++ b/drivers/mfd/ab3550-core.c
@@ -589,16 +589,16 @@
 }
 
 /*
- * The exported register access functionality.
+ * The register access functionality.
  */
-int ab3550_get_chip_id(struct device *dev)
+static int ab3550_get_chip_id(struct device *dev)
 {
 	struct ab3550 *ab = dev_get_drvdata(dev->parent);
 	return (int)ab->chip_id;
 }
 
-int ab3550_mask_and_set_register_interruptible(struct device *dev, u8 bank,
-	u8 reg, u8 bitmask, u8 bitvalues)
+static int ab3550_mask_and_set_register_interruptible(struct device *dev,
+	u8 bank, u8 reg, u8 bitmask, u8 bitvalues)
 {
 	struct ab3550 *ab;
 	struct platform_device *pdev = to_platform_device(dev);
@@ -612,15 +612,15 @@
 		bitmask, bitvalues);
 }
 
-int ab3550_set_register_interruptible(struct device *dev, u8 bank, u8 reg,
-	u8 value)
+static int ab3550_set_register_interruptible(struct device *dev, u8 bank,
+	u8 reg, u8 value)
 {
 	return ab3550_mask_and_set_register_interruptible(dev, bank, reg, 0xFF,
 		value);
 }
 
-int ab3550_get_register_interruptible(struct device *dev, u8 bank, u8 reg,
-	u8 *value)
+static int ab3550_get_register_interruptible(struct device *dev, u8 bank,
+	u8 reg, u8 *value)
 {
 	struct ab3550 *ab;
 	struct platform_device *pdev = to_platform_device(dev);
@@ -633,7 +633,7 @@
 	return get_register_interruptible(ab, bank, reg, value);
 }
 
-int ab3550_get_register_page_interruptible(struct device *dev, u8 bank,
+static int ab3550_get_register_page_interruptible(struct device *dev, u8 bank,
 	u8 first_reg, u8 *regvals, u8 numregs)
 {
 	struct ab3550 *ab;
@@ -649,7 +649,8 @@
 		numregs);
 }
 
-int ab3550_event_registers_startup_state_get(struct device *dev, u8 *event)
+static int ab3550_event_registers_startup_state_get(struct device *dev,
+	u8 *event)
 {
 	struct ab3550 *ab;
 
@@ -661,7 +662,7 @@
 	return 0;
 }
 
-int ab3550_startup_irq_enabled(struct device *dev, unsigned int irq)
+static int ab3550_startup_irq_enabled(struct device *dev, unsigned int irq)
 {
 	struct ab3550 *ab;
 	struct ab3550_platform_data *plf_data;
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index f3d26fa..defa786 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -16,6 +16,7 @@
 #include <linux/platform_device.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/ab8500.h>
+#include <linux/regulator/ab8500.h>
 
 /*
  * Interrupt register offsets
@@ -352,6 +353,7 @@
 	{ .name = "ab8500-audio", },
 	{ .name = "ab8500-usb", },
 	{ .name = "ab8500-pwm", },
+	{ .name = "ab8500-regulator", },
 };
 
 int __devinit ab8500_init(struct ab8500 *ab8500)
@@ -411,7 +413,7 @@
 			goto out_removeirq;
 	}
 
-	ret = mfd_add_devices(ab8500->dev, -1, ab8500_devs,
+	ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
 			      ARRAY_SIZE(ab8500_devs), NULL,
 			      ab8500->irq_base);
 	if (ret)
diff --git a/drivers/mfd/ab8500-spi.c b/drivers/mfd/ab8500-spi.c
index b81d4f7..e1c8b62 100644
--- a/drivers/mfd/ab8500-spi.c
+++ b/drivers/mfd/ab8500-spi.c
@@ -68,7 +68,12 @@
 
 	ret = spi_sync(spi, &msg);
 	if (!ret)
-		ret = ab8500->rx_buf[0];
+		/*
+		 * Only the 8 lowermost bytes are
+		 * defined with value, the rest may
+		 * vary depending on chip/board noise.
+		 */
+		ret = ab8500->rx_buf[0] & 0xFFU;
 
 	return ret;
 }
diff --git a/drivers/mfd/abx500-core.c b/drivers/mfd/abx500-core.c
index 3b3b97e..f12720d 100644
--- a/drivers/mfd/abx500-core.c
+++ b/drivers/mfd/abx500-core.c
@@ -36,7 +36,7 @@
 	struct abx500_device_entry *dev_entry;
 
 	dev_entry = kzalloc(sizeof(struct abx500_device_entry), GFP_KERNEL);
-	if (IS_ERR(dev_entry)) {
+	if (!dev_entry) {
 		dev_err(dev, "register_ops kzalloc failed");
 		return -ENOMEM;
 	}
diff --git a/drivers/mfd/davinci_voicecodec.c b/drivers/mfd/davinci_voicecodec.c
index 3e75f02..33c923d 100644
--- a/drivers/mfd/davinci_voicecodec.c
+++ b/drivers/mfd/davinci_voicecodec.c
@@ -94,7 +94,8 @@
 	res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
 	if (!res) {
 		dev_err(&pdev->dev, "no DMA resource\n");
-		return -ENXIO;
+		ret = -ENXIO;
+		goto fail4;
 	}
 
 	davinci_vc->davinci_vcif.dma_tx_channel = res->start;
@@ -104,7 +105,8 @@
 	res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
 	if (!res) {
 		dev_err(&pdev->dev, "no DMA resource\n");
-		return -ENXIO;
+		ret = -ENXIO;
+		goto fail4;
 	}
 
 	davinci_vc->davinci_vcif.dma_rx_channel = res->start;
diff --git a/drivers/mfd/janz-cmodio.c b/drivers/mfd/janz-cmodio.c
index 9ed6307..36a166b 100644
--- a/drivers/mfd/janz-cmodio.c
+++ b/drivers/mfd/janz-cmodio.c
@@ -18,6 +18,7 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
+#include <linux/slab.h>
 #include <linux/mfd/core.h>
 
 #include <linux/mfd/janz.h>
diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c
new file mode 100644
index 0000000..3ad492c
--- /dev/null
+++ b/drivers/mfd/jz4740-adc.c
@@ -0,0 +1,394 @@
+/*
+ * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 SoC ADC driver
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This driver synchronizes access to the JZ4740 ADC core between the
+ * JZ4740 battery and hwmon drivers.
+ */
+
+#include <linux/err.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <linux/clk.h>
+#include <linux/mfd/core.h>
+
+#include <linux/jz4740-adc.h>
+
+
+#define JZ_REG_ADC_ENABLE	0x00
+#define JZ_REG_ADC_CFG		0x04
+#define JZ_REG_ADC_CTRL		0x08
+#define JZ_REG_ADC_STATUS	0x0c
+
+#define JZ_REG_ADC_TOUCHSCREEN_BASE	0x10
+#define JZ_REG_ADC_BATTERY_BASE	0x1c
+#define JZ_REG_ADC_HWMON_BASE	0x20
+
+#define JZ_ADC_ENABLE_TOUCH	BIT(2)
+#define JZ_ADC_ENABLE_BATTERY	BIT(1)
+#define JZ_ADC_ENABLE_ADCIN	BIT(0)
+
+enum {
+	JZ_ADC_IRQ_ADCIN = 0,
+	JZ_ADC_IRQ_BATTERY,
+	JZ_ADC_IRQ_TOUCH,
+	JZ_ADC_IRQ_PENUP,
+	JZ_ADC_IRQ_PENDOWN,
+};
+
+struct jz4740_adc {
+	struct resource *mem;
+	void __iomem *base;
+
+	int irq;
+	int irq_base;
+
+	struct clk *clk;
+	atomic_t clk_ref;
+
+	spinlock_t lock;
+};
+
+static inline void jz4740_adc_irq_set_masked(struct jz4740_adc *adc, int irq,
+	bool masked)
+{
+	unsigned long flags;
+	uint8_t val;
+
+	irq -= adc->irq_base;
+
+	spin_lock_irqsave(&adc->lock, flags);
+
+	val = readb(adc->base + JZ_REG_ADC_CTRL);
+	if (masked)
+		val |= BIT(irq);
+	else
+		val &= ~BIT(irq);
+	writeb(val, adc->base + JZ_REG_ADC_CTRL);
+
+	spin_unlock_irqrestore(&adc->lock, flags);
+}
+
+static void jz4740_adc_irq_mask(unsigned int irq)
+{
+	struct jz4740_adc *adc = get_irq_chip_data(irq);
+	jz4740_adc_irq_set_masked(adc, irq, true);
+}
+
+static void jz4740_adc_irq_unmask(unsigned int irq)
+{
+	struct jz4740_adc *adc = get_irq_chip_data(irq);
+	jz4740_adc_irq_set_masked(adc, irq, false);
+}
+
+static void jz4740_adc_irq_ack(unsigned int irq)
+{
+	struct jz4740_adc *adc = get_irq_chip_data(irq);
+
+	irq -= adc->irq_base;
+	writeb(BIT(irq), adc->base + JZ_REG_ADC_STATUS);
+}
+
+static struct irq_chip jz4740_adc_irq_chip = {
+	.name = "jz4740-adc",
+	.mask = jz4740_adc_irq_mask,
+	.unmask = jz4740_adc_irq_unmask,
+	.ack = jz4740_adc_irq_ack,
+};
+
+static void jz4740_adc_irq_demux(unsigned int irq, struct irq_desc *desc)
+{
+	struct jz4740_adc *adc = get_irq_desc_data(desc);
+	uint8_t status;
+	unsigned int i;
+
+	status = readb(adc->base + JZ_REG_ADC_STATUS);
+
+	for (i = 0; i < 5; ++i) {
+		if (status & BIT(i))
+			generic_handle_irq(adc->irq_base + i);
+	}
+}
+
+
+/* Refcounting for the ADC clock is done in here instead of in the clock
+ * framework, because it is the only clock which is shared between multiple
+ * devices and thus is the only clock which needs refcounting */
+static inline void jz4740_adc_clk_enable(struct jz4740_adc *adc)
+{
+	if (atomic_inc_return(&adc->clk_ref) == 1)
+		clk_enable(adc->clk);
+}
+
+static inline void jz4740_adc_clk_disable(struct jz4740_adc *adc)
+{
+	if (atomic_dec_return(&adc->clk_ref) == 0)
+		clk_disable(adc->clk);
+}
+
+static inline void jz4740_adc_set_enabled(struct jz4740_adc *adc, int engine,
+	bool enabled)
+{
+	unsigned long flags;
+	uint8_t val;
+
+	spin_lock_irqsave(&adc->lock, flags);
+
+	val = readb(adc->base + JZ_REG_ADC_ENABLE);
+	if (enabled)
+		val |= BIT(engine);
+	else
+		val &= BIT(engine);
+	writeb(val, adc->base + JZ_REG_ADC_ENABLE);
+
+	spin_unlock_irqrestore(&adc->lock, flags);
+}
+
+static int jz4740_adc_cell_enable(struct platform_device *pdev)
+{
+	struct jz4740_adc *adc = dev_get_drvdata(pdev->dev.parent);
+
+	jz4740_adc_clk_enable(adc);
+	jz4740_adc_set_enabled(adc, pdev->id, true);
+
+	return 0;
+}
+
+static int jz4740_adc_cell_disable(struct platform_device *pdev)
+{
+	struct jz4740_adc *adc = dev_get_drvdata(pdev->dev.parent);
+
+	jz4740_adc_set_enabled(adc, pdev->id, false);
+	jz4740_adc_clk_disable(adc);
+
+	return 0;
+}
+
+int jz4740_adc_set_config(struct device *dev, uint32_t mask, uint32_t val)
+{
+	struct jz4740_adc *adc = dev_get_drvdata(dev);
+	unsigned long flags;
+	uint32_t cfg;
+
+	if (!adc)
+		return -ENODEV;
+
+	spin_lock_irqsave(&adc->lock, flags);
+
+	cfg = readl(adc->base + JZ_REG_ADC_CFG);
+
+	cfg &= ~mask;
+	cfg |= val;
+
+	writel(cfg, adc->base + JZ_REG_ADC_CFG);
+
+	spin_unlock_irqrestore(&adc->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(jz4740_adc_set_config);
+
+static struct resource jz4740_hwmon_resources[] = {
+	{
+		.start = JZ_ADC_IRQ_ADCIN,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start	= JZ_REG_ADC_HWMON_BASE,
+		.end	= JZ_REG_ADC_HWMON_BASE + 3,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct resource jz4740_battery_resources[] = {
+	{
+		.start = JZ_ADC_IRQ_BATTERY,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.start	= JZ_REG_ADC_BATTERY_BASE,
+		.end	= JZ_REG_ADC_BATTERY_BASE + 3,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+const struct mfd_cell jz4740_adc_cells[] = {
+	{
+		.id = 0,
+		.name = "jz4740-hwmon",
+		.num_resources = ARRAY_SIZE(jz4740_hwmon_resources),
+		.resources = jz4740_hwmon_resources,
+		.platform_data = (void *)&jz4740_adc_cells[0],
+		.data_size = sizeof(struct mfd_cell),
+
+		.enable = jz4740_adc_cell_enable,
+		.disable = jz4740_adc_cell_disable,
+	},
+	{
+		.id = 1,
+		.name = "jz4740-battery",
+		.num_resources = ARRAY_SIZE(jz4740_battery_resources),
+		.resources = jz4740_battery_resources,
+		.platform_data = (void *)&jz4740_adc_cells[1],
+		.data_size = sizeof(struct mfd_cell),
+
+		.enable = jz4740_adc_cell_enable,
+		.disable = jz4740_adc_cell_disable,
+	},
+};
+
+static int __devinit jz4740_adc_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct jz4740_adc *adc;
+	struct resource *mem_base;
+	int irq;
+
+	adc = kmalloc(sizeof(*adc), GFP_KERNEL);
+	if (!adc) {
+		dev_err(&pdev->dev, "Failed to allocate driver structure\n");
+		return -ENOMEM;
+	}
+
+	adc->irq = platform_get_irq(pdev, 0);
+	if (adc->irq < 0) {
+		ret = adc->irq;
+		dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret);
+		goto err_free;
+	}
+
+	adc->irq_base = platform_get_irq(pdev, 1);
+	if (adc->irq_base < 0) {
+		ret = adc->irq_base;
+		dev_err(&pdev->dev, "Failed to get irq base: %d\n", ret);
+		goto err_free;
+	}
+
+	mem_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem_base) {
+		ret = -ENOENT;
+		dev_err(&pdev->dev, "Failed to get platform mmio resource\n");
+		goto err_free;
+	}
+
+	/* Only request the shared registers for the MFD driver */
+	adc->mem = request_mem_region(mem_base->start, JZ_REG_ADC_STATUS,
+					pdev->name);
+	if (!adc->mem) {
+		ret = -EBUSY;
+		dev_err(&pdev->dev, "Failed to request mmio memory region\n");
+		goto err_free;
+	}
+
+	adc->base = ioremap_nocache(adc->mem->start, resource_size(adc->mem));
+	if (!adc->base) {
+		ret = -EBUSY;
+		dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
+		goto err_release_mem_region;
+	}
+
+	adc->clk = clk_get(&pdev->dev, "adc");
+	if (IS_ERR(adc->clk)) {
+		ret = PTR_ERR(adc->clk);
+		dev_err(&pdev->dev, "Failed to get clock: %d\n", ret);
+		goto err_iounmap;
+	}
+
+	spin_lock_init(&adc->lock);
+	atomic_set(&adc->clk_ref, 0);
+
+	platform_set_drvdata(pdev, adc);
+
+	for (irq = adc->irq_base; irq < adc->irq_base + 5; ++irq) {
+		set_irq_chip_data(irq, adc);
+		set_irq_chip_and_handler(irq, &jz4740_adc_irq_chip,
+		    handle_level_irq);
+	}
+
+	set_irq_data(adc->irq, adc);
+	set_irq_chained_handler(adc->irq, jz4740_adc_irq_demux);
+
+	writeb(0x00, adc->base + JZ_REG_ADC_ENABLE);
+	writeb(0xff, adc->base + JZ_REG_ADC_CTRL);
+
+	ret = mfd_add_devices(&pdev->dev, 0, jz4740_adc_cells,
+		ARRAY_SIZE(jz4740_adc_cells), mem_base, adc->irq_base);
+	if (ret < 0)
+		goto err_clk_put;
+
+	return 0;
+
+err_clk_put:
+	clk_put(adc->clk);
+err_iounmap:
+	platform_set_drvdata(pdev, NULL);
+	iounmap(adc->base);
+err_release_mem_region:
+	release_mem_region(adc->mem->start, resource_size(adc->mem));
+err_free:
+	kfree(adc);
+
+	return ret;
+}
+
+static int __devexit jz4740_adc_remove(struct platform_device *pdev)
+{
+	struct jz4740_adc *adc = platform_get_drvdata(pdev);
+
+	mfd_remove_devices(&pdev->dev);
+
+	set_irq_data(adc->irq, NULL);
+	set_irq_chained_handler(adc->irq, NULL);
+
+	iounmap(adc->base);
+	release_mem_region(adc->mem->start, resource_size(adc->mem));
+
+	clk_put(adc->clk);
+
+	platform_set_drvdata(pdev, NULL);
+
+	kfree(adc);
+
+	return 0;
+}
+
+struct platform_driver jz4740_adc_driver = {
+	.probe	= jz4740_adc_probe,
+	.remove = __devexit_p(jz4740_adc_remove),
+	.driver = {
+		.name = "jz4740-adc",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init jz4740_adc_init(void)
+{
+	return platform_driver_register(&jz4740_adc_driver);
+}
+module_init(jz4740_adc_init);
+
+static void __exit jz4740_adc_exit(void)
+{
+	platform_driver_unregister(&jz4740_adc_driver);
+}
+module_exit(jz4740_adc_exit);
+
+MODULE_DESCRIPTION("JZ4740 SoC ADC driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:jz4740-adc");
diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c
index f621bce..04028a9 100644
--- a/drivers/mfd/max8925-core.c
+++ b/drivers/mfd/max8925-core.c
@@ -90,6 +90,24 @@
 	},
 };
 
+static struct resource onkey_resources[] = {
+	{
+		.name	= "max8925-onkey",
+		.start	= MAX8925_IRQ_GPM_SW_3SEC,
+		.end	= MAX8925_IRQ_GPM_SW_3SEC,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct mfd_cell onkey_devs[] = {
+	{
+		.name		= "max8925-onkey",
+		.num_resources	= 1,
+		.resources	= &onkey_resources[0],
+		.id		= -1,
+	},
+};
+
 #define MAX8925_REG_RESOURCE(_start, _end)	\
 {						\
 	.start	= MAX8925_##_start,		\
@@ -596,6 +614,15 @@
 		dev_err(chip->dev, "Failed to add rtc subdev\n");
 		goto out;
 	}
+
+	ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0],
+			      ARRAY_SIZE(onkey_devs),
+			      &onkey_resources[0], 0);
+	if (ret < 0) {
+		dev_err(chip->dev, "Failed to add onkey subdev\n");
+		goto out_dev;
+	}
+
 	if (pdata && pdata->regulator[0]) {
 		ret = mfd_add_devices(chip->dev, 0, &regulator_devs[0],
 				      ARRAY_SIZE(regulator_devs),
diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c
new file mode 100644
index 0000000..73e6f5c
--- /dev/null
+++ b/drivers/mfd/max8998.c
@@ -0,0 +1,158 @@
+/*
+ * max8698.c - mfd core driver for the Maxim 8998
+ *
+ *  Copyright (C) 2009-2010 Samsung Electronics
+ *  Kyungmin Park <kyungmin.park@samsung.com>
+ *  Marek Szyprowski <m.szyprowski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/max8998.h>
+#include <linux/mfd/max8998-private.h>
+
+static struct mfd_cell max8998_devs[] = {
+	{
+		.name = "max8998-pmic",
+	}
+};
+
+static int max8998_i2c_device_read(struct max8998_dev *max8998, u8 reg, u8 *dest)
+{
+	struct i2c_client *client = max8998->i2c_client;
+	int ret;
+
+	mutex_lock(&max8998->iolock);
+	ret = i2c_smbus_read_byte_data(client, reg);
+	mutex_unlock(&max8998->iolock);
+	if (ret < 0)
+		return ret;
+
+	ret &= 0xff;
+	*dest = ret;
+	return 0;
+}
+
+static int max8998_i2c_device_write(struct max8998_dev *max8998, u8 reg, u8 value)
+{
+	struct i2c_client *client = max8998->i2c_client;
+	int ret;
+
+	mutex_lock(&max8998->iolock);
+	ret = i2c_smbus_write_byte_data(client, reg, value);
+	mutex_unlock(&max8998->iolock);
+	return ret;
+}
+
+static int max8998_i2c_device_update(struct max8998_dev *max8998, u8 reg,
+				     u8 val, u8 mask)
+{
+	struct i2c_client *client = max8998->i2c_client;
+	int ret;
+
+	mutex_lock(&max8998->iolock);
+	ret = i2c_smbus_read_byte_data(client, reg);
+	if (ret >= 0) {
+		u8 old_val = ret & 0xff;
+		u8 new_val = (val & mask) | (old_val & (~mask));
+		ret = i2c_smbus_write_byte_data(client, reg, new_val);
+		if (ret >= 0)
+			ret = 0;
+	}
+	mutex_unlock(&max8998->iolock);
+	return ret;
+}
+
+static int max8998_i2c_probe(struct i2c_client *i2c,
+			    const struct i2c_device_id *id)
+{
+	struct max8998_dev *max8998;
+	int ret = 0;
+
+	max8998 = kzalloc(sizeof(struct max8998_dev), GFP_KERNEL);
+	if (max8998 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, max8998);
+	max8998->dev = &i2c->dev;
+	max8998->i2c_client = i2c;
+	max8998->dev_read = max8998_i2c_device_read;
+	max8998->dev_write = max8998_i2c_device_write;
+	max8998->dev_update = max8998_i2c_device_update;
+	mutex_init(&max8998->iolock);
+
+	ret = mfd_add_devices(max8998->dev, -1,
+			      max8998_devs, ARRAY_SIZE(max8998_devs),
+			      NULL, 0);
+	if (ret < 0)
+		goto err;
+
+	return ret;
+
+err:
+	mfd_remove_devices(max8998->dev);
+	kfree(max8998);
+	return ret;
+}
+
+static int max8998_i2c_remove(struct i2c_client *i2c)
+{
+	struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
+
+	mfd_remove_devices(max8998->dev);
+	kfree(max8998);
+
+	return 0;
+}
+
+static const struct i2c_device_id max8998_i2c_id[] = {
+       { "max8998", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, max8998_i2c_id);
+
+static struct i2c_driver max8998_i2c_driver = {
+	.driver = {
+		   .name = "max8998",
+		   .owner = THIS_MODULE,
+	},
+	.probe = max8998_i2c_probe,
+	.remove = max8998_i2c_remove,
+	.id_table = max8998_i2c_id,
+};
+
+static int __init max8998_i2c_init(void)
+{
+	return i2c_add_driver(&max8998_i2c_driver);
+}
+/* init early so consumer devices can complete system boot */
+subsys_initcall(max8998_i2c_init);
+
+static void __exit max8998_i2c_exit(void)
+{
+	i2c_del_driver(&max8998_i2c_driver);
+}
+module_exit(max8998_i2c_exit);
+
+MODULE_DESCRIPTION("MAXIM 8998 multi-function core driver");
+MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/mc13783-core.c b/drivers/mfd/mc13783-core.c
index fecf38a..6df3498 100644
--- a/drivers/mfd/mc13783-core.c
+++ b/drivers/mfd/mc13783-core.c
@@ -11,9 +11,31 @@
  */
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
 #include <linux/spi/spi.h>
 #include <linux/mfd/core.h>
-#include <linux/mfd/mc13783-private.h>
+#include <linux/mfd/mc13783.h>
+
+struct mc13783 {
+	struct spi_device *spidev;
+	struct mutex lock;
+	int irq;
+	int flags;
+
+	irq_handler_t irqhandler[MC13783_NUM_IRQ];
+	void *irqdata[MC13783_NUM_IRQ];
+
+	/* XXX these should go as platformdata to the regulator subdevice */
+	struct mc13783_regulator_init_data *regulators;
+	int num_regulators;
+};
+
+#define MC13783_REG_REVISION			 7
+#define MC13783_REG_ADC_0			43
+#define MC13783_REG_ADC_1			44
+#define MC13783_REG_ADC_2			45
 
 #define MC13783_IRQSTAT0	0
 #define MC13783_IRQSTAT0_ADCDONEI	(1 << 0)
@@ -226,6 +248,12 @@
 }
 EXPORT_SYMBOL(mc13783_reg_rmw);
 
+int mc13783_get_flags(struct mc13783 *mc13783)
+{
+	return mc13783->flags;
+}
+EXPORT_SYMBOL(mc13783_get_flags);
+
 int mc13783_irq_mask(struct mc13783 *mc13783, int irq)
 {
 	int ret;
diff --git a/drivers/mfd/menelaus.c b/drivers/mfd/menelaus.c
index a3fb4bc..4ba85bb 100644
--- a/drivers/mfd/menelaus.c
+++ b/drivers/mfd/menelaus.c
@@ -128,6 +128,39 @@
 #define MENELAUS_RESERVED14_IRQ		14	/* Reserved */
 #define MENELAUS_RESERVED15_IRQ		15	/* Reserved */
 
+/* VCORE_CTRL1 register */
+#define VCORE_CTRL1_BYP_COMP		(1 << 5)
+#define VCORE_CTRL1_HW_NSW		(1 << 7)
+
+/* GPIO_CTRL register */
+#define GPIO_CTRL_SLOTSELEN		(1 << 5)
+#define GPIO_CTRL_SLPCTLEN		(1 << 6)
+#define GPIO1_DIR_INPUT			(1 << 0)
+#define GPIO2_DIR_INPUT			(1 << 1)
+#define GPIO3_DIR_INPUT			(1 << 2)
+
+/* MCT_CTRL1 register */
+#define MCT_CTRL1_S1_CMD_OD		(1 << 2)
+#define MCT_CTRL1_S2_CMD_OD		(1 << 3)
+
+/* MCT_CTRL2 register */
+#define MCT_CTRL2_VS2_SEL_D0		(1 << 0)
+#define MCT_CTRL2_VS2_SEL_D1		(1 << 1)
+#define MCT_CTRL2_S1CD_BUFEN		(1 << 4)
+#define MCT_CTRL2_S2CD_BUFEN		(1 << 5)
+#define MCT_CTRL2_S1CD_DBEN		(1 << 6)
+#define MCT_CTRL2_S2CD_BEN		(1 << 7)
+
+/* MCT_CTRL3 register */
+#define MCT_CTRL3_SLOT1_EN		(1 << 0)
+#define MCT_CTRL3_SLOT2_EN		(1 << 1)
+#define MCT_CTRL3_S1_AUTO_EN		(1 << 2)
+#define MCT_CTRL3_S2_AUTO_EN		(1 << 3)
+
+/* MCT_PIN_ST register */
+#define MCT_PIN_ST_S1_CD_ST		(1 << 0)
+#define MCT_PIN_ST_S2_CD_ST		(1 << 1)
+
 static void menelaus_work(struct work_struct *_menelaus);
 
 struct menelaus_chip {
@@ -249,10 +282,10 @@
 		return;
 
 	if (!(reg & 0x1))
-		card_mask |= (1 << 0);
+		card_mask |= MCT_PIN_ST_S1_CD_ST;
 
 	if (!(reg & 0x2))
-		card_mask |= (1 << 1);
+		card_mask |= MCT_PIN_ST_S2_CD_ST;
 
 	if (menelaus_hw->mmc_callback)
 		menelaus_hw->mmc_callback(menelaus_hw->mmc_callback_data,
@@ -277,14 +310,14 @@
 	val = ret;
 	if (slot == 1) {
 		if (enable)
-			val |= 1 << 2;
+			val |= MCT_CTRL1_S1_CMD_OD;
 		else
-			val &= ~(1 << 2);
+			val &= ~MCT_CTRL1_S1_CMD_OD;
 	} else {
 		if (enable)
-			val |= 1 << 3;
+			val |= MCT_CTRL1_S2_CMD_OD;
 		else
-			val &= ~(1 << 3);
+			val &= ~MCT_CTRL1_S2_CMD_OD;
 	}
 	ret = menelaus_write_reg(MENELAUS_MCT_CTRL1, val);
 	mutex_unlock(&the_menelaus->lock);
@@ -301,11 +334,11 @@
 	ret = menelaus_read_reg(MENELAUS_GPIO_CTRL);
 	if (ret < 0)
 		goto out;
-	ret |= 0x02;
+	ret |= GPIO2_DIR_INPUT;
 	if (enable)
-		ret |= 1 << 5;
+		ret |= GPIO_CTRL_SLOTSELEN;
 	else
-		ret &= ~(1 << 5);
+		ret &= ~GPIO_CTRL_SLOTSELEN;
 	ret = menelaus_write_reg(MENELAUS_GPIO_CTRL, ret);
 out:
 	mutex_unlock(&the_menelaus->lock);
@@ -330,14 +363,14 @@
 	val = ret;
 	if (slot == 1) {
 		if (cd_en)
-			val |= (1 << 4) | (1 << 6);
+			val |= MCT_CTRL2_S1CD_BUFEN | MCT_CTRL2_S1CD_DBEN;
 		else
-			val &= ~((1 << 4) | (1 << 6));
+			val &= ~(MCT_CTRL2_S1CD_BUFEN | MCT_CTRL2_S1CD_DBEN);
 	} else {
 		if (cd_en)
-			val |= (1 << 5) | (1 << 7);
+			val |= MCT_CTRL2_S2CD_BUFEN | MCT_CTRL2_S2CD_BEN;
 		else
-			val &= ~((1 << 5) | (1 << 7));
+			val &= ~(MCT_CTRL2_S2CD_BUFEN | MCT_CTRL2_S2CD_BEN);
 	}
 	ret = menelaus_write_reg(MENELAUS_MCT_CTRL2, val);
 	if (ret < 0)
@@ -349,25 +382,25 @@
 	val = ret;
 	if (slot == 1) {
 		if (enable)
-			val |= 1 << 0;
+			val |= MCT_CTRL3_SLOT1_EN;
 		else
-			val &= ~(1 << 0);
+			val &= ~MCT_CTRL3_SLOT1_EN;
 	} else {
 		int b;
 
 		if (enable)
-			ret |= 1 << 1;
+			val |= MCT_CTRL3_SLOT2_EN;
 		else
-			ret &= ~(1 << 1);
+			val &= ~MCT_CTRL3_SLOT2_EN;
 		b = menelaus_read_reg(MENELAUS_MCT_CTRL2);
-		b &= ~0x03;
+		b &= ~(MCT_CTRL2_VS2_SEL_D0 | MCT_CTRL2_VS2_SEL_D1);
 		b |= power;
 		ret = menelaus_write_reg(MENELAUS_MCT_CTRL2, b);
 		if (ret < 0)
 			goto out;
 	}
 	/* Disable autonomous shutdown */
-	val &= ~(0x03 << 2);
+	val &= ~(MCT_CTRL3_S1_AUTO_EN | MCT_CTRL3_S2_AUTO_EN);
 	ret = menelaus_write_reg(MENELAUS_MCT_CTRL3, val);
 out:
 	mutex_unlock(&the_menelaus->lock);
@@ -552,7 +585,7 @@
 	if (!the_menelaus->vcore_hw_mode) {
 		val = menelaus_read_reg(MENELAUS_VCORE_CTRL1);
 		/* HW mode, turn OFF byte comparator */
-		val |= ((1 << 7) | (1 << 5));
+		val |= (VCORE_CTRL1_HW_NSW | VCORE_CTRL1_BYP_COMP);
 		ret = menelaus_write_reg(MENELAUS_VCORE_CTRL1, val);
 		the_menelaus->vcore_hw_mode = 1;
 	}
@@ -749,7 +782,7 @@
 	ret = menelaus_read_reg(MENELAUS_GPIO_CTRL);
 	if (ret < 0)
 		goto out;
-	t = ((1 << 6) | 0x04);
+	t = (GPIO_CTRL_SLPCTLEN | GPIO3_DIR_INPUT);
 	if (enable)
 		ret |= t;
 	else
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index 7dd76bc..1823a57 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -70,7 +70,9 @@
 			goto fail_res;
 	}
 
-	platform_device_add_resources(pdev, res, cell->num_resources);
+	ret = platform_device_add_resources(pdev, res, cell->num_resources);
+	if (ret)
+		goto fail_res;
 
 	ret = platform_device_add(pdev);
 	if (ret)
diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c
new file mode 100644
index 0000000..0754c5e9
--- /dev/null
+++ b/drivers/mfd/stmpe.c
@@ -0,0 +1,985 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License, version 2
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/stmpe.h>
+#include "stmpe.h"
+
+static int __stmpe_enable(struct stmpe *stmpe, unsigned int blocks)
+{
+	return stmpe->variant->enable(stmpe, blocks, true);
+}
+
+static int __stmpe_disable(struct stmpe *stmpe, unsigned int blocks)
+{
+	return stmpe->variant->enable(stmpe, blocks, false);
+}
+
+static int __stmpe_reg_read(struct stmpe *stmpe, u8 reg)
+{
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(stmpe->i2c, reg);
+	if (ret < 0)
+		dev_err(stmpe->dev, "failed to read reg %#x: %d\n",
+			reg, ret);
+
+	dev_vdbg(stmpe->dev, "rd: reg %#x => data %#x\n", reg, ret);
+
+	return ret;
+}
+
+static int __stmpe_reg_write(struct stmpe *stmpe, u8 reg, u8 val)
+{
+	int ret;
+
+	dev_vdbg(stmpe->dev, "wr: reg %#x <= %#x\n", reg, val);
+
+	ret = i2c_smbus_write_byte_data(stmpe->i2c, reg, val);
+	if (ret < 0)
+		dev_err(stmpe->dev, "failed to write reg %#x: %d\n",
+			reg, ret);
+
+	return ret;
+}
+
+static int __stmpe_set_bits(struct stmpe *stmpe, u8 reg, u8 mask, u8 val)
+{
+	int ret;
+
+	ret = __stmpe_reg_read(stmpe, reg);
+	if (ret < 0)
+		return ret;
+
+	ret &= ~mask;
+	ret |= val;
+
+	return __stmpe_reg_write(stmpe, reg, ret);
+}
+
+static int __stmpe_block_read(struct stmpe *stmpe, u8 reg, u8 length,
+			      u8 *values)
+{
+	int ret;
+
+	ret = i2c_smbus_read_i2c_block_data(stmpe->i2c, reg, length, values);
+	if (ret < 0)
+		dev_err(stmpe->dev, "failed to read regs %#x: %d\n",
+			reg, ret);
+
+	dev_vdbg(stmpe->dev, "rd: reg %#x (%d) => ret %#x\n", reg, length, ret);
+	stmpe_dump_bytes("stmpe rd: ", values, length);
+
+	return ret;
+}
+
+static int __stmpe_block_write(struct stmpe *stmpe, u8 reg, u8 length,
+			const u8 *values)
+{
+	int ret;
+
+	dev_vdbg(stmpe->dev, "wr: regs %#x (%d)\n", reg, length);
+	stmpe_dump_bytes("stmpe wr: ", values, length);
+
+	ret = i2c_smbus_write_i2c_block_data(stmpe->i2c, reg, length,
+					     values);
+	if (ret < 0)
+		dev_err(stmpe->dev, "failed to write regs %#x: %d\n",
+			reg, ret);
+
+	return ret;
+}
+
+/**
+ * stmpe_enable - enable blocks on an STMPE device
+ * @stmpe:	Device to work on
+ * @blocks:	Mask of blocks (enum stmpe_block values) to enable
+ */
+int stmpe_enable(struct stmpe *stmpe, unsigned int blocks)
+{
+	int ret;
+
+	mutex_lock(&stmpe->lock);
+	ret = __stmpe_enable(stmpe, blocks);
+	mutex_unlock(&stmpe->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(stmpe_enable);
+
+/**
+ * stmpe_disable - disable blocks on an STMPE device
+ * @stmpe:	Device to work on
+ * @blocks:	Mask of blocks (enum stmpe_block values) to enable
+ */
+int stmpe_disable(struct stmpe *stmpe, unsigned int blocks)
+{
+	int ret;
+
+	mutex_lock(&stmpe->lock);
+	ret = __stmpe_disable(stmpe, blocks);
+	mutex_unlock(&stmpe->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(stmpe_disable);
+
+/**
+ * stmpe_reg_read() - read a single STMPE register
+ * @stmpe:	Device to read from
+ * @reg:	Register to read
+ */
+int stmpe_reg_read(struct stmpe *stmpe, u8 reg)
+{
+	int ret;
+
+	mutex_lock(&stmpe->lock);
+	ret = __stmpe_reg_read(stmpe, reg);
+	mutex_unlock(&stmpe->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(stmpe_reg_read);
+
+/**
+ * stmpe_reg_write() - write a single STMPE register
+ * @stmpe:	Device to write to
+ * @reg:	Register to write
+ * @val:	Value to write
+ */
+int stmpe_reg_write(struct stmpe *stmpe, u8 reg, u8 val)
+{
+	int ret;
+
+	mutex_lock(&stmpe->lock);
+	ret = __stmpe_reg_write(stmpe, reg, val);
+	mutex_unlock(&stmpe->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(stmpe_reg_write);
+
+/**
+ * stmpe_set_bits() - set the value of a bitfield in a STMPE register
+ * @stmpe:	Device to write to
+ * @reg:	Register to write
+ * @mask:	Mask of bits to set
+ * @val:	Value to set
+ */
+int stmpe_set_bits(struct stmpe *stmpe, u8 reg, u8 mask, u8 val)
+{
+	int ret;
+
+	mutex_lock(&stmpe->lock);
+	ret = __stmpe_set_bits(stmpe, reg, mask, val);
+	mutex_unlock(&stmpe->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(stmpe_set_bits);
+
+/**
+ * stmpe_block_read() - read multiple STMPE registers
+ * @stmpe:	Device to read from
+ * @reg:	First register
+ * @length:	Number of registers
+ * @values:	Buffer to write to
+ */
+int stmpe_block_read(struct stmpe *stmpe, u8 reg, u8 length, u8 *values)
+{
+	int ret;
+
+	mutex_lock(&stmpe->lock);
+	ret = __stmpe_block_read(stmpe, reg, length, values);
+	mutex_unlock(&stmpe->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(stmpe_block_read);
+
+/**
+ * stmpe_block_write() - write multiple STMPE registers
+ * @stmpe:	Device to write to
+ * @reg:	First register
+ * @length:	Number of registers
+ * @values:	Values to write
+ */
+int stmpe_block_write(struct stmpe *stmpe, u8 reg, u8 length,
+		      const u8 *values)
+{
+	int ret;
+
+	mutex_lock(&stmpe->lock);
+	ret = __stmpe_block_write(stmpe, reg, length, values);
+	mutex_unlock(&stmpe->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(stmpe_block_write);
+
+/**
+ * stmpe_set_altfunc: set the alternate function for STMPE pins
+ * @stmpe:	Device to configure
+ * @pins:	Bitmask of pins to affect
+ * @block:	block to enable alternate functions for
+ *
+ * @pins is assumed to have a bit set for each of the bits whose alternate
+ * function is to be changed, numbered according to the GPIOXY numbers.
+ *
+ * If the GPIO module is not enabled, this function automatically enables it in
+ * order to perform the change.
+ */
+int stmpe_set_altfunc(struct stmpe *stmpe, u32 pins, enum stmpe_block block)
+{
+	struct stmpe_variant_info *variant = stmpe->variant;
+	u8 regaddr = stmpe->regs[STMPE_IDX_GPAFR_U_MSB];
+	int af_bits = variant->af_bits;
+	int numregs = DIV_ROUND_UP(stmpe->num_gpios * af_bits, 8);
+	int afperreg = 8 / af_bits;
+	int mask = (1 << af_bits) - 1;
+	u8 regs[numregs];
+	int af;
+	int ret;
+
+	mutex_lock(&stmpe->lock);
+
+	ret = __stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
+	if (ret < 0)
+		goto out;
+
+	ret = __stmpe_block_read(stmpe, regaddr, numregs, regs);
+	if (ret < 0)
+		goto out;
+
+	af = variant->get_altfunc(stmpe, block);
+
+	while (pins) {
+		int pin = __ffs(pins);
+		int regoffset = numregs - (pin / afperreg) - 1;
+		int pos = (pin % afperreg) * (8 / afperreg);
+
+		regs[regoffset] &= ~(mask << pos);
+		regs[regoffset] |= af << pos;
+
+		pins &= ~(1 << pin);
+	}
+
+	ret = __stmpe_block_write(stmpe, regaddr, numregs, regs);
+
+out:
+	mutex_unlock(&stmpe->lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(stmpe_set_altfunc);
+
+/*
+ * GPIO (all variants)
+ */
+
+static struct resource stmpe_gpio_resources[] = {
+	/* Start and end filled dynamically */
+	{
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct mfd_cell stmpe_gpio_cell = {
+	.name		= "stmpe-gpio",
+	.resources	= stmpe_gpio_resources,
+	.num_resources	= ARRAY_SIZE(stmpe_gpio_resources),
+};
+
+/*
+ * Keypad (1601, 2401, 2403)
+ */
+
+static struct resource stmpe_keypad_resources[] = {
+	{
+		.name	= "KEYPAD",
+		.start	= 0,
+		.end	= 0,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "KEYPAD_OVER",
+		.start	= 1,
+		.end	= 1,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct mfd_cell stmpe_keypad_cell = {
+	.name		= "stmpe-keypad",
+	.resources	= stmpe_keypad_resources,
+	.num_resources	= ARRAY_SIZE(stmpe_keypad_resources),
+};
+
+/*
+ * Touchscreen (STMPE811)
+ */
+
+static struct resource stmpe_ts_resources[] = {
+	{
+		.name	= "TOUCH_DET",
+		.start	= 0,
+		.end	= 0,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.name	= "FIFO_TH",
+		.start	= 1,
+		.end	= 1,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct mfd_cell stmpe_ts_cell = {
+	.name		= "stmpe-ts",
+	.resources	= stmpe_ts_resources,
+	.num_resources	= ARRAY_SIZE(stmpe_ts_resources),
+};
+
+/*
+ * STMPE811
+ */
+
+static const u8 stmpe811_regs[] = {
+	[STMPE_IDX_CHIP_ID]	= STMPE811_REG_CHIP_ID,
+	[STMPE_IDX_ICR_LSB]	= STMPE811_REG_INT_CTRL,
+	[STMPE_IDX_IER_LSB]	= STMPE811_REG_INT_EN,
+	[STMPE_IDX_ISR_MSB]	= STMPE811_REG_INT_STA,
+	[STMPE_IDX_GPMR_LSB]	= STMPE811_REG_GPIO_MP_STA,
+	[STMPE_IDX_GPSR_LSB]	= STMPE811_REG_GPIO_SET_PIN,
+	[STMPE_IDX_GPCR_LSB]	= STMPE811_REG_GPIO_CLR_PIN,
+	[STMPE_IDX_GPDR_LSB]	= STMPE811_REG_GPIO_DIR,
+	[STMPE_IDX_GPRER_LSB]	= STMPE811_REG_GPIO_RE,
+	[STMPE_IDX_GPFER_LSB]	= STMPE811_REG_GPIO_FE,
+	[STMPE_IDX_GPAFR_U_MSB]	= STMPE811_REG_GPIO_AF,
+	[STMPE_IDX_IEGPIOR_LSB]	= STMPE811_REG_GPIO_INT_EN,
+	[STMPE_IDX_ISGPIOR_MSB]	= STMPE811_REG_GPIO_INT_STA,
+	[STMPE_IDX_GPEDR_MSB]	= STMPE811_REG_GPIO_ED,
+};
+
+static struct stmpe_variant_block stmpe811_blocks[] = {
+	{
+		.cell	= &stmpe_gpio_cell,
+		.irq	= STMPE811_IRQ_GPIOC,
+		.block	= STMPE_BLOCK_GPIO,
+	},
+	{
+		.cell	= &stmpe_ts_cell,
+		.irq	= STMPE811_IRQ_TOUCH_DET,
+		.block	= STMPE_BLOCK_TOUCHSCREEN,
+	},
+};
+
+static int stmpe811_enable(struct stmpe *stmpe, unsigned int blocks,
+			   bool enable)
+{
+	unsigned int mask = 0;
+
+	if (blocks & STMPE_BLOCK_GPIO)
+		mask |= STMPE811_SYS_CTRL2_GPIO_OFF;
+
+	if (blocks & STMPE_BLOCK_ADC)
+		mask |= STMPE811_SYS_CTRL2_ADC_OFF;
+
+	if (blocks & STMPE_BLOCK_TOUCHSCREEN)
+		mask |= STMPE811_SYS_CTRL2_TSC_OFF;
+
+	return __stmpe_set_bits(stmpe, STMPE811_REG_SYS_CTRL2, mask,
+				enable ? 0 : mask);
+}
+
+static int stmpe811_get_altfunc(struct stmpe *stmpe, enum stmpe_block block)
+{
+	/* 0 for touchscreen, 1 for GPIO */
+	return block != STMPE_BLOCK_TOUCHSCREEN;
+}
+
+static struct stmpe_variant_info stmpe811 = {
+	.name		= "stmpe811",
+	.id_val		= 0x0811,
+	.id_mask	= 0xffff,
+	.num_gpios	= 8,
+	.af_bits	= 1,
+	.regs		= stmpe811_regs,
+	.blocks		= stmpe811_blocks,
+	.num_blocks	= ARRAY_SIZE(stmpe811_blocks),
+	.num_irqs	= STMPE811_NR_INTERNAL_IRQS,
+	.enable		= stmpe811_enable,
+	.get_altfunc	= stmpe811_get_altfunc,
+};
+
+/*
+ * STMPE1601
+ */
+
+static const u8 stmpe1601_regs[] = {
+	[STMPE_IDX_CHIP_ID]	= STMPE1601_REG_CHIP_ID,
+	[STMPE_IDX_ICR_LSB]	= STMPE1601_REG_ICR_LSB,
+	[STMPE_IDX_IER_LSB]	= STMPE1601_REG_IER_LSB,
+	[STMPE_IDX_ISR_MSB]	= STMPE1601_REG_ISR_MSB,
+	[STMPE_IDX_GPMR_LSB]	= STMPE1601_REG_GPIO_MP_LSB,
+	[STMPE_IDX_GPSR_LSB]	= STMPE1601_REG_GPIO_SET_LSB,
+	[STMPE_IDX_GPCR_LSB]	= STMPE1601_REG_GPIO_CLR_LSB,
+	[STMPE_IDX_GPDR_LSB]	= STMPE1601_REG_GPIO_SET_DIR_LSB,
+	[STMPE_IDX_GPRER_LSB]	= STMPE1601_REG_GPIO_RE_LSB,
+	[STMPE_IDX_GPFER_LSB]	= STMPE1601_REG_GPIO_FE_LSB,
+	[STMPE_IDX_GPAFR_U_MSB]	= STMPE1601_REG_GPIO_AF_U_MSB,
+	[STMPE_IDX_IEGPIOR_LSB]	= STMPE1601_REG_INT_EN_GPIO_MASK_LSB,
+	[STMPE_IDX_ISGPIOR_MSB]	= STMPE1601_REG_INT_STA_GPIO_MSB,
+	[STMPE_IDX_GPEDR_MSB]	= STMPE1601_REG_GPIO_ED_MSB,
+};
+
+static struct stmpe_variant_block stmpe1601_blocks[] = {
+	{
+		.cell	= &stmpe_gpio_cell,
+		.irq	= STMPE24XX_IRQ_GPIOC,
+		.block	= STMPE_BLOCK_GPIO,
+	},
+	{
+		.cell	= &stmpe_keypad_cell,
+		.irq	= STMPE24XX_IRQ_KEYPAD,
+		.block	= STMPE_BLOCK_KEYPAD,
+	},
+};
+
+/* supported autosleep timeout delay (in msecs) */
+static const int stmpe_autosleep_delay[] = {
+	4, 16, 32, 64, 128, 256, 512, 1024,
+};
+
+static int stmpe_round_timeout(int timeout)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(stmpe_autosleep_delay); i++) {
+		if (stmpe_autosleep_delay[i] >= timeout)
+			return i;
+	}
+
+	/*
+	 * requests for delays longer than supported should not return the
+	 * longest supported delay
+	 */
+	return -EINVAL;
+}
+
+static int stmpe_autosleep(struct stmpe *stmpe, int autosleep_timeout)
+{
+	int ret;
+
+	if (!stmpe->variant->enable_autosleep)
+		return -ENOSYS;
+
+	mutex_lock(&stmpe->lock);
+	ret = stmpe->variant->enable_autosleep(stmpe, autosleep_timeout);
+	mutex_unlock(&stmpe->lock);
+
+	return ret;
+}
+
+/*
+ * Both stmpe 1601/2403 support same layout for autosleep
+ */
+static int stmpe1601_autosleep(struct stmpe *stmpe,
+		int autosleep_timeout)
+{
+	int ret, timeout;
+
+	/* choose the best available timeout */
+	timeout = stmpe_round_timeout(autosleep_timeout);
+	if (timeout < 0) {
+		dev_err(stmpe->dev, "invalid timeout\n");
+		return timeout;
+	}
+
+	ret = __stmpe_set_bits(stmpe, STMPE1601_REG_SYS_CTRL2,
+			STMPE1601_AUTOSLEEP_TIMEOUT_MASK,
+			timeout);
+	if (ret < 0)
+		return ret;
+
+	return __stmpe_set_bits(stmpe, STMPE1601_REG_SYS_CTRL2,
+			STPME1601_AUTOSLEEP_ENABLE,
+			STPME1601_AUTOSLEEP_ENABLE);
+}
+
+static int stmpe1601_enable(struct stmpe *stmpe, unsigned int blocks,
+			    bool enable)
+{
+	unsigned int mask = 0;
+
+	if (blocks & STMPE_BLOCK_GPIO)
+		mask |= STMPE1601_SYS_CTRL_ENABLE_GPIO;
+
+	if (blocks & STMPE_BLOCK_KEYPAD)
+		mask |= STMPE1601_SYS_CTRL_ENABLE_KPC;
+
+	return __stmpe_set_bits(stmpe, STMPE1601_REG_SYS_CTRL, mask,
+				enable ? mask : 0);
+}
+
+static int stmpe1601_get_altfunc(struct stmpe *stmpe, enum stmpe_block block)
+{
+	switch (block) {
+	case STMPE_BLOCK_PWM:
+		return 2;
+
+	case STMPE_BLOCK_KEYPAD:
+		return 1;
+
+	case STMPE_BLOCK_GPIO:
+	default:
+		return 0;
+	}
+}
+
+static struct stmpe_variant_info stmpe1601 = {
+	.name		= "stmpe1601",
+	.id_val		= 0x0210,
+	.id_mask	= 0xfff0,	/* at least 0x0210 and 0x0212 */
+	.num_gpios	= 16,
+	.af_bits	= 2,
+	.regs		= stmpe1601_regs,
+	.blocks		= stmpe1601_blocks,
+	.num_blocks	= ARRAY_SIZE(stmpe1601_blocks),
+	.num_irqs	= STMPE1601_NR_INTERNAL_IRQS,
+	.enable		= stmpe1601_enable,
+	.get_altfunc	= stmpe1601_get_altfunc,
+	.enable_autosleep	= stmpe1601_autosleep,
+};
+
+/*
+ * STMPE24XX
+ */
+
+static const u8 stmpe24xx_regs[] = {
+	[STMPE_IDX_CHIP_ID]	= STMPE24XX_REG_CHIP_ID,
+	[STMPE_IDX_ICR_LSB]	= STMPE24XX_REG_ICR_LSB,
+	[STMPE_IDX_IER_LSB]	= STMPE24XX_REG_IER_LSB,
+	[STMPE_IDX_ISR_MSB]	= STMPE24XX_REG_ISR_MSB,
+	[STMPE_IDX_GPMR_LSB]	= STMPE24XX_REG_GPMR_LSB,
+	[STMPE_IDX_GPSR_LSB]	= STMPE24XX_REG_GPSR_LSB,
+	[STMPE_IDX_GPCR_LSB]	= STMPE24XX_REG_GPCR_LSB,
+	[STMPE_IDX_GPDR_LSB]	= STMPE24XX_REG_GPDR_LSB,
+	[STMPE_IDX_GPRER_LSB]	= STMPE24XX_REG_GPRER_LSB,
+	[STMPE_IDX_GPFER_LSB]	= STMPE24XX_REG_GPFER_LSB,
+	[STMPE_IDX_GPAFR_U_MSB]	= STMPE24XX_REG_GPAFR_U_MSB,
+	[STMPE_IDX_IEGPIOR_LSB]	= STMPE24XX_REG_IEGPIOR_LSB,
+	[STMPE_IDX_ISGPIOR_MSB]	= STMPE24XX_REG_ISGPIOR_MSB,
+	[STMPE_IDX_GPEDR_MSB]	= STMPE24XX_REG_GPEDR_MSB,
+};
+
+static struct stmpe_variant_block stmpe24xx_blocks[] = {
+	{
+		.cell	= &stmpe_gpio_cell,
+		.irq	= STMPE24XX_IRQ_GPIOC,
+		.block	= STMPE_BLOCK_GPIO,
+	},
+	{
+		.cell	= &stmpe_keypad_cell,
+		.irq	= STMPE24XX_IRQ_KEYPAD,
+		.block	= STMPE_BLOCK_KEYPAD,
+	},
+};
+
+static int stmpe24xx_enable(struct stmpe *stmpe, unsigned int blocks,
+			    bool enable)
+{
+	unsigned int mask = 0;
+
+	if (blocks & STMPE_BLOCK_GPIO)
+		mask |= STMPE24XX_SYS_CTRL_ENABLE_GPIO;
+
+	if (blocks & STMPE_BLOCK_KEYPAD)
+		mask |= STMPE24XX_SYS_CTRL_ENABLE_KPC;
+
+	return __stmpe_set_bits(stmpe, STMPE24XX_REG_SYS_CTRL, mask,
+				enable ? mask : 0);
+}
+
+static int stmpe24xx_get_altfunc(struct stmpe *stmpe, enum stmpe_block block)
+{
+	switch (block) {
+	case STMPE_BLOCK_ROTATOR:
+		return 2;
+
+	case STMPE_BLOCK_KEYPAD:
+		return 1;
+
+	case STMPE_BLOCK_GPIO:
+	default:
+		return 0;
+	}
+}
+
+static struct stmpe_variant_info stmpe2401 = {
+	.name		= "stmpe2401",
+	.id_val		= 0x0101,
+	.id_mask	= 0xffff,
+	.num_gpios	= 24,
+	.af_bits	= 2,
+	.regs		= stmpe24xx_regs,
+	.blocks		= stmpe24xx_blocks,
+	.num_blocks	= ARRAY_SIZE(stmpe24xx_blocks),
+	.num_irqs	= STMPE24XX_NR_INTERNAL_IRQS,
+	.enable		= stmpe24xx_enable,
+	.get_altfunc	= stmpe24xx_get_altfunc,
+};
+
+static struct stmpe_variant_info stmpe2403 = {
+	.name		= "stmpe2403",
+	.id_val		= 0x0120,
+	.id_mask	= 0xffff,
+	.num_gpios	= 24,
+	.af_bits	= 2,
+	.regs		= stmpe24xx_regs,
+	.blocks		= stmpe24xx_blocks,
+	.num_blocks	= ARRAY_SIZE(stmpe24xx_blocks),
+	.num_irqs	= STMPE24XX_NR_INTERNAL_IRQS,
+	.enable		= stmpe24xx_enable,
+	.get_altfunc	= stmpe24xx_get_altfunc,
+	.enable_autosleep	= stmpe1601_autosleep, /* same as stmpe1601 */
+};
+
+static struct stmpe_variant_info *stmpe_variant_info[] = {
+	[STMPE811]	= &stmpe811,
+	[STMPE1601]	= &stmpe1601,
+	[STMPE2401]	= &stmpe2401,
+	[STMPE2403]	= &stmpe2403,
+};
+
+static irqreturn_t stmpe_irq(int irq, void *data)
+{
+	struct stmpe *stmpe = data;
+	struct stmpe_variant_info *variant = stmpe->variant;
+	int num = DIV_ROUND_UP(variant->num_irqs, 8);
+	u8 israddr = stmpe->regs[STMPE_IDX_ISR_MSB];
+	u8 isr[num];
+	int ret;
+	int i;
+
+	ret = stmpe_block_read(stmpe, israddr, num, isr);
+	if (ret < 0)
+		return IRQ_NONE;
+
+	for (i = 0; i < num; i++) {
+		int bank = num - i - 1;
+		u8 status = isr[i];
+		u8 clear;
+
+		status &= stmpe->ier[bank];
+		if (!status)
+			continue;
+
+		clear = status;
+		while (status) {
+			int bit = __ffs(status);
+			int line = bank * 8 + bit;
+
+			handle_nested_irq(stmpe->irq_base + line);
+			status &= ~(1 << bit);
+		}
+
+		stmpe_reg_write(stmpe, israddr + i, clear);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void stmpe_irq_lock(unsigned int irq)
+{
+	struct stmpe *stmpe = get_irq_chip_data(irq);
+
+	mutex_lock(&stmpe->irq_lock);
+}
+
+static void stmpe_irq_sync_unlock(unsigned int irq)
+{
+	struct stmpe *stmpe = get_irq_chip_data(irq);
+	struct stmpe_variant_info *variant = stmpe->variant;
+	int num = DIV_ROUND_UP(variant->num_irqs, 8);
+	int i;
+
+	for (i = 0; i < num; i++) {
+		u8 new = stmpe->ier[i];
+		u8 old = stmpe->oldier[i];
+
+		if (new == old)
+			continue;
+
+		stmpe->oldier[i] = new;
+		stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_IER_LSB] - i, new);
+	}
+
+	mutex_unlock(&stmpe->irq_lock);
+}
+
+static void stmpe_irq_mask(unsigned int irq)
+{
+	struct stmpe *stmpe = get_irq_chip_data(irq);
+	int offset = irq - stmpe->irq_base;
+	int regoffset = offset / 8;
+	int mask = 1 << (offset % 8);
+
+	stmpe->ier[regoffset] &= ~mask;
+}
+
+static void stmpe_irq_unmask(unsigned int irq)
+{
+	struct stmpe *stmpe = get_irq_chip_data(irq);
+	int offset = irq - stmpe->irq_base;
+	int regoffset = offset / 8;
+	int mask = 1 << (offset % 8);
+
+	stmpe->ier[regoffset] |= mask;
+}
+
+static struct irq_chip stmpe_irq_chip = {
+	.name			= "stmpe",
+	.bus_lock		= stmpe_irq_lock,
+	.bus_sync_unlock	= stmpe_irq_sync_unlock,
+	.mask			= stmpe_irq_mask,
+	.unmask			= stmpe_irq_unmask,
+};
+
+static int __devinit stmpe_irq_init(struct stmpe *stmpe)
+{
+	int num_irqs = stmpe->variant->num_irqs;
+	int base = stmpe->irq_base;
+	int irq;
+
+	for (irq = base; irq < base + num_irqs; irq++) {
+		set_irq_chip_data(irq, stmpe);
+		set_irq_chip_and_handler(irq, &stmpe_irq_chip,
+					 handle_edge_irq);
+		set_irq_nested_thread(irq, 1);
+#ifdef CONFIG_ARM
+		set_irq_flags(irq, IRQF_VALID);
+#else
+		set_irq_noprobe(irq);
+#endif
+	}
+
+	return 0;
+}
+
+static void stmpe_irq_remove(struct stmpe *stmpe)
+{
+	int num_irqs = stmpe->variant->num_irqs;
+	int base = stmpe->irq_base;
+	int irq;
+
+	for (irq = base; irq < base + num_irqs; irq++) {
+#ifdef CONFIG_ARM
+		set_irq_flags(irq, 0);
+#endif
+		set_irq_chip_and_handler(irq, NULL, NULL);
+		set_irq_chip_data(irq, NULL);
+	}
+}
+
+static int __devinit stmpe_chip_init(struct stmpe *stmpe)
+{
+	unsigned int irq_trigger = stmpe->pdata->irq_trigger;
+	int autosleep_timeout = stmpe->pdata->autosleep_timeout;
+	struct stmpe_variant_info *variant = stmpe->variant;
+	u8 icr = STMPE_ICR_LSB_GIM;
+	unsigned int id;
+	u8 data[2];
+	int ret;
+
+	ret = stmpe_block_read(stmpe, stmpe->regs[STMPE_IDX_CHIP_ID],
+			       ARRAY_SIZE(data), data);
+	if (ret < 0)
+		return ret;
+
+	id = (data[0] << 8) | data[1];
+	if ((id & variant->id_mask) != variant->id_val) {
+		dev_err(stmpe->dev, "unknown chip id: %#x\n", id);
+		return -EINVAL;
+	}
+
+	dev_info(stmpe->dev, "%s detected, chip id: %#x\n", variant->name, id);
+
+	/* Disable all modules -- subdrivers should enable what they need. */
+	ret = stmpe_disable(stmpe, ~0);
+	if (ret)
+		return ret;
+
+	if (irq_trigger == IRQF_TRIGGER_FALLING ||
+	    irq_trigger == IRQF_TRIGGER_RISING)
+		icr |= STMPE_ICR_LSB_EDGE;
+
+	if (irq_trigger == IRQF_TRIGGER_RISING ||
+	    irq_trigger == IRQF_TRIGGER_HIGH)
+		icr |= STMPE_ICR_LSB_HIGH;
+
+	if (stmpe->pdata->irq_invert_polarity)
+		icr ^= STMPE_ICR_LSB_HIGH;
+
+	if (stmpe->pdata->autosleep) {
+		ret = stmpe_autosleep(stmpe, autosleep_timeout);
+		if (ret)
+			return ret;
+	}
+
+	return stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_ICR_LSB], icr);
+}
+
+static int __devinit stmpe_add_device(struct stmpe *stmpe,
+				      struct mfd_cell *cell, int irq)
+{
+	return mfd_add_devices(stmpe->dev, stmpe->pdata->id, cell, 1,
+			       NULL, stmpe->irq_base + irq);
+}
+
+static int __devinit stmpe_devices_init(struct stmpe *stmpe)
+{
+	struct stmpe_variant_info *variant = stmpe->variant;
+	unsigned int platform_blocks = stmpe->pdata->blocks;
+	int ret = -EINVAL;
+	int i;
+
+	for (i = 0; i < variant->num_blocks; i++) {
+		struct stmpe_variant_block *block = &variant->blocks[i];
+
+		if (!(platform_blocks & block->block))
+			continue;
+
+		platform_blocks &= ~block->block;
+		ret = stmpe_add_device(stmpe, block->cell, block->irq);
+		if (ret)
+			return ret;
+	}
+
+	if (platform_blocks)
+		dev_warn(stmpe->dev,
+			 "platform wants blocks (%#x) not present on variant",
+			 platform_blocks);
+
+	return ret;
+}
+
+static int __devinit stmpe_probe(struct i2c_client *i2c,
+				 const struct i2c_device_id *id)
+{
+	struct stmpe_platform_data *pdata = i2c->dev.platform_data;
+	struct stmpe *stmpe;
+	int ret;
+
+	if (!pdata)
+		return -EINVAL;
+
+	stmpe = kzalloc(sizeof(struct stmpe), GFP_KERNEL);
+	if (!stmpe)
+		return -ENOMEM;
+
+	mutex_init(&stmpe->irq_lock);
+	mutex_init(&stmpe->lock);
+
+	stmpe->dev = &i2c->dev;
+	stmpe->i2c = i2c;
+
+	stmpe->pdata = pdata;
+	stmpe->irq_base = pdata->irq_base;
+
+	stmpe->partnum = id->driver_data;
+	stmpe->variant = stmpe_variant_info[stmpe->partnum];
+	stmpe->regs = stmpe->variant->regs;
+	stmpe->num_gpios = stmpe->variant->num_gpios;
+
+	i2c_set_clientdata(i2c, stmpe);
+
+	ret = stmpe_chip_init(stmpe);
+	if (ret)
+		goto out_free;
+
+	ret = stmpe_irq_init(stmpe);
+	if (ret)
+		goto out_free;
+
+	ret = request_threaded_irq(stmpe->i2c->irq, NULL, stmpe_irq,
+				   pdata->irq_trigger | IRQF_ONESHOT,
+				   "stmpe", stmpe);
+	if (ret) {
+		dev_err(stmpe->dev, "failed to request IRQ: %d\n", ret);
+		goto out_removeirq;
+	}
+
+	ret = stmpe_devices_init(stmpe);
+	if (ret) {
+		dev_err(stmpe->dev, "failed to add children\n");
+		goto out_removedevs;
+	}
+
+	return 0;
+
+out_removedevs:
+	mfd_remove_devices(stmpe->dev);
+	free_irq(stmpe->i2c->irq, stmpe);
+out_removeirq:
+	stmpe_irq_remove(stmpe);
+out_free:
+	kfree(stmpe);
+	return ret;
+}
+
+static int __devexit stmpe_remove(struct i2c_client *client)
+{
+	struct stmpe *stmpe = i2c_get_clientdata(client);
+
+	mfd_remove_devices(stmpe->dev);
+
+	free_irq(stmpe->i2c->irq, stmpe);
+	stmpe_irq_remove(stmpe);
+
+	kfree(stmpe);
+
+	return 0;
+}
+
+static const struct i2c_device_id stmpe_id[] = {
+	{ "stmpe811", STMPE811 },
+	{ "stmpe1601", STMPE1601 },
+	{ "stmpe2401", STMPE2401 },
+	{ "stmpe2403", STMPE2403 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, stmpe_id);
+
+static struct i2c_driver stmpe_driver = {
+	.driver.name	= "stmpe",
+	.driver.owner	= THIS_MODULE,
+	.probe		= stmpe_probe,
+	.remove		= __devexit_p(stmpe_remove),
+	.id_table	= stmpe_id,
+};
+
+static int __init stmpe_init(void)
+{
+	return i2c_add_driver(&stmpe_driver);
+}
+subsys_initcall(stmpe_init);
+
+static void __exit stmpe_exit(void)
+{
+	i2c_del_driver(&stmpe_driver);
+}
+module_exit(stmpe_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("STMPE MFD core driver");
+MODULE_AUTHOR("Rabin Vincent <rabin.vincent@stericsson.com>");
diff --git a/drivers/mfd/stmpe.h b/drivers/mfd/stmpe.h
new file mode 100644
index 0000000..0dbdc4e
--- /dev/null
+++ b/drivers/mfd/stmpe.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License, version 2
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ */
+
+#ifndef __STMPE_H
+#define __STMPE_H
+
+#ifdef STMPE_DUMP_BYTES
+static inline void stmpe_dump_bytes(const char *str, const void *buf,
+				    size_t len)
+{
+	print_hex_dump_bytes(str, DUMP_PREFIX_OFFSET, buf, len);
+}
+#else
+static inline void stmpe_dump_bytes(const char *str, const void *buf,
+				    size_t len)
+{
+}
+#endif
+
+/**
+ * struct stmpe_variant_block - information about block
+ * @cell:	base mfd cell
+ * @irq:	interrupt number to be added to each IORESOURCE_IRQ
+ *		in the cell
+ * @block:	block id; used for identification with platform data and for
+ *		enable and altfunc callbacks
+ */
+struct stmpe_variant_block {
+	struct mfd_cell		*cell;
+	int			irq;
+	enum stmpe_block	block;
+};
+
+/**
+ * struct stmpe_variant_info - variant-specific information
+ * @name:	part name
+ * @id_val:	content of CHIPID register
+ * @id_mask:	bits valid in CHIPID register for comparison with id_val
+ * @num_gpios:	number of GPIOS
+ * @af_bits:	number of bits used to specify the alternate function
+ * @blocks:	list of blocks present on this device
+ * @num_blocks:	number of blocks present on this device
+ * @num_irqs:	number of internal IRQs available on this device
+ * @enable:	callback to enable the specified blocks.
+ *		Called with the I/O lock held.
+ * @get_altfunc: callback to get the alternate function number for the
+ *		 specific block
+ * @enable_autosleep: callback to configure autosleep with specified timeout
+ */
+struct stmpe_variant_info {
+	const char *name;
+	u16 id_val;
+	u16 id_mask;
+	int num_gpios;
+	int af_bits;
+	const u8 *regs;
+	struct stmpe_variant_block *blocks;
+	int num_blocks;
+	int num_irqs;
+	int (*enable)(struct stmpe *stmpe, unsigned int blocks, bool enable);
+	int (*get_altfunc)(struct stmpe *stmpe, enum stmpe_block block);
+	int (*enable_autosleep)(struct stmpe *stmpe, int autosleep_timeout);
+};
+
+#define STMPE_ICR_LSB_HIGH	(1 << 2)
+#define STMPE_ICR_LSB_EDGE	(1 << 1)
+#define STMPE_ICR_LSB_GIM	(1 << 0)
+
+/*
+ * STMPE811
+ */
+
+#define STMPE811_IRQ_TOUCH_DET		0
+#define STMPE811_IRQ_FIFO_TH		1
+#define STMPE811_IRQ_FIFO_OFLOW		2
+#define STMPE811_IRQ_FIFO_FULL		3
+#define STMPE811_IRQ_FIFO_EMPTY		4
+#define STMPE811_IRQ_TEMP_SENS		5
+#define STMPE811_IRQ_ADC		6
+#define STMPE811_IRQ_GPIOC		7
+#define STMPE811_NR_INTERNAL_IRQS	8
+
+#define STMPE811_REG_CHIP_ID		0x00
+#define STMPE811_REG_SYS_CTRL2		0x04
+#define STMPE811_REG_INT_CTRL		0x09
+#define STMPE811_REG_INT_EN		0x0A
+#define STMPE811_REG_INT_STA		0x0B
+#define STMPE811_REG_GPIO_INT_EN	0x0C
+#define STMPE811_REG_GPIO_INT_STA	0x0D
+#define STMPE811_REG_GPIO_SET_PIN	0x10
+#define STMPE811_REG_GPIO_CLR_PIN	0x11
+#define STMPE811_REG_GPIO_MP_STA	0x12
+#define STMPE811_REG_GPIO_DIR		0x13
+#define STMPE811_REG_GPIO_ED		0x14
+#define STMPE811_REG_GPIO_RE		0x15
+#define STMPE811_REG_GPIO_FE		0x16
+#define STMPE811_REG_GPIO_AF		0x17
+
+#define STMPE811_SYS_CTRL2_ADC_OFF	(1 << 0)
+#define STMPE811_SYS_CTRL2_TSC_OFF	(1 << 1)
+#define STMPE811_SYS_CTRL2_GPIO_OFF	(1 << 2)
+#define STMPE811_SYS_CTRL2_TS_OFF	(1 << 3)
+
+/*
+ * STMPE1601
+ */
+
+#define STMPE1601_IRQ_GPIOC		8
+#define STMPE1601_IRQ_PWM3		7
+#define STMPE1601_IRQ_PWM2		6
+#define STMPE1601_IRQ_PWM1		5
+#define STMPE1601_IRQ_PWM0		4
+#define STMPE1601_IRQ_KEYPAD_OVER	2
+#define STMPE1601_IRQ_KEYPAD		1
+#define STMPE1601_IRQ_WAKEUP		0
+#define STMPE1601_NR_INTERNAL_IRQS	9
+
+#define STMPE1601_REG_SYS_CTRL			0x02
+#define STMPE1601_REG_SYS_CTRL2			0x03
+#define STMPE1601_REG_ICR_LSB			0x11
+#define STMPE1601_REG_IER_LSB			0x13
+#define STMPE1601_REG_ISR_MSB			0x14
+#define STMPE1601_REG_CHIP_ID			0x80
+#define STMPE1601_REG_INT_EN_GPIO_MASK_LSB	0x17
+#define STMPE1601_REG_INT_STA_GPIO_MSB		0x18
+#define STMPE1601_REG_GPIO_MP_LSB		0x87
+#define STMPE1601_REG_GPIO_SET_LSB		0x83
+#define STMPE1601_REG_GPIO_CLR_LSB		0x85
+#define STMPE1601_REG_GPIO_SET_DIR_LSB		0x89
+#define STMPE1601_REG_GPIO_ED_MSB		0x8A
+#define STMPE1601_REG_GPIO_RE_LSB		0x8D
+#define STMPE1601_REG_GPIO_FE_LSB		0x8F
+#define STMPE1601_REG_GPIO_AF_U_MSB		0x92
+
+#define STMPE1601_SYS_CTRL_ENABLE_GPIO		(1 << 3)
+#define STMPE1601_SYS_CTRL_ENABLE_KPC		(1 << 1)
+#define STMPE1601_SYSCON_ENABLE_SPWM		(1 << 0)
+
+/* The 1601/2403 share the same masks */
+#define STMPE1601_AUTOSLEEP_TIMEOUT_MASK	(0x7)
+#define STPME1601_AUTOSLEEP_ENABLE		(1 << 3)
+
+/*
+ * STMPE24xx
+ */
+
+#define STMPE24XX_IRQ_GPIOC		8
+#define STMPE24XX_IRQ_PWM2		7
+#define STMPE24XX_IRQ_PWM1		6
+#define STMPE24XX_IRQ_PWM0		5
+#define STMPE24XX_IRQ_ROT_OVER		4
+#define STMPE24XX_IRQ_ROT		3
+#define STMPE24XX_IRQ_KEYPAD_OVER	2
+#define STMPE24XX_IRQ_KEYPAD		1
+#define STMPE24XX_IRQ_WAKEUP		0
+#define STMPE24XX_NR_INTERNAL_IRQS	9
+
+#define STMPE24XX_REG_SYS_CTRL		0x02
+#define STMPE24XX_REG_ICR_LSB		0x11
+#define STMPE24XX_REG_IER_LSB		0x13
+#define STMPE24XX_REG_ISR_MSB		0x14
+#define STMPE24XX_REG_CHIP_ID		0x80
+#define STMPE24XX_REG_IEGPIOR_LSB	0x18
+#define STMPE24XX_REG_ISGPIOR_MSB	0x19
+#define STMPE24XX_REG_GPMR_LSB		0xA5
+#define STMPE24XX_REG_GPSR_LSB		0x85
+#define STMPE24XX_REG_GPCR_LSB		0x88
+#define STMPE24XX_REG_GPDR_LSB		0x8B
+#define STMPE24XX_REG_GPEDR_MSB		0x8C
+#define STMPE24XX_REG_GPRER_LSB		0x91
+#define STMPE24XX_REG_GPFER_LSB		0x94
+#define STMPE24XX_REG_GPAFR_U_MSB	0x9B
+
+#define STMPE24XX_SYS_CTRL_ENABLE_GPIO		(1 << 3)
+#define STMPE24XX_SYSCON_ENABLE_PWM		(1 << 2)
+#define STMPE24XX_SYS_CTRL_ENABLE_KPC		(1 << 1)
+#define STMPE24XX_SYSCON_ENABLE_ROT		(1 << 0)
+
+#endif
diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c
index 5041d33..006c121 100644
--- a/drivers/mfd/t7l66xb.c
+++ b/drivers/mfd/t7l66xb.c
@@ -350,7 +350,6 @@
 	t7l66xb->clk48m = clk_get(&dev->dev, "CLK_CK48M");
 	if (IS_ERR(t7l66xb->clk48m)) {
 		ret = PTR_ERR(t7l66xb->clk48m);
-		clk_put(t7l66xb->clk32k);
 		goto err_clk48m_get;
 	}
 
@@ -425,6 +424,8 @@
 	ret = pdata->disable(dev);
 	clk_disable(t7l66xb->clk48m);
 	clk_put(t7l66xb->clk48m);
+	clk_disable(t7l66xb->clk32k);
+	clk_put(t7l66xb->clk32k);
 	t7l66xb_detach_irq(dev);
 	iounmap(t7l66xb->scr);
 	release_resource(&t7l66xb->rscr);
diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c
index 517f9bc..6315f63 100644
--- a/drivers/mfd/tc6387xb.c
+++ b/drivers/mfd/tc6387xb.c
@@ -137,7 +137,7 @@
 	},
 };
 
-static int tc6387xb_probe(struct platform_device *dev)
+static int __devinit tc6387xb_probe(struct platform_device *dev)
 {
 	struct tc6387xb_platform_data *pdata = dev->dev.platform_data;
 	struct resource *iomem, *rscr;
@@ -201,6 +201,7 @@
 	if (!ret)
 		return 0;
 
+	iounmap(tc6387xb->scr);
 err_ioremap:
 	release_resource(&tc6387xb->rscr);
 err_resource:
@@ -211,14 +212,17 @@
 	return ret;
 }
 
-static int tc6387xb_remove(struct platform_device *dev)
+static int __devexit tc6387xb_remove(struct platform_device *dev)
 {
-	struct clk *clk32k = platform_get_drvdata(dev);
+	struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
 
 	mfd_remove_devices(&dev->dev);
-	clk_disable(clk32k);
-	clk_put(clk32k);
+	iounmap(tc6387xb->scr);
+	release_resource(&tc6387xb->rscr);
+	clk_disable(tc6387xb->clk32k);
+	clk_put(tc6387xb->clk32k);
 	platform_set_drvdata(dev, NULL);
+	kfree(tc6387xb);
 
 	return 0;
 }
@@ -229,7 +233,7 @@
 		.name		= "tc6387xb",
 	},
 	.probe		= tc6387xb_probe,
-	.remove		= tc6387xb_remove,
+	.remove		= __devexit_p(tc6387xb_remove),
 	.suspend        = tc6387xb_suspend,
 	.resume         = tc6387xb_resume,
 };
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c
index fcf9068..ef6c42c 100644
--- a/drivers/mfd/tc6393xb.c
+++ b/drivers/mfd/tc6393xb.c
@@ -732,9 +732,9 @@
 	if (tc6393xb->gpio.base != -1)
 		temp = gpiochip_remove(&tc6393xb->gpio);
 	tcpd->disable(dev);
-err_clk_enable:
-	clk_disable(tc6393xb->clk);
 err_enable:
+	clk_disable(tc6393xb->clk);
+err_clk_enable:
 	iounmap(tc6393xb->scr);
 err_ioremap:
 	release_resource(&tc6393xb->rscr);
diff --git a/drivers/mfd/tps6507x.c b/drivers/mfd/tps6507x.c
index d859dff..fc01976 100644
--- a/drivers/mfd/tps6507x.c
+++ b/drivers/mfd/tps6507x.c
@@ -89,10 +89,8 @@
 	int ret = 0;
 
 	tps6507x = kzalloc(sizeof(struct tps6507x_dev), GFP_KERNEL);
-	if (tps6507x == NULL) {
-		kfree(i2c);
+	if (tps6507x == NULL)
 		return -ENOMEM;
-	}
 
 	i2c_set_clientdata(i2c, tps6507x);
 	tps6507x->dev = &i2c->dev;
diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c
new file mode 100644
index 0000000..4cde31e
--- /dev/null
+++ b/drivers/mfd/tps6586x.c
@@ -0,0 +1,375 @@
+/*
+ * Core driver for TI TPS6586x PMIC family
+ *
+ * Copyright (c) 2010 CompuLab Ltd.
+ * Mike Rapoport <mike@compulab.co.il>
+ *
+ * Based on da903x.c.
+ * Copyright (C) 2008 Compulab, Ltd.
+ * Mike Rapoport <mike@compulab.co.il>
+ * Copyright (C) 2006-2008 Marvell International Ltd.
+ * Eric Miao <eric.miao@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+
+#include <linux/mfd/core.h>
+#include <linux/mfd/tps6586x.h>
+
+/* GPIO control registers */
+#define TPS6586X_GPIOSET1	0x5d
+#define TPS6586X_GPIOSET2	0x5e
+
+/* device id */
+#define TPS6586X_VERSIONCRC	0xcd
+#define TPS658621A_VERSIONCRC	0x15
+
+struct tps6586x {
+	struct mutex		lock;
+	struct device		*dev;
+	struct i2c_client	*client;
+
+	struct gpio_chip	gpio;
+};
+
+static inline int __tps6586x_read(struct i2c_client *client,
+				  int reg, uint8_t *val)
+{
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(client, reg);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed reading at 0x%02x\n", reg);
+		return ret;
+	}
+
+	*val = (uint8_t)ret;
+
+	return 0;
+}
+
+static inline int __tps6586x_reads(struct i2c_client *client, int reg,
+				   int len, uint8_t *val)
+{
+	int ret;
+
+	ret = i2c_smbus_read_i2c_block_data(client, reg, len, val);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed reading from 0x%02x\n", reg);
+		return ret;
+	}
+
+	return 0;
+}
+
+static inline int __tps6586x_write(struct i2c_client *client,
+				 int reg, uint8_t val)
+{
+	int ret;
+
+	ret = i2c_smbus_write_byte_data(client, reg, val);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed writing 0x%02x to 0x%02x\n",
+				val, reg);
+		return ret;
+	}
+
+	return 0;
+}
+
+static inline int __tps6586x_writes(struct i2c_client *client, int reg,
+				  int len, uint8_t *val)
+{
+	int ret;
+
+	ret = i2c_smbus_write_i2c_block_data(client, reg, len, val);
+	if (ret < 0) {
+		dev_err(&client->dev, "failed writings to 0x%02x\n", reg);
+		return ret;
+	}
+
+	return 0;
+}
+
+int tps6586x_write(struct device *dev, int reg, uint8_t val)
+{
+	return __tps6586x_write(to_i2c_client(dev), reg, val);
+}
+EXPORT_SYMBOL_GPL(tps6586x_write);
+
+int tps6586x_writes(struct device *dev, int reg, int len, uint8_t *val)
+{
+	return __tps6586x_writes(to_i2c_client(dev), reg, len, val);
+}
+EXPORT_SYMBOL_GPL(tps6586x_writes);
+
+int tps6586x_read(struct device *dev, int reg, uint8_t *val)
+{
+	return __tps6586x_read(to_i2c_client(dev), reg, val);
+}
+EXPORT_SYMBOL_GPL(tps6586x_read);
+
+int tps6586x_reads(struct device *dev, int reg, int len, uint8_t *val)
+{
+	return __tps6586x_reads(to_i2c_client(dev), reg, len, val);
+}
+EXPORT_SYMBOL_GPL(tps6586x_reads);
+
+int tps6586x_set_bits(struct device *dev, int reg, uint8_t bit_mask)
+{
+	struct tps6586x *tps6586x = dev_get_drvdata(dev);
+	uint8_t reg_val;
+	int ret = 0;
+
+	mutex_lock(&tps6586x->lock);
+
+	ret = __tps6586x_read(to_i2c_client(dev), reg, &reg_val);
+	if (ret)
+		goto out;
+
+	if ((reg_val & bit_mask) == 0) {
+		reg_val |= bit_mask;
+		ret = __tps6586x_write(to_i2c_client(dev), reg, reg_val);
+	}
+out:
+	mutex_unlock(&tps6586x->lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(tps6586x_set_bits);
+
+int tps6586x_clr_bits(struct device *dev, int reg, uint8_t bit_mask)
+{
+	struct tps6586x *tps6586x = dev_get_drvdata(dev);
+	uint8_t reg_val;
+	int ret = 0;
+
+	mutex_lock(&tps6586x->lock);
+
+	ret = __tps6586x_read(to_i2c_client(dev), reg, &reg_val);
+	if (ret)
+		goto out;
+
+	if (reg_val & bit_mask) {
+		reg_val &= ~bit_mask;
+		ret = __tps6586x_write(to_i2c_client(dev), reg, reg_val);
+	}
+out:
+	mutex_unlock(&tps6586x->lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(tps6586x_clr_bits);
+
+int tps6586x_update(struct device *dev, int reg, uint8_t val, uint8_t mask)
+{
+	struct tps6586x *tps6586x = dev_get_drvdata(dev);
+	uint8_t reg_val;
+	int ret = 0;
+
+	mutex_lock(&tps6586x->lock);
+
+	ret = __tps6586x_read(tps6586x->client, reg, &reg_val);
+	if (ret)
+		goto out;
+
+	if ((reg_val & mask) != val) {
+		reg_val = (reg_val & ~mask) | val;
+		ret = __tps6586x_write(tps6586x->client, reg, reg_val);
+	}
+out:
+	mutex_unlock(&tps6586x->lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(tps6586x_update);
+
+static int tps6586x_gpio_get(struct gpio_chip *gc, unsigned offset)
+{
+	struct tps6586x *tps6586x = container_of(gc, struct tps6586x, gpio);
+	uint8_t val;
+	int ret;
+
+	ret = __tps6586x_read(tps6586x->client, TPS6586X_GPIOSET2, &val);
+	if (ret)
+		return ret;
+
+	return !!(val & (1 << offset));
+}
+
+
+static void tps6586x_gpio_set(struct gpio_chip *chip, unsigned offset,
+			      int value)
+{
+	struct tps6586x *tps6586x = container_of(chip, struct tps6586x, gpio);
+
+	__tps6586x_write(tps6586x->client, TPS6586X_GPIOSET2,
+			 value << offset);
+}
+
+static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset,
+				int value)
+{
+	struct tps6586x *tps6586x = container_of(gc, struct tps6586x, gpio);
+	uint8_t val, mask;
+
+	tps6586x_gpio_set(gc, offset, value);
+
+	val = 0x1 << (offset * 2);
+	mask = 0x3 << (offset * 2);
+
+	return tps6586x_update(tps6586x->dev, TPS6586X_GPIOSET1, val, mask);
+}
+
+static void tps6586x_gpio_init(struct tps6586x *tps6586x, int gpio_base)
+{
+	int ret;
+
+	if (!gpio_base)
+		return;
+
+	tps6586x->gpio.owner		= THIS_MODULE;
+	tps6586x->gpio.label		= tps6586x->client->name;
+	tps6586x->gpio.dev		= tps6586x->dev;
+	tps6586x->gpio.base		= gpio_base;
+	tps6586x->gpio.ngpio		= 4;
+	tps6586x->gpio.can_sleep	= 1;
+
+	/* FIXME: add handling of GPIOs as dedicated inputs */
+	tps6586x->gpio.direction_output	= tps6586x_gpio_output;
+	tps6586x->gpio.set		= tps6586x_gpio_set;
+	tps6586x->gpio.get		= tps6586x_gpio_get;
+
+	ret = gpiochip_add(&tps6586x->gpio);
+	if (ret)
+		dev_warn(tps6586x->dev, "GPIO registration failed: %d\n", ret);
+}
+
+static int __remove_subdev(struct device *dev, void *unused)
+{
+	platform_device_unregister(to_platform_device(dev));
+	return 0;
+}
+
+static int tps6586x_remove_subdevs(struct tps6586x *tps6586x)
+{
+	return device_for_each_child(tps6586x->dev, NULL, __remove_subdev);
+}
+
+static int __devinit tps6586x_add_subdevs(struct tps6586x *tps6586x,
+					  struct tps6586x_platform_data *pdata)
+{
+	struct tps6586x_subdev_info *subdev;
+	struct platform_device *pdev;
+	int i, ret = 0;
+
+	for (i = 0; i < pdata->num_subdevs; i++) {
+		subdev = &pdata->subdevs[i];
+
+		pdev = platform_device_alloc(subdev->name, subdev->id);
+
+		pdev->dev.parent = tps6586x->dev;
+		pdev->dev.platform_data = subdev->platform_data;
+
+		ret = platform_device_add(pdev);
+		if (ret)
+			goto failed;
+	}
+	return 0;
+
+failed:
+	tps6586x_remove_subdevs(tps6586x);
+	return ret;
+}
+
+static int __devinit tps6586x_i2c_probe(struct i2c_client *client,
+					const struct i2c_device_id *id)
+{
+	struct tps6586x_platform_data *pdata = client->dev.platform_data;
+	struct tps6586x *tps6586x;
+	int ret;
+
+	if (!pdata) {
+		dev_err(&client->dev, "tps6586x requires platform data\n");
+		return -ENOTSUPP;
+	}
+
+	ret = i2c_smbus_read_byte_data(client, TPS6586X_VERSIONCRC);
+	if (ret < 0) {
+		dev_err(&client->dev, "Chip ID read failed: %d\n", ret);
+		return -EIO;
+	}
+
+	if (ret != TPS658621A_VERSIONCRC) {
+		dev_err(&client->dev, "Unsupported chip ID: %x\n", ret);
+		return -ENODEV;
+	}
+
+	tps6586x = kzalloc(sizeof(struct tps6586x), GFP_KERNEL);
+	if (tps6586x == NULL)
+		return -ENOMEM;
+
+	tps6586x->client = client;
+	tps6586x->dev = &client->dev;
+	i2c_set_clientdata(client, tps6586x);
+
+	mutex_init(&tps6586x->lock);
+
+	ret = tps6586x_add_subdevs(tps6586x, pdata);
+	if (ret) {
+		dev_err(&client->dev, "add devices failed: %d\n", ret);
+		goto err_add_devs;
+	}
+
+	tps6586x_gpio_init(tps6586x, pdata->gpio_base);
+
+	return 0;
+
+err_add_devs:
+	kfree(tps6586x);
+	return ret;
+}
+
+static int __devexit tps6586x_i2c_remove(struct i2c_client *client)
+{
+	return 0;
+}
+
+static const struct i2c_device_id tps6586x_id_table[] = {
+	{ "tps6586x", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, tps6586x_id_table);
+
+static struct i2c_driver tps6586x_driver = {
+	.driver	= {
+		.name	= "tps6586x",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= tps6586x_i2c_probe,
+	.remove		= __devexit_p(tps6586x_i2c_remove),
+	.id_table	= tps6586x_id_table,
+};
+
+static int __init tps6586x_init(void)
+{
+	return i2c_add_driver(&tps6586x_driver);
+}
+subsys_initcall(tps6586x_init);
+
+static void __exit tps6586x_exit(void)
+{
+	i2c_del_driver(&tps6586x_driver);
+}
+module_exit(tps6586x_exit);
+
+MODULE_DESCRIPTION("TPS6586X core driver");
+MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/mfd/twl6030-pwm.c b/drivers/mfd/twl6030-pwm.c
new file mode 100644
index 0000000..5d25bdc
--- /dev/null
+++ b/drivers/mfd/twl6030-pwm.c
@@ -0,0 +1,163 @@
+/*
+ * twl6030_pwm.c
+ * Driver for PHOENIX (TWL6030) Pulse Width Modulator
+ *
+ * Copyright (C) 2010 Texas Instruments
+ * Author: Hemanth V <hemanthv@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/i2c/twl.h>
+#include <linux/slab.h>
+
+#define LED_PWM_CTRL1	0xF4
+#define LED_PWM_CTRL2	0xF5
+
+/* Max value for CTRL1 register */
+#define PWM_CTRL1_MAX	255
+
+/* Pull down disable */
+#define PWM_CTRL2_DIS_PD	(1 << 6)
+
+/* Current control 2.5 milli Amps */
+#define PWM_CTRL2_CURR_02	(2 << 4)
+
+/* LED supply source */
+#define PWM_CTRL2_SRC_VAC	(1 << 2)
+
+/* LED modes */
+#define PWM_CTRL2_MODE_HW	(0 << 0)
+#define PWM_CTRL2_MODE_SW	(1 << 0)
+#define PWM_CTRL2_MODE_DIS	(2 << 0)
+
+#define PWM_CTRL2_MODE_MASK	0x3
+
+struct pwm_device {
+	const char *label;
+	unsigned int pwm_id;
+};
+
+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+	u8 duty_cycle;
+	int ret;
+
+	if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
+		return -EINVAL;
+
+	duty_cycle = (duty_ns * PWM_CTRL1_MAX) / period_ns;
+
+	ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, duty_cycle, LED_PWM_CTRL1);
+
+	if (ret < 0) {
+		pr_err("%s: Failed to configure PWM, Error %d\n",
+			pwm->label, ret);
+		return ret;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(pwm_config);
+
+int pwm_enable(struct pwm_device *pwm)
+{
+	u8 val;
+	int ret;
+
+	ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2);
+	if (ret < 0) {
+		pr_err("%s: Failed to enable PWM, Error %d\n", pwm->label, ret);
+		return ret;
+	}
+
+	/* Change mode to software control */
+	val &= ~PWM_CTRL2_MODE_MASK;
+	val |= PWM_CTRL2_MODE_SW;
+
+	ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2);
+	if (ret < 0) {
+		pr_err("%s: Failed to enable PWM, Error %d\n", pwm->label, ret);
+		return ret;
+	}
+
+	twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2);
+	return 0;
+}
+EXPORT_SYMBOL(pwm_enable);
+
+void pwm_disable(struct pwm_device *pwm)
+{
+	u8 val;
+	int ret;
+
+	ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2);
+	if (ret < 0) {
+		pr_err("%s: Failed to disable PWM, Error %d\n",
+			pwm->label, ret);
+		return;
+	}
+
+	val &= ~PWM_CTRL2_MODE_MASK;
+	val |= PWM_CTRL2_MODE_HW;
+
+	ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2);
+	if (ret < 0) {
+		pr_err("%s: Failed to disable PWM, Error %d\n",
+			pwm->label, ret);
+		return;
+	}
+	return;
+}
+EXPORT_SYMBOL(pwm_disable);
+
+struct pwm_device *pwm_request(int pwm_id, const char *label)
+{
+	u8 val;
+	int ret;
+	struct pwm_device *pwm;
+
+	pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
+	if (pwm == NULL) {
+		pr_err("%s: failed to allocate memory\n", label);
+		return NULL;
+	}
+
+	pwm->label = label;
+	pwm->pwm_id = pwm_id;
+
+	/* Configure PWM */
+	val = PWM_CTRL2_DIS_PD | PWM_CTRL2_CURR_02 | PWM_CTRL2_SRC_VAC |
+		PWM_CTRL2_MODE_HW;
+
+	ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2);
+
+	if (ret < 0) {
+		pr_err("%s: Failed to configure PWM, Error %d\n",
+			 pwm->label, ret);
+
+		kfree(pwm);
+		return NULL;
+	}
+
+	return pwm;
+}
+EXPORT_SYMBOL(pwm_request);
+
+void pwm_free(struct pwm_device *pwm)
+{
+	pwm_disable(pwm);
+	kfree(pwm);
+}
+EXPORT_SYMBOL(pwm_free);
diff --git a/drivers/mfd/ucb1400_core.c b/drivers/mfd/ucb1400_core.c
index dbe2801..d73f84b 100644
--- a/drivers/mfd/ucb1400_core.c
+++ b/drivers/mfd/ucb1400_core.c
@@ -114,7 +114,7 @@
 err3:
 	platform_device_put(ucb->ucb1400_ts);
 err2:
-	platform_device_unregister(ucb->ucb1400_gpio);
+	platform_device_del(ucb->ucb1400_gpio);
 err1:
 	platform_device_put(ucb->ucb1400_gpio);
 err0:
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index 1a968f3..1e7aaaf 100644
--- a/drivers/mfd/wm831x-core.c
+++ b/drivers/mfd/wm831x-core.c
@@ -95,6 +95,7 @@
 	WM8311 = 0x8311,
 	WM8312 = 0x8312,
 	WM8320 = 0x8320,
+	WM8321 = 0x8321,
 };
 
 static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg)
@@ -1533,6 +1534,12 @@
 		dev_info(wm831x->dev, "WM8320 revision %c\n", 'A' + rev);
 		break;
 
+	case WM8321:
+		parent = WM8321;
+		wm831x->num_gpio = 12;
+		dev_info(wm831x->dev, "WM8321 revision %c\n", 'A' + rev);
+		break;
+
 	default:
 		dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret);
 		ret = -EINVAL;
@@ -1607,6 +1614,12 @@
 				      NULL, 0);
 		break;
 
+	case WM8321:
+		ret = mfd_add_devices(wm831x->dev, -1,
+				      wm8320_devs, ARRAY_SIZE(wm8320_devs),
+				      NULL, 0);
+		break;
+
 	default:
 		/* If this happens the bus probe function is buggy */
 		BUG();
@@ -1744,10 +1757,8 @@
 	struct wm831x *wm831x;
 
 	wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
-	if (wm831x == NULL) {
-		kfree(i2c);
+	if (wm831x == NULL)
 		return -ENOMEM;
-	}
 
 	i2c_set_clientdata(i2c, wm831x);
 	wm831x->dev = &i2c->dev;
@@ -1779,6 +1790,7 @@
 	{ "wm8311", WM8311 },
 	{ "wm8312", WM8312 },
 	{ "wm8320", WM8320 },
+	{ "wm8321", WM8321 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id);
diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c
index b580748..e81cc31 100644
--- a/drivers/mfd/wm8350-core.c
+++ b/drivers/mfd/wm8350-core.c
@@ -536,6 +536,7 @@
 	}
 
 out:
+	kfree(wm8350->reg_cache);
 	return ret;
 }
 
@@ -700,7 +701,7 @@
 
 	ret = wm8350_irq_init(wm8350, irq, pdata);
 	if (ret < 0)
-		goto err;
+		goto err_free;
 
 	if (wm8350->irq_base) {
 		ret = request_threaded_irq(wm8350->irq_base +
@@ -738,8 +739,9 @@
 
 err_irq:
 	wm8350_irq_exit(wm8350);
-err:
+err_free:
 	kfree(wm8350->reg_cache);
+err:
 	return ret;
 }
 EXPORT_SYMBOL_GPL(wm8350_device_init);
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
index ec71c936..b3b2aaf8 100644
--- a/drivers/mfd/wm8994-core.c
+++ b/drivers/mfd/wm8994-core.c
@@ -326,8 +326,10 @@
 	wm8994->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
 				   ARRAY_SIZE(wm8994_main_supplies),
 				   GFP_KERNEL);
-	if (!wm8994->supplies)
+	if (!wm8994->supplies) {
+		ret = -ENOMEM;
 		goto err;
+	}
 
 	for (i = 0; i < ARRAY_SIZE(wm8994_main_supplies); i++)
 		wm8994->supplies[i].supply = wm8994_main_supplies[i];
@@ -495,10 +497,8 @@
 	struct wm8994 *wm8994;
 
 	wm8994 = kzalloc(sizeof(struct wm8994), GFP_KERNEL);
-	if (wm8994 == NULL) {
-		kfree(i2c);
+	if (wm8994 == NULL)
 		return -ENOMEM;
-	}
 
 	i2c_set_clientdata(i2c, wm8994);
 	wm8994->dev = &i2c->dev;
diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c
index 5bfb2a2..ef34de7 100644
--- a/drivers/misc/lkdtm.c
+++ b/drivers/misc/lkdtm.c
@@ -124,9 +124,9 @@
 module_param(recur_count, int, 0644);
 MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test, "\
 				 "default is 10");
-module_param(cpoint_name, charp, 0644);
+module_param(cpoint_name, charp, 0444);
 MODULE_PARM_DESC(cpoint_name, " Crash Point, where kernel is to be crashed");
-module_param(cpoint_type, charp, 0644);
+module_param(cpoint_type, charp, 0444);
 MODULE_PARM_DESC(cpoint_type, " Crash Point Type, action to be taken on "\
 				"hitting the crash point");
 module_param(cpoint_count, int, 0644);
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 8433cde..d545f79 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -247,7 +247,76 @@
 	return cmd.resp[0];
 }
 
-static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
+static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
+{
+	struct mmc_blk_data *md = mq->data;
+	struct mmc_card *card = md->queue.card;
+	unsigned int from, nr, arg;
+	int err = 0;
+
+	mmc_claim_host(card->host);
+
+	if (!mmc_can_erase(card)) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	from = blk_rq_pos(req);
+	nr = blk_rq_sectors(req);
+
+	if (mmc_can_trim(card))
+		arg = MMC_TRIM_ARG;
+	else
+		arg = MMC_ERASE_ARG;
+
+	err = mmc_erase(card, from, nr, arg);
+out:
+	spin_lock_irq(&md->lock);
+	__blk_end_request(req, err, blk_rq_bytes(req));
+	spin_unlock_irq(&md->lock);
+
+	mmc_release_host(card->host);
+
+	return err ? 0 : 1;
+}
+
+static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
+				       struct request *req)
+{
+	struct mmc_blk_data *md = mq->data;
+	struct mmc_card *card = md->queue.card;
+	unsigned int from, nr, arg;
+	int err = 0;
+
+	mmc_claim_host(card->host);
+
+	if (!mmc_can_secure_erase_trim(card)) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	from = blk_rq_pos(req);
+	nr = blk_rq_sectors(req);
+
+	if (mmc_can_trim(card) && !mmc_erase_group_aligned(card, from, nr))
+		arg = MMC_SECURE_TRIM1_ARG;
+	else
+		arg = MMC_SECURE_ERASE_ARG;
+
+	err = mmc_erase(card, from, nr, arg);
+	if (!err && arg == MMC_SECURE_TRIM1_ARG)
+		err = mmc_erase(card, from, nr, MMC_SECURE_TRIM2_ARG);
+out:
+	spin_lock_irq(&md->lock);
+	__blk_end_request(req, err, blk_rq_bytes(req));
+	spin_unlock_irq(&md->lock);
+
+	mmc_release_host(card->host);
+
+	return err ? 0 : 1;
+}
+
+static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 {
 	struct mmc_blk_data *md = mq->data;
 	struct mmc_card *card = md->queue.card;
@@ -475,6 +544,17 @@
 	return 0;
 }
 
+static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
+{
+	if (req->cmd_flags & REQ_DISCARD) {
+		if (req->cmd_flags & REQ_SECURE)
+			return mmc_blk_issue_secdiscard_rq(mq, req);
+		else
+			return mmc_blk_issue_discard_rq(mq, req);
+	} else {
+		return mmc_blk_issue_rw_rq(mq, req);
+	}
+}
 
 static inline int mmc_blk_readonly(struct mmc_card *card)
 {
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
index 445d7db..5dd8576 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/card/mmc_test.c
@@ -16,6 +16,7 @@
 #include <linux/slab.h>
 
 #include <linux/scatterlist.h>
+#include <linux/swap.h>		/* For nr_free_buffer_pages() */
 
 #define RESULT_OK		0
 #define RESULT_FAIL		1
@@ -25,6 +26,60 @@
 #define BUFFER_ORDER		2
 #define BUFFER_SIZE		(PAGE_SIZE << BUFFER_ORDER)
 
+/*
+ * Limit the test area size to the maximum MMC HC erase group size.  Note that
+ * the maximum SD allocation unit size is just 4MiB.
+ */
+#define TEST_AREA_MAX_SIZE (128 * 1024 * 1024)
+
+/**
+ * struct mmc_test_pages - pages allocated by 'alloc_pages()'.
+ * @page: first page in the allocation
+ * @order: order of the number of pages allocated
+ */
+struct mmc_test_pages {
+	struct page *page;
+	unsigned int order;
+};
+
+/**
+ * struct mmc_test_mem - allocated memory.
+ * @arr: array of allocations
+ * @cnt: number of allocations
+ */
+struct mmc_test_mem {
+	struct mmc_test_pages *arr;
+	unsigned int cnt;
+};
+
+/**
+ * struct mmc_test_area - information for performance tests.
+ * @max_sz: test area size (in bytes)
+ * @dev_addr: address on card at which to do performance tests
+ * @max_segs: maximum segments in scatterlist @sg
+ * @blocks: number of (512 byte) blocks currently mapped by @sg
+ * @sg_len: length of currently mapped scatterlist @sg
+ * @mem: allocated memory
+ * @sg: scatterlist
+ */
+struct mmc_test_area {
+	unsigned long max_sz;
+	unsigned int dev_addr;
+	unsigned int max_segs;
+	unsigned int blocks;
+	unsigned int sg_len;
+	struct mmc_test_mem *mem;
+	struct scatterlist *sg;
+};
+
+/**
+ * struct mmc_test_card - test information.
+ * @card: card under test
+ * @scratch: transfer buffer
+ * @buffer: transfer buffer
+ * @highmem: buffer for highmem tests
+ * @area: information for performance tests
+ */
 struct mmc_test_card {
 	struct mmc_card	*card;
 
@@ -33,6 +88,7 @@
 #ifdef CONFIG_HIGHMEM
 	struct page	*highmem;
 #endif
+	struct mmc_test_area area;
 };
 
 /*******************************************************************/
@@ -97,6 +153,12 @@
 	mmc_set_data_timeout(mrq->data, test->card);
 }
 
+static int mmc_test_busy(struct mmc_command *cmd)
+{
+	return !(cmd->resp[0] & R1_READY_FOR_DATA) ||
+		(R1_CURRENT_STATE(cmd->resp[0]) == 7);
+}
+
 /*
  * Wait for the card to finish the busy state
  */
@@ -117,13 +179,13 @@
 		if (ret)
 			break;
 
-		if (!busy && !(cmd.resp[0] & R1_READY_FOR_DATA)) {
+		if (!busy && mmc_test_busy(&cmd)) {
 			busy = 1;
 			printk(KERN_INFO "%s: Warning: Host did not "
 				"wait for busy state to end.\n",
 				mmc_hostname(test->card->host));
 		}
-	} while (!(cmd.resp[0] & R1_READY_FOR_DATA));
+	} while (mmc_test_busy(&cmd));
 
 	return ret;
 }
@@ -170,6 +232,248 @@
 	return 0;
 }
 
+static void mmc_test_free_mem(struct mmc_test_mem *mem)
+{
+	if (!mem)
+		return;
+	while (mem->cnt--)
+		__free_pages(mem->arr[mem->cnt].page,
+			     mem->arr[mem->cnt].order);
+	kfree(mem->arr);
+	kfree(mem);
+}
+
+/*
+ * Allocate a lot of memory, preferrably max_sz but at least min_sz.  In case
+ * there isn't much memory do not exceed 1/16th total lowmem pages.
+ */
+static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
+					       unsigned long max_sz)
+{
+	unsigned long max_page_cnt = DIV_ROUND_UP(max_sz, PAGE_SIZE);
+	unsigned long min_page_cnt = DIV_ROUND_UP(min_sz, PAGE_SIZE);
+	unsigned long page_cnt = 0;
+	unsigned long limit = nr_free_buffer_pages() >> 4;
+	struct mmc_test_mem *mem;
+
+	if (max_page_cnt > limit)
+		max_page_cnt = limit;
+	if (max_page_cnt < min_page_cnt)
+		max_page_cnt = min_page_cnt;
+
+	mem = kzalloc(sizeof(struct mmc_test_mem), GFP_KERNEL);
+	if (!mem)
+		return NULL;
+
+	mem->arr = kzalloc(sizeof(struct mmc_test_pages) * max_page_cnt,
+			   GFP_KERNEL);
+	if (!mem->arr)
+		goto out_free;
+
+	while (max_page_cnt) {
+		struct page *page;
+		unsigned int order;
+		gfp_t flags = GFP_KERNEL | GFP_DMA | __GFP_NOWARN |
+				__GFP_NORETRY;
+
+		order = get_order(max_page_cnt << PAGE_SHIFT);
+		while (1) {
+			page = alloc_pages(flags, order);
+			if (page || !order)
+				break;
+			order -= 1;
+		}
+		if (!page) {
+			if (page_cnt < min_page_cnt)
+				goto out_free;
+			break;
+		}
+		mem->arr[mem->cnt].page = page;
+		mem->arr[mem->cnt].order = order;
+		mem->cnt += 1;
+		if (max_page_cnt <= (1UL << order))
+			break;
+		max_page_cnt -= 1UL << order;
+		page_cnt += 1UL << order;
+	}
+
+	return mem;
+
+out_free:
+	mmc_test_free_mem(mem);
+	return NULL;
+}
+
+/*
+ * Map memory into a scatterlist.  Optionally allow the same memory to be
+ * mapped more than once.
+ */
+static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long sz,
+			   struct scatterlist *sglist, int repeat,
+			   unsigned int max_segs, unsigned int *sg_len)
+{
+	struct scatterlist *sg = NULL;
+	unsigned int i;
+
+	sg_init_table(sglist, max_segs);
+
+	*sg_len = 0;
+	do {
+		for (i = 0; i < mem->cnt; i++) {
+			unsigned long len = PAGE_SIZE << mem->arr[i].order;
+
+			if (sz < len)
+				len = sz;
+			if (sg)
+				sg = sg_next(sg);
+			else
+				sg = sglist;
+			if (!sg)
+				return -EINVAL;
+			sg_set_page(sg, mem->arr[i].page, len, 0);
+			sz -= len;
+			*sg_len += 1;
+			if (!sz)
+				break;
+		}
+	} while (sz && repeat);
+
+	if (sz)
+		return -EINVAL;
+
+	if (sg)
+		sg_mark_end(sg);
+
+	return 0;
+}
+
+/*
+ * Map memory into a scatterlist so that no pages are contiguous.  Allow the
+ * same memory to be mapped more than once.
+ */
+static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem,
+				       unsigned long sz,
+				       struct scatterlist *sglist,
+				       unsigned int max_segs,
+				       unsigned int *sg_len)
+{
+	struct scatterlist *sg = NULL;
+	unsigned int i = mem->cnt, cnt;
+	unsigned long len;
+	void *base, *addr, *last_addr = NULL;
+
+	sg_init_table(sglist, max_segs);
+
+	*sg_len = 0;
+	while (sz && i) {
+		base = page_address(mem->arr[--i].page);
+		cnt = 1 << mem->arr[i].order;
+		while (sz && cnt) {
+			addr = base + PAGE_SIZE * --cnt;
+			if (last_addr && last_addr + PAGE_SIZE == addr)
+				continue;
+			last_addr = addr;
+			len = PAGE_SIZE;
+			if (sz < len)
+				len = sz;
+			if (sg)
+				sg = sg_next(sg);
+			else
+				sg = sglist;
+			if (!sg)
+				return -EINVAL;
+			sg_set_page(sg, virt_to_page(addr), len, 0);
+			sz -= len;
+			*sg_len += 1;
+		}
+	}
+
+	if (sg)
+		sg_mark_end(sg);
+
+	return 0;
+}
+
+/*
+ * Calculate transfer rate in bytes per second.
+ */
+static unsigned int mmc_test_rate(uint64_t bytes, struct timespec *ts)
+{
+	uint64_t ns;
+
+	ns = ts->tv_sec;
+	ns *= 1000000000;
+	ns += ts->tv_nsec;
+
+	bytes *= 1000000000;
+
+	while (ns > UINT_MAX) {
+		bytes >>= 1;
+		ns >>= 1;
+	}
+
+	if (!ns)
+		return 0;
+
+	do_div(bytes, (uint32_t)ns);
+
+	return bytes;
+}
+
+/*
+ * Print the transfer rate.
+ */
+static void mmc_test_print_rate(struct mmc_test_card *test, uint64_t bytes,
+				struct timespec *ts1, struct timespec *ts2)
+{
+	unsigned int rate, sectors = bytes >> 9;
+	struct timespec ts;
+
+	ts = timespec_sub(*ts2, *ts1);
+
+	rate = mmc_test_rate(bytes, &ts);
+
+	printk(KERN_INFO "%s: Transfer of %u sectors (%u%s KiB) took %lu.%09lu "
+			 "seconds (%u kB/s, %u KiB/s)\n",
+			 mmc_hostname(test->card->host), sectors, sectors >> 1,
+			 (sectors == 1 ? ".5" : ""), (unsigned long)ts.tv_sec,
+			 (unsigned long)ts.tv_nsec, rate / 1000, rate / 1024);
+}
+
+/*
+ * Print the average transfer rate.
+ */
+static void mmc_test_print_avg_rate(struct mmc_test_card *test, uint64_t bytes,
+				    unsigned int count, struct timespec *ts1,
+				    struct timespec *ts2)
+{
+	unsigned int rate, sectors = bytes >> 9;
+	uint64_t tot = bytes * count;
+	struct timespec ts;
+
+	ts = timespec_sub(*ts2, *ts1);
+
+	rate = mmc_test_rate(tot, &ts);
+
+	printk(KERN_INFO "%s: Transfer of %u x %u sectors (%u x %u%s KiB) took "
+			 "%lu.%09lu seconds (%u kB/s, %u KiB/s)\n",
+			 mmc_hostname(test->card->host), count, sectors, count,
+			 sectors >> 1, (sectors == 1 ? ".5" : ""),
+			 (unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec,
+			 rate / 1000, rate / 1024);
+}
+
+/*
+ * Return the card size in sectors.
+ */
+static unsigned int mmc_test_capacity(struct mmc_card *card)
+{
+	if (!mmc_card_sd(card) && mmc_card_blockaddr(card))
+		return card->ext_csd.sectors;
+	else
+		return card->csd.capacity << (card->csd.read_blkbits - 9);
+}
+
 /*******************************************************************/
 /*  Test preparation and cleanup                                   */
 /*******************************************************************/
@@ -893,8 +1197,419 @@
 	return 0;
 }
 
+#else
+
+static int mmc_test_no_highmem(struct mmc_test_card *test)
+{
+	printk(KERN_INFO "%s: Highmem not configured - test skipped\n",
+	       mmc_hostname(test->card->host));
+	return 0;
+}
+
 #endif /* CONFIG_HIGHMEM */
 
+/*
+ * Map sz bytes so that it can be transferred.
+ */
+static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz,
+			     int max_scatter)
+{
+	struct mmc_test_area *t = &test->area;
+
+	t->blocks = sz >> 9;
+
+	if (max_scatter) {
+		return mmc_test_map_sg_max_scatter(t->mem, sz, t->sg,
+						   t->max_segs, &t->sg_len);
+	} else {
+		return mmc_test_map_sg(t->mem, sz, t->sg, 1, t->max_segs,
+				       &t->sg_len);
+	}
+}
+
+/*
+ * Transfer bytes mapped by mmc_test_area_map().
+ */
+static int mmc_test_area_transfer(struct mmc_test_card *test,
+				  unsigned int dev_addr, int write)
+{
+	struct mmc_test_area *t = &test->area;
+
+	return mmc_test_simple_transfer(test, t->sg, t->sg_len, dev_addr,
+					t->blocks, 512, write);
+}
+
+/*
+ * Map and transfer bytes.
+ */
+static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
+			    unsigned int dev_addr, int write, int max_scatter,
+			    int timed)
+{
+	struct timespec ts1, ts2;
+	int ret;
+
+	ret = mmc_test_area_map(test, sz, max_scatter);
+	if (ret)
+		return ret;
+
+	if (timed)
+		getnstimeofday(&ts1);
+
+	ret = mmc_test_area_transfer(test, dev_addr, write);
+	if (ret)
+		return ret;
+
+	if (timed)
+		getnstimeofday(&ts2);
+
+	if (timed)
+		mmc_test_print_rate(test, sz, &ts1, &ts2);
+
+	return 0;
+}
+
+/*
+ * Write the test area entirely.
+ */
+static int mmc_test_area_fill(struct mmc_test_card *test)
+{
+	return mmc_test_area_io(test, test->area.max_sz, test->area.dev_addr,
+				1, 0, 0);
+}
+
+/*
+ * Erase the test area entirely.
+ */
+static int mmc_test_area_erase(struct mmc_test_card *test)
+{
+	struct mmc_test_area *t = &test->area;
+
+	if (!mmc_can_erase(test->card))
+		return 0;
+
+	return mmc_erase(test->card, t->dev_addr, test->area.max_sz >> 9,
+			 MMC_ERASE_ARG);
+}
+
+/*
+ * Cleanup struct mmc_test_area.
+ */
+static int mmc_test_area_cleanup(struct mmc_test_card *test)
+{
+	struct mmc_test_area *t = &test->area;
+
+	kfree(t->sg);
+	mmc_test_free_mem(t->mem);
+
+	return 0;
+}
+
+/*
+ * Initialize an area for testing large transfers.  The size of the area is the
+ * preferred erase size which is a good size for optimal transfer speed.  Note
+ * that is typically 4MiB for modern cards.  The test area is set to the middle
+ * of the card because cards may have different charateristics at the front
+ * (for FAT file system optimization).  Optionally, the area is erased (if the
+ * card supports it) which may improve write performance.  Optionally, the area
+ * is filled with data for subsequent read tests.
+ */
+static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill)
+{
+	struct mmc_test_area *t = &test->area;
+	unsigned long min_sz = 64 * 1024;
+	int ret;
+
+	ret = mmc_test_set_blksize(test, 512);
+	if (ret)
+		return ret;
+
+	if (test->card->pref_erase > TEST_AREA_MAX_SIZE >> 9)
+		t->max_sz = TEST_AREA_MAX_SIZE;
+	else
+		t->max_sz = (unsigned long)test->card->pref_erase << 9;
+	/*
+	 * Try to allocate enough memory for the whole area.  Less is OK
+	 * because the same memory can be mapped into the scatterlist more than
+	 * once.
+	 */
+	t->mem = mmc_test_alloc_mem(min_sz, t->max_sz);
+	if (!t->mem)
+		return -ENOMEM;
+
+	t->max_segs = DIV_ROUND_UP(t->max_sz, PAGE_SIZE);
+	t->sg = kmalloc(sizeof(struct scatterlist) * t->max_segs, GFP_KERNEL);
+	if (!t->sg) {
+		ret = -ENOMEM;
+		goto out_free;
+	}
+
+	t->dev_addr = mmc_test_capacity(test->card) / 2;
+	t->dev_addr -= t->dev_addr % (t->max_sz >> 9);
+
+	if (erase) {
+		ret = mmc_test_area_erase(test);
+		if (ret)
+			goto out_free;
+	}
+
+	if (fill) {
+		ret = mmc_test_area_fill(test);
+		if (ret)
+			goto out_free;
+	}
+
+	return 0;
+
+out_free:
+	mmc_test_area_cleanup(test);
+	return ret;
+}
+
+/*
+ * Prepare for large transfers.  Do not erase the test area.
+ */
+static int mmc_test_area_prepare(struct mmc_test_card *test)
+{
+	return mmc_test_area_init(test, 0, 0);
+}
+
+/*
+ * Prepare for large transfers.  Do erase the test area.
+ */
+static int mmc_test_area_prepare_erase(struct mmc_test_card *test)
+{
+	return mmc_test_area_init(test, 1, 0);
+}
+
+/*
+ * Prepare for large transfers.  Erase and fill the test area.
+ */
+static int mmc_test_area_prepare_fill(struct mmc_test_card *test)
+{
+	return mmc_test_area_init(test, 1, 1);
+}
+
+/*
+ * Test best-case performance.  Best-case performance is expected from
+ * a single large transfer.
+ *
+ * An additional option (max_scatter) allows the measurement of the same
+ * transfer but with no contiguous pages in the scatter list.  This tests
+ * the efficiency of DMA to handle scattered pages.
+ */
+static int mmc_test_best_performance(struct mmc_test_card *test, int write,
+				     int max_scatter)
+{
+	return mmc_test_area_io(test, test->area.max_sz, test->area.dev_addr,
+				write, max_scatter, 1);
+}
+
+/*
+ * Best-case read performance.
+ */
+static int mmc_test_best_read_performance(struct mmc_test_card *test)
+{
+	return mmc_test_best_performance(test, 0, 0);
+}
+
+/*
+ * Best-case write performance.
+ */
+static int mmc_test_best_write_performance(struct mmc_test_card *test)
+{
+	return mmc_test_best_performance(test, 1, 0);
+}
+
+/*
+ * Best-case read performance into scattered pages.
+ */
+static int mmc_test_best_read_perf_max_scatter(struct mmc_test_card *test)
+{
+	return mmc_test_best_performance(test, 0, 1);
+}
+
+/*
+ * Best-case write performance from scattered pages.
+ */
+static int mmc_test_best_write_perf_max_scatter(struct mmc_test_card *test)
+{
+	return mmc_test_best_performance(test, 1, 1);
+}
+
+/*
+ * Single read performance by transfer size.
+ */
+static int mmc_test_profile_read_perf(struct mmc_test_card *test)
+{
+	unsigned long sz;
+	unsigned int dev_addr;
+	int ret;
+
+	for (sz = 512; sz < test->area.max_sz; sz <<= 1) {
+		dev_addr = test->area.dev_addr + (sz >> 9);
+		ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 1);
+		if (ret)
+			return ret;
+	}
+	dev_addr = test->area.dev_addr;
+	return mmc_test_area_io(test, sz, dev_addr, 0, 0, 1);
+}
+
+/*
+ * Single write performance by transfer size.
+ */
+static int mmc_test_profile_write_perf(struct mmc_test_card *test)
+{
+	unsigned long sz;
+	unsigned int dev_addr;
+	int ret;
+
+	ret = mmc_test_area_erase(test);
+	if (ret)
+		return ret;
+	for (sz = 512; sz < test->area.max_sz; sz <<= 1) {
+		dev_addr = test->area.dev_addr + (sz >> 9);
+		ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 1);
+		if (ret)
+			return ret;
+	}
+	ret = mmc_test_area_erase(test);
+	if (ret)
+		return ret;
+	dev_addr = test->area.dev_addr;
+	return mmc_test_area_io(test, sz, dev_addr, 1, 0, 1);
+}
+
+/*
+ * Single trim performance by transfer size.
+ */
+static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
+{
+	unsigned long sz;
+	unsigned int dev_addr;
+	struct timespec ts1, ts2;
+	int ret;
+
+	if (!mmc_can_trim(test->card))
+		return RESULT_UNSUP_CARD;
+
+	if (!mmc_can_erase(test->card))
+		return RESULT_UNSUP_HOST;
+
+	for (sz = 512; sz < test->area.max_sz; sz <<= 1) {
+		dev_addr = test->area.dev_addr + (sz >> 9);
+		getnstimeofday(&ts1);
+		ret = mmc_erase(test->card, dev_addr, sz >> 9, MMC_TRIM_ARG);
+		if (ret)
+			return ret;
+		getnstimeofday(&ts2);
+		mmc_test_print_rate(test, sz, &ts1, &ts2);
+	}
+	dev_addr = test->area.dev_addr;
+	getnstimeofday(&ts1);
+	ret = mmc_erase(test->card, dev_addr, sz >> 9, MMC_TRIM_ARG);
+	if (ret)
+		return ret;
+	getnstimeofday(&ts2);
+	mmc_test_print_rate(test, sz, &ts1, &ts2);
+	return 0;
+}
+
+/*
+ * Consecutive read performance by transfer size.
+ */
+static int mmc_test_profile_seq_read_perf(struct mmc_test_card *test)
+{
+	unsigned long sz;
+	unsigned int dev_addr, i, cnt;
+	struct timespec ts1, ts2;
+	int ret;
+
+	for (sz = 512; sz <= test->area.max_sz; sz <<= 1) {
+		cnt = test->area.max_sz / sz;
+		dev_addr = test->area.dev_addr;
+		getnstimeofday(&ts1);
+		for (i = 0; i < cnt; i++) {
+			ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 0);
+			if (ret)
+				return ret;
+			dev_addr += (sz >> 9);
+		}
+		getnstimeofday(&ts2);
+		mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
+	}
+	return 0;
+}
+
+/*
+ * Consecutive write performance by transfer size.
+ */
+static int mmc_test_profile_seq_write_perf(struct mmc_test_card *test)
+{
+	unsigned long sz;
+	unsigned int dev_addr, i, cnt;
+	struct timespec ts1, ts2;
+	int ret;
+
+	for (sz = 512; sz <= test->area.max_sz; sz <<= 1) {
+		ret = mmc_test_area_erase(test);
+		if (ret)
+			return ret;
+		cnt = test->area.max_sz / sz;
+		dev_addr = test->area.dev_addr;
+		getnstimeofday(&ts1);
+		for (i = 0; i < cnt; i++) {
+			ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 0);
+			if (ret)
+				return ret;
+			dev_addr += (sz >> 9);
+		}
+		getnstimeofday(&ts2);
+		mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
+	}
+	return 0;
+}
+
+/*
+ * Consecutive trim performance by transfer size.
+ */
+static int mmc_test_profile_seq_trim_perf(struct mmc_test_card *test)
+{
+	unsigned long sz;
+	unsigned int dev_addr, i, cnt;
+	struct timespec ts1, ts2;
+	int ret;
+
+	if (!mmc_can_trim(test->card))
+		return RESULT_UNSUP_CARD;
+
+	if (!mmc_can_erase(test->card))
+		return RESULT_UNSUP_HOST;
+
+	for (sz = 512; sz <= test->area.max_sz; sz <<= 1) {
+		ret = mmc_test_area_erase(test);
+		if (ret)
+			return ret;
+		ret = mmc_test_area_fill(test);
+		if (ret)
+			return ret;
+		cnt = test->area.max_sz / sz;
+		dev_addr = test->area.dev_addr;
+		getnstimeofday(&ts1);
+		for (i = 0; i < cnt; i++) {
+			ret = mmc_erase(test->card, dev_addr, sz >> 9,
+					MMC_TRIM_ARG);
+			if (ret)
+				return ret;
+			dev_addr += (sz >> 9);
+		}
+		getnstimeofday(&ts2);
+		mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
+	}
+	return 0;
+}
+
 static const struct mmc_test_case mmc_test_cases[] = {
 	{
 		.name = "Basic write (no data verification)",
@@ -1040,8 +1755,100 @@
 		.cleanup = mmc_test_cleanup,
 	},
 
+#else
+
+	{
+		.name = "Highmem write",
+		.run = mmc_test_no_highmem,
+	},
+
+	{
+		.name = "Highmem read",
+		.run = mmc_test_no_highmem,
+	},
+
+	{
+		.name = "Multi-block highmem write",
+		.run = mmc_test_no_highmem,
+	},
+
+	{
+		.name = "Multi-block highmem read",
+		.run = mmc_test_no_highmem,
+	},
+
 #endif /* CONFIG_HIGHMEM */
 
+	{
+		.name = "Best-case read performance",
+		.prepare = mmc_test_area_prepare_fill,
+		.run = mmc_test_best_read_performance,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Best-case write performance",
+		.prepare = mmc_test_area_prepare_erase,
+		.run = mmc_test_best_write_performance,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Best-case read performance into scattered pages",
+		.prepare = mmc_test_area_prepare_fill,
+		.run = mmc_test_best_read_perf_max_scatter,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Best-case write performance from scattered pages",
+		.prepare = mmc_test_area_prepare_erase,
+		.run = mmc_test_best_write_perf_max_scatter,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Single read performance by transfer size",
+		.prepare = mmc_test_area_prepare_fill,
+		.run = mmc_test_profile_read_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Single write performance by transfer size",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_write_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Single trim performance by transfer size",
+		.prepare = mmc_test_area_prepare_fill,
+		.run = mmc_test_profile_trim_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Consecutive read performance by transfer size",
+		.prepare = mmc_test_area_prepare_fill,
+		.run = mmc_test_profile_seq_read_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Consecutive write performance by transfer size",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_seq_write_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
+	{
+		.name = "Consecutive trim performance by transfer size",
+		.prepare = mmc_test_area_prepare,
+		.run = mmc_test_profile_seq_trim_perf,
+		.cleanup = mmc_test_area_cleanup,
+	},
+
 };
 
 static DEFINE_MUTEX(mmc_test_lock);
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index c77eb49..e876678 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -30,9 +30,9 @@
 static int mmc_prep_request(struct request_queue *q, struct request *req)
 {
 	/*
-	 * We only like normal block requests.
+	 * We only like normal block requests and discards.
 	 */
-	if (req->cmd_type != REQ_TYPE_FS) {
+	if (req->cmd_type != REQ_TYPE_FS && !(req->cmd_flags & REQ_DISCARD)) {
 		blk_dump_rq_flags(req, "MMC bad request");
 		return BLKPREP_KILL;
 	}
@@ -130,6 +130,21 @@
 	blk_queue_prep_rq(mq->queue, mmc_prep_request);
 	blk_queue_ordered(mq->queue, QUEUE_ORDERED_DRAIN);
 	queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
+	if (mmc_can_erase(card)) {
+		queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mq->queue);
+		mq->queue->limits.max_discard_sectors = UINT_MAX;
+		if (card->erased_byte == 0)
+			mq->queue->limits.discard_zeroes_data = 1;
+		if (!mmc_can_trim(card) && is_power_of_2(card->erase_size)) {
+			mq->queue->limits.discard_granularity =
+							card->erase_size << 9;
+			mq->queue->limits.discard_alignment =
+							card->erase_size << 9;
+		}
+		if (mmc_can_secure_erase_trim(card))
+			queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD,
+						mq->queue);
+	}
 
 #ifdef CONFIG_MMC_BLOCK_BOUNCE
 	if (host->max_hw_segs == 1) {
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 83240fa..5db49b1 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1050,6 +1050,352 @@
 
 EXPORT_SYMBOL(mmc_detect_change);
 
+void mmc_init_erase(struct mmc_card *card)
+{
+	unsigned int sz;
+
+	if (is_power_of_2(card->erase_size))
+		card->erase_shift = ffs(card->erase_size) - 1;
+	else
+		card->erase_shift = 0;
+
+	/*
+	 * It is possible to erase an arbitrarily large area of an SD or MMC
+	 * card.  That is not desirable because it can take a long time
+	 * (minutes) potentially delaying more important I/O, and also the
+	 * timeout calculations become increasingly hugely over-estimated.
+	 * Consequently, 'pref_erase' is defined as a guide to limit erases
+	 * to that size and alignment.
+	 *
+	 * For SD cards that define Allocation Unit size, limit erases to one
+	 * Allocation Unit at a time.  For MMC cards that define High Capacity
+	 * Erase Size, whether it is switched on or not, limit to that size.
+	 * Otherwise just have a stab at a good value.  For modern cards it
+	 * will end up being 4MiB.  Note that if the value is too small, it
+	 * can end up taking longer to erase.
+	 */
+	if (mmc_card_sd(card) && card->ssr.au) {
+		card->pref_erase = card->ssr.au;
+		card->erase_shift = ffs(card->ssr.au) - 1;
+	} else if (card->ext_csd.hc_erase_size) {
+		card->pref_erase = card->ext_csd.hc_erase_size;
+	} else {
+		sz = (card->csd.capacity << (card->csd.read_blkbits - 9)) >> 11;
+		if (sz < 128)
+			card->pref_erase = 512 * 1024 / 512;
+		else if (sz < 512)
+			card->pref_erase = 1024 * 1024 / 512;
+		else if (sz < 1024)
+			card->pref_erase = 2 * 1024 * 1024 / 512;
+		else
+			card->pref_erase = 4 * 1024 * 1024 / 512;
+		if (card->pref_erase < card->erase_size)
+			card->pref_erase = card->erase_size;
+		else {
+			sz = card->pref_erase % card->erase_size;
+			if (sz)
+				card->pref_erase += card->erase_size - sz;
+		}
+	}
+}
+
+static void mmc_set_mmc_erase_timeout(struct mmc_card *card,
+				      struct mmc_command *cmd,
+				      unsigned int arg, unsigned int qty)
+{
+	unsigned int erase_timeout;
+
+	if (card->ext_csd.erase_group_def & 1) {
+		/* High Capacity Erase Group Size uses HC timeouts */
+		if (arg == MMC_TRIM_ARG)
+			erase_timeout = card->ext_csd.trim_timeout;
+		else
+			erase_timeout = card->ext_csd.hc_erase_timeout;
+	} else {
+		/* CSD Erase Group Size uses write timeout */
+		unsigned int mult = (10 << card->csd.r2w_factor);
+		unsigned int timeout_clks = card->csd.tacc_clks * mult;
+		unsigned int timeout_us;
+
+		/* Avoid overflow: e.g. tacc_ns=80000000 mult=1280 */
+		if (card->csd.tacc_ns < 1000000)
+			timeout_us = (card->csd.tacc_ns * mult) / 1000;
+		else
+			timeout_us = (card->csd.tacc_ns / 1000) * mult;
+
+		/*
+		 * ios.clock is only a target.  The real clock rate might be
+		 * less but not that much less, so fudge it by multiplying by 2.
+		 */
+		timeout_clks <<= 1;
+		timeout_us += (timeout_clks * 1000) /
+			      (card->host->ios.clock / 1000);
+
+		erase_timeout = timeout_us / 1000;
+
+		/*
+		 * Theoretically, the calculation could underflow so round up
+		 * to 1ms in that case.
+		 */
+		if (!erase_timeout)
+			erase_timeout = 1;
+	}
+
+	/* Multiplier for secure operations */
+	if (arg & MMC_SECURE_ARGS) {
+		if (arg == MMC_SECURE_ERASE_ARG)
+			erase_timeout *= card->ext_csd.sec_erase_mult;
+		else
+			erase_timeout *= card->ext_csd.sec_trim_mult;
+	}
+
+	erase_timeout *= qty;
+
+	/*
+	 * Ensure at least a 1 second timeout for SPI as per
+	 * 'mmc_set_data_timeout()'
+	 */
+	if (mmc_host_is_spi(card->host) && erase_timeout < 1000)
+		erase_timeout = 1000;
+
+	cmd->erase_timeout = erase_timeout;
+}
+
+static void mmc_set_sd_erase_timeout(struct mmc_card *card,
+				     struct mmc_command *cmd, unsigned int arg,
+				     unsigned int qty)
+{
+	if (card->ssr.erase_timeout) {
+		/* Erase timeout specified in SD Status Register (SSR) */
+		cmd->erase_timeout = card->ssr.erase_timeout * qty +
+				     card->ssr.erase_offset;
+	} else {
+		/*
+		 * Erase timeout not specified in SD Status Register (SSR) so
+		 * use 250ms per write block.
+		 */
+		cmd->erase_timeout = 250 * qty;
+	}
+
+	/* Must not be less than 1 second */
+	if (cmd->erase_timeout < 1000)
+		cmd->erase_timeout = 1000;
+}
+
+static void mmc_set_erase_timeout(struct mmc_card *card,
+				  struct mmc_command *cmd, unsigned int arg,
+				  unsigned int qty)
+{
+	if (mmc_card_sd(card))
+		mmc_set_sd_erase_timeout(card, cmd, arg, qty);
+	else
+		mmc_set_mmc_erase_timeout(card, cmd, arg, qty);
+}
+
+static int mmc_do_erase(struct mmc_card *card, unsigned int from,
+			unsigned int to, unsigned int arg)
+{
+	struct mmc_command cmd;
+	unsigned int qty = 0;
+	int err;
+
+	/*
+	 * qty is used to calculate the erase timeout which depends on how many
+	 * erase groups (or allocation units in SD terminology) are affected.
+	 * We count erasing part of an erase group as one erase group.
+	 * For SD, the allocation units are always a power of 2.  For MMC, the
+	 * erase group size is almost certainly also power of 2, but it does not
+	 * seem to insist on that in the JEDEC standard, so we fall back to
+	 * division in that case.  SD may not specify an allocation unit size,
+	 * in which case the timeout is based on the number of write blocks.
+	 *
+	 * Note that the timeout for secure trim 2 will only be correct if the
+	 * number of erase groups specified is the same as the total of all
+	 * preceding secure trim 1 commands.  Since the power may have been
+	 * lost since the secure trim 1 commands occurred, it is generally
+	 * impossible to calculate the secure trim 2 timeout correctly.
+	 */
+	if (card->erase_shift)
+		qty += ((to >> card->erase_shift) -
+			(from >> card->erase_shift)) + 1;
+	else if (mmc_card_sd(card))
+		qty += to - from + 1;
+	else
+		qty += ((to / card->erase_size) -
+			(from / card->erase_size)) + 1;
+
+	if (!mmc_card_blockaddr(card)) {
+		from <<= 9;
+		to <<= 9;
+	}
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+	if (mmc_card_sd(card))
+		cmd.opcode = SD_ERASE_WR_BLK_START;
+	else
+		cmd.opcode = MMC_ERASE_GROUP_START;
+	cmd.arg = from;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+	err = mmc_wait_for_cmd(card->host, &cmd, 0);
+	if (err) {
+		printk(KERN_ERR "mmc_erase: group start error %d, "
+		       "status %#x\n", err, cmd.resp[0]);
+		err = -EINVAL;
+		goto out;
+	}
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+	if (mmc_card_sd(card))
+		cmd.opcode = SD_ERASE_WR_BLK_END;
+	else
+		cmd.opcode = MMC_ERASE_GROUP_END;
+	cmd.arg = to;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+	err = mmc_wait_for_cmd(card->host, &cmd, 0);
+	if (err) {
+		printk(KERN_ERR "mmc_erase: group end error %d, status %#x\n",
+		       err, cmd.resp[0]);
+		err = -EINVAL;
+		goto out;
+	}
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+	cmd.opcode = MMC_ERASE;
+	cmd.arg = arg;
+	cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+	mmc_set_erase_timeout(card, &cmd, arg, qty);
+	err = mmc_wait_for_cmd(card->host, &cmd, 0);
+	if (err) {
+		printk(KERN_ERR "mmc_erase: erase error %d, status %#x\n",
+		       err, cmd.resp[0]);
+		err = -EIO;
+		goto out;
+	}
+
+	if (mmc_host_is_spi(card->host))
+		goto out;
+
+	do {
+		memset(&cmd, 0, sizeof(struct mmc_command));
+		cmd.opcode = MMC_SEND_STATUS;
+		cmd.arg = card->rca << 16;
+		cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+		/* Do not retry else we can't see errors */
+		err = mmc_wait_for_cmd(card->host, &cmd, 0);
+		if (err || (cmd.resp[0] & 0xFDF92000)) {
+			printk(KERN_ERR "error %d requesting status %#x\n",
+				err, cmd.resp[0]);
+			err = -EIO;
+			goto out;
+		}
+	} while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
+		 R1_CURRENT_STATE(cmd.resp[0]) == 7);
+out:
+	return err;
+}
+
+/**
+ * mmc_erase - erase sectors.
+ * @card: card to erase
+ * @from: first sector to erase
+ * @nr: number of sectors to erase
+ * @arg: erase command argument (SD supports only %MMC_ERASE_ARG)
+ *
+ * Caller must claim host before calling this function.
+ */
+int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
+	      unsigned int arg)
+{
+	unsigned int rem, to = from + nr;
+
+	if (!(card->host->caps & MMC_CAP_ERASE) ||
+	    !(card->csd.cmdclass & CCC_ERASE))
+		return -EOPNOTSUPP;
+
+	if (!card->erase_size)
+		return -EOPNOTSUPP;
+
+	if (mmc_card_sd(card) && arg != MMC_ERASE_ARG)
+		return -EOPNOTSUPP;
+
+	if ((arg & MMC_SECURE_ARGS) &&
+	    !(card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN))
+		return -EOPNOTSUPP;
+
+	if ((arg & MMC_TRIM_ARGS) &&
+	    !(card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN))
+		return -EOPNOTSUPP;
+
+	if (arg == MMC_SECURE_ERASE_ARG) {
+		if (from % card->erase_size || nr % card->erase_size)
+			return -EINVAL;
+	}
+
+	if (arg == MMC_ERASE_ARG) {
+		rem = from % card->erase_size;
+		if (rem) {
+			rem = card->erase_size - rem;
+			from += rem;
+			if (nr > rem)
+				nr -= rem;
+			else
+				return 0;
+		}
+		rem = nr % card->erase_size;
+		if (rem)
+			nr -= rem;
+	}
+
+	if (nr == 0)
+		return 0;
+
+	to = from + nr;
+
+	if (to <= from)
+		return -EINVAL;
+
+	/* 'from' and 'to' are inclusive */
+	to -= 1;
+
+	return mmc_do_erase(card, from, to, arg);
+}
+EXPORT_SYMBOL(mmc_erase);
+
+int mmc_can_erase(struct mmc_card *card)
+{
+	if ((card->host->caps & MMC_CAP_ERASE) &&
+	    (card->csd.cmdclass & CCC_ERASE) && card->erase_size)
+		return 1;
+	return 0;
+}
+EXPORT_SYMBOL(mmc_can_erase);
+
+int mmc_can_trim(struct mmc_card *card)
+{
+	if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN)
+		return 1;
+	return 0;
+}
+EXPORT_SYMBOL(mmc_can_trim);
+
+int mmc_can_secure_erase_trim(struct mmc_card *card)
+{
+	if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN)
+		return 1;
+	return 0;
+}
+EXPORT_SYMBOL(mmc_can_secure_erase_trim);
+
+int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
+			    unsigned int nr)
+{
+	if (!card->erase_size)
+		return 0;
+	if (from % card->erase_size || nr % card->erase_size)
+		return 0;
+	return 1;
+}
+EXPORT_SYMBOL(mmc_erase_group_aligned);
 
 void mmc_rescan(struct work_struct *work)
 {
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index a811c52..9d9eef5 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -29,6 +29,8 @@
 void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
 void mmc_detach_bus(struct mmc_host *host);
 
+void mmc_init_erase(struct mmc_card *card);
+
 void mmc_set_chip_select(struct mmc_host *host, int mode);
 void mmc_set_clock(struct mmc_host *host, unsigned int hz);
 void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index ccba386..6909a54 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -108,13 +108,23 @@
 	return 0;
 }
 
+static void mmc_set_erase_size(struct mmc_card *card)
+{
+	if (card->ext_csd.erase_group_def & 1)
+		card->erase_size = card->ext_csd.hc_erase_size;
+	else
+		card->erase_size = card->csd.erase_size;
+
+	mmc_init_erase(card);
+}
+
 /*
  * Given a 128-bit response, decode to our card CSD structure.
  */
 static int mmc_decode_csd(struct mmc_card *card)
 {
 	struct mmc_csd *csd = &card->csd;
-	unsigned int e, m;
+	unsigned int e, m, a, b;
 	u32 *resp = card->raw_csd;
 
 	/*
@@ -152,6 +162,13 @@
 	csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
 	csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
 
+	if (csd->write_blkbits >= 9) {
+		a = UNSTUFF_BITS(resp, 42, 5);
+		b = UNSTUFF_BITS(resp, 37, 5);
+		csd->erase_size = (a + 1) * (b + 1);
+		csd->erase_size <<= csd->write_blkbits - 9;
+	}
+
 	return 0;
 }
 
@@ -261,8 +278,30 @@
 		if (sa_shift > 0 && sa_shift <= 0x17)
 			card->ext_csd.sa_timeout =
 					1 << ext_csd[EXT_CSD_S_A_TIMEOUT];
+		card->ext_csd.erase_group_def =
+			ext_csd[EXT_CSD_ERASE_GROUP_DEF];
+		card->ext_csd.hc_erase_timeout = 300 *
+			ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
+		card->ext_csd.hc_erase_size =
+			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] << 10;
 	}
 
+	if (card->ext_csd.rev >= 4) {
+		card->ext_csd.sec_trim_mult =
+			ext_csd[EXT_CSD_SEC_TRIM_MULT];
+		card->ext_csd.sec_erase_mult =
+			ext_csd[EXT_CSD_SEC_ERASE_MULT];
+		card->ext_csd.sec_feature_support =
+			ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT];
+		card->ext_csd.trim_timeout = 300 *
+			ext_csd[EXT_CSD_TRIM_MULT];
+	}
+
+	if (ext_csd[EXT_CSD_ERASED_MEM_CONT])
+		card->erased_byte = 0xFF;
+	else
+		card->erased_byte = 0x0;
+
 out:
 	kfree(ext_csd);
 
@@ -274,6 +313,8 @@
 MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
 	card->raw_csd[2], card->raw_csd[3]);
 MMC_DEV_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
+MMC_DEV_ATTR(erase_size, "%u\n", card->erase_size << 9);
+MMC_DEV_ATTR(preferred_erase_size, "%u\n", card->pref_erase << 9);
 MMC_DEV_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
 MMC_DEV_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
 MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
@@ -285,6 +326,8 @@
 	&dev_attr_cid.attr,
 	&dev_attr_csd.attr,
 	&dev_attr_date.attr,
+	&dev_attr_erase_size.attr,
+	&dev_attr_preferred_erase_size.attr,
 	&dev_attr_fwrev.attr,
 	&dev_attr_hwrev.attr,
 	&dev_attr_manfid.attr,
@@ -421,6 +464,8 @@
 		err = mmc_read_ext_csd(card);
 		if (err)
 			goto free_card;
+		/* Erase size depends on CSD and Extended CSD */
+		mmc_set_erase_size(card);
 	}
 
 	/*
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index e6d7d9f..0f52410 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -119,6 +119,13 @@
 		csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
 		csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
 		csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
+
+		if (UNSTUFF_BITS(resp, 46, 1)) {
+			csd->erase_size = 1;
+		} else if (csd->write_blkbits >= 9) {
+			csd->erase_size = UNSTUFF_BITS(resp, 39, 7) + 1;
+			csd->erase_size <<= csd->write_blkbits - 9;
+		}
 		break;
 	case 1:
 		/*
@@ -147,6 +154,7 @@
 		csd->r2w_factor = 4; /* Unused */
 		csd->write_blkbits = 9;
 		csd->write_partial = 0;
+		csd->erase_size = 1;
 		break;
 	default:
 		printk(KERN_ERR "%s: unrecognised CSD structure version %d\n",
@@ -154,6 +162,8 @@
 		return -EINVAL;
 	}
 
+	card->erase_size = csd->erase_size;
+
 	return 0;
 }
 
@@ -179,10 +189,68 @@
 	scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
 	scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
 
+	if (UNSTUFF_BITS(resp, 55, 1))
+		card->erased_byte = 0xFF;
+	else
+		card->erased_byte = 0x0;
+
 	return 0;
 }
 
 /*
+ * Fetch and process SD Status register.
+ */
+static int mmc_read_ssr(struct mmc_card *card)
+{
+	unsigned int au, es, et, eo;
+	int err, i;
+	u32 *ssr;
+
+	if (!(card->csd.cmdclass & CCC_APP_SPEC)) {
+		printk(KERN_WARNING "%s: card lacks mandatory SD Status "
+			"function.\n", mmc_hostname(card->host));
+		return 0;
+	}
+
+	ssr = kmalloc(64, GFP_KERNEL);
+	if (!ssr)
+		return -ENOMEM;
+
+	err = mmc_app_sd_status(card, ssr);
+	if (err) {
+		printk(KERN_WARNING "%s: problem reading SD Status "
+			"register.\n", mmc_hostname(card->host));
+		err = 0;
+		goto out;
+	}
+
+	for (i = 0; i < 16; i++)
+		ssr[i] = be32_to_cpu(ssr[i]);
+
+	/*
+	 * UNSTUFF_BITS only works with four u32s so we have to offset the
+	 * bitfield positions accordingly.
+	 */
+	au = UNSTUFF_BITS(ssr, 428 - 384, 4);
+	if (au > 0 || au <= 9) {
+		card->ssr.au = 1 << (au + 4);
+		es = UNSTUFF_BITS(ssr, 408 - 384, 16);
+		et = UNSTUFF_BITS(ssr, 402 - 384, 6);
+		eo = UNSTUFF_BITS(ssr, 400 - 384, 2);
+		if (es && et) {
+			card->ssr.erase_timeout = (et * 1000) / es;
+			card->ssr.erase_offset = eo * 1000;
+		}
+	} else {
+		printk(KERN_WARNING "%s: SD Status: Invalid Allocation Unit "
+			"size.\n", mmc_hostname(card->host));
+	}
+out:
+	kfree(ssr);
+	return err;
+}
+
+/*
  * Fetches and decodes switch information
  */
 static int mmc_read_switch(struct mmc_card *card)
@@ -289,6 +357,8 @@
 	card->raw_csd[2], card->raw_csd[3]);
 MMC_DEV_ATTR(scr, "%08x%08x\n", card->raw_scr[0], card->raw_scr[1]);
 MMC_DEV_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
+MMC_DEV_ATTR(erase_size, "%u\n", card->erase_size << 9);
+MMC_DEV_ATTR(preferred_erase_size, "%u\n", card->pref_erase << 9);
 MMC_DEV_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
 MMC_DEV_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
 MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
@@ -302,6 +372,8 @@
 	&dev_attr_csd.attr,
 	&dev_attr_scr.attr,
 	&dev_attr_date.attr,
+	&dev_attr_erase_size.attr,
+	&dev_attr_preferred_erase_size.attr,
 	&dev_attr_fwrev.attr,
 	&dev_attr_hwrev.attr,
 	&dev_attr_manfid.attr,
@@ -397,6 +469,16 @@
 			return err;
 
 		/*
+		 * Fetch and process SD Status register.
+		 */
+		err = mmc_read_ssr(card);
+		if (err)
+			return err;
+
+		/* Erase init depends on CSD and SSR */
+		mmc_init_erase(card);
+
+		/*
 		 * Fetch switch information from card.
 		 */
 		err = mmc_read_switch(card);
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index 63772e7..797cdb5 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -346,3 +346,51 @@
 	return 0;
 }
 
+int mmc_app_sd_status(struct mmc_card *card, void *ssr)
+{
+	int err;
+	struct mmc_request mrq;
+	struct mmc_command cmd;
+	struct mmc_data data;
+	struct scatterlist sg;
+
+	BUG_ON(!card);
+	BUG_ON(!card->host);
+	BUG_ON(!ssr);
+
+	/* NOTE: caller guarantees ssr is heap-allocated */
+
+	err = mmc_app_cmd(card->host, card);
+	if (err)
+		return err;
+
+	memset(&mrq, 0, sizeof(struct mmc_request));
+	memset(&cmd, 0, sizeof(struct mmc_command));
+	memset(&data, 0, sizeof(struct mmc_data));
+
+	mrq.cmd = &cmd;
+	mrq.data = &data;
+
+	cmd.opcode = SD_APP_SD_STATUS;
+	cmd.arg = 0;
+	cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_ADTC;
+
+	data.blksz = 64;
+	data.blocks = 1;
+	data.flags = MMC_DATA_READ;
+	data.sg = &sg;
+	data.sg_len = 1;
+
+	sg_init_one(&sg, ssr, 64);
+
+	mmc_set_data_timeout(&data, card);
+
+	mmc_wait_for_req(card->host, &mrq);
+
+	if (cmd.error)
+		return cmd.error;
+	if (data.error)
+		return data.error;
+
+	return 0;
+}
diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h
index 9742d8a..ffc2305 100644
--- a/drivers/mmc/core/sd_ops.h
+++ b/drivers/mmc/core/sd_ops.h
@@ -19,6 +19,7 @@
 int mmc_app_send_scr(struct mmc_card *card, u32 *scr);
 int mmc_sd_switch(struct mmc_card *card, int mode, int group,
 	u8 value, u8 *resp);
+int mmc_app_sd_status(struct mmc_card *card, void *ssr);
 
 #endif
 
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
index 7b0f3ef..1145ea0 100644
--- a/drivers/mmc/host/mmc_spi.c
+++ b/drivers/mmc/host/mmc_spi.c
@@ -1536,6 +1536,7 @@
 #if defined(CONFIG_OF)
 static struct of_device_id mmc_spi_of_match_table[] __devinitdata = {
 	{ .compatible = "mmc-spi-slot", },
+	{},
 };
 #endif
 
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 3bd8ff7..6824917 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -1060,7 +1060,7 @@
 static int
 msmsdcc_probe(struct platform_device *pdev)
 {
-	struct mmc_platform_data *plat = pdev->dev.platform_data;
+	struct msm_mmc_platform_data *plat = pdev->dev.platform_data;
 	struct msmsdcc_host *host;
 	struct mmc_host *mmc;
 	struct resource *cmd_irqres = NULL;
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index d7dedcf..ff2b0f7 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -225,7 +225,7 @@
 
 	u32			pwr;
 	u32			saved_irq0mask;	/* MMCIMASK0 reg value */
-	struct mmc_platform_data *plat;
+	struct msm_mmc_platform_data *plat;
 
 	struct timer_list	timer;
 	unsigned int		oldstat;
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index dc57ef6..4a8776f 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -28,6 +28,7 @@
 #include <linux/clk.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/core.h>
+#include <linux/mmc/mmc.h>
 #include <linux/io.h>
 #include <linux/semaphore.h>
 #include <linux/gpio.h>
@@ -78,6 +79,7 @@
 #define INT_EN_MASK		0x307F0033
 #define BWR_ENABLE		(1 << 4)
 #define BRR_ENABLE		(1 << 5)
+#define DTO_ENABLE		(1 << 20)
 #define INIT_STREAM		(1 << 1)
 #define DP_SELECT		(1 << 21)
 #define DDIR			(1 << 4)
@@ -523,7 +525,8 @@
 		dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stoped\n");
 }
 
-static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host)
+static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host,
+				  struct mmc_command *cmd)
 {
 	unsigned int irq_mask;
 
@@ -532,6 +535,10 @@
 	else
 		irq_mask = INT_EN_MASK;
 
+	/* Disable timeout for erases */
+	if (cmd->opcode == MMC_ERASE)
+		irq_mask &= ~DTO_ENABLE;
+
 	OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
 	OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
 	OMAP_HSMMC_WRITE(host->base, IE, irq_mask);
@@ -782,7 +789,7 @@
 		mmc_hostname(host->mmc), cmd->opcode, cmd->arg);
 	host->cmd = cmd;
 
-	omap_hsmmc_enable_irq(host);
+	omap_hsmmc_enable_irq(host, cmd);
 
 	host->response_busy = 0;
 	if (cmd->flags & MMC_RSP_PRESENT) {
@@ -2107,7 +2114,7 @@
 	mmc->max_seg_size = mmc->max_req_size;
 
 	mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
-		     MMC_CAP_WAIT_WHILE_BUSY;
+		     MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
 
 	switch (mmc_slot(host).wires) {
 	case 8:
diff --git a/drivers/mmc/host/sdhci-of-core.c b/drivers/mmc/host/sdhci-of-core.c
index dd1bdd1..c51b711 100644
--- a/drivers/mmc/host/sdhci-of-core.c
+++ b/drivers/mmc/host/sdhci-of-core.c
@@ -85,14 +85,14 @@
 
 #ifdef CONFIG_PM
 
-static int sdhci_of_suspend(struct of_device *ofdev, pm_message_t state)
+static int sdhci_of_suspend(struct platform_device *ofdev, pm_message_t state)
 {
 	struct sdhci_host *host = dev_get_drvdata(&ofdev->dev);
 
 	return mmc_suspend_host(host->mmc);
 }
 
-static int sdhci_of_resume(struct of_device *ofdev)
+static int sdhci_of_resume(struct platform_device *ofdev)
 {
 	struct sdhci_host *host = dev_get_drvdata(&ofdev->dev);
 
@@ -115,7 +115,7 @@
 	return machine_is(mpc837x_rdb) || machine_is(mpc837x_mds);
 }
 
-static int __devinit sdhci_of_probe(struct of_device *ofdev,
+static int __devinit sdhci_of_probe(struct platform_device *ofdev,
 				 const struct of_device_id *match)
 {
 	struct device_node *np = ofdev->dev.of_node;
@@ -183,7 +183,7 @@
 	return ret;
 }
 
-static int __devexit sdhci_of_remove(struct of_device *ofdev)
+static int __devexit sdhci_of_remove(struct platform_device *ofdev)
 {
 	struct sdhci_host *host = dev_get_drvdata(&ofdev->dev);
 
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
index 6ac5f9f..00af55d 100644
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -43,7 +43,7 @@
 #ifdef CONFIG_MTD_PARTITIONS
 #define OF_FLASH_PARTS(info)	((info)->parts)
 
-static int parse_obsolete_partitions(struct of_device *dev,
+static int parse_obsolete_partitions(struct platform_device *dev,
 				     struct of_flash *info,
 				     struct device_node *dp)
 {
@@ -93,7 +93,7 @@
 #define parse_partitions(info, dev)	(0)
 #endif /* MTD_PARTITIONS */
 
-static int of_flash_remove(struct of_device *dev)
+static int of_flash_remove(struct platform_device *dev)
 {
 	struct of_flash *info;
 	int i;
@@ -140,7 +140,7 @@
 /* Helper function to handle probing of the obsolete "direct-mapped"
  * compatible binding, which has an extra "probe-type" property
  * describing the type of flash probe necessary. */
-static struct mtd_info * __devinit obsolete_probe(struct of_device *dev,
+static struct mtd_info * __devinit obsolete_probe(struct platform_device *dev,
 						  struct map_info *map)
 {
 	struct device_node *dp = dev->dev.of_node;
@@ -215,7 +215,7 @@
 }
 #endif
 
-static int __devinit of_flash_probe(struct of_device *dev,
+static int __devinit of_flash_probe(struct platform_device *dev,
 				    const struct of_device_id *match)
 {
 #ifdef CONFIG_MTD_PARTITIONS
diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c
index 8984236..3582ba1 100644
--- a/drivers/mtd/maps/sun_uflash.c
+++ b/drivers/mtd/maps/sun_uflash.c
@@ -48,7 +48,7 @@
 	.bankwidth =	UFLASH_BUSWIDTH,
 };
 
-int uflash_devinit(struct of_device *op, struct device_node *dp)
+int uflash_devinit(struct platform_device *op, struct device_node *dp)
 {
 	struct uflash_dev *up;
 
@@ -108,7 +108,7 @@
 	return 0;
 }
 
-static int __devinit uflash_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit uflash_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	struct device_node *dp = op->dev.of_node;
 
@@ -121,7 +121,7 @@
 	return uflash_devinit(op, dp);
 }
 
-static int __devexit uflash_remove(struct of_device *op)
+static int __devexit uflash_remove(struct platform_device *op)
 {
 	struct uflash_dev *up = dev_get_drvdata(&op->dev);
 
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 5084cc5..80de0bf 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -958,7 +958,7 @@
 	return 0;
 }
 
-static int fsl_elbc_ctrl_remove(struct of_device *ofdev)
+static int fsl_elbc_ctrl_remove(struct platform_device *ofdev)
 {
 	struct fsl_elbc_ctrl *ctrl = dev_get_drvdata(&ofdev->dev);
 	int i;
@@ -1013,7 +1013,7 @@
  * in the chip probe function.
 */
 
-static int __devinit fsl_elbc_ctrl_probe(struct of_device *ofdev,
+static int __devinit fsl_elbc_ctrl_probe(struct platform_device *ofdev,
                                          const struct of_device_id *match)
 {
 	struct device_node *child;
diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c
index 1312eda..4eff8b2 100644
--- a/drivers/mtd/nand/fsl_upm.c
+++ b/drivers/mtd/nand/fsl_upm.c
@@ -217,7 +217,7 @@
 	return ret;
 }
 
-static int __devinit fun_probe(struct of_device *ofdev,
+static int __devinit fun_probe(struct platform_device *ofdev,
 			       const struct of_device_id *ofid)
 {
 	struct fsl_upm_nand *fun;
@@ -335,7 +335,7 @@
 	return ret;
 }
 
-static int __devexit fun_remove(struct of_device *ofdev)
+static int __devexit fun_remove(struct platform_device *ofdev)
 {
 	struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev);
 	int i;
diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c
index 0a130dc..df0c1da 100644
--- a/drivers/mtd/nand/mpc5121_nfc.c
+++ b/drivers/mtd/nand/mpc5121_nfc.c
@@ -647,7 +647,7 @@
 		iounmap(prv->csreg);
 }
 
-static int __devinit mpc5121_nfc_probe(struct of_device *op,
+static int __devinit mpc5121_nfc_probe(struct platform_device *op,
 					const struct of_device_id *match)
 {
 	struct device_node *rootnode, *dn = op->dev.of_node;
@@ -869,7 +869,7 @@
 	return retval;
 }
 
-static int __devexit mpc5121_nfc_remove(struct of_device *op)
+static int __devexit mpc5121_nfc_remove(struct platform_device *op)
 {
 	struct device *dev = &op->dev;
 	struct mtd_info *mtd = dev_get_drvdata(dev);
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
index 98fd2bd..510554e 100644
--- a/drivers/mtd/nand/ndfc.c
+++ b/drivers/mtd/nand/ndfc.c
@@ -35,7 +35,7 @@
 
 
 struct ndfc_controller {
-	struct of_device *ofdev;
+	struct platform_device *ofdev;
 	void __iomem *ndfcbase;
 	struct mtd_info mtd;
 	struct nand_chip chip;
@@ -225,7 +225,7 @@
 	return ret;
 }
 
-static int __devinit ndfc_probe(struct of_device *ofdev,
+static int __devinit ndfc_probe(struct platform_device *ofdev,
 				const struct of_device_id *match)
 {
 	struct ndfc_controller *ndfc = &ndfc_ctrl;
@@ -277,7 +277,7 @@
 	return 0;
 }
 
-static int __devexit ndfc_remove(struct of_device *ofdev)
+static int __devexit ndfc_remove(struct platform_device *ofdev)
 {
 	struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev);
 
diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c
index f02af24..6ddb246 100644
--- a/drivers/mtd/nand/pasemi_nand.c
+++ b/drivers/mtd/nand/pasemi_nand.c
@@ -89,7 +89,7 @@
 	return !!(inl(lpcctl) & LBICTRL_LPCCTL_NR);
 }
 
-static int __devinit pasemi_nand_probe(struct of_device *ofdev,
+static int __devinit pasemi_nand_probe(struct platform_device *ofdev,
 				      const struct of_device_id *match)
 {
 	struct pci_dev *pdev;
@@ -185,7 +185,7 @@
 	return err;
 }
 
-static int __devexit pasemi_nand_remove(struct of_device *ofdev)
+static int __devexit pasemi_nand_remove(struct platform_device *ofdev)
 {
 	struct nand_chip *chip;
 
diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c
index cc728b1..a8e403e 100644
--- a/drivers/mtd/nand/socrates_nand.c
+++ b/drivers/mtd/nand/socrates_nand.c
@@ -162,7 +162,7 @@
 /*
  * Probe for the NAND device.
  */
-static int __devinit socrates_nand_probe(struct of_device *ofdev,
+static int __devinit socrates_nand_probe(struct platform_device *ofdev,
 					 const struct of_device_id *ofid)
 {
 	struct socrates_nand_host *host;
@@ -276,7 +276,7 @@
 /*
  * Remove a NAND device.
  */
-static int __devexit socrates_nand_remove(struct of_device *ofdev)
+static int __devexit socrates_nand_remove(struct platform_device *ofdev)
 {
 	struct socrates_nand_host *host = dev_get_drvdata(&ofdev->dev);
 	struct mtd_info *mtd = &host->mtd;
diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c
index af75393..b1bdc90 100644
--- a/drivers/net/can/mscan/mpc5xxx_can.c
+++ b/drivers/net/can/mscan/mpc5xxx_can.c
@@ -38,7 +38,7 @@
 
 struct mpc5xxx_can_data {
 	unsigned int type;
-	u32 (*get_clock)(struct of_device *ofdev, const char *clock_name,
+	u32 (*get_clock)(struct platform_device *ofdev, const char *clock_name,
 			 int *mscan_clksrc);
 };
 
@@ -48,7 +48,7 @@
 	{}
 };
 
-static u32 __devinit mpc52xx_can_get_clock(struct of_device *ofdev,
+static u32 __devinit mpc52xx_can_get_clock(struct platform_device *ofdev,
 					   const char *clock_name,
 					   int *mscan_clksrc)
 {
@@ -101,7 +101,7 @@
 	return freq;
 }
 #else /* !CONFIG_PPC_MPC52xx */
-static u32 __devinit mpc52xx_can_get_clock(struct of_device *ofdev,
+static u32 __devinit mpc52xx_can_get_clock(struct platform_device *ofdev,
 					   const char *clock_name,
 					   int *mscan_clksrc)
 {
@@ -129,7 +129,7 @@
 	{}
 };
 
-static u32 __devinit mpc512x_can_get_clock(struct of_device *ofdev,
+static u32 __devinit mpc512x_can_get_clock(struct platform_device *ofdev,
 					   const char *clock_name,
 					   int *mscan_clksrc)
 {
@@ -239,7 +239,7 @@
 	return freq;
 }
 #else /* !CONFIG_PPC_MPC512x */
-static u32 __devinit mpc512x_can_get_clock(struct of_device *ofdev,
+static u32 __devinit mpc512x_can_get_clock(struct platform_device *ofdev,
 					   const char *clock_name,
 					   int *mscan_clksrc)
 {
@@ -247,7 +247,7 @@
 }
 #endif /* CONFIG_PPC_MPC512x */
 
-static int __devinit mpc5xxx_can_probe(struct of_device *ofdev,
+static int __devinit mpc5xxx_can_probe(struct platform_device *ofdev,
 				       const struct of_device_id *id)
 {
 	struct mpc5xxx_can_data *data = (struct mpc5xxx_can_data *)id->data;
@@ -317,7 +317,7 @@
 	return err;
 }
 
-static int __devexit mpc5xxx_can_remove(struct of_device *ofdev)
+static int __devexit mpc5xxx_can_remove(struct platform_device *ofdev)
 {
 	struct net_device *dev = dev_get_drvdata(&ofdev->dev);
 	struct mscan_priv *priv = netdev_priv(dev);
@@ -334,7 +334,7 @@
 
 #ifdef CONFIG_PM
 static struct mscan_regs saved_regs;
-static int mpc5xxx_can_suspend(struct of_device *ofdev, pm_message_t state)
+static int mpc5xxx_can_suspend(struct platform_device *ofdev, pm_message_t state)
 {
 	struct net_device *dev = dev_get_drvdata(&ofdev->dev);
 	struct mscan_priv *priv = netdev_priv(dev);
@@ -345,7 +345,7 @@
 	return 0;
 }
 
-static int mpc5xxx_can_resume(struct of_device *ofdev)
+static int mpc5xxx_can_resume(struct platform_device *ofdev)
 {
 	struct net_device *dev = dev_get_drvdata(&ofdev->dev);
 	struct mscan_priv *priv = netdev_priv(dev);
diff --git a/drivers/net/can/sja1000/sja1000_of_platform.c b/drivers/net/can/sja1000/sja1000_of_platform.c
index ac1a83d..5bfccfd 100644
--- a/drivers/net/can/sja1000/sja1000_of_platform.c
+++ b/drivers/net/can/sja1000/sja1000_of_platform.c
@@ -67,7 +67,7 @@
 	out_8(priv->reg_base + reg, val);
 }
 
-static int __devexit sja1000_ofp_remove(struct of_device *ofdev)
+static int __devexit sja1000_ofp_remove(struct platform_device *ofdev)
 {
 	struct net_device *dev = dev_get_drvdata(&ofdev->dev);
 	struct sja1000_priv *priv = netdev_priv(dev);
@@ -87,7 +87,7 @@
 	return 0;
 }
 
-static int __devinit sja1000_ofp_probe(struct of_device *ofdev,
+static int __devinit sja1000_ofp_probe(struct platform_device *ofdev,
 				       const struct of_device_id *id)
 {
 	struct device_node *np = ofdev->dev.of_node;
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index 0060e42..99a9299 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -413,7 +413,7 @@
 
 struct ehea_adapter {
 	u64 handle;
-	struct of_device *ofdev;
+	struct platform_device *ofdev;
 	struct ehea_port *port[EHEA_MAX_PORTS];
 	struct ehea_eq *neq;       /* notification event queue */
 	struct tasklet_struct neq_tasklet;
@@ -465,7 +465,7 @@
 	struct net_device *netdev;
 	struct net_device_stats stats;
 	struct ehea_port_res port_res[EHEA_MAX_PORT_RES];
-	struct of_device  ofdev; /* Open Firmware Device */
+	struct platform_device  ofdev; /* Open Firmware Device */
 	struct ehea_mc_list *mc_list;	 /* Multicast MAC addresses */
 	struct vlan_group *vgrp;
 	struct ehea_eq *qp_eq;
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index 3beba70..897719b 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -107,10 +107,10 @@
 struct ehea_bcmc_reg_array ehea_bcmc_regs;
 
 
-static int __devinit ehea_probe_adapter(struct of_device *dev,
+static int __devinit ehea_probe_adapter(struct platform_device *dev,
 					const struct of_device_id *id);
 
-static int __devexit ehea_remove(struct of_device *dev);
+static int __devexit ehea_remove(struct platform_device *dev);
 
 static struct of_device_id ehea_device_table[] = {
 	{
@@ -3376,7 +3376,7 @@
 static DEVICE_ATTR(probe_port, S_IWUSR, NULL, ehea_probe_port);
 static DEVICE_ATTR(remove_port, S_IWUSR, NULL, ehea_remove_port);
 
-int ehea_create_device_sysfs(struct of_device *dev)
+int ehea_create_device_sysfs(struct platform_device *dev)
 {
 	int ret = device_create_file(&dev->dev, &dev_attr_probe_port);
 	if (ret)
@@ -3387,13 +3387,13 @@
 	return ret;
 }
 
-void ehea_remove_device_sysfs(struct of_device *dev)
+void ehea_remove_device_sysfs(struct platform_device *dev)
 {
 	device_remove_file(&dev->dev, &dev_attr_probe_port);
 	device_remove_file(&dev->dev, &dev_attr_remove_port);
 }
 
-static int __devinit ehea_probe_adapter(struct of_device *dev,
+static int __devinit ehea_probe_adapter(struct platform_device *dev,
 					const struct of_device_id *id)
 {
 	struct ehea_adapter *adapter;
@@ -3492,7 +3492,7 @@
 	return ret;
 }
 
-static int __devexit ehea_remove(struct of_device *dev)
+static int __devexit ehea_remove(struct platform_device *dev)
 {
 	struct ehea_adapter *adapter = dev_get_drvdata(&dev->dev);
 	int i;
diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c
index d1a5b17..e3e10b4 100644
--- a/drivers/net/fec_mpc52xx.c
+++ b/drivers/net/fec_mpc52xx.c
@@ -850,7 +850,7 @@
 /* ======================================================================== */
 
 static int __devinit
-mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
+mpc52xx_fec_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	int rv;
 	struct net_device *ndev;
@@ -995,7 +995,7 @@
 }
 
 static int
-mpc52xx_fec_remove(struct of_device *op)
+mpc52xx_fec_remove(struct platform_device *op)
 {
 	struct net_device *ndev;
 	struct mpc52xx_fec_priv *priv;
@@ -1025,7 +1025,7 @@
 }
 
 #ifdef CONFIG_PM
-static int mpc52xx_fec_of_suspend(struct of_device *op, pm_message_t state)
+static int mpc52xx_fec_of_suspend(struct platform_device *op, pm_message_t state)
 {
 	struct net_device *dev = dev_get_drvdata(&op->dev);
 
@@ -1035,7 +1035,7 @@
 	return 0;
 }
 
-static int mpc52xx_fec_of_resume(struct of_device *op)
+static int mpc52xx_fec_of_resume(struct platform_device *op)
 {
 	struct net_device *dev = dev_get_drvdata(&op->dev);
 
diff --git a/drivers/net/fec_mpc52xx_phy.c b/drivers/net/fec_mpc52xx_phy.c
index dbaf72c..0b4cb6f 100644
--- a/drivers/net/fec_mpc52xx_phy.c
+++ b/drivers/net/fec_mpc52xx_phy.c
@@ -61,7 +61,7 @@
 		data | FEC_MII_WRITE_FRAME);
 }
 
-static int mpc52xx_fec_mdio_probe(struct of_device *of,
+static int mpc52xx_fec_mdio_probe(struct platform_device *of,
 		const struct of_device_id *match)
 {
 	struct device *dev = &of->dev;
@@ -122,7 +122,7 @@
 	return err;
 }
 
-static int mpc52xx_fec_mdio_remove(struct of_device *of)
+static int mpc52xx_fec_mdio_remove(struct platform_device *of)
 {
 	struct device *dev = &of->dev;
 	struct mii_bus *bus = dev_get_drvdata(dev);
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index f08cff9..d6e3111 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -997,7 +997,7 @@
 #endif
 };
 
-static int __devinit fs_enet_probe(struct of_device *ofdev,
+static int __devinit fs_enet_probe(struct platform_device *ofdev,
                                    const struct of_device_id *match)
 {
 	struct net_device *ndev;
@@ -1105,7 +1105,7 @@
 	return ret;
 }
 
-static int fs_enet_remove(struct of_device *ofdev)
+static int fs_enet_remove(struct platform_device *ofdev)
 {
 	struct net_device *ndev = dev_get_drvdata(&ofdev->dev);
 	struct fs_enet_private *fep = netdev_priv(ndev);
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c
index 48e91b6..7a84e45 100644
--- a/drivers/net/fs_enet/mac-fcc.c
+++ b/drivers/net/fs_enet/mac-fcc.c
@@ -84,7 +84,7 @@
 
 static int do_pd_setup(struct fs_enet_private *fep)
 {
-	struct of_device *ofdev = to_of_device(fep->dev);
+	struct platform_device *ofdev = to_platform_device(fep->dev);
 	struct fs_platform_info *fpi = fep->fpi;
 	int ret = -EINVAL;
 
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c
index 7ca1642..61035fc 100644
--- a/drivers/net/fs_enet/mac-fec.c
+++ b/drivers/net/fs_enet/mac-fec.c
@@ -96,7 +96,7 @@
 
 static int do_pd_setup(struct fs_enet_private *fep)
 {
-	struct of_device *ofdev = to_of_device(fep->dev);
+	struct platform_device *ofdev = to_platform_device(fep->dev);
 
 	fep->interrupt = of_irq_to_resource(ofdev->dev.of_node, 0, NULL);
 	if (fep->interrupt == NO_IRQ)
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c
index a3c4454..22a02a7 100644
--- a/drivers/net/fs_enet/mac-scc.c
+++ b/drivers/net/fs_enet/mac-scc.c
@@ -96,7 +96,7 @@
 
 static int do_pd_setup(struct fs_enet_private *fep)
 {
-	struct of_device *ofdev = to_of_device(fep->dev);
+	struct platform_device *ofdev = to_platform_device(fep->dev);
 
 	fep->interrupt = of_irq_to_resource(ofdev->dev.of_node, 0, NULL);
 	if (fep->interrupt == NO_IRQ)
diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c
index 3607340..3cda2b5 100644
--- a/drivers/net/fs_enet/mii-bitbang.c
+++ b/drivers/net/fs_enet/mii-bitbang.c
@@ -150,7 +150,7 @@
 	return 0;
 }
 
-static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
+static int __devinit fs_enet_mdio_probe(struct platform_device *ofdev,
                                         const struct of_device_id *match)
 {
 	struct mii_bus *new_bus;
@@ -200,7 +200,7 @@
 	return ret;
 }
 
-static int fs_enet_mdio_remove(struct of_device *ofdev)
+static int fs_enet_mdio_remove(struct platform_device *ofdev)
 {
 	struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
 	struct bb_info *bitbang = bus->priv;
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c
index bddffd1..dbb9c48 100644
--- a/drivers/net/fs_enet/mii-fec.c
+++ b/drivers/net/fs_enet/mii-fec.c
@@ -101,7 +101,7 @@
 	return 0;
 }
 
-static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
+static int __devinit fs_enet_mdio_probe(struct platform_device *ofdev,
                                         const struct of_device_id *match)
 {
 	struct resource res;
@@ -192,7 +192,7 @@
 	return ret;
 }
 
-static int fs_enet_mdio_remove(struct of_device *ofdev)
+static int fs_enet_mdio_remove(struct platform_device *ofdev)
 {
 	struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
 	struct fec_info *fec = bus->priv;
diff --git a/drivers/net/fsl_pq_mdio.c b/drivers/net/fsl_pq_mdio.c
index f53f850..d4bf91a 100644
--- a/drivers/net/fsl_pq_mdio.c
+++ b/drivers/net/fsl_pq_mdio.c
@@ -265,7 +265,7 @@
 #endif
 
 
-static int fsl_pq_mdio_probe(struct of_device *ofdev,
+static int fsl_pq_mdio_probe(struct platform_device *ofdev,
 		const struct of_device_id *match)
 {
 	struct device_node *np = ofdev->dev.of_node;
@@ -425,7 +425,7 @@
 }
 
 
-static int fsl_pq_mdio_remove(struct of_device *ofdev)
+static int fsl_pq_mdio_remove(struct platform_device *ofdev)
 {
 	struct device *device = &ofdev->dev;
 	struct mii_bus *bus = dev_get_drvdata(device);
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index a1b6301..4f7c3f3 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -122,9 +122,9 @@
 static void adjust_link(struct net_device *dev);
 static void init_registers(struct net_device *dev);
 static int init_phy(struct net_device *dev);
-static int gfar_probe(struct of_device *ofdev,
+static int gfar_probe(struct platform_device *ofdev,
 		const struct of_device_id *match);
-static int gfar_remove(struct of_device *ofdev);
+static int gfar_remove(struct platform_device *ofdev);
 static void free_skb_resources(struct gfar_private *priv);
 static void gfar_set_multi(struct net_device *dev);
 static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);
@@ -605,7 +605,7 @@
 	return 0;
 }
 
-static int gfar_of_init(struct of_device *ofdev, struct net_device **pdev)
+static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
 {
 	const char *model;
 	const char *ctype;
@@ -959,7 +959,7 @@
 
 /* Set up the ethernet device structure, private data,
  * and anything else we need before we start */
-static int gfar_probe(struct of_device *ofdev,
+static int gfar_probe(struct platform_device *ofdev,
 		const struct of_device_id *match)
 {
 	u32 tempval;
@@ -1238,7 +1238,7 @@
 	return err;
 }
 
-static int gfar_remove(struct of_device *ofdev)
+static int gfar_remove(struct platform_device *ofdev)
 {
 	struct gfar_private *priv = dev_get_drvdata(&ofdev->dev);
 
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index 710810e..68984eb 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -1054,7 +1054,7 @@
 
 	struct device_node *node;
 	struct net_device *ndev;
-	struct of_device *ofdev;
+	struct platform_device *ofdev;
 	enum gfar_errata errata;
 
 	struct gfar_priv_grp gfargrp[MAXGROUPS];
diff --git a/drivers/net/greth.c b/drivers/net/greth.c
index 4d09eab..f15c64f 100644
--- a/drivers/net/greth.c
+++ b/drivers/net/greth.c
@@ -1373,7 +1373,7 @@
 }
 
 /* Initialize the GRETH MAC */
-static int __devinit greth_of_probe(struct of_device *ofdev, const struct of_device_id *match)
+static int __devinit greth_of_probe(struct platform_device *ofdev, const struct of_device_id *match)
 {
 	struct net_device *dev;
 	struct greth_private *greth;
@@ -1412,7 +1412,7 @@
 	}
 
 	regs = (struct greth_regs *) greth->regs;
-	greth->irq = ofdev->irqs[0];
+	greth->irq = ofdev->archdata.irqs[0];
 
 	dev_set_drvdata(greth->dev, dev);
 	SET_NETDEV_DEV(dev, greth->dev);
@@ -1572,7 +1572,7 @@
 	return err;
 }
 
-static int __devexit greth_of_remove(struct of_device *of_dev)
+static int __devexit greth_of_remove(struct platform_device *of_dev)
 {
 	struct net_device *ndev = dev_get_drvdata(&of_dev->dev);
 	struct greth_private *greth = netdev_priv(ndev);
diff --git a/drivers/net/greth.h b/drivers/net/greth.h
index 973388d..03ad903 100644
--- a/drivers/net/greth.h
+++ b/drivers/net/greth.h
@@ -118,7 +118,7 @@
 
 	int irq;
 
-	struct device *dev;	        /* Pointer to of_device->dev */
+	struct device *dev;	        /* Pointer to platform_device->dev */
 	struct net_device *netdev;
 	struct napi_struct napi;
 	spinlock_t devlock;
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
index eeec7bc..3506fd6 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ibm_newemac/core.c
@@ -2245,7 +2245,7 @@
 struct emac_depentry {
 	u32			phandle;
 	struct device_node	*node;
-	struct of_device	*ofdev;
+	struct platform_device	*ofdev;
 	void			*drvdata;
 };
 
@@ -2719,7 +2719,7 @@
 	.ndo_change_mtu		= emac_change_mtu,
 };
 
-static int __devinit emac_probe(struct of_device *ofdev,
+static int __devinit emac_probe(struct platform_device *ofdev,
 				const struct of_device_id *match)
 {
 	struct net_device *ndev;
@@ -2941,7 +2941,7 @@
 	return err;
 }
 
-static int __devexit emac_remove(struct of_device *ofdev)
+static int __devexit emac_remove(struct platform_device *ofdev)
 {
 	struct emac_instance *dev = dev_get_drvdata(&ofdev->dev);
 
diff --git a/drivers/net/ibm_newemac/core.h b/drivers/net/ibm_newemac/core.h
index b1cbe6f..9e37e3d 100644
--- a/drivers/net/ibm_newemac/core.h
+++ b/drivers/net/ibm_newemac/core.h
@@ -170,12 +170,12 @@
 	struct net_device		*ndev;
 	struct resource			rsrc_regs;
 	struct emac_regs		__iomem *emacp;
-	struct of_device		*ofdev;
+	struct platform_device		*ofdev;
 	struct device_node		**blist; /* bootlist entry */
 
 	/* MAL linkage */
 	u32				mal_ph;
-	struct of_device		*mal_dev;
+	struct platform_device		*mal_dev;
 	u32				mal_rx_chan;
 	u32				mal_tx_chan;
 	struct mal_instance		*mal;
@@ -196,24 +196,24 @@
 
 	/* Shared MDIO if any */
 	u32				mdio_ph;
-	struct of_device		*mdio_dev;
+	struct platform_device		*mdio_dev;
 	struct emac_instance		*mdio_instance;
 	struct mutex			mdio_lock;
 
 	/* ZMII infos if any */
 	u32				zmii_ph;
 	u32				zmii_port;
-	struct of_device		*zmii_dev;
+	struct platform_device		*zmii_dev;
 
 	/* RGMII infos if any */
 	u32				rgmii_ph;
 	u32				rgmii_port;
-	struct of_device		*rgmii_dev;
+	struct platform_device		*rgmii_dev;
 
 	/* TAH infos if any */
 	u32				tah_ph;
 	u32				tah_port;
-	struct of_device		*tah_dev;
+	struct platform_device		*tah_dev;
 
 	/* IRQs */
 	int				wol_irq;
diff --git a/drivers/net/ibm_newemac/mal.c b/drivers/net/ibm_newemac/mal.c
index fcff9e0..d5717e2 100644
--- a/drivers/net/ibm_newemac/mal.c
+++ b/drivers/net/ibm_newemac/mal.c
@@ -517,7 +517,7 @@
 	return regs + 1;
 }
 
-static int __devinit mal_probe(struct of_device *ofdev,
+static int __devinit mal_probe(struct platform_device *ofdev,
 			       const struct of_device_id *match)
 {
 	struct mal_instance *mal;
@@ -730,7 +730,7 @@
 	return err;
 }
 
-static int __devexit mal_remove(struct of_device *ofdev)
+static int __devexit mal_remove(struct platform_device *ofdev)
 {
 	struct mal_instance *mal = dev_get_drvdata(&ofdev->dev);
 
diff --git a/drivers/net/ibm_newemac/mal.h b/drivers/net/ibm_newemac/mal.h
index 9ededfb..6608421 100644
--- a/drivers/net/ibm_newemac/mal.h
+++ b/drivers/net/ibm_newemac/mal.h
@@ -210,7 +210,7 @@
 	dma_addr_t		bd_dma;
 	struct mal_descriptor	*bd_virt;
 
-	struct of_device	*ofdev;
+	struct platform_device	*ofdev;
 	int			index;
 	spinlock_t		lock;
 
diff --git a/drivers/net/ibm_newemac/rgmii.c b/drivers/net/ibm_newemac/rgmii.c
index 108919b..dd61798 100644
--- a/drivers/net/ibm_newemac/rgmii.c
+++ b/drivers/net/ibm_newemac/rgmii.c
@@ -93,7 +93,7 @@
 	}
 }
 
-int __devinit rgmii_attach(struct of_device *ofdev, int input, int mode)
+int __devinit rgmii_attach(struct platform_device *ofdev, int input, int mode)
 {
 	struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
 	struct rgmii_regs __iomem *p = dev->base;
@@ -122,7 +122,7 @@
 	return 0;
 }
 
-void rgmii_set_speed(struct of_device *ofdev, int input, int speed)
+void rgmii_set_speed(struct platform_device *ofdev, int input, int speed)
 {
 	struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
 	struct rgmii_regs __iomem *p = dev->base;
@@ -144,7 +144,7 @@
 	mutex_unlock(&dev->lock);
 }
 
-void rgmii_get_mdio(struct of_device *ofdev, int input)
+void rgmii_get_mdio(struct platform_device *ofdev, int input)
 {
 	struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
 	struct rgmii_regs __iomem *p = dev->base;
@@ -165,7 +165,7 @@
 	DBG2(dev, " fer = 0x%08x\n", fer);
 }
 
-void rgmii_put_mdio(struct of_device *ofdev, int input)
+void rgmii_put_mdio(struct platform_device *ofdev, int input)
 {
 	struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
 	struct rgmii_regs __iomem *p = dev->base;
@@ -186,7 +186,7 @@
 	mutex_unlock(&dev->lock);
 }
 
-void rgmii_detach(struct of_device *ofdev, int input)
+void rgmii_detach(struct platform_device *ofdev, int input)
 {
 	struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
 	struct rgmii_regs __iomem *p;
@@ -206,13 +206,13 @@
 	mutex_unlock(&dev->lock);
 }
 
-int rgmii_get_regs_len(struct of_device *ofdev)
+int rgmii_get_regs_len(struct platform_device *ofdev)
 {
 	return sizeof(struct emac_ethtool_regs_subhdr) +
 		sizeof(struct rgmii_regs);
 }
 
-void *rgmii_dump_regs(struct of_device *ofdev, void *buf)
+void *rgmii_dump_regs(struct platform_device *ofdev, void *buf)
 {
 	struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
 	struct emac_ethtool_regs_subhdr *hdr = buf;
@@ -228,7 +228,7 @@
 }
 
 
-static int __devinit rgmii_probe(struct of_device *ofdev,
+static int __devinit rgmii_probe(struct platform_device *ofdev,
 				 const struct of_device_id *match)
 {
 	struct device_node *np = ofdev->dev.of_node;
@@ -293,7 +293,7 @@
 	return rc;
 }
 
-static int __devexit rgmii_remove(struct of_device *ofdev)
+static int __devexit rgmii_remove(struct platform_device *ofdev)
 {
 	struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
 
diff --git a/drivers/net/ibm_newemac/rgmii.h b/drivers/net/ibm_newemac/rgmii.h
index c4a4b35..d697990 100644
--- a/drivers/net/ibm_newemac/rgmii.h
+++ b/drivers/net/ibm_newemac/rgmii.h
@@ -51,20 +51,20 @@
 	int				users;
 
 	/* OF device instance */
-	struct of_device		*ofdev;
+	struct platform_device		*ofdev;
 };
 
 #ifdef CONFIG_IBM_NEW_EMAC_RGMII
 
 extern int rgmii_init(void);
 extern void rgmii_exit(void);
-extern int rgmii_attach(struct of_device *ofdev, int input, int mode);
-extern void rgmii_detach(struct of_device *ofdev, int input);
-extern void rgmii_get_mdio(struct of_device *ofdev, int input);
-extern void rgmii_put_mdio(struct of_device *ofdev, int input);
-extern void rgmii_set_speed(struct of_device *ofdev, int input, int speed);
-extern int rgmii_get_regs_len(struct of_device *ofdev);
-extern void *rgmii_dump_regs(struct of_device *ofdev, void *buf);
+extern int rgmii_attach(struct platform_device *ofdev, int input, int mode);
+extern void rgmii_detach(struct platform_device *ofdev, int input);
+extern void rgmii_get_mdio(struct platform_device *ofdev, int input);
+extern void rgmii_put_mdio(struct platform_device *ofdev, int input);
+extern void rgmii_set_speed(struct platform_device *ofdev, int input, int speed);
+extern int rgmii_get_regs_len(struct platform_device *ofdev);
+extern void *rgmii_dump_regs(struct platform_device *ofdev, void *buf);
 
 #else
 
diff --git a/drivers/net/ibm_newemac/tah.c b/drivers/net/ibm_newemac/tah.c
index 0446371..299aa49 100644
--- a/drivers/net/ibm_newemac/tah.c
+++ b/drivers/net/ibm_newemac/tah.c
@@ -23,7 +23,7 @@
 #include "emac.h"
 #include "core.h"
 
-int __devinit tah_attach(struct of_device *ofdev, int channel)
+int __devinit tah_attach(struct platform_device *ofdev, int channel)
 {
 	struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
 
@@ -35,7 +35,7 @@
 	return 0;
 }
 
-void tah_detach(struct of_device *ofdev, int channel)
+void tah_detach(struct platform_device *ofdev, int channel)
 {
 	struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
 
@@ -44,7 +44,7 @@
 	mutex_unlock(&dev->lock);
 }
 
-void tah_reset(struct of_device *ofdev)
+void tah_reset(struct platform_device *ofdev)
 {
 	struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
 	struct tah_regs __iomem *p = dev->base;
@@ -66,13 +66,13 @@
 		 TAH_MR_DIG);
 }
 
-int tah_get_regs_len(struct of_device *ofdev)
+int tah_get_regs_len(struct platform_device *ofdev)
 {
 	return sizeof(struct emac_ethtool_regs_subhdr) +
 		sizeof(struct tah_regs);
 }
 
-void *tah_dump_regs(struct of_device *ofdev, void *buf)
+void *tah_dump_regs(struct platform_device *ofdev, void *buf)
 {
 	struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
 	struct emac_ethtool_regs_subhdr *hdr = buf;
@@ -87,7 +87,7 @@
 	return regs + 1;
 }
 
-static int __devinit tah_probe(struct of_device *ofdev,
+static int __devinit tah_probe(struct platform_device *ofdev,
 			       const struct of_device_id *match)
 {
 	struct device_node *np = ofdev->dev.of_node;
@@ -139,7 +139,7 @@
 	return rc;
 }
 
-static int __devexit tah_remove(struct of_device *ofdev)
+static int __devexit tah_remove(struct platform_device *ofdev)
 {
 	struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
 
diff --git a/drivers/net/ibm_newemac/tah.h b/drivers/net/ibm_newemac/tah.h
index a068b56..61dbeca 100644
--- a/drivers/net/ibm_newemac/tah.h
+++ b/drivers/net/ibm_newemac/tah.h
@@ -48,7 +48,7 @@
 	int				users;
 
 	/* OF device instance */
-	struct of_device		*ofdev;
+	struct platform_device		*ofdev;
 };
 
 
@@ -74,11 +74,11 @@
 
 extern int tah_init(void);
 extern void tah_exit(void);
-extern int tah_attach(struct of_device *ofdev, int channel);
-extern void tah_detach(struct of_device *ofdev, int channel);
-extern void tah_reset(struct of_device *ofdev);
-extern int tah_get_regs_len(struct of_device *ofdev);
-extern void *tah_dump_regs(struct of_device *ofdev, void *buf);
+extern int tah_attach(struct platform_device *ofdev, int channel);
+extern void tah_detach(struct platform_device *ofdev, int channel);
+extern void tah_reset(struct platform_device *ofdev);
+extern int tah_get_regs_len(struct platform_device *ofdev);
+extern void *tah_dump_regs(struct platform_device *ofdev, void *buf);
 
 #else
 
diff --git a/drivers/net/ibm_newemac/zmii.c b/drivers/net/ibm_newemac/zmii.c
index 046dcd0..34ed6ee 100644
--- a/drivers/net/ibm_newemac/zmii.c
+++ b/drivers/net/ibm_newemac/zmii.c
@@ -82,7 +82,7 @@
 	}
 }
 
-int __devinit zmii_attach(struct of_device *ofdev, int input, int *mode)
+int __devinit zmii_attach(struct platform_device *ofdev, int input, int *mode)
 {
 	struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
 	struct zmii_regs __iomem *p = dev->base;
@@ -148,7 +148,7 @@
 	return 0;
 }
 
-void zmii_get_mdio(struct of_device *ofdev, int input)
+void zmii_get_mdio(struct platform_device *ofdev, int input)
 {
 	struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
 	u32 fer;
@@ -161,7 +161,7 @@
 	out_be32(&dev->base->fer, fer | ZMII_FER_MDI(input));
 }
 
-void zmii_put_mdio(struct of_device *ofdev, int input)
+void zmii_put_mdio(struct platform_device *ofdev, int input)
 {
 	struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
 
@@ -170,7 +170,7 @@
 }
 
 
-void zmii_set_speed(struct of_device *ofdev, int input, int speed)
+void zmii_set_speed(struct platform_device *ofdev, int input, int speed)
 {
 	struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
 	u32 ssr;
@@ -191,7 +191,7 @@
 	mutex_unlock(&dev->lock);
 }
 
-void zmii_detach(struct of_device *ofdev, int input)
+void zmii_detach(struct platform_device *ofdev, int input)
 {
 	struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
 
@@ -210,13 +210,13 @@
 	mutex_unlock(&dev->lock);
 }
 
-int zmii_get_regs_len(struct of_device *ofdev)
+int zmii_get_regs_len(struct platform_device *ofdev)
 {
 	return sizeof(struct emac_ethtool_regs_subhdr) +
 		sizeof(struct zmii_regs);
 }
 
-void *zmii_dump_regs(struct of_device *ofdev, void *buf)
+void *zmii_dump_regs(struct platform_device *ofdev, void *buf)
 {
 	struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
 	struct emac_ethtool_regs_subhdr *hdr = buf;
@@ -231,7 +231,7 @@
 	return regs + 1;
 }
 
-static int __devinit zmii_probe(struct of_device *ofdev,
+static int __devinit zmii_probe(struct platform_device *ofdev,
 				const struct of_device_id *match)
 {
 	struct device_node *np = ofdev->dev.of_node;
@@ -286,7 +286,7 @@
 	return rc;
 }
 
-static int __devexit zmii_remove(struct of_device *ofdev)
+static int __devexit zmii_remove(struct platform_device *ofdev)
 {
 	struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
 
diff --git a/drivers/net/ibm_newemac/zmii.h b/drivers/net/ibm_newemac/zmii.h
index 6c9beba..1333fa2 100644
--- a/drivers/net/ibm_newemac/zmii.h
+++ b/drivers/net/ibm_newemac/zmii.h
@@ -48,20 +48,20 @@
 	u32				fer_save;
 
 	/* OF device instance */
-	struct of_device		*ofdev;
+	struct platform_device		*ofdev;
 };
 
 #ifdef CONFIG_IBM_NEW_EMAC_ZMII
 
 extern int zmii_init(void);
 extern void zmii_exit(void);
-extern int zmii_attach(struct of_device *ofdev, int input, int *mode);
-extern void zmii_detach(struct of_device *ofdev, int input);
-extern void zmii_get_mdio(struct of_device *ofdev, int input);
-extern void zmii_put_mdio(struct of_device *ofdev, int input);
-extern void zmii_set_speed(struct of_device *ofdev, int input, int speed);
-extern int zmii_get_regs_len(struct of_device *ocpdev);
-extern void *zmii_dump_regs(struct of_device *ofdev, void *buf);
+extern int zmii_attach(struct platform_device *ofdev, int input, int *mode);
+extern void zmii_detach(struct platform_device *ofdev, int input);
+extern void zmii_get_mdio(struct platform_device *ofdev, int input);
+extern void zmii_put_mdio(struct platform_device *ofdev, int input);
+extern void zmii_set_speed(struct platform_device *ofdev, int input, int speed);
+extern int zmii_get_regs_len(struct platform_device *ocpdev);
+extern void *zmii_dump_regs(struct platform_device *ofdev, void *buf);
 
 #else
 # define zmii_init()		0
diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c
index 4eea3f7..c7b6247 100644
--- a/drivers/net/ll_temac_main.c
+++ b/drivers/net/ll_temac_main.c
@@ -159,7 +159,7 @@
  * temac_dcr_setup - If the DMA is DCR based, then setup the address and
  * I/O  functions
  */
-static int temac_dcr_setup(struct temac_local *lp, struct of_device *op,
+static int temac_dcr_setup(struct temac_local *lp, struct platform_device *op,
 				struct device_node *np)
 {
 	unsigned int dcrs;
@@ -184,7 +184,7 @@
  * temac_dcr_setup - This is a stub for when DCR is not supported,
  * such as with MicroBlaze
  */
-static int temac_dcr_setup(struct temac_local *lp, struct of_device *op,
+static int temac_dcr_setup(struct temac_local *lp, struct platform_device *op,
 				struct device_node *np)
 {
 	return -1;
@@ -952,7 +952,7 @@
 };
 
 static int __init
-temac_of_probe(struct of_device *op, const struct of_device_id *match)
+temac_of_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	struct device_node *np;
 	struct temac_local *lp;
@@ -1094,7 +1094,7 @@
 	return rc;
 }
 
-static int __devexit temac_of_remove(struct of_device *op)
+static int __devexit temac_of_remove(struct platform_device *op)
 {
 	struct net_device *ndev = dev_get_drvdata(&op->dev);
 	struct temac_local *lp = netdev_priv(ndev);
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index d771d16..fb2c092 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -239,6 +239,7 @@
 	int watchdog_resets;
 	int watchdog_pause;
 	int pause;
+	bool fw_name_allocated;
 	char *fw_name;
 	char eeprom_strings[MYRI10GE_EEPROM_STRINGS_SIZE];
 	char *product_code_string;
@@ -271,6 +272,7 @@
 MODULE_FIRMWARE("myri10ge_rss_ethp_z8e.dat");
 MODULE_FIRMWARE("myri10ge_rss_eth_z8e.dat");
 
+/* Careful: must be accessed under kparam_block_sysfs_write */
 static char *myri10ge_fw_name = NULL;
 module_param(myri10ge_fw_name, charp, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(myri10ge_fw_name, "Firmware image name");
@@ -376,6 +378,14 @@
 
 static struct net_device_stats *myri10ge_get_stats(struct net_device *dev);
 
+static void set_fw_name(struct myri10ge_priv *mgp, char *name, bool allocated)
+{
+	if (mgp->fw_name_allocated)
+		kfree(mgp->fw_name);
+	mgp->fw_name = name;
+	mgp->fw_name_allocated = allocated;
+}
+
 static int
 myri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd,
 		  struct myri10ge_cmd *data, int atomic)
@@ -747,7 +757,7 @@
 			dev_warn(&mgp->pdev->dev, "via hotplug\n");
 		}
 
-		mgp->fw_name = "adopted";
+		set_fw_name(mgp, "adopted", false);
 		mgp->tx_boundary = 2048;
 		myri10ge_dummy_rdma(mgp, 1);
 		status = myri10ge_get_firmware_capabilities(mgp);
@@ -3233,7 +3243,7 @@
 	 * load the optimized firmware (which assumes aligned PCIe
 	 * completions) in order to see if it works on this host.
 	 */
-	mgp->fw_name = myri10ge_fw_aligned;
+	set_fw_name(mgp, myri10ge_fw_aligned, false);
 	status = myri10ge_load_firmware(mgp, 1);
 	if (status != 0) {
 		goto abort;
@@ -3261,7 +3271,7 @@
 abort:
 	/* fall back to using the unaligned firmware */
 	mgp->tx_boundary = 2048;
-	mgp->fw_name = myri10ge_fw_unaligned;
+	set_fw_name(mgp, myri10ge_fw_unaligned, false);
 
 }
 
@@ -3284,7 +3294,7 @@
 			dev_info(&mgp->pdev->dev, "PCIE x%d Link\n",
 				 link_width);
 			mgp->tx_boundary = 4096;
-			mgp->fw_name = myri10ge_fw_aligned;
+			set_fw_name(mgp, myri10ge_fw_aligned, false);
 		} else {
 			myri10ge_firmware_probe(mgp);
 		}
@@ -3293,22 +3303,29 @@
 			dev_info(&mgp->pdev->dev,
 				 "Assuming aligned completions (forced)\n");
 			mgp->tx_boundary = 4096;
-			mgp->fw_name = myri10ge_fw_aligned;
+			set_fw_name(mgp, myri10ge_fw_aligned, false);
 		} else {
 			dev_info(&mgp->pdev->dev,
 				 "Assuming unaligned completions (forced)\n");
 			mgp->tx_boundary = 2048;
-			mgp->fw_name = myri10ge_fw_unaligned;
+			set_fw_name(mgp, myri10ge_fw_unaligned, false);
 		}
 	}
+
+	kparam_block_sysfs_write(myri10ge_fw_name);
 	if (myri10ge_fw_name != NULL) {
-		overridden = 1;
-		mgp->fw_name = myri10ge_fw_name;
+		char *fw_name = kstrdup(myri10ge_fw_name, GFP_KERNEL);
+		if (fw_name) {
+			overridden = 1;
+			set_fw_name(mgp, fw_name, true);
+		}
 	}
+	kparam_unblock_sysfs_write(myri10ge_fw_name);
+
 	if (mgp->board_number < MYRI10GE_MAX_BOARDS &&
 	    myri10ge_fw_names[mgp->board_number] != NULL &&
 	    strlen(myri10ge_fw_names[mgp->board_number])) {
-		mgp->fw_name = myri10ge_fw_names[mgp->board_number];
+		set_fw_name(mgp, myri10ge_fw_names[mgp->board_number], false);
 		overridden = 1;
 	}
 	if (overridden)
@@ -3660,6 +3677,7 @@
 	struct myri10ge_cmd cmd;
 	struct pci_dev *pdev = mgp->pdev;
 	char *old_fw;
+	bool old_allocated;
 	int i, status, ncpus, msix_cap;
 
 	mgp->num_slices = 1;
@@ -3672,17 +3690,23 @@
 
 	/* try to load the slice aware rss firmware */
 	old_fw = mgp->fw_name;
+	old_allocated = mgp->fw_name_allocated;
+	/* don't free old_fw if we override it. */
+	mgp->fw_name_allocated = false;
+
 	if (myri10ge_fw_name != NULL) {
 		dev_info(&mgp->pdev->dev, "overriding rss firmware to %s\n",
 			 myri10ge_fw_name);
-		mgp->fw_name = myri10ge_fw_name;
+		set_fw_name(mgp, myri10ge_fw_name, false);
 	} else if (old_fw == myri10ge_fw_aligned)
-		mgp->fw_name = myri10ge_fw_rss_aligned;
+		set_fw_name(mgp, myri10ge_fw_rss_aligned, false);
 	else
-		mgp->fw_name = myri10ge_fw_rss_unaligned;
+		set_fw_name(mgp, myri10ge_fw_rss_unaligned, false);
 	status = myri10ge_load_firmware(mgp, 0);
 	if (status != 0) {
 		dev_info(&pdev->dev, "Rss firmware not found\n");
+		if (old_allocated)
+			kfree(old_fw);
 		return;
 	}
 
@@ -3747,6 +3771,8 @@
 					 mgp->num_slices);
 		if (status == 0) {
 			pci_disable_msix(pdev);
+			if (old_allocated)
+				kfree(old_fw);
 			return;
 		}
 		if (status > 0)
@@ -3763,7 +3789,7 @@
 
 abort_with_fw:
 	mgp->num_slices = 1;
-	mgp->fw_name = old_fw;
+	set_fw_name(mgp, old_fw, old_allocated);
 	myri10ge_load_firmware(mgp, 0);
 }
 
@@ -3993,6 +4019,7 @@
 	pci_disable_device(pdev);
 
 abort_with_netdev:
+	set_fw_name(mgp, NULL, false);
 	free_netdev(netdev);
 	return status;
 }
@@ -4037,6 +4064,7 @@
 	dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd),
 			  mgp->cmd, mgp->cmd_bus);
 
+	set_fw_name(mgp, NULL, false);
 	free_netdev(netdev);
 	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index 04e552a..617f898 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -926,7 +926,7 @@
 	.ndo_validate_addr	= eth_validate_addr,
 };
 
-static int __devinit myri_sbus_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit myri_sbus_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	struct device_node *dp = op->dev.of_node;
 	static unsigned version_printed;
@@ -1124,7 +1124,7 @@
 	return -ENODEV;
 }
 
-static int __devexit myri_sbus_remove(struct of_device *op)
+static int __devexit myri_sbus_remove(struct platform_device *op)
 {
 	struct myri_eth *mp = dev_get_drvdata(&op->dev);
 	struct net_device *net_dev = mp->dev;
diff --git a/drivers/net/myri_sbus.h b/drivers/net/myri_sbus.h
index ff363e9..80a2fa5 100644
--- a/drivers/net/myri_sbus.h
+++ b/drivers/net/myri_sbus.h
@@ -288,7 +288,7 @@
 	struct myri_eeprom		eeprom;		/* Local copy of EEPROM.      */
 	unsigned int			reg_size;	/* Size of register space.    */
 	unsigned int			shmem_base;	/* Offset to shared ram.      */
-	struct of_device		*myri_op;	/* Our OF device struct.    */
+	struct platform_device		*myri_op;	/* Our OF device struct.    */
 };
 
 /* We use this to acquire receive skb's that we can DMA directly into. */
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index 404f2d55..bc695d5 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -9103,7 +9103,7 @@
 static int __devinit niu_n2_irq_init(struct niu *np, u8 *ldg_num_map)
 {
 #ifdef CONFIG_SPARC64
-	struct of_device *op = np->op;
+	struct platform_device *op = np->op;
 	const u32 *int_prop;
 	int i;
 
@@ -9688,7 +9688,7 @@
 
 static struct net_device * __devinit niu_alloc_and_init(
 	struct device *gen_dev, struct pci_dev *pdev,
-	struct of_device *op, const struct niu_ops *ops,
+	struct platform_device *op, const struct niu_ops *ops,
 	u8 port)
 {
 	struct net_device *dev;
@@ -10064,7 +10064,7 @@
 	.unmap_single	= niu_phys_unmap_single,
 };
 
-static int __devinit niu_of_probe(struct of_device *op,
+static int __devinit niu_of_probe(struct platform_device *op,
 				  const struct of_device_id *match)
 {
 	union niu_parent_id parent_id;
@@ -10179,7 +10179,7 @@
 	return err;
 }
 
-static int __devexit niu_of_remove(struct of_device *op)
+static int __devexit niu_of_remove(struct platform_device *op)
 {
 	struct net_device *dev = dev_get_drvdata(&op->dev);
 
diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
index fc5fef2..f62c7b7 100644
--- a/drivers/net/phy/mdio-gpio.c
+++ b/drivers/net/phy/mdio-gpio.c
@@ -188,7 +188,7 @@
 
 #ifdef CONFIG_OF_GPIO
 
-static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
+static int __devinit mdio_ofgpio_probe(struct platform_device *ofdev,
                                         const struct of_device_id *match)
 {
 	struct mdio_gpio_platform_data *pdata;
@@ -224,7 +224,7 @@
 	return -ENODEV;
 }
 
-static int __devexit mdio_ofgpio_remove(struct of_device *ofdev)
+static int __devexit mdio_ofgpio_remove(struct platform_device *ofdev)
 {
 	mdio_gpio_bus_destroy(&ofdev->dev);
 	kfree(ofdev->dev.platform_data);
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
index 09c071b..618643e 100644
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/sunbmac.c
@@ -97,7 +97,7 @@
 
 static void qec_init(struct bigmac *bp)
 {
-	struct of_device *qec_op = bp->qec_op;
+	struct platform_device *qec_op = bp->qec_op;
 	void __iomem *gregs = bp->gregs;
 	u8 bsizes = bp->bigmac_bursts;
 	u32 regval;
@@ -1083,8 +1083,8 @@
 	.ndo_validate_addr	= eth_validate_addr,
 };
 
-static int __devinit bigmac_ether_init(struct of_device *op,
-				       struct of_device *qec_op)
+static int __devinit bigmac_ether_init(struct platform_device *op,
+				       struct platform_device *qec_op)
 {
 	static int version_printed;
 	struct net_device *dev;
@@ -1242,25 +1242,25 @@
 /* QEC can be the parent of either QuadEthernet or a BigMAC.  We want
  * the latter.
  */
-static int __devinit bigmac_sbus_probe(struct of_device *op,
+static int __devinit bigmac_sbus_probe(struct platform_device *op,
 				       const struct of_device_id *match)
 {
 	struct device *parent = op->dev.parent;
-	struct of_device *qec_op;
+	struct platform_device *qec_op;
 
-	qec_op = to_of_device(parent);
+	qec_op = to_platform_device(parent);
 
 	return bigmac_ether_init(op, qec_op);
 }
 
-static int __devexit bigmac_sbus_remove(struct of_device *op)
+static int __devexit bigmac_sbus_remove(struct platform_device *op)
 {
 	struct bigmac *bp = dev_get_drvdata(&op->dev);
 	struct device *parent = op->dev.parent;
 	struct net_device *net_dev = bp->dev;
-	struct of_device *qec_op;
+	struct platform_device *qec_op;
 
-	qec_op = to_of_device(parent);
+	qec_op = to_platform_device(parent);
 
 	unregister_netdev(net_dev);
 
diff --git a/drivers/net/sunbmac.h b/drivers/net/sunbmac.h
index 8840bc0..8db8894 100644
--- a/drivers/net/sunbmac.h
+++ b/drivers/net/sunbmac.h
@@ -329,8 +329,8 @@
 	unsigned int		timer_ticks;
 
 	struct net_device_stats	enet_stats;
-	struct of_device	*qec_op;
-	struct of_device	*bigmac_op;
+	struct platform_device	*qec_op;
+	struct platform_device	*bigmac_op;
 	struct net_device	*dev;
 };
 
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index eec443f..bd0df1c 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -1591,7 +1591,7 @@
 		 */
 #ifdef CONFIG_SBUS
 		if ((hp->happy_flags & HFLAG_PCI) == 0) {
-			struct of_device *op = hp->happy_dev;
+			struct platform_device *op = hp->happy_dev;
 			if (sbus_can_dma_64bit()) {
 				sbus_set_sbus64(&op->dev,
 						hp->happy_bursts);
@@ -2480,7 +2480,7 @@
 #ifdef CONFIG_SBUS
 	else {
 		const struct linux_prom_registers *regs;
-		struct of_device *op = hp->happy_dev;
+		struct platform_device *op = hp->happy_dev;
 		regs = of_get_property(op->dev.of_node, "regs", NULL);
 		if (regs)
 			sprintf(info->bus_info, "SBUS:%d",
@@ -2515,13 +2515,13 @@
  *
  * Return NULL on failure.
  */
-static struct quattro * __devinit quattro_sbus_find(struct of_device *child)
+static struct quattro * __devinit quattro_sbus_find(struct platform_device *child)
 {
 	struct device *parent = child->dev.parent;
-	struct of_device *op;
+	struct platform_device *op;
 	struct quattro *qp;
 
-	op = to_of_device(parent);
+	op = to_platform_device(parent);
 	qp = dev_get_drvdata(&op->dev);
 	if (qp)
 		return qp;
@@ -2551,7 +2551,7 @@
 	struct quattro *qp;
 
 	for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
-		struct of_device *op = qp->quattro_dev;
+		struct platform_device *op = qp->quattro_dev;
 		int err, qfe_slot, skip = 0;
 
 		for (qfe_slot = 0; qfe_slot < 4; qfe_slot++) {
@@ -2580,7 +2580,7 @@
 	struct quattro *qp;
 
 	for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
-		struct of_device *op = qp->quattro_dev;
+		struct platform_device *op = qp->quattro_dev;
 		int qfe_slot, skip = 0;
 
 		for (qfe_slot = 0; qfe_slot < 4; qfe_slot++) {
@@ -2639,7 +2639,7 @@
 };
 
 #ifdef CONFIG_SBUS
-static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe)
+static int __devinit happy_meal_sbus_probe_one(struct platform_device *op, int is_qfe)
 {
 	struct device_node *dp = op->dev.of_node, *sbus_dp;
 	struct quattro *qp = NULL;
@@ -2648,7 +2648,7 @@
 	int i, qfe_slot = -1;
 	int err = -ENODEV;
 
-	sbus_dp = to_of_device(op->dev.parent)->dev.of_node;
+	sbus_dp = op->dev.parent->of_node;
 
 	/* We can match PCI devices too, do not accept those here. */
 	if (strcmp(sbus_dp->name, "sbus"))
@@ -3235,7 +3235,7 @@
 #endif
 
 #ifdef CONFIG_SBUS
-static int __devinit hme_sbus_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit hme_sbus_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	struct device_node *dp = op->dev.of_node;
 	const char *model = of_get_property(dp, "model", NULL);
@@ -3247,7 +3247,7 @@
 	return happy_meal_sbus_probe_one(op, is_qfe);
 }
 
-static int __devexit hme_sbus_remove(struct of_device *op)
+static int __devexit hme_sbus_remove(struct platform_device *op)
 {
 	struct happy_meal *hp = dev_get_drvdata(&op->dev);
 	struct net_device *net_dev = hp->dev;
diff --git a/drivers/net/sunhme.h b/drivers/net/sunhme.h
index efd2ca0..756b5bf 100644
--- a/drivers/net/sunhme.h
+++ b/drivers/net/sunhme.h
@@ -407,7 +407,7 @@
 	void (*write_rxd)(struct happy_meal_rxd *, u32, u32);
 #endif
 
-	/* This is either an of_device or a pci_dev. */
+	/* This is either an platform_device or a pci_dev. */
 	void			  *happy_dev;
 	struct device		  *dma_dev;
 
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index ee364fa..8dcb858 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -250,7 +250,7 @@
 	int		rx_new, tx_new;
 	int		rx_old, tx_old;
 
-	struct of_device *ledma;	/* If set this points to ledma	*/
+	struct platform_device *ledma;	/* If set this points to ledma	*/
 	char		tpe;		/* cable-selection is TPE	*/
 	char		auto_select;	/* cable-selection by carrier	*/
 	char		burst_sizes;	/* ledma SBus burst sizes	*/
@@ -265,8 +265,8 @@
 	char	       	       *name;
 	dma_addr_t		init_block_dvma;
 	struct net_device      *dev;		  /* Backpointer	*/
-	struct of_device       *op;
-	struct of_device       *lebuffer;
+	struct platform_device       *op;
+	struct platform_device       *lebuffer;
 	struct timer_list       multicast_timer;
 };
 
@@ -1272,7 +1272,7 @@
 	if (lp->lregs)
 		of_iounmap(&lp->op->resource[0], lp->lregs, LANCE_REG_SIZE);
 	if (lp->dregs) {
-		struct of_device *ledma = lp->ledma;
+		struct platform_device *ledma = lp->ledma;
 
 		of_iounmap(&ledma->resource[0], lp->dregs,
 			   resource_size(&ledma->resource[0]));
@@ -1319,9 +1319,9 @@
 	.ndo_validate_addr	= eth_validate_addr,
 };
 
-static int __devinit sparc_lance_probe_one(struct of_device *op,
-					   struct of_device *ledma,
-					   struct of_device *lebuffer)
+static int __devinit sparc_lance_probe_one(struct platform_device *op,
+					   struct platform_device *ledma,
+					   struct platform_device *lebuffer)
 {
 	struct device_node *dp = op->dev.of_node;
 	static unsigned version_printed;
@@ -1503,9 +1503,9 @@
 	return -ENODEV;
 }
 
-static int __devinit sunlance_sbus_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit sunlance_sbus_probe(struct platform_device *op, const struct of_device_id *match)
 {
-	struct of_device *parent = to_of_device(op->dev.parent);
+	struct platform_device *parent = to_platform_device(op->dev.parent);
 	struct device_node *parent_dp = parent->dev.of_node;
 	int err;
 
@@ -1519,7 +1519,7 @@
 	return err;
 }
 
-static int __devexit sunlance_sbus_remove(struct of_device *op)
+static int __devexit sunlance_sbus_remove(struct platform_device *op)
 {
 	struct lance_private *lp = dev_get_drvdata(&op->dev);
 	struct net_device *net_dev = lp->dev;
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index 5f84a5d..72e65d4 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -689,7 +689,7 @@
 {
 	const struct linux_prom_registers *regs;
 	struct sunqe *qep = netdev_priv(dev);
-	struct of_device *op;
+	struct platform_device *op;
 
 	strcpy(info->driver, "sunqe");
 	strcpy(info->version, "3.0");
@@ -720,7 +720,7 @@
 };
 
 /* This is only called once at boot time for each card probed. */
-static void qec_init_once(struct sunqec *qecp, struct of_device *op)
+static void qec_init_once(struct sunqec *qecp, struct platform_device *op)
 {
 	u8 bsizes = qecp->qec_bursts;
 
@@ -770,9 +770,9 @@
 	return bsizes;
 }
 
-static struct sunqec * __devinit get_qec(struct of_device *child)
+static struct sunqec * __devinit get_qec(struct platform_device *child)
 {
-	struct of_device *op = to_of_device(child->dev.parent);
+	struct platform_device *op = to_platform_device(child->dev.parent);
 	struct sunqec *qecp;
 
 	qecp = dev_get_drvdata(&op->dev);
@@ -836,7 +836,7 @@
 	.ndo_validate_addr	= eth_validate_addr,
 };
 
-static int __devinit qec_ether_init(struct of_device *op)
+static int __devinit qec_ether_init(struct platform_device *op)
 {
 	static unsigned version_printed;
 	struct net_device *dev;
@@ -941,12 +941,12 @@
 	return res;
 }
 
-static int __devinit qec_sbus_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit qec_sbus_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	return qec_ether_init(op);
 }
 
-static int __devexit qec_sbus_remove(struct of_device *op)
+static int __devexit qec_sbus_remove(struct platform_device *op)
 {
 	struct sunqe *qp = dev_get_drvdata(&op->dev);
 	struct net_device *net_dev = qp->dev;
@@ -997,7 +997,7 @@
 
 	while (root_qec_dev) {
 		struct sunqec *next = root_qec_dev->next_module;
-		struct of_device *op = root_qec_dev->op;
+		struct platform_device *op = root_qec_dev->op;
 
 		free_irq(op->archdata.irqs[0], (void *) root_qec_dev);
 		of_iounmap(&op->resource[0], root_qec_dev->gregs,
diff --git a/drivers/net/sunqe.h b/drivers/net/sunqe.h
index 5813a7b..581781b 100644
--- a/drivers/net/sunqe.h
+++ b/drivers/net/sunqe.h
@@ -314,7 +314,7 @@
 	void __iomem		*gregs;		/* QEC Global Registers         */
 	struct sunqe		*qes[4];	/* Each child MACE              */
 	unsigned int            qec_bursts;	/* Support burst sizes          */
-	struct of_device	*op;		/* QEC's OF device              */
+	struct platform_device	*op;		/* QEC's OF device              */
 	struct sunqec		*next_module;	/* List of all QECs in system   */
 };
 
@@ -342,7 +342,7 @@
 	__u32				buffers_dvma;	/* DVMA visible address.       */
 	struct sunqec			*parent;
 	u8				mconfig;	/* Base MACE mconfig value     */
-	struct of_device		*op;		/* QE's OF device struct       */
+	struct platform_device		*op;		/* QE's OF device struct       */
 	struct net_device		*dev;		/* QE's netdevice struct       */
 	int				channel;	/* Who am I?                   */
 };
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 8d532f9..a4c3f57 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -3601,7 +3601,7 @@
 
 #ifdef CONFIG_PM
 
-static int ucc_geth_suspend(struct of_device *ofdev, pm_message_t state)
+static int ucc_geth_suspend(struct platform_device *ofdev, pm_message_t state)
 {
 	struct net_device *ndev = dev_get_drvdata(&ofdev->dev);
 	struct ucc_geth_private *ugeth = netdev_priv(ndev);
@@ -3629,7 +3629,7 @@
 	return 0;
 }
 
-static int ucc_geth_resume(struct of_device *ofdev)
+static int ucc_geth_resume(struct platform_device *ofdev)
 {
 	struct net_device *ndev = dev_get_drvdata(&ofdev->dev);
 	struct ucc_geth_private *ugeth = netdev_priv(ndev);
@@ -3732,7 +3732,7 @@
 #endif
 };
 
-static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *match)
+static int ucc_geth_probe(struct platform_device* ofdev, const struct of_device_id *match)
 {
 	struct device *device = &ofdev->dev;
 	struct device_node *np = ofdev->dev.of_node;
@@ -3954,7 +3954,7 @@
 	return 0;
 }
 
-static int ucc_geth_remove(struct of_device* ofdev)
+static int ucc_geth_remove(struct platform_device* ofdev)
 {
 	struct device *device = &ofdev->dev;
 	struct net_device *dev = dev_get_drvdata(device);
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 6e71346..ba854c7 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -125,6 +125,8 @@
 
 	const char		*helper;
 	const char		*firmware;
+	bool			helper_allocated;
+	bool			firmware_allocated;
 
 	u8			buffer[65536];
 
@@ -984,16 +986,34 @@
 	card->helper = if_sdio_models[i].helper;
 	card->firmware = if_sdio_models[i].firmware;
 
+	kparam_block_sysfs_write(helper_name);
 	if (lbs_helper_name) {
+		char *helper = kstrdup(lbs_helper_name, GFP_KERNEL);
+		if (!helper) {
+			kparam_unblock_sysfs_write(helper_name);
+			ret = -ENOMEM;
+			goto free;
+		}
 		lbs_deb_sdio("overriding helper firmware: %s\n",
 			lbs_helper_name);
-		card->helper = lbs_helper_name;
+		card->helper = helper;
+		card->helper_allocated = true;
 	}
+	kparam_unblock_sysfs_write(helper_name);
 
+	kparam_block_sysfs_write(fw_name);
 	if (lbs_fw_name) {
+		char *fw_name = kstrdup(lbs_fw_name, GFP_KERNEL);
+		if (!fw_name) {
+			kparam_unblock_sysfs_write(fw_name);
+			ret = -ENOMEM;
+			goto free;
+		}
 		lbs_deb_sdio("overriding firmware: %s\n", lbs_fw_name);
-		card->firmware = lbs_fw_name;
+		card->firmware = fw_name;
+		card->firmware_allocated = true;
 	}
+	kparam_unblock_sysfs_write(fw_name);
 
 	sdio_claim_host(func);
 
@@ -1127,6 +1147,10 @@
 		kfree(packet);
 	}
 
+	if (card->helper_allocated)
+		kfree(card->helper);
+	if (card->firmware_allocated)
+		kfree(card->firmware);
 	kfree(card);
 
 	goto out;
@@ -1177,6 +1201,10 @@
 		kfree(packet);
 	}
 
+	if (card->helper_allocated)
+		kfree(card->helper);
+	if (card->firmware_allocated)
+		kfree(card->firmware);
 	kfree(card);
 
 	lbs_deb_leave(LBS_DEB_SDIO);
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 07ece9d..3ff6106 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -289,10 +289,13 @@
 	}
 
 	/* Upload firmware */
+	kparam_block_sysfs_write(fw_name);
 	if (__if_usb_prog_firmware(cardp, lbs_fw_name, BOOT_CMD_FW_BY_USB)) {
+		kparam_unblock_sysfs_write(fw_name);
 		lbs_deb_usbd(&udev->dev, "FW upload failed\n");
 		goto err_prog_firmware;
 	}
+	kparam_unblock_sysfs_write(fw_name);
 
 	if (!(priv = lbs_add_card(cardp, &udev->dev)))
 		goto err_prog_firmware;
diff --git a/drivers/net/wireless/libertas_tf/if_usb.c b/drivers/net/wireless/libertas_tf/if_usb.c
index b172f5d..41a4f21 100644
--- a/drivers/net/wireless/libertas_tf/if_usb.c
+++ b/drivers/net/wireless/libertas_tf/if_usb.c
@@ -811,12 +811,15 @@
 
 	lbtf_deb_enter(LBTF_DEB_USB);
 
+	kparam_block_sysfs_write(fw_name);
 	ret = request_firmware(&cardp->fw, lbtf_fw_name, &cardp->udev->dev);
 	if (ret < 0) {
 		pr_err("request_firmware() failed with %#x\n", ret);
 		pr_err("firmware %s not found\n", lbtf_fw_name);
+		kparam_unblock_sysfs_write(fw_name);
 		goto done;
 	}
+	kparam_unblock_sysfs_write(fw_name);
 
 	if (check_fwfile_format(cardp->fw->data, cardp->fw->size))
 		goto release_fw;
diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c
index b2c2f39..ecbbb68 100644
--- a/drivers/net/xilinx_emaclite.c
+++ b/drivers/net/xilinx_emaclite.c
@@ -1086,7 +1086,7 @@
  *
  * Return:	Value of the parameter if the parameter is found, or 0 otherwise
  */
-static bool get_bool(struct of_device *ofdev, const char *s)
+static bool get_bool(struct platform_device *ofdev, const char *s)
 {
 	u32 *p = (u32 *)of_get_property(ofdev->dev.of_node, s, NULL);
 
@@ -1115,7 +1115,7 @@
  * Return:	0, if the driver is bound to the Emaclite device, or
  *		a negative error if there is failure.
  */
-static int __devinit xemaclite_of_probe(struct of_device *ofdev,
+static int __devinit xemaclite_of_probe(struct platform_device *ofdev,
 					const struct of_device_id *match)
 {
 	struct resource r_irq; /* Interrupt resources */
@@ -1240,7 +1240,7 @@
  *
  * Return:	0, always.
  */
-static int __devexit xemaclite_of_remove(struct of_device *of_dev)
+static int __devexit xemaclite_of_remove(struct platform_device *of_dev)
 {
 	struct device *dev = &of_dev->dev;
 	struct net_device *ndev = dev_get_drvdata(dev);
diff --git a/drivers/of/device.c b/drivers/of/device.c
index 0d8a064..92de0eb 100644
--- a/drivers/of/device.c
+++ b/drivers/of/device.c
@@ -14,7 +14,7 @@
  * @ids: array of of device match structures to search in
  * @dev: the of device structure to match against
  *
- * Used by a driver to check whether an of_device present in the
+ * Used by a driver to check whether an platform_device present in the
  * system is in its list of supported devices.
  */
 const struct of_device_id *of_match_device(const struct of_device_id *matches,
diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c
index 210a644..55ba118 100644
--- a/drivers/parport/parport_sunbpp.c
+++ b/drivers/parport/parport_sunbpp.c
@@ -286,7 +286,7 @@
 	.owner		= THIS_MODULE,
 };
 
-static int __devinit bpp_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit bpp_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	struct parport_operations *ops;
 	struct bpp_regs __iomem *regs;
@@ -351,7 +351,7 @@
 	return err;
 }
 
-static int __devexit bpp_remove(struct of_device *op)
+static int __devexit bpp_remove(struct platform_device *op)
 {
 	struct parport *p = dev_get_drvdata(&op->dev);
 	struct parport_operations *ops = p->ops;
diff --git a/drivers/pcmcia/electra_cf.c b/drivers/pcmcia/electra_cf.c
index f94d828..546d302 100644
--- a/drivers/pcmcia/electra_cf.c
+++ b/drivers/pcmcia/electra_cf.c
@@ -44,7 +44,7 @@
 	unsigned		present:1;
 	unsigned		active:1;
 
-	struct of_device	*ofdev;
+	struct platform_device	*ofdev;
 	unsigned long		mem_phys;
 	void __iomem *		mem_base;
 	unsigned long		mem_size;
@@ -181,7 +181,7 @@
 	.set_mem_map		= electra_cf_set_mem_map,
 };
 
-static int __devinit electra_cf_probe(struct of_device *ofdev,
+static int __devinit electra_cf_probe(struct platform_device *ofdev,
 				      const struct of_device_id *match)
 {
 	struct device *device = &ofdev->dev;
@@ -325,7 +325,7 @@
 
 }
 
-static int __devexit electra_cf_remove(struct of_device *ofdev)
+static int __devexit electra_cf_remove(struct platform_device *ofdev)
 {
 	struct device *device = &ofdev->dev;
 	struct electra_cf_socket *cf;
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
index f2f90a7..f0ecad9 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -1149,7 +1149,7 @@
 	.set_mem_map = m8xx_set_mem_map,
 };
 
-static int __init m8xx_probe(struct of_device *ofdev,
+static int __init m8xx_probe(struct platform_device *ofdev,
 			     const struct of_device_id *match)
 {
 	struct pcmcia_win *w;
@@ -1249,7 +1249,7 @@
 	return 0;
 }
 
-static int m8xx_remove(struct of_device *ofdev)
+static int m8xx_remove(struct platform_device *ofdev)
 {
 	u32 m, i;
 	struct pcmcia_win *w;
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 1e5506b..0734356 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -136,6 +136,12 @@
 	help
 	  Say Y to include support for the battery on the Zipit Z2.
 
+config BATTERY_S3C_ADC
+	tristate "Battery driver for Samsung ADC based monitoring"
+	depends on S3C_ADC
+	help
+	  Say Y here to enable support for iPAQ h1930/h1940/rx1950 battery
+
 config CHARGER_PCF50633
 	tristate "NXP PCF50633 MBC"
 	depends on MFD_PCF50633
@@ -153,4 +159,11 @@
 	  This driver can be build as a module. If so, the module will be
 	  called jz4740-battery.
 
+config BATTERY_INTEL_MID
+	tristate "Battery driver for Intel MID platforms"
+	depends on INTEL_SCU_IPC && SPI
+	help
+	  Say Y here to enable the battery driver on Intel MID
+	  platforms.
+
 endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index cf95009..10143aa 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -33,5 +33,7 @@
 obj-$(CONFIG_BATTERY_DA9030)	+= da9030_battery.o
 obj-$(CONFIG_BATTERY_MAX17040)	+= max17040_battery.o
 obj-$(CONFIG_BATTERY_Z2)	+= z2_battery.o
+obj-$(CONFIG_BATTERY_S3C_ADC)	+= s3c_adc_battery.o
 obj-$(CONFIG_CHARGER_PCF50633)	+= pcf50633-charger.o
 obj-$(CONFIG_BATTERY_JZ4740)	+= jz4740-battery.o
+obj-$(CONFIG_BATTERY_INTEL_MID)	+= intel_mid_battery.o
diff --git a/drivers/power/intel_mid_battery.c b/drivers/power/intel_mid_battery.c
new file mode 100644
index 0000000..c61ffec
--- /dev/null
+++ b/drivers/power/intel_mid_battery.c
@@ -0,0 +1,799 @@
+/*
+ * intel_mid_battery.c - Intel MID PMIC Battery Driver
+ *
+ * Copyright (C) 2009 Intel Corporation
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * Author: Nithish Mahalingam <nithish.mahalingam@intel.com>
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/jiffies.h>
+#include <linux/param.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+
+#include <asm/intel_scu_ipc.h>
+
+#define DRIVER_NAME "pmic_battery"
+
+/*********************************************************************
+ *		Generic defines
+ *********************************************************************/
+
+static int debug;
+module_param(debug, int, 0444);
+MODULE_PARM_DESC(debug, "Flag to enable PMIC Battery debug messages.");
+
+#define PMIC_BATT_DRV_INFO_UPDATED	1
+#define PMIC_BATT_PRESENT		1
+#define PMIC_BATT_NOT_PRESENT		0
+#define PMIC_USB_PRESENT		PMIC_BATT_PRESENT
+#define PMIC_USB_NOT_PRESENT		PMIC_BATT_NOT_PRESENT
+
+/* pmic battery register related */
+#define PMIC_BATT_CHR_SCHRGINT_ADDR	0xD2
+#define PMIC_BATT_CHR_SBATOVP_MASK	(1 << 1)
+#define PMIC_BATT_CHR_STEMP_MASK	(1 << 2)
+#define PMIC_BATT_CHR_SCOMP_MASK	(1 << 3)
+#define PMIC_BATT_CHR_SUSBDET_MASK	(1 << 4)
+#define PMIC_BATT_CHR_SBATDET_MASK	(1 << 5)
+#define PMIC_BATT_CHR_SDCLMT_MASK	(1 << 6)
+#define PMIC_BATT_CHR_SUSBOVP_MASK	(1 << 7)
+#define PMIC_BATT_CHR_EXCPT_MASK	0xC6
+#define PMIC_BATT_ADC_ACCCHRG_MASK	(1 << 31)
+#define PMIC_BATT_ADC_ACCCHRGVAL_MASK	0x7FFFFFFF
+
+/* pmic ipc related */
+#define PMIC_BATT_CHR_IPC_FCHRG_SUBID	0x4
+#define PMIC_BATT_CHR_IPC_TCHRG_SUBID	0x6
+
+/* types of battery charging */
+enum batt_charge_type {
+	BATT_USBOTG_500MA_CHARGE,
+	BATT_USBOTG_TRICKLE_CHARGE,
+};
+
+/* valid battery events */
+enum batt_event {
+	BATT_EVENT_BATOVP_EXCPT,
+	BATT_EVENT_USBOVP_EXCPT,
+	BATT_EVENT_TEMP_EXCPT,
+	BATT_EVENT_DCLMT_EXCPT,
+	BATT_EVENT_EXCPT
+};
+
+
+/*********************************************************************
+ *		Battery properties
+ *********************************************************************/
+
+/*
+ * pmic battery info
+ */
+struct pmic_power_module_info {
+	bool is_dev_info_updated;
+	struct device *dev;
+	/* pmic battery data */
+	unsigned long update_time;		/* jiffies when data read */
+	unsigned int usb_is_present;
+	unsigned int batt_is_present;
+	unsigned int batt_health;
+	unsigned int usb_health;
+	unsigned int batt_status;
+	unsigned int batt_charge_now;		/* in mAS */
+	unsigned int batt_prev_charge_full;	/* in mAS */
+	unsigned int batt_charge_rate;		/* in units per second */
+
+	struct power_supply usb;
+	struct power_supply batt;
+	int irq;				/* GPE_ID or IRQ# */
+	struct workqueue_struct *monitor_wqueue;
+	struct delayed_work monitor_battery;
+	struct work_struct handler;
+};
+
+static unsigned int delay_time = 2000;	/* in ms */
+
+/*
+ * pmic ac properties
+ */
+static enum power_supply_property pmic_usb_props[] = {
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_HEALTH,
+};
+
+/*
+ * pmic battery properties
+ */
+static enum power_supply_property pmic_battery_props[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_CHARGE_NOW,
+	POWER_SUPPLY_PROP_CHARGE_FULL,
+};
+
+
+/*
+ * Glue functions for talking to the IPC
+ */
+
+struct battery_property {
+	u32 capacity;	/* Charger capacity */
+	u8  crnt;	/* Quick charge current value*/
+	u8  volt;	/* Fine adjustment of constant charge voltage */
+	u8  prot;	/* CHRGPROT register value */
+	u8  prot2;	/* CHRGPROT1 register value */
+	u8  timer;	/* Charging timer */
+};
+
+#define IPCMSG_BATTERY		0xEF
+
+/* Battery coulomb counter accumulator commands */
+#define IPC_CMD_CC_WR		  0 /* Update coulomb counter value */
+#define IPC_CMD_CC_RD		  1 /* Read coulomb counter value */
+#define IPC_CMD_BATTERY_PROPERTY  2 /* Read Battery property */
+
+/**
+ *	pmic_scu_ipc_battery_cc_read	-	read battery cc
+ *	@value: battery coulomb counter read
+ *
+ *	Reads the battery couloumb counter value, returns 0 on success, or
+ *	an error code
+ *
+ *	This function may sleep. Locking for SCU accesses is handled for
+ *	the caller.
+ */
+static int pmic_scu_ipc_battery_cc_read(u32 *value)
+{
+	return intel_scu_ipc_command(IPCMSG_BATTERY, IPC_CMD_CC_RD,
+					NULL, 0, value, 1);
+}
+
+/**
+ *	pmic_scu_ipc_battery_property_get	-	fetch properties
+ *	@prop: battery properties
+ *
+ *	Retrieve the battery properties from the power management
+ *
+ *	This function may sleep. Locking for SCU accesses is handled for
+ *	the caller.
+ */
+static int pmic_scu_ipc_battery_property_get(struct battery_property *prop)
+{
+	u32 data[3];
+	u8 *p = (u8 *)&data[1];
+	int err = intel_scu_ipc_command(IPC_CMD_BATTERY_PROPERTY,
+				IPCMSG_BATTERY, NULL, 0, data, 3);
+
+	prop->capacity = data[0];
+	prop->crnt = *p++;
+	prop->volt = *p++;
+	prop->prot = *p++;
+	prop->prot2 = *p++;
+	prop->timer = *p++;
+
+	return err;
+}
+
+/**
+ *	pmic_scu_ipc_set_charger	-	set charger
+ *	@charger: charger to select
+ *
+ *	Switch the charging mode for the SCU
+ */
+
+static int pmic_scu_ipc_set_charger(int charger)
+{
+	return intel_scu_ipc_simple_command(charger, IPCMSG_BATTERY);
+}
+
+/**
+ * pmic_battery_log_event - log battery events
+ * @event: battery event to be logged
+ * Context: can sleep
+ *
+ * There are multiple battery events which may be of interest to users;
+ * this battery function logs the different battery events onto the
+ * kernel log messages.
+ */
+static void pmic_battery_log_event(enum batt_event event)
+{
+	printk(KERN_WARNING "pmic-battery: ");
+	switch (event) {
+	case BATT_EVENT_BATOVP_EXCPT:
+		printk(KERN_CONT "battery overvoltage condition\n");
+		break;
+	case BATT_EVENT_USBOVP_EXCPT:
+		printk(KERN_CONT "usb charger overvoltage condition\n");
+		break;
+	case BATT_EVENT_TEMP_EXCPT:
+		printk(KERN_CONT "high battery temperature condition\n");
+		break;
+	case BATT_EVENT_DCLMT_EXCPT:
+		printk(KERN_CONT "over battery charge current condition\n");
+		break;
+	default:
+		printk(KERN_CONT "charger/battery exception %d\n", event);
+		break;
+	}
+}
+
+/**
+ * pmic_battery_read_status - read battery status information
+ * @pbi: device info structure to update the read information
+ * Context: can sleep
+ *
+ * PMIC power source information need to be updated based on the data read
+ * from the PMIC battery registers.
+ *
+ */
+static void pmic_battery_read_status(struct pmic_power_module_info *pbi)
+{
+	unsigned int update_time_intrvl;
+	unsigned int chrg_val;
+	u32 ccval;
+	u8 r8;
+	struct battery_property batt_prop;
+	int batt_present = 0;
+	int usb_present = 0;
+	int batt_exception = 0;
+
+	/* make sure the last batt_status read happened delay_time before */
+	if (pbi->update_time && time_before(jiffies, pbi->update_time +
+						msecs_to_jiffies(delay_time)))
+		return;
+
+	update_time_intrvl = jiffies_to_msecs(jiffies -	pbi->update_time);
+	pbi->update_time = jiffies;
+
+	/* read coulomb counter registers and schrgint register */
+	if (pmic_scu_ipc_battery_cc_read(&ccval)) {
+		dev_warn(pbi->dev, "%s(): ipc config cmd failed\n",
+								__func__);
+		return;
+	}
+
+	if (intel_scu_ipc_ioread8(PMIC_BATT_CHR_SCHRGINT_ADDR, &r8)) {
+		dev_warn(pbi->dev, "%s(): ipc pmic read failed\n",
+								__func__);
+		return;
+	}
+
+	/*
+	 * set pmic_power_module_info members based on pmic register values
+	 * read.
+	 */
+
+	/* set batt_is_present */
+	if (r8 & PMIC_BATT_CHR_SBATDET_MASK) {
+		pbi->batt_is_present = PMIC_BATT_PRESENT;
+		batt_present = 1;
+	} else {
+		pbi->batt_is_present = PMIC_BATT_NOT_PRESENT;
+		pbi->batt_health = POWER_SUPPLY_HEALTH_UNKNOWN;
+		pbi->batt_status = POWER_SUPPLY_STATUS_UNKNOWN;
+	}
+
+	/* set batt_health */
+	if (batt_present) {
+		if (r8 & PMIC_BATT_CHR_SBATOVP_MASK) {
+			pbi->batt_health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+			pbi->batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+			pmic_battery_log_event(BATT_EVENT_BATOVP_EXCPT);
+			batt_exception = 1;
+		} else if (r8 & PMIC_BATT_CHR_SDCLMT_MASK) {
+			pbi->batt_health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+			pbi->batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+			pmic_battery_log_event(BATT_EVENT_DCLMT_EXCPT);
+			batt_exception = 1;
+		} else if (r8 & PMIC_BATT_CHR_STEMP_MASK) {
+			pbi->batt_health = POWER_SUPPLY_HEALTH_OVERHEAT;
+			pbi->batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+			pmic_battery_log_event(BATT_EVENT_TEMP_EXCPT);
+			batt_exception = 1;
+		} else {
+			pbi->batt_health = POWER_SUPPLY_HEALTH_GOOD;
+		}
+	}
+
+	/* set usb_is_present */
+	if (r8 & PMIC_BATT_CHR_SUSBDET_MASK) {
+		pbi->usb_is_present = PMIC_USB_PRESENT;
+		usb_present = 1;
+	} else {
+		pbi->usb_is_present = PMIC_USB_NOT_PRESENT;
+		pbi->usb_health = POWER_SUPPLY_HEALTH_UNKNOWN;
+	}
+
+	if (usb_present) {
+		if (r8 & PMIC_BATT_CHR_SUSBOVP_MASK) {
+			pbi->usb_health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+			pmic_battery_log_event(BATT_EVENT_USBOVP_EXCPT);
+		} else {
+			pbi->usb_health = POWER_SUPPLY_HEALTH_GOOD;
+		}
+	}
+
+	chrg_val = ccval & PMIC_BATT_ADC_ACCCHRGVAL_MASK;
+
+	/* set batt_prev_charge_full to battery capacity the first time */
+	if (!pbi->is_dev_info_updated) {
+		if (pmic_scu_ipc_battery_property_get(&batt_prop)) {
+			dev_warn(pbi->dev, "%s(): ipc config cmd failed\n",
+								__func__);
+			return;
+		}
+		pbi->batt_prev_charge_full = batt_prop.capacity;
+	}
+
+	/* set batt_status */
+	if (batt_present && !batt_exception) {
+		if (r8 & PMIC_BATT_CHR_SCOMP_MASK) {
+			pbi->batt_status = POWER_SUPPLY_STATUS_FULL;
+			pbi->batt_prev_charge_full = chrg_val;
+		} else if (ccval & PMIC_BATT_ADC_ACCCHRG_MASK) {
+			pbi->batt_status = POWER_SUPPLY_STATUS_DISCHARGING;
+		} else {
+			pbi->batt_status = POWER_SUPPLY_STATUS_CHARGING;
+		}
+	}
+
+	/* set batt_charge_rate */
+	if (pbi->is_dev_info_updated && batt_present && !batt_exception) {
+		if (pbi->batt_status == POWER_SUPPLY_STATUS_DISCHARGING) {
+			if (pbi->batt_charge_now - chrg_val) {
+				pbi->batt_charge_rate = ((pbi->batt_charge_now -
+					chrg_val) * 1000 * 60) /
+					update_time_intrvl;
+			}
+		} else if (pbi->batt_status == POWER_SUPPLY_STATUS_CHARGING) {
+			if (chrg_val - pbi->batt_charge_now) {
+				pbi->batt_charge_rate = ((chrg_val -
+					pbi->batt_charge_now) * 1000 * 60) /
+					update_time_intrvl;
+			}
+		} else
+			pbi->batt_charge_rate = 0;
+	} else {
+		pbi->batt_charge_rate = -1;
+	}
+
+	/* batt_charge_now */
+	if (batt_present && !batt_exception)
+		pbi->batt_charge_now = chrg_val;
+	else
+		pbi->batt_charge_now = -1;
+
+	pbi->is_dev_info_updated = PMIC_BATT_DRV_INFO_UPDATED;
+}
+
+/**
+ * pmic_usb_get_property - usb power source get property
+ * @psy: usb power supply context
+ * @psp: usb power source property
+ * @val: usb power source property value
+ * Context: can sleep
+ *
+ * PMIC usb power source property needs to be provided to power_supply
+ * subsytem for it to provide the information to users.
+ */
+static int pmic_usb_get_property(struct power_supply *psy,
+				enum power_supply_property psp,
+				union power_supply_propval *val)
+{
+	struct pmic_power_module_info *pbi = container_of(psy,
+				struct pmic_power_module_info, usb);
+
+	/* update pmic_power_module_info members */
+	pmic_battery_read_status(pbi);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = pbi->usb_is_present;
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		val->intval = pbi->usb_health;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static inline unsigned long mAStouAh(unsigned long v)
+{
+	/* seconds to hours, mA to µA */
+	return (v * 1000) / 3600;
+}
+
+/**
+ * pmic_battery_get_property - battery power source get property
+ * @psy: battery power supply context
+ * @psp: battery power source property
+ * @val: battery power source property value
+ * Context: can sleep
+ *
+ * PMIC battery power source property needs to be provided to power_supply
+ * subsytem for it to provide the information to users.
+ */
+static int pmic_battery_get_property(struct power_supply *psy,
+				enum power_supply_property psp,
+				union power_supply_propval *val)
+{
+	struct pmic_power_module_info *pbi = container_of(psy,
+				struct pmic_power_module_info, batt);
+
+	/* update pmic_power_module_info members */
+	pmic_battery_read_status(pbi);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = pbi->batt_status;
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		val->intval = pbi->batt_health;
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = pbi->batt_is_present;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_NOW:
+		val->intval = mAStouAh(pbi->batt_charge_now);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_FULL:
+		val->intval = mAStouAh(pbi->batt_prev_charge_full);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * pmic_battery_monitor - monitor battery status
+ * @work: work structure
+ * Context: can sleep
+ *
+ * PMIC battery status needs to be monitored for any change
+ * and information needs to be frequently updated.
+ */
+static void pmic_battery_monitor(struct work_struct *work)
+{
+	struct pmic_power_module_info *pbi = container_of(work,
+			struct pmic_power_module_info, monitor_battery.work);
+
+	/* update pmic_power_module_info members */
+	pmic_battery_read_status(pbi);
+	queue_delayed_work(pbi->monitor_wqueue, &pbi->monitor_battery, HZ * 10);
+}
+
+/**
+ * pmic_battery_set_charger - set battery charger
+ * @pbi: device info structure
+ * @chrg: charge mode to set battery charger in
+ * Context: can sleep
+ *
+ * PMIC battery charger needs to be enabled based on the usb charge
+ * capabilities connected to the platform.
+ */
+static int pmic_battery_set_charger(struct pmic_power_module_info *pbi,
+						enum batt_charge_type chrg)
+{
+	int retval;
+
+	/* set usblmt bits and chrgcntl register bits appropriately */
+	switch (chrg) {
+	case BATT_USBOTG_500MA_CHARGE:
+		retval = pmic_scu_ipc_set_charger(PMIC_BATT_CHR_IPC_FCHRG_SUBID);
+		break;
+	case BATT_USBOTG_TRICKLE_CHARGE:
+		retval = pmic_scu_ipc_set_charger(PMIC_BATT_CHR_IPC_TCHRG_SUBID);
+		break;
+	default:
+		dev_warn(pbi->dev, "%s(): out of range usb charger "
+						"charge detected\n", __func__);
+		return -EINVAL;
+	}
+
+	if (retval) {
+		dev_warn(pbi->dev, "%s(): ipc pmic read failed\n",
+								__func__);
+		return retval;;
+	}
+
+	return 0;
+}
+
+/**
+ * pmic_battery_interrupt_handler - pmic battery interrupt handler
+ * Context: interrupt context
+ *
+ * PMIC battery interrupt handler which will be called with either
+ * battery full condition occurs or usb otg & battery connect
+ * condition occurs.
+ */
+static irqreturn_t pmic_battery_interrupt_handler(int id, void *dev)
+{
+	struct pmic_power_module_info *pbi = dev;
+
+	schedule_work(&pbi->handler);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * pmic_battery_handle_intrpt - pmic battery service interrupt
+ * @work: work structure
+ * Context: can sleep
+ *
+ * PMIC battery needs to either update the battery status as full
+ * if it detects battery full condition caused the interrupt or needs
+ * to enable battery charger if it detects usb and battery detect
+ * caused the source of interrupt.
+ */
+static void pmic_battery_handle_intrpt(struct work_struct *work)
+{
+	struct pmic_power_module_info *pbi = container_of(work,
+				struct pmic_power_module_info, handler);
+	enum batt_charge_type chrg;
+	u8 r8;
+
+	if (intel_scu_ipc_ioread8(PMIC_BATT_CHR_SCHRGINT_ADDR, &r8)) {
+		dev_warn(pbi->dev, "%s(): ipc pmic read failed\n",
+								__func__);
+		return;
+	}
+	/* find the cause of the interrupt */
+	if (r8 & PMIC_BATT_CHR_SBATDET_MASK) {
+		pbi->batt_is_present = PMIC_BATT_PRESENT;
+	} else {
+		pbi->batt_is_present = PMIC_BATT_NOT_PRESENT;
+		pbi->batt_health = POWER_SUPPLY_HEALTH_UNKNOWN;
+		pbi->batt_status = POWER_SUPPLY_STATUS_UNKNOWN;
+		return;
+	}
+
+	if (r8 & PMIC_BATT_CHR_EXCPT_MASK) {
+		pbi->batt_health = POWER_SUPPLY_HEALTH_UNKNOWN;
+		pbi->batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+		pbi->usb_health = POWER_SUPPLY_HEALTH_UNKNOWN;
+		pmic_battery_log_event(BATT_EVENT_EXCPT);
+		return;
+	} else {
+		pbi->batt_health = POWER_SUPPLY_HEALTH_GOOD;
+		pbi->usb_health = POWER_SUPPLY_HEALTH_GOOD;
+	}
+
+	if (r8 & PMIC_BATT_CHR_SCOMP_MASK) {
+		u32 ccval;
+		pbi->batt_status = POWER_SUPPLY_STATUS_FULL;
+
+		if (pmic_scu_ipc_battery_cc_read(&ccval)) {
+			dev_warn(pbi->dev, "%s(): ipc config cmd "
+							"failed\n", __func__);
+			return;
+		}
+		pbi->batt_prev_charge_full = ccval &
+						PMIC_BATT_ADC_ACCCHRGVAL_MASK;
+		return;
+	}
+
+	if (r8 & PMIC_BATT_CHR_SUSBDET_MASK) {
+		pbi->usb_is_present = PMIC_USB_PRESENT;
+	} else {
+		pbi->usb_is_present = PMIC_USB_NOT_PRESENT;
+		pbi->usb_health = POWER_SUPPLY_HEALTH_UNKNOWN;
+		return;
+	}
+
+	/* setup battery charging */
+
+#if 0
+	/* check usb otg power capability and set charger accordingly */
+	retval = langwell_udc_maxpower(&power);
+	if (retval) {
+		dev_warn(pbi->dev,
+		    "%s(): usb otg power query failed with error code %d\n",
+			__func__, retval);
+		return;
+	}
+
+	if (power >= 500)
+		chrg = BATT_USBOTG_500MA_CHARGE;
+	else
+#endif
+		chrg = BATT_USBOTG_TRICKLE_CHARGE;
+
+	/* enable battery charging */
+	if (pmic_battery_set_charger(pbi, chrg)) {
+		dev_warn(pbi->dev,
+			"%s(): failed to set up battery charging\n", __func__);
+		return;
+	}
+
+	dev_dbg(pbi->dev,
+		"pmic-battery: %s() - setting up battery charger successful\n",
+			__func__);
+}
+
+/**
+ * pmic_battery_probe - pmic battery initialize
+ * @irq: pmic battery device irq
+ * @dev: pmic battery device structure
+ * Context: can sleep
+ *
+ * PMIC battery initializes its internal data structue and other
+ * infrastructure components for it to work as expected.
+ */
+static __devinit int probe(int irq, struct device *dev)
+{
+	int retval = 0;
+	struct pmic_power_module_info *pbi;
+
+	dev_dbg(dev, "pmic-battery: found pmic battery device\n");
+
+	pbi = kzalloc(sizeof(*pbi), GFP_KERNEL);
+	if (!pbi) {
+		dev_err(dev, "%s(): memory allocation failed\n",
+								__func__);
+		return -ENOMEM;
+	}
+
+	pbi->dev = dev;
+	pbi->irq = irq;
+	dev_set_drvdata(dev, pbi);
+
+	/* initialize all required framework before enabling interrupts */
+	INIT_WORK(&pbi->handler, pmic_battery_handle_intrpt);
+	INIT_DELAYED_WORK(&pbi->monitor_battery, pmic_battery_monitor);
+	pbi->monitor_wqueue =
+			create_singlethread_workqueue(dev_name(dev));
+	if (!pbi->monitor_wqueue) {
+		dev_err(dev, "%s(): wqueue init failed\n", __func__);
+		retval = -ESRCH;
+		goto wqueue_failed;
+	}
+
+	/* register interrupt */
+	retval = request_irq(pbi->irq, pmic_battery_interrupt_handler,
+							0, DRIVER_NAME, pbi);
+	if (retval) {
+		dev_err(dev, "%s(): cannot get IRQ\n", __func__);
+		goto requestirq_failed;
+	}
+
+	/* register pmic-batt with power supply subsystem */
+	pbi->batt.name = "pmic-batt";
+	pbi->batt.type = POWER_SUPPLY_TYPE_BATTERY;
+	pbi->batt.properties = pmic_battery_props;
+	pbi->batt.num_properties = ARRAY_SIZE(pmic_battery_props);
+	pbi->batt.get_property = pmic_battery_get_property;
+	retval = power_supply_register(dev, &pbi->batt);
+	if (retval) {
+		dev_err(dev,
+			"%s(): failed to register pmic battery device with power supply subsystem\n",
+				__func__);
+		goto power_reg_failed;
+	}
+
+	dev_dbg(dev, "pmic-battery: %s() - pmic battery device "
+		"registration with power supply subsystem successful\n",
+		__func__);
+
+	queue_delayed_work(pbi->monitor_wqueue, &pbi->monitor_battery, HZ * 1);
+
+	/* register pmic-usb with power supply subsystem */
+	pbi->usb.name = "pmic-usb";
+	pbi->usb.type = POWER_SUPPLY_TYPE_USB;
+	pbi->usb.properties = pmic_usb_props;
+	pbi->usb.num_properties = ARRAY_SIZE(pmic_usb_props);
+	pbi->usb.get_property = pmic_usb_get_property;
+	retval = power_supply_register(dev, &pbi->usb);
+	if (retval) {
+		dev_err(dev,
+			"%s(): failed to register pmic usb device with power supply subsystem\n",
+				__func__);
+		goto power_reg_failed_1;
+	}
+
+	if (debug)
+		printk(KERN_INFO "pmic-battery: %s() - pmic usb device "
+			"registration with power supply subsystem successful\n",
+			__func__);
+
+	return retval;
+
+power_reg_failed_1:
+	power_supply_unregister(&pbi->batt);
+power_reg_failed:
+	cancel_rearming_delayed_workqueue(pbi->monitor_wqueue,
+						&pbi->monitor_battery);
+requestirq_failed:
+	destroy_workqueue(pbi->monitor_wqueue);
+wqueue_failed:
+	kfree(pbi);
+
+	return retval;
+}
+
+static int __devinit platform_pmic_battery_probe(struct platform_device *pdev)
+{
+	return probe(pdev->id, &pdev->dev);
+}
+
+/**
+ * pmic_battery_remove - pmic battery finalize
+ * @dev: pmic battery device structure
+ * Context: can sleep
+ *
+ * PMIC battery finalizes its internal data structue and other
+ * infrastructure components that it initialized in
+ * pmic_battery_probe.
+ */
+
+static int __devexit platform_pmic_battery_remove(struct platform_device *pdev)
+{
+	struct pmic_power_module_info *pbi = dev_get_drvdata(&pdev->dev);
+
+	free_irq(pbi->irq, pbi);
+	cancel_rearming_delayed_workqueue(pbi->monitor_wqueue,
+					&pbi->monitor_battery);
+	destroy_workqueue(pbi->monitor_wqueue);
+
+	power_supply_unregister(&pbi->usb);
+	power_supply_unregister(&pbi->batt);
+
+	flush_scheduled_work();
+	kfree(pbi);
+	return 0;
+}
+
+static struct platform_driver platform_pmic_battery_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+	},
+	.probe = platform_pmic_battery_probe,
+	.remove = __devexit_p(platform_pmic_battery_remove),
+};
+
+static int __init platform_pmic_battery_module_init(void)
+{
+	return platform_driver_register(&platform_pmic_battery_driver);
+}
+
+static void __exit platform_pmic_battery_module_exit(void)
+{
+	platform_driver_unregister(&platform_pmic_battery_driver);
+}
+
+module_init(platform_pmic_battery_module_init);
+module_exit(platform_pmic_battery_module_exit);
+
+MODULE_AUTHOR("Nithish Mahalingam <nithish.mahalingam@intel.com>");
+MODULE_DESCRIPTION("Intel Moorestown PMIC Battery Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c
index 5ab9109..aafc1c5 100644
--- a/drivers/power/olpc_battery.c
+++ b/drivers/power/olpc_battery.c
@@ -1,7 +1,7 @@
 /*
  * Battery driver for One Laptop Per Child board.
  *
- *	Copyright © 2006  David Woodhouse <dwmw2@infradead.org>
+ *	Copyright © 2006-2010  David Woodhouse <dwmw2@infradead.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/drivers/power/s3c_adc_battery.c b/drivers/power/s3c_adc_battery.c
new file mode 100644
index 0000000..fe16b48
--- /dev/null
+++ b/drivers/power/s3c_adc_battery.c
@@ -0,0 +1,431 @@
+/*
+ *	iPAQ h1930/h1940/rx1950 battery controler driver
+ *	Copyright (c) Vasily Khoruzhick
+ *	Based on h1940_battery.c by Arnaud Patard
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ */
+
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include <linux/err.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/s3c_adc_battery.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <plat/adc.h>
+
+#define BAT_POLL_INTERVAL		10000 /* ms */
+#define JITTER_DELAY			500 /* ms */
+
+struct s3c_adc_bat {
+	struct power_supply		psy;
+	struct s3c_adc_client		*client;
+	struct s3c_adc_bat_pdata	*pdata;
+	int				volt_value;
+	int				cur_value;
+	unsigned int			timestamp;
+	int				level;
+	int				status;
+	int				cable_plugged:1;
+};
+
+static struct delayed_work bat_work;
+
+static void s3c_adc_bat_ext_power_changed(struct power_supply *psy)
+{
+	schedule_delayed_work(&bat_work,
+		msecs_to_jiffies(JITTER_DELAY));
+}
+
+static enum power_supply_property s3c_adc_backup_bat_props[] = {
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_VOLTAGE_MIN,
+	POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+};
+
+static int s3c_adc_backup_bat_get_property(struct power_supply *psy,
+				enum power_supply_property psp,
+				union power_supply_propval *val)
+{
+	struct s3c_adc_bat *bat = container_of(psy, struct s3c_adc_bat, psy);
+
+	if (!bat) {
+		dev_err(psy->dev, "%s: no battery infos ?!\n", __func__);
+		return -EINVAL;
+	}
+
+	if (bat->volt_value < 0 ||
+		jiffies_to_msecs(jiffies - bat->timestamp) >
+			BAT_POLL_INTERVAL) {
+		bat->volt_value = s3c_adc_read(bat->client,
+			bat->pdata->backup_volt_channel);
+		bat->volt_value *= bat->pdata->backup_volt_mult;
+		bat->timestamp = jiffies;
+	}
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		val->intval = bat->volt_value;
+		return 0;
+	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
+		val->intval = bat->pdata->backup_volt_min;
+		return 0;
+	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+		val->intval = bat->pdata->backup_volt_max;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static struct s3c_adc_bat backup_bat = {
+	.psy = {
+		.name		= "backup-battery",
+		.type		= POWER_SUPPLY_TYPE_BATTERY,
+		.properties	= s3c_adc_backup_bat_props,
+		.num_properties = ARRAY_SIZE(s3c_adc_backup_bat_props),
+		.get_property	= s3c_adc_backup_bat_get_property,
+		.use_for_apm	= 1,
+	},
+};
+
+static enum power_supply_property s3c_adc_main_bat_props[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+	POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN,
+	POWER_SUPPLY_PROP_CHARGE_NOW,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+};
+
+static int calc_full_volt(int volt_val, int cur_val, int impedance)
+{
+	return volt_val + cur_val * impedance / 1000;
+}
+
+static int s3c_adc_bat_get_property(struct power_supply *psy,
+				    enum power_supply_property psp,
+				    union power_supply_propval *val)
+{
+	struct s3c_adc_bat *bat = container_of(psy, struct s3c_adc_bat, psy);
+
+	int new_level;
+	int full_volt;
+	const struct s3c_adc_bat_thresh *lut = bat->pdata->lut_noac;
+	unsigned int lut_size = bat->pdata->lut_noac_cnt;
+
+	if (!bat) {
+		dev_err(psy->dev, "no battery infos ?!\n");
+		return -EINVAL;
+	}
+
+	if (bat->volt_value < 0 || bat->cur_value < 0 ||
+		jiffies_to_msecs(jiffies - bat->timestamp) >
+			BAT_POLL_INTERVAL) {
+		bat->volt_value = s3c_adc_read(bat->client,
+			bat->pdata->volt_channel) * bat->pdata->volt_mult;
+		bat->cur_value = s3c_adc_read(bat->client,
+			bat->pdata->current_channel) * bat->pdata->current_mult;
+		bat->timestamp = jiffies;
+	}
+
+	if (bat->cable_plugged &&
+		((bat->pdata->gpio_charge_finished < 0) ||
+		!gpio_get_value(bat->pdata->gpio_charge_finished))) {
+		lut = bat->pdata->lut_acin;
+		lut_size = bat->pdata->lut_acin_cnt;
+	}
+
+	new_level = 100000;
+	full_volt = calc_full_volt((bat->volt_value / 1000),
+		(bat->cur_value / 1000), bat->pdata->internal_impedance);
+
+	if (full_volt < calc_full_volt(lut->volt, lut->cur,
+		bat->pdata->internal_impedance)) {
+		lut_size--;
+		while (lut_size--) {
+			int lut_volt1;
+			int lut_volt2;
+
+			lut_volt1 = calc_full_volt(lut[0].volt, lut[0].cur,
+				bat->pdata->internal_impedance);
+			lut_volt2 = calc_full_volt(lut[1].volt, lut[1].cur,
+				bat->pdata->internal_impedance);
+			if (full_volt < lut_volt1 && full_volt >= lut_volt2) {
+				new_level = (lut[1].level +
+					(lut[0].level - lut[1].level) *
+					(full_volt - lut_volt2) /
+					(lut_volt1 - lut_volt2)) * 1000;
+				break;
+			}
+			new_level = lut[1].level * 1000;
+			lut++;
+		}
+	}
+
+	bat->level = new_level;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		if (bat->pdata->gpio_charge_finished < 0)
+			val->intval = bat->level == 100000 ?
+				POWER_SUPPLY_STATUS_FULL : bat->status;
+		else
+			val->intval = bat->status;
+		return 0;
+	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+		val->intval = 100000;
+		return 0;
+	case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN:
+		val->intval = 0;
+		return 0;
+	case POWER_SUPPLY_PROP_CHARGE_NOW:
+		val->intval = bat->level;
+		return 0;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		val->intval = bat->volt_value;
+		return 0;
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		val->intval = bat->cur_value;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static struct s3c_adc_bat main_bat = {
+	.psy = {
+		.name			= "main-battery",
+		.type			= POWER_SUPPLY_TYPE_BATTERY,
+		.properties		= s3c_adc_main_bat_props,
+		.num_properties		= ARRAY_SIZE(s3c_adc_main_bat_props),
+		.get_property		= s3c_adc_bat_get_property,
+		.external_power_changed = s3c_adc_bat_ext_power_changed,
+		.use_for_apm		= 1,
+	},
+};
+
+static void s3c_adc_bat_work(struct work_struct *work)
+{
+	struct s3c_adc_bat *bat = &main_bat;
+	int is_charged;
+	int is_plugged;
+	static int was_plugged;
+
+	is_plugged = power_supply_am_i_supplied(&bat->psy);
+	bat->cable_plugged = is_plugged;
+	if (is_plugged != was_plugged) {
+		was_plugged = is_plugged;
+		if (is_plugged) {
+			if (bat->pdata->enable_charger)
+				bat->pdata->enable_charger();
+			bat->status = POWER_SUPPLY_STATUS_CHARGING;
+		} else {
+			if (bat->pdata->disable_charger)
+				bat->pdata->disable_charger();
+			bat->status = POWER_SUPPLY_STATUS_DISCHARGING;
+		}
+	} else {
+		if ((bat->pdata->gpio_charge_finished >= 0) && is_plugged) {
+			is_charged = gpio_get_value(
+				main_bat.pdata->gpio_charge_finished);
+			if (is_charged) {
+				if (bat->pdata->disable_charger)
+					bat->pdata->disable_charger();
+				bat->status = POWER_SUPPLY_STATUS_FULL;
+			} else {
+				if (bat->pdata->enable_charger)
+					bat->pdata->enable_charger();
+				bat->status = POWER_SUPPLY_STATUS_CHARGING;
+			}
+		}
+	}
+
+	power_supply_changed(&bat->psy);
+}
+
+static irqreturn_t s3c_adc_bat_charged(int irq, void *dev_id)
+{
+	schedule_delayed_work(&bat_work,
+		msecs_to_jiffies(JITTER_DELAY));
+	return IRQ_HANDLED;
+}
+
+static int __init s3c_adc_bat_probe(struct platform_device *pdev)
+{
+	struct s3c_adc_client	*client;
+	struct s3c_adc_bat_pdata *pdata = pdev->dev.platform_data;
+	int ret;
+
+	client = s3c_adc_register(pdev, NULL, NULL, 0);
+	if (IS_ERR(client)) {
+		dev_err(&pdev->dev, "cannot register adc\n");
+		return PTR_ERR(client);
+	}
+
+	platform_set_drvdata(pdev, client);
+
+	main_bat.client = client;
+	main_bat.pdata = pdata;
+	main_bat.volt_value = -1;
+	main_bat.cur_value = -1;
+	main_bat.cable_plugged = 0;
+	main_bat.status = POWER_SUPPLY_STATUS_DISCHARGING;
+
+	ret = power_supply_register(&pdev->dev, &main_bat.psy);
+	if (ret)
+		goto err_reg_main;
+	if (pdata->backup_volt_mult) {
+		backup_bat.client = client;
+		backup_bat.pdata = pdev->dev.platform_data;
+		backup_bat.volt_value = -1;
+		ret = power_supply_register(&pdev->dev, &backup_bat.psy);
+		if (ret)
+			goto err_reg_backup;
+	}
+
+	INIT_DELAYED_WORK(&bat_work, s3c_adc_bat_work);
+
+	if (pdata->gpio_charge_finished >= 0) {
+		ret = gpio_request(pdata->gpio_charge_finished, "charged");
+		if (ret)
+			goto err_gpio;
+
+		ret = request_irq(gpio_to_irq(pdata->gpio_charge_finished),
+				s3c_adc_bat_charged,
+				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+				"battery charged", NULL);
+		if (ret)
+			goto err_irq;
+	}
+
+	if (pdata->init) {
+		ret = pdata->init();
+		if (ret)
+			goto err_platform;
+	}
+
+	dev_info(&pdev->dev, "successfully loaded\n");
+	device_init_wakeup(&pdev->dev, 1);
+
+	/* Schedule timer to check current status */
+	schedule_delayed_work(&bat_work,
+		msecs_to_jiffies(JITTER_DELAY));
+
+	return 0;
+
+err_platform:
+	if (pdata->gpio_charge_finished >= 0)
+		free_irq(gpio_to_irq(pdata->gpio_charge_finished), NULL);
+err_irq:
+	if (pdata->gpio_charge_finished >= 0)
+		gpio_free(pdata->gpio_charge_finished);
+err_gpio:
+	if (pdata->backup_volt_mult)
+		power_supply_unregister(&backup_bat.psy);
+err_reg_backup:
+	power_supply_unregister(&main_bat.psy);
+err_reg_main:
+	return ret;
+}
+
+static int s3c_adc_bat_remove(struct platform_device *pdev)
+{
+	struct s3c_adc_client *client = platform_get_drvdata(pdev);
+	struct s3c_adc_bat_pdata *pdata = pdev->dev.platform_data;
+
+	power_supply_unregister(&main_bat.psy);
+	if (pdata->backup_volt_mult)
+		power_supply_unregister(&backup_bat.psy);
+
+	s3c_adc_release(client);
+
+	if (pdata->gpio_charge_finished >= 0) {
+		free_irq(gpio_to_irq(pdata->gpio_charge_finished), NULL);
+		gpio_free(pdata->gpio_charge_finished);
+	}
+
+	cancel_delayed_work(&bat_work);
+
+	if (pdata->exit)
+		pdata->exit();
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int s3c_adc_bat_suspend(struct platform_device *pdev,
+	pm_message_t state)
+{
+	struct s3c_adc_bat_pdata *pdata = pdev->dev.platform_data;
+
+	if (pdata->gpio_charge_finished >= 0) {
+		if (device_may_wakeup(&pdev->dev))
+			enable_irq_wake(
+				gpio_to_irq(pdata->gpio_charge_finished));
+		else {
+			disable_irq(gpio_to_irq(pdata->gpio_charge_finished));
+			main_bat.pdata->disable_charger();
+		}
+	}
+
+	return 0;
+}
+
+static int s3c_adc_bat_resume(struct platform_device *pdev)
+{
+	struct s3c_adc_bat_pdata *pdata = pdev->dev.platform_data;
+
+	if (pdata->gpio_charge_finished >= 0) {
+		if (device_may_wakeup(&pdev->dev))
+			disable_irq_wake(
+				gpio_to_irq(pdata->gpio_charge_finished));
+		else
+			enable_irq(gpio_to_irq(pdata->gpio_charge_finished));
+	}
+
+	/* Schedule timer to check current status */
+	schedule_delayed_work(&bat_work,
+		msecs_to_jiffies(JITTER_DELAY));
+
+	return 0;
+}
+#else
+#define s3c_adc_battery_suspend NULL
+#define s3c_adc_battery_resume NULL
+#endif
+
+static struct platform_driver s3c_adc_bat_driver = {
+	.driver		= {
+		.name	= "s3c-adc-battery",
+	},
+	.probe		= s3c_adc_bat_probe,
+	.remove		= s3c_adc_bat_remove,
+	.suspend	= s3c_adc_bat_suspend,
+	.resume		= s3c_adc_bat_resume,
+};
+
+static int __init s3c_adc_bat_init(void)
+{
+	return platform_driver_register(&s3c_adc_bat_driver);
+}
+module_init(s3c_adc_bat_init);
+
+static void __exit s3c_adc_bat_exit(void)
+{
+	platform_driver_unregister(&s3c_adc_bat_driver);
+}
+module_exit(s3c_adc_bat_exit);
+
+MODULE_AUTHOR("Vasily Khoruzhick <anarsoul@gmail.com>");
+MODULE_DESCRIPTION("iPAQ H1930/H1940/RX1950 battery controler driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 04f2e08..172951b 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -100,6 +100,14 @@
 	help
 	  Say y here to support the voltage regulaltor of Maxim MAX8925 PMIC.
 
+config REGULATOR_MAX8998
+	tristate "Maxim 8998 voltage regulator"
+	depends on MFD_MAX8998
+	help
+	  This driver controls a Maxim 8998 voltage output regulator
+	  via I2C bus. The provided regulator is suitable for S3C6410
+	  and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages.
+
 config REGULATOR_TWL4030
 	bool "TI TWL4030/TWL5030/TWL6030/TPS695x0 PMIC"
 	depends on TWL4030_CORE
@@ -201,5 +209,31 @@
 	help
 	  This driver supports 88PM8607 voltage regulator chips.
 
+config REGULATOR_ISL6271A
+	tristate "Intersil ISL6271A Power regulator"
+	depends on I2C
+	help
+	  This driver supports ISL6271A voltage regulator chip.
+
+config REGULATOR_AD5398
+	tristate "Analog Devices AD5398/AD5821 regulators"
+	depends on I2C
+	help
+	  This driver supports AD5398 and AD5821 current regulator chips.
+	  If building into module, its name is ad5398.ko.
+
+config REGULATOR_AB8500
+	bool "ST-Ericsson AB8500 Power Regulators"
+	depends on AB8500_CORE
+	help
+	  This driver supports the regulators found on the ST-Ericsson mixed
+	  signal AB8500 PMIC
+
+config REGULATOR_TPS6586X
+	tristate "TI TPS6586X Power regulators"
+	depends on MFD_TPS6586X
+	help
+	  This driver supports TPS6586X voltage regulator chips.
+
 endif
 
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 4e7feec..8285fd8 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -8,6 +8,7 @@
 obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
 obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
 
+obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o
 obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
 obj-$(CONFIG_REGULATOR_DUMMY) += dummy.o
 obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
@@ -16,12 +17,14 @@
 obj-$(CONFIG_REGULATOR_MAX8649)	+= max8649.o
 obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
 obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o
+obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
 obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
 obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
 obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o
 obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
 obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
 obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o
+obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o
 obj-$(CONFIG_REGULATOR_DA903X)	+= da903x.o
 obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
 obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
@@ -31,5 +34,7 @@
 obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
 obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
 obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
+obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
+obj-$(CONFIG_REGULATOR_AB8500)	+= ab8500.o
 
 ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c
new file mode 100644
index 0000000..dc3f1a4
--- /dev/null
+++ b/drivers/regulator/ab8500.c
@@ -0,0 +1,427 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ *
+ * AB8500 peripheral regulators
+ *
+ * AB8500 supports the following regulators,
+ * LDOs - VAUDIO, VANAMIC2/2, VDIGMIC, VINTCORE12, VTVOUT,
+ *        VAUX1/2/3, VANA
+ *
+ * for DB8500 cut 1.0 and previous versions of the silicon, all accesses
+ * to registers are through the DB8500 SPI. In cut 1.1 onwards, these
+ * accesses are through the DB8500 PRCMU I2C
+ *
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/ab8500.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/ab8500.h>
+
+/**
+ * struct ab8500_regulator_info - ab8500 regulator information
+ * @desc: regulator description
+ * @ab8500: ab8500 parent
+ * @regulator_dev: regulator device
+ * @max_uV: maximum voltage (for variable voltage supplies)
+ * @min_uV: minimum voltage (for variable voltage supplies)
+ * @fixed_uV: typical voltage (for fixed voltage supplies)
+ * @update_reg: register to control on/off
+ * @mask: mask to enable/disable regulator
+ * @enable: bits to enable the regulator in normal(high power) mode
+ * @voltage_reg: register to control regulator voltage
+ * @voltage_mask: mask to control regulator voltage
+ * @supported_voltages: supported voltage table
+ * @voltages_len: number of supported voltages for the regulator
+ */
+struct ab8500_regulator_info {
+	struct device		*dev;
+	struct regulator_desc	desc;
+	struct ab8500		*ab8500;
+	struct regulator_dev	*regulator;
+	int max_uV;
+	int min_uV;
+	int fixed_uV;
+	int update_reg;
+	int mask;
+	int enable;
+	int voltage_reg;
+	int voltage_mask;
+	int const *supported_voltages;
+	int voltages_len;
+};
+
+/* voltage tables for the vauxn/vintcore supplies */
+static const int ldo_vauxn_voltages[] = {
+	1100000,
+	1200000,
+	1300000,
+	1400000,
+	1500000,
+	1800000,
+	1850000,
+	1900000,
+	2500000,
+	2650000,
+	2700000,
+	2750000,
+	2800000,
+	2900000,
+	3000000,
+	3300000,
+};
+
+static const int ldo_vintcore_voltages[] = {
+	1200000,
+	1225000,
+	1250000,
+	1275000,
+	1300000,
+	1325000,
+	1350000,
+};
+
+static int ab8500_regulator_enable(struct regulator_dev *rdev)
+{
+	int regulator_id, ret;
+	struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+	regulator_id = rdev_get_id(rdev);
+	if (regulator_id >= AB8500_NUM_REGULATORS)
+		return -EINVAL;
+
+	ret = ab8500_set_bits(info->ab8500, info->update_reg,
+			info->mask, info->enable);
+	if (ret < 0)
+		dev_err(rdev_get_dev(rdev),
+			"couldn't set enable bits for regulator\n");
+	return ret;
+}
+
+static int ab8500_regulator_disable(struct regulator_dev *rdev)
+{
+	int regulator_id, ret;
+	struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+	regulator_id = rdev_get_id(rdev);
+	if (regulator_id >= AB8500_NUM_REGULATORS)
+		return -EINVAL;
+
+	ret = ab8500_set_bits(info->ab8500, info->update_reg,
+			info->mask, 0x0);
+	if (ret < 0)
+		dev_err(rdev_get_dev(rdev),
+			"couldn't set disable bits for regulator\n");
+	return ret;
+}
+
+static int ab8500_regulator_is_enabled(struct regulator_dev *rdev)
+{
+	int regulator_id, ret;
+	struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+	regulator_id = rdev_get_id(rdev);
+	if (regulator_id >= AB8500_NUM_REGULATORS)
+		return -EINVAL;
+
+	ret = ab8500_read(info->ab8500, info->update_reg);
+	if (ret < 0) {
+		dev_err(rdev_get_dev(rdev),
+			"couldn't read 0x%x register\n", info->update_reg);
+		return ret;
+	}
+
+	if (ret & info->mask)
+		return true;
+	else
+		return false;
+}
+
+static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector)
+{
+	int regulator_id;
+	struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+	regulator_id = rdev_get_id(rdev);
+	if (regulator_id >= AB8500_NUM_REGULATORS)
+		return -EINVAL;
+
+	/* return the uV for the fixed regulators */
+	if (info->fixed_uV)
+		return info->fixed_uV;
+
+	if (selector > info->voltages_len)
+		return -EINVAL;
+
+	return info->supported_voltages[selector];
+}
+
+static int ab8500_regulator_get_voltage(struct regulator_dev *rdev)
+{
+	int regulator_id, ret, val;
+	struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+	regulator_id = rdev_get_id(rdev);
+	if (regulator_id >= AB8500_NUM_REGULATORS)
+		return -EINVAL;
+
+	ret = ab8500_read(info->ab8500, info->voltage_reg);
+	if (ret < 0) {
+		dev_err(rdev_get_dev(rdev),
+			"couldn't read voltage reg for regulator\n");
+		return ret;
+	}
+
+	/* vintcore has a different layout */
+	val = ret & info->voltage_mask;
+	if (regulator_id == AB8500_LDO_INTCORE)
+		ret = info->supported_voltages[val >> 0x3];
+	else
+		ret = info->supported_voltages[val];
+
+	return ret;
+}
+
+static int ab8500_get_best_voltage_index(struct regulator_dev *rdev,
+		int min_uV, int max_uV)
+{
+	struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+	int i;
+
+	/* check the supported voltage */
+	for (i = 0; i < info->voltages_len; i++) {
+		if ((info->supported_voltages[i] >= min_uV) &&
+		    (info->supported_voltages[i] <= max_uV))
+			return i;
+	}
+
+	return -EINVAL;
+}
+
+static int ab8500_regulator_set_voltage(struct regulator_dev *rdev,
+		int min_uV, int max_uV)
+{
+	int regulator_id, ret;
+	struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+	regulator_id = rdev_get_id(rdev);
+	if (regulator_id >= AB8500_NUM_REGULATORS)
+		return -EINVAL;
+
+	/* get the appropriate voltages within the range */
+	ret = ab8500_get_best_voltage_index(rdev, min_uV, max_uV);
+	if (ret < 0) {
+		dev_err(rdev_get_dev(rdev),
+				"couldn't get best voltage for regulator\n");
+		return ret;
+	}
+
+	/* set the registers for the request */
+	ret = ab8500_set_bits(info->ab8500, info->voltage_reg,
+				info->voltage_mask, ret);
+	if (ret < 0)
+		dev_err(rdev_get_dev(rdev),
+		"couldn't set voltage reg for regulator\n");
+
+	return ret;
+}
+
+static struct regulator_ops ab8500_regulator_ops = {
+	.enable		= ab8500_regulator_enable,
+	.disable	= ab8500_regulator_disable,
+	.is_enabled	= ab8500_regulator_is_enabled,
+	.get_voltage	= ab8500_regulator_get_voltage,
+	.set_voltage	= ab8500_regulator_set_voltage,
+	.list_voltage	= ab8500_list_voltage,
+};
+
+static int ab8500_fixed_get_voltage(struct regulator_dev *rdev)
+{
+	int regulator_id;
+	struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+	regulator_id = rdev_get_id(rdev);
+	if (regulator_id >= AB8500_NUM_REGULATORS)
+		return -EINVAL;
+
+	return info->fixed_uV;
+}
+
+static struct regulator_ops ab8500_ldo_fixed_ops = {
+	.enable		= ab8500_regulator_enable,
+	.disable	= ab8500_regulator_disable,
+	.is_enabled	= ab8500_regulator_is_enabled,
+	.get_voltage	= ab8500_fixed_get_voltage,
+	.list_voltage	= ab8500_list_voltage,
+};
+
+#define AB8500_LDO(_id, min, max, reg, reg_mask, reg_enable,	\
+		volt_reg, volt_mask, voltages,			\
+			len_volts)				\
+{								\
+	.desc	= {						\
+		.name	= "LDO-" #_id,				\
+		.ops	= &ab8500_regulator_ops,		\
+		.type	= REGULATOR_VOLTAGE,			\
+		.id	= AB8500_LDO_##_id,			\
+		.owner	= THIS_MODULE,				\
+	},							\
+	.min_uV		= (min) * 1000,				\
+	.max_uV		= (max) * 1000,				\
+	.update_reg	= reg,					\
+	.mask		= reg_mask,				\
+	.enable		= reg_enable,				\
+	.voltage_reg	= volt_reg,				\
+	.voltage_mask	= volt_mask,				\
+	.supported_voltages = voltages,				\
+	.voltages_len	= len_volts,				\
+	.fixed_uV	= 0,					\
+}
+
+#define AB8500_FIXED_LDO(_id, fixed, reg, reg_mask,	\
+				reg_enable)		\
+{							\
+	.desc	= {					\
+		.name	= "LDO-" #_id,			\
+		.ops	= &ab8500_ldo_fixed_ops,	\
+		.type	= REGULATOR_VOLTAGE,		\
+		.id	= AB8500_LDO_##_id,		\
+		.owner	= THIS_MODULE,			\
+	},						\
+	.fixed_uV	= fixed * 1000,			\
+	.update_reg	= reg,				\
+	.mask		= reg_mask,			\
+	.enable		= reg_enable,			\
+}
+
+static struct ab8500_regulator_info ab8500_regulator_info[] = {
+	/*
+	 * Variable Voltage LDOs
+	 * name, min uV, max uV, ctrl reg, reg mask, enable mask,
+	 *	volt ctrl reg, volt ctrl mask, volt table, num supported volts
+	 */
+	AB8500_LDO(AUX1, 1100, 3300, 0x0409, 0x3, 0x1, 0x041f, 0xf,
+			ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)),
+	AB8500_LDO(AUX2, 1100, 3300, 0x0409, 0xc, 0x4, 0x0420, 0xf,
+			ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)),
+	AB8500_LDO(AUX3, 1100, 3300, 0x040a, 0x3, 0x1, 0x0421, 0xf,
+			ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)),
+	AB8500_LDO(INTCORE, 1100, 3300, 0x0380, 0x4, 0x4, 0x0380, 0x38,
+		ldo_vintcore_voltages, ARRAY_SIZE(ldo_vintcore_voltages)),
+
+	/*
+	 * Fixed Voltage LDOs
+	 *		 name,	o/p uV, ctrl reg, enable, disable
+	 */
+	AB8500_FIXED_LDO(TVOUT,	  2000,   0x0380,   0x2,    0x2),
+	AB8500_FIXED_LDO(AUDIO,   2000,   0x0383,   0x2,    0x2),
+	AB8500_FIXED_LDO(ANAMIC1, 2050,   0x0383,   0x4,    0x4),
+	AB8500_FIXED_LDO(ANAMIC2, 2050,   0x0383,   0x8,    0x8),
+	AB8500_FIXED_LDO(DMIC,    1800,   0x0383,   0x10,   0x10),
+	AB8500_FIXED_LDO(ANA,     1200,   0x0383,   0xc,    0x4),
+};
+
+static inline struct ab8500_regulator_info *find_regulator_info(int id)
+{
+	struct ab8500_regulator_info *info;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) {
+		info = &ab8500_regulator_info[i];
+		if (info->desc.id == id)
+			return info;
+	}
+	return NULL;
+}
+
+static __devinit int ab8500_regulator_probe(struct platform_device *pdev)
+{
+	struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
+	struct ab8500_platform_data *pdata = dev_get_platdata(ab8500->dev);
+	int i, err;
+
+	if (!ab8500) {
+		dev_err(&pdev->dev, "null mfd parent\n");
+		return -EINVAL;
+	}
+
+	/* register all regulators */
+	for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) {
+		struct ab8500_regulator_info *info = NULL;
+
+		/* assign per-regulator data */
+		info = &ab8500_regulator_info[i];
+		info->dev = &pdev->dev;
+		info->ab8500 = ab8500;
+
+		info->regulator = regulator_register(&info->desc, &pdev->dev,
+				pdata->regulator[i], info);
+		if (IS_ERR(info->regulator)) {
+			err = PTR_ERR(info->regulator);
+			dev_err(&pdev->dev, "failed to register regulator %s\n",
+					info->desc.name);
+			/* when we fail, un-register all earlier regulators */
+			i--;
+			while (i > 0) {
+				info = &ab8500_regulator_info[i];
+				regulator_unregister(info->regulator);
+				i--;
+			}
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+static __devexit int ab8500_regulator_remove(struct platform_device *pdev)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) {
+		struct ab8500_regulator_info *info = NULL;
+		info = &ab8500_regulator_info[i];
+		regulator_unregister(info->regulator);
+	}
+
+	return 0;
+}
+
+static struct platform_driver ab8500_regulator_driver = {
+	.probe = ab8500_regulator_probe,
+	.remove = __devexit_p(ab8500_regulator_remove),
+	.driver         = {
+		.name   = "ab8500-regulator",
+		.owner  = THIS_MODULE,
+	},
+};
+
+static int __init ab8500_regulator_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&ab8500_regulator_driver);
+	if (ret != 0)
+		pr_err("Failed to register ab8500 regulator: %d\n", ret);
+
+	return ret;
+}
+subsys_initcall(ab8500_regulator_init);
+
+static void __exit ab8500_regulator_exit(void)
+{
+	platform_driver_unregister(&ab8500_regulator_driver);
+}
+module_exit(ab8500_regulator_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Sundar Iyer <sundar.iyer@stericsson.com>");
+MODULE_DESCRIPTION("Regulator Driver for ST-Ericsson AB8500 Mixed-Sig PMIC");
+MODULE_ALIAS("platform:ab8500-regulator");
diff --git a/drivers/regulator/ad5398.c b/drivers/regulator/ad5398.c
new file mode 100644
index 0000000..d59d2f2
--- /dev/null
+++ b/drivers/regulator/ad5398.c
@@ -0,0 +1,288 @@
+/*
+ * Voltage and current regulation for AD5398 and AD5821
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+#define AD5398_CURRENT_EN_MASK	0x8000
+
+struct ad5398_chip_info {
+	struct i2c_client *client;
+	int min_uA;
+	int max_uA;
+	unsigned int current_level;
+	unsigned int current_mask;
+	unsigned int current_offset;
+	struct regulator_dev rdev;
+};
+
+static int ad5398_calc_current(struct ad5398_chip_info *chip,
+	unsigned selector)
+{
+	unsigned range_uA = chip->max_uA - chip->min_uA;
+
+	return chip->min_uA + (selector * range_uA / chip->current_level);
+}
+
+static int ad5398_read_reg(struct i2c_client *client, unsigned short *data)
+{
+	unsigned short val;
+	int ret;
+
+	ret = i2c_master_recv(client, (char *)&val, 2);
+	if (ret < 0) {
+		dev_err(&client->dev, "I2C read error\n");
+		return ret;
+	}
+	*data = be16_to_cpu(val);
+
+	return ret;
+}
+
+static int ad5398_write_reg(struct i2c_client *client, const unsigned short data)
+{
+	unsigned short val;
+	int ret;
+
+	val = cpu_to_be16(data);
+	ret = i2c_master_send(client, (char *)&val, 2);
+	if (ret < 0)
+		dev_err(&client->dev, "I2C write error\n");
+
+	return ret;
+}
+
+static int ad5398_get_current_limit(struct regulator_dev *rdev)
+{
+	struct ad5398_chip_info *chip = rdev_get_drvdata(rdev);
+	struct i2c_client *client = chip->client;
+	unsigned short data;
+	int ret;
+
+	ret = ad5398_read_reg(client, &data);
+	if (ret < 0)
+		return ret;
+
+	ret = (data & chip->current_mask) >> chip->current_offset;
+
+	return ad5398_calc_current(chip, ret);
+}
+
+static int ad5398_set_current_limit(struct regulator_dev *rdev, int min_uA, int max_uA)
+{
+	struct ad5398_chip_info *chip = rdev_get_drvdata(rdev);
+	struct i2c_client *client = chip->client;
+	unsigned range_uA = chip->max_uA - chip->min_uA;
+	unsigned selector;
+	unsigned short data;
+	int ret;
+
+	if (min_uA > chip->max_uA || min_uA < chip->min_uA)
+		return -EINVAL;
+	if (max_uA > chip->max_uA || max_uA < chip->min_uA)
+		return -EINVAL;
+
+	selector = ((min_uA - chip->min_uA) * chip->current_level +
+			range_uA - 1) / range_uA;
+	if (ad5398_calc_current(chip, selector) > max_uA)
+		return -EINVAL;
+
+	dev_dbg(&client->dev, "changing current %dmA\n",
+		ad5398_calc_current(chip, selector) / 1000);
+
+	/* read chip enable bit */
+	ret = ad5398_read_reg(client, &data);
+	if (ret < 0)
+		return ret;
+
+	/* prepare register data */
+	selector = (selector << chip->current_offset) & chip->current_mask;
+	data = (unsigned short)selector | (data & AD5398_CURRENT_EN_MASK);
+
+	/* write the new current value back as well as enable bit */
+	ret = ad5398_write_reg(client, data);
+
+	return ret;
+}
+
+static int ad5398_is_enabled(struct regulator_dev *rdev)
+{
+	struct ad5398_chip_info *chip = rdev_get_drvdata(rdev);
+	struct i2c_client *client = chip->client;
+	unsigned short data;
+	int ret;
+
+	ret = ad5398_read_reg(client, &data);
+	if (ret < 0)
+		return ret;
+
+	if (data & AD5398_CURRENT_EN_MASK)
+		return 1;
+	else
+		return 0;
+}
+
+static int ad5398_enable(struct regulator_dev *rdev)
+{
+	struct ad5398_chip_info *chip = rdev_get_drvdata(rdev);
+	struct i2c_client *client = chip->client;
+	unsigned short data;
+	int ret;
+
+	ret = ad5398_read_reg(client, &data);
+	if (ret < 0)
+		return ret;
+
+	if (data & AD5398_CURRENT_EN_MASK)
+		return 0;
+
+	data |= AD5398_CURRENT_EN_MASK;
+
+	ret = ad5398_write_reg(client, data);
+
+	return ret;
+}
+
+static int ad5398_disable(struct regulator_dev *rdev)
+{
+	struct ad5398_chip_info *chip = rdev_get_drvdata(rdev);
+	struct i2c_client *client = chip->client;
+	unsigned short data;
+	int ret;
+
+	ret = ad5398_read_reg(client, &data);
+	if (ret < 0)
+		return ret;
+
+	if (!(data & AD5398_CURRENT_EN_MASK))
+		return 0;
+
+	data &= ~AD5398_CURRENT_EN_MASK;
+
+	ret = ad5398_write_reg(client, data);
+
+	return ret;
+}
+
+static struct regulator_ops ad5398_ops = {
+	.get_current_limit = ad5398_get_current_limit,
+	.set_current_limit = ad5398_set_current_limit,
+	.enable = ad5398_enable,
+	.disable = ad5398_disable,
+	.is_enabled = ad5398_is_enabled,
+};
+
+static struct regulator_desc ad5398_reg = {
+	.name = "isink",
+	.id = 0,
+	.ops = &ad5398_ops,
+	.type = REGULATOR_CURRENT,
+	.owner = THIS_MODULE,
+};
+
+struct ad5398_current_data_format {
+	int current_bits;
+	int current_offset;
+	int min_uA;
+	int max_uA;
+};
+
+static const struct ad5398_current_data_format df_10_4_120 = {10, 4, 0, 120000};
+
+static const struct i2c_device_id ad5398_id[] = {
+	{ "ad5398", (kernel_ulong_t)&df_10_4_120 },
+	{ "ad5821", (kernel_ulong_t)&df_10_4_120 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ad5398_id);
+
+static int __devinit ad5398_probe(struct i2c_client *client,
+				const struct i2c_device_id *id)
+{
+	struct regulator_dev *rdev;
+	struct regulator_init_data *init_data = client->dev.platform_data;
+	struct ad5398_chip_info *chip;
+	const struct ad5398_current_data_format *df =
+			(struct ad5398_current_data_format *)id->driver_data;
+	int ret;
+
+	if (!init_data)
+		return -EINVAL;
+
+	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	chip->client = client;
+
+	chip->min_uA = df->min_uA;
+	chip->max_uA = df->max_uA;
+	chip->current_level = 1 << df->current_bits;
+	chip->current_offset = df->current_offset;
+	chip->current_mask = (chip->current_level - 1) << chip->current_offset;
+
+	rdev = regulator_register(&ad5398_reg, &client->dev, init_data, chip);
+	if (IS_ERR(rdev)) {
+		ret = PTR_ERR(rdev);
+		dev_err(&client->dev, "failed to register %s %s\n",
+			id->name, ad5398_reg.name);
+		goto err;
+	}
+
+	i2c_set_clientdata(client, chip);
+	dev_dbg(&client->dev, "%s regulator driver is registered.\n", id->name);
+	return 0;
+
+err:
+	kfree(chip);
+	return ret;
+}
+
+static int __devexit ad5398_remove(struct i2c_client *client)
+{
+	struct ad5398_chip_info *chip = i2c_get_clientdata(client);
+
+	regulator_unregister(&chip->rdev);
+	kfree(chip);
+	i2c_set_clientdata(client, NULL);
+
+	return 0;
+}
+
+static struct i2c_driver ad5398_driver = {
+	.probe = ad5398_probe,
+	.remove = __devexit_p(ad5398_remove),
+	.driver		= {
+		.name	= "ad5398",
+	},
+	.id_table	= ad5398_id,
+};
+
+static int __init ad5398_init(void)
+{
+	return i2c_add_driver(&ad5398_driver);
+}
+subsys_initcall(ad5398_init);
+
+static void __exit ad5398_exit(void)
+{
+	i2c_del_driver(&ad5398_driver);
+}
+module_exit(ad5398_exit);
+
+MODULE_DESCRIPTION("AD5398 and AD5821 current regulator driver");
+MODULE_AUTHOR("Sonic Zhang");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("i2c:ad5398-regulator");
diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c
new file mode 100644
index 0000000..e49d2bd
--- /dev/null
+++ b/drivers/regulator/isl6271a-regulator.c
@@ -0,0 +1,236 @@
+/*
+ * isl6271a-regulator.c
+ *
+ * Support for Intersil ISL6271A voltage regulator
+ *
+ * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#define	ISL6271A_VOLTAGE_MIN	850000
+#define	ISL6271A_VOLTAGE_MAX	1600000
+#define	ISL6271A_VOLTAGE_STEP	50000
+
+/* PMIC details */
+struct isl_pmic {
+	struct i2c_client	*client;
+	struct regulator_dev	*rdev[3];
+	struct mutex		mtx;
+};
+
+static int isl6271a_get_voltage(struct regulator_dev *dev)
+{
+	struct isl_pmic *pmic = rdev_get_drvdata(dev);
+	int idx, data;
+
+	mutex_lock(&pmic->mtx);
+
+	idx = i2c_smbus_read_byte(pmic->client);
+	if (idx < 0) {
+		dev_err(&pmic->client->dev, "Error getting voltage\n");
+		data = idx;
+		goto out;
+	}
+
+	/* Convert the data from chip to microvolts */
+	data = ISL6271A_VOLTAGE_MIN + (ISL6271A_VOLTAGE_STEP * (idx & 0xf));
+
+out:
+	mutex_unlock(&pmic->mtx);
+	return data;
+}
+
+static int isl6271a_set_voltage(struct regulator_dev *dev, int minuV, int maxuV)
+{
+	struct isl_pmic *pmic = rdev_get_drvdata(dev);
+	int vsel, err, data;
+
+	if (minuV < ISL6271A_VOLTAGE_MIN || minuV > ISL6271A_VOLTAGE_MAX)
+		return -EINVAL;
+	if (maxuV < ISL6271A_VOLTAGE_MIN || maxuV > ISL6271A_VOLTAGE_MAX)
+		return -EINVAL;
+
+	/* Align to 50000 mV */
+	vsel = minuV - (minuV % ISL6271A_VOLTAGE_STEP);
+
+	/* If the result fell out of [minuV,maxuV] range, put it back */
+	if (vsel < minuV)
+		vsel += ISL6271A_VOLTAGE_STEP;
+
+	/* Convert the microvolts to data for the chip */
+	data = (vsel - ISL6271A_VOLTAGE_MIN) / ISL6271A_VOLTAGE_STEP;
+
+	mutex_lock(&pmic->mtx);
+
+	err = i2c_smbus_write_byte(pmic->client, data);
+	if (err < 0)
+		dev_err(&pmic->client->dev, "Error setting voltage\n");
+
+	mutex_unlock(&pmic->mtx);
+	return err;
+}
+
+static int isl6271a_list_voltage(struct regulator_dev *dev, unsigned selector)
+{
+	return ISL6271A_VOLTAGE_MIN + (ISL6271A_VOLTAGE_STEP * selector);
+}
+
+static struct regulator_ops isl_core_ops = {
+	.get_voltage	= isl6271a_get_voltage,
+	.set_voltage	= isl6271a_set_voltage,
+	.list_voltage	= isl6271a_list_voltage,
+};
+
+static int isl6271a_get_fixed_voltage(struct regulator_dev *dev)
+{
+	int id = rdev_get_id(dev);
+	return (id == 1) ? 1100000 : 1300000;
+}
+
+static int isl6271a_list_fixed_voltage(struct regulator_dev *dev, unsigned selector)
+{
+	int id = rdev_get_id(dev);
+	return (id == 1) ? 1100000 : 1300000;
+}
+
+static struct regulator_ops isl_fixed_ops = {
+	.get_voltage	= isl6271a_get_fixed_voltage,
+	.list_voltage	= isl6271a_list_fixed_voltage,
+};
+
+static struct regulator_desc isl_rd[] = {
+	{
+		.name		= "Core Buck",
+		.id		= 0,
+		.n_voltages	= 16,
+		.ops		= &isl_core_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO1",
+		.id		= 1,
+		.n_voltages	= 1,
+		.ops		= &isl_fixed_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO2",
+		.id		= 2,
+		.n_voltages	= 1,
+		.ops		= &isl_fixed_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	},
+};
+
+static int __devinit isl6271a_probe(struct i2c_client *i2c,
+				     const struct i2c_device_id *id)
+{
+	struct regulator_init_data *init_data	= i2c->dev.platform_data;
+	struct isl_pmic *pmic;
+	int err, i;
+
+	if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return -EIO;
+
+	if (!init_data) {
+		dev_err(&i2c->dev, "no platform data supplied\n");
+		return -EIO;
+	}
+
+	pmic = kzalloc(sizeof(struct isl_pmic), GFP_KERNEL);
+	if (!pmic)
+		return -ENOMEM;
+
+	pmic->client = i2c;
+
+	mutex_init(&pmic->mtx);
+
+	for (i = 0; i < 3; i++) {
+		pmic->rdev[i] = regulator_register(&isl_rd[0], &i2c->dev,
+						init_data, pmic);
+		if (IS_ERR(pmic->rdev[i])) {
+			dev_err(&i2c->dev, "failed to register %s\n", id->name);
+			err = PTR_ERR(pmic->rdev);
+			goto error;
+		}
+	}
+
+	i2c_set_clientdata(i2c, pmic);
+
+	return 0;
+
+error:
+	while (--i >= 0)
+		regulator_unregister(pmic->rdev[i]);
+
+	kfree(pmic);
+	return err;
+}
+
+static int __devexit isl6271a_remove(struct i2c_client *i2c)
+{
+	struct isl_pmic *pmic = i2c_get_clientdata(i2c);
+	int i;
+
+	i2c_set_clientdata(i2c, NULL);
+
+	for (i = 0; i < 3; i++)
+		regulator_unregister(pmic->rdev[i]);
+
+	kfree(pmic);
+
+	return 0;
+}
+
+static const struct i2c_device_id isl6271a_id[] = {
+	{.name = "isl6271a", 0 },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(i2c, isl6271a_id);
+
+static struct i2c_driver isl6271a_i2c_driver = {
+	.driver = {
+		.name = "isl6271a",
+		.owner = THIS_MODULE,
+	},
+	.probe = isl6271a_probe,
+	.remove = __devexit_p(isl6271a_remove),
+	.id_table = isl6271a_id,
+};
+
+static int __init isl6271a_init(void)
+{
+	return i2c_add_driver(&isl6271a_i2c_driver);
+}
+
+static void __exit isl6271a_cleanup(void)
+{
+	i2c_del_driver(&isl6271a_i2c_driver);
+}
+
+subsys_initcall(isl6271a_init);
+module_exit(isl6271a_cleanup);
+
+MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
+MODULE_DESCRIPTION("Intersil ISL6271A voltage regulator driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c
index 8ae3732..3bb82b6 100644
--- a/drivers/regulator/lp3971.c
+++ b/drivers/regulator/lp3971.c
@@ -377,7 +377,7 @@
 	if (count != 1)
 		return -EIO;
 	ret = i2c_smbus_read_byte_data(i2c, reg);
-	if (ret < 0 || count != 1)
+	if (ret < 0)
 		return -EIO;
 
 	*dest = ret;
@@ -387,15 +387,9 @@
 static int lp3971_i2c_write(struct i2c_client *i2c, char reg, int count,
 	const u16 *src)
 {
-	int ret;
-
 	if (count != 1)
 		return -EIO;
-	ret = i2c_smbus_write_byte_data(i2c, reg, *src);
-	if (ret >= 0)
-		return 0;
-
-	return ret;
+	return i2c_smbus_write_byte_data(i2c, reg, *src);
 }
 
 static u8 lp3971_reg_read(struct lp3971 *lp3971, u8 reg)
diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c
index 2b54d9d..8867c27 100644
--- a/drivers/regulator/max1586.c
+++ b/drivers/regulator/max1586.c
@@ -223,7 +223,7 @@
 		}
 	}
 
-	i2c_set_clientdata(client, rdev);
+	i2c_set_clientdata(client, max1586);
 	dev_info(&client->dev, "Maxim 1586 regulator driver loaded\n");
 	return 0;
 
@@ -238,13 +238,13 @@
 
 static int __devexit max1586_pmic_remove(struct i2c_client *client)
 {
-	struct regulator_dev **rdev = i2c_get_clientdata(client);
+	struct max1586_data *max1586 = i2c_get_clientdata(client);
 	int i;
 
 	for (i = 0; i <= MAX1586_V6; i++)
-		if (rdev[i])
-			regulator_unregister(rdev[i]);
-	kfree(rdev);
+		if (max1586->rdev[i])
+			regulator_unregister(max1586->rdev[i]);
+	kfree(max1586);
 
 	return 0;
 }
diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c
index d97220e..c570e6e 100644
--- a/drivers/regulator/max8660.c
+++ b/drivers/regulator/max8660.c
@@ -450,7 +450,7 @@
 		}
 	}
 
-	i2c_set_clientdata(client, rdev);
+	i2c_set_clientdata(client, max8660);
 	dev_info(&client->dev, "Maxim 8660/8661 regulator driver loaded\n");
 	return 0;
 
@@ -465,13 +465,13 @@
 
 static int __devexit max8660_remove(struct i2c_client *client)
 {
-	struct regulator_dev **rdev = i2c_get_clientdata(client);
+	struct max8660 *max8660 = i2c_get_clientdata(client);
 	int i;
 
 	for (i = 0; i < MAX8660_V_END; i++)
-		if (rdev[i])
-			regulator_unregister(rdev[i]);
-	kfree(rdev);
+		if (max8660->rdev[i])
+			regulator_unregister(max8660->rdev[i]);
+	kfree(max8660);
 
 	return 0;
 }
diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c
new file mode 100644
index 0000000..ab67298
--- /dev/null
+++ b/drivers/regulator/max8998.c
@@ -0,0 +1,635 @@
+/*
+ * max8998.c - Voltage regulator driver for the Maxim 8998
+ *
+ *  Copyright (C) 2009-2010 Samsung Electronics
+ *  Kyungmin Park <kyungmin.park@samsung.com>
+ *  Marek Szyprowski <m.szyprowski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/mfd/max8998.h>
+#include <linux/mfd/max8998-private.h>
+
+struct max8998_data {
+	struct device		*dev;
+	struct max8998_dev	*iodev;
+	int			num_regulators;
+	struct regulator_dev	**rdev;
+};
+
+struct voltage_map_desc {
+	int min;
+	int max;
+	int step;
+};
+
+/* Voltage maps */
+static const struct voltage_map_desc ldo23_voltage_map_desc = {
+	.min = 800,	.step = 50,	.max = 1300,
+};
+static const struct voltage_map_desc ldo456711_voltage_map_desc = {
+	.min = 1600,	.step = 100,	.max = 3600,
+};
+static const struct voltage_map_desc ldo8_voltage_map_desc = {
+	.min = 3000,	.step = 100,	.max = 3600,
+};
+static const struct voltage_map_desc ldo9_voltage_map_desc = {
+	.min = 2800,	.step = 100,	.max = 3100,
+};
+static const struct voltage_map_desc ldo10_voltage_map_desc = {
+	.min = 950,	.step = 50,	.max = 1300,
+};
+static const struct voltage_map_desc ldo1213_voltage_map_desc = {
+	.min = 800,	.step = 100,	.max = 3300,
+};
+static const struct voltage_map_desc ldo1415_voltage_map_desc = {
+	.min = 1200,	.step = 100,	.max = 3300,
+};
+static const struct voltage_map_desc ldo1617_voltage_map_desc = {
+	.min = 1600,	.step = 100,	.max = 3600,
+};
+static const struct voltage_map_desc buck12_voltage_map_desc = {
+	.min = 750,	.step = 25,	.max = 1525,
+};
+static const struct voltage_map_desc buck3_voltage_map_desc = {
+	.min = 1600,	.step = 100,	.max = 3600,
+};
+static const struct voltage_map_desc buck4_voltage_map_desc = {
+	.min = 800,	.step = 100,	.max = 2300,
+};
+
+static const struct voltage_map_desc *ldo_voltage_map[] = {
+	NULL,
+	NULL,
+	&ldo23_voltage_map_desc,	/* LDO2 */
+	&ldo23_voltage_map_desc,	/* LDO3 */
+	&ldo456711_voltage_map_desc,	/* LDO4 */
+	&ldo456711_voltage_map_desc,	/* LDO5 */
+	&ldo456711_voltage_map_desc,	/* LDO6 */
+	&ldo456711_voltage_map_desc,	/* LDO7 */
+	&ldo8_voltage_map_desc,		/* LDO8 */
+	&ldo9_voltage_map_desc,		/* LDO9 */
+	&ldo10_voltage_map_desc,	/* LDO10 */
+	&ldo456711_voltage_map_desc,	/* LDO11 */
+	&ldo1213_voltage_map_desc,	/* LDO12 */
+	&ldo1213_voltage_map_desc,	/* LDO13 */
+	&ldo1415_voltage_map_desc,	/* LDO14 */
+	&ldo1415_voltage_map_desc,	/* LDO15 */
+	&ldo1617_voltage_map_desc,	/* LDO16 */
+	&ldo1617_voltage_map_desc,	/* LDO17 */
+	&buck12_voltage_map_desc,	/* BUCK1 */
+	&buck12_voltage_map_desc,	/* BUCK2 */
+	&buck3_voltage_map_desc,	/* BUCK3 */
+	&buck4_voltage_map_desc,	/* BUCK4 */
+};
+
+static inline int max8998_get_ldo(struct regulator_dev *rdev)
+{
+	return rdev_get_id(rdev);
+}
+
+static int max8998_list_voltage(struct regulator_dev *rdev,
+				unsigned int selector)
+{
+	const struct voltage_map_desc *desc;
+	int ldo = max8998_get_ldo(rdev);
+	int val;
+
+	if (ldo >= ARRAY_SIZE(ldo_voltage_map))
+		return -EINVAL;
+
+	desc = ldo_voltage_map[ldo];
+	if (desc == NULL)
+		return -EINVAL;
+
+	val = desc->min + desc->step * selector;
+	if (val > desc->max)
+		return -EINVAL;
+
+	return val * 1000;
+}
+
+static int max8998_get_enable_register(struct regulator_dev *rdev,
+					int *reg, int *shift)
+{
+	int ldo = max8998_get_ldo(rdev);
+
+	switch (ldo) {
+	case MAX8998_LDO2 ... MAX8998_LDO5:
+		*reg = MAX8998_REG_ONOFF1;
+		*shift = 3 - (ldo - MAX8998_LDO2);
+		break;
+	case MAX8998_LDO6 ... MAX8998_LDO13:
+		*reg = MAX8998_REG_ONOFF2;
+		*shift = 7 - (ldo - MAX8998_LDO6);
+		break;
+	case MAX8998_LDO14 ... MAX8998_LDO17:
+		*reg = MAX8998_REG_ONOFF3;
+		*shift = 7 - (ldo - MAX8998_LDO14);
+		break;
+	case MAX8998_BUCK1 ... MAX8998_BUCK4:
+		*reg = MAX8998_REG_ONOFF1;
+		*shift = 7 - (ldo - MAX8998_BUCK1);
+		break;
+	case MAX8998_EN32KHZ_AP ... MAX8998_ENVICHG:
+		*reg = MAX8998_REG_ONOFF4;
+		*shift = 7 - (ldo - MAX8998_EN32KHZ_AP);
+		break;
+	case MAX8998_ESAFEOUT1 ... MAX8998_ESAFEOUT2:
+		*reg = MAX8998_REG_CHGR2;
+		*shift = 7 - (ldo - MAX8998_ESAFEOUT1);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int max8998_ldo_is_enabled(struct regulator_dev *rdev)
+{
+	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
+	int ret, reg, shift = 8;
+	u8 val;
+
+	ret = max8998_get_enable_register(rdev, &reg, &shift);
+	if (ret)
+		return ret;
+
+	ret = max8998_read_reg(max8998->iodev, reg, &val);
+	if (ret)
+		return ret;
+
+	return val & (1 << shift);
+}
+
+static int max8998_ldo_enable(struct regulator_dev *rdev)
+{
+	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
+	int reg, shift = 8, ret;
+
+	ret = max8998_get_enable_register(rdev, &reg, &shift);
+	if (ret)
+		return ret;
+
+	return max8998_update_reg(max8998->iodev, reg, 1<<shift, 1<<shift);
+}
+
+static int max8998_ldo_disable(struct regulator_dev *rdev)
+{
+	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
+	int reg, shift = 8, ret;
+
+	ret = max8998_get_enable_register(rdev, &reg, &shift);
+	if (ret)
+		return ret;
+
+	return max8998_update_reg(max8998->iodev, reg, 0, 1<<shift);
+}
+
+static int max8998_get_voltage_register(struct regulator_dev *rdev,
+				int *_reg, int *_shift, int *_mask)
+{
+	int ldo = max8998_get_ldo(rdev);
+	int reg, shift = 0, mask = 0xff;
+
+	switch (ldo) {
+	case MAX8998_LDO2 ... MAX8998_LDO3:
+		reg = MAX8998_REG_LDO2_LDO3;
+		mask = 0xf;
+		if (ldo == MAX8998_LDO2)
+			shift = 4;
+		else
+			shift = 0;
+		break;
+	case MAX8998_LDO4 ... MAX8998_LDO7:
+		reg = MAX8998_REG_LDO4 + (ldo - MAX8998_LDO4);
+		break;
+	case MAX8998_LDO8 ... MAX8998_LDO9:
+		reg = MAX8998_REG_LDO8_LDO9;
+		mask = 0xf;
+		if (ldo == MAX8998_LDO8)
+			shift = 4;
+		else
+			shift = 0;
+		break;
+	case MAX8998_LDO10 ... MAX8998_LDO11:
+		reg = MAX8998_REG_LDO10_LDO11;
+		if (ldo == MAX8998_LDO10) {
+			shift = 5;
+			mask = 0x7;
+		} else {
+			shift = 0;
+			mask = 0x1f;
+		}
+		break;
+	case MAX8998_LDO12 ... MAX8998_LDO17:
+		reg = MAX8998_REG_LDO12 + (ldo - MAX8998_LDO12);
+		break;
+	case MAX8998_BUCK1:
+		reg = MAX8998_REG_BUCK1_DVSARM1;
+		break;
+	case MAX8998_BUCK2:
+		reg = MAX8998_REG_BUCK2_DVSINT1;
+		break;
+	case MAX8998_BUCK3:
+		reg = MAX8998_REG_BUCK3;
+		break;
+	case MAX8998_BUCK4:
+		reg = MAX8998_REG_BUCK4;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*_reg = reg;
+	*_shift = shift;
+	*_mask = mask;
+
+	return 0;
+}
+
+static int max8998_get_voltage(struct regulator_dev *rdev)
+{
+	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
+	int reg, shift = 0, mask, ret;
+	u8 val;
+
+	ret = max8998_get_voltage_register(rdev, &reg, &shift, &mask);
+	if (ret)
+		return ret;
+
+	ret = max8998_read_reg(max8998->iodev, reg, &val);
+	if (ret)
+		return ret;
+
+	val >>= shift;
+	val &= mask;
+
+	return max8998_list_voltage(rdev, val);
+}
+
+static int max8998_set_voltage(struct regulator_dev *rdev,
+				int min_uV, int max_uV)
+{
+	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
+	int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
+	int previous_vol = 0;
+	const struct voltage_map_desc *desc;
+	int ldo = max8998_get_ldo(rdev);
+	int reg, shift = 0, mask, ret;
+	int i = 0;
+	u8 val;
+	bool en_ramp = false;
+
+	if (ldo >= ARRAY_SIZE(ldo_voltage_map))
+		return -EINVAL;
+
+	desc = ldo_voltage_map[ldo];
+	if (desc == NULL)
+		return -EINVAL;
+
+	if (max_vol < desc->min || min_vol > desc->max)
+		return -EINVAL;
+
+	while (desc->min + desc->step*i < min_vol &&
+	       desc->min + desc->step*i < desc->max)
+		i++;
+
+	if (desc->min + desc->step*i > max_vol)
+		return -EINVAL;
+
+	ret = max8998_get_voltage_register(rdev, &reg, &shift, &mask);
+	if (ret)
+		return ret;
+
+	/* wait for RAMP_UP_DELAY if rdev is BUCK1/2 and
+	 * ENRAMP is ON */
+	if (ldo == MAX8998_BUCK1 || ldo == MAX8998_BUCK2) {
+		max8998_read_reg(max8998->iodev, MAX8998_REG_ONOFF4, &val);
+		if (val & (1 << 4)) {
+			en_ramp = true;
+			previous_vol = max8998_get_voltage(rdev);
+		}
+	}
+
+	ret = max8998_update_reg(max8998->iodev, reg, i<<shift, mask<<shift);
+
+	if (en_ramp == true) {
+		int difference = desc->min + desc->step*i - previous_vol/1000;
+		if (difference > 0)
+			udelay(difference / ((val & 0x0f) + 1));
+	}
+
+	return ret;
+}
+
+static struct regulator_ops max8998_ldo_ops = {
+	.list_voltage		= max8998_list_voltage,
+	.is_enabled		= max8998_ldo_is_enabled,
+	.enable			= max8998_ldo_enable,
+	.disable		= max8998_ldo_disable,
+	.get_voltage		= max8998_get_voltage,
+	.set_voltage		= max8998_set_voltage,
+	.set_suspend_enable	= max8998_ldo_enable,
+	.set_suspend_disable	= max8998_ldo_disable,
+};
+
+static struct regulator_ops max8998_buck_ops = {
+	.list_voltage		= max8998_list_voltage,
+	.is_enabled		= max8998_ldo_is_enabled,
+	.enable			= max8998_ldo_enable,
+	.disable		= max8998_ldo_disable,
+	.get_voltage		= max8998_get_voltage,
+	.set_voltage		= max8998_set_voltage,
+	.set_suspend_enable	= max8998_ldo_enable,
+	.set_suspend_disable	= max8998_ldo_disable,
+};
+
+static struct regulator_ops max8998_others_ops = {
+	.is_enabled		= max8998_ldo_is_enabled,
+	.enable			= max8998_ldo_enable,
+	.disable		= max8998_ldo_disable,
+	.set_suspend_enable	= max8998_ldo_enable,
+	.set_suspend_disable	= max8998_ldo_disable,
+};
+
+static struct regulator_desc regulators[] = {
+	{
+		.name		= "LDO2",
+		.id		= MAX8998_LDO2,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO3",
+		.id		= MAX8998_LDO3,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO4",
+		.id		= MAX8998_LDO4,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO5",
+		.id		= MAX8998_LDO5,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO6",
+		.id		= MAX8998_LDO6,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO7",
+		.id		= MAX8998_LDO7,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO8",
+		.id		= MAX8998_LDO8,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO9",
+		.id		= MAX8998_LDO9,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO10",
+		.id		= MAX8998_LDO10,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO11",
+		.id		= MAX8998_LDO11,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO12",
+		.id		= MAX8998_LDO12,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO13",
+		.id		= MAX8998_LDO13,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO14",
+		.id		= MAX8998_LDO14,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO15",
+		.id		= MAX8998_LDO15,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO16",
+		.id		= MAX8998_LDO16,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "LDO17",
+		.id		= MAX8998_LDO17,
+		.ops		= &max8998_ldo_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "BUCK1",
+		.id		= MAX8998_BUCK1,
+		.ops		= &max8998_buck_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "BUCK2",
+		.id		= MAX8998_BUCK2,
+		.ops		= &max8998_buck_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "BUCK3",
+		.id		= MAX8998_BUCK3,
+		.ops		= &max8998_buck_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "BUCK4",
+		.id		= MAX8998_BUCK4,
+		.ops		= &max8998_buck_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "EN32KHz AP",
+		.id		= MAX8998_EN32KHZ_AP,
+		.ops		= &max8998_others_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "EN32KHz CP",
+		.id		= MAX8998_EN32KHZ_CP,
+		.ops		= &max8998_others_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "ENVICHG",
+		.id		= MAX8998_ENVICHG,
+		.ops		= &max8998_others_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "ESAFEOUT1",
+		.id		= MAX8998_ESAFEOUT1,
+		.ops		= &max8998_others_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}, {
+		.name		= "ESAFEOUT2",
+		.id		= MAX8998_ESAFEOUT2,
+		.ops		= &max8998_others_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+	}
+};
+
+static __devinit int max8998_pmic_probe(struct platform_device *pdev)
+{
+	struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+	struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev);
+	struct regulator_dev **rdev;
+	struct max8998_data *max8998;
+	int i, ret, size;
+
+	if (!pdata) {
+		dev_err(pdev->dev.parent, "No platform init data supplied\n");
+		return -ENODEV;
+	}
+
+	max8998 = kzalloc(sizeof(struct max8998_data), GFP_KERNEL);
+	if (!max8998)
+		return -ENOMEM;
+
+	size = sizeof(struct regulator_dev *) * (pdata->num_regulators + 1);
+	max8998->rdev = kzalloc(size, GFP_KERNEL);
+	if (!max8998->rdev) {
+		kfree(max8998);
+		return -ENOMEM;
+	}
+
+	rdev = max8998->rdev;
+	max8998->iodev = iodev;
+	platform_set_drvdata(pdev, max8998);
+
+	for (i = 0; i < pdata->num_regulators; i++) {
+		const struct voltage_map_desc *desc;
+		int id = pdata->regulators[i].id;
+		int index = id - MAX8998_LDO2;
+
+		desc = ldo_voltage_map[id];
+		if (desc && regulators[index].ops != &max8998_others_ops) {
+			int count = (desc->max - desc->min) / desc->step + 1;
+			regulators[index].n_voltages = count;
+		}
+		rdev[i] = regulator_register(&regulators[index], max8998->dev,
+				pdata->regulators[i].initdata, max8998);
+		if (IS_ERR(rdev[i])) {
+			ret = PTR_ERR(rdev[i]);
+			dev_err(max8998->dev, "regulator init failed\n");
+			rdev[i] = NULL;
+			goto err;
+		}
+	}
+
+
+	return 0;
+err:
+	for (i = 0; i <= max8998->num_regulators; i++)
+		if (rdev[i])
+			regulator_unregister(rdev[i]);
+
+	kfree(max8998->rdev);
+	kfree(max8998);
+
+	return ret;
+}
+
+static int __devexit max8998_pmic_remove(struct platform_device *pdev)
+{
+	struct max8998_data *max8998 = platform_get_drvdata(pdev);
+	struct regulator_dev **rdev = max8998->rdev;
+	int i;
+
+	for (i = 0; i <= max8998->num_regulators; i++)
+		if (rdev[i])
+			regulator_unregister(rdev[i]);
+
+	kfree(max8998->rdev);
+	kfree(max8998);
+
+	return 0;
+}
+
+static struct platform_driver max8998_pmic_driver = {
+	.driver = {
+		.name = "max8998-pmic",
+		.owner = THIS_MODULE,
+	},
+	.probe = max8998_pmic_probe,
+	.remove = __devexit_p(max8998_pmic_remove),
+};
+
+static int __init max8998_pmic_init(void)
+{
+	return platform_driver_register(&max8998_pmic_driver);
+}
+subsys_initcall(max8998_pmic_init);
+
+static void __exit max8998_pmic_cleanup(void)
+{
+	platform_driver_unregister(&max8998_pmic_driver);
+}
+module_exit(max8998_pmic_cleanup);
+
+MODULE_DESCRIPTION("MAXIM 8998 voltage regulator driver");
+MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c
index f50afc9..cd6d4fc 100644
--- a/drivers/regulator/tps65023-regulator.c
+++ b/drivers/regulator/tps65023-regulator.c
@@ -585,6 +585,8 @@
 static const struct i2c_device_id tps_65023_id[] = {
 	{.name = "tps65023",
 	.driver_data = (unsigned long) tps65023_regs,},
+	{.name = "tps65021",
+	.driver_data = (unsigned long) tps65023_regs,},
 	{ },
 };
 
diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c
index 8152d65..c239f42 100644
--- a/drivers/regulator/tps6507x-regulator.c
+++ b/drivers/regulator/tps6507x-regulator.c
@@ -614,6 +614,7 @@
 	}
 
 	tps6507x_dev->pmic = tps;
+	platform_set_drvdata(pdev, tps6507x_dev);
 
 	return 0;
 
diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c
new file mode 100644
index 0000000..8cff141
--- /dev/null
+++ b/drivers/regulator/tps6586x-regulator.c
@@ -0,0 +1,396 @@
+/*
+ * Regulator driver for TI TPS6586x
+ *
+ * Copyright (C) 2010 Compulab Ltd.
+ * Author: Mike Rapoport <mike@compulab.co.il>
+ *
+ * Based on da903x
+ * Copyright (C) 2006-2008 Marvell International Ltd.
+ * Copyright (C) 2008 Compulab Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/tps6586x.h>
+
+/* supply control and voltage setting  */
+#define TPS6586X_SUPPLYENA	0x10
+#define TPS6586X_SUPPLYENB	0x11
+#define TPS6586X_SUPPLYENC	0x12
+#define TPS6586X_SUPPLYEND	0x13
+#define TPS6586X_SUPPLYENE	0x14
+#define TPS6586X_VCC1		0x20
+#define TPS6586X_VCC2		0x21
+#define TPS6586X_SM1V1		0x23
+#define TPS6586X_SM1V2		0x24
+#define TPS6586X_SM1SL		0x25
+#define TPS6586X_SM0V1		0x26
+#define TPS6586X_SM0V2		0x27
+#define TPS6586X_SM0SL		0x28
+#define TPS6586X_LDO2AV1	0x29
+#define TPS6586X_LDO2AV2	0x2A
+#define TPS6586X_LDO2BV1	0x2F
+#define TPS6586X_LDO2BV2	0x30
+#define TPS6586X_LDO4V1		0x32
+#define TPS6586X_LDO4V2		0x33
+
+/* converter settings  */
+#define TPS6586X_SUPPLYV1	0x41
+#define TPS6586X_SUPPLYV2	0x42
+#define TPS6586X_SUPPLYV3	0x43
+#define TPS6586X_SUPPLYV4	0x44
+#define TPS6586X_SUPPLYV5	0x45
+#define TPS6586X_SUPPLYV6	0x46
+#define TPS6586X_SMODE1		0x47
+#define TPS6586X_SMODE2		0x48
+
+struct tps6586x_regulator {
+	struct regulator_desc desc;
+
+	int volt_reg;
+	int volt_shift;
+	int volt_nbits;
+	int enable_bit[2];
+	int enable_reg[2];
+
+	int *voltages;
+
+	/* for DVM regulators */
+	int go_reg;
+	int go_bit;
+};
+
+static inline struct device *to_tps6586x_dev(struct regulator_dev *rdev)
+{
+	return rdev_get_dev(rdev)->parent->parent;
+}
+
+static int tps6586x_ldo_list_voltage(struct regulator_dev *rdev,
+				     unsigned selector)
+{
+	struct tps6586x_regulator *info = rdev_get_drvdata(rdev);
+
+	return info->voltages[selector] * 1000;
+}
+
+
+static int __tps6586x_ldo_set_voltage(struct device *parent,
+				      struct tps6586x_regulator *ri,
+				      int min_uV, int max_uV)
+{
+	int val, uV;
+	uint8_t mask;
+
+	for (val = 0; val < ri->desc.n_voltages; val++) {
+		uV = ri->voltages[val] * 1000;
+
+		/* LDO0 has minimal voltage 1.2 rather than 1.25 */
+		if (ri->desc.id == TPS6586X_ID_LDO_0 && val == 0)
+			uV -= 50 * 1000;
+
+		/* use the first in-range value */
+		if (min_uV <= uV && uV <= max_uV) {
+
+			val <<= ri->volt_shift;
+			mask = ((1 << ri->volt_nbits) - 1) << ri->volt_shift;
+
+			return tps6586x_update(parent, ri->volt_reg, val, mask);
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int tps6586x_ldo_set_voltage(struct regulator_dev *rdev,
+				    int min_uV, int max_uV)
+{
+	struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
+	struct device *parent = to_tps6586x_dev(rdev);
+
+	return __tps6586x_ldo_set_voltage(parent, ri, min_uV, max_uV);
+}
+
+static int tps6586x_ldo_get_voltage(struct regulator_dev *rdev)
+{
+	struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
+	struct device *parent = to_tps6586x_dev(rdev);
+	uint8_t val, mask;
+	int ret;
+
+	ret = tps6586x_read(parent, ri->volt_reg, &val);
+	if (ret)
+		return ret;
+
+	mask = ((1 << ri->volt_nbits) - 1) << ri->volt_shift;
+	val = (val & mask) >> ri->volt_shift;
+
+	if (val > ri->desc.n_voltages)
+		BUG();
+
+	return ri->voltages[val] * 1000;
+}
+
+static int tps6586x_dvm_set_voltage(struct regulator_dev *rdev,
+				    int min_uV, int max_uV)
+{
+	struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
+	struct device *parent = to_tps6586x_dev(rdev);
+	int ret;
+
+	ret = __tps6586x_ldo_set_voltage(parent, ri, min_uV, max_uV);
+	if (ret)
+		return ret;
+
+	return tps6586x_set_bits(parent, ri->go_reg, ri->go_bit);
+}
+
+static int tps6586x_regulator_enable(struct regulator_dev *rdev)
+{
+	struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
+	struct device *parent = to_tps6586x_dev(rdev);
+
+	return tps6586x_set_bits(parent, ri->enable_reg[0],
+				 1 << ri->enable_bit[0]);
+}
+
+static int tps6586x_regulator_disable(struct regulator_dev *rdev)
+{
+	struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
+	struct device *parent = to_tps6586x_dev(rdev);
+
+	return tps6586x_clr_bits(parent, ri->enable_reg[0],
+				 1 << ri->enable_bit[0]);
+}
+
+static int tps6586x_regulator_is_enabled(struct regulator_dev *rdev)
+{
+	struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
+	struct device *parent = to_tps6586x_dev(rdev);
+	uint8_t reg_val;
+	int ret;
+
+	ret = tps6586x_read(parent, ri->enable_reg[0], &reg_val);
+	if (ret)
+		return ret;
+
+	return !!(reg_val & (1 << ri->enable_bit[0]));
+}
+
+static struct regulator_ops tps6586x_regulator_ldo_ops = {
+	.list_voltage = tps6586x_ldo_list_voltage,
+	.get_voltage = tps6586x_ldo_get_voltage,
+	.set_voltage = tps6586x_ldo_set_voltage,
+
+	.is_enabled = tps6586x_regulator_is_enabled,
+	.enable = tps6586x_regulator_enable,
+	.disable = tps6586x_regulator_disable,
+};
+
+static struct regulator_ops tps6586x_regulator_dvm_ops = {
+	.list_voltage = tps6586x_ldo_list_voltage,
+	.get_voltage = tps6586x_ldo_get_voltage,
+	.set_voltage = tps6586x_dvm_set_voltage,
+
+	.is_enabled = tps6586x_regulator_is_enabled,
+	.enable = tps6586x_regulator_enable,
+	.disable = tps6586x_regulator_disable,
+};
+
+static int tps6586x_ldo_voltages[] = {
+	1250, 1500, 1800, 2500, 2700, 2850, 3100, 3300,
+};
+
+static int tps6586x_ldo4_voltages[] = {
+	1700, 1725, 1750, 1775, 1800, 1825, 1850, 1875,
+	1900, 1925, 1950, 1975, 2000, 2025, 2050, 2075,
+	2100, 2125, 2150, 2175, 2200, 2225, 2250, 2275,
+	2300, 2325, 2350, 2375, 2400, 2425, 2450, 2475,
+};
+
+static int tps6586x_sm2_voltages[] = {
+	3000, 3050, 3100, 3150, 3200, 3250, 3300, 3350,
+	3400, 3450, 3500, 3550, 3600, 3650, 3700, 3750,
+	3800, 3850, 3900, 3950, 4000, 4050, 4100, 4150,
+	4200, 4250, 4300, 4350, 4400, 4450, 4500, 4550,
+};
+
+static int tps6586x_dvm_voltages[] = {
+	 725,  750,  775,  800,  825,  850,  875,  900,
+	 925,  950,  975, 1000, 1025, 1050, 1075, 1100,
+	1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300,
+	1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500,
+};
+
+#define TPS6586X_REGULATOR(_id, vdata, _ops, vreg, shift, nbits,	\
+			   ereg0, ebit0, ereg1, ebit1, goreg, gobit)	\
+{									\
+	.desc	= {							\
+		.name	= "REG-" #_id,					\
+		.ops	= &tps6586x_regulator_##_ops,			\
+		.type	= REGULATOR_VOLTAGE,				\
+		.id	= TPS6586X_ID_##_id,				\
+		.n_voltages = ARRAY_SIZE(tps6586x_##vdata##_voltages),	\
+		.owner	= THIS_MODULE,					\
+	},								\
+	.volt_reg	= TPS6586X_##vreg,				\
+	.volt_shift	= (shift),					\
+	.volt_nbits	= (nbits),					\
+	.enable_reg[0]	= TPS6586X_SUPPLY##ereg0,			\
+	.enable_bit[0]	= (ebit0),					\
+	.enable_reg[1]	= TPS6586X_SUPPLY##ereg1,			\
+	.enable_bit[1]	= (ebit1),					\
+	.voltages	= tps6586x_##vdata##_voltages,			\
+}
+
+#define TPS6586X_LDO(_id, vdata, vreg, shift, nbits,			\
+		     ereg0, ebit0, ereg1, ebit1)			\
+	TPS6586X_REGULATOR(_id, vdata, ldo_ops, vreg, shift, nbits,	\
+			   ereg0, ebit0, ereg1, ebit1, 0, 0)
+
+#define TPS6586X_DVM(_id, vdata, vreg, shift, nbits,			\
+		     ereg0, ebit0, ereg1, ebit1, goreg, gobit)		\
+	TPS6586X_REGULATOR(_id, vdata, dvm_ops, vreg, shift, nbits,	\
+			   ereg0, ebit0, ereg1, ebit1, goreg, gobit)
+
+static struct tps6586x_regulator tps6586x_regulator[] = {
+	TPS6586X_LDO(LDO_0, ldo, SUPPLYV1, 5, 3, ENC, 0, END, 0),
+	TPS6586X_LDO(LDO_3, ldo, SUPPLYV4, 0, 3, ENC, 2, END, 2),
+	TPS6586X_LDO(LDO_5, ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6),
+	TPS6586X_LDO(LDO_6, ldo, SUPPLYV3, 0, 3, ENC, 4, END, 4),
+	TPS6586X_LDO(LDO_7, ldo, SUPPLYV3, 3, 3, ENC, 5, END, 5),
+	TPS6586X_LDO(LDO_8, ldo, SUPPLYV1, 5, 3, ENC, 6, END, 6),
+	TPS6586X_LDO(LDO_9, ldo, SUPPLYV6, 3, 3, ENE, 7, ENE, 7),
+	TPS6586X_LDO(LDO_RTC, ldo, SUPPLYV4, 3, 3, ENE, 7, ENE, 7),
+	TPS6586X_LDO(LDO_1, dvm, SUPPLYV1, 0, 5, ENC, 1, END, 1),
+	TPS6586X_LDO(SM_2, sm2, SUPPLYV2, 0, 5, ENC, 1, END, 1),
+
+	TPS6586X_DVM(LDO_2, dvm, LDO2BV1, 0, 5, ENA, 3, ENB, 3, VCC2, 6),
+	TPS6586X_DVM(LDO_4, ldo4, LDO4V1, 0, 5, ENC, 3, END, 3, VCC1, 6),
+	TPS6586X_DVM(SM_0, dvm, SM0V1, 0, 5, ENA, 1, ENB, 1, VCC1, 2),
+	TPS6586X_DVM(SM_1, dvm, SM1V1, 0, 5, ENA, 0, ENB, 0, VCC1, 0),
+};
+
+/*
+ * TPS6586X has 2 enable bits that are OR'ed to determine the actual
+ * regulator state. Clearing one of this bits allows switching
+ * regulator on and of with single register write.
+ */
+static inline int tps6586x_regulator_preinit(struct device *parent,
+					     struct tps6586x_regulator *ri)
+{
+	uint8_t val1, val2;
+	int ret;
+
+	ret = tps6586x_read(parent, ri->enable_reg[0], &val1);
+	if (ret)
+		return ret;
+
+	ret = tps6586x_read(parent, ri->enable_reg[1], &val2);
+	if (ret)
+		return ret;
+
+	if (!(val2 & ri->enable_bit[1]))
+		return 0;
+
+	/*
+	 * The regulator is on, but it's enabled with the bit we don't
+	 * want to use, so we switch the enable bits
+	 */
+	if (!(val1 & ri->enable_bit[0])) {
+		ret = tps6586x_set_bits(parent, ri->enable_reg[0],
+					1 << ri->enable_bit[0]);
+		if (ret)
+			return ret;
+	}
+
+	return tps6586x_clr_bits(parent, ri->enable_reg[1],
+				 1 << ri->enable_bit[1]);
+}
+
+static inline struct tps6586x_regulator *find_regulator_info(int id)
+{
+	struct tps6586x_regulator *ri;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(tps6586x_regulator); i++) {
+		ri = &tps6586x_regulator[i];
+		if (ri->desc.id == id)
+			return ri;
+	}
+	return NULL;
+}
+
+static int __devinit tps6586x_regulator_probe(struct platform_device *pdev)
+{
+	struct tps6586x_regulator *ri = NULL;
+	struct regulator_dev *rdev;
+	int id = pdev->id;
+	int err;
+
+	dev_dbg(&pdev->dev, "Probing reulator %d\n", id);
+
+	ri = find_regulator_info(id);
+	if (ri == NULL) {
+		dev_err(&pdev->dev, "invalid regulator ID specified\n");
+		return -EINVAL;
+	}
+
+	err = tps6586x_regulator_preinit(pdev->dev.parent, ri);
+	if (err)
+		return err;
+
+	rdev = regulator_register(&ri->desc, &pdev->dev,
+				  pdev->dev.platform_data, ri);
+	if (IS_ERR(rdev)) {
+		dev_err(&pdev->dev, "failed to register regulator %s\n",
+				ri->desc.name);
+		return PTR_ERR(rdev);
+	}
+
+	platform_set_drvdata(pdev, rdev);
+
+	return 0;
+}
+
+static int __devexit tps6586x_regulator_remove(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+	regulator_unregister(rdev);
+	return 0;
+}
+
+static struct platform_driver tps6586x_regulator_driver = {
+	.driver	= {
+		.name	= "tps6586x-regulator",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= tps6586x_regulator_probe,
+	.remove		= __devexit_p(tps6586x_regulator_remove),
+};
+
+static int __init tps6586x_regulator_init(void)
+{
+	return platform_driver_register(&tps6586x_regulator_driver);
+}
+subsys_initcall(tps6586x_regulator_init);
+
+static void __exit tps6586x_regulator_exit(void)
+{
+	platform_driver_unregister(&tps6586x_regulator_driver);
+}
+module_exit(tps6586x_regulator_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
+MODULE_DESCRIPTION("Regulator Driver for TI TPS6586X PMIC");
+MODULE_ALIAS("platform:tps6586x-regulator");
diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c
index 5a1dc8a..03713bc 100644
--- a/drivers/regulator/wm8994-regulator.c
+++ b/drivers/regulator/wm8994-regulator.c
@@ -219,8 +219,6 @@
 
 	ldo->wm8994 = wm8994;
 
-	ldo->is_enabled = true;
-
 	if (pdata->ldo[id].enable && gpio_is_valid(pdata->ldo[id].enable)) {
 		ldo->enable = pdata->ldo[id].enable;
 
@@ -237,7 +235,8 @@
 				ret);
 			goto err_gpio;
 		}
-	}
+	} else
+		ldo->is_enabled = true;
 
 	ldo->regulator = regulator_register(&wm8994_ldo_desc[id], &pdev->dev,
 					     pdata->ldo[id].init_data, ldo);
diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c
index db5d8c4..dfcdf09 100644
--- a/drivers/rtc/rtc-mpc5121.c
+++ b/drivers/rtc/rtc-mpc5121.c
@@ -268,7 +268,7 @@
 	.update_irq_enable = mpc5121_rtc_update_irq_enable,
 };
 
-static int __devinit mpc5121_rtc_probe(struct of_device *op,
+static int __devinit mpc5121_rtc_probe(struct platform_device *op,
 					const struct of_device_id *match)
 {
 	struct mpc5121_rtc_data *rtc;
@@ -338,7 +338,7 @@
 	return err;
 }
 
-static int __devexit mpc5121_rtc_remove(struct of_device *op)
+static int __devexit mpc5121_rtc_remove(struct platform_device *op)
 {
 	struct mpc5121_rtc_data *rtc = dev_get_drvdata(&op->dev);
 	struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c
index 103fdf6..160e751 100644
--- a/drivers/sbus/char/bbc_envctrl.c
+++ b/drivers/sbus/char/bbc_envctrl.c
@@ -443,7 +443,7 @@
 	return 0;
 }
 
-static void attach_one_temp(struct bbc_i2c_bus *bp, struct of_device *op,
+static void attach_one_temp(struct bbc_i2c_bus *bp, struct platform_device *op,
 			    int temp_idx)
 {
 	struct bbc_cpu_temperature *tp;
@@ -488,7 +488,7 @@
 	tp->fan_todo[FAN_CPU] = FAN_SAME;
 }
 
-static void attach_one_fan(struct bbc_i2c_bus *bp, struct of_device *op,
+static void attach_one_fan(struct bbc_i2c_bus *bp, struct platform_device *op,
 			   int fan_idx)
 {
 	struct bbc_fan_control *fp;
@@ -559,7 +559,7 @@
 
 int bbc_envctrl_init(struct bbc_i2c_bus *bp)
 {
-	struct of_device *op;
+	struct platform_device *op;
 	int temp_index = 0;
 	int fan_index = 0;
 	int devidx = 0;
diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c
index 3e89c31..614a5e1 100644
--- a/drivers/sbus/char/bbc_i2c.c
+++ b/drivers/sbus/char/bbc_i2c.c
@@ -51,7 +51,7 @@
  * The second controller also connects to the smartcard reader, if present.
  */
 
-static void set_device_claimage(struct bbc_i2c_bus *bp, struct of_device *op, int val)
+static void set_device_claimage(struct bbc_i2c_bus *bp, struct platform_device *op, int val)
 {
 	int i;
 
@@ -66,9 +66,9 @@
 #define claim_device(BP,ECHILD)		set_device_claimage(BP,ECHILD,1)
 #define release_device(BP,ECHILD)	set_device_claimage(BP,ECHILD,0)
 
-struct of_device *bbc_i2c_getdev(struct bbc_i2c_bus *bp, int index)
+struct platform_device *bbc_i2c_getdev(struct bbc_i2c_bus *bp, int index)
 {
-	struct of_device *op = NULL;
+	struct platform_device *op = NULL;
 	int curidx = 0, i;
 
 	for (i = 0; i < NUM_CHILDREN; i++) {
@@ -86,7 +86,7 @@
 	return NULL;
 }
 
-struct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct of_device *op)
+struct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct platform_device *op)
 {
 	struct bbc_i2c_client *client;
 	const u32 *reg;
@@ -114,7 +114,7 @@
 void bbc_i2c_detach(struct bbc_i2c_client *client)
 {
 	struct bbc_i2c_bus *bp = client->bp;
-	struct of_device *op = client->op;
+	struct platform_device *op = client->op;
 
 	release_device(bp, op);
 	kfree(client);
@@ -297,7 +297,7 @@
 	writeb(I2C_PCF_IDLE, bp->i2c_control_regs + 0x0);
 }
 
-static struct bbc_i2c_bus * __init attach_one_i2c(struct of_device *op, int index)
+static struct bbc_i2c_bus * __init attach_one_i2c(struct platform_device *op, int index)
 {
 	struct bbc_i2c_bus *bp;
 	struct device_node *dp;
@@ -330,7 +330,7 @@
 	for (dp = op->dev.of_node->child;
 	     dp && entry < 8;
 	     dp = dp->sibling, entry++) {
-		struct of_device *child_op;
+		struct platform_device *child_op;
 
 		child_op = of_find_device_by_node(dp);
 		bp->devs[entry].device = child_op;
@@ -361,7 +361,7 @@
 extern int bbc_envctrl_init(struct bbc_i2c_bus *bp);
 extern void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp);
 
-static int __devinit bbc_i2c_probe(struct of_device *op,
+static int __devinit bbc_i2c_probe(struct platform_device *op,
 				   const struct of_device_id *match)
 {
 	struct bbc_i2c_bus *bp;
@@ -386,7 +386,7 @@
 	return err;
 }
 
-static int __devexit bbc_i2c_remove(struct of_device *op)
+static int __devexit bbc_i2c_remove(struct platform_device *op)
 {
 	struct bbc_i2c_bus *bp = dev_get_drvdata(&op->dev);
 
diff --git a/drivers/sbus/char/bbc_i2c.h b/drivers/sbus/char/bbc_i2c.h
index 83c4811..4b45310 100644
--- a/drivers/sbus/char/bbc_i2c.h
+++ b/drivers/sbus/char/bbc_i2c.h
@@ -7,7 +7,7 @@
 
 struct bbc_i2c_client {
 	struct bbc_i2c_bus		*bp;
-	struct of_device		*op;
+	struct platform_device		*op;
 	int				bus;
 	int				address;
 };
@@ -64,16 +64,16 @@
 	struct list_head		temps;
 	struct list_head		fans;
 
-	struct of_device		*op;
+	struct platform_device		*op;
 	struct {
-		struct of_device	*device;
+		struct platform_device	*device;
 		int			client_claimed;
 	} devs[NUM_CHILDREN];
 };
 
 /* Probing and attachment. */
-extern struct of_device *bbc_i2c_getdev(struct bbc_i2c_bus *, int);
-extern struct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct of_device *);
+extern struct platform_device *bbc_i2c_getdev(struct bbc_i2c_bus *, int);
+extern struct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct platform_device *);
 extern void bbc_i2c_detach(struct bbc_i2c_client *);
 
 /* Register read/write.  NOTE: Blocking! */
diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c
index 47db975..1690e53 100644
--- a/drivers/sbus/char/display7seg.c
+++ b/drivers/sbus/char/display7seg.c
@@ -170,7 +170,7 @@
 	.fops		= &d7s_fops
 };
 
-static int __devinit d7s_probe(struct of_device *op,
+static int __devinit d7s_probe(struct platform_device *op,
 			       const struct of_device_id *match)
 {
 	struct device_node *opts;
@@ -236,7 +236,7 @@
 	goto out;
 }
 
-static int __devexit d7s_remove(struct of_device *op)
+static int __devexit d7s_remove(struct platform_device *op)
 {
 	struct d7s *p = dev_get_drvdata(&op->dev);
 	u8 regs = readb(p->regs);
diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c
index 3c27f45..078e5f4 100644
--- a/drivers/sbus/char/envctrl.c
+++ b/drivers/sbus/char/envctrl.c
@@ -1027,7 +1027,7 @@
 	return 0;
 }
 
-static int __devinit envctrl_probe(struct of_device *op,
+static int __devinit envctrl_probe(struct platform_device *op,
 				   const struct of_device_id *match)
 {
 	struct device_node *dp;
@@ -1104,7 +1104,7 @@
 	return err;
 }
 
-static int __devexit envctrl_remove(struct of_device *op)
+static int __devexit envctrl_remove(struct platform_device *op)
 {
 	int index;
 
diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c
index 8bb31c5..2b4b4b6 100644
--- a/drivers/sbus/char/flash.c
+++ b/drivers/sbus/char/flash.c
@@ -160,7 +160,7 @@
 
 static struct miscdevice flash_dev = { FLASH_MINOR, "flash", &flash_fops };
 
-static int __devinit flash_probe(struct of_device *op,
+static int __devinit flash_probe(struct platform_device *op,
 				 const struct of_device_id *match)
 {
 	struct device_node *dp = op->dev.of_node;
@@ -192,7 +192,7 @@
 	return misc_register(&flash_dev);
 }
 
-static int __devexit flash_remove(struct of_device *op)
+static int __devexit flash_remove(struct platform_device *op)
 {
 	misc_deregister(&flash_dev);
 
diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c
index 41eb672..1b345be 100644
--- a/drivers/sbus/char/uctrl.c
+++ b/drivers/sbus/char/uctrl.c
@@ -348,7 +348,7 @@
 	
 }
 
-static int __devinit uctrl_probe(struct of_device *op,
+static int __devinit uctrl_probe(struct platform_device *op,
 				 const struct of_device_id *match)
 {
 	struct uctrl_driver *p;
@@ -404,7 +404,7 @@
 	goto out;
 }
 
-static int __devexit uctrl_remove(struct of_device *op)
+static int __devexit uctrl_remove(struct platform_device *op)
 {
 	struct uctrl_driver *p = dev_get_drvdata(&op->dev);
 
diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c
index 915a29d..ca04cc9 100644
--- a/drivers/scsi/bfa/bfad.c
+++ b/drivers/scsi/bfa/bfad.c
@@ -788,6 +788,7 @@
 	memset(&driver_info, 0, sizeof(driver_info));
 	strncpy(driver_info.version, BFAD_DRIVER_VERSION,
 		sizeof(driver_info.version) - 1);
+	__kernel_param_lock();
 	if (host_name)
 		strncpy(driver_info.host_machine_name, host_name,
 			sizeof(driver_info.host_machine_name) - 1);
@@ -797,6 +798,7 @@
 	if (os_patch)
 		strncpy(driver_info.host_os_patch, os_patch,
 			sizeof(driver_info.host_os_patch) - 1);
+	__kernel_param_unlock();
 
 	strncpy(driver_info.os_device_name, bfad->pci_name,
 		sizeof(driver_info.os_device_name - 1));
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index 53d7ed0..f8c561c 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -704,7 +704,7 @@
 
 static int __devinit qpti_map_regs(struct qlogicpti *qpti)
 {
-	struct of_device *op = qpti->op;
+	struct platform_device *op = qpti->op;
 
 	qpti->qregs = of_ioremap(&op->resource[0], 0,
 				 resource_size(&op->resource[0]),
@@ -727,7 +727,7 @@
 
 static int __devinit qpti_register_irq(struct qlogicpti *qpti)
 {
-	struct of_device *op = qpti->op;
+	struct platform_device *op = qpti->op;
 
 	qpti->qhost->irq = qpti->irq = op->archdata.irqs[0];
 
@@ -752,7 +752,7 @@
 
 static void __devinit qpti_get_scsi_id(struct qlogicpti *qpti)
 {
-	struct of_device *op = qpti->op;
+	struct platform_device *op = qpti->op;
 	struct device_node *dp;
 
 	dp = op->dev.of_node;
@@ -773,7 +773,7 @@
 
 static void qpti_get_bursts(struct qlogicpti *qpti)
 {
-	struct of_device *op = qpti->op;
+	struct platform_device *op = qpti->op;
 	u8 bursts, bmask;
 
 	bursts = of_getintprop_default(op->dev.of_node, "burst-sizes", 0xff);
@@ -806,7 +806,7 @@
  */
 static int __devinit qpti_map_queues(struct qlogicpti *qpti)
 {
-	struct of_device *op = qpti->op;
+	struct platform_device *op = qpti->op;
 
 #define QSIZE(entries)	(((entries) + 1) * QUEUE_ENTRY_LEN)
 	qpti->res_cpu = dma_alloc_coherent(&op->dev,
@@ -1290,7 +1290,7 @@
 	.use_clustering		= ENABLE_CLUSTERING,
 };
 
-static int __devinit qpti_sbus_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit qpti_sbus_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	struct scsi_host_template *tpnt = match->data;
 	struct device_node *dp = op->dev.of_node;
@@ -1401,7 +1401,7 @@
 	return -ENODEV;
 }
 
-static int __devexit qpti_sbus_remove(struct of_device *op)
+static int __devexit qpti_sbus_remove(struct platform_device *op)
 {
 	struct qlogicpti *qpti = dev_get_drvdata(&op->dev);
 
diff --git a/drivers/scsi/qlogicpti.h b/drivers/scsi/qlogicpti.h
index e3c74d1..4377e87 100644
--- a/drivers/scsi/qlogicpti.h
+++ b/drivers/scsi/qlogicpti.h
@@ -342,7 +342,7 @@
 	u_int	                  req_in_ptr;		/* index of next request slot */
 	u_int	                  res_out_ptr;		/* index of next result slot  */
 	long	                  send_marker;		/* must we send a marker?     */
-	struct of_device	 *op;
+	struct platform_device	 *op;
 	unsigned long		  __pad;
 
 	int                       cmd_count[MAX_TARGETS];
diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c
index 89ba6fe..193b37b 100644
--- a/drivers/scsi/sun_esp.c
+++ b/drivers/scsi/sun_esp.c
@@ -44,7 +44,7 @@
 };
 
 static int __devinit esp_sbus_setup_dma(struct esp *esp,
-					struct of_device *dma_of)
+					struct platform_device *dma_of)
 {
 	esp->dma = dma_of;
 
@@ -81,7 +81,7 @@
 
 static int __devinit esp_sbus_map_regs(struct esp *esp, int hme)
 {
-	struct of_device *op = esp->dev;
+	struct platform_device *op = esp->dev;
 	struct resource *res;
 
 	/* On HME, two reg sets exist, first is DVMA,
@@ -101,7 +101,7 @@
 
 static int __devinit esp_sbus_map_command_block(struct esp *esp)
 {
-	struct of_device *op = esp->dev;
+	struct platform_device *op = esp->dev;
 
 	esp->command_block = dma_alloc_coherent(&op->dev, 16,
 						&esp->command_block_dma,
@@ -114,15 +114,15 @@
 static int __devinit esp_sbus_register_irq(struct esp *esp)
 {
 	struct Scsi_Host *host = esp->host;
-	struct of_device *op = esp->dev;
+	struct platform_device *op = esp->dev;
 
 	host->irq = op->archdata.irqs[0];
 	return request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp);
 }
 
-static void __devinit esp_get_scsi_id(struct esp *esp, struct of_device *espdma)
+static void __devinit esp_get_scsi_id(struct esp *esp, struct platform_device *espdma)
 {
-	struct of_device *op = esp->dev;
+	struct platform_device *op = esp->dev;
 	struct device_node *dp;
 
 	dp = op->dev.of_node;
@@ -144,7 +144,7 @@
 
 static void __devinit esp_get_differential(struct esp *esp)
 {
-	struct of_device *op = esp->dev;
+	struct platform_device *op = esp->dev;
 	struct device_node *dp;
 
 	dp = op->dev.of_node;
@@ -156,7 +156,7 @@
 
 static void __devinit esp_get_clock_params(struct esp *esp)
 {
-	struct of_device *op = esp->dev;
+	struct platform_device *op = esp->dev;
 	struct device_node *bus_dp, *dp;
 	int fmhz;
 
@@ -170,10 +170,10 @@
 	esp->cfreq = fmhz;
 }
 
-static void __devinit esp_get_bursts(struct esp *esp, struct of_device *dma_of)
+static void __devinit esp_get_bursts(struct esp *esp, struct platform_device *dma_of)
 {
 	struct device_node *dma_dp = dma_of->dev.of_node;
-	struct of_device *op = esp->dev;
+	struct platform_device *op = esp->dev;
 	struct device_node *dp;
 	u8 bursts, val;
 
@@ -195,7 +195,7 @@
 	esp->bursts = bursts;
 }
 
-static void __devinit esp_sbus_get_props(struct esp *esp, struct of_device *espdma)
+static void __devinit esp_sbus_get_props(struct esp *esp, struct platform_device *espdma)
 {
 	esp_get_scsi_id(esp, espdma);
 	esp_get_differential(esp);
@@ -216,7 +216,7 @@
 static dma_addr_t sbus_esp_map_single(struct esp *esp, void *buf,
 				      size_t sz, int dir)
 {
-	struct of_device *op = esp->dev;
+	struct platform_device *op = esp->dev;
 
 	return dma_map_single(&op->dev, buf, sz, dir);
 }
@@ -224,7 +224,7 @@
 static int sbus_esp_map_sg(struct esp *esp, struct scatterlist *sg,
 				  int num_sg, int dir)
 {
-	struct of_device *op = esp->dev;
+	struct platform_device *op = esp->dev;
 
 	return dma_map_sg(&op->dev, sg, num_sg, dir);
 }
@@ -232,7 +232,7 @@
 static void sbus_esp_unmap_single(struct esp *esp, dma_addr_t addr,
 				  size_t sz, int dir)
 {
-	struct of_device *op = esp->dev;
+	struct platform_device *op = esp->dev;
 
 	dma_unmap_single(&op->dev, addr, sz, dir);
 }
@@ -240,7 +240,7 @@
 static void sbus_esp_unmap_sg(struct esp *esp, struct scatterlist *sg,
 			      int num_sg, int dir)
 {
-	struct of_device *op = esp->dev;
+	struct platform_device *op = esp->dev;
 
 	dma_unmap_sg(&op->dev, sg, num_sg, dir);
 }
@@ -256,7 +256,7 @@
 {
 	int can_do_burst16, can_do_burst32, can_do_burst64;
 	int can_do_sbus64, lim;
-	struct of_device *op;
+	struct platform_device *op;
 	u32 val;
 
 	can_do_burst16 = (esp->bursts & DMA_BURST16) != 0;
@@ -487,8 +487,8 @@
 	.dma_error	=	sbus_esp_dma_error,
 };
 
-static int __devinit esp_sbus_probe_one(struct of_device *op,
-					struct of_device *espdma,
+static int __devinit esp_sbus_probe_one(struct platform_device *op,
+					struct platform_device *espdma,
 					int hme)
 {
 	struct scsi_host_template *tpnt = &scsi_esp_template;
@@ -562,11 +562,11 @@
 	return err;
 }
 
-static int __devinit esp_sbus_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit esp_sbus_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	struct device_node *dma_node = NULL;
 	struct device_node *dp = op->dev.of_node;
-	struct of_device *dma_of = NULL;
+	struct platform_device *dma_of = NULL;
 	int hme = 0;
 
 	if (dp->parent &&
@@ -585,10 +585,10 @@
 	return esp_sbus_probe_one(op, dma_of, hme);
 }
 
-static int __devexit esp_sbus_remove(struct of_device *op)
+static int __devexit esp_sbus_remove(struct platform_device *op)
 {
 	struct esp *esp = dev_get_drvdata(&op->dev);
-	struct of_device *dma_of = esp->dma;
+	struct platform_device *dma_of = esp->dma;
 	unsigned int irq = esp->host->irq;
 	bool is_hme;
 	u32 val;
diff --git a/drivers/serial/apbuart.c b/drivers/serial/apbuart.c
index 0099b86..cc01c65 100644
--- a/drivers/serial/apbuart.c
+++ b/drivers/serial/apbuart.c
@@ -551,7 +551,7 @@
 /* OF Platform Driver                                                       */
 /* ======================================================================== */
 
-static int __devinit apbuart_probe(struct of_device *op,
+static int __devinit apbuart_probe(struct platform_device *op,
 				   const struct of_device_id *match)
 {
 	int i = -1;
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index 6016179..f2b8adc 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -1340,7 +1340,7 @@
 
 static int probe_index;
 
-static int __devinit cpm_uart_probe(struct of_device *ofdev,
+static int __devinit cpm_uart_probe(struct platform_device *ofdev,
                                     const struct of_device_id *match)
 {
 	int index = probe_index++;
@@ -1364,7 +1364,7 @@
 	return uart_add_one_port(&cpm_reg, &pinfo->port);
 }
 
-static int __devexit cpm_uart_remove(struct of_device *ofdev)
+static int __devexit cpm_uart_remove(struct platform_device *ofdev)
 {
 	struct uart_cpm_port *pinfo = dev_get_drvdata(&ofdev->dev);
 	return uart_remove_one_port(&cpm_reg, &pinfo->port);
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 1a88b36..8dedb26 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -1298,7 +1298,7 @@
 };
 
 static int __devinit
-mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
+mpc52xx_uart_of_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	int idx = -1;
 	unsigned int uartclk;
@@ -1369,7 +1369,7 @@
 }
 
 static int
-mpc52xx_uart_of_remove(struct of_device *op)
+mpc52xx_uart_of_remove(struct platform_device *op)
 {
 	struct uart_port *port = dev_get_drvdata(&op->dev);
 	dev_set_drvdata(&op->dev, NULL);
@@ -1382,7 +1382,7 @@
 
 #ifdef CONFIG_PM
 static int
-mpc52xx_uart_of_suspend(struct of_device *op, pm_message_t state)
+mpc52xx_uart_of_suspend(struct platform_device *op, pm_message_t state)
 {
 	struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev);
 
@@ -1393,7 +1393,7 @@
 }
 
 static int
-mpc52xx_uart_of_resume(struct of_device *op)
+mpc52xx_uart_of_resume(struct platform_device *op)
 {
 	struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev);
 
diff --git a/drivers/serial/nwpserial.c b/drivers/serial/nwpserial.c
index e65b0d9..de17367 100644
--- a/drivers/serial/nwpserial.c
+++ b/drivers/serial/nwpserial.c
@@ -344,7 +344,7 @@
 
 	mutex_lock(&nwpserial_mutex);
 
-	dn = to_of_device(port->dev)->dev.of_node;
+	dn = port->dev->of_node;
 	if (dn == NULL)
 		goto out;
 
diff --git a/drivers/serial/of_serial.c b/drivers/serial/of_serial.c
index a48d908..659a695 100644
--- a/drivers/serial/of_serial.c
+++ b/drivers/serial/of_serial.c
@@ -27,7 +27,7 @@
 /*
  * Fill a struct uart_port for a given device node
  */
-static int __devinit of_platform_serial_setup(struct of_device *ofdev,
+static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
 					int type, struct uart_port *port)
 {
 	struct resource resource;
@@ -80,7 +80,7 @@
 /*
  * Try to register a serial port
  */
-static int __devinit of_platform_serial_probe(struct of_device *ofdev,
+static int __devinit of_platform_serial_probe(struct platform_device *ofdev,
 						const struct of_device_id *id)
 {
 	struct of_serial_info *info;
@@ -134,7 +134,7 @@
 /*
  * Release a line
  */
-static int of_platform_serial_remove(struct of_device *ofdev)
+static int of_platform_serial_remove(struct platform_device *ofdev)
 {
 	struct of_serial_info *info = dev_get_drvdata(&ofdev->dev);
 	switch (info->type) {
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
index a779e22..c901486 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/serial/sunhv.c
@@ -519,7 +519,7 @@
 	.data	=	&sunhv_reg,
 };
 
-static int __devinit hv_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit hv_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	struct uart_port *port;
 	unsigned long minor;
@@ -598,7 +598,7 @@
 	return err;
 }
 
-static int __devexit hv_remove(struct of_device *dev)
+static int __devexit hv_remove(struct platform_device *dev)
 {
 	struct uart_port *port = dev_get_drvdata(&dev->dev);
 
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index 9845fb1..5b246b1 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -883,7 +883,7 @@
 	printk("Console: ttyS%d (SAB82532)\n",
 	       (sunsab_reg.minor - 64) + con->index);
 
-	sunserial_console_termios(con, to_of_device(up->port.dev)->dev.of_node);
+	sunserial_console_termios(con, up->port.dev->of_node);
 
 	switch (con->cflag & CBAUD) {
 	case B150: baud = 150; break;
@@ -954,7 +954,7 @@
 #endif
 
 static int __devinit sunsab_init_one(struct uart_sunsab_port *up,
-				     struct of_device *op,
+				     struct platform_device *op,
 				     unsigned long offset,
 				     int line)
 {
@@ -1006,7 +1006,7 @@
 	return 0;
 }
 
-static int __devinit sab_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit sab_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	static int inst;
 	struct uart_sunsab_port *up;
@@ -1062,7 +1062,7 @@
 	return err;
 }
 
-static int __devexit sab_remove(struct of_device *op)
+static int __devexit sab_remove(struct platform_device *op)
 {
 	struct uart_sunsab_port *up = dev_get_drvdata(&op->dev);
 
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index 3cdf748..551ebfe 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -1200,7 +1200,7 @@
 		return -ENODEV;
 
 	printk("%s: %s port at %llx, irq %u\n",
-	       to_of_device(up->port.dev)->dev.of_node->full_name,
+	       up->port.dev->of_node->full_name,
 	       (up->su_type == SU_PORT_KBD) ? "Keyboard" : "Mouse",
 	       (unsigned long long) up->port.mapbase,
 	       up->port.irq);
@@ -1352,7 +1352,7 @@
 	spin_lock_init(&port->lock);
 
 	/* Get firmware console settings.  */
-	sunserial_console_termios(co, to_of_device(port->dev)->dev.of_node);
+	sunserial_console_termios(co, port->dev->of_node);
 
 	memset(&termios, 0, sizeof(struct ktermios));
 	termios.c_cflag = co->cflag;
@@ -1406,7 +1406,7 @@
 	return SU_PORT_PORT;
 }
 
-static int __devinit su_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit su_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	static int inst;
 	struct device_node *dp = op->dev.of_node;
@@ -1497,7 +1497,7 @@
 	return err;
 }
 
-static int __devexit su_remove(struct of_device *op)
+static int __devexit su_remove(struct platform_device *op)
 {
 	struct uart_sunsu_port *up = dev_get_drvdata(&op->dev);
 	bool kbdms = false;
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index d1e6bcb..c1967ac 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -1230,7 +1230,7 @@
 	       (sunzilog_reg.minor - 64) + con->index, con->index);
 
 	/* Get firmware console settings.  */
-	sunserial_console_termios(con, to_of_device(up->port.dev)->dev.of_node);
+	sunserial_console_termios(con, up->port.dev->of_node);
 
 	/* Firmware console speed is limited to 150-->38400 baud so
 	 * this hackish cflag thing is OK.
@@ -1399,7 +1399,7 @@
 
 static int zilog_irq = -1;
 
-static int __devinit zs_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit zs_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	static int kbm_inst, uart_inst;
 	int inst;
@@ -1516,7 +1516,7 @@
 		uart_remove_one_port(&sunzilog_reg, &up->port);
 }
 
-static int __devexit zs_remove(struct of_device *op)
+static int __devexit zs_remove(struct platform_device *op)
 {
 	struct uart_sunzilog_port *up = dev_get_drvdata(&op->dev);
 	struct zilog_layout __iomem *regs;
diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c
index caf085d..9b03d7b 100644
--- a/drivers/serial/uartlite.c
+++ b/drivers/serial/uartlite.c
@@ -584,7 +584,7 @@
  */
 #if defined(CONFIG_OF) && (defined(CONFIG_PPC32) || defined(CONFIG_MICROBLAZE))
 static int __devinit
-ulite_of_probe(struct of_device *op, const struct of_device_id *match)
+ulite_of_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	struct resource res;
 	const unsigned int *id;
@@ -605,7 +605,7 @@
 	return ulite_assign(&op->dev, id ? *id : -1, res.start, irq);
 }
 
-static int __devexit ulite_of_remove(struct of_device *op)
+static int __devexit ulite_of_remove(struct platform_device *op)
 {
 	return ulite_release(&op->dev);
 }
diff --git a/drivers/serial/ucc_uart.c b/drivers/serial/ucc_uart.c
index 907b06f..3f4848e 100644
--- a/drivers/serial/ucc_uart.c
+++ b/drivers/serial/ucc_uart.c
@@ -1194,7 +1194,7 @@
 	release_firmware(fw);
 }
 
-static int ucc_uart_probe(struct of_device *ofdev,
+static int ucc_uart_probe(struct platform_device *ofdev,
 	const struct of_device_id *match)
 {
 	struct device_node *np = ofdev->dev.of_node;
@@ -1462,7 +1462,7 @@
 	return 0;
 }
 
-static int ucc_uart_remove(struct of_device *ofdev)
+static int ucc_uart_remove(struct platform_device *ofdev)
 {
 	struct uart_qe_port *qe_port = dev_get_drvdata(&ofdev->dev);
 
diff --git a/drivers/spi/mpc512x_psc_spi.c b/drivers/spi/mpc512x_psc_spi.c
index 10baac3..cddbfce 100644
--- a/drivers/spi/mpc512x_psc_spi.c
+++ b/drivers/spi/mpc512x_psc_spi.c
@@ -507,7 +507,7 @@
 	return 0;
 }
 
-static int __init mpc512x_psc_spi_of_probe(struct of_device *op,
+static int __init mpc512x_psc_spi_of_probe(struct platform_device *op,
 					   const struct of_device_id *match)
 {
 	const u32 *regaddr_p;
@@ -539,7 +539,7 @@
 				irq_of_parse_and_map(op->dev.of_node, 0), id);
 }
 
-static int __exit mpc512x_psc_spi_of_remove(struct of_device *op)
+static int __exit mpc512x_psc_spi_of_remove(struct platform_device *op)
 {
 	return mpc512x_psc_spi_do_remove(&op->dev);
 }
diff --git a/drivers/spi/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c
index 66d1701..983fbbf 100644
--- a/drivers/spi/mpc52xx_psc_spi.c
+++ b/drivers/spi/mpc52xx_psc_spi.c
@@ -465,7 +465,7 @@
 	return 0;
 }
 
-static int __init mpc52xx_psc_spi_of_probe(struct of_device *op,
+static int __init mpc52xx_psc_spi_of_probe(struct platform_device *op,
 	const struct of_device_id *match)
 {
 	const u32 *regaddr_p;
@@ -495,7 +495,7 @@
 				irq_of_parse_and_map(op->dev.of_node, 0), id);
 }
 
-static int __exit mpc52xx_psc_spi_of_remove(struct of_device *op)
+static int __exit mpc52xx_psc_spi_of_remove(struct platform_device *op)
 {
 	return mpc52xx_psc_spi_do_remove(&op->dev);
 }
diff --git a/drivers/spi/mpc52xx_spi.c b/drivers/spi/mpc52xx_spi.c
index 56136ff..ec9f0b1 100644
--- a/drivers/spi/mpc52xx_spi.c
+++ b/drivers/spi/mpc52xx_spi.c
@@ -390,7 +390,7 @@
 /*
  * OF Platform Bus Binding
  */
-static int __devinit mpc52xx_spi_probe(struct of_device *op,
+static int __devinit mpc52xx_spi_probe(struct platform_device *op,
 				       const struct of_device_id *match)
 {
 	struct spi_master *master;
@@ -530,7 +530,7 @@
 	return rc;
 }
 
-static int __devexit mpc52xx_spi_remove(struct of_device *op)
+static int __devexit mpc52xx_spi_remove(struct platform_device *op)
 {
 	struct spi_master *master = dev_get_drvdata(&op->dev);
 	struct mpc52xx_spi *ms = spi_master_get_devdata(master);
diff --git a/drivers/spi/spi_mpc8xxx.c b/drivers/spi/spi_mpc8xxx.c
index aad9ae1..d31b57f 100644
--- a/drivers/spi/spi_mpc8xxx.c
+++ b/drivers/spi/spi_mpc8xxx.c
@@ -1236,7 +1236,7 @@
 	return 0;
 }
 
-static int __devinit of_mpc8xxx_spi_probe(struct of_device *ofdev,
+static int __devinit of_mpc8xxx_spi_probe(struct platform_device *ofdev,
 					  const struct of_device_id *ofid)
 {
 	struct device *dev = &ofdev->dev;
@@ -1308,7 +1308,7 @@
 	return ret;
 }
 
-static int __devexit of_mpc8xxx_spi_remove(struct of_device *ofdev)
+static int __devexit of_mpc8xxx_spi_remove(struct platform_device *ofdev)
 {
 	int ret;
 
diff --git a/drivers/spi/spi_ppc4xx.c b/drivers/spi/spi_ppc4xx.c
index 0f5fa7e..80e172d 100644
--- a/drivers/spi/spi_ppc4xx.c
+++ b/drivers/spi/spi_ppc4xx.c
@@ -388,9 +388,9 @@
 }
 
 /*
- * of_device layer stuff...
+ * platform_device layer stuff...
  */
-static int __init spi_ppc4xx_of_probe(struct of_device *op,
+static int __init spi_ppc4xx_of_probe(struct platform_device *op,
 				      const struct of_device_id *match)
 {
 	struct ppc4xx_spi *hw;
@@ -565,7 +565,7 @@
 	return ret;
 }
 
-static int __exit spi_ppc4xx_of_remove(struct of_device *op)
+static int __exit spi_ppc4xx_of_remove(struct platform_device *op)
 {
 	struct spi_master *master = dev_get_drvdata(&op->dev);
 	struct ppc4xx_spi *hw = spi_master_get_devdata(master);
diff --git a/drivers/spi/xilinx_spi_of.c b/drivers/spi/xilinx_spi_of.c
index f53d3f6..b66c2db 100644
--- a/drivers/spi/xilinx_spi_of.c
+++ b/drivers/spi/xilinx_spi_of.c
@@ -38,7 +38,7 @@
 #include "xilinx_spi.h"
 
 
-static int __devinit xilinx_spi_of_probe(struct of_device *ofdev,
+static int __devinit xilinx_spi_of_probe(struct platform_device *ofdev,
 	const struct of_device_id *match)
 {
 	struct spi_master *master;
@@ -84,7 +84,7 @@
 	return 0;
 }
 
-static int __devexit xilinx_spi_remove(struct of_device *ofdev)
+static int __devexit xilinx_spi_remove(struct platform_device *ofdev)
 {
 	xilinx_spi_deinit(dev_get_drvdata(&ofdev->dev));
 	dev_set_drvdata(&ofdev->dev, 0);
@@ -93,7 +93,7 @@
 	return 0;
 }
 
-static int __exit xilinx_spi_of_remove(struct of_device *op)
+static int __exit xilinx_spi_of_remove(struct platform_device *op)
 {
 	return xilinx_spi_remove(op);
 }
diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c
index 49ab9fa..ed7457b 100644
--- a/drivers/staging/rtl8187se/r8180_core.c
+++ b/drivers/staging/rtl8187se/r8180_core.c
@@ -61,7 +61,7 @@
 };
 
 
-static char *ifname = "wlan%d";
+static char ifname[IFNAMSIZ] = "wlan%d";
 static int hwseqnum = 0;
 static int hwwep = 0;
 static int channels = 0x3fff;
@@ -72,7 +72,7 @@
 MODULE_DESCRIPTION("Linux driver for Realtek RTL8180 / RTL8185 WiFi cards");
 
 
-module_param(ifname, charp, S_IRUGO|S_IWUSR);
+module_param_string(ifname, ifname, sizeof(ifname), S_IRUGO|S_IWUSR);
 module_param(hwseqnum, int, S_IRUGO|S_IWUSR);
 module_param(hwwep, int, S_IRUGO|S_IWUSR);
 module_param(channels, int, S_IRUGO|S_IWUSR);
@@ -3609,7 +3609,7 @@
 
 	if (dev_alloc_name(dev, ifname) < 0) {
 		DMESG("Oops: devname already taken! Trying wlan%%d...\n");
-		ifname = "wlan%d";
+		strcpy(ifname, "wlan%d");
 		dev_alloc_name(dev, ifname);
 	}
 
diff --git a/drivers/staging/rtl8192e/r8192E_core.c b/drivers/staging/rtl8192e/r8192E_core.c
index 4cd071a..17a806f 100644
--- a/drivers/staging/rtl8192e/r8192E_core.c
+++ b/drivers/staging/rtl8192e/r8192E_core.c
@@ -112,7 +112,7 @@
 	{}
 };
 
-static char* ifname = "wlan%d";
+static char ifname[IFNAMSIZ] = "wlan%d";
 static int hwwep = 1; //default use hw. set 0 to use software security
 static int channels = 0x3fff;
 
@@ -123,7 +123,7 @@
 MODULE_DESCRIPTION("Linux driver for Realtek RTL819x WiFi cards");
 
 
-module_param(ifname, charp, S_IRUGO|S_IWUSR );
+module_param_string(ifname, ifname, sizeof(ifname), S_IRUGO|S_IWUSR);
 //module_param(hwseqnum,int, S_IRUGO|S_IWUSR);
 module_param(hwwep,int, S_IRUGO|S_IWUSR);
 module_param(channels,int, S_IRUGO|S_IWUSR);
@@ -6446,7 +6446,7 @@
 
 	if (dev_alloc_name(dev, ifname) < 0){
                 RT_TRACE(COMP_INIT, "Oops: devname already taken! Trying wlan%%d...\n");
-		ifname = "wlan%d";
+		strcpy(ifname, "wlan%d");
 		dev_alloc_name(dev, ifname);
         }
 
diff --git a/drivers/staging/rtl8192su/r8192U_core.c b/drivers/staging/rtl8192su/r8192U_core.c
index 6970c97..df5b52b 100644
--- a/drivers/staging/rtl8192su/r8192U_core.c
+++ b/drivers/staging/rtl8192su/r8192U_core.c
@@ -144,13 +144,13 @@
 MODULE_DEVICE_TABLE(usb, rtl8192_usb_id_tbl);
 MODULE_DESCRIPTION("Linux driver for Realtek RTL8192 USB WiFi cards");
 
-static char* ifname = "wlan%d";
+static char ifname[IFNAMSIZ] = "wlan%d";
 static int hwwep = 1;  //default use hw. set 0 to use software security
 static int channels = 0x3fff;
 
 
 
-module_param(ifname, charp, S_IRUGO|S_IWUSR );
+module_param_string(ifname, ifname, sizeof(ifname), S_IRUGO|S_IWUSR);
 //module_param(hwseqnum,int, S_IRUGO|S_IWUSR);
 module_param(hwwep,int, S_IRUGO|S_IWUSR);
 module_param(channels,int, S_IRUGO|S_IWUSR);
@@ -7406,7 +7406,7 @@
 
 	if (dev_alloc_name(dev, ifname) < 0){
                 RT_TRACE(COMP_INIT, "Oops: devname already taken! Trying wlan%%d...\n");
-		ifname = "wlan%d";
+		strcpy(ifname, "wlan%d");
 		dev_alloc_name(dev, ifname);
         }
 
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index 5b3f555..ea071a5 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -1577,6 +1577,7 @@
 	char file_arr[] = "CMVxy.bin";
 	char *file;
 
+	kparam_block_sysfs_write(cmv_file);
 	/* set proper name corresponding modem version and line type */
 	if (cmv_file[sc->modem_index] == NULL) {
 		if (UEA_CHIP_VERSION(sc) == ADI930)
@@ -1595,6 +1596,7 @@
 	strlcat(cmv_name, file, UEA_FW_NAME_MAX);
 	if (ver == 2)
 		strlcat(cmv_name, ".v2", UEA_FW_NAME_MAX);
+	kparam_unblock_sysfs_write(cmv_file);
 }
 
 static int request_cmvs_old(struct uea_softc *sc,
diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c
index 9648b75..a5ea2c1 100644
--- a/drivers/usb/gadget/fsl_qe_udc.c
+++ b/drivers/usb/gadget/fsl_qe_udc.c
@@ -2398,7 +2398,7 @@
 EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 /* udc structure's alloc and setup, include ep-param alloc */
-static struct qe_udc __devinit *qe_udc_config(struct of_device *ofdev)
+static struct qe_udc __devinit *qe_udc_config(struct platform_device *ofdev)
 {
 	struct qe_udc *udc;
 	struct device_node *np = ofdev->dev.of_node;
@@ -2523,7 +2523,7 @@
 }
 
 /* Driver probe functions */
-static int __devinit qe_udc_probe(struct of_device *ofdev,
+static int __devinit qe_udc_probe(struct platform_device *ofdev,
 			const struct of_device_id *match)
 {
 	struct device_node *np = ofdev->dev.of_node;
@@ -2679,18 +2679,18 @@
 }
 
 #ifdef CONFIG_PM
-static int qe_udc_suspend(struct of_device *dev, pm_message_t state)
+static int qe_udc_suspend(struct platform_device *dev, pm_message_t state)
 {
 	return -ENOTSUPP;
 }
 
-static int qe_udc_resume(struct of_device *dev)
+static int qe_udc_resume(struct platform_device *dev)
 {
 	return -ENOTSUPP;
 }
 #endif
 
-static int __devexit qe_udc_remove(struct of_device *ofdev)
+static int __devexit qe_udc_remove(struct platform_device *ofdev)
 {
 	struct qe_ep *ep;
 	unsigned int size;
diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c
index 5aec928..335ee69 100644
--- a/drivers/usb/host/ehci-ppc-of.c
+++ b/drivers/usb/host/ehci-ppc-of.c
@@ -106,7 +106,7 @@
 
 
 static int __devinit
-ehci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
+ehci_hcd_ppc_of_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	struct device_node *dn = op->dev.of_node;
 	struct usb_hcd *hcd;
@@ -210,7 +210,7 @@
 }
 
 
-static int ehci_hcd_ppc_of_remove(struct of_device *op)
+static int ehci_hcd_ppc_of_remove(struct platform_device *op)
 {
 	struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
@@ -253,7 +253,7 @@
 }
 
 
-static int ehci_hcd_ppc_of_shutdown(struct of_device *op)
+static int ehci_hcd_ppc_of_shutdown(struct platform_device *op)
 {
 	struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
 
diff --git a/drivers/usb/host/ehci-xilinx-of.c b/drivers/usb/host/ehci-xilinx-of.c
index 4899f45..6c8076a 100644
--- a/drivers/usb/host/ehci-xilinx-of.c
+++ b/drivers/usb/host/ehci-xilinx-of.c
@@ -140,7 +140,7 @@
 
 /**
  * ehci_hcd_xilinx_of_probe - Probe method for the USB host controller
- * @op:		pointer to the of_device to which the host controller bound
+ * @op:		pointer to the platform_device bound to the host controller
  * @match:	pointer to of_device_id structure, not used
  *
  * This function requests resources and sets up appropriate properties for the
@@ -149,7 +149,7 @@
  * entry, and sets an appropriate value for hcd->has_tt.
  */
 static int __devinit
-ehci_hcd_xilinx_of_probe(struct of_device *op, const struct of_device_id *match)
+ehci_hcd_xilinx_of_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	struct device_node *dn = op->dev.of_node;
 	struct usb_hcd *hcd;
@@ -242,12 +242,12 @@
 
 /**
  * ehci_hcd_xilinx_of_remove - shutdown hcd and release resources
- * @op:		pointer to of_device structure that is to be removed
+ * @op:		pointer to platform_device structure that is to be removed
  *
  * Remove the hcd structure, and release resources that has been requested
  * during probe.
  */
-static int ehci_hcd_xilinx_of_remove(struct of_device *op)
+static int ehci_hcd_xilinx_of_remove(struct platform_device *op)
 {
 	struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
 	dev_set_drvdata(&op->dev, NULL);
@@ -266,11 +266,11 @@
 
 /**
  * ehci_hcd_xilinx_of_shutdown - shutdown the hcd
- * @op:		pointer to of_device structure that is to be removed
+ * @op:		pointer to platform_device structure that is to be removed
  *
  * Properly shutdown the hcd, call driver's shutdown routine.
  */
-static int ehci_hcd_xilinx_of_shutdown(struct of_device *op)
+static int ehci_hcd_xilinx_of_shutdown(struct platform_device *op)
 {
 	struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
 
diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c
index c7c8392..20092a2 100644
--- a/drivers/usb/host/fhci-hcd.c
+++ b/drivers/usb/host/fhci-hcd.c
@@ -561,7 +561,7 @@
 	.hub_control = fhci_hub_control,
 };
 
-static int __devinit of_fhci_probe(struct of_device *ofdev,
+static int __devinit of_fhci_probe(struct platform_device *ofdev,
 				   const struct of_device_id *ofid)
 {
 	struct device *dev = &ofdev->dev;
@@ -801,7 +801,7 @@
 	return 0;
 }
 
-static int __devexit of_fhci_remove(struct of_device *ofdev)
+static int __devexit of_fhci_remove(struct platform_device *ofdev)
 {
 	return fhci_remove(&ofdev->dev);
 }
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c
index ec85d0c..3b28dbfc 100644
--- a/drivers/usb/host/isp1760-if.c
+++ b/drivers/usb/host/isp1760-if.c
@@ -27,7 +27,7 @@
 #endif
 
 #ifdef CONFIG_PPC_OF
-static int of_isp1760_probe(struct of_device *dev,
+static int of_isp1760_probe(struct platform_device *dev,
 		const struct of_device_id *match)
 {
 	struct usb_hcd *hcd;
@@ -95,7 +95,7 @@
 	return ret;
 }
 
-static int of_isp1760_remove(struct of_device *dev)
+static int of_isp1760_remove(struct platform_device *dev)
 {
 	struct usb_hcd *hcd = dev_get_drvdata(&dev->dev);
 
diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
index cd74bbd..653d6a6 100644
--- a/drivers/usb/host/ohci-pnx4008.c
+++ b/drivers/usb/host/ohci-pnx4008.c
@@ -329,7 +329,7 @@
 	memset(&i2c_info, 0, sizeof(struct i2c_board_info));
 	strlcpy(i2c_info.type, "isp1301_pnx", I2C_NAME_SIZE);
 	isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info,
-						   normal_i2c);
+						   normal_i2c, NULL);
 	i2c_put_adapter(i2c_adap);
 	if (!isp1301_i2c_client) {
 		err("failed to connect I2C to ISP1301 USB Transceiver");
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
index df16591..b2c2dbf 100644
--- a/drivers/usb/host/ohci-ppc-of.c
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -81,7 +81,7 @@
 
 
 static int __devinit
-ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
+ohci_hcd_ppc_of_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	struct device_node *dn = op->dev.of_node;
 	struct usb_hcd *hcd;
@@ -183,7 +183,7 @@
 	return rv;
 }
 
-static int ohci_hcd_ppc_of_remove(struct of_device *op)
+static int ohci_hcd_ppc_of_remove(struct platform_device *op)
 {
 	struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
 	dev_set_drvdata(&op->dev, NULL);
@@ -201,7 +201,7 @@
 	return 0;
 }
 
-static int ohci_hcd_ppc_of_shutdown(struct of_device *op)
+static int ohci_hcd_ppc_of_shutdown(struct platform_device *op)
 {
 	struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
 
diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c
index c779663..4dc1346 100644
--- a/drivers/video/bw2.c
+++ b/drivers/video/bw2.c
@@ -273,7 +273,7 @@
 	return 0;
 }
 
-static int __devinit bw2_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit bw2_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	struct device_node *dp = op->dev.of_node;
 	struct fb_info *info;
@@ -350,7 +350,7 @@
 	return err;
 }
 
-static int __devexit bw2_remove(struct of_device *op)
+static int __devexit bw2_remove(struct platform_device *op)
 {
 	struct fb_info *info = dev_get_drvdata(&op->dev);
 	struct bw2_par *par = info->par;
diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c
index d09fde8..2424953 100644
--- a/drivers/video/cg14.c
+++ b/drivers/video/cg14.c
@@ -446,7 +446,7 @@
 	{ .size = 0 }
 };
 
-static void cg14_unmap_regs(struct of_device *op, struct fb_info *info,
+static void cg14_unmap_regs(struct platform_device *op, struct fb_info *info,
 			    struct cg14_par *par)
 {
 	if (par->regs)
@@ -463,7 +463,7 @@
 			   info->screen_base, info->fix.smem_len);
 }
 
-static int __devinit cg14_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit cg14_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	struct device_node *dp = op->dev.of_node;
 	struct fb_info *info;
@@ -570,7 +570,7 @@
 	return err;
 }
 
-static int __devexit cg14_remove(struct of_device *op)
+static int __devexit cg14_remove(struct platform_device *op)
 {
 	struct fb_info *info = dev_get_drvdata(&op->dev);
 	struct cg14_par *par = info->par;
diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c
index 64aa2980..09c0c3c 100644
--- a/drivers/video/cg3.c
+++ b/drivers/video/cg3.c
@@ -346,7 +346,7 @@
 	return 0;
 }
 
-static int __devinit cg3_probe(struct of_device *op,
+static int __devinit cg3_probe(struct platform_device *op,
 			       const struct of_device_id *match)
 {
 	struct device_node *dp = op->dev.of_node;
@@ -433,7 +433,7 @@
 	return err;
 }
 
-static int __devexit cg3_remove(struct of_device *op)
+static int __devexit cg3_remove(struct platform_device *op)
 {
 	struct fb_info *info = dev_get_drvdata(&op->dev);
 	struct cg3_par *par = info->par;
diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c
index 2389a71..2b5a970 100644
--- a/drivers/video/cg6.c
+++ b/drivers/video/cg6.c
@@ -718,7 +718,7 @@
 	sbus_writel(info->var.yres - 1, &fbc->clipmaxy);
 }
 
-static void cg6_unmap_regs(struct of_device *op, struct fb_info *info,
+static void cg6_unmap_regs(struct platform_device *op, struct fb_info *info,
 			   struct cg6_par *par)
 {
 	if (par->fbc)
@@ -737,7 +737,7 @@
 			   info->fix.smem_len);
 }
 
-static int __devinit cg6_probe(struct of_device *op,
+static int __devinit cg6_probe(struct platform_device *op,
 				const struct of_device_id *match)
 {
 	struct device_node *dp = op->dev.of_node;
@@ -827,7 +827,7 @@
 	return err;
 }
 
-static int __devexit cg6_remove(struct of_device *op)
+static int __devexit cg6_remove(struct platform_device *op)
 {
 	struct fb_info *info = dev_get_drvdata(&op->dev);
 	struct cg6_par *par = info->par;
diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c
index f6ecfab..6739b2a 100644
--- a/drivers/video/ffb.c
+++ b/drivers/video/ffb.c
@@ -893,7 +893,7 @@
 	info->fix.accel = FB_ACCEL_SUN_CREATOR;
 }
 
-static int __devinit ffb_probe(struct of_device *op,
+static int __devinit ffb_probe(struct platform_device *op,
 			       const struct of_device_id *match)
 {
 	struct device_node *dp = op->dev.of_node;
@@ -1023,7 +1023,7 @@
 	return err;
 }
 
-static int __devexit ffb_remove(struct of_device *op)
+static int __devexit ffb_remove(struct platform_device *op)
 {
 	struct fb_info *info = dev_get_drvdata(&op->dev);
 	struct ffb_par *par = info->par;
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index e38ad22..8bbbf08 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -1393,7 +1393,7 @@
  * Power management hooks. Note that we won't be called from IRQ context,
  * unlike the blank functions above, so we may sleep.
  */
-static int fsl_diu_suspend(struct of_device *ofdev, pm_message_t state)
+static int fsl_diu_suspend(struct platform_device *ofdev, pm_message_t state)
 {
 	struct fsl_diu_data *machine_data;
 
@@ -1403,7 +1403,7 @@
 	return 0;
 }
 
-static int fsl_diu_resume(struct of_device *ofdev)
+static int fsl_diu_resume(struct platform_device *ofdev)
 {
 	struct fsl_diu_data *machine_data;
 
@@ -1487,7 +1487,7 @@
 	return diu_ops.show_monitor_port(machine_data->monitor_port, buf);
 }
 
-static int __devinit fsl_diu_probe(struct of_device *ofdev,
+static int __devinit fsl_diu_probe(struct platform_device *ofdev,
 	const struct of_device_id *match)
 {
 	struct device_node *np = ofdev->dev.of_node;
@@ -1667,7 +1667,7 @@
 }
 
 
-static int fsl_diu_remove(struct of_device *ofdev)
+static int fsl_diu_remove(struct platform_device *ofdev)
 {
 	struct fsl_diu_data *machine_data;
 	int i;
diff --git a/drivers/video/leo.c b/drivers/video/leo.c
index ad67763..b599e5e 100644
--- a/drivers/video/leo.c
+++ b/drivers/video/leo.c
@@ -529,7 +529,7 @@
 	var->transp.length = 0;
 }
 
-static void leo_unmap_regs(struct of_device *op, struct fb_info *info,
+static void leo_unmap_regs(struct platform_device *op, struct fb_info *info,
 			   struct leo_par *par)
 {
 	if (par->lc_ss0_usr)
@@ -547,7 +547,7 @@
 		of_iounmap(&op->resource[0], info->screen_base, 0x800000);
 }
 
-static int __devinit leo_probe(struct of_device *op,
+static int __devinit leo_probe(struct platform_device *op,
 			       const struct of_device_id *match)
 {
 	struct device_node *dp = op->dev.of_node;
@@ -637,7 +637,7 @@
 	return err;
 }
 
-static int __devexit leo_remove(struct of_device *op)
+static int __devexit leo_remove(struct platform_device *op)
 {
 	struct fb_info *info = dev_get_drvdata(&op->dev);
 	struct leo_par *par = info->par;
diff --git a/drivers/video/matrox/i2c-matroxfb.c b/drivers/video/matrox/i2c-matroxfb.c
index 403b144..0fb280e 100644
--- a/drivers/video/matrox/i2c-matroxfb.c
+++ b/drivers/video/matrox/i2c-matroxfb.c
@@ -191,7 +191,7 @@
 			};
 
 			i2c_new_probed_device(&m2info->maven.adapter,
-					      &maven_info, addr_list);
+					      &maven_info, addr_list, NULL);
 		}
 	}
 	return m2info;
diff --git a/drivers/video/mb862xx/mb862xxfb.c b/drivers/video/mb862xx/mb862xxfb.c
index 4e2b8cc..b1c4374 100644
--- a/drivers/video/mb862xx/mb862xxfb.c
+++ b/drivers/video/mb862xx/mb862xxfb.c
@@ -550,7 +550,7 @@
 	return 0;
 }
 
-static int __devinit of_platform_mb862xx_probe(struct of_device *ofdev,
+static int __devinit of_platform_mb862xx_probe(struct platform_device *ofdev,
 					       const struct of_device_id *id)
 {
 	struct device_node *np = ofdev->dev.of_node;
@@ -669,7 +669,7 @@
 	return ret;
 }
 
-static int __devexit of_platform_mb862xx_remove(struct of_device *ofdev)
+static int __devexit of_platform_mb862xx_remove(struct platform_device *ofdev)
 {
 	struct fb_info *fbi = dev_get_drvdata(&ofdev->dev);
 	struct mb862xxfb_par *par = fbi->par;
diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c
index 688b055..b6c3fc2 100644
--- a/drivers/video/p9100.c
+++ b/drivers/video/p9100.c
@@ -249,7 +249,7 @@
 	info->fix.accel = FB_ACCEL_SUN_CGTHREE;
 }
 
-static int __devinit p9100_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit p9100_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	struct device_node *dp = op->dev.of_node;
 	struct fb_info *info;
@@ -326,7 +326,7 @@
 	return err;
 }
 
-static int __devexit p9100_remove(struct of_device *op)
+static int __devexit p9100_remove(struct platform_device *op)
 {
 	struct fb_info *info = dev_get_drvdata(&op->dev);
 	struct p9100_par *par = info->par;
diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c
index 72a1f4c..a50e197 100644
--- a/drivers/video/platinumfb.c
+++ b/drivers/video/platinumfb.c
@@ -533,7 +533,7 @@
 #define invalidate_cache(addr)
 #endif
 
-static int __devinit platinumfb_probe(struct of_device* odev,
+static int __devinit platinumfb_probe(struct platform_device* odev,
 				      const struct of_device_id *match)
 {
 	struct device_node	*dp = odev->dev.of_node;
@@ -646,7 +646,7 @@
 	return rc;
 }
 
-static int __devexit platinumfb_remove(struct of_device* odev)
+static int __devexit platinumfb_remove(struct platform_device* odev)
 {
 	struct fb_info		*info = dev_get_drvdata(&odev->dev);
 	struct fb_info_platinum	*pinfo = info->par;
diff --git a/drivers/video/sunxvr1000.c b/drivers/video/sunxvr1000.c
index 7288934..5dbe06a 100644
--- a/drivers/video/sunxvr1000.c
+++ b/drivers/video/sunxvr1000.c
@@ -111,7 +111,7 @@
         return 0;
 }
 
-static int __devinit gfb_probe(struct of_device *op,
+static int __devinit gfb_probe(struct platform_device *op,
 			       const struct of_device_id *match)
 {
 	struct device_node *dp = op->dev.of_node;
@@ -172,7 +172,7 @@
 	return err;
 }
 
-static int __devexit gfb_remove(struct of_device *op)
+static int __devexit gfb_remove(struct platform_device *op)
 {
 	struct fb_info *info = dev_get_drvdata(&op->dev);
 	struct gfb_info *gp = info->par;
diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c
index f375e0d..77ad279 100644
--- a/drivers/video/tcx.c
+++ b/drivers/video/tcx.c
@@ -342,7 +342,7 @@
 	info->fix.accel = FB_ACCEL_SUN_TCX;
 }
 
-static void tcx_unmap_regs(struct of_device *op, struct fb_info *info,
+static void tcx_unmap_regs(struct platform_device *op, struct fb_info *info,
 			   struct tcx_par *par)
 {
 	if (par->tec)
@@ -362,7 +362,7 @@
 			   info->screen_base, info->fix.smem_len);
 }
 
-static int __devinit tcx_probe(struct of_device *op,
+static int __devinit tcx_probe(struct platform_device *op,
 			       const struct of_device_id *match)
 {
 	struct device_node *dp = op->dev.of_node;
@@ -486,7 +486,7 @@
 	return err;
 }
 
-static int __devexit tcx_remove(struct of_device *op)
+static int __devexit tcx_remove(struct platform_device *op)
 {
 	struct fb_info *info = dev_get_drvdata(&op->dev);
 	struct tcx_par *par = info->par;
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
index 7b8839e..52ec095 100644
--- a/drivers/video/uvesafb.c
+++ b/drivers/video/uvesafb.c
@@ -1977,8 +1977,7 @@
 
 module_exit(uvesafb_exit);
 
-#define param_get_scroll NULL
-static int param_set_scroll(const char *val, struct kernel_param *kp)
+static int param_set_scroll(const char *val, const struct kernel_param *kp)
 {
 	ypan = 0;
 
@@ -1993,7 +1992,9 @@
 
 	return 0;
 }
-
+static struct kernel_param_ops param_ops_scroll = {
+	.set = param_set_scroll,
+};
 #define param_check_scroll(name, p) __param_check(name, p, void)
 
 module_param_named(scroll, ypan, scroll, 0);
diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c
index d31dc96..85d76ec 100644
--- a/drivers/video/vt8623fb.c
+++ b/drivers/video/vt8623fb.c
@@ -726,7 +726,9 @@
 
 	/* Prepare startup mode */
 
+	kparam_block_sysfs_write(mode_option);
 	rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8);
+	kparam_unblock_sysfs_write(mode_option);
 	if (! ((rc == 1) || (rc == 2))) {
 		rc = -EINVAL;
 		dev_err(info->device, "mode %s not found\n", mode_option);
diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
index 29b5daa..0c9ce88 100644
--- a/drivers/video/xilinxfb.c
+++ b/drivers/video/xilinxfb.c
@@ -397,7 +397,7 @@
  */
 
 static int __devinit
-xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match)
+xilinxfb_of_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	const u32 *prop;
 	u32 *p;
@@ -477,7 +477,7 @@
 	return -ENODEV;
 }
 
-static int __devexit xilinxfb_of_remove(struct of_device *op)
+static int __devexit xilinxfb_of_remove(struct platform_device *op)
 {
 	return xilinxfb_release(&op->dev);
 }
diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c
index 30a2512..566343b 100644
--- a/drivers/watchdog/cpwd.c
+++ b/drivers/watchdog/cpwd.c
@@ -526,7 +526,7 @@
 	.release =		cpwd_release,
 };
 
-static int __devinit cpwd_probe(struct of_device *op,
+static int __devinit cpwd_probe(struct platform_device *op,
 				const struct of_device_id *match)
 {
 	struct device_node *options;
@@ -639,7 +639,7 @@
 	goto out;
 }
 
-static int __devexit cpwd_remove(struct of_device *op)
+static int __devexit cpwd_remove(struct platform_device *op)
 {
 	struct cpwd *p = dev_get_drvdata(&op->dev);
 	int i;
diff --git a/drivers/watchdog/gef_wdt.c b/drivers/watchdog/gef_wdt.c
index 1df284f..9c21d19 100644
--- a/drivers/watchdog/gef_wdt.c
+++ b/drivers/watchdog/gef_wdt.c
@@ -260,7 +260,7 @@
 };
 
 
-static int __devinit gef_wdt_probe(struct of_device *dev,
+static int __devinit gef_wdt_probe(struct platform_device *dev,
 	const struct of_device_id *match)
 {
 	int timeout = 10;
diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c
index 4cda64d..8fa213c 100644
--- a/drivers/watchdog/mpc8xxx_wdt.c
+++ b/drivers/watchdog/mpc8xxx_wdt.c
@@ -185,7 +185,7 @@
 	.fops	= &mpc8xxx_wdt_fops,
 };
 
-static int __devinit mpc8xxx_wdt_probe(struct of_device *ofdev,
+static int __devinit mpc8xxx_wdt_probe(struct platform_device *ofdev,
 				       const struct of_device_id *match)
 {
 	int ret;
@@ -238,7 +238,7 @@
 	return ret;
 }
 
-static int __devexit mpc8xxx_wdt_remove(struct of_device *ofdev)
+static int __devexit mpc8xxx_wdt_remove(struct platform_device *ofdev)
 {
 	mpc8xxx_wdt_pr_warn("watchdog removed");
 	del_timer_sync(&wdt_timer);
diff --git a/drivers/watchdog/riowd.c b/drivers/watchdog/riowd.c
index 4082b4a..3faee1a 100644
--- a/drivers/watchdog/riowd.c
+++ b/drivers/watchdog/riowd.c
@@ -172,7 +172,7 @@
 	.fops	= &riowd_fops
 };
 
-static int __devinit riowd_probe(struct of_device *op,
+static int __devinit riowd_probe(struct platform_device *op,
 				 const struct of_device_id *match)
 {
 	struct riowd *p;
@@ -219,7 +219,7 @@
 	return err;
 }
 
-static int __devexit riowd_remove(struct of_device *op)
+static int __devexit riowd_remove(struct platform_device *op)
 {
 	struct riowd *p = dev_get_drvdata(&op->dev);
 
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index 0a88269..60d71e9 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -71,4 +71,9 @@
 	  initializing xenbus and grant_table when running in a Xen HVM
 	  domain. As a consequence this driver is required to run any Xen PV
 	  frontend on Xen HVM.
+
+config SWIOTLB_XEN
+	def_bool y
+	depends on SWIOTLB
+
 endmenu
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index e392fb7..fcaf838 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -11,3 +11,4 @@
 obj-$(CONFIG_XENFS)		+= xenfs/
 obj-$(CONFIG_XEN_SYS_HYPERVISOR)	+= sys-hypervisor.o
 obj-$(CONFIG_XEN_PLATFORM_PCI)	+= platform-pci.o
+obj-$(CONFIG_SWIOTLB_XEN)	+= swiotlb-xen.o
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index 1a0d8c2..500290b 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -85,13 +85,6 @@
 
 static int register_balloon(struct sys_device *sysdev);
 
-/*
- * Protects atomic reservation decrease/increase against concurrent increases.
- * Also protects non-atomic updates of current_pages and driver_pages, and
- * balloon lists.
- */
-static DEFINE_SPINLOCK(balloon_lock);
-
 static struct balloon_stats balloon_stats;
 
 /* We increase/decrease in batches which fit in a page */
@@ -210,7 +203,7 @@
 	if (nr_pages > ARRAY_SIZE(frame_list))
 		nr_pages = ARRAY_SIZE(frame_list);
 
-	spin_lock_irqsave(&balloon_lock, flags);
+	spin_lock_irqsave(&xen_reservation_lock, flags);
 
 	page = balloon_first_page();
 	for (i = 0; i < nr_pages; i++) {
@@ -254,7 +247,7 @@
 	balloon_stats.current_pages += rc;
 
  out:
-	spin_unlock_irqrestore(&balloon_lock, flags);
+	spin_unlock_irqrestore(&xen_reservation_lock, flags);
 
 	return rc < 0 ? rc : rc != nr_pages;
 }
@@ -299,7 +292,7 @@
 	kmap_flush_unused();
 	flush_tlb_all();
 
-	spin_lock_irqsave(&balloon_lock, flags);
+	spin_lock_irqsave(&xen_reservation_lock, flags);
 
 	/* No more mappings: invalidate P2M and add to balloon. */
 	for (i = 0; i < nr_pages; i++) {
@@ -315,7 +308,7 @@
 
 	balloon_stats.current_pages -= nr_pages;
 
-	spin_unlock_irqrestore(&balloon_lock, flags);
+	spin_unlock_irqrestore(&xen_reservation_lock, flags);
 
 	return need_sleep;
 }
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
new file mode 100644
index 0000000..54469c3
--- /dev/null
+++ b/drivers/xen/swiotlb-xen.c
@@ -0,0 +1,515 @@
+/*
+ *  Copyright 2010
+ *  by Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+ *
+ * This code provides a IOMMU for Xen PV guests with PCI passthrough.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 as published by
+ * the Free Software Foundation
+ *
+ * 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.
+ *
+ * PV guests under Xen are running in an non-contiguous memory architecture.
+ *
+ * When PCI pass-through is utilized, this necessitates an IOMMU for
+ * translating bus (DMA) to virtual and vice-versa and also providing a
+ * mechanism to have contiguous pages for device drivers operations (say DMA
+ * operations).
+ *
+ * Specifically, under Xen the Linux idea of pages is an illusion. It
+ * assumes that pages start at zero and go up to the available memory. To
+ * help with that, the Linux Xen MMU provides a lookup mechanism to
+ * translate the page frame numbers (PFN) to machine frame numbers (MFN)
+ * and vice-versa. The MFN are the "real" frame numbers. Furthermore
+ * memory is not contiguous. Xen hypervisor stitches memory for guests
+ * from different pools, which means there is no guarantee that PFN==MFN
+ * and PFN+1==MFN+1. Lastly with Xen 4.0, pages (in debug mode) are
+ * allocated in descending order (high to low), meaning the guest might
+ * never get any MFN's under the 4GB mark.
+ *
+ */
+
+#include <linux/bootmem.h>
+#include <linux/dma-mapping.h>
+#include <xen/swiotlb-xen.h>
+#include <xen/page.h>
+#include <xen/xen-ops.h>
+/*
+ * Used to do a quick range check in swiotlb_tbl_unmap_single and
+ * swiotlb_tbl_sync_single_*, to see if the memory was in fact allocated by this
+ * API.
+ */
+
+static char *xen_io_tlb_start, *xen_io_tlb_end;
+static unsigned long xen_io_tlb_nslabs;
+/*
+ * Quick lookup value of the bus address of the IOTLB.
+ */
+
+u64 start_dma_addr;
+
+static dma_addr_t xen_phys_to_bus(phys_addr_t paddr)
+{
+	return phys_to_machine(XPADDR(paddr)).maddr;;
+}
+
+static phys_addr_t xen_bus_to_phys(dma_addr_t baddr)
+{
+	return machine_to_phys(XMADDR(baddr)).paddr;
+}
+
+static dma_addr_t xen_virt_to_bus(void *address)
+{
+	return xen_phys_to_bus(virt_to_phys(address));
+}
+
+static int check_pages_physically_contiguous(unsigned long pfn,
+					     unsigned int offset,
+					     size_t length)
+{
+	unsigned long next_mfn;
+	int i;
+	int nr_pages;
+
+	next_mfn = pfn_to_mfn(pfn);
+	nr_pages = (offset + length + PAGE_SIZE-1) >> PAGE_SHIFT;
+
+	for (i = 1; i < nr_pages; i++) {
+		if (pfn_to_mfn(++pfn) != ++next_mfn)
+			return 0;
+	}
+	return 1;
+}
+
+static int range_straddles_page_boundary(phys_addr_t p, size_t size)
+{
+	unsigned long pfn = PFN_DOWN(p);
+	unsigned int offset = p & ~PAGE_MASK;
+
+	if (offset + size <= PAGE_SIZE)
+		return 0;
+	if (check_pages_physically_contiguous(pfn, offset, size))
+		return 0;
+	return 1;
+}
+
+static int is_xen_swiotlb_buffer(dma_addr_t dma_addr)
+{
+	unsigned long mfn = PFN_DOWN(dma_addr);
+	unsigned long pfn = mfn_to_local_pfn(mfn);
+	phys_addr_t paddr;
+
+	/* If the address is outside our domain, it CAN
+	 * have the same virtual address as another address
+	 * in our domain. Therefore _only_ check address within our domain.
+	 */
+	if (pfn_valid(pfn)) {
+		paddr = PFN_PHYS(pfn);
+		return paddr >= virt_to_phys(xen_io_tlb_start) &&
+		       paddr < virt_to_phys(xen_io_tlb_end);
+	}
+	return 0;
+}
+
+static int max_dma_bits = 32;
+
+static int
+xen_swiotlb_fixup(void *buf, size_t size, unsigned long nslabs)
+{
+	int i, rc;
+	int dma_bits;
+
+	dma_bits = get_order(IO_TLB_SEGSIZE << IO_TLB_SHIFT) + PAGE_SHIFT;
+
+	i = 0;
+	do {
+		int slabs = min(nslabs - i, (unsigned long)IO_TLB_SEGSIZE);
+
+		do {
+			rc = xen_create_contiguous_region(
+				(unsigned long)buf + (i << IO_TLB_SHIFT),
+				get_order(slabs << IO_TLB_SHIFT),
+				dma_bits);
+		} while (rc && dma_bits++ < max_dma_bits);
+		if (rc)
+			return rc;
+
+		i += slabs;
+	} while (i < nslabs);
+	return 0;
+}
+
+void __init xen_swiotlb_init(int verbose)
+{
+	unsigned long bytes;
+	int rc;
+
+	xen_io_tlb_nslabs = (64 * 1024 * 1024 >> IO_TLB_SHIFT);
+	xen_io_tlb_nslabs = ALIGN(xen_io_tlb_nslabs, IO_TLB_SEGSIZE);
+
+	bytes = xen_io_tlb_nslabs << IO_TLB_SHIFT;
+
+	/*
+	 * Get IO TLB memory from any location.
+	 */
+	xen_io_tlb_start = alloc_bootmem(bytes);
+	if (!xen_io_tlb_start)
+		panic("Cannot allocate SWIOTLB buffer");
+
+	xen_io_tlb_end = xen_io_tlb_start + bytes;
+	/*
+	 * And replace that memory with pages under 4GB.
+	 */
+	rc = xen_swiotlb_fixup(xen_io_tlb_start,
+			       bytes,
+			       xen_io_tlb_nslabs);
+	if (rc)
+		goto error;
+
+	start_dma_addr = xen_virt_to_bus(xen_io_tlb_start);
+	swiotlb_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs, verbose);
+
+	return;
+error:
+	panic("DMA(%d): Failed to exchange pages allocated for DMA with Xen! "\
+	      "We either don't have the permission or you do not have enough"\
+	      "free memory under 4GB!\n", rc);
+}
+
+void *
+xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
+			   dma_addr_t *dma_handle, gfp_t flags)
+{
+	void *ret;
+	int order = get_order(size);
+	u64 dma_mask = DMA_BIT_MASK(32);
+	unsigned long vstart;
+
+	/*
+	* Ignore region specifiers - the kernel's ideas of
+	* pseudo-phys memory layout has nothing to do with the
+	* machine physical layout.  We can't allocate highmem
+	* because we can't return a pointer to it.
+	*/
+	flags &= ~(__GFP_DMA | __GFP_HIGHMEM);
+
+	if (dma_alloc_from_coherent(hwdev, size, dma_handle, &ret))
+		return ret;
+
+	vstart = __get_free_pages(flags, order);
+	ret = (void *)vstart;
+
+	if (hwdev && hwdev->coherent_dma_mask)
+		dma_mask = dma_alloc_coherent_mask(hwdev, flags);
+
+	if (ret) {
+		if (xen_create_contiguous_region(vstart, order,
+						 fls64(dma_mask)) != 0) {
+			free_pages(vstart, order);
+			return NULL;
+		}
+		memset(ret, 0, size);
+		*dma_handle = virt_to_machine(ret).maddr;
+	}
+	return ret;
+}
+EXPORT_SYMBOL_GPL(xen_swiotlb_alloc_coherent);
+
+void
+xen_swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
+			  dma_addr_t dev_addr)
+{
+	int order = get_order(size);
+
+	if (dma_release_from_coherent(hwdev, order, vaddr))
+		return;
+
+	xen_destroy_contiguous_region((unsigned long)vaddr, order);
+	free_pages((unsigned long)vaddr, order);
+}
+EXPORT_SYMBOL_GPL(xen_swiotlb_free_coherent);
+
+
+/*
+ * Map a single buffer of the indicated size for DMA in streaming mode.  The
+ * physical address to use is returned.
+ *
+ * Once the device is given the dma address, the device owns this memory until
+ * either xen_swiotlb_unmap_page or xen_swiotlb_dma_sync_single is performed.
+ */
+dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
+				unsigned long offset, size_t size,
+				enum dma_data_direction dir,
+				struct dma_attrs *attrs)
+{
+	phys_addr_t phys = page_to_phys(page) + offset;
+	dma_addr_t dev_addr = xen_phys_to_bus(phys);
+	void *map;
+
+	BUG_ON(dir == DMA_NONE);
+	/*
+	 * If the address happens to be in the device's DMA window,
+	 * we can safely return the device addr and not worry about bounce
+	 * buffering it.
+	 */
+	if (dma_capable(dev, dev_addr, size) &&
+	    !range_straddles_page_boundary(phys, size) && !swiotlb_force)
+		return dev_addr;
+
+	/*
+	 * Oh well, have to allocate and map a bounce buffer.
+	 */
+	map = swiotlb_tbl_map_single(dev, start_dma_addr, phys, size, dir);
+	if (!map)
+		return DMA_ERROR_CODE;
+
+	dev_addr = xen_virt_to_bus(map);
+
+	/*
+	 * Ensure that the address returned is DMA'ble
+	 */
+	if (!dma_capable(dev, dev_addr, size))
+		panic("map_single: bounce buffer is not DMA'ble");
+
+	return dev_addr;
+}
+EXPORT_SYMBOL_GPL(xen_swiotlb_map_page);
+
+/*
+ * Unmap a single streaming mode DMA translation.  The dma_addr and size must
+ * match what was provided for in a previous xen_swiotlb_map_page call.  All
+ * other usages are undefined.
+ *
+ * After this call, reads by the cpu to the buffer are guaranteed to see
+ * whatever the device wrote there.
+ */
+static void xen_unmap_single(struct device *hwdev, dma_addr_t dev_addr,
+			     size_t size, enum dma_data_direction dir)
+{
+	phys_addr_t paddr = xen_bus_to_phys(dev_addr);
+
+	BUG_ON(dir == DMA_NONE);
+
+	/* NOTE: We use dev_addr here, not paddr! */
+	if (is_xen_swiotlb_buffer(dev_addr)) {
+		swiotlb_tbl_unmap_single(hwdev, phys_to_virt(paddr), size, dir);
+		return;
+	}
+
+	if (dir != DMA_FROM_DEVICE)
+		return;
+
+	/*
+	 * phys_to_virt doesn't work with hihgmem page but we could
+	 * call dma_mark_clean() with hihgmem page here. However, we
+	 * are fine since dma_mark_clean() is null on POWERPC. We can
+	 * make dma_mark_clean() take a physical address if necessary.
+	 */
+	dma_mark_clean(phys_to_virt(paddr), size);
+}
+
+void xen_swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr,
+			    size_t size, enum dma_data_direction dir,
+			    struct dma_attrs *attrs)
+{
+	xen_unmap_single(hwdev, dev_addr, size, dir);
+}
+EXPORT_SYMBOL_GPL(xen_swiotlb_unmap_page);
+
+/*
+ * Make physical memory consistent for a single streaming mode DMA translation
+ * after a transfer.
+ *
+ * If you perform a xen_swiotlb_map_page() but wish to interrogate the buffer
+ * using the cpu, yet do not wish to teardown the dma mapping, you must
+ * call this function before doing so.  At the next point you give the dma
+ * address back to the card, you must first perform a
+ * xen_swiotlb_dma_sync_for_device, and then the device again owns the buffer
+ */
+static void
+xen_swiotlb_sync_single(struct device *hwdev, dma_addr_t dev_addr,
+			size_t size, enum dma_data_direction dir,
+			enum dma_sync_target target)
+{
+	phys_addr_t paddr = xen_bus_to_phys(dev_addr);
+
+	BUG_ON(dir == DMA_NONE);
+
+	/* NOTE: We use dev_addr here, not paddr! */
+	if (is_xen_swiotlb_buffer(dev_addr)) {
+		swiotlb_tbl_sync_single(hwdev, phys_to_virt(paddr), size, dir,
+				       target);
+		return;
+	}
+
+	if (dir != DMA_FROM_DEVICE)
+		return;
+
+	dma_mark_clean(phys_to_virt(paddr), size);
+}
+
+void
+xen_swiotlb_sync_single_for_cpu(struct device *hwdev, dma_addr_t dev_addr,
+				size_t size, enum dma_data_direction dir)
+{
+	xen_swiotlb_sync_single(hwdev, dev_addr, size, dir, SYNC_FOR_CPU);
+}
+EXPORT_SYMBOL_GPL(xen_swiotlb_sync_single_for_cpu);
+
+void
+xen_swiotlb_sync_single_for_device(struct device *hwdev, dma_addr_t dev_addr,
+				   size_t size, enum dma_data_direction dir)
+{
+	xen_swiotlb_sync_single(hwdev, dev_addr, size, dir, SYNC_FOR_DEVICE);
+}
+EXPORT_SYMBOL_GPL(xen_swiotlb_sync_single_for_device);
+
+/*
+ * Map a set of buffers described by scatterlist in streaming mode for DMA.
+ * This is the scatter-gather version of the above xen_swiotlb_map_page
+ * interface.  Here the scatter gather list elements are each tagged with the
+ * appropriate dma address and length.  They are obtained via
+ * sg_dma_{address,length}(SG).
+ *
+ * NOTE: An implementation may be able to use a smaller number of
+ *       DMA address/length pairs than there are SG table elements.
+ *       (for example via virtual mapping capabilities)
+ *       The routine returns the number of addr/length pairs actually
+ *       used, at most nents.
+ *
+ * Device ownership issues as mentioned above for xen_swiotlb_map_page are the
+ * same here.
+ */
+int
+xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
+			 int nelems, enum dma_data_direction dir,
+			 struct dma_attrs *attrs)
+{
+	struct scatterlist *sg;
+	int i;
+
+	BUG_ON(dir == DMA_NONE);
+
+	for_each_sg(sgl, sg, nelems, i) {
+		phys_addr_t paddr = sg_phys(sg);
+		dma_addr_t dev_addr = xen_phys_to_bus(paddr);
+
+		if (swiotlb_force ||
+		    !dma_capable(hwdev, dev_addr, sg->length) ||
+		    range_straddles_page_boundary(paddr, sg->length)) {
+			void *map = swiotlb_tbl_map_single(hwdev,
+							   start_dma_addr,
+							   sg_phys(sg),
+							   sg->length, dir);
+			if (!map) {
+				/* Don't panic here, we expect map_sg users
+				   to do proper error handling. */
+				xen_swiotlb_unmap_sg_attrs(hwdev, sgl, i, dir,
+							   attrs);
+				sgl[0].dma_length = 0;
+				return DMA_ERROR_CODE;
+			}
+			sg->dma_address = xen_virt_to_bus(map);
+		} else
+			sg->dma_address = dev_addr;
+		sg->dma_length = sg->length;
+	}
+	return nelems;
+}
+EXPORT_SYMBOL_GPL(xen_swiotlb_map_sg_attrs);
+
+int
+xen_swiotlb_map_sg(struct device *hwdev, struct scatterlist *sgl, int nelems,
+		   enum dma_data_direction dir)
+{
+	return xen_swiotlb_map_sg_attrs(hwdev, sgl, nelems, dir, NULL);
+}
+EXPORT_SYMBOL_GPL(xen_swiotlb_map_sg);
+
+/*
+ * Unmap a set of streaming mode DMA translations.  Again, cpu read rules
+ * concerning calls here are the same as for swiotlb_unmap_page() above.
+ */
+void
+xen_swiotlb_unmap_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
+			   int nelems, enum dma_data_direction dir,
+			   struct dma_attrs *attrs)
+{
+	struct scatterlist *sg;
+	int i;
+
+	BUG_ON(dir == DMA_NONE);
+
+	for_each_sg(sgl, sg, nelems, i)
+		xen_unmap_single(hwdev, sg->dma_address, sg->dma_length, dir);
+
+}
+EXPORT_SYMBOL_GPL(xen_swiotlb_unmap_sg_attrs);
+
+void
+xen_swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sgl, int nelems,
+		     enum dma_data_direction dir)
+{
+	return xen_swiotlb_unmap_sg_attrs(hwdev, sgl, nelems, dir, NULL);
+}
+EXPORT_SYMBOL_GPL(xen_swiotlb_unmap_sg);
+
+/*
+ * Make physical memory consistent for a set of streaming mode DMA translations
+ * after a transfer.
+ *
+ * The same as swiotlb_sync_single_* but for a scatter-gather list, same rules
+ * and usage.
+ */
+static void
+xen_swiotlb_sync_sg(struct device *hwdev, struct scatterlist *sgl,
+		    int nelems, enum dma_data_direction dir,
+		    enum dma_sync_target target)
+{
+	struct scatterlist *sg;
+	int i;
+
+	for_each_sg(sgl, sg, nelems, i)
+		xen_swiotlb_sync_single(hwdev, sg->dma_address,
+					sg->dma_length, dir, target);
+}
+
+void
+xen_swiotlb_sync_sg_for_cpu(struct device *hwdev, struct scatterlist *sg,
+			    int nelems, enum dma_data_direction dir)
+{
+	xen_swiotlb_sync_sg(hwdev, sg, nelems, dir, SYNC_FOR_CPU);
+}
+EXPORT_SYMBOL_GPL(xen_swiotlb_sync_sg_for_cpu);
+
+void
+xen_swiotlb_sync_sg_for_device(struct device *hwdev, struct scatterlist *sg,
+			       int nelems, enum dma_data_direction dir)
+{
+	xen_swiotlb_sync_sg(hwdev, sg, nelems, dir, SYNC_FOR_DEVICE);
+}
+EXPORT_SYMBOL_GPL(xen_swiotlb_sync_sg_for_device);
+
+int
+xen_swiotlb_dma_mapping_error(struct device *hwdev, dma_addr_t dma_addr)
+{
+	return !dma_addr;
+}
+EXPORT_SYMBOL_GPL(xen_swiotlb_dma_mapping_error);
+
+/*
+ * Return whether the given device DMA address mask can be supported
+ * properly.  For example, if your device can only drive the low 24-bits
+ * during bus mastering, then you would pass 0x00ffffff as the mask to
+ * this function.
+ */
+int
+xen_swiotlb_dma_supported(struct device *hwdev, u64 mask)
+{
+	return xen_virt_to_bus(xen_io_tlb_end - 1) <= mask;
+}
+EXPORT_SYMBOL_GPL(xen_swiotlb_dma_supported);
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 8679089..c6c93f1 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -752,12 +752,6 @@
 #define dbgprintk(FMT,...) \
 	printk("[%-6.6s] "FMT"\n", current->comm ,##__VA_ARGS__)
 
-/* make sure we maintain the format strings, even when debugging is disabled */
-static inline __attribute__((format(printf,1,2)))
-void _dbprintk(const char *fmt, ...)
-{
-}
-
 #define kenter(FMT,...)	dbgprintk("==> %s("FMT")",__func__ ,##__VA_ARGS__)
 #define kleave(FMT,...)	dbgprintk("<== %s()"FMT"",__func__ ,##__VA_ARGS__)
 #define kdebug(FMT,...)	dbgprintk("    "FMT ,##__VA_ARGS__)
@@ -792,9 +786,9 @@
 } while (0)
 
 #else
-#define _enter(FMT,...)	_dbprintk("==> %s("FMT")",__func__ ,##__VA_ARGS__)
-#define _leave(FMT,...)	_dbprintk("<== %s()"FMT"",__func__ ,##__VA_ARGS__)
-#define _debug(FMT,...)	_dbprintk("    "FMT ,##__VA_ARGS__)
+#define _enter(FMT,...)	no_printk("==> %s("FMT")",__func__ ,##__VA_ARGS__)
+#define _leave(FMT,...)	no_printk("<== %s()"FMT"",__func__ ,##__VA_ARGS__)
+#define _debug(FMT,...)	no_printk("    "FMT ,##__VA_ARGS__)
 #endif
 
 /*
diff --git a/fs/cachefiles/internal.h b/fs/cachefiles/internal.h
index a8cd821..bd6bc1b 100644
--- a/fs/cachefiles/internal.h
+++ b/fs/cachefiles/internal.h
@@ -267,13 +267,6 @@
 #define dbgprintk(FMT, ...) \
 	printk(KERN_DEBUG "[%-6.6s] "FMT"\n", current->comm, ##__VA_ARGS__)
 
-/* make sure we maintain the format strings, even when debugging is disabled */
-static inline void _dbprintk(const char *fmt, ...)
-	__attribute__((format(printf, 1, 2)));
-static inline void _dbprintk(const char *fmt, ...)
-{
-}
-
 #define kenter(FMT, ...) dbgprintk("==> %s("FMT")", __func__, ##__VA_ARGS__)
 #define kleave(FMT, ...) dbgprintk("<== %s()"FMT"", __func__, ##__VA_ARGS__)
 #define kdebug(FMT, ...) dbgprintk(FMT, ##__VA_ARGS__)
@@ -304,9 +297,9 @@
 } while (0)
 
 #else
-#define _enter(FMT, ...) _dbprintk("==> %s("FMT")", __func__, ##__VA_ARGS__)
-#define _leave(FMT, ...) _dbprintk("<== %s()"FMT"", __func__, ##__VA_ARGS__)
-#define _debug(FMT, ...) _dbprintk(FMT, ##__VA_ARGS__)
+#define _enter(FMT, ...) no_printk("==> %s("FMT")", __func__, ##__VA_ARGS__)
+#define _leave(FMT, ...) no_printk("<== %s()"FMT"", __func__, ##__VA_ARGS__)
+#define _debug(FMT, ...) no_printk(FMT, ##__VA_ARGS__)
 #endif
 
 #if 1 /* defined(__KDEBUGALL) */
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 2f76c4a..7d9d06b 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -68,7 +68,7 @@
  */
 int writeback_in_progress(struct backing_dev_info *bdi)
 {
-	return !list_empty(&bdi->work_list);
+	return test_bit(BDI_writeback_running, &bdi->state);
 }
 
 static void bdi_queue_work(struct backing_dev_info *bdi,
@@ -249,10 +249,18 @@
 
 /*
  * Queue all expired dirty inodes for io, eldest first.
+ * Before
+ *         newly dirtied     b_dirty    b_io    b_more_io
+ *         =============>    gf         edc     BA
+ * After
+ *         newly dirtied     b_dirty    b_io    b_more_io
+ *         =============>    g          fBAedc
+ *                                           |
+ *                                           +--> dequeue for IO
  */
 static void queue_io(struct bdi_writeback *wb, unsigned long *older_than_this)
 {
-	list_splice_init(&wb->b_more_io, wb->b_io.prev);
+	list_splice_init(&wb->b_more_io, &wb->b_io);
 	move_expired_inodes(&wb->b_dirty, &wb->b_io, older_than_this);
 }
 
@@ -363,62 +371,35 @@
 	spin_lock(&inode_lock);
 	inode->i_state &= ~I_SYNC;
 	if (!(inode->i_state & I_FREEING)) {
-		if ((inode->i_state & I_DIRTY_PAGES) && wbc->for_kupdate) {
-			/*
-			 * More pages get dirtied by a fast dirtier.
-			 */
-			goto select_queue;
-		} else if (inode->i_state & I_DIRTY) {
-			/*
-			 * At least XFS will redirty the inode during the
-			 * writeback (delalloc) and on io completion (isize).
-			 */
-			redirty_tail(inode);
-		} else if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) {
+		if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) {
 			/*
 			 * We didn't write back all the pages.  nfs_writepages()
-			 * sometimes bales out without doing anything. Redirty
-			 * the inode; Move it from b_io onto b_more_io/b_dirty.
+			 * sometimes bales out without doing anything.
 			 */
-			/*
-			 * akpm: if the caller was the kupdate function we put
-			 * this inode at the head of b_dirty so it gets first
-			 * consideration.  Otherwise, move it to the tail, for
-			 * the reasons described there.  I'm not really sure
-			 * how much sense this makes.  Presumably I had a good
-			 * reasons for doing it this way, and I'd rather not
-			 * muck with it at present.
-			 */
-			if (wbc->for_kupdate) {
+			inode->i_state |= I_DIRTY_PAGES;
+			if (wbc->nr_to_write <= 0) {
 				/*
-				 * For the kupdate function we move the inode
-				 * to b_more_io so it will get more writeout as
-				 * soon as the queue becomes uncongested.
+				 * slice used up: queue for next turn
 				 */
-				inode->i_state |= I_DIRTY_PAGES;
-select_queue:
-				if (wbc->nr_to_write <= 0) {
-					/*
-					 * slice used up: queue for next turn
-					 */
-					requeue_io(inode);
-				} else {
-					/*
-					 * somehow blocked: retry later
-					 */
-					redirty_tail(inode);
-				}
+				requeue_io(inode);
 			} else {
 				/*
-				 * Otherwise fully redirty the inode so that
-				 * other inodes on this superblock will get some
-				 * writeout.  Otherwise heavy writing to one
-				 * file would indefinitely suspend writeout of
-				 * all the other files.
+				 * Writeback blocked by something other than
+				 * congestion. Delay the inode for some time to
+				 * avoid spinning on the CPU (100% iowait)
+				 * retrying writeback of the dirty page/inode
+				 * that cannot be performed immediately.
 				 */
-				inode->i_state |= I_DIRTY_PAGES;
 				redirty_tail(inode);
 			}
+		} else if (inode->i_state & I_DIRTY) {
+			/*
+			 * Filesystems can dirty the inode during writeback
+			 * operations, such as delayed allocation during
+			 * submission or metadata updates after data IO
+			 * completion.
+			 */
+			redirty_tail(inode);
 		} else if (atomic_read(&inode->i_count)) {
 			/*
 			 * The inode is clean, inuse
@@ -590,7 +571,7 @@
 {
 	unsigned long background_thresh, dirty_thresh;
 
-	get_dirty_limits(&background_thresh, &dirty_thresh, NULL, NULL);
+	global_dirty_limits(&background_thresh, &dirty_thresh);
 
 	return (global_page_state(NR_FILE_DIRTY) +
 		global_page_state(NR_UNSTABLE_NFS) >= background_thresh);
@@ -759,6 +740,7 @@
 	struct wb_writeback_work *work;
 	long wrote = 0;
 
+	set_bit(BDI_writeback_running, &wb->bdi->state);
 	while ((work = get_next_work_item(bdi)) != NULL) {
 		/*
 		 * Override sync mode, in case we must wait for completion
@@ -785,6 +767,7 @@
 	 * Check for periodic writeback, kupdated() style
 	 */
 	wrote += wb_check_old_data_flush(wb);
+	clear_bit(BDI_writeback_running, &wb->bdi->state);
 
 	return wrote;
 }
diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h
index 6a02644..f6aad48 100644
--- a/fs/fscache/internal.h
+++ b/fs/fscache/internal.h
@@ -321,17 +321,11 @@
 #define dbgprintk(FMT, ...) \
 	printk(KERN_DEBUG "[%-6.6s] "FMT"\n", current->comm, ##__VA_ARGS__)
 
-/* make sure we maintain the format strings, even when debugging is disabled */
-static inline __attribute__((format(printf, 1, 2)))
-void _dbprintk(const char *fmt, ...)
-{
-}
-
 #define kenter(FMT, ...) dbgprintk("==> %s("FMT")", __func__, ##__VA_ARGS__)
 #define kleave(FMT, ...) dbgprintk("<== %s()"FMT"", __func__, ##__VA_ARGS__)
 #define kdebug(FMT, ...) dbgprintk(FMT, ##__VA_ARGS__)
 
-#define kjournal(FMT, ...) _dbprintk(FMT, ##__VA_ARGS__)
+#define kjournal(FMT, ...) no_printk(FMT, ##__VA_ARGS__)
 
 #ifdef __KDEBUG
 #define _enter(FMT, ...) kenter(FMT, ##__VA_ARGS__)
@@ -358,9 +352,9 @@
 } while (0)
 
 #else
-#define _enter(FMT, ...) _dbprintk("==> %s("FMT")", __func__, ##__VA_ARGS__)
-#define _leave(FMT, ...) _dbprintk("<== %s()"FMT"", __func__, ##__VA_ARGS__)
-#define _debug(FMT, ...) _dbprintk(FMT, ##__VA_ARGS__)
+#define _enter(FMT, ...) no_printk("==> %s("FMT")", __func__, ##__VA_ARGS__)
+#define _leave(FMT, ...) no_printk("<== %s()"FMT"", __func__, ##__VA_ARGS__)
+#define _debug(FMT, ...) no_printk(FMT, ##__VA_ARGS__)
 #endif
 
 /*
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index 36dfdae..e17b49e 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -45,7 +45,7 @@
 unsigned short nfs_callback_tcpport6;
 #define NFS_CALLBACK_MAXPORTNR (65535U)
 
-static int param_set_portnr(const char *val, struct kernel_param *kp)
+static int param_set_portnr(const char *val, const struct kernel_param *kp)
 {
 	unsigned long num;
 	int ret;
@@ -58,11 +58,10 @@
 	*((unsigned int *)kp->arg) = num;
 	return 0;
 }
-
-static int param_get_portnr(char *buffer, struct kernel_param *kp)
-{
-	return param_get_uint(buffer, kp);
-}
+static struct kernel_param_ops param_ops_portnr = {
+	.set = param_set_portnr,
+	.get = param_get_uint,
+};
 #define param_check_portnr(name, p) __param_check(name, p, unsigned int);
 
 module_param_named(callback_tcpport, nfs_callback_set_tcpport, portnr, 0644);
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index e5039a2..103f08a 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -148,13 +148,17 @@
 #define ACPI_ALLOCATE_ZEROED(a) acpi_os_allocate_zeroed(a)
 #define ACPI_FREE(a)            kfree(a)
 
-/* Used within ACPICA to show where it is safe to preempt execution */
-#include <linux/hardirq.h>
+#ifndef CONFIG_PREEMPT
+/*
+ * Used within ACPICA to show where it is safe to preempt execution
+ * when CONFIG_PREEMPT=n
+ */
 #define ACPI_PREEMPTION_POINT() \
 	do { \
-		if (!in_atomic_preempt_off() && !irqs_disabled()) \
+		if (!irqs_disabled()) \
 			cond_resched(); \
 	} while (0)
+#endif
 
 #endif /* __KERNEL__ */
 
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index e2a4da7..2a512bc 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -1075,7 +1075,6 @@
 	return ((dev->driver->driver_features & feature) ? 1 : 0);
 }
 
-
 static inline int drm_dev_to_irq(struct drm_device *dev)
 {
 	if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE))
@@ -1084,11 +1083,22 @@
 		return dev->pdev->irq;
 }
 
-#ifdef __alpha__
-#define drm_get_pci_domain(dev) dev->hose->index
-#else
-#define drm_get_pci_domain(dev) 0
-#endif
+static inline int drm_get_pci_domain(struct drm_device *dev)
+{
+	if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE))
+		return 0;
+
+#ifndef __alpha__
+	/* For historical reasons, drm_get_pci_domain() is busticated
+	 * on most archs and has to remain so for userspace interface
+	 * < 1.4, except on alpha which was right from the beginning
+	 */
+	if (dev->if_version < 0x10004)
+		return 0;
+#endif /* __alpha__ */
+
+	return pci_domain_nr(dev->pdev->bus);
+}
 
 #if __OS_HAS_AGP
 static inline int drm_core_has_AGP(struct drm_device *dev)
diff --git a/include/drm/drm_core.h b/include/drm/drm_core.h
index 3167390..4e75238 100644
--- a/include/drm/drm_core.h
+++ b/include/drm/drm_core.h
@@ -27,7 +27,7 @@
 #define CORE_DATE		"20060810"
 
 #define DRM_IF_MAJOR	1
-#define DRM_IF_MINOR	3
+#define DRM_IF_MINOR	4
 
 #define CORE_MAJOR	1
 #define CORE_MINOR	1
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index c707270..c9f3cc5 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -189,49 +189,16 @@
  */
 struct drm_display_info {
 	char name[DRM_DISPLAY_INFO_LEN];
-	/* Input info */
-	bool serration_vsync;
-	bool sync_on_green;
-	bool composite_sync;
-	bool separate_syncs;
-	bool blank_to_black;
-	unsigned char video_level;
-	bool digital;
+
 	/* Physical size */
         unsigned int width_mm;
 	unsigned int height_mm;
 
-	/* Display parameters */
-	unsigned char gamma; /* FIXME: storage format */
-	bool gtf_supported;
-	bool standard_color;
-	enum {
-		monochrome = 0,
-		rgb,
-		other,
-		unknown,
-	} display_type;
-	bool active_off_supported;
-	bool suspend_supported;
-	bool standby_supported;
-
-	/* Color info FIXME: storage format */
-	unsigned short redx, redy;
-	unsigned short greenx, greeny;
-	unsigned short bluex, bluey;
-	unsigned short whitex, whitey;
-
 	/* Clock limits FIXME: storage format */
 	unsigned int min_vfreq, max_vfreq;
 	unsigned int min_hfreq, max_hfreq;
 	unsigned int pixel_clock;
 
-	/* White point indices FIXME: storage format */
-	unsigned int wpx1, wpy1;
-	unsigned int wpgamma1;
-	unsigned int wpx2, wpy2;
-	unsigned int wpgamma2;
-
 	enum subpixel_order subpixel_order;
 
 	char *raw_edid; /* if any */
@@ -342,7 +309,7 @@
 
 	/* Set gamma on the CRTC */
 	void (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
-			  uint32_t size);
+			  uint32_t start, uint32_t size);
 	/* Object destroy routine */
 	void (*destroy)(struct drm_crtc *crtc);
 
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index 39e2cc5..5881fad 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -28,6 +28,12 @@
 #define EDID_LENGTH 128
 #define DDC_ADDR 0x50
 
+#define CEA_EXT	    0x02
+#define VTB_EXT	    0x10
+#define DI_EXT	    0x40
+#define LS_EXT	    0x50
+#define MI_EXT	    0x60
+
 struct est_timings {
 	u8 t1;
 	u8 t2;
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
index 7628219..35b0074 100644
--- a/include/linux/backing-dev.h
+++ b/include/linux/backing-dev.h
@@ -31,6 +31,7 @@
 	BDI_async_congested,	/* The async (write) queue is getting full */
 	BDI_sync_congested,	/* The sync queue is getting full */
 	BDI_registered,		/* bdi_register() was done */
+	BDI_writeback_running,	/* Writeback is in progress */
 	BDI_unused,		/* Available bits start here */
 };
 
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 5369177..ca83a97 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -150,6 +150,7 @@
 	__REQ_FLUSH,		/* request for cache flush */
 	__REQ_IO_STAT,		/* account I/O stat */
 	__REQ_MIXED_MERGE,	/* merge of different types, fail separately */
+	__REQ_SECURE,		/* secure discard (used with __REQ_DISCARD) */
 	__REQ_NR_BITS,		/* stops here */
 };
 
@@ -190,5 +191,6 @@
 #define REQ_FLUSH		(1 << __REQ_FLUSH)
 #define REQ_IO_STAT		(1 << __REQ_IO_STAT)
 #define REQ_MIXED_MERGE		(1 << __REQ_MIXED_MERGE)
+#define REQ_SECURE		(1 << __REQ_SECURE)
 
 #endif /* __LINUX_BLK_TYPES_H */
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 89c855c..2c54906 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -389,6 +389,7 @@
 #define QUEUE_FLAG_DISCARD     16	/* supports DISCARD */
 #define QUEUE_FLAG_NOXMERGES   17	/* No extended merges */
 #define QUEUE_FLAG_ADD_RANDOM  18	/* Contributes to random pool */
+#define QUEUE_FLAG_SECDISCARD  19	/* supports SECDISCARD */
 
 #define QUEUE_FLAG_DEFAULT	((1 << QUEUE_FLAG_IO_STAT) |		\
 				 (1 << QUEUE_FLAG_CLUSTER) |		\
@@ -524,6 +525,8 @@
 #define blk_queue_stackable(q)	\
 	test_bit(QUEUE_FLAG_STACKABLE, &(q)->queue_flags)
 #define blk_queue_discard(q)	test_bit(QUEUE_FLAG_DISCARD, &(q)->queue_flags)
+#define blk_queue_secdiscard(q)	(blk_queue_discard(q) && \
+	test_bit(QUEUE_FLAG_SECDISCARD, &(q)->queue_flags))
 
 #define blk_noretry_request(rq) \
 	((rq)->cmd_flags & (REQ_FAILFAST_DEV|REQ_FAILFAST_TRANSPORT| \
@@ -918,10 +921,12 @@
 }
 enum{
 	BLKDEV_WAIT,	/* wait for completion */
-	BLKDEV_BARRIER,	/*issue request with barrier */
+	BLKDEV_BARRIER,	/* issue request with barrier */
+	BLKDEV_SECURE,	/* secure discard */
 };
 #define BLKDEV_IFL_WAIT		(1 << BLKDEV_WAIT)
 #define BLKDEV_IFL_BARRIER	(1 << BLKDEV_BARRIER)
+#define BLKDEV_IFL_SECURE	(1 << BLKDEV_SECURE)
 extern int blkdev_issue_flush(struct block_device *, gfp_t, sector_t *,
 			unsigned long);
 extern int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 267d026..7a0625e 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -174,6 +174,7 @@
  */
 #define DISCARD_NOBARRIER	(WRITE | REQ_DISCARD)
 #define DISCARD_BARRIER		(WRITE | REQ_DISCARD | REQ_HARDBARRIER)
+#define DISCARD_SECURE		(DISCARD_NOBARRIER | REQ_SECURE)
 
 #define SEL_IN		1
 #define SEL_OUT		2
@@ -317,6 +318,7 @@
 #define BLKALIGNOFF _IO(0x12,122)
 #define BLKPBSZGET _IO(0x12,123)
 #define BLKDISCARDZEROES _IO(0x12,124)
+#define BLKSECDISCARD _IO(0x12,125)
 
 #define BMAP_IOCTL 1		/* obsolete - kept for compatibility */
 #define FIBMAP	   _IO(0x00,1)	/* bmap access */
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index 78b4bc6..f479700 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -2,6 +2,7 @@
 #define _LINUX_HUGETLB_H
 
 #include <linux/fs.h>
+#include <linux/hugetlb_inline.h>
 
 struct ctl_table;
 struct user_struct;
@@ -14,11 +15,6 @@
 
 int PageHuge(struct page *page);
 
-static inline int is_vm_hugetlb_page(struct vm_area_struct *vma)
-{
-	return vma->vm_flags & VM_HUGETLB;
-}
-
 void reset_vma_resv_huge_pages(struct vm_area_struct *vma);
 int hugetlb_sysctl_handler(struct ctl_table *, int, void __user *, size_t *, loff_t *);
 int hugetlb_overcommit_handler(struct ctl_table *, int, void __user *, size_t *, loff_t *);
@@ -47,6 +43,7 @@
 						struct vm_area_struct *vma,
 						int acctflags);
 void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed);
+void __isolate_hwpoisoned_huge_page(struct page *page);
 
 extern unsigned long hugepages_treat_as_movable;
 extern const unsigned long hugetlb_zero, hugetlb_infinity;
@@ -77,11 +74,6 @@
 	return 0;
 }
 
-static inline int is_vm_hugetlb_page(struct vm_area_struct *vma)
-{
-	return 0;
-}
-
 static inline void reset_vma_resv_huge_pages(struct vm_area_struct *vma)
 {
 }
@@ -108,6 +100,8 @@
 #define is_hugepage_only_range(mm, addr, len)	0
 #define hugetlb_free_pgd_range(tlb, addr, end, floor, ceiling) ({BUG(); 0; })
 #define hugetlb_fault(mm, vma, addr, flags)	({ BUG(); 0; })
+#define huge_pte_offset(mm, address)	0
+#define __isolate_hwpoisoned_huge_page(page)	0
 
 #define hugetlb_change_protection(vma, address, end, newprot)
 
diff --git a/include/linux/hugetlb_inline.h b/include/linux/hugetlb_inline.h
new file mode 100644
index 0000000..6931489
--- /dev/null
+++ b/include/linux/hugetlb_inline.h
@@ -0,0 +1,22 @@
+#ifndef _LINUX_HUGETLB_INLINE_H
+#define _LINUX_HUGETLB_INLINE_H
+
+#ifdef CONFIG_HUGETLB_PAGE
+
+#include <linux/mm.h>
+
+static inline int is_vm_hugetlb_page(struct vm_area_struct *vma)
+{
+	return vma->vm_flags & VM_HUGETLB;
+}
+
+#else
+
+static inline int is_vm_hugetlb_page(struct vm_area_struct *vma)
+{
+	return 0;
+}
+
+#endif
+
+#endif
diff --git a/include/linux/i2c-mux.h b/include/linux/i2c-mux.h
new file mode 100644
index 0000000..34536ef
--- /dev/null
+++ b/include/linux/i2c-mux.h
@@ -0,0 +1,46 @@
+/*
+ *
+ * i2c-mux.h - functions for the i2c-bus mux support
+ *
+ * Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it>
+ * Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it>
+ * Michael Lawnick <michael.lawnick.ext@nsn.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _LINUX_I2C_MUX_H
+#define _LINUX_I2C_MUX_H
+
+#ifdef __KERNEL__
+
+/*
+ * Called to create a i2c bus on a multiplexed bus segment.
+ * The mux_dev and chan_id parameters are passed to the select
+ * and deselect callback functions to perform hardware-specific
+ * mux control.
+ */
+struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
+				void *mux_dev, u32 force_nr, u32 chan_id,
+				int (*select) (struct i2c_adapter *,
+					       void *mux_dev, u32 chan_id),
+				int (*deselect) (struct i2c_adapter *,
+						 void *mux_dev, u32 chan_id));
+
+int i2c_del_mux_adapter(struct i2c_adapter *adap);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_I2C_MUX_H */
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 38dd402..4bae0b7 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -37,6 +37,7 @@
 #include <linux/of.h>		/* for struct device_node */
 
 extern struct bus_type i2c_bus_type;
+extern struct device_type i2c_adapter_type;
 
 /* --- General options ------------------------------------------------	*/
 
@@ -284,12 +285,18 @@
 
 /* If you don't know the exact address of an I2C device, use this variant
  * instead, which can probe for device presence in a list of possible
- * addresses.
+ * addresses. The "probe" callback function is optional. If it is provided,
+ * it must return 1 on successful probe, 0 otherwise. If it is not provided,
+ * a default probing method is used.
  */
 extern struct i2c_client *
 i2c_new_probed_device(struct i2c_adapter *adap,
 		      struct i2c_board_info *info,
-		      unsigned short const *addr_list);
+		      unsigned short const *addr_list,
+		      int (*probe)(struct i2c_adapter *, unsigned short addr));
+
+/* Common custom probe functions */
+extern int i2c_probe_func_quick_read(struct i2c_adapter *, unsigned short addr);
 
 /* For devices that use several addresses, use i2c_new_dummy() to make
  * client handles for the extra addresses.
@@ -362,6 +369,7 @@
 	char name[48];
 	struct completion dev_released;
 
+	struct mutex userspace_clients_lock;
 	struct list_head userspace_clients;
 };
 #define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
@@ -376,23 +384,16 @@
 	dev_set_drvdata(&dev->dev, data);
 }
 
-/**
- * i2c_lock_adapter - Prevent access to an I2C bus segment
- * @adapter: Target I2C bus segment
- */
-static inline void i2c_lock_adapter(struct i2c_adapter *adapter)
+static inline int i2c_parent_is_i2c_adapter(const struct i2c_adapter *adapter)
 {
-	rt_mutex_lock(&adapter->bus_lock);
+	return adapter->dev.parent != NULL
+		&& adapter->dev.parent->bus == &i2c_bus_type
+		&& adapter->dev.parent->type == &i2c_adapter_type;
 }
 
-/**
- * i2c_unlock_adapter - Reauthorize access to an I2C bus segment
- * @adapter: Target I2C bus segment
- */
-static inline void i2c_unlock_adapter(struct i2c_adapter *adapter)
-{
-	rt_mutex_unlock(&adapter->bus_lock);
-}
+/* Adapter locking functions, exported for shared pin cases */
+void i2c_lock_adapter(struct i2c_adapter *);
+void i2c_unlock_adapter(struct i2c_adapter *);
 
 /*flags for the client struct: */
 #define I2C_CLIENT_PEC	0x04		/* Use Packet Error Checking */
diff --git a/include/linux/i2c/pca954x.h b/include/linux/i2c/pca954x.h
new file mode 100644
index 0000000..28f1f8d
--- /dev/null
+++ b/include/linux/i2c/pca954x.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * pca954x.h - I2C multiplexer/switch support
+ *
+ * Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it>
+ * Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it>
+ * Michael Lawnick <michael.lawnick.ext@nsn.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#ifndef _LINUX_I2C_PCA954X_H
+#define _LINUX_I2C_PCA954X_H
+
+/* Platform data for the PCA954x I2C multiplexers */
+
+/* Per channel initialisation data:
+ * @adap_id: bus number for the adapter. 0 = don't care
+ * @deselect_on_exit: set this entry to 1, if your H/W needs deselection
+ *                    of this channel after transaction.
+ *
+ */
+struct pca954x_platform_mode {
+	int		adap_id;
+	unsigned int	deselect_on_exit:1;
+};
+
+/* Per mux/switch data, used with i2c_register_board_info */
+struct pca954x_platform_data {
+	struct pca954x_platform_mode *modes;
+	int num_modes;
+};
+
+#endif /* _LINUX_I2C_PCA954X_H */
diff --git a/include/linux/io-mapping.h b/include/linux/io-mapping.h
index e0ea40f..0a6b3d5 100644
--- a/include/linux/io-mapping.h
+++ b/include/linux/io-mapping.h
@@ -22,7 +22,6 @@
 #include <linux/slab.h>
 #include <asm/io.h>
 #include <asm/page.h>
-#include <asm/iomap.h>
 
 /*
  * The io_mapping mechanism provides an abstraction for mapping
@@ -33,6 +32,8 @@
 
 #ifdef CONFIG_HAVE_ATOMIC_IOMAP
 
+#include <asm/iomap.h>
+
 struct io_mapping {
 	resource_size_t base;
 	unsigned long size;
diff --git a/include/linux/jz4740-adc.h b/include/linux/jz4740-adc.h
new file mode 100644
index 0000000..9053f95
--- /dev/null
+++ b/include/linux/jz4740-adc.h
@@ -0,0 +1,32 @@
+
+#ifndef __LINUX_JZ4740_ADC
+#define __LINUX_JZ4740_ADC
+
+#include <linux/device.h>
+
+/*
+ * jz4740_adc_set_config - Configure a JZ4740 adc device
+ * @dev: Pointer to a jz4740-adc device
+ * @mask: Mask for the config value to be set
+ * @val: Value to be set
+ *
+ * This function can be used by the JZ4740 ADC mfd cells to configure their
+ * options in the shared config register.
+*/
+int jz4740_adc_set_config(struct device *dev, uint32_t mask, uint32_t val);
+
+#define JZ_ADC_CONFIG_SPZZ		BIT(31)
+#define JZ_ADC_CONFIG_EX_IN		BIT(30)
+#define JZ_ADC_CONFIG_DNUM_MASK		(0x7 << 16)
+#define JZ_ADC_CONFIG_DMA_ENABLE	BIT(15)
+#define JZ_ADC_CONFIG_XYZ_MASK		(0x2 << 13)
+#define JZ_ADC_CONFIG_SAMPLE_NUM_MASK	(0x7 << 10)
+#define JZ_ADC_CONFIG_CLKDIV_MASK	(0xf << 5)
+#define JZ_ADC_CONFIG_BAT_MB		BIT(4)
+
+#define JZ_ADC_CONFIG_DNUM(dnum)	((dnum) << 16)
+#define JZ_ADC_CONFIG_XYZ_OFFSET(dnum)	((xyz) << 13)
+#define JZ_ADC_CONFIG_SAMPLE_NUM(x)	((x) << 10)
+#define JZ_ADC_CONFIG_CLKDIV(div)	((div) << 5)
+
+#endif
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index d848cb8..2b0a35e 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -306,6 +306,13 @@
 }
 #endif
 
+/*
+ * Dummy printk for disabled debugging statements to use whilst maintaining
+ * gcc's format and side-effect checking.
+ */
+static inline __attribute__ ((format (printf, 1, 2)))
+int no_printk(const char *s, ...) { return 0; }
+
 extern int printk_needs_cpu(int cpu);
 extern void printk_tick(void);
 
diff --git a/include/linux/mfd/ab8500.h b/include/linux/mfd/ab8500.h
index b63ff3b..f5cec45 100644
--- a/include/linux/mfd/ab8500.h
+++ b/include/linux/mfd/ab8500.h
@@ -76,6 +76,8 @@
 #define AB8500_NR_IRQS			104
 #define AB8500_NUM_IRQ_REGS		13
 
+#define AB8500_NUM_REGULATORS   15
+
 /**
  * struct ab8500 - ab8500 internal structure
  * @dev: parent device
@@ -108,14 +110,18 @@
 	u8 oldmask[AB8500_NUM_IRQ_REGS];
 };
 
+struct regulator_init_data;
+
 /**
  * struct ab8500_platform_data - AB8500 platform data
  * @irq_base: start of AB8500 IRQs, AB8500_NR_IRQS will be used
  * @init: board-specific initialization after detection of ab8500
+ * @regulator: machine-specific constraints for regulators
  */
 struct ab8500_platform_data {
 	int irq_base;
 	void (*init) (struct ab8500 *);
+	struct regulator_init_data *regulator[AB8500_NUM_REGULATORS];
 };
 
 extern int ab8500_write(struct ab8500 *a8500, u16 addr, u8 data);
diff --git a/include/linux/mfd/max8998-private.h b/include/linux/mfd/max8998-private.h
new file mode 100644
index 0000000..6dc75b3
--- /dev/null
+++ b/include/linux/mfd/max8998-private.h
@@ -0,0 +1,112 @@
+/*
+ * max8698.h - Voltage regulator driver for the Maxim 8998
+ *
+ *  Copyright (C) 2009-2010 Samsung Electrnoics
+ *  Kyungmin Park <kyungmin.park@samsung.com>
+ *  Marek Szyprowski <m.szyprowski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __LINUX_MFD_MAX8998_PRIV_H
+#define __LINUX_MFD_MAX8998_PRIV_H
+
+/* MAX 8998 registers */
+enum {
+	MAX8998_REG_IRQ1,
+	MAX8998_REG_IRQ2,
+	MAX8998_REG_IRQ3,
+	MAX8998_REG_IRQ4,
+	MAX8998_REG_IRQM1,
+	MAX8998_REG_IRQM2,
+	MAX8998_REG_IRQM3,
+	MAX8998_REG_IRQM4,
+	MAX8998_REG_STATUS1,
+	MAX8998_REG_STATUS2,
+	MAX8998_REG_STATUSM1,
+	MAX8998_REG_STATUSM2,
+	MAX8998_REG_CHGR1,
+	MAX8998_REG_CHGR2,
+	MAX8998_REG_LDO_ACTIVE_DISCHARGE1,
+	MAX8998_REG_LDO_ACTIVE_DISCHARGE2,
+	MAX8998_REG_BUCK_ACTIVE_DISCHARGE3,
+	MAX8998_REG_ONOFF1,
+	MAX8998_REG_ONOFF2,
+	MAX8998_REG_ONOFF3,
+	MAX8998_REG_ONOFF4,
+	MAX8998_REG_BUCK1_DVSARM1,
+	MAX8998_REG_BUCK1_DVSARM2,
+	MAX8998_REG_BUCK1_DVSARM3,
+	MAX8998_REG_BUCK1_DVSARM4,
+	MAX8998_REG_BUCK2_DVSINT1,
+	MAX8998_REG_BUCK2_DVSINT2,
+	MAX8998_REG_BUCK3,
+	MAX8998_REG_BUCK4,
+	MAX8998_REG_LDO2_LDO3,
+	MAX8998_REG_LDO4,
+	MAX8998_REG_LDO5,
+	MAX8998_REG_LDO6,
+	MAX8998_REG_LDO7,
+	MAX8998_REG_LDO8_LDO9,
+	MAX8998_REG_LDO10_LDO11,
+	MAX8998_REG_LDO12,
+	MAX8998_REG_LDO13,
+	MAX8998_REG_LDO14,
+	MAX8998_REG_LDO15,
+	MAX8998_REG_LDO16,
+	MAX8998_REG_LDO17,
+	MAX8998_REG_BKCHR,
+	MAX8998_REG_LBCNFG1,
+	MAX8998_REG_LBCNFG2,
+};
+
+/**
+ * struct max8998_dev - max8998 master device for sub-drivers
+ * @dev: master device of the chip (can be used to access platform data)
+ * @i2c_client: i2c client private data
+ * @dev_read():	chip register read function
+ * @dev_write(): chip register write function
+ * @dev_update(): chip register update function
+ * @iolock: mutex for serializing io access
+ */
+
+struct max8998_dev {
+	struct device *dev;
+	struct i2c_client *i2c_client;
+	int (*dev_read)(struct max8998_dev *max8998, u8 reg, u8 *dest);
+	int (*dev_write)(struct max8998_dev *max8998, u8 reg, u8 val);
+	int (*dev_update)(struct max8998_dev *max8998, u8 reg, u8 val, u8 mask);
+	struct mutex iolock;
+};
+
+static inline int max8998_read_reg(struct max8998_dev *max8998, u8 reg,
+				   u8 *value)
+{
+	return max8998->dev_read(max8998, reg, value);
+}
+
+static inline int max8998_write_reg(struct max8998_dev *max8998, u8 reg,
+				    u8 value)
+{
+	return max8998->dev_write(max8998, reg, value);
+}
+
+static inline int max8998_update_reg(struct max8998_dev *max8998, u8 reg,
+				     u8 value, u8 mask)
+{
+	return max8998->dev_update(max8998, reg, value, mask);
+}
+
+#endif /*  __LINUX_MFD_MAX8998_PRIV_H */
diff --git a/include/linux/mfd/max8998.h b/include/linux/mfd/max8998.h
new file mode 100644
index 0000000..1d3601a
--- /dev/null
+++ b/include/linux/mfd/max8998.h
@@ -0,0 +1,78 @@
+/*
+ * max8698.h - Voltage regulator driver for the Maxim 8998
+ *
+ *  Copyright (C) 2009-2010 Samsung Electrnoics
+ *  Kyungmin Park <kyungmin.park@samsung.com>
+ *  Marek Szyprowski <m.szyprowski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __LINUX_MFD_MAX8998_H
+#define __LINUX_MFD_MAX8998_H
+
+#include <linux/regulator/machine.h>
+
+/* MAX 8998 regulator ids */
+enum {
+	MAX8998_LDO2 = 2,
+	MAX8998_LDO3,
+	MAX8998_LDO4,
+	MAX8998_LDO5,
+	MAX8998_LDO6,
+	MAX8998_LDO7,
+	MAX8998_LDO8,
+	MAX8998_LDO9,
+	MAX8998_LDO10,
+	MAX8998_LDO11,
+	MAX8998_LDO12,
+	MAX8998_LDO13,
+	MAX8998_LDO14,
+	MAX8998_LDO15,
+	MAX8998_LDO16,
+	MAX8998_LDO17,
+	MAX8998_BUCK1,
+	MAX8998_BUCK2,
+	MAX8998_BUCK3,
+	MAX8998_BUCK4,
+	MAX8998_EN32KHZ_AP,
+	MAX8998_EN32KHZ_CP,
+	MAX8998_ENVICHG,
+	MAX8998_ESAFEOUT1,
+	MAX8998_ESAFEOUT2,
+};
+
+/**
+ * max8998_regulator_data - regulator data
+ * @id: regulator id
+ * @initdata: regulator init data (contraints, supplies, ...)
+ */
+struct max8998_regulator_data {
+	int				id;
+	struct regulator_init_data	*initdata;
+};
+
+/**
+ * struct max8998_board - packages regulator init data
+ * @num_regulators: number of regultors used
+ * @regulators: array of defined regulators
+ */
+
+struct max8998_platform_data {
+	int				num_regulators;
+	struct max8998_regulator_data	*regulators;
+};
+
+#endif /*  __LINUX_MFD_MAX8998_H */
diff --git a/include/linux/mfd/mc13783-private.h b/include/linux/mfd/mc13783-private.h
deleted file mode 100644
index 95cf936..0000000
--- a/include/linux/mfd/mc13783-private.h
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
- *
- * Initial development of this code was funded by
- * Phytec Messtechnik GmbH, http://www.phytec.de
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __LINUX_MFD_MC13783_PRIV_H
-#define __LINUX_MFD_MC13783_PRIV_H
-
-#include <linux/platform_device.h>
-#include <linux/mfd/mc13783.h>
-#include <linux/mutex.h>
-#include <linux/interrupt.h>
-
-struct mc13783 {
-	struct spi_device *spidev;
-	struct mutex lock;
-	int irq;
-	int flags;
-
-	irq_handler_t irqhandler[MC13783_NUM_IRQ];
-	void *irqdata[MC13783_NUM_IRQ];
-
-	/* XXX these should go as platformdata to the regulator subdevice */
-	struct mc13783_regulator_init_data *regulators;
-	int num_regulators;
-};
-
-#define MC13783_REG_INTERRUPT_STATUS_0		 0
-#define MC13783_REG_INTERRUPT_MASK_0		 1
-#define MC13783_REG_INTERRUPT_SENSE_0		 2
-#define MC13783_REG_INTERRUPT_STATUS_1		 3
-#define MC13783_REG_INTERRUPT_MASK_1		 4
-#define MC13783_REG_INTERRUPT_SENSE_1		 5
-#define MC13783_REG_POWER_UP_MODE_SENSE		 6
-#define MC13783_REG_REVISION			 7
-#define MC13783_REG_SEMAPHORE			 8
-#define MC13783_REG_ARBITRATION_PERIPHERAL_AUDIO 9
-#define MC13783_REG_ARBITRATION_SWITCHERS	10
-#define MC13783_REG_ARBITRATION_REGULATORS_0	11
-#define MC13783_REG_ARBITRATION_REGULATORS_1	12
-#define MC13783_REG_POWER_CONTROL_0		13
-#define MC13783_REG_POWER_CONTROL_1		14
-#define MC13783_REG_POWER_CONTROL_2		15
-#define MC13783_REG_REGEN_ASSIGNMENT		16
-#define MC13783_REG_CONTROL_SPARE		17
-#define MC13783_REG_MEMORY_A			18
-#define MC13783_REG_MEMORY_B			19
-#define MC13783_REG_RTC_TIME			20
-#define MC13783_REG_RTC_ALARM			21
-#define MC13783_REG_RTC_DAY			22
-#define MC13783_REG_RTC_DAY_ALARM		23
-#define MC13783_REG_SWITCHERS_0			24
-#define MC13783_REG_SWITCHERS_1			25
-#define MC13783_REG_SWITCHERS_2			26
-#define MC13783_REG_SWITCHERS_3			27
-#define MC13783_REG_SWITCHERS_4			28
-#define MC13783_REG_SWITCHERS_5			29
-#define MC13783_REG_REGULATOR_SETTING_0		30
-#define MC13783_REG_REGULATOR_SETTING_1		31
-#define MC13783_REG_REGULATOR_MODE_0		32
-#define MC13783_REG_REGULATOR_MODE_1		33
-#define MC13783_REG_POWER_MISCELLANEOUS		34
-#define MC13783_REG_POWER_SPARE			35
-#define MC13783_REG_AUDIO_RX_0			36
-#define MC13783_REG_AUDIO_RX_1			37
-#define MC13783_REG_AUDIO_TX			38
-#define MC13783_REG_AUDIO_SSI_NETWORK		39
-#define MC13783_REG_AUDIO_CODEC			40
-#define MC13783_REG_AUDIO_STEREO_DAC		41
-#define MC13783_REG_AUDIO_SPARE			42
-#define MC13783_REG_ADC_0			43
-#define MC13783_REG_ADC_1			44
-#define MC13783_REG_ADC_2			45
-#define MC13783_REG_ADC_3			46
-#define MC13783_REG_ADC_4			47
-#define MC13783_REG_CHARGER			48
-#define MC13783_REG_USB				49
-#define MC13783_REG_CHARGE_USB_SPARE		50
-#define MC13783_REG_LED_CONTROL_0		51
-#define MC13783_REG_LED_CONTROL_1		52
-#define MC13783_REG_LED_CONTROL_2		53
-#define MC13783_REG_LED_CONTROL_3		54
-#define MC13783_REG_LED_CONTROL_4		55
-#define MC13783_REG_LED_CONTROL_5		56
-#define MC13783_REG_SPARE			57
-#define MC13783_REG_TRIM_0			58
-#define MC13783_REG_TRIM_1			59
-#define MC13783_REG_TEST_0			60
-#define MC13783_REG_TEST_1			61
-#define MC13783_REG_TEST_2			62
-#define MC13783_REG_TEST_3			63
-#define MC13783_REG_NB				64
-
-/*
- * Reg Regulator Mode 0
- */
-#define MC13783_REGCTRL_VAUDIO_EN	(1 << 0)
-#define MC13783_REGCTRL_VAUDIO_STBY	(1 << 1)
-#define MC13783_REGCTRL_VAUDIO_MODE	(1 << 2)
-#define MC13783_REGCTRL_VIOHI_EN	(1 << 3)
-#define MC13783_REGCTRL_VIOHI_STBY	(1 << 4)
-#define MC13783_REGCTRL_VIOHI_MODE	(1 << 5)
-#define MC13783_REGCTRL_VIOLO_EN	(1 << 6)
-#define MC13783_REGCTRL_VIOLO_STBY 	(1 << 7)
-#define MC13783_REGCTRL_VIOLO_MODE	(1 << 8)
-#define MC13783_REGCTRL_VDIG_EN		(1 << 9)
-#define MC13783_REGCTRL_VDIG_STBY	(1 << 10)
-#define MC13783_REGCTRL_VDIG_MODE	(1 << 11)
-#define MC13783_REGCTRL_VGEN_EN		(1 << 12)
-#define MC13783_REGCTRL_VGEN_STBY	(1 << 13)
-#define MC13783_REGCTRL_VGEN_MODE	(1 << 14)
-#define MC13783_REGCTRL_VRFDIG_EN	(1 << 15)
-#define MC13783_REGCTRL_VRFDIG_STBY	(1 << 16)
-#define MC13783_REGCTRL_VRFDIG_MODE	(1 << 17)
-#define MC13783_REGCTRL_VRFREF_EN	(1 << 18)
-#define MC13783_REGCTRL_VRFREF_STBY	(1 << 19)
-#define MC13783_REGCTRL_VRFREF_MODE	(1 << 20)
-#define MC13783_REGCTRL_VRFCP_EN	(1 << 21)
-#define MC13783_REGCTRL_VRFCP_STBY	(1 << 22)
-#define MC13783_REGCTRL_VRFCP_MODE	(1 << 23)
-
-/*
- * Reg Regulator Mode 1
- */
-#define MC13783_REGCTRL_VSIM_EN		(1 << 0)
-#define MC13783_REGCTRL_VSIM_STBY	(1 << 1)
-#define MC13783_REGCTRL_VSIM_MODE	(1 << 2)
-#define MC13783_REGCTRL_VESIM_EN	(1 << 3)
-#define MC13783_REGCTRL_VESIM_STBY	(1 << 4)
-#define MC13783_REGCTRL_VESIM_MODE	(1 << 5)
-#define MC13783_REGCTRL_VCAM_EN		(1 << 6)
-#define MC13783_REGCTRL_VCAM_STBY	(1 << 7)
-#define MC13783_REGCTRL_VCAM_MODE	(1 << 8)
-#define	MC13783_REGCTRL_VRFBG_EN	(1 << 9)
-#define MC13783_REGCTRL_VRFBG_STBY	(1 << 10)
-#define MC13783_REGCTRL_VVIB_EN		(1 << 11)
-#define MC13783_REGCTRL_VRF1_EN		(1 << 12)
-#define MC13783_REGCTRL_VRF1_STBY	(1 << 13)
-#define MC13783_REGCTRL_VRF1_MODE	(1 << 14)
-#define MC13783_REGCTRL_VRF2_EN		(1 << 15)
-#define MC13783_REGCTRL_VRF2_STBY	(1 << 16)
-#define MC13783_REGCTRL_VRF2_MODE	(1 << 17)
-#define MC13783_REGCTRL_VMMC1_EN	(1 << 18)
-#define MC13783_REGCTRL_VMMC1_STBY	(1 << 19)
-#define MC13783_REGCTRL_VMMC1_MODE	(1 << 20)
-#define MC13783_REGCTRL_VMMC2_EN	(1 << 21)
-#define MC13783_REGCTRL_VMMC2_STBY	(1 << 22)
-#define MC13783_REGCTRL_VMMC2_MODE	(1 << 23)
-
-/*
- * Reg Regulator Misc.
- */
-#define MC13783_REGCTRL_GPO1_EN		(1 << 6)
-#define MC13783_REGCTRL_GPO2_EN		(1 << 8)
-#define MC13783_REGCTRL_GPO3_EN		(1 << 10)
-#define MC13783_REGCTRL_GPO4_EN		(1 << 12)
-#define MC13783_REGCTRL_VIBPINCTRL	(1 << 14)
-
-/*
- * Reg Switcher 4
- */
-#define MC13783_SWCTRL_SW1A_MODE	(1 << 0)
-#define MC13783_SWCTRL_SW1A_STBY_MODE	(1 << 2)
-#define MC13783_SWCTRL_SW1A_DVS_SPEED	(1 << 6)
-#define MC13783_SWCTRL_SW1A_PANIC_MODE	(1 << 8)
-#define MC13783_SWCTRL_SW1A_SOFTSTART	(1 << 9)
-#define MC13783_SWCTRL_SW1B_MODE	(1 << 10)
-#define MC13783_SWCTRL_SW1B_STBY_MODE	(1 << 12)
-#define MC13783_SWCTRL_SW1B_DVS_SPEED	(1 << 14)
-#define MC13783_SWCTRL_SW1B_PANIC_MODE	(1 << 16)
-#define MC13783_SWCTRL_SW1B_SOFTSTART	(1 << 17)
-#define MC13783_SWCTRL_PLL_EN		(1 << 18)
-#define MC13783_SWCTRL_PLL_FACTOR	(1 << 19)
-
-/*
- * Reg Switcher 5
- */
-#define MC13783_SWCTRL_SW2A_MODE	(1 << 0)
-#define MC13783_SWCTRL_SW2A_STBY_MODE	(1 << 2)
-#define MC13783_SWCTRL_SW2A_DVS_SPEED	(1 << 6)
-#define MC13783_SWCTRL_SW2A_PANIC_MODE	(1 << 8)
-#define MC13783_SWCTRL_SW2A_SOFTSTART	(1 << 9)
-#define MC13783_SWCTRL_SW2B_MODE	(1 << 10)
-#define MC13783_SWCTRL_SW2B_STBY_MODE	(1 << 12)
-#define MC13783_SWCTRL_SW2B_DVS_SPEED	(1 << 14)
-#define MC13783_SWCTRL_SW2B_PANIC_MODE	(1 << 16)
-#define MC13783_SWCTRL_SW2B_SOFTSTART	(1 << 17)
-#define MC13783_SWSET_SW3		(1 << 18)
-#define MC13783_SWCTRL_SW3_EN		(1 << 20)
-#define MC13783_SWCTRL_SW3_STBY		(1 << 21)
-#define MC13783_SWCTRL_SW3_MODE		(1 << 22)
-
-static inline int mc13783_set_bits(struct mc13783 *mc13783, unsigned int offset,
-		u32 mask, u32 val)
-{
-	int ret;
-	mc13783_lock(mc13783);
-	ret = mc13783_reg_rmw(mc13783, offset, mask, val);
-	mc13783_unlock(mc13783);
-
-	return ret;
-}
-
-#endif /* __LINUX_MFD_MC13783_PRIV_H */
diff --git a/include/linux/mfd/mc13783.h b/include/linux/mfd/mc13783.h
index 4a894f6..0fa44fb 100644
--- a/include/linux/mfd/mc13783.h
+++ b/include/linux/mfd/mc13783.h
@@ -21,6 +21,8 @@
 int mc13783_reg_rmw(struct mc13783 *mc13783, unsigned int offset,
 		u32 mask, u32 val);
 
+int mc13783_get_flags(struct mc13783 *mc13783);
+
 int mc13783_irq_request(struct mc13783 *mc13783, int irq,
 		irq_handler_t handler, const char *name, void *dev);
 int mc13783_irq_request_nounmask(struct mc13783 *mc13783, int irq,
diff --git a/include/linux/mfd/stmpe.h b/include/linux/mfd/stmpe.h
new file mode 100644
index 0000000..39ca758
--- /dev/null
+++ b/include/linux/mfd/stmpe.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License, version 2
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ */
+
+#ifndef __LINUX_MFD_STMPE_H
+#define __LINUX_MFD_STMPE_H
+
+#include <linux/device.h>
+
+enum stmpe_block {
+	STMPE_BLOCK_GPIO	= 1 << 0,
+	STMPE_BLOCK_KEYPAD	= 1 << 1,
+	STMPE_BLOCK_TOUCHSCREEN	= 1 << 2,
+	STMPE_BLOCK_ADC		= 1 << 3,
+	STMPE_BLOCK_PWM		= 1 << 4,
+	STMPE_BLOCK_ROTATOR	= 1 << 5,
+};
+
+enum stmpe_partnum {
+	STMPE811,
+	STMPE1601,
+	STMPE2401,
+	STMPE2403,
+};
+
+/*
+ * For registers whose locations differ on variants,  the correct address is
+ * obtained by indexing stmpe->regs with one of the following.
+ */
+enum {
+	STMPE_IDX_CHIP_ID,
+	STMPE_IDX_ICR_LSB,
+	STMPE_IDX_IER_LSB,
+	STMPE_IDX_ISR_MSB,
+	STMPE_IDX_GPMR_LSB,
+	STMPE_IDX_GPSR_LSB,
+	STMPE_IDX_GPCR_LSB,
+	STMPE_IDX_GPDR_LSB,
+	STMPE_IDX_GPEDR_MSB,
+	STMPE_IDX_GPRER_LSB,
+	STMPE_IDX_GPFER_LSB,
+	STMPE_IDX_GPAFR_U_MSB,
+	STMPE_IDX_IEGPIOR_LSB,
+	STMPE_IDX_ISGPIOR_MSB,
+	STMPE_IDX_MAX,
+};
+
+
+struct stmpe_variant_info;
+
+/**
+ * struct stmpe - STMPE MFD structure
+ * @lock: lock protecting I/O operations
+ * @irq_lock: IRQ bus lock
+ * @dev: device, mostly for dev_dbg()
+ * @i2c: i2c client
+ * @variant: the detected STMPE model number
+ * @regs: list of addresses of registers which are at different addresses on
+ *	  different variants.  Indexed by one of STMPE_IDX_*.
+ * @irq_base: starting IRQ number for internal IRQs
+ * @num_gpios: number of gpios, differs for variants
+ * @ier: cache of IER registers for bus_lock
+ * @oldier: cache of IER registers for bus_lock
+ * @pdata: platform data
+ */
+struct stmpe {
+	struct mutex lock;
+	struct mutex irq_lock;
+	struct device *dev;
+	struct i2c_client *i2c;
+	enum stmpe_partnum partnum;
+	struct stmpe_variant_info *variant;
+	const u8 *regs;
+
+	int irq_base;
+	int num_gpios;
+	u8 ier[2];
+	u8 oldier[2];
+	struct stmpe_platform_data *pdata;
+};
+
+extern int stmpe_reg_write(struct stmpe *stmpe, u8 reg, u8 data);
+extern int stmpe_reg_read(struct stmpe *stmpe, u8 reg);
+extern int stmpe_block_read(struct stmpe *stmpe, u8 reg, u8 length,
+			    u8 *values);
+extern int stmpe_block_write(struct stmpe *stmpe, u8 reg, u8 length,
+			     const u8 *values);
+extern int stmpe_set_bits(struct stmpe *stmpe, u8 reg, u8 mask, u8 val);
+extern int stmpe_set_altfunc(struct stmpe *stmpe, u32 pins,
+			     enum stmpe_block block);
+extern int stmpe_enable(struct stmpe *stmpe, unsigned int blocks);
+extern int stmpe_disable(struct stmpe *stmpe, unsigned int blocks);
+
+struct matrix_keymap_data;
+
+/**
+ * struct stmpe_keypad_platform_data - STMPE keypad platform data
+ * @keymap_data: key map table and size
+ * @debounce_ms: debounce interval, in ms.  Maximum is
+ *		 %STMPE_KEYPAD_MAX_DEBOUNCE.
+ * @scan_count: number of key scanning cycles to confirm key data.
+ *		Maximum is %STMPE_KEYPAD_MAX_SCAN_COUNT.
+ * @no_autorepeat: disable key autorepeat
+ */
+struct stmpe_keypad_platform_data {
+	struct matrix_keymap_data *keymap_data;
+	unsigned int debounce_ms;
+	unsigned int scan_count;
+	bool no_autorepeat;
+};
+
+/**
+ * struct stmpe_gpio_platform_data - STMPE GPIO platform data
+ * @gpio_base: first gpio number assigned.  A maximum of
+ *	       %STMPE_NR_GPIOS GPIOs will be allocated.
+ */
+struct stmpe_gpio_platform_data {
+	int gpio_base;
+	void (*setup)(struct stmpe *stmpe, unsigned gpio_base);
+	void (*remove)(struct stmpe *stmpe, unsigned gpio_base);
+};
+
+/**
+ * struct stmpe_ts_platform_data - stmpe811 touch screen controller platform
+ * data
+ * @sample_time: ADC converstion time in number of clock.
+ * (0 -> 36 clocks, 1 -> 44 clocks, 2 -> 56 clocks, 3 -> 64 clocks,
+ * 4 -> 80 clocks, 5 -> 96 clocks, 6 -> 144 clocks),
+ * recommended is 4.
+ * @mod_12b: ADC Bit mode (0 -> 10bit ADC, 1 -> 12bit ADC)
+ * @ref_sel: ADC reference source
+ * (0 -> internal reference, 1 -> external reference)
+ * @adc_freq: ADC Clock speed
+ * (0 -> 1.625 MHz, 1 -> 3.25 MHz, 2 || 3 -> 6.5 MHz)
+ * @ave_ctrl: Sample average control
+ * (0 -> 1 sample, 1 -> 2 samples, 2 -> 4 samples, 3 -> 8 samples)
+ * @touch_det_delay: Touch detect interrupt delay
+ * (0 -> 10 us, 1 -> 50 us, 2 -> 100 us, 3 -> 500 us,
+ * 4-> 1 ms, 5 -> 5 ms, 6 -> 10 ms, 7 -> 50 ms)
+ * recommended is 3
+ * @settling: Panel driver settling time
+ * (0 -> 10 us, 1 -> 100 us, 2 -> 500 us, 3 -> 1 ms,
+ * 4 -> 5 ms, 5 -> 10 ms, 6 for 50 ms, 7 -> 100 ms)
+ * recommended is 2
+ * @fraction_z: Length of the fractional part in z
+ * (fraction_z ([0..7]) = Count of the fractional part)
+ * recommended is 7
+ * @i_drive: current limit value of the touchscreen drivers
+ * (0 -> 20 mA typical 35 mA max, 1 -> 50 mA typical 80 mA max)
+ *
+ * */
+struct stmpe_ts_platform_data {
+       u8 sample_time;
+       u8 mod_12b;
+       u8 ref_sel;
+       u8 adc_freq;
+       u8 ave_ctrl;
+       u8 touch_det_delay;
+       u8 settling;
+       u8 fraction_z;
+       u8 i_drive;
+};
+
+/**
+ * struct stmpe_platform_data - STMPE platform data
+ * @id: device id to distinguish between multiple STMPEs on the same board
+ * @blocks: bitmask of blocks to enable (use STMPE_BLOCK_*)
+ * @irq_trigger: IRQ trigger to use for the interrupt to the host
+ * @irq_invert_polarity: IRQ line is connected with reversed polarity
+ * @autosleep: bool to enable/disable stmpe autosleep
+ * @autosleep_timeout: inactivity timeout in milliseconds for autosleep
+ * @irq_base: base IRQ number.  %STMPE_NR_IRQS irqs will be used, or
+ *	      %STMPE_NR_INTERNAL_IRQS if the GPIO driver is not used.
+ * @gpio: GPIO-specific platform data
+ * @keypad: keypad-specific platform data
+ * @ts: touchscreen-specific platform data
+ */
+struct stmpe_platform_data {
+	int id;
+	unsigned int blocks;
+	int irq_base;
+	unsigned int irq_trigger;
+	bool irq_invert_polarity;
+	bool autosleep;
+	int autosleep_timeout;
+
+	struct stmpe_gpio_platform_data *gpio;
+	struct stmpe_keypad_platform_data *keypad;
+	struct stmpe_ts_platform_data *ts;
+};
+
+#define STMPE_NR_INTERNAL_IRQS	9
+#define STMPE_INT_GPIO(x)	(STMPE_NR_INTERNAL_IRQS + (x))
+
+#define STMPE_NR_GPIOS		24
+#define STMPE_NR_IRQS		STMPE_INT_GPIO(STMPE_NR_GPIOS)
+
+#endif
diff --git a/include/linux/mfd/tps6586x.h b/include/linux/mfd/tps6586x.h
new file mode 100644
index 0000000..772b3ae
--- /dev/null
+++ b/include/linux/mfd/tps6586x.h
@@ -0,0 +1,47 @@
+#ifndef __LINUX_MFD_TPS6586X_H
+#define __LINUX_MFD_TPS6586X_H
+
+enum {
+	TPS6586X_ID_SM_0,
+	TPS6586X_ID_SM_1,
+	TPS6586X_ID_SM_2,
+	TPS6586X_ID_LDO_0,
+	TPS6586X_ID_LDO_1,
+	TPS6586X_ID_LDO_2,
+	TPS6586X_ID_LDO_3,
+	TPS6586X_ID_LDO_4,
+	TPS6586X_ID_LDO_5,
+	TPS6586X_ID_LDO_6,
+	TPS6586X_ID_LDO_7,
+	TPS6586X_ID_LDO_8,
+	TPS6586X_ID_LDO_9,
+	TPS6586X_ID_LDO_RTC,
+};
+
+struct tps6586x_subdev_info {
+	int		id;
+	const char	*name;
+	void		*platform_data;
+};
+
+struct tps6586x_platform_data {
+	int num_subdevs;
+	struct tps6586x_subdev_info *subdevs;
+
+	int gpio_base;
+};
+
+/*
+ * NOTE: the functions below are not intended for use outside
+ * of the TPS6586X sub-device drivers
+ */
+extern int tps6586x_write(struct device *dev, int reg, uint8_t val);
+extern int tps6586x_writes(struct device *dev, int reg, int len, uint8_t *val);
+extern int tps6586x_read(struct device *dev, int reg, uint8_t *val);
+extern int tps6586x_reads(struct device *dev, int reg, int len, uint8_t *val);
+extern int tps6586x_set_bits(struct device *dev, int reg, uint8_t bit_mask);
+extern int tps6586x_clr_bits(struct device *dev, int reg, uint8_t bit_mask);
+extern int tps6586x_update(struct device *dev, int reg, uint8_t val,
+			   uint8_t mask);
+
+#endif /*__LINUX_MFD_TPS6586X_H */
diff --git a/include/linux/mfd/wm8994/gpio.h b/include/linux/mfd/wm8994/gpio.h
index b4d4c22..0c79b5f 100644
--- a/include/linux/mfd/wm8994/gpio.h
+++ b/include/linux/mfd/wm8994/gpio.h
@@ -36,6 +36,10 @@
 #define WM8994_GP_FN_WSEQ_STATUS    16
 #define WM8994_GP_FN_FIFO_ERROR     17
 #define WM8994_GP_FN_OPCLK          18
+#define WM8994_GP_FN_THW	    19
+#define WM8994_GP_FN_DCS_DONE	    20
+#define WM8994_GP_FN_FLL1_OUT       21
+#define WM8994_GP_FN_FLL2_OUT       22
 
 #define WM8994_GPN_DIR                          0x8000  /* GPN_DIR */
 #define WM8994_GPN_DIR_MASK                     0x8000  /* GPN_DIR */
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 4d893ea..6b75250 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -31,6 +31,7 @@
 	unsigned int		tacc_ns;
 	unsigned int		r2w_factor;
 	unsigned int		max_dtr;
+	unsigned int		erase_size;		/* In sectors */
 	unsigned int		read_blkbits;
 	unsigned int		write_blkbits;
 	unsigned int		capacity;
@@ -42,9 +43,16 @@
 
 struct mmc_ext_csd {
 	u8			rev;
+	u8			erase_group_def;
+	u8			sec_feature_support;
 	unsigned int		sa_timeout;		/* Units: 100ns */
 	unsigned int		hs_max_dtr;
 	unsigned int		sectors;
+	unsigned int		hc_erase_size;		/* In sectors */
+	unsigned int		hc_erase_timeout;	/* In milliseconds */
+	unsigned int		sec_trim_mult;	/* Secure trim multiplier  */
+	unsigned int		sec_erase_mult;	/* Secure erase multiplier */
+	unsigned int		trim_timeout;		/* In milliseconds */
 };
 
 struct sd_scr {
@@ -54,6 +62,12 @@
 #define SD_SCR_BUS_WIDTH_4	(1<<2)
 };
 
+struct sd_ssr {
+	unsigned int		au;			/* In sectors */
+	unsigned int		erase_timeout;		/* In milliseconds */
+	unsigned int		erase_offset;		/* In milliseconds */
+};
+
 struct sd_switch_caps {
 	unsigned int		hs_max_dtr;
 };
@@ -106,6 +120,11 @@
 #define MMC_QUIRK_NONSTD_SDIO	(1<<2)		/* non-standard SDIO card attached */
 						/* (missing CIA registers) */
 
+	unsigned int		erase_size;	/* erase size in sectors */
+ 	unsigned int		erase_shift;	/* if erase unit is power 2 */
+ 	unsigned int		pref_erase;	/* in sectors */
+ 	u8			erased_byte;	/* value of erased bytes */
+
 	u32			raw_cid[4];	/* raw card CID */
 	u32			raw_csd[4];	/* raw card CSD */
 	u32			raw_scr[2];	/* raw card SCR */
@@ -113,6 +132,7 @@
 	struct mmc_csd		csd;		/* card specific */
 	struct mmc_ext_csd	ext_csd;	/* mmc v4 extended card specific */
 	struct sd_scr		scr;		/* extra SD information */
+	struct sd_ssr		ssr;		/* yet more SD information */
 	struct sd_switch_caps	sw_caps;	/* switch (CMD6) caps */
 
 	unsigned int		sdio_funcs;	/* number of SDIO functions */
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index e4898e9..7429033 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -92,6 +92,8 @@
  *              actively failing requests
  */
 
+	unsigned int		erase_timeout;	/* in milliseconds */
+
 	struct mmc_data		*data;		/* data segment associated with cmd */
 	struct mmc_request	*mrq;		/* associated request */
 };
@@ -134,6 +136,23 @@
 extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
 	struct mmc_command *, int);
 
+#define MMC_ERASE_ARG		0x00000000
+#define MMC_SECURE_ERASE_ARG	0x80000000
+#define MMC_TRIM_ARG		0x00000001
+#define MMC_SECURE_TRIM1_ARG	0x80000001
+#define MMC_SECURE_TRIM2_ARG	0x80008000
+
+#define MMC_SECURE_ARGS		0x80000000
+#define MMC_TRIM_ARGS		0x00008001
+
+extern int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
+		     unsigned int arg);
+extern int mmc_can_erase(struct mmc_card *card);
+extern int mmc_can_trim(struct mmc_card *card);
+extern int mmc_can_secure_erase_trim(struct mmc_card *card);
+extern int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
+				   unsigned int nr);
+
 extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *);
 extern unsigned int mmc_align_data_size(struct mmc_card *, unsigned int);
 
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 513ff03..1575b52 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -156,6 +156,7 @@
 #define MMC_CAP_DISABLE		(1 << 7)	/* Can the host be disabled */
 #define MMC_CAP_NONREMOVABLE	(1 << 8)	/* Nonremovable e.g. eMMC */
 #define MMC_CAP_WAIT_WHILE_BUSY	(1 << 9)	/* Waits while card is busy */
+#define MMC_CAP_ERASE		(1 << 10)	/* Allow erase/trim commands */
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 52ce988..dd11ae5 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -251,13 +251,21 @@
  * EXT_CSD fields
  */
 
-#define EXT_CSD_BUS_WIDTH	183	/* R/W */
-#define EXT_CSD_HS_TIMING	185	/* R/W */
-#define EXT_CSD_CARD_TYPE	196	/* RO */
-#define EXT_CSD_STRUCTURE	194	/* RO */
-#define EXT_CSD_REV		192	/* RO */
-#define EXT_CSD_SEC_CNT		212	/* RO, 4 bytes */
-#define EXT_CSD_S_A_TIMEOUT	217
+#define EXT_CSD_ERASE_GROUP_DEF		175	/* R/W */
+#define EXT_CSD_ERASED_MEM_CONT		181	/* RO */
+#define EXT_CSD_BUS_WIDTH		183	/* R/W */
+#define EXT_CSD_HS_TIMING		185	/* R/W */
+#define EXT_CSD_REV			192	/* RO */
+#define EXT_CSD_STRUCTURE		194	/* RO */
+#define EXT_CSD_CARD_TYPE		196	/* RO */
+#define EXT_CSD_SEC_CNT			212	/* RO, 4 bytes */
+#define EXT_CSD_S_A_TIMEOUT		217	/* RO */
+#define EXT_CSD_ERASE_TIMEOUT_MULT	223	/* RO */
+#define EXT_CSD_HC_ERASE_GRP_SIZE	224	/* RO */
+#define EXT_CSD_SEC_TRIM_MULT		229	/* RO */
+#define EXT_CSD_SEC_ERASE_MULT		230	/* RO */
+#define EXT_CSD_SEC_FEATURE_SUPPORT	231	/* RO */
+#define EXT_CSD_TRIM_MULT		232	/* RO */
 
 /*
  * EXT_CSD field definitions
@@ -275,6 +283,10 @@
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
 #define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */
 
+#define EXT_CSD_SEC_ER_EN	BIT(0)
+#define EXT_CSD_SEC_BD_BLK_EN	BIT(2)
+#define EXT_CSD_SEC_GB_CL_EN	BIT(4)
+
 /*
  * MMC_SWITCH access modes
  */
diff --git a/include/linux/mmc/sd.h b/include/linux/mmc/sd.h
index f310062..3fd85e0 100644
--- a/include/linux/mmc/sd.h
+++ b/include/linux/mmc/sd.h
@@ -21,8 +21,13 @@
   /* class 10 */
 #define SD_SWITCH                 6   /* adtc [31:0] See below   R1  */
 
+  /* class 5 */
+#define SD_ERASE_WR_BLK_START    32   /* ac   [31:0] data addr   R1  */
+#define SD_ERASE_WR_BLK_END      33   /* ac   [31:0] data addr   R1  */
+
   /* Application commands */
 #define SD_APP_SET_BUS_WIDTH      6   /* ac   [1:0] bus width    R1  */
+#define SD_APP_SD_STATUS         13   /* adtc                    R1  */
 #define SD_APP_SEND_NUM_WR_BLKS  22   /* adtc                    R1  */
 #define SD_APP_OP_COND           41   /* bcr  [31:0] OCR         R3  */
 #define SD_APP_SEND_SCR          51   /* adtc                    R1  */
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h
index 82a9124..9d2f183 100644
--- a/include/linux/moduleparam.h
+++ b/include/linux/moduleparam.h
@@ -31,20 +31,23 @@
 
 struct kernel_param;
 
-/* Returns 0, or -errno.  arg is in kp->arg. */
-typedef int (*param_set_fn)(const char *val, struct kernel_param *kp);
-/* Returns length written or -errno.  Buffer is 4k (ie. be short!) */
-typedef int (*param_get_fn)(char *buffer, struct kernel_param *kp);
+struct kernel_param_ops {
+	/* Returns 0, or -errno.  arg is in kp->arg. */
+	int (*set)(const char *val, const struct kernel_param *kp);
+	/* Returns length written or -errno.  Buffer is 4k (ie. be short!) */
+	int (*get)(char *buffer, const struct kernel_param *kp);
+	/* Optional function to free kp->arg when module unloaded. */
+	void (*free)(void *arg);
+};
 
 /* Flag bits for kernel_param.flags */
 #define KPARAM_ISBOOL		2
 
 struct kernel_param {
 	const char *name;
+	const struct kernel_param_ops *ops;
 	u16 perm;
 	u16 flags;
-	param_set_fn set;
-	param_get_fn get;
 	union {
 		void *arg;
 		const struct kparam_string *str;
@@ -63,12 +66,67 @@
 {
 	unsigned int max;
 	unsigned int *num;
-	param_set_fn set;
-	param_get_fn get;
+	const struct kernel_param_ops *ops;
 	unsigned int elemsize;
 	void *elem;
 };
 
+/**
+ * module_param - typesafe helper for a module/cmdline parameter
+ * @value: the variable to alter, and exposed parameter name.
+ * @type: the type of the parameter
+ * @perm: visibility in sysfs.
+ *
+ * @value becomes the module parameter, or (prefixed by KBUILD_MODNAME and a
+ * ".") the kernel commandline parameter.  Note that - is changed to _, so
+ * the user can use "foo-bar=1" even for variable "foo_bar".
+ *
+ * @perm is 0 if the the variable is not to appear in sysfs, or 0444
+ * for world-readable, 0644 for root-writable, etc.  Note that if it
+ * is writable, you may need to use kparam_block_sysfs_write() around
+ * accesses (esp. charp, which can be kfreed when it changes).
+ *
+ * The @type is simply pasted to refer to a param_ops_##type and a
+ * param_check_##type: for convenience many standard types are provided but
+ * you can create your own by defining those variables.
+ *
+ * Standard types are:
+ *	byte, short, ushort, int, uint, long, ulong
+ *	charp: a character pointer
+ *	bool: a bool, values 0/1, y/n, Y/N.
+ *	invbool: the above, only sense-reversed (N = true).
+ */
+#define module_param(name, type, perm)				\
+	module_param_named(name, name, type, perm)
+
+/**
+ * module_param_named - typesafe helper for a renamed module/cmdline parameter
+ * @name: a valid C identifier which is the parameter name.
+ * @value: the actual lvalue to alter.
+ * @type: the type of the parameter
+ * @perm: visibility in sysfs.
+ *
+ * Usually it's a good idea to have variable names and user-exposed names the
+ * same, but that's harder if the variable must be non-static or is inside a
+ * structure.  This allows exposure under a different name.
+ */
+#define module_param_named(name, value, type, perm)			   \
+	param_check_##type(name, &(value));				   \
+	module_param_cb(name, &param_ops_##type, &value, perm);		   \
+	__MODULE_PARM_TYPE(name, #type)
+
+/**
+ * module_param_cb - general callback for a module/cmdline parameter
+ * @name: a valid C identifier which is the parameter name.
+ * @ops: the set & get operations for this parameter.
+ * @perm: visibility in sysfs.
+ *
+ * The ops can have NULL set or get functions.
+ */
+#define module_param_cb(name, ops, arg, perm)				      \
+	__module_param_call(MODULE_PARAM_PREFIX,			      \
+			    name, ops, arg, __same_type((arg), bool *), perm)
+
 /* On alpha, ia64 and ppc64 relocations to global data cannot go into
    read-only sections (which is part of respective UNIX ABI on these
    platforms). So 'const' makes no sense and even causes compile failures
@@ -80,10 +138,8 @@
 #endif
 
 /* This is the fundamental function for registering boot/module
-   parameters.  perm sets the visibility in sysfs: 000 means it's
-   not there, read bits mean it's readable, write bits mean it's
-   writable. */
-#define __module_param_call(prefix, name, set, get, arg, isbool, perm)	\
+   parameters. */
+#define __module_param_call(prefix, name, ops, arg, isbool, perm)	\
 	/* Default value instead of permissions? */			\
 	static int __param_perm_check_##name __attribute__((unused)) =	\
 	BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2))	\
@@ -92,31 +148,87 @@
 	static struct kernel_param __moduleparam_const __param_##name	\
 	__used								\
     __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \
-	= { __param_str_##name, perm, isbool ? KPARAM_ISBOOL : 0,	\
-	    set, get, { arg } }
+	= { __param_str_##name, ops, perm, isbool ? KPARAM_ISBOOL : 0,	\
+	    { arg } }
 
-#define module_param_call(name, set, get, arg, perm)			      \
-	__module_param_call(MODULE_PARAM_PREFIX,			      \
-			    name, set, get, arg,			      \
-			    __same_type(*(arg), bool), perm)
+/* Obsolete - use module_param_cb() */
+#define module_param_call(name, set, get, arg, perm)			\
+	static struct kernel_param_ops __param_ops_##name =		\
+		 { (void *)set, (void *)get };				\
+	__module_param_call(MODULE_PARAM_PREFIX,			\
+			    name, &__param_ops_##name, arg,		\
+			    __same_type(arg, bool *),			\
+			    (perm) + sizeof(__check_old_set_param(set))*0)
 
-/* Helper functions: type is byte, short, ushort, int, uint, long,
-   ulong, charp, bool or invbool, or XXX if you define param_get_XXX,
-   param_set_XXX and param_check_XXX. */
-#define module_param_named(name, value, type, perm)			   \
-	param_check_##type(name, &(value));				   \
-	module_param_call(name, param_set_##type, param_get_##type, &value, perm); \
-	__MODULE_PARM_TYPE(name, #type)
+/* We don't get oldget: it's often a new-style param_get_uint, etc. */
+static inline int
+__check_old_set_param(int (*oldset)(const char *, struct kernel_param *))
+{
+	return 0;
+}
 
-#define module_param(name, type, perm)				\
-	module_param_named(name, name, type, perm)
+/**
+ * kparam_block_sysfs_write - make sure a parameter isn't written via sysfs.
+ * @name: the name of the parameter
+ *
+ * There's no point blocking write on a paramter that isn't writable via sysfs!
+ */
+#define kparam_block_sysfs_write(name)			\
+	do {						\
+		BUG_ON(!(__param_##name.perm & 0222));	\
+		__kernel_param_lock();			\
+	} while (0)
+
+/**
+ * kparam_unblock_sysfs_write - allows sysfs to write to a parameter again.
+ * @name: the name of the parameter
+ */
+#define kparam_unblock_sysfs_write(name)		\
+	do {						\
+		BUG_ON(!(__param_##name.perm & 0222));	\
+		__kernel_param_unlock();		\
+	} while (0)
+
+/**
+ * kparam_block_sysfs_read - make sure a parameter isn't read via sysfs.
+ * @name: the name of the parameter
+ *
+ * This also blocks sysfs writes.
+ */
+#define kparam_block_sysfs_read(name)			\
+	do {						\
+		BUG_ON(!(__param_##name.perm & 0444));	\
+		__kernel_param_lock();			\
+	} while (0)
+
+/**
+ * kparam_unblock_sysfs_read - allows sysfs to read a parameter again.
+ * @name: the name of the parameter
+ */
+#define kparam_unblock_sysfs_read(name)			\
+	do {						\
+		BUG_ON(!(__param_##name.perm & 0444));	\
+		__kernel_param_unlock();		\
+	} while (0)
+
+#ifdef CONFIG_SYSFS
+extern void __kernel_param_lock(void);
+extern void __kernel_param_unlock(void);
+#else
+static inline void __kernel_param_lock(void)
+{
+}
+static inline void __kernel_param_unlock(void)
+{
+}
+#endif
 
 #ifndef MODULE
 /**
  * core_param - define a historical core kernel parameter.
  * @name: the name of the cmdline and sysfs parameter (often the same as var)
  * @var: the variable
- * @type: the type (for param_set_##type and param_get_##type)
+ * @type: the type of the parameter
  * @perm: visibility in sysfs
  *
  * core_param is just like module_param(), but cannot be modular and
@@ -126,23 +238,32 @@
  */
 #define core_param(name, var, type, perm)				\
 	param_check_##type(name, &(var));				\
-	__module_param_call("", name, param_set_##type, param_get_##type, \
+	__module_param_call("", name, &param_ops_##type,		\
 			    &var, __same_type(var, bool), perm)
 #endif /* !MODULE */
 
-/* Actually copy string: maxlen param is usually sizeof(string). */
+/**
+ * module_param_string - a char array parameter
+ * @name: the name of the parameter
+ * @string: the string variable
+ * @len: the maximum length of the string, incl. terminator
+ * @perm: visibility in sysfs.
+ *
+ * This actually copies the string when it's set (unlike type charp).
+ * @len is usually just sizeof(string).
+ */
 #define module_param_string(name, string, len, perm)			\
 	static const struct kparam_string __param_string_##name		\
 		= { len, string };					\
 	__module_param_call(MODULE_PARAM_PREFIX, name,			\
-			    param_set_copystring, param_get_string,	\
+			    &param_ops_string,				\
 			    .str = &__param_string_##name, 0, perm);	\
 	__MODULE_PARM_TYPE(name, "string")
 
 /* Called on module insert or kernel boot */
 extern int parse_args(const char *name,
 		      char *args,
-		      struct kernel_param *params,
+		      const struct kernel_param *params,
 		      unsigned num,
 		      int (*unknown)(char *param, char *val));
 
@@ -162,72 +283,105 @@
 #define __param_check(name, p, type) \
 	static inline type *__check_##name(void) { return(p); }
 
-extern int param_set_byte(const char *val, struct kernel_param *kp);
-extern int param_get_byte(char *buffer, struct kernel_param *kp);
+extern struct kernel_param_ops param_ops_byte;
+extern int param_set_byte(const char *val, const struct kernel_param *kp);
+extern int param_get_byte(char *buffer, const struct kernel_param *kp);
 #define param_check_byte(name, p) __param_check(name, p, unsigned char)
 
-extern int param_set_short(const char *val, struct kernel_param *kp);
-extern int param_get_short(char *buffer, struct kernel_param *kp);
+extern struct kernel_param_ops param_ops_short;
+extern int param_set_short(const char *val, const struct kernel_param *kp);
+extern int param_get_short(char *buffer, const struct kernel_param *kp);
 #define param_check_short(name, p) __param_check(name, p, short)
 
-extern int param_set_ushort(const char *val, struct kernel_param *kp);
-extern int param_get_ushort(char *buffer, struct kernel_param *kp);
+extern struct kernel_param_ops param_ops_ushort;
+extern int param_set_ushort(const char *val, const struct kernel_param *kp);
+extern int param_get_ushort(char *buffer, const struct kernel_param *kp);
 #define param_check_ushort(name, p) __param_check(name, p, unsigned short)
 
-extern int param_set_int(const char *val, struct kernel_param *kp);
-extern int param_get_int(char *buffer, struct kernel_param *kp);
+extern struct kernel_param_ops param_ops_int;
+extern int param_set_int(const char *val, const struct kernel_param *kp);
+extern int param_get_int(char *buffer, const struct kernel_param *kp);
 #define param_check_int(name, p) __param_check(name, p, int)
 
-extern int param_set_uint(const char *val, struct kernel_param *kp);
-extern int param_get_uint(char *buffer, struct kernel_param *kp);
+extern struct kernel_param_ops param_ops_uint;
+extern int param_set_uint(const char *val, const struct kernel_param *kp);
+extern int param_get_uint(char *buffer, const struct kernel_param *kp);
 #define param_check_uint(name, p) __param_check(name, p, unsigned int)
 
-extern int param_set_long(const char *val, struct kernel_param *kp);
-extern int param_get_long(char *buffer, struct kernel_param *kp);
+extern struct kernel_param_ops param_ops_long;
+extern int param_set_long(const char *val, const struct kernel_param *kp);
+extern int param_get_long(char *buffer, const struct kernel_param *kp);
 #define param_check_long(name, p) __param_check(name, p, long)
 
-extern int param_set_ulong(const char *val, struct kernel_param *kp);
-extern int param_get_ulong(char *buffer, struct kernel_param *kp);
+extern struct kernel_param_ops param_ops_ulong;
+extern int param_set_ulong(const char *val, const struct kernel_param *kp);
+extern int param_get_ulong(char *buffer, const struct kernel_param *kp);
 #define param_check_ulong(name, p) __param_check(name, p, unsigned long)
 
-extern int param_set_charp(const char *val, struct kernel_param *kp);
-extern int param_get_charp(char *buffer, struct kernel_param *kp);
+extern struct kernel_param_ops param_ops_charp;
+extern int param_set_charp(const char *val, const struct kernel_param *kp);
+extern int param_get_charp(char *buffer, const struct kernel_param *kp);
 #define param_check_charp(name, p) __param_check(name, p, char *)
 
 /* For historical reasons "bool" parameters can be (unsigned) "int". */
-extern int param_set_bool(const char *val, struct kernel_param *kp);
-extern int param_get_bool(char *buffer, struct kernel_param *kp);
+extern struct kernel_param_ops param_ops_bool;
+extern int param_set_bool(const char *val, const struct kernel_param *kp);
+extern int param_get_bool(char *buffer, const struct kernel_param *kp);
 #define param_check_bool(name, p)					\
 	static inline void __check_##name(void)				\
 	{								\
-		BUILD_BUG_ON(!__same_type(*(p), bool) &&		\
-			     !__same_type(*(p), unsigned int) &&	\
-			     !__same_type(*(p), int));			\
+		BUILD_BUG_ON(!__same_type((p), bool *) &&		\
+			     !__same_type((p), unsigned int *) &&	\
+			     !__same_type((p), int *));			\
 	}
 
-extern int param_set_invbool(const char *val, struct kernel_param *kp);
-extern int param_get_invbool(char *buffer, struct kernel_param *kp);
+extern struct kernel_param_ops param_ops_invbool;
+extern int param_set_invbool(const char *val, const struct kernel_param *kp);
+extern int param_get_invbool(char *buffer, const struct kernel_param *kp);
 #define param_check_invbool(name, p) __param_check(name, p, bool)
 
-/* Comma-separated array: *nump is set to number they actually specified. */
+/**
+ * module_param_array - a parameter which is an array of some type
+ * @name: the name of the array variable
+ * @type: the type, as per module_param()
+ * @nump: optional pointer filled in with the number written
+ * @perm: visibility in sysfs
+ *
+ * Input and output are as comma-separated values.  Commas inside values
+ * don't work properly (eg. an array of charp).
+ *
+ * ARRAY_SIZE(@name) is used to determine the number of elements in the
+ * array, so the definition must be visible.
+ */
+#define module_param_array(name, type, nump, perm)		\
+	module_param_array_named(name, name, type, nump, perm)
+
+/**
+ * module_param_array_named - renamed parameter which is an array of some type
+ * @name: a valid C identifier which is the parameter name
+ * @array: the name of the array variable
+ * @type: the type, as per module_param()
+ * @nump: optional pointer filled in with the number written
+ * @perm: visibility in sysfs
+ *
+ * This exposes a different name than the actual variable name.  See
+ * module_param_named() for why this might be necessary.
+ */
 #define module_param_array_named(name, array, type, nump, perm)		\
 	static const struct kparam_array __param_arr_##name		\
-	= { ARRAY_SIZE(array), nump, param_set_##type, param_get_##type,\
+	= { ARRAY_SIZE(array), nump, &param_ops_##type,			\
 	    sizeof(array[0]), array };					\
 	__module_param_call(MODULE_PARAM_PREFIX, name,			\
-			    param_array_set, param_array_get,		\
+			    &param_array_ops,				\
 			    .arr = &__param_arr_##name,			\
 			    __same_type(array[0], bool), perm);		\
 	__MODULE_PARM_TYPE(name, "array of " #type)
 
-#define module_param_array(name, type, nump, perm)		\
-	module_param_array_named(name, name, type, nump, perm)
+extern struct kernel_param_ops param_array_ops;
 
-extern int param_array_set(const char *val, struct kernel_param *kp);
-extern int param_array_get(char *buffer, struct kernel_param *kp);
-
-extern int param_set_copystring(const char *val, struct kernel_param *kp);
-extern int param_get_string(char *buffer, struct kernel_param *kp);
+extern struct kernel_param_ops param_ops_string;
+extern int param_set_copystring(const char *val, const struct kernel_param *);
+extern int param_get_string(char *buffer, const struct kernel_param *kp);
 
 /* for exporting parameters in /sys/parameters */
 
@@ -235,13 +389,13 @@
 
 #if defined(CONFIG_SYSFS) && defined(CONFIG_MODULES)
 extern int module_param_sysfs_setup(struct module *mod,
-				    struct kernel_param *kparam,
+				    const struct kernel_param *kparam,
 				    unsigned int num_params);
 
 extern void module_param_sysfs_remove(struct module *mod);
 #else
 static inline int module_param_sysfs_setup(struct module *mod,
-			     struct kernel_param *kparam,
+			     const struct kernel_param *kparam,
 			     unsigned int num_params)
 {
 	return 0;
diff --git a/include/linux/of_device.h b/include/linux/of_device.h
index 35aa44a..835f85e 100644
--- a/include/linux/of_device.h
+++ b/include/linux/of_device.h
@@ -1,20 +1,6 @@
 #ifndef _LINUX_OF_DEVICE_H
 #define _LINUX_OF_DEVICE_H
 
-/*
- * The of_device *was* a kind of "base class" that was a superset of
- * struct device for use by devices attached to an OF node and probed
- * using OF properties.  However, the important bit of OF-style
- * probing, namely the device node pointer, has been moved into the
- * common struct device when CONFIG_OF is set to make OF-style probing
- * available to all bus types.  So now, just make of_device and
- * platform_device equivalent so that current of_platform bus users
- * can be transparently migrated over to using the platform bus.
- *
- * This line will go away once all references to of_device are removed
- * from the kernel.
- */
-#define of_device platform_device
 #include <linux/platform_device.h>
 #include <linux/of_platform.h> /* temporary until merge */
 
@@ -23,8 +9,6 @@
 #include <linux/of.h>
 #include <linux/mod_devicetable.h>
 
-#define	to_of_device(d) container_of(d, struct of_device, dev)
-
 extern const struct of_device_id *of_match_device(
 	const struct of_device_id *matches, const struct device *dev);
 extern void of_device_make_bus_id(struct device *dev);
diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h
index 4e6d989..a68716a 100644
--- a/include/linux/of_platform.h
+++ b/include/linux/of_platform.h
@@ -19,9 +19,17 @@
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 
-/*
- * An of_platform_driver driver is attached to a basic of_device on
- * the "platform bus" (platform_bus_type).
+/**
+ * of_platform_driver - Legacy of-aware driver for platform devices.
+ *
+ * An of_platform_driver driver is attached to a basic platform_device on
+ * ether the "platform bus" (platform_bus_type), or the ibm ebus
+ * (ibmebus_bus_type).
+ *
+ * of_platform_driver is being phased out when used with the platform_bus_type,
+ * and regular platform_drivers should be used instead.  When the transition
+ * is complete, only ibmebus will be using this structure, and the
+ * platform_driver member of this structure will be removed.
  */
 struct of_platform_driver
 {
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 78a702c..e12cdc6 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -13,6 +13,7 @@
 #include <linux/gfp.h>
 #include <linux/bitops.h>
 #include <linux/hardirq.h> /* for in_interrupt() */
+#include <linux/hugetlb_inline.h>
 
 /*
  * Bits in mapping->flags.  The lower __GFP_BITS_SHIFT bits are the page
@@ -281,10 +282,16 @@
 	return ((loff_t)page->index) << PAGE_CACHE_SHIFT;
 }
 
+extern pgoff_t linear_hugepage_index(struct vm_area_struct *vma,
+				     unsigned long address);
+
 static inline pgoff_t linear_page_index(struct vm_area_struct *vma,
 					unsigned long address)
 {
-	pgoff_t pgoff = (address - vma->vm_start) >> PAGE_SHIFT;
+	pgoff_t pgoff;
+	if (unlikely(is_vm_hugetlb_page(vma)))
+		return linear_hugepage_index(vma, address);
+	pgoff = (address - vma->vm_start) >> PAGE_SHIFT;
 	pgoff += vma->vm_pgoff;
 	return pgoff >> (PAGE_CACHE_SHIFT - PAGE_SHIFT);
 }
diff --git a/include/linux/poison.h b/include/linux/poison.h
index 34066ff..2110a81 100644
--- a/include/linux/poison.h
+++ b/include/linux/poison.h
@@ -48,15 +48,6 @@
 #define POISON_FREE	0x6b	/* for use-after-free poisoning */
 #define	POISON_END	0xa5	/* end-byte of poisoning */
 
-/********** mm/hugetlb.c **********/
-/*
- * Private mappings of hugetlb pages use this poisoned value for
- * page->mapping. The core VM should not be doing anything with this mapping
- * but futex requires the existence of some page->mapping value even though it
- * is unused if PAGE_MAPPING_ANON is set.
- */
-#define HUGETLB_POISON	((void *)(0x00300300 + POISON_POINTER_DELTA + PAGE_MAPPING_ANON))
-
 /********** arch/$ARCH/mm/init.c **********/
 #define POISON_FREE_INITMEM	0xcc
 
diff --git a/include/linux/raid/pq.h b/include/linux/raid/pq.h
index 1cbbd2c..2b59cc8 100644
--- a/include/linux/raid/pq.h
+++ b/include/linux/raid/pq.h
@@ -62,7 +62,9 @@
 #define disable_kernel_altivec()
 
 #define EXPORT_SYMBOL(sym)
+#define EXPORT_SYMBOL_GPL(sym)
 #define MODULE_LICENSE(licence)
+#define MODULE_DESCRIPTION(desc)
 #define subsys_initcall(x)
 #define module_exit(x)
 #endif /* __KERNEL__ */
diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h
new file mode 100644
index 0000000..f509877
--- /dev/null
+++ b/include/linux/regulator/ab8500.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ *
+ */
+
+#ifndef __LINUX_MFD_AB8500_REGULATOR_H
+#define __LINUX_MFD_AB8500_REGULATOR_H
+
+/* AB8500 regulators */
+#define AB8500_LDO_AUX1         0
+#define AB8500_LDO_AUX2         1
+#define AB8500_LDO_AUX3         2
+#define AB8500_LDO_INTCORE      3
+#define AB8500_LDO_TVOUT        4
+#define AB8500_LDO_AUDIO	5
+#define AB8500_LDO_ANAMIC1      6
+#define AB8500_LDO_ANAMIC2      7
+#define AB8500_LDO_DMIC         8
+#define AB8500_LDO_ANA          9
+
+#endif
diff --git a/include/linux/rmap.h b/include/linux/rmap.h
index d6661de..31b2fd7 100644
--- a/include/linux/rmap.h
+++ b/include/linux/rmap.h
@@ -168,6 +168,11 @@
 void page_add_file_rmap(struct page *);
 void page_remove_rmap(struct page *);
 
+void hugepage_add_anon_rmap(struct page *, struct vm_area_struct *,
+			    unsigned long);
+void hugepage_add_new_anon_rmap(struct page *, struct vm_area_struct *,
+				unsigned long);
+
 static inline void page_dup_rmap(struct page *page)
 {
 	atomic_inc(&page->_mapcount);
diff --git a/include/linux/s3c_adc_battery.h b/include/linux/s3c_adc_battery.h
new file mode 100644
index 0000000..dbce22f
--- /dev/null
+++ b/include/linux/s3c_adc_battery.h
@@ -0,0 +1,36 @@
+#ifndef _S3C_ADC_BATTERY_H
+#define _S3C_ADC_BATTERY_H
+
+struct s3c_adc_bat_thresh {
+	int volt; /* mV */
+	int cur; /* mA */
+	int level; /* percent */
+};
+
+struct s3c_adc_bat_pdata {
+	int (*init)(void);
+	void (*exit)(void);
+	void (*enable_charger)(void);
+	void (*disable_charger)(void);
+
+	int gpio_charge_finished;
+
+	const struct s3c_adc_bat_thresh *lut_noac;
+	unsigned int lut_noac_cnt;
+	const struct s3c_adc_bat_thresh *lut_acin;
+	unsigned int lut_acin_cnt;
+
+	const unsigned int volt_channel;
+	const unsigned int current_channel;
+	const unsigned int backup_volt_channel;
+
+	const unsigned int volt_mult;
+	const unsigned int current_mult;
+	const unsigned int backup_volt_mult;
+	const unsigned int internal_impedance;
+
+	const unsigned int backup_volt_max;
+	const unsigned int backup_volt_min;
+};
+
+#endif
diff --git a/include/linux/time.h b/include/linux/time.h
index cb34e35..1261270 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -38,7 +38,7 @@
 #define NSEC_PER_MSEC	1000000L
 #define USEC_PER_SEC	1000000L
 #define NSEC_PER_SEC	1000000000L
-#define FSEC_PER_SEC	1000000000000000L
+#define FSEC_PER_SEC	1000000000000000LL
 
 #define TIME_T_MAX	(time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
 
diff --git a/include/linux/vgaarb.h b/include/linux/vgaarb.h
index 814f294..6228b5b 100644
--- a/include/linux/vgaarb.h
+++ b/include/linux/vgaarb.h
@@ -31,7 +31,6 @@
 #ifndef LINUX_VGA_H
 #define LINUX_VGA_H
 
-#include <asm/vga.h>
 
 /* Legacy VGA regions */
 #define VGA_RSRC_NONE	       0x00
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index de05e96..01c2145 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -7,6 +7,8 @@
 
 struct vm_area_struct;		/* vma defining user mapping in mm_types.h */
 
+extern bool vmap_lazy_unmap;
+
 /* bits in flags of vmalloc's vm_struct below */
 #define VM_IOREMAP	0x00000001	/* ioremap() and friends */
 #define VM_ALLOC	0x00000002	/* vmalloc() */
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index c24eca7..72a5d64 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -124,8 +124,9 @@
 int dirty_writeback_centisecs_handler(struct ctl_table *, int,
 				      void __user *, size_t *, loff_t *);
 
-void get_dirty_limits(unsigned long *pbackground, unsigned long *pdirty,
-		      unsigned long *pbdi_dirty, struct backing_dev_info *bdi);
+void global_dirty_limits(unsigned long *pbackground, unsigned long *pdirty);
+unsigned long bdi_dirty_limit(struct backing_dev_info *bdi,
+			       unsigned long dirty);
 
 void page_writeback_init(void);
 void balance_dirty_pages_ratelimited_nr(struct address_space *mapping,
diff --git a/include/xen/interface/memory.h b/include/xen/interface/memory.h
index af36ead..d3938d3 100644
--- a/include/xen/interface/memory.h
+++ b/include/xen/interface/memory.h
@@ -9,6 +9,8 @@
 #ifndef __XEN_PUBLIC_MEMORY_H__
 #define __XEN_PUBLIC_MEMORY_H__
 
+#include <linux/spinlock.h>
+
 /*
  * Increase or decrease the specified domain's memory reservation. Returns a
  * -ve errcode on failure, or the # extents successfully allocated or freed.
@@ -53,6 +55,48 @@
 DEFINE_GUEST_HANDLE_STRUCT(xen_memory_reservation);
 
 /*
+ * An atomic exchange of memory pages. If return code is zero then
+ * @out.extent_list provides GMFNs of the newly-allocated memory.
+ * Returns zero on complete success, otherwise a negative error code.
+ * On complete success then always @nr_exchanged == @in.nr_extents.
+ * On partial success @nr_exchanged indicates how much work was done.
+ */
+#define XENMEM_exchange             11
+struct xen_memory_exchange {
+    /*
+     * [IN] Details of memory extents to be exchanged (GMFN bases).
+     * Note that @in.address_bits is ignored and unused.
+     */
+    struct xen_memory_reservation in;
+
+    /*
+     * [IN/OUT] Details of new memory extents.
+     * We require that:
+     *  1. @in.domid == @out.domid
+     *  2. @in.nr_extents  << @in.extent_order ==
+     *     @out.nr_extents << @out.extent_order
+     *  3. @in.extent_start and @out.extent_start lists must not overlap
+     *  4. @out.extent_start lists GPFN bases to be populated
+     *  5. @out.extent_start is overwritten with allocated GMFN bases
+     */
+    struct xen_memory_reservation out;
+
+    /*
+     * [OUT] Number of input extents that were successfully exchanged:
+     *  1. The first @nr_exchanged input extents were successfully
+     *     deallocated.
+     *  2. The corresponding first entries in the output extent list correctly
+     *     indicate the GMFNs that were successfully exchanged.
+     *  3. All other input and output extents are untouched.
+     *  4. If not all input exents are exchanged then the return code of this
+     *     command will be non-zero.
+     *  5. THIS FIELD MUST BE INITIALISED TO ZERO BY THE CALLER!
+     */
+    unsigned long nr_exchanged;
+};
+
+DEFINE_GUEST_HANDLE_STRUCT(xen_memory_exchange);
+/*
  * Returns the maximum machine frame number of mapped RAM in this system.
  * This command always succeeds (it never returns an error code).
  * arg == NULL.
@@ -142,4 +186,10 @@
 };
 DEFINE_GUEST_HANDLE_STRUCT(xen_translate_gpfn_list);
 
+
+/*
+ * Prevent the balloon driver from changing the memory reservation
+ * during a driver critical region.
+ */
+extern spinlock_t xen_reservation_lock;
 #endif /* __XEN_PUBLIC_MEMORY_H__ */
diff --git a/include/xen/swiotlb-xen.h b/include/xen/swiotlb-xen.h
new file mode 100644
index 0000000..2ea2fdc
--- /dev/null
+++ b/include/xen/swiotlb-xen.h
@@ -0,0 +1,65 @@
+#ifndef __LINUX_SWIOTLB_XEN_H
+#define __LINUX_SWIOTLB_XEN_H
+
+#include <linux/swiotlb.h>
+
+extern void xen_swiotlb_init(int verbose);
+
+extern void
+*xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
+			    dma_addr_t *dma_handle, gfp_t flags);
+
+extern void
+xen_swiotlb_free_coherent(struct device *hwdev, size_t size,
+			  void *vaddr, dma_addr_t dma_handle);
+
+extern dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
+				       unsigned long offset, size_t size,
+				       enum dma_data_direction dir,
+				       struct dma_attrs *attrs);
+
+extern void xen_swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr,
+				   size_t size, enum dma_data_direction dir,
+				   struct dma_attrs *attrs);
+/*
+extern int
+xen_swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, int nents,
+		   enum dma_data_direction dir);
+
+extern void
+xen_swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nents,
+		     enum dma_data_direction dir);
+*/
+extern int
+xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
+			 int nelems, enum dma_data_direction dir,
+			 struct dma_attrs *attrs);
+
+extern void
+xen_swiotlb_unmap_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
+			   int nelems, enum dma_data_direction dir,
+			   struct dma_attrs *attrs);
+
+extern void
+xen_swiotlb_sync_single_for_cpu(struct device *hwdev, dma_addr_t dev_addr,
+				size_t size, enum dma_data_direction dir);
+
+extern void
+xen_swiotlb_sync_sg_for_cpu(struct device *hwdev, struct scatterlist *sg,
+			    int nelems, enum dma_data_direction dir);
+
+extern void
+xen_swiotlb_sync_single_for_device(struct device *hwdev, dma_addr_t dev_addr,
+				   size_t size, enum dma_data_direction dir);
+
+extern void
+xen_swiotlb_sync_sg_for_device(struct device *hwdev, struct scatterlist *sg,
+			       int nelems, enum dma_data_direction dir);
+
+extern int
+xen_swiotlb_dma_mapping_error(struct device *hwdev, dma_addr_t dma_addr);
+
+extern int
+xen_swiotlb_dma_supported(struct device *hwdev, u64 mask);
+
+#endif /* __LINUX_SWIOTLB_XEN_H */
diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h
index 46bc81e..351f405 100644
--- a/include/xen/xen-ops.h
+++ b/include/xen/xen-ops.h
@@ -17,4 +17,10 @@
 
 int xen_setup_shutdown_event(void);
 
+extern unsigned long *xen_contiguous_bitmap;
+int xen_create_contiguous_region(unsigned long vstart, unsigned int order,
+				unsigned int address_bits);
+
+void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order);
+
 #endif /* INCLUDE_XEN_OPS_H */
diff --git a/init/main.c b/init/main.c
index 86cbfd0..22d61cb 100644
--- a/init/main.c
+++ b/init/main.c
@@ -201,11 +201,11 @@
 char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };
 static const char *panic_later, *panic_param;
 
-extern struct obs_kernel_param __setup_start[], __setup_end[];
+extern const struct obs_kernel_param __setup_start[], __setup_end[];
 
 static int __init obsolete_checksetup(char *line)
 {
-	struct obs_kernel_param *p;
+	const struct obs_kernel_param *p;
 	int had_early_param = 0;
 
 	p = __setup_start;
@@ -458,7 +458,7 @@
 /* Check for early params. */
 static int __init do_early_param(char *param, char *val)
 {
-	struct obs_kernel_param *p;
+	const struct obs_kernel_param *p;
 
 	for (p = __setup_start; p < __setup_end; p++) {
 		if ((p->early && strcmp(param, p->str) == 0) ||
@@ -536,7 +536,7 @@
 asmlinkage void __init start_kernel(void)
 {
 	char * command_line;
-	extern struct kernel_param __start___param[], __stop___param[];
+	extern const struct kernel_param __start___param[], __stop___param[];
 
 	smp_setup_processor_id();
 
diff --git a/kernel/cred.c b/kernel/cred.c
index 60bc8b1..9a3e226 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -22,10 +22,6 @@
 #define kdebug(FMT, ...) \
 	printk("[%-5.5s%5u] "FMT"\n", current->comm, current->pid ,##__VA_ARGS__)
 #else
-static inline __attribute__((format(printf, 1, 2)))
-void no_printk(const char *fmt, ...)
-{
-}
 #define kdebug(FMT, ...) \
 	no_printk("[%-5.5s%5u] "FMT"\n", current->comm, current->pid ,##__VA_ARGS__)
 #endif
diff --git a/kernel/kfifo.c b/kernel/kfifo.c
index 02192dd..4502604 100644
--- a/kernel/kfifo.c
+++ b/kernel/kfifo.c
@@ -10,7 +10,7 @@
  *
  * 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
+ * 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
@@ -333,17 +333,16 @@
 		buf += PAGE_SIZE;
 		npage = virt_to_page(buf);
 		if (page_to_phys(page) != page_to_phys(npage) - l) {
-			sgl->page_link = 0;
-			sg_set_page(sgl++, page, l - off, off);
-			if (++n == nents)
+			sg_set_page(sgl, page, l - off, off);
+			sgl = sg_next(sgl);
+			if (++n == nents || sgl == NULL)
 				return n;
 			page = npage;
 			len -= l - off;
 			l = off = 0;
 		}
 	}
-	sgl->page_link = 0;
-	sg_set_page(sgl++, page, len, off);
+	sg_set_page(sgl, page, len, off);
 	return n + 1;
 }
 
@@ -363,7 +362,7 @@
 	}
 	l = min(len, size - off);
 
-	n  = setup_sgl_buf(sgl, fifo->data + off, nents, l);
+	n = setup_sgl_buf(sgl, fifo->data + off, nents, l);
 	n += setup_sgl_buf(sgl + n, fifo->data, nents - n, len - l);
 
 	if (n)
diff --git a/kernel/params.c b/kernel/params.c
index 0b30ecd..08107d1 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -31,6 +31,42 @@
 #define DEBUGP(fmt, a...)
 #endif
 
+/* Protects all parameters, and incidentally kmalloced_param list. */
+static DEFINE_MUTEX(param_lock);
+
+/* This just allows us to keep track of which parameters are kmalloced. */
+struct kmalloced_param {
+	struct list_head list;
+	char val[];
+};
+static LIST_HEAD(kmalloced_params);
+
+static void *kmalloc_parameter(unsigned int size)
+{
+	struct kmalloced_param *p;
+
+	p = kmalloc(sizeof(*p) + size, GFP_KERNEL);
+	if (!p)
+		return NULL;
+
+	list_add(&p->list, &kmalloced_params);
+	return p->val;
+}
+
+/* Does nothing if parameter wasn't kmalloced above. */
+static void maybe_kfree_parameter(void *param)
+{
+	struct kmalloced_param *p;
+
+	list_for_each_entry(p, &kmalloced_params, list) {
+		if (p->val == param) {
+			list_del(&p->list);
+			kfree(p);
+			break;
+		}
+	}
+}
+
 static inline char dash2underscore(char c)
 {
 	if (c == '-')
@@ -49,18 +85,25 @@
 
 static int parse_one(char *param,
 		     char *val,
-		     struct kernel_param *params, 
+		     const struct kernel_param *params,
 		     unsigned num_params,
 		     int (*handle_unknown)(char *param, char *val))
 {
 	unsigned int i;
+	int err;
 
 	/* Find parameter */
 	for (i = 0; i < num_params; i++) {
 		if (parameq(param, params[i].name)) {
+			/* Noone handled NULL, so do it here. */
+			if (!val && params[i].ops->set != param_set_bool)
+				return -EINVAL;
 			DEBUGP("They are equal!  Calling %p\n",
-			       params[i].set);
-			return params[i].set(val, &params[i]);
+			       params[i].ops->set);
+			mutex_lock(&param_lock);
+			err = params[i].ops->set(val, &params[i]);
+			mutex_unlock(&param_lock);
+			return err;
 		}
 	}
 
@@ -128,7 +171,7 @@
 /* Args looks like "foo=bar,bar2 baz=fuz wiz". */
 int parse_args(const char *name,
 	       char *args,
-	       struct kernel_param *params,
+	       const struct kernel_param *params,
 	       unsigned num,
 	       int (*unknown)(char *param, char *val))
 {
@@ -176,22 +219,29 @@
 
 /* Lazy bastard, eh? */
 #define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn)      	\
-	int param_set_##name(const char *val, struct kernel_param *kp)	\
+	int param_set_##name(const char *val, const struct kernel_param *kp) \
 	{								\
 		tmptype l;						\
 		int ret;						\
 									\
-		if (!val) return -EINVAL;				\
 		ret = strtolfn(val, 0, &l);				\
 		if (ret == -EINVAL || ((type)l != l))			\
 			return -EINVAL;					\
 		*((type *)kp->arg) = l;					\
 		return 0;						\
 	}								\
-	int param_get_##name(char *buffer, struct kernel_param *kp)	\
+	int param_get_##name(char *buffer, const struct kernel_param *kp) \
 	{								\
 		return sprintf(buffer, format, *((type *)kp->arg));	\
-	}
+	}								\
+	struct kernel_param_ops param_ops_##name = {			\
+		.set = param_set_##name,				\
+		.get = param_get_##name,				\
+	};								\
+	EXPORT_SYMBOL(param_set_##name);				\
+	EXPORT_SYMBOL(param_get_##name);				\
+	EXPORT_SYMBOL(param_ops_##name)
+
 
 STANDARD_PARAM_DEF(byte, unsigned char, "%c", unsigned long, strict_strtoul);
 STANDARD_PARAM_DEF(short, short, "%hi", long, strict_strtol);
@@ -201,39 +251,50 @@
 STANDARD_PARAM_DEF(long, long, "%li", long, strict_strtol);
 STANDARD_PARAM_DEF(ulong, unsigned long, "%lu", unsigned long, strict_strtoul);
 
-int param_set_charp(const char *val, struct kernel_param *kp)
+int param_set_charp(const char *val, const struct kernel_param *kp)
 {
-	if (!val) {
-		printk(KERN_ERR "%s: string parameter expected\n",
-		       kp->name);
-		return -EINVAL;
-	}
-
 	if (strlen(val) > 1024) {
 		printk(KERN_ERR "%s: string parameter too long\n",
 		       kp->name);
 		return -ENOSPC;
 	}
 
-	/* This is a hack.  We can't need to strdup in early boot, and we
+	maybe_kfree_parameter(*(char **)kp->arg);
+
+	/* This is a hack.  We can't kmalloc in early boot, and we
 	 * don't need to; this mangled commandline is preserved. */
 	if (slab_is_available()) {
-		*(char **)kp->arg = kstrdup(val, GFP_KERNEL);
+		*(char **)kp->arg = kmalloc_parameter(strlen(val)+1);
 		if (!*(char **)kp->arg)
 			return -ENOMEM;
+		strcpy(*(char **)kp->arg, val);
 	} else
 		*(const char **)kp->arg = val;
 
 	return 0;
 }
+EXPORT_SYMBOL(param_set_charp);
 
-int param_get_charp(char *buffer, struct kernel_param *kp)
+int param_get_charp(char *buffer, const struct kernel_param *kp)
 {
 	return sprintf(buffer, "%s", *((char **)kp->arg));
 }
+EXPORT_SYMBOL(param_get_charp);
+
+static void param_free_charp(void *arg)
+{
+	maybe_kfree_parameter(*((char **)arg));
+}
+
+struct kernel_param_ops param_ops_charp = {
+	.set = param_set_charp,
+	.get = param_get_charp,
+	.free = param_free_charp,
+};
+EXPORT_SYMBOL(param_ops_charp);
 
 /* Actually could be a bool or an int, for historical reasons. */
-int param_set_bool(const char *val, struct kernel_param *kp)
+int param_set_bool(const char *val, const struct kernel_param *kp)
 {
 	bool v;
 
@@ -258,8 +319,9 @@
 		*(int *)kp->arg = v;
 	return 0;
 }
+EXPORT_SYMBOL(param_set_bool);
 
-int param_get_bool(char *buffer, struct kernel_param *kp)
+int param_get_bool(char *buffer, const struct kernel_param *kp)
 {
 	bool val;
 	if (kp->flags & KPARAM_ISBOOL)
@@ -270,9 +332,16 @@
 	/* Y and N chosen as being relatively non-coder friendly */
 	return sprintf(buffer, "%c", val ? 'Y' : 'N');
 }
+EXPORT_SYMBOL(param_get_bool);
+
+struct kernel_param_ops param_ops_bool = {
+	.set = param_set_bool,
+	.get = param_get_bool,
+};
+EXPORT_SYMBOL(param_ops_bool);
 
 /* This one must be bool. */
-int param_set_invbool(const char *val, struct kernel_param *kp)
+int param_set_invbool(const char *val, const struct kernel_param *kp)
 {
 	int ret;
 	bool boolval;
@@ -285,18 +354,26 @@
 		*(bool *)kp->arg = !boolval;
 	return ret;
 }
+EXPORT_SYMBOL(param_set_invbool);
 
-int param_get_invbool(char *buffer, struct kernel_param *kp)
+int param_get_invbool(char *buffer, const struct kernel_param *kp)
 {
 	return sprintf(buffer, "%c", (*(bool *)kp->arg) ? 'N' : 'Y');
 }
+EXPORT_SYMBOL(param_get_invbool);
+
+struct kernel_param_ops param_ops_invbool = {
+	.set = param_set_invbool,
+	.get = param_get_invbool,
+};
+EXPORT_SYMBOL(param_ops_invbool);
 
 /* We break the rule and mangle the string. */
 static int param_array(const char *name,
 		       const char *val,
 		       unsigned int min, unsigned int max,
 		       void *elem, int elemsize,
-		       int (*set)(const char *, struct kernel_param *kp),
+		       int (*set)(const char *, const struct kernel_param *kp),
 		       u16 flags,
 		       unsigned int *num)
 {
@@ -309,12 +386,6 @@
 	kp.arg = elem;
 	kp.flags = flags;
 
-	/* No equals sign? */
-	if (!val) {
-		printk(KERN_ERR "%s: expects arguments\n", name);
-		return -EINVAL;
-	}
-
 	*num = 0;
 	/* We expect a comma-separated list of values. */
 	do {
@@ -330,6 +401,7 @@
 		/* nul-terminate and parse */
 		save = val[len];
 		((char *)val)[len] = '\0';
+		BUG_ON(!mutex_is_locked(&param_lock));
 		ret = set(val, &kp);
 
 		if (ret != 0)
@@ -347,17 +419,17 @@
 	return 0;
 }
 
-int param_array_set(const char *val, struct kernel_param *kp)
+static int param_array_set(const char *val, const struct kernel_param *kp)
 {
 	const struct kparam_array *arr = kp->arr;
 	unsigned int temp_num;
 
 	return param_array(kp->name, val, 1, arr->max, arr->elem,
-			   arr->elemsize, arr->set, kp->flags,
+			   arr->elemsize, arr->ops->set, kp->flags,
 			   arr->num ?: &temp_num);
 }
 
-int param_array_get(char *buffer, struct kernel_param *kp)
+static int param_array_get(char *buffer, const struct kernel_param *kp)
 {
 	int i, off, ret;
 	const struct kparam_array *arr = kp->arr;
@@ -368,7 +440,8 @@
 		if (i)
 			buffer[off++] = ',';
 		p.arg = arr->elem + arr->elemsize * i;
-		ret = arr->get(buffer + off, &p);
+		BUG_ON(!mutex_is_locked(&param_lock));
+		ret = arr->ops->get(buffer + off, &p);
 		if (ret < 0)
 			return ret;
 		off += ret;
@@ -377,14 +450,27 @@
 	return off;
 }
 
-int param_set_copystring(const char *val, struct kernel_param *kp)
+static void param_array_free(void *arg)
+{
+	unsigned int i;
+	const struct kparam_array *arr = arg;
+
+	if (arr->ops->free)
+		for (i = 0; i < (arr->num ? *arr->num : arr->max); i++)
+			arr->ops->free(arr->elem + arr->elemsize * i);
+}
+
+struct kernel_param_ops param_array_ops = {
+	.set = param_array_set,
+	.get = param_array_get,
+	.free = param_array_free,
+};
+EXPORT_SYMBOL(param_array_ops);
+
+int param_set_copystring(const char *val, const struct kernel_param *kp)
 {
 	const struct kparam_string *kps = kp->str;
 
-	if (!val) {
-		printk(KERN_ERR "%s: missing param set value\n", kp->name);
-		return -EINVAL;
-	}
 	if (strlen(val)+1 > kps->maxlen) {
 		printk(KERN_ERR "%s: string doesn't fit in %u chars.\n",
 		       kp->name, kps->maxlen-1);
@@ -393,12 +479,20 @@
 	strcpy(kps->string, val);
 	return 0;
 }
+EXPORT_SYMBOL(param_set_copystring);
 
-int param_get_string(char *buffer, struct kernel_param *kp)
+int param_get_string(char *buffer, const struct kernel_param *kp)
 {
 	const struct kparam_string *kps = kp->str;
 	return strlcpy(buffer, kps->string, kps->maxlen);
 }
+EXPORT_SYMBOL(param_get_string);
+
+struct kernel_param_ops param_ops_string = {
+	.set = param_set_copystring,
+	.get = param_get_string,
+};
+EXPORT_SYMBOL(param_ops_string);
 
 /* sysfs output in /sys/modules/XYZ/parameters/ */
 #define to_module_attr(n) container_of(n, struct module_attribute, attr)
@@ -409,7 +503,7 @@
 struct param_attribute
 {
 	struct module_attribute mattr;
-	struct kernel_param *param;
+	const struct kernel_param *param;
 };
 
 struct module_param_attrs
@@ -428,10 +522,12 @@
 	int count;
 	struct param_attribute *attribute = to_param_attr(mattr);
 
-	if (!attribute->param->get)
+	if (!attribute->param->ops->get)
 		return -EPERM;
 
-	count = attribute->param->get(buf, attribute->param);
+	mutex_lock(&param_lock);
+	count = attribute->param->ops->get(buf, attribute->param);
+	mutex_unlock(&param_lock);
 	if (count > 0) {
 		strcat(buf, "\n");
 		++count;
@@ -447,10 +543,12 @@
  	int err;
 	struct param_attribute *attribute = to_param_attr(mattr);
 
-	if (!attribute->param->set)
+	if (!attribute->param->ops->set)
 		return -EPERM;
 
-	err = attribute->param->set(buf, attribute->param);
+	mutex_lock(&param_lock);
+	err = attribute->param->ops->set(buf, attribute->param);
+	mutex_unlock(&param_lock);
 	if (!err)
 		return len;
 	return err;
@@ -464,6 +562,18 @@
 #endif
 
 #ifdef CONFIG_SYSFS
+void __kernel_param_lock(void)
+{
+	mutex_lock(&param_lock);
+}
+EXPORT_SYMBOL(__kernel_param_lock);
+
+void __kernel_param_unlock(void)
+{
+	mutex_unlock(&param_lock);
+}
+EXPORT_SYMBOL(__kernel_param_unlock);
+
 /*
  * add_sysfs_param - add a parameter to sysfs
  * @mk: struct module_kobject
@@ -475,7 +585,7 @@
  * if there's an error.
  */
 static __modinit int add_sysfs_param(struct module_kobject *mk,
-				     struct kernel_param *kp,
+				     const struct kernel_param *kp,
 				     const char *name)
 {
 	struct module_param_attrs *new;
@@ -557,7 +667,7 @@
  * /sys/module/[mod->name]/parameters/
  */
 int module_param_sysfs_setup(struct module *mod,
-			     struct kernel_param *kparam,
+			     const struct kernel_param *kparam,
 			     unsigned int num_params)
 {
 	int i, err;
@@ -602,7 +712,11 @@
 
 void destroy_params(const struct kernel_param *params, unsigned num)
 {
-	/* FIXME: This should free kmalloced charp parameters.  It doesn't. */
+	unsigned int i;
+
+	for (i = 0; i < num; i++)
+		if (params[i].ops->free)
+			params[i].ops->free(params[i].arg);
 }
 
 static void __init kernel_add_sysfs_param(const char *name,
@@ -768,28 +882,3 @@
 subsys_initcall(param_sysfs_init);
 
 #endif /* CONFIG_SYSFS */
-
-EXPORT_SYMBOL(param_set_byte);
-EXPORT_SYMBOL(param_get_byte);
-EXPORT_SYMBOL(param_set_short);
-EXPORT_SYMBOL(param_get_short);
-EXPORT_SYMBOL(param_set_ushort);
-EXPORT_SYMBOL(param_get_ushort);
-EXPORT_SYMBOL(param_set_int);
-EXPORT_SYMBOL(param_get_int);
-EXPORT_SYMBOL(param_set_uint);
-EXPORT_SYMBOL(param_get_uint);
-EXPORT_SYMBOL(param_set_long);
-EXPORT_SYMBOL(param_get_long);
-EXPORT_SYMBOL(param_set_ulong);
-EXPORT_SYMBOL(param_get_ulong);
-EXPORT_SYMBOL(param_set_charp);
-EXPORT_SYMBOL(param_get_charp);
-EXPORT_SYMBOL(param_set_bool);
-EXPORT_SYMBOL(param_get_bool);
-EXPORT_SYMBOL(param_set_invbool);
-EXPORT_SYMBOL(param_get_invbool);
-EXPORT_SYMBOL(param_array_set);
-EXPORT_SYMBOL(param_array_get);
-EXPORT_SYMBOL(param_set_copystring);
-EXPORT_SYMBOL(param_get_string);
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index e14c839..e960d82 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -690,6 +690,7 @@
 static cycle_t logarithmic_accumulation(cycle_t offset, int shift)
 {
 	u64 nsecps = (u64)NSEC_PER_SEC << timekeeper.shift;
+	u64 raw_nsecs;
 
 	/* If the offset is smaller then a shifted interval, do nothing */
 	if (offset < timekeeper.cycle_interval<<shift)
@@ -706,12 +707,14 @@
 		second_overflow();
 	}
 
-	/* Accumulate into raw time */
-	raw_time.tv_nsec += timekeeper.raw_interval << shift;;
-	while (raw_time.tv_nsec >= NSEC_PER_SEC) {
-		raw_time.tv_nsec -= NSEC_PER_SEC;
+	/* Accumulate raw time */
+	raw_nsecs = timekeeper.raw_interval << shift;
+	raw_nsecs += raw_time.tv_nsec;
+	while (raw_nsecs >= NSEC_PER_SEC) {
+		raw_nsecs -= NSEC_PER_SEC;
 		raw_time.tv_sec++;
 	}
+	raw_time.tv_nsec = raw_nsecs;
 
 	/* Accumulate error between NTP and clock interval */
 	timekeeper.ntp_error += tick_length << shift;
diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
index 82499a5..959f8d6 100644
--- a/kernel/trace/blktrace.c
+++ b/kernel/trace/blktrace.c
@@ -710,6 +710,9 @@
 	if (rq->cmd_flags & REQ_DISCARD)
 		rw |= REQ_DISCARD;
 
+	if (rq->cmd_flags & REQ_SECURE)
+		rw |= REQ_SECURE;
+
 	if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
 		what |= BLK_TC_ACT(BLK_TC_PC);
 		__blk_add_trace(bt, 0, blk_rq_bytes(rq), rw,
@@ -1816,6 +1819,8 @@
 		rwbs[i++] = 'S';
 	if (rw & REQ_META)
 		rwbs[i++] = 'M';
+	if (rw & REQ_SECURE)
+		rwbs[i++] = 'E';
 
 	rwbs[i] = '\0';
 }
@@ -1828,6 +1833,9 @@
 	if (rq->cmd_flags & REQ_DISCARD)
 		rw |= REQ_DISCARD;
 
+	if (rq->cmd_flags & REQ_SECURE)
+		rw |= REQ_SECURE;
+
 	bytes = blk_rq_bytes(rq);
 
 	blk_fill_rwbs(rwbs, rw, bytes);
diff --git a/lib/inflate.c b/lib/inflate.c
index 677b738..013a761 100644
--- a/lib/inflate.c
+++ b/lib/inflate.c
@@ -103,7 +103,9 @@
       the two sets of lengths.
  */
 #include <linux/compiler.h>
+#ifdef NO_INFLATE_MALLOC
 #include <linux/slab.h>
+#endif
 
 #ifdef RCSID
 static char rcsid[] = "#Id: inflate.c,v 0.14 1993/06/10 13:27:04 jloup Exp #";
diff --git a/lib/raid6/Makefile b/lib/raid6/Makefile
index 19bf32d..8a38102 100644
--- a/lib/raid6/Makefile
+++ b/lib/raid6/Makefile
@@ -1,11 +1,8 @@
 obj-$(CONFIG_RAID6_PQ)	+= raid6_pq.o
 
-raid6_pq-y	+= raid6algos.o raid6recov.o raid6tables.o \
-		   raid6int1.o raid6int2.o raid6int4.o \
-		   raid6int8.o raid6int16.o raid6int32.o \
-		   raid6altivec1.o raid6altivec2.o raid6altivec4.o \
-		   raid6altivec8.o \
-		   raid6mmx.o raid6sse1.o raid6sse2.o
+raid6_pq-y	+= algos.o recov.o tables.o int1.o int2.o int4.o \
+		   int8.o int16.o int32.o altivec1.o altivec2.o altivec4.o \
+		   altivec8.o mmx.o sse1.o sse2.o
 hostprogs-y	+= mktables
 
 quiet_cmd_unroll = UNROLL  $@
@@ -16,63 +13,63 @@
 altivec_flags := -maltivec -mabi=altivec
 endif
 
-targets += raid6int1.c
-$(obj)/raid6int1.c:   UNROLL := 1
-$(obj)/raid6int1.c:   $(src)/raid6int.uc $(src)/unroll.awk FORCE
+targets += int1.c
+$(obj)/int1.c:   UNROLL := 1
+$(obj)/int1.c:   $(src)/int.uc $(src)/unroll.awk FORCE
 	$(call if_changed,unroll)
 
-targets += raid6int2.c
-$(obj)/raid6int2.c:   UNROLL := 2
-$(obj)/raid6int2.c:   $(src)/raid6int.uc $(src)/unroll.awk FORCE
+targets += int2.c
+$(obj)/int2.c:   UNROLL := 2
+$(obj)/int2.c:   $(src)/int.uc $(src)/unroll.awk FORCE
 	$(call if_changed,unroll)
 
-targets += raid6int4.c
-$(obj)/raid6int4.c:   UNROLL := 4
-$(obj)/raid6int4.c:   $(src)/raid6int.uc $(src)/unroll.awk FORCE
+targets += int4.c
+$(obj)/int4.c:   UNROLL := 4
+$(obj)/int4.c:   $(src)/int.uc $(src)/unroll.awk FORCE
 	$(call if_changed,unroll)
 
-targets += raid6int8.c
-$(obj)/raid6int8.c:   UNROLL := 8
-$(obj)/raid6int8.c:   $(src)/raid6int.uc $(src)/unroll.awk FORCE
+targets += int8.c
+$(obj)/int8.c:   UNROLL := 8
+$(obj)/int8.c:   $(src)/int.uc $(src)/unroll.awk FORCE
 	$(call if_changed,unroll)
 
-targets += raid6int16.c
-$(obj)/raid6int16.c:  UNROLL := 16
-$(obj)/raid6int16.c:  $(src)/raid6int.uc $(src)/unroll.awk FORCE
+targets += int16.c
+$(obj)/int16.c:  UNROLL := 16
+$(obj)/int16.c:  $(src)/int.uc $(src)/unroll.awk FORCE
 	$(call if_changed,unroll)
 
-targets += raid6int32.c
-$(obj)/raid6int32.c:  UNROLL := 32
-$(obj)/raid6int32.c:  $(src)/raid6int.uc $(src)/unroll.awk FORCE
+targets += int32.c
+$(obj)/int32.c:  UNROLL := 32
+$(obj)/int32.c:  $(src)/int.uc $(src)/unroll.awk FORCE
 	$(call if_changed,unroll)
 
-CFLAGS_raid6altivec1.o += $(altivec_flags)
-targets += raid6altivec1.c
-$(obj)/raid6altivec1.c:   UNROLL := 1
-$(obj)/raid6altivec1.c:   $(src)/raid6altivec.uc $(src)/unroll.awk FORCE
+CFLAGS_altivec1.o += $(altivec_flags)
+targets += altivec1.c
+$(obj)/altivec1.c:   UNROLL := 1
+$(obj)/altivec1.c:   $(src)/altivec.uc $(src)/unroll.awk FORCE
 	$(call if_changed,unroll)
 
-CFLAGS_raid6altivec2.o += $(altivec_flags)
-targets += raid6altivec2.c
-$(obj)/raid6altivec2.c:   UNROLL := 2
-$(obj)/raid6altivec2.c:   $(src)/raid6altivec.uc $(src)/unroll.awk FORCE
+CFLAGS_altivec2.o += $(altivec_flags)
+targets += altivec2.c
+$(obj)/altivec2.c:   UNROLL := 2
+$(obj)/altivec2.c:   $(src)/altivec.uc $(src)/unroll.awk FORCE
 	$(call if_changed,unroll)
 
-CFLAGS_raid6altivec4.o += $(altivec_flags)
-targets += raid6altivec4.c
-$(obj)/raid6altivec4.c:   UNROLL := 4
-$(obj)/raid6altivec4.c:   $(src)/raid6altivec.uc $(src)/unroll.awk FORCE
+CFLAGS_altivec4.o += $(altivec_flags)
+targets += altivec4.c
+$(obj)/altivec4.c:   UNROLL := 4
+$(obj)/altivec4.c:   $(src)/altivec.uc $(src)/unroll.awk FORCE
 	$(call if_changed,unroll)
 
-CFLAGS_raid6altivec8.o += $(altivec_flags)
-targets += raid6altivec8.c
-$(obj)/raid6altivec8.c:   UNROLL := 8
-$(obj)/raid6altivec8.c:   $(src)/raid6altivec.uc $(src)/unroll.awk FORCE
+CFLAGS_altivec8.o += $(altivec_flags)
+targets += altivec8.c
+$(obj)/altivec8.c:   UNROLL := 8
+$(obj)/altivec8.c:   $(src)/altivec.uc $(src)/unroll.awk FORCE
 	$(call if_changed,unroll)
 
 quiet_cmd_mktable = TABLE   $@
       cmd_mktable = $(obj)/mktables > $@ || ( rm -f $@ && exit 1 )
 
-targets += raid6tables.c
-$(obj)/raid6tables.c: $(obj)/mktables FORCE
+targets += tables.c
+$(obj)/tables.c: $(obj)/mktables FORCE
 	$(call if_changed,mktable)
diff --git a/lib/raid6/raid6algos.c b/lib/raid6/algos.c
similarity index 99%
rename from lib/raid6/raid6algos.c
rename to lib/raid6/algos.c
index 1f8784b..b595f56 100644
--- a/lib/raid6/raid6algos.c
+++ b/lib/raid6/algos.c
@@ -11,17 +11,17 @@
  * ----------------------------------------------------------------------- */
 
 /*
- * raid6algos.c
+ * raid6/algos.c
  *
  * Algorithm list and algorithm selection for RAID-6
  */
 
 #include <linux/raid/pq.h>
-#include <linux/gfp.h>
 #ifndef __KERNEL__
 #include <sys/mman.h>
 #include <stdio.h>
 #else
+#include <linux/gfp.h>
 #if !RAID6_USE_EMPTY_ZERO_PAGE
 /* In .bss so it's zeroed */
 const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(256)));
diff --git a/lib/raid6/raid6altivec.uc b/lib/raid6/altivec.uc
similarity index 100%
rename from lib/raid6/raid6altivec.uc
rename to lib/raid6/altivec.uc
diff --git a/lib/raid6/raid6int.uc b/lib/raid6/int.uc
similarity index 100%
rename from lib/raid6/raid6int.uc
rename to lib/raid6/int.uc
diff --git a/lib/raid6/raid6mmx.c b/lib/raid6/mmx.c
similarity index 98%
rename from lib/raid6/raid6mmx.c
rename to lib/raid6/mmx.c
index e7f6c13..279347f 100644
--- a/lib/raid6/raid6mmx.c
+++ b/lib/raid6/mmx.c
@@ -11,7 +11,7 @@
  * ----------------------------------------------------------------------- */
 
 /*
- * raid6mmx.c
+ * raid6/mmx.c
  *
  * MMX implementation of RAID-6 syndrome functions
  */
@@ -19,9 +19,9 @@
 #if defined(__i386__) && !defined(__arch_um__)
 
 #include <linux/raid/pq.h>
-#include "raid6x86.h"
+#include "x86.h"
 
-/* Shared with raid6sse1.c */
+/* Shared with raid6/sse1.c */
 const struct raid6_mmx_constants {
 	u64 x1d;
 } raid6_mmx_constants = {
diff --git a/lib/raid6/raid6test/Makefile b/lib/raid6/raid6test/Makefile
deleted file mode 100644
index 2874cbe..0000000
--- a/lib/raid6/raid6test/Makefile
+++ /dev/null
@@ -1,75 +0,0 @@
-#
-# This is a simple Makefile to test some of the RAID-6 code
-# from userspace.
-#
-
-CC	 = gcc
-OPTFLAGS = -O2			# Adjust as desired
-CFLAGS	 = -I.. -I ../../../include -g $(OPTFLAGS)
-LD	 = ld
-AWK	 = awk
-AR	 = ar
-RANLIB	 = ranlib
-
-.c.o:
-	$(CC) $(CFLAGS) -c -o $@ $<
-
-%.c: ../%.c
-	cp -f $< $@
-
-%.uc: ../%.uc
-	cp -f $< $@
-
-all:	raid6.a raid6test
-
-raid6.a: raid6int1.o raid6int2.o raid6int4.o raid6int8.o raid6int16.o \
-	 raid6int32.o \
-	 raid6mmx.o raid6sse1.o raid6sse2.o \
-	 raid6altivec1.o raid6altivec2.o raid6altivec4.o raid6altivec8.o \
-	 raid6recov.o raid6algos.o \
-	 raid6tables.o
-	 rm -f $@
-	 $(AR) cq $@ $^
-	 $(RANLIB) $@
-
-raid6test: test.c raid6.a
-	$(CC) $(CFLAGS) -o raid6test $^
-
-raid6altivec1.c: raid6altivec.uc ../unroll.awk
-	$(AWK) ../unroll.awk -vN=1 < raid6altivec.uc > $@
-
-raid6altivec2.c: raid6altivec.uc ../unroll.awk
-	$(AWK) ../unroll.awk -vN=2 < raid6altivec.uc > $@
-
-raid6altivec4.c: raid6altivec.uc ../unroll.awk
-	$(AWK) ../unroll.awk -vN=4 < raid6altivec.uc > $@
-
-raid6altivec8.c: raid6altivec.uc ../unroll.awk
-	$(AWK) ../unroll.awk -vN=8 < raid6altivec.uc > $@
-
-raid6int1.c: raid6int.uc ../unroll.awk
-	$(AWK) ../unroll.awk -vN=1 < raid6int.uc > $@
-
-raid6int2.c: raid6int.uc ../unroll.awk
-	$(AWK) ../unroll.awk -vN=2 < raid6int.uc > $@
-
-raid6int4.c: raid6int.uc ../unroll.awk
-	$(AWK) ../unroll.awk -vN=4 < raid6int.uc > $@
-
-raid6int8.c: raid6int.uc ../unroll.awk
-	$(AWK) ../unroll.awk -vN=8 < raid6int.uc > $@
-
-raid6int16.c: raid6int.uc ../unroll.awk
-	$(AWK) ../unroll.awk -vN=16 < raid6int.uc > $@
-
-raid6int32.c: raid6int.uc ../unroll.awk
-	$(AWK) ../unroll.awk -vN=32 < raid6int.uc > $@
-
-raid6tables.c: mktables
-	./mktables > raid6tables.c
-
-clean:
-	rm -f *.o *.a mktables mktables.c raid6int.uc raid6*.c raid6test
-
-spotless: clean
-	rm -f *~
diff --git a/lib/raid6/raid6recov.c b/lib/raid6/recov.c
similarity index 99%
rename from lib/raid6/raid6recov.c
rename to lib/raid6/recov.c
index 2609f00..8590d19 100644
--- a/lib/raid6/raid6recov.c
+++ b/lib/raid6/recov.c
@@ -11,7 +11,7 @@
  * ----------------------------------------------------------------------- */
 
 /*
- * raid6recov.c
+ * raid6/recov.c
  *
  * RAID-6 data recovery in dual failure mode.  In single failure mode,
  * use the RAID-5 algorithm (or, in the case of Q failure, just reconstruct
diff --git a/lib/raid6/raid6sse1.c b/lib/raid6/sse1.c
similarity index 98%
rename from lib/raid6/raid6sse1.c
rename to lib/raid6/sse1.c
index b274dd5..10dd9194 100644
--- a/lib/raid6/raid6sse1.c
+++ b/lib/raid6/sse1.c
@@ -11,7 +11,7 @@
  * ----------------------------------------------------------------------- */
 
 /*
- * raid6sse1.c
+ * raid6/sse1.c
  *
  * SSE-1/MMXEXT implementation of RAID-6 syndrome functions
  *
@@ -24,9 +24,9 @@
 #if defined(__i386__) && !defined(__arch_um__)
 
 #include <linux/raid/pq.h>
-#include "raid6x86.h"
+#include "x86.h"
 
-/* Defined in raid6mmx.c */
+/* Defined in raid6/mmx.c */
 extern const struct raid6_mmx_constants {
 	u64 x1d;
 } raid6_mmx_constants;
diff --git a/lib/raid6/raid6sse2.c b/lib/raid6/sse2.c
similarity index 99%
rename from lib/raid6/raid6sse2.c
rename to lib/raid6/sse2.c
index 6ed6c6c..bc2d57d 100644
--- a/lib/raid6/raid6sse2.c
+++ b/lib/raid6/sse2.c
@@ -11,7 +11,7 @@
  * ----------------------------------------------------------------------- */
 
 /*
- * raid6sse2.c
+ * raid6/sse2.c
  *
  * SSE-2 implementation of RAID-6 syndrome functions
  *
@@ -20,7 +20,7 @@
 #if (defined(__i386__) || defined(__x86_64__)) && !defined(__arch_um__)
 
 #include <linux/raid/pq.h>
-#include "raid6x86.h"
+#include "x86.h"
 
 static const struct raid6_sse_constants {
 	u64 x1d[2];
diff --git a/lib/raid6/test/Makefile b/lib/raid6/test/Makefile
new file mode 100644
index 0000000..aa65169
--- /dev/null
+++ b/lib/raid6/test/Makefile
@@ -0,0 +1,72 @@
+#
+# This is a simple Makefile to test some of the RAID-6 code
+# from userspace.
+#
+
+CC	 = gcc
+OPTFLAGS = -O2			# Adjust as desired
+CFLAGS	 = -I.. -I ../../../include -g $(OPTFLAGS)
+LD	 = ld
+AWK	 = awk -f
+AR	 = ar
+RANLIB	 = ranlib
+
+.c.o:
+	$(CC) $(CFLAGS) -c -o $@ $<
+
+%.c: ../%.c
+	cp -f $< $@
+
+%.uc: ../%.uc
+	cp -f $< $@
+
+all:	raid6.a raid6test
+
+raid6.a: int1.o int2.o int4.o int8.o int16.o int32.o mmx.o sse1.o sse2.o \
+	 altivec1.o altivec2.o altivec4.o altivec8.o recov.o algos.o \
+	 tables.o
+	 rm -f $@
+	 $(AR) cq $@ $^
+	 $(RANLIB) $@
+
+raid6test: test.c raid6.a
+	$(CC) $(CFLAGS) -o raid6test $^
+
+altivec1.c: altivec.uc ../unroll.awk
+	$(AWK) ../unroll.awk -vN=1 < altivec.uc > $@
+
+altivec2.c: altivec.uc ../unroll.awk
+	$(AWK) ../unroll.awk -vN=2 < altivec.uc > $@
+
+altivec4.c: altivec.uc ../unroll.awk
+	$(AWK) ../unroll.awk -vN=4 < altivec.uc > $@
+
+altivec8.c: altivec.uc ../unroll.awk
+	$(AWK) ../unroll.awk -vN=8 < altivec.uc > $@
+
+int1.c: int.uc ../unroll.awk
+	$(AWK) ../unroll.awk -vN=1 < int.uc > $@
+
+int2.c: int.uc ../unroll.awk
+	$(AWK) ../unroll.awk -vN=2 < int.uc > $@
+
+int4.c: int.uc ../unroll.awk
+	$(AWK) ../unroll.awk -vN=4 < int.uc > $@
+
+int8.c: int.uc ../unroll.awk
+	$(AWK) ../unroll.awk -vN=8 < int.uc > $@
+
+int16.c: int.uc ../unroll.awk
+	$(AWK) ../unroll.awk -vN=16 < int.uc > $@
+
+int32.c: int.uc ../unroll.awk
+	$(AWK) ../unroll.awk -vN=32 < int.uc > $@
+
+tables.c: mktables
+	./mktables > tables.c
+
+clean:
+	rm -f *.o *.a mktables mktables.c *.uc int*.c altivec*.c tables.c raid6test
+
+spotless: clean
+	rm -f *~
diff --git a/lib/raid6/raid6test/test.c b/lib/raid6/test/test.c
similarity index 100%
rename from lib/raid6/raid6test/test.c
rename to lib/raid6/test/test.c
diff --git a/lib/raid6/raid6x86.h b/lib/raid6/x86.h
similarity index 98%
rename from lib/raid6/raid6x86.h
rename to lib/raid6/x86.h
index 4c22c15..cb2a8c9 100644
--- a/lib/raid6/raid6x86.h
+++ b/lib/raid6/x86.h
@@ -11,7 +11,7 @@
  * ----------------------------------------------------------------------- */
 
 /*
- * raid6x86.h
+ * raid6/x86.h
  *
  * Definitions common to x86 and x86-64 RAID-6 code only
  */
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index 08d3575..eaa4a5b 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -81,7 +81,8 @@
 		nr_more_io++;
 	spin_unlock(&inode_lock);
 
-	get_dirty_limits(&background_thresh, &dirty_thresh, &bdi_thresh, bdi);
+	global_dirty_limits(&background_thresh, &dirty_thresh);
+	bdi_thresh = bdi_dirty_limit(bdi, dirty_thresh);
 
 #define K(x) ((x) << (PAGE_SHIFT - 10))
 	seq_printf(m,
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index b61d2db..cc5be78 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -18,6 +18,9 @@
 #include <linux/bootmem.h>
 #include <linux/sysfs.h>
 #include <linux/slab.h>
+#include <linux/rmap.h>
+#include <linux/swap.h>
+#include <linux/swapops.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -220,6 +223,12 @@
 			(vma->vm_pgoff >> huge_page_order(h));
 }
 
+pgoff_t linear_hugepage_index(struct vm_area_struct *vma,
+				     unsigned long address)
+{
+	return vma_hugecache_offset(hstate_vma(vma), vma, address);
+}
+
 /*
  * Return the size of the pages allocated when backing a VMA. In the majority
  * cases this will be same size as used by the page table entries.
@@ -552,6 +561,7 @@
 	set_page_private(page, 0);
 	page->mapping = NULL;
 	BUG_ON(page_count(page));
+	BUG_ON(page_mapcount(page));
 	INIT_LIST_HEAD(&page->lru);
 
 	spin_lock(&hugetlb_lock);
@@ -605,6 +615,8 @@
 	return dtor == free_huge_page;
 }
 
+EXPORT_SYMBOL_GPL(PageHuge);
+
 static struct page *alloc_fresh_huge_page_node(struct hstate *h, int nid)
 {
 	struct page *page;
@@ -2129,6 +2141,7 @@
 			entry = huge_ptep_get(src_pte);
 			ptepage = pte_page(entry);
 			get_page(ptepage);
+			page_dup_rmap(ptepage);
 			set_huge_pte_at(dst, addr, dst_pte, entry);
 		}
 		spin_unlock(&src->page_table_lock);
@@ -2140,6 +2153,19 @@
 	return -ENOMEM;
 }
 
+static int is_hugetlb_entry_hwpoisoned(pte_t pte)
+{
+	swp_entry_t swp;
+
+	if (huge_pte_none(pte) || pte_present(pte))
+		return 0;
+	swp = pte_to_swp_entry(pte);
+	if (non_swap_entry(swp) && is_hwpoison_entry(swp)) {
+		return 1;
+	} else
+		return 0;
+}
+
 void __unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
 			    unsigned long end, struct page *ref_page)
 {
@@ -2198,6 +2224,12 @@
 		if (huge_pte_none(pte))
 			continue;
 
+		/*
+		 * HWPoisoned hugepage is already unmapped and dropped reference
+		 */
+		if (unlikely(is_hugetlb_entry_hwpoisoned(pte)))
+			continue;
+
 		page = pte_page(pte);
 		if (pte_dirty(pte))
 			set_page_dirty(page);
@@ -2207,6 +2239,7 @@
 	flush_tlb_range(vma, start, end);
 	mmu_notifier_invalidate_range_end(mm, start, end);
 	list_for_each_entry_safe(page, tmp, &page_list, lru) {
+		page_remove_rmap(page);
 		list_del(&page->lru);
 		put_page(page);
 	}
@@ -2272,6 +2305,9 @@
 	return 1;
 }
 
+/*
+ * Hugetlb_cow() should be called with page lock of the original hugepage held.
+ */
 static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma,
 			unsigned long address, pte_t *ptep, pte_t pte,
 			struct page *pagecache_page)
@@ -2286,8 +2322,13 @@
 retry_avoidcopy:
 	/* If no-one else is actually using this page, avoid the copy
 	 * and just make the page writable */
-	avoidcopy = (page_count(old_page) == 1);
+	avoidcopy = (page_mapcount(old_page) == 1);
 	if (avoidcopy) {
+		if (!trylock_page(old_page)) {
+			if (PageAnon(old_page))
+				page_move_anon_rmap(old_page, vma, address);
+		} else
+			unlock_page(old_page);
 		set_huge_ptep_writable(vma, address, ptep);
 		return 0;
 	}
@@ -2338,6 +2379,13 @@
 		return -PTR_ERR(new_page);
 	}
 
+	/*
+	 * When the original hugepage is shared one, it does not have
+	 * anon_vma prepared.
+	 */
+	if (unlikely(anon_vma_prepare(vma)))
+		return VM_FAULT_OOM;
+
 	copy_huge_page(new_page, old_page, address, vma);
 	__SetPageUptodate(new_page);
 
@@ -2355,6 +2403,8 @@
 		huge_ptep_clear_flush(vma, address, ptep);
 		set_huge_pte_at(mm, address, ptep,
 				make_huge_pte(vma, new_page, 1));
+		page_remove_rmap(old_page);
+		hugepage_add_anon_rmap(new_page, vma, address);
 		/* Make the old page be freed below */
 		new_page = old_page;
 		mmu_notifier_invalidate_range_end(mm,
@@ -2458,10 +2508,29 @@
 			spin_lock(&inode->i_lock);
 			inode->i_blocks += blocks_per_huge_page(h);
 			spin_unlock(&inode->i_lock);
+			page_dup_rmap(page);
 		} else {
 			lock_page(page);
-			page->mapping = HUGETLB_POISON;
+			if (unlikely(anon_vma_prepare(vma))) {
+				ret = VM_FAULT_OOM;
+				goto backout_unlocked;
+			}
+			hugepage_add_new_anon_rmap(page, vma, address);
 		}
+	} else {
+		page_dup_rmap(page);
+	}
+
+	/*
+	 * Since memory error handler replaces pte into hwpoison swap entry
+	 * at the time of error handling, a process which reserved but not have
+	 * the mapping to the error hugepage does not have hwpoison swap entry.
+	 * So we need to block accesses from such a process by checking
+	 * PG_hwpoison bit here.
+	 */
+	if (unlikely(PageHWPoison(page))) {
+		ret = VM_FAULT_HWPOISON;
+		goto backout_unlocked;
 	}
 
 	/*
@@ -2513,10 +2582,18 @@
 	pte_t *ptep;
 	pte_t entry;
 	int ret;
+	struct page *page = NULL;
 	struct page *pagecache_page = NULL;
 	static DEFINE_MUTEX(hugetlb_instantiation_mutex);
 	struct hstate *h = hstate_vma(vma);
 
+	ptep = huge_pte_offset(mm, address);
+	if (ptep) {
+		entry = huge_ptep_get(ptep);
+		if (unlikely(is_hugetlb_entry_hwpoisoned(entry)))
+			return VM_FAULT_HWPOISON;
+	}
+
 	ptep = huge_pte_alloc(mm, address, huge_page_size(h));
 	if (!ptep)
 		return VM_FAULT_OOM;
@@ -2554,6 +2631,11 @@
 								vma, address);
 	}
 
+	if (!pagecache_page) {
+		page = pte_page(entry);
+		lock_page(page);
+	}
+
 	spin_lock(&mm->page_table_lock);
 	/* Check for a racing update before calling hugetlb_cow */
 	if (unlikely(!pte_same(entry, huge_ptep_get(ptep))))
@@ -2579,6 +2661,8 @@
 	if (pagecache_page) {
 		unlock_page(pagecache_page);
 		put_page(pagecache_page);
+	} else {
+		unlock_page(page);
 	}
 
 out_mutex:
@@ -2791,3 +2875,19 @@
 	hugetlb_put_quota(inode->i_mapping, (chg - freed));
 	hugetlb_acct_memory(h, -(chg - freed));
 }
+
+/*
+ * This function is called from memory failure code.
+ * Assume the caller holds page lock of the head page.
+ */
+void __isolate_hwpoisoned_huge_page(struct page *hpage)
+{
+	struct hstate *h = page_hstate(hpage);
+	int nid = page_to_nid(hpage);
+
+	spin_lock(&hugetlb_lock);
+	list_del(&hpage->lru);
+	h->free_huge_pages--;
+	h->free_huge_pages_node[nid]--;
+	spin_unlock(&hugetlb_lock);
+}
diff --git a/mm/hwpoison-inject.c b/mm/hwpoison-inject.c
index 10ea719..0948f10 100644
--- a/mm/hwpoison-inject.c
+++ b/mm/hwpoison-inject.c
@@ -5,6 +5,7 @@
 #include <linux/mm.h>
 #include <linux/swap.h>
 #include <linux/pagemap.h>
+#include <linux/hugetlb.h>
 #include "internal.h"
 
 static struct dentry *hwpoison_dir;
@@ -13,6 +14,7 @@
 {
 	unsigned long pfn = val;
 	struct page *p;
+	struct page *hpage;
 	int err;
 
 	if (!capable(CAP_SYS_ADMIN))
@@ -24,18 +26,19 @@
 		return -ENXIO;
 
 	p = pfn_to_page(pfn);
+	hpage = compound_head(p);
 	/*
 	 * This implies unable to support free buddy pages.
 	 */
-	if (!get_page_unless_zero(p))
+	if (!get_page_unless_zero(hpage))
 		return 0;
 
-	if (!PageLRU(p))
+	if (!PageLRU(p) && !PageHuge(p))
 		shake_page(p, 0);
 	/*
 	 * This implies unable to support non-LRU pages.
 	 */
-	if (!PageLRU(p))
+	if (!PageLRU(p) && !PageHuge(p))
 		return 0;
 
 	/*
@@ -44,9 +47,9 @@
 	 * We temporarily take page lock for try_get_mem_cgroup_from_page().
 	 * __memory_failure() will redo the check reliably inside page lock.
 	 */
-	lock_page(p);
-	err = hwpoison_filter(p);
-	unlock_page(p);
+	lock_page(hpage);
+	err = hwpoison_filter(hpage);
+	unlock_page(hpage);
 	if (err)
 		return 0;
 
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 6b44e52..9c26eec 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -46,6 +46,7 @@
 #include <linux/suspend.h>
 #include <linux/slab.h>
 #include <linux/swapops.h>
+#include <linux/hugetlb.h>
 #include "internal.h"
 
 int sysctl_memory_failure_early_kill __read_mostly = 0;
@@ -690,17 +691,29 @@
 /*
  * Huge pages. Needs work.
  * Issues:
- * No rmap support so we cannot find the original mapper. In theory could walk
- * all MMs and look for the mappings, but that would be non atomic and racy.
- * Need rmap for hugepages for this. Alternatively we could employ a heuristic,
- * like just walking the current process and hoping it has it mapped (that
- * should be usually true for the common "shared database cache" case)
- * Should handle free huge pages and dequeue them too, but this needs to
- * handle huge page accounting correctly.
+ * - Error on hugepage is contained in hugepage unit (not in raw page unit.)
+ *   To narrow down kill region to one page, we need to break up pmd.
+ * - To support soft-offlining for hugepage, we need to support hugepage
+ *   migration.
  */
 static int me_huge_page(struct page *p, unsigned long pfn)
 {
-	return FAILED;
+	struct page *hpage = compound_head(p);
+	/*
+	 * We can safely recover from error on free or reserved (i.e.
+	 * not in-use) hugepage by dequeuing it from freelist.
+	 * To check whether a hugepage is in-use or not, we can't use
+	 * page->lru because it can be used in other hugepage operations,
+	 * such as __unmap_hugepage_range() and gather_surplus_pages().
+	 * So instead we use page_mapping() and PageAnon().
+	 * We assume that this function is called with page lock held,
+	 * so there is no race between isolation and mapping/unmapping.
+	 */
+	if (!(page_mapping(hpage) || PageAnon(hpage))) {
+		__isolate_hwpoisoned_huge_page(hpage);
+		return RECOVERED;
+	}
+	return DELAYED;
 }
 
 /*
@@ -838,6 +851,7 @@
 	int ret;
 	int i;
 	int kill = 1;
+	struct page *hpage = compound_head(p);
 
 	if (PageReserved(p) || PageSlab(p))
 		return SWAP_SUCCESS;
@@ -846,10 +860,10 @@
 	 * This check implies we don't kill processes if their pages
 	 * are in the swap cache early. Those are always late kills.
 	 */
-	if (!page_mapped(p))
+	if (!page_mapped(hpage))
 		return SWAP_SUCCESS;
 
-	if (PageCompound(p) || PageKsm(p))
+	if (PageKsm(p))
 		return SWAP_FAIL;
 
 	if (PageSwapCache(p)) {
@@ -864,10 +878,11 @@
 	 * XXX: the dirty test could be racy: set_page_dirty() may not always
 	 * be called inside page lock (it's recommended but not enforced).
 	 */
-	mapping = page_mapping(p);
-	if (!PageDirty(p) && mapping && mapping_cap_writeback_dirty(mapping)) {
-		if (page_mkclean(p)) {
-			SetPageDirty(p);
+	mapping = page_mapping(hpage);
+	if (!PageDirty(hpage) && mapping &&
+	    mapping_cap_writeback_dirty(mapping)) {
+		if (page_mkclean(hpage)) {
+			SetPageDirty(hpage);
 		} else {
 			kill = 0;
 			ttu |= TTU_IGNORE_HWPOISON;
@@ -886,14 +901,14 @@
 	 * there's nothing that can be done.
 	 */
 	if (kill)
-		collect_procs(p, &tokill);
+		collect_procs(hpage, &tokill);
 
 	/*
 	 * try_to_unmap can fail temporarily due to races.
 	 * Try a few times (RED-PEN better strategy?)
 	 */
 	for (i = 0; i < N_UNMAP_TRIES; i++) {
-		ret = try_to_unmap(p, ttu);
+		ret = try_to_unmap(hpage, ttu);
 		if (ret == SWAP_SUCCESS)
 			break;
 		pr_debug("MCE %#lx: try_to_unmap retry needed %d\n", pfn,  ret);
@@ -901,7 +916,7 @@
 
 	if (ret != SWAP_SUCCESS)
 		printk(KERN_ERR "MCE %#lx: failed to unmap page (mapcount=%d)\n",
-				pfn, page_mapcount(p));
+				pfn, page_mapcount(hpage));
 
 	/*
 	 * Now that the dirty bit has been propagated to the
@@ -912,17 +927,35 @@
 	 * use a more force-full uncatchable kill to prevent
 	 * any accesses to the poisoned memory.
 	 */
-	kill_procs_ao(&tokill, !!PageDirty(p), trapno,
+	kill_procs_ao(&tokill, !!PageDirty(hpage), trapno,
 		      ret != SWAP_SUCCESS, pfn);
 
 	return ret;
 }
 
+static void set_page_hwpoison_huge_page(struct page *hpage)
+{
+	int i;
+	int nr_pages = 1 << compound_order(hpage);
+	for (i = 0; i < nr_pages; i++)
+		SetPageHWPoison(hpage + i);
+}
+
+static void clear_page_hwpoison_huge_page(struct page *hpage)
+{
+	int i;
+	int nr_pages = 1 << compound_order(hpage);
+	for (i = 0; i < nr_pages; i++)
+		ClearPageHWPoison(hpage + i);
+}
+
 int __memory_failure(unsigned long pfn, int trapno, int flags)
 {
 	struct page_state *ps;
 	struct page *p;
+	struct page *hpage;
 	int res;
+	unsigned int nr_pages;
 
 	if (!sysctl_memory_failure_recovery)
 		panic("Memory failure from trap %d on page %lx", trapno, pfn);
@@ -935,12 +968,14 @@
 	}
 
 	p = pfn_to_page(pfn);
+	hpage = compound_head(p);
 	if (TestSetPageHWPoison(p)) {
 		printk(KERN_ERR "MCE %#lx: already hardware poisoned\n", pfn);
 		return 0;
 	}
 
-	atomic_long_add(1, &mce_bad_pages);
+	nr_pages = 1 << compound_order(hpage);
+	atomic_long_add(nr_pages, &mce_bad_pages);
 
 	/*
 	 * We need/can do nothing about count=0 pages.
@@ -954,7 +989,7 @@
 	 * that may make page_freeze_refs()/page_unfreeze_refs() mismatch.
 	 */
 	if (!(flags & MF_COUNT_INCREASED) &&
-		!get_page_unless_zero(compound_head(p))) {
+		!get_page_unless_zero(hpage)) {
 		if (is_free_buddy_page(p)) {
 			action_result(pfn, "free buddy", DELAYED);
 			return 0;
@@ -972,9 +1007,9 @@
 	 * The check (unnecessarily) ignores LRU pages being isolated and
 	 * walked by the page reclaim code, however that's not a big loss.
 	 */
-	if (!PageLRU(p))
+	if (!PageLRU(p) && !PageHuge(p))
 		shake_page(p, 0);
-	if (!PageLRU(p)) {
+	if (!PageLRU(p) && !PageHuge(p)) {
 		/*
 		 * shake_page could have turned it free.
 		 */
@@ -992,7 +1027,7 @@
 	 * It's very difficult to mess with pages currently under IO
 	 * and in many cases impossible, so we just avoid it here.
 	 */
-	lock_page_nosync(p);
+	lock_page_nosync(hpage);
 
 	/*
 	 * unpoison always clear PG_hwpoison inside page lock
@@ -1004,12 +1039,32 @@
 	}
 	if (hwpoison_filter(p)) {
 		if (TestClearPageHWPoison(p))
-			atomic_long_dec(&mce_bad_pages);
-		unlock_page(p);
-		put_page(p);
+			atomic_long_sub(nr_pages, &mce_bad_pages);
+		unlock_page(hpage);
+		put_page(hpage);
 		return 0;
 	}
 
+	/*
+	 * For error on the tail page, we should set PG_hwpoison
+	 * on the head page to show that the hugepage is hwpoisoned
+	 */
+	if (PageTail(p) && TestSetPageHWPoison(hpage)) {
+		action_result(pfn, "hugepage already hardware poisoned",
+				IGNORED);
+		unlock_page(hpage);
+		put_page(hpage);
+		return 0;
+	}
+	/*
+	 * Set PG_hwpoison on all pages in an error hugepage,
+	 * because containment is done in hugepage unit for now.
+	 * Since we have done TestSetPageHWPoison() for the head page with
+	 * page lock held, we can safely set PG_hwpoison bits on tail pages.
+	 */
+	if (PageHuge(p))
+		set_page_hwpoison_huge_page(hpage);
+
 	wait_on_page_writeback(p);
 
 	/*
@@ -1039,7 +1094,7 @@
 		}
 	}
 out:
-	unlock_page(p);
+	unlock_page(hpage);
 	return res;
 }
 EXPORT_SYMBOL_GPL(__memory_failure);
@@ -1083,6 +1138,7 @@
 	struct page *page;
 	struct page *p;
 	int freeit = 0;
+	unsigned int nr_pages;
 
 	if (!pfn_valid(pfn))
 		return -ENXIO;
@@ -1095,9 +1151,11 @@
 		return 0;
 	}
 
+	nr_pages = 1 << compound_order(page);
+
 	if (!get_page_unless_zero(page)) {
 		if (TestClearPageHWPoison(p))
-			atomic_long_dec(&mce_bad_pages);
+			atomic_long_sub(nr_pages, &mce_bad_pages);
 		pr_debug("MCE: Software-unpoisoned free page %#lx\n", pfn);
 		return 0;
 	}
@@ -1109,11 +1167,13 @@
 	 * the PG_hwpoison page will be caught and isolated on the entrance to
 	 * the free buddy page pool.
 	 */
-	if (TestClearPageHWPoison(p)) {
+	if (TestClearPageHWPoison(page)) {
 		pr_debug("MCE: Software-unpoisoned page %#lx\n", pfn);
-		atomic_long_dec(&mce_bad_pages);
+		atomic_long_sub(nr_pages, &mce_bad_pages);
 		freeit = 1;
 	}
+	if (PageHuge(p))
+		clear_page_hwpoison_huge_page(page);
 	unlock_page(page);
 
 	put_page(page);
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 0c6258b..20890d8 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -253,32 +253,6 @@
 	}
 }
 
-/*
- * Clip the earned share of dirty pages to that which is actually available.
- * This avoids exceeding the total dirty_limit when the floating averages
- * fluctuate too quickly.
- */
-static void clip_bdi_dirty_limit(struct backing_dev_info *bdi,
-		unsigned long dirty, unsigned long *pbdi_dirty)
-{
-	unsigned long avail_dirty;
-
-	avail_dirty = global_page_state(NR_FILE_DIRTY) +
-		 global_page_state(NR_WRITEBACK) +
-		 global_page_state(NR_UNSTABLE_NFS) +
-		 global_page_state(NR_WRITEBACK_TEMP);
-
-	if (avail_dirty < dirty)
-		avail_dirty = dirty - avail_dirty;
-	else
-		avail_dirty = 0;
-
-	avail_dirty += bdi_stat(bdi, BDI_RECLAIMABLE) +
-		bdi_stat(bdi, BDI_WRITEBACK);
-
-	*pbdi_dirty = min(*pbdi_dirty, avail_dirty);
-}
-
 static inline void task_dirties_fraction(struct task_struct *tsk,
 		long *numerator, long *denominator)
 {
@@ -287,16 +261,24 @@
 }
 
 /*
- * scale the dirty limit
+ * task_dirty_limit - scale down dirty throttling threshold for one task
  *
  * task specific dirty limit:
  *
  *   dirty -= (dirty/8) * p_{t}
+ *
+ * To protect light/slow dirtying tasks from heavier/fast ones, we start
+ * throttling individual tasks before reaching the bdi dirty limit.
+ * Relatively low thresholds will be allocated to heavy dirtiers. So when
+ * dirty pages grow large, heavy dirtiers will be throttled first, which will
+ * effectively curb the growth of dirty pages. Light dirtiers with high enough
+ * dirty threshold may never get throttled.
  */
-static void task_dirty_limit(struct task_struct *tsk, unsigned long *pdirty)
+static unsigned long task_dirty_limit(struct task_struct *tsk,
+				       unsigned long bdi_dirty)
 {
 	long numerator, denominator;
-	unsigned long dirty = *pdirty;
+	unsigned long dirty = bdi_dirty;
 	u64 inv = dirty >> 3;
 
 	task_dirties_fraction(tsk, &numerator, &denominator);
@@ -304,10 +286,8 @@
 	do_div(inv, denominator);
 
 	dirty -= inv;
-	if (dirty < *pdirty/2)
-		dirty = *pdirty/2;
 
-	*pdirty = dirty;
+	return max(dirty, bdi_dirty/2);
 }
 
 /*
@@ -417,9 +397,16 @@
 	return x + 1;	/* Ensure that we never return 0 */
 }
 
-void
-get_dirty_limits(unsigned long *pbackground, unsigned long *pdirty,
-		 unsigned long *pbdi_dirty, struct backing_dev_info *bdi)
+/**
+ * global_dirty_limits - background-writeback and dirty-throttling thresholds
+ *
+ * Calculate the dirty thresholds based on sysctl parameters
+ * - vm.dirty_background_ratio  or  vm.dirty_background_bytes
+ * - vm.dirty_ratio             or  vm.dirty_bytes
+ * The dirty limits will be lifted by 1/4 for PF_LESS_THROTTLE (ie. nfsd) and
+ * runtime tasks.
+ */
+void global_dirty_limits(unsigned long *pbackground, unsigned long *pdirty)
 {
 	unsigned long background;
 	unsigned long dirty;
@@ -451,27 +438,37 @@
 	}
 	*pbackground = background;
 	*pdirty = dirty;
+}
 
-	if (bdi) {
-		u64 bdi_dirty;
-		long numerator, denominator;
+/**
+ * bdi_dirty_limit - @bdi's share of dirty throttling threshold
+ *
+ * Allocate high/low dirty limits to fast/slow devices, in order to prevent
+ * - starving fast devices
+ * - piling up dirty pages (that will take long time to sync) on slow devices
+ *
+ * The bdi's share of dirty limit will be adapting to its throughput and
+ * bounded by the bdi->min_ratio and/or bdi->max_ratio parameters, if set.
+ */
+unsigned long bdi_dirty_limit(struct backing_dev_info *bdi, unsigned long dirty)
+{
+	u64 bdi_dirty;
+	long numerator, denominator;
 
-		/*
-		 * Calculate this BDI's share of the dirty ratio.
-		 */
-		bdi_writeout_fraction(bdi, &numerator, &denominator);
+	/*
+	 * Calculate this BDI's share of the dirty ratio.
+	 */
+	bdi_writeout_fraction(bdi, &numerator, &denominator);
 
-		bdi_dirty = (dirty * (100 - bdi_min_ratio)) / 100;
-		bdi_dirty *= numerator;
-		do_div(bdi_dirty, denominator);
-		bdi_dirty += (dirty * bdi->min_ratio) / 100;
-		if (bdi_dirty > (dirty * bdi->max_ratio) / 100)
-			bdi_dirty = dirty * bdi->max_ratio / 100;
+	bdi_dirty = (dirty * (100 - bdi_min_ratio)) / 100;
+	bdi_dirty *= numerator;
+	do_div(bdi_dirty, denominator);
 
-		*pbdi_dirty = bdi_dirty;
-		clip_bdi_dirty_limit(bdi, dirty, pbdi_dirty);
-		task_dirty_limit(current, pbdi_dirty);
-	}
+	bdi_dirty += (dirty * bdi->min_ratio) / 100;
+	if (bdi_dirty > (dirty * bdi->max_ratio) / 100)
+		bdi_dirty = dirty * bdi->max_ratio / 100;
+
+	return bdi_dirty;
 }
 
 /*
@@ -491,7 +488,7 @@
 	unsigned long bdi_thresh;
 	unsigned long pages_written = 0;
 	unsigned long pause = 1;
-
+	bool dirty_exceeded = false;
 	struct backing_dev_info *bdi = mapping->backing_dev_info;
 
 	for (;;) {
@@ -502,18 +499,11 @@
 			.range_cyclic	= 1,
 		};
 
-		get_dirty_limits(&background_thresh, &dirty_thresh,
-				&bdi_thresh, bdi);
-
 		nr_reclaimable = global_page_state(NR_FILE_DIRTY) +
 					global_page_state(NR_UNSTABLE_NFS);
 		nr_writeback = global_page_state(NR_WRITEBACK);
 
-		bdi_nr_reclaimable = bdi_stat(bdi, BDI_RECLAIMABLE);
-		bdi_nr_writeback = bdi_stat(bdi, BDI_WRITEBACK);
-
-		if (bdi_nr_reclaimable + bdi_nr_writeback <= bdi_thresh)
-			break;
+		global_dirty_limits(&background_thresh, &dirty_thresh);
 
 		/*
 		 * Throttle it only when the background writeback cannot
@@ -524,6 +514,40 @@
 				(background_thresh + dirty_thresh) / 2)
 			break;
 
+		bdi_thresh = bdi_dirty_limit(bdi, dirty_thresh);
+		bdi_thresh = task_dirty_limit(current, bdi_thresh);
+
+		/*
+		 * In order to avoid the stacked BDI deadlock we need
+		 * to ensure we accurately count the 'dirty' pages when
+		 * the threshold is low.
+		 *
+		 * Otherwise it would be possible to get thresh+n pages
+		 * reported dirty, even though there are thresh-m pages
+		 * actually dirty; with m+n sitting in the percpu
+		 * deltas.
+		 */
+		if (bdi_thresh < 2*bdi_stat_error(bdi)) {
+			bdi_nr_reclaimable = bdi_stat_sum(bdi, BDI_RECLAIMABLE);
+			bdi_nr_writeback = bdi_stat_sum(bdi, BDI_WRITEBACK);
+		} else {
+			bdi_nr_reclaimable = bdi_stat(bdi, BDI_RECLAIMABLE);
+			bdi_nr_writeback = bdi_stat(bdi, BDI_WRITEBACK);
+		}
+
+		/*
+		 * The bdi thresh is somehow "soft" limit derived from the
+		 * global "hard" limit. The former helps to prevent heavy IO
+		 * bdi or process from holding back light ones; The latter is
+		 * the last resort safeguard.
+		 */
+		dirty_exceeded =
+			(bdi_nr_reclaimable + bdi_nr_writeback >= bdi_thresh)
+			|| (nr_reclaimable + nr_writeback >= dirty_thresh);
+
+		if (!dirty_exceeded)
+			break;
+
 		if (!bdi->dirty_exceeded)
 			bdi->dirty_exceeded = 1;
 
@@ -540,34 +564,10 @@
 		if (bdi_nr_reclaimable > bdi_thresh) {
 			writeback_inodes_wb(&bdi->wb, &wbc);
 			pages_written += write_chunk - wbc.nr_to_write;
-			get_dirty_limits(&background_thresh, &dirty_thresh,
-				       &bdi_thresh, bdi);
 			trace_wbc_balance_dirty_written(&wbc, bdi);
+			if (pages_written >= write_chunk)
+				break;		/* We've done our duty */
 		}
-
-		/*
-		 * In order to avoid the stacked BDI deadlock we need
-		 * to ensure we accurately count the 'dirty' pages when
-		 * the threshold is low.
-		 *
-		 * Otherwise it would be possible to get thresh+n pages
-		 * reported dirty, even though there are thresh-m pages
-		 * actually dirty; with m+n sitting in the percpu
-		 * deltas.
-		 */
-		if (bdi_thresh < 2*bdi_stat_error(bdi)) {
-			bdi_nr_reclaimable = bdi_stat_sum(bdi, BDI_RECLAIMABLE);
-			bdi_nr_writeback = bdi_stat_sum(bdi, BDI_WRITEBACK);
-		} else if (bdi_nr_reclaimable) {
-			bdi_nr_reclaimable = bdi_stat(bdi, BDI_RECLAIMABLE);
-			bdi_nr_writeback = bdi_stat(bdi, BDI_WRITEBACK);
-		}
-
-		if (bdi_nr_reclaimable + bdi_nr_writeback <= bdi_thresh)
-			break;
-		if (pages_written >= write_chunk)
-			break;		/* We've done our duty */
-
 		trace_wbc_balance_dirty_wait(&wbc, bdi);
 		__set_current_state(TASK_INTERRUPTIBLE);
 		io_schedule_timeout(pause);
@@ -581,8 +581,7 @@
 			pause = HZ / 10;
 	}
 
-	if (bdi_nr_reclaimable + bdi_nr_writeback < bdi_thresh &&
-			bdi->dirty_exceeded)
+	if (!dirty_exceeded && bdi->dirty_exceeded)
 		bdi->dirty_exceeded = 0;
 
 	if (writeback_in_progress(bdi))
@@ -597,9 +596,7 @@
 	 * background_thresh, to keep the amount of dirty memory low.
 	 */
 	if ((laptop_mode && pages_written) ||
-	    (!laptop_mode && ((global_page_state(NR_FILE_DIRTY)
-			       + global_page_state(NR_UNSTABLE_NFS))
-					  > background_thresh)))
+	    (!laptop_mode && (nr_reclaimable > background_thresh)))
 		bdi_start_background_writeback(bdi);
 }
 
@@ -663,7 +660,7 @@
 	unsigned long dirty_thresh;
 
         for ( ; ; ) {
-		get_dirty_limits(&background_thresh, &dirty_thresh, NULL, NULL);
+		global_dirty_limits(&background_thresh, &dirty_thresh);
 
                 /*
                  * Boost the allowable dirty threshold a bit for page
@@ -825,10 +822,10 @@
 /*
  * We tag pages in batches of WRITEBACK_TAG_BATCH to reduce tree_lock latency.
  */
-#define WRITEBACK_TAG_BATCH 4096
 void tag_pages_for_writeback(struct address_space *mapping,
 			     pgoff_t start, pgoff_t end)
 {
+#define WRITEBACK_TAG_BATCH 4096
 	unsigned long tagged;
 
 	do {
diff --git a/mm/rmap.c b/mm/rmap.c
index a7d0f54..87b9e8a 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -56,6 +56,7 @@
 #include <linux/memcontrol.h>
 #include <linux/mmu_notifier.h>
 #include <linux/migrate.h>
+#include <linux/hugetlb.h>
 
 #include <asm/tlbflush.h>
 
@@ -350,6 +351,8 @@
 	pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
 	unsigned long address;
 
+	if (unlikely(is_vm_hugetlb_page(vma)))
+		pgoff = page->index << huge_page_order(page_hstate(page));
 	address = vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
 	if (unlikely(address < vma->vm_start || address >= vma->vm_end)) {
 		/* page should be within @vma mapping range */
@@ -394,6 +397,12 @@
 	pte_t *pte;
 	spinlock_t *ptl;
 
+	if (unlikely(PageHuge(page))) {
+		pte = huge_pte_offset(mm, address);
+		ptl = &mm->page_table_lock;
+		goto check;
+	}
+
 	pgd = pgd_offset(mm, address);
 	if (!pgd_present(*pgd))
 		return NULL;
@@ -414,6 +423,7 @@
 	}
 
 	ptl = pte_lockptr(mm, pmd);
+check:
 	spin_lock(ptl);
 	if (pte_present(*pte) && page_to_pfn(page) == pte_pfn(*pte)) {
 		*ptlp = ptl;
@@ -916,6 +926,12 @@
 		page_clear_dirty(page);
 		set_page_dirty(page);
 	}
+	/*
+	 * Hugepages are not counted in NR_ANON_PAGES nor NR_FILE_MAPPED
+	 * and not charged by memcg for now.
+	 */
+	if (unlikely(PageHuge(page)))
+		return;
 	if (PageAnon(page)) {
 		mem_cgroup_uncharge_page(page);
 		__dec_zone_page_state(page, NR_ANON_PAGES);
@@ -1524,3 +1540,46 @@
 		return rmap_walk_file(page, rmap_one, arg);
 }
 #endif /* CONFIG_MIGRATION */
+
+#ifdef CONFIG_HUGETLB_PAGE
+/*
+ * The following three functions are for anonymous (private mapped) hugepages.
+ * Unlike common anonymous pages, anonymous hugepages have no accounting code
+ * and no lru code, because we handle hugepages differently from common pages.
+ */
+static void __hugepage_set_anon_rmap(struct page *page,
+	struct vm_area_struct *vma, unsigned long address, int exclusive)
+{
+	struct anon_vma *anon_vma = vma->anon_vma;
+	BUG_ON(!anon_vma);
+	if (!exclusive) {
+		struct anon_vma_chain *avc;
+		avc = list_entry(vma->anon_vma_chain.prev,
+				 struct anon_vma_chain, same_vma);
+		anon_vma = avc->anon_vma;
+	}
+	anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON;
+	page->mapping = (struct address_space *) anon_vma;
+	page->index = linear_page_index(vma, address);
+}
+
+void hugepage_add_anon_rmap(struct page *page,
+			    struct vm_area_struct *vma, unsigned long address)
+{
+	struct anon_vma *anon_vma = vma->anon_vma;
+	int first;
+	BUG_ON(!anon_vma);
+	BUG_ON(address < vma->vm_start || address >= vma->vm_end);
+	first = atomic_inc_and_test(&page->_mapcount);
+	if (first)
+		__hugepage_set_anon_rmap(page, vma, address, 0);
+}
+
+void hugepage_add_new_anon_rmap(struct page *page,
+			struct vm_area_struct *vma, unsigned long address)
+{
+	BUG_ON(address < vma->vm_start || address >= vma->vm_end);
+	atomic_set(&page->_mapcount, 0);
+	__hugepage_set_anon_rmap(page, vma, address, 1);
+}
+#endif /* CONFIG_HUGETLB_PAGE */
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 918c513..6b8889d 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -31,6 +31,7 @@
 #include <asm/tlbflush.h>
 #include <asm/shmparam.h>
 
+bool vmap_lazy_unmap __read_mostly = true;
 
 /*** Page table manipulation functions ***/
 
@@ -502,6 +503,9 @@
 {
 	unsigned int log;
 
+	if (!vmap_lazy_unmap)
+		return 0;
+
 	log = fls(num_online_cpus());
 
 	return log * (32UL * 1024 * 1024 / PAGE_SIZE);
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index 6d0bd19..be04d461 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -103,6 +103,7 @@
 	struct rate_control_ops *ops;
 	const char *alg_name;
 
+	kparam_block_sysfs_write(ieee80211_default_rc_algo);
 	if (!name)
 		alg_name = ieee80211_default_rc_algo;
 	else
@@ -120,6 +121,7 @@
 	/* try built-in one if specific alg requested but not found */
 	if (!ops && strlen(CONFIG_MAC80211_RC_DEFAULT))
 		ops = ieee80211_try_rate_control_ops_get(CONFIG_MAC80211_RC_DEFAULT);
+	kparam_unblock_sysfs_write(ieee80211_default_rc_algo);
 
 	return ops;
 }
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index 7043b29..8e22bd3 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -597,12 +597,6 @@
 #define dbgprintk(FMT,...) \
 	printk("[%-6.6s] "FMT"\n", current->comm ,##__VA_ARGS__)
 
-/* make sure we maintain the format strings, even when debugging is disabled */
-static inline __attribute__((format(printf,1,2)))
-void _dbprintk(const char *fmt, ...)
-{
-}
-
 #define kenter(FMT,...)	dbgprintk("==> %s("FMT")",__func__ ,##__VA_ARGS__)
 #define kleave(FMT,...)	dbgprintk("<== %s()"FMT"",__func__ ,##__VA_ARGS__)
 #define kdebug(FMT,...)	dbgprintk("    "FMT ,##__VA_ARGS__)
@@ -655,11 +649,11 @@
 } while (0)
 
 #else
-#define _enter(FMT,...)	_dbprintk("==> %s("FMT")",__func__ ,##__VA_ARGS__)
-#define _leave(FMT,...)	_dbprintk("<== %s()"FMT"",__func__ ,##__VA_ARGS__)
-#define _debug(FMT,...)	_dbprintk("    "FMT ,##__VA_ARGS__)
-#define _proto(FMT,...)	_dbprintk("### "FMT ,##__VA_ARGS__)
-#define _net(FMT,...)	_dbprintk("@@@ "FMT ,##__VA_ARGS__)
+#define _enter(FMT,...)	no_printk("==> %s("FMT")",__func__ ,##__VA_ARGS__)
+#define _leave(FMT,...)	no_printk("<== %s()"FMT"",__func__ ,##__VA_ARGS__)
+#define _debug(FMT,...)	no_printk("    "FMT ,##__VA_ARGS__)
+#define _proto(FMT,...)	no_printk("### "FMT ,##__VA_ARGS__)
+#define _net(FMT,...)	no_printk("@@@ "FMT ,##__VA_ARGS__)
 #endif
 
 /*
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index 880d0de..36cb660 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -39,7 +39,7 @@
 static unsigned long number_cred_unused;
 
 #define MAX_HASHTABLE_BITS (10) 
-static int param_set_hashtbl_sz(const char *val, struct kernel_param *kp)
+static int param_set_hashtbl_sz(const char *val, const struct kernel_param *kp)
 {
 	unsigned long num;
 	unsigned int nbits;
@@ -61,7 +61,7 @@
 	return -EINVAL;
 }
 
-static int param_get_hashtbl_sz(char *buffer, struct kernel_param *kp)
+static int param_get_hashtbl_sz(char *buffer, const struct kernel_param *kp)
 {
 	unsigned int nbits;
 
@@ -71,6 +71,11 @@
 
 #define param_check_hashtbl_sz(name, p) __param_check(name, p, unsigned int);
 
+static struct kernel_param_ops param_ops_hashtbl_sz = {
+	.set = param_set_hashtbl_sz,
+	.get = param_get_hashtbl_sz,
+};
+
 module_param_named(auth_hashtable_size, auth_hashbits, hashtbl_sz, 0644);
 MODULE_PARM_DESC(auth_hashtable_size, "RPC credential cache hashtable size");
 
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 7ca65c7..49a62f0 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -2577,7 +2577,8 @@
 	xprt_unregister_transport(&xs_bc_tcp_transport);
 }
 
-static int param_set_uint_minmax(const char *val, struct kernel_param *kp,
+static int param_set_uint_minmax(const char *val,
+		const struct kernel_param *kp,
 		unsigned int min, unsigned int max)
 {
 	unsigned long num;
@@ -2592,34 +2593,37 @@
 	return 0;
 }
 
-static int param_set_portnr(const char *val, struct kernel_param *kp)
+static int param_set_portnr(const char *val, const struct kernel_param *kp)
 {
 	return param_set_uint_minmax(val, kp,
 			RPC_MIN_RESVPORT,
 			RPC_MAX_RESVPORT);
 }
 
-static int param_get_portnr(char *buffer, struct kernel_param *kp)
-{
-	return param_get_uint(buffer, kp);
-}
+static struct kernel_param_ops param_ops_portnr = {
+	.set = param_set_portnr,
+	.get = param_get_uint,
+};
+
 #define param_check_portnr(name, p) \
 	__param_check(name, p, unsigned int);
 
 module_param_named(min_resvport, xprt_min_resvport, portnr, 0644);
 module_param_named(max_resvport, xprt_max_resvport, portnr, 0644);
 
-static int param_set_slot_table_size(const char *val, struct kernel_param *kp)
+static int param_set_slot_table_size(const char *val,
+				     const struct kernel_param *kp)
 {
 	return param_set_uint_minmax(val, kp,
 			RPC_MIN_SLOT_TABLE,
 			RPC_MAX_SLOT_TABLE);
 }
 
-static int param_get_slot_table_size(char *buffer, struct kernel_param *kp)
-{
-	return param_get_uint(buffer, kp);
-}
+static struct kernel_param_ops param_ops_slot_table_size = {
+	.set = param_set_slot_table_size,
+	.get = param_get_uint,
+};
+
 #define param_check_slot_table_size(name, p) \
 	__param_check(name, p, unsigned int);
 
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 7acbdd8..1ec7158 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -790,6 +790,7 @@
 {
 	".comment*",
 	".debug*",
+	".GCC-command-line",	/* mn10300 */
 	".mdebug*",        /* alpha, score, mips etc. */
 	".pdr",            /* alpha, score, mips etc. */
 	".stab*",
@@ -1034,6 +1035,13 @@
  *   fromsec = .data*
  *   atsym   =__param*
  *
+ * Pattern 1a:
+ *   module_param_call() ops can refer to __init set function if permissions=0
+ *   The pattern is identified by:
+ *   tosec   = .init.text
+ *   fromsec = .data*
+ *   atsym   = __param_ops_*
+ *
  * Pattern 2:
  *   Many drivers utilise a *driver container with references to
  *   add, remove, probe functions etc.
@@ -1068,6 +1076,12 @@
 	    (strncmp(fromsym, "__param", strlen("__param")) == 0))
 		return 0;
 
+	/* Check for pattern 1a */
+	if (strcmp(tosec, ".init.text") == 0 &&
+	    match(fromsec, data_sections) &&
+	    (strncmp(fromsym, "__param_ops_", strlen("__param_ops_")) == 0))
+		return 0;
+
 	/* Check for pattern 2 */
 	if (match(tosec, init_exit_sections) &&
 	    match(fromsec, data_sections) &&
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 8db33a8..d5666d3 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -667,17 +667,29 @@
  * AppArmor sysfs module parameters
  */
 
-static int param_set_aabool(const char *val, struct kernel_param *kp);
-static int param_get_aabool(char *buffer, struct kernel_param *kp);
+static int param_set_aabool(const char *val, const struct kernel_param *kp);
+static int param_get_aabool(char *buffer, const struct kernel_param *kp);
 #define param_check_aabool(name, p) __param_check(name, p, int)
+static struct kernel_param_ops param_ops_aabool = {
+	.set = param_set_aabool,
+	.get = param_get_aabool
+};
 
-static int param_set_aauint(const char *val, struct kernel_param *kp);
-static int param_get_aauint(char *buffer, struct kernel_param *kp);
+static int param_set_aauint(const char *val, const struct kernel_param *kp);
+static int param_get_aauint(char *buffer, const struct kernel_param *kp);
 #define param_check_aauint(name, p) __param_check(name, p, int)
+static struct kernel_param_ops param_ops_aauint = {
+	.set = param_set_aauint,
+	.get = param_get_aauint
+};
 
-static int param_set_aalockpolicy(const char *val, struct kernel_param *kp);
-static int param_get_aalockpolicy(char *buffer, struct kernel_param *kp);
+static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp);
+static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp);
 #define param_check_aalockpolicy(name, p) __param_check(name, p, int)
+static struct kernel_param_ops param_ops_aalockpolicy = {
+	.set = param_set_aalockpolicy,
+	.get = param_get_aalockpolicy
+};
 
 static int param_set_audit(const char *val, struct kernel_param *kp);
 static int param_get_audit(char *buffer, struct kernel_param *kp);
@@ -751,7 +763,7 @@
 __setup("apparmor=", apparmor_enabled_setup);
 
 /* set global flag turning off the ability to load policy */
-static int param_set_aalockpolicy(const char *val, struct kernel_param *kp)
+static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp)
 {
 	if (!capable(CAP_MAC_ADMIN))
 		return -EPERM;
@@ -760,35 +772,35 @@
 	return param_set_bool(val, kp);
 }
 
-static int param_get_aalockpolicy(char *buffer, struct kernel_param *kp)
+static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp)
 {
 	if (!capable(CAP_MAC_ADMIN))
 		return -EPERM;
 	return param_get_bool(buffer, kp);
 }
 
-static int param_set_aabool(const char *val, struct kernel_param *kp)
+static int param_set_aabool(const char *val, const struct kernel_param *kp)
 {
 	if (!capable(CAP_MAC_ADMIN))
 		return -EPERM;
 	return param_set_bool(val, kp);
 }
 
-static int param_get_aabool(char *buffer, struct kernel_param *kp)
+static int param_get_aabool(char *buffer, const struct kernel_param *kp)
 {
 	if (!capable(CAP_MAC_ADMIN))
 		return -EPERM;
 	return param_get_bool(buffer, kp);
 }
 
-static int param_set_aauint(const char *val, struct kernel_param *kp)
+static int param_set_aauint(const char *val, const struct kernel_param *kp)
 {
 	if (!capable(CAP_MAC_ADMIN))
 		return -EPERM;
 	return param_set_uint(val, kp);
 }
 
-static int param_get_aauint(char *buffer, struct kernel_param *kp)
+static int param_get_aauint(char *buffer, const struct kernel_param *kp)
 {
 	if (!capable(CAP_MAC_ADMIN))
 		return -EPERM;
diff --git a/security/keys/internal.h b/security/keys/internal.h
index addb67b..56a133d 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -15,11 +15,6 @@
 #include <linux/sched.h>
 #include <linux/key-type.h>
 
-static inline __attribute__((format(printf, 1, 2)))
-void no_printk(const char *fmt, ...)
-{
-}
-
 #ifdef __KDEBUG
 #define kenter(FMT, ...) \
 	printk(KERN_DEBUG "==> %s("FMT")\n", __func__, ##__VA_ARGS__)
diff --git a/sound/aoa/soundbus/core.c b/sound/aoa/soundbus/core.c
index 99ca712..7487eb7 100644
--- a/sound/aoa/soundbus/core.c
+++ b/sound/aoa/soundbus/core.c
@@ -59,7 +59,7 @@
 static int soundbus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct soundbus_dev * soundbus_dev;
-	struct of_device * of;
+	struct platform_device * of;
 	const char *compat;
 	int retval = 0;
 	int cplen, seen = 0;
diff --git a/sound/aoa/soundbus/soundbus.h b/sound/aoa/soundbus/soundbus.h
index a0f223c..adecbf3 100644
--- a/sound/aoa/soundbus/soundbus.h
+++ b/sound/aoa/soundbus/soundbus.h
@@ -141,7 +141,7 @@
 	struct list_head onbuslist;
 
 	/* the of device it represents */
-	struct of_device ofdev;
+	struct platform_device ofdev;
 
 	/* what modules go by */
 	char modalias[32];
diff --git a/sound/aoa/soundbus/sysfs.c b/sound/aoa/soundbus/sysfs.c
index 6496e75..e0980b5 100644
--- a/sound/aoa/soundbus/sysfs.c
+++ b/sound/aoa/soundbus/sysfs.c
@@ -16,7 +16,7 @@
 			     char *buf)
 {
 	struct soundbus_dev *sdev = to_soundbus_device(dev);
-	struct of_device *of = &sdev->ofdev;
+	struct platform_device *of = &sdev->ofdev;
 	int length;
 
 	if (*sdev->modalias) {
diff --git a/sound/oss/ad1848.c b/sound/oss/ad1848.c
index 24793c5..4d2a6ae9 100644
--- a/sound/oss/ad1848.c
+++ b/sound/oss/ad1848.c
@@ -716,7 +716,7 @@
 				
 				default:
 					if (get_user(val, (int __user *)arg))
-					return -EFAULT;
+						return -EFAULT;
 					val = ad1848_mixer_set(devc, cmd & 0xff, val);
 					break;
 			} 
diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c
index c4a4cdc..c6f2621 100644
--- a/sound/oss/au1550_ac97.c
+++ b/sound/oss/au1550_ac97.c
@@ -50,7 +50,6 @@
 #include <linux/poll.h>
 #include <linux/bitops.h>
 #include <linux/spinlock.h>
-#include <linux/smp_lock.h>
 #include <linux/ac97_codec.h>
 #include <linux/mutex.h>
 
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index a7802b9..720a81d 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -971,6 +971,36 @@
 }
 
 /*
+ * audio-converter setup caches
+ */
+struct hda_cvt_setup {
+	hda_nid_t nid;
+	u8 stream_tag;
+	u8 channel_id;
+	u16 format_id;
+	unsigned char active;	/* cvt is currently used */
+	unsigned char dirty;	/* setups should be cleared */
+};
+
+/* get or create a cache entry for the given audio converter NID */
+static struct hda_cvt_setup *
+get_hda_cvt_setup(struct hda_codec *codec, hda_nid_t nid)
+{
+	struct hda_cvt_setup *p;
+	int i;
+
+	for (i = 0; i < codec->cvt_setups.used; i++) {
+		p = snd_array_elem(&codec->cvt_setups, i);
+		if (p->nid == nid)
+			return p;
+	}
+	p = snd_array_new(&codec->cvt_setups);
+	if (p)
+		p->nid = nid;
+	return p;
+}
+
+/*
  * codec destructor
  */
 static void snd_hda_codec_free(struct hda_codec *codec)
@@ -1038,12 +1068,14 @@
 	codec->addr = codec_addr;
 	mutex_init(&codec->spdif_mutex);
 	mutex_init(&codec->control_mutex);
+	mutex_init(&codec->prepare_mutex);
 	init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
 	init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
 	snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32);
 	snd_array_init(&codec->nids, sizeof(struct hda_nid_item), 32);
 	snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16);
 	snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16);
+	snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8);
 	if (codec->bus->modelname) {
 		codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
 		if (!codec->modelname) {
@@ -1181,16 +1213,51 @@
 				u32 stream_tag,
 				int channel_id, int format)
 {
+	struct hda_cvt_setup *p;
+	unsigned int oldval, newval;
+	int i;
+
 	if (!nid)
 		return;
 
 	snd_printdd("hda_codec_setup_stream: "
 		    "NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n",
 		    nid, stream_tag, channel_id, format);
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID,
-			    (stream_tag << 4) | channel_id);
-	msleep(1);
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, format);
+	p = get_hda_cvt_setup(codec, nid);
+	if (!p)
+		return;
+	/* update the stream-id if changed */
+	if (p->stream_tag != stream_tag || p->channel_id != channel_id) {
+		oldval = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
+		newval = (stream_tag << 4) | channel_id;
+		if (oldval != newval)
+			snd_hda_codec_write(codec, nid, 0,
+					    AC_VERB_SET_CHANNEL_STREAMID,
+					    newval);
+		p->stream_tag = stream_tag;
+		p->channel_id = channel_id;
+	}
+	/* update the format-id if changed */
+	if (p->format_id != format) {
+		oldval = snd_hda_codec_read(codec, nid, 0,
+					    AC_VERB_GET_STREAM_FORMAT, 0);
+		if (oldval != format) {
+			msleep(1);
+			snd_hda_codec_write(codec, nid, 0,
+					    AC_VERB_SET_STREAM_FORMAT,
+					    format);
+		}
+		p->format_id = format;
+	}
+	p->active = 1;
+	p->dirty = 0;
+
+	/* make other inactive cvts with the same stream-tag dirty */
+	for (i = 0; i < codec->cvt_setups.used; i++) {
+		p = snd_array_elem(&codec->cvt_setups, i);
+		if (!p->active && p->stream_tag == stream_tag)
+			p->dirty = 1;
+	}
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_setup_stream);
 
@@ -1201,18 +1268,55 @@
  */
 void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid)
 {
+	struct hda_cvt_setup *p;
+
 	if (!nid)
 		return;
 
 	snd_printdd("hda_codec_cleanup_stream: NID=0x%x\n", nid);
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0);
-#if 0 /* keep the format */
-	msleep(1);
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0);
-#endif
+	/* here we just clear the active flag; actual clean-ups will be done
+	 * in purify_inactive_streams()
+	 */
+	p = get_hda_cvt_setup(codec, nid);
+	if (p)
+		p->active = 0;
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup_stream);
 
+static void really_cleanup_stream(struct hda_codec *codec,
+				  struct hda_cvt_setup *q)
+{
+	hda_nid_t nid = q->nid;
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0);
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0);
+	memset(q, 0, sizeof(*q));
+	q->nid = nid;
+}
+
+/* clean up the all conflicting obsolete streams */
+static void purify_inactive_streams(struct hda_codec *codec)
+{
+	int i;
+
+	for (i = 0; i < codec->cvt_setups.used; i++) {
+		struct hda_cvt_setup *p = snd_array_elem(&codec->cvt_setups, i);
+		if (p->dirty)
+			really_cleanup_stream(codec, p);
+	}
+}
+
+/* clean up all streams; called from suspend */
+static void hda_cleanup_all_streams(struct hda_codec *codec)
+{
+	int i;
+
+	for (i = 0; i < codec->cvt_setups.used; i++) {
+		struct hda_cvt_setup *p = snd_array_elem(&codec->cvt_setups, i);
+		if (p->stream_tag)
+			really_cleanup_stream(codec, p);
+	}
+}
+
 /*
  * amp access functions
  */
@@ -2928,6 +3032,7 @@
 {
 	if (codec->patch_ops.suspend)
 		codec->patch_ops.suspend(codec, PMSG_SUSPEND);
+	hda_cleanup_all_streams(codec);
 	hda_set_power_state(codec,
 			    codec->afg ? codec->afg : codec->mfg,
 			    AC_PWRST_D3);
@@ -3377,6 +3482,35 @@
 	return 0;
 }
 
+/*
+ * codec prepare/cleanup entries
+ */
+int snd_hda_codec_prepare(struct hda_codec *codec,
+			  struct hda_pcm_stream *hinfo,
+			  unsigned int stream,
+			  unsigned int format,
+			  struct snd_pcm_substream *substream)
+{
+	int ret;
+	mutex_lock(&codec->prepare_mutex);
+	ret = hinfo->ops.prepare(hinfo, codec, stream, format, substream);
+	if (ret >= 0)
+		purify_inactive_streams(codec);
+	mutex_unlock(&codec->prepare_mutex);
+	return ret;
+}
+EXPORT_SYMBOL_HDA(snd_hda_codec_prepare);
+
+void snd_hda_codec_cleanup(struct hda_codec *codec,
+			   struct hda_pcm_stream *hinfo,
+			   struct snd_pcm_substream *substream)
+{
+	mutex_lock(&codec->prepare_mutex);
+	hinfo->ops.cleanup(hinfo, codec, substream);
+	mutex_unlock(&codec->prepare_mutex);
+}
+EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup);
+
 /* global */
 const char *snd_hda_pcm_type_name[HDA_PCM_NTYPES] = {
 	"Audio", "SPDIF", "HDMI", "Modem"
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 0328cf5..3f7a479 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -826,12 +826,14 @@
 
 	struct mutex spdif_mutex;
 	struct mutex control_mutex;
+	struct mutex prepare_mutex;
 	unsigned int spdif_status;	/* IEC958 status bits */
 	unsigned short spdif_ctls;	/* SPDIF control bits */
 	unsigned int spdif_in_enable;	/* SPDIF input enable? */
 	hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
 	struct snd_array init_pins;	/* initial (BIOS) pin configurations */
 	struct snd_array driver_pins;	/* pin configs set by codec parser */
+	struct snd_array cvt_setups;	/* audio convert setups */
 
 #ifdef CONFIG_SND_HDA_HWDEP
 	struct snd_hwdep *hwdep;	/* assigned hwdep device */
@@ -948,6 +950,16 @@
  */
 int snd_hda_build_pcms(struct hda_bus *bus);
 int snd_hda_codec_build_pcms(struct hda_codec *codec);
+
+int snd_hda_codec_prepare(struct hda_codec *codec,
+			  struct hda_pcm_stream *hinfo,
+			  unsigned int stream,
+			  unsigned int format,
+			  struct snd_pcm_substream *substream);
+void snd_hda_codec_cleanup(struct hda_codec *codec,
+			   struct hda_pcm_stream *hinfo,
+			   struct snd_pcm_substream *substream);
+
 void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
 				u32 stream_tag,
 				int channel_id, int format);
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 66d4202..1053fff 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -1634,7 +1634,7 @@
 	azx_dev->period_bytes = 0;
 	azx_dev->format_val = 0;
 
-	hinfo->ops.cleanup(hinfo, apcm->codec, substream);
+	snd_hda_codec_cleanup(apcm->codec, hinfo, substream);
 
 	return snd_pcm_lib_free_pages(substream);
 }
@@ -1688,8 +1688,8 @@
 	else
 		azx_dev->fifo_size = 0;
 
-	return hinfo->ops.prepare(hinfo, apcm->codec, azx_dev->stream_tag,
-				  azx_dev->format_val, substream);
+	return snd_hda_codec_prepare(apcm->codec, hinfo, azx_dev->stream_tag,
+				     azx_dev->format_val, substream);
 }
 
 static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index df8b19b..f7e234e 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -3206,6 +3206,8 @@
 	  .patch = patch_cxt5066 },
 	{ .id = 0x14f15067, .name = "CX20583 (Pebble HSF)",
 	  .patch = patch_cxt5066 },
+	{ .id = 0x14f15068, .name = "CX20584",
+	  .patch = patch_cxt5066 },
 	{ .id = 0x14f15069, .name = "CX20585",
 	  .patch = patch_cxt5066 },
 	{} /* terminator */
@@ -3216,6 +3218,7 @@
 MODULE_ALIAS("snd-hda-codec-id:14f15051");
 MODULE_ALIAS("snd-hda-codec-id:14f15066");
 MODULE_ALIAS("snd-hda-codec-id:14f15067");
+MODULE_ALIAS("snd-hda-codec-id:14f15068");
 MODULE_ALIAS("snd-hda-codec-id:14f15069");
 
 MODULE_LICENSE("GPL");
diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c
index a281836..77e2b40 100644
--- a/sound/pci/hda/patch_nvhdmi.c
+++ b/sound/pci/hda/patch_nvhdmi.c
@@ -540,26 +540,32 @@
  * patch entries
  */
 static struct hda_codec_preset snd_hda_preset_nvhdmi[] = {
-	{ .id = 0x10de0002, .name = "MCP77/78 HDMI",
-	  .patch = patch_nvhdmi_8ch_7x },
-	{ .id = 0x10de0003, .name = "MCP77/78 HDMI",
-	  .patch = patch_nvhdmi_8ch_7x },
-	{ .id = 0x10de0005, .name = "MCP77/78 HDMI",
-	  .patch = patch_nvhdmi_8ch_7x },
-	{ .id = 0x10de0006, .name = "MCP77/78 HDMI",
-	  .patch = patch_nvhdmi_8ch_7x },
-	{ .id = 0x10de0007, .name = "MCP79/7A HDMI",
-	  .patch = patch_nvhdmi_8ch_7x },
-	{ .id = 0x10de000a, .name = "GT220 HDMI",
-	  .patch = patch_nvhdmi_8ch_89 },
-	{ .id = 0x10de000b, .name = "GT21x HDMI",
-	  .patch = patch_nvhdmi_8ch_89 },
-	{ .id = 0x10de000c, .name = "MCP89 HDMI",
-	  .patch = patch_nvhdmi_8ch_89 },
-	{ .id = 0x10de000d, .name = "GT240 HDMI",
-	  .patch = patch_nvhdmi_8ch_89 },
-	{ .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch },
-	{ .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch },
+	{ .id = 0x10de0002, .name = "MCP77/78 HDMI",  .patch = patch_nvhdmi_8ch_7x },
+	{ .id = 0x10de0003, .name = "MCP77/78 HDMI",  .patch = patch_nvhdmi_8ch_7x },
+	{ .id = 0x10de0005, .name = "MCP77/78 HDMI",  .patch = patch_nvhdmi_8ch_7x },
+	{ .id = 0x10de0006, .name = "MCP77/78 HDMI",  .patch = patch_nvhdmi_8ch_7x },
+	{ .id = 0x10de0007, .name = "MCP79/7A HDMI",  .patch = patch_nvhdmi_8ch_7x },
+	{ .id = 0x10de000a, .name = "GPU 0a HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+	{ .id = 0x10de000b, .name = "GPU 0b HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+	{ .id = 0x10de000c, .name = "MCP89 HDMI",     .patch = patch_nvhdmi_8ch_89 },
+	{ .id = 0x10de000d, .name = "GPU 0d HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+	{ .id = 0x10de0010, .name = "GPU 10 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+	{ .id = 0x10de0011, .name = "GPU 11 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+	{ .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+	{ .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+	{ .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+	{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+	{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+	{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+	{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+	{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+	{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+	{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+	{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+	{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+	{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_nvhdmi_8ch_89 },
+	{ .id = 0x10de0067, .name = "MCP67 HDMI",     .patch = patch_nvhdmi_2ch },
+	{ .id = 0x10de8001, .name = "MCP73 HDMI",     .patch = patch_nvhdmi_2ch },
 	{} /* terminator */
 };
 
@@ -572,6 +578,21 @@
 MODULE_ALIAS("snd-hda-codec-id:10de000b");
 MODULE_ALIAS("snd-hda-codec-id:10de000c");
 MODULE_ALIAS("snd-hda-codec-id:10de000d");
+MODULE_ALIAS("snd-hda-codec-id:10de0010");
+MODULE_ALIAS("snd-hda-codec-id:10de0011");
+MODULE_ALIAS("snd-hda-codec-id:10de0012");
+MODULE_ALIAS("snd-hda-codec-id:10de0013");
+MODULE_ALIAS("snd-hda-codec-id:10de0014");
+MODULE_ALIAS("snd-hda-codec-id:10de0018");
+MODULE_ALIAS("snd-hda-codec-id:10de0019");
+MODULE_ALIAS("snd-hda-codec-id:10de001a");
+MODULE_ALIAS("snd-hda-codec-id:10de001b");
+MODULE_ALIAS("snd-hda-codec-id:10de001c");
+MODULE_ALIAS("snd-hda-codec-id:10de0040");
+MODULE_ALIAS("snd-hda-codec-id:10de0041");
+MODULE_ALIAS("snd-hda-codec-id:10de0042");
+MODULE_ALIAS("snd-hda-codec-id:10de0043");
+MODULE_ALIAS("snd-hda-codec-id:10de0044");
 MODULE_ALIAS("snd-hda-codec-id:10de0067");
 MODULE_ALIAS("snd-hda-codec-id:10de8001");
 
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 6ac53f7..55d6e5b 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -137,6 +137,7 @@
 	ALC269VB_DMIC,
 	ALC269_FUJITSU,
 	ALC269_LIFEBOOK,
+	ALC271_ACER,
 	ALC269_AUTO,
 	ALC269_MODEL_LAST /* last tag */
 };
@@ -7041,6 +7042,7 @@
 
 	spec->stream_analog_playback = &alc260_pcm_analog_playback;
 	spec->stream_analog_capture = &alc260_pcm_analog_capture;
+	spec->stream_analog_alt_capture = &alc260_pcm_analog_capture;
 
 	spec->stream_digital_playback = &alc260_pcm_digital_playback;
 	spec->stream_digital_capture = &alc260_pcm_digital_capture;
@@ -13475,7 +13477,6 @@
 	SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
 	SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
 	SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
-	SND_PCI_QUIRK(0x1854, 0x1775, "LG R510", ALC268_DELL),
 	{}
 };
 
@@ -13866,6 +13867,12 @@
 	{ } /* end */
 };
 
+static struct snd_kcontrol_new alc269_asus_mixer[] = {
+	HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT),
+	{ } /* end */
+};
+
 /* capture mixer elements */
 static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
@@ -14086,6 +14093,20 @@
 	{}
 };
 
+static struct hda_verb alc271_acer_dmic_verbs[] = {
+	{0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
+	{0x20, AC_VERB_SET_PROC_COEF, 0x4000},
+	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x21, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+	{0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
+	{0x22, AC_VERB_SET_CONNECT_SEL, 6},
+	{ }
+};
+
 /* toggle speaker-output according to the hp-jack state */
 static void alc269_speaker_automute(struct hda_codec *codec)
 {
@@ -14465,6 +14486,7 @@
 
 static struct snd_pci_quirk alc269_cfg_tbl[] = {
 	SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
+	SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER),
 	SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
 		      ALC269_AMIC),
 	SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC),
@@ -14626,6 +14648,23 @@
 		.unsol_event = alc269_lifebook_unsol_event,
 		.init_hook = alc269_lifebook_init_hook,
 	},
+	[ALC271_ACER] = {
+		.mixers = { alc269_asus_mixer },
+		.cap_mixer = alc269vb_laptop_digital_capture_mixer,
+		.init_verbs = { alc269_init_verbs, alc271_acer_dmic_verbs },
+		.num_dacs = ARRAY_SIZE(alc269_dac_nids),
+		.dac_nids = alc269_dac_nids,
+		.adc_nids = alc262_dmic_adc_nids,
+		.num_adc_nids = ARRAY_SIZE(alc262_dmic_adc_nids),
+		.capsrc_nids = alc262_dmic_capsrc_nids,
+		.num_channel_mode = ARRAY_SIZE(alc269_modes),
+		.channel_mode = alc269_modes,
+		.input_mux = &alc269_capture_source,
+		.dig_out_nid = ALC880_DIGOUT_NID,
+		.unsol_event = alc_sku_unsol_event,
+		.setup = alc269vb_laptop_dmic_setup,
+		.init_hook = alc_inithook,
+	},
 };
 
 static int patch_alc269(struct hda_codec *codec)
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index b8d730c..f3f861b 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -94,6 +94,7 @@
 	STAC_92HD83XXX_PWR_REF,
 	STAC_DELL_S14,
 	STAC_92HD83XXX_HP,
+	STAC_HP_DV7_4000,
 	STAC_92HD83XXX_MODELS
 };
 
@@ -1632,10 +1633,17 @@
 	0x40f000f0, 0x40f000f0,
 };
 
+static unsigned int hp_dv7_4000_pin_configs[10] = {
+	0x03a12050, 0x0321201f, 0x40f000f0, 0x90170110,
+	0x40f000f0, 0x40f000f0, 0x90170110, 0xd5a30140,
+	0x40f000f0, 0x40f000f0,
+};
+
 static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = {
 	[STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs,
 	[STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs,
 	[STAC_DELL_S14] = dell_s14_pin_configs,
+	[STAC_HP_DV7_4000] = hp_dv7_4000_pin_configs,
 };
 
 static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = {
@@ -1644,6 +1652,7 @@
 	[STAC_92HD83XXX_PWR_REF] = "mic-ref",
 	[STAC_DELL_S14] = "dell-s14",
 	[STAC_92HD83XXX_HP] = "hp",
+	[STAC_HP_DV7_4000] = "hp-dv7-4000",
 };
 
 static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
@@ -5340,6 +5349,8 @@
 	case 0x111d7667:
 	case 0x111d7668:
 	case 0x111d7669:
+	case 0x111d76d1:
+	case 0x111d76d9:
 		spec->num_pins = ARRAY_SIZE(stac92hd88xxx_pin_nids);
 		spec->pin_nids = stac92hd88xxx_pin_nids;
 		spec->mono_nid = 0;
@@ -6274,6 +6285,8 @@
 	{ .id = 0x111d76d4, .name = "92HD83C1C5", .patch = patch_stac92hd83xxx},
 	{ .id = 0x111d7605, .name = "92HD81B1X5", .patch = patch_stac92hd83xxx},
 	{ .id = 0x111d76d5, .name = "92HD81B1C5", .patch = patch_stac92hd83xxx},
+	{ .id = 0x111d76d1, .name = "92HD87B1/3", .patch = patch_stac92hd83xxx},
+	{ .id = 0x111d76d9, .name = "92HD87B2/4", .patch = patch_stac92hd83xxx},
 	{ .id = 0x111d7666, .name = "92HD88B3", .patch = patch_stac92hd83xxx},
 	{ .id = 0x111d7667, .name = "92HD88B1", .patch = patch_stac92hd83xxx},
 	{ .id = 0x111d7668, .name = "92HD88B2", .patch = patch_stac92hd83xxx},
diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig
index 8ef2502..3abeedd 100644
--- a/sound/soc/blackfin/Kconfig
+++ b/sound/soc/blackfin/Kconfig
@@ -105,13 +105,18 @@
 	  Set the correct GPIO for RESET the sound chip.
 
 config SND_BF5XX_SOC_AD1980
-	tristate "SoC AD1980/1 Audio support for BF5xx"
+	tristate "SoC AD1980/1 Audio support for BF5xx (Obsolete)"
 	depends on SND_BF5XX_AC97
 	select SND_BF5XX_SOC_AC97
 	select SND_SOC_AD1980
 	help
 	  Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT.
 
+	  Warning:
+	  Because Analog Devices Inc. discontinued the ad1980 sound chip since
+	  Sep. 2009, this ad1980 driver is not maintained, tested and supported
+	  by ADI now.
+
 config SND_BF5XX_SOC_SPORT
 	tristate
 
diff --git a/sound/soc/blackfin/bf5xx-ad1980.c b/sound/soc/blackfin/bf5xx-ad1980.c
index d8f5912..92f7c32 100644
--- a/sound/soc/blackfin/bf5xx-ad1980.c
+++ b/sound/soc/blackfin/bf5xx-ad1980.c
@@ -26,6 +26,14 @@
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+/*
+ * WARNING:
+ *
+ * Because Analog Devices Inc. discontinued the ad1980 sound chip since
+ * Sep. 2009, this ad1980 driver is not maintained, tested and supported
+ * by ADI now.
+ */
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/device.h>
@@ -109,5 +117,5 @@
 
 /* Module information */
 MODULE_AUTHOR("Cliff Cai");
-MODULE_DESCRIPTION("ALSA SoC AD1980/1 BF5xx board");
+MODULE_DESCRIPTION("ALSA SoC AD1980/1 BF5xx board (Obsolete)");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
index 0420727..70cfaec 100644
--- a/sound/soc/codecs/ad1980.c
+++ b/sound/soc/codecs/ad1980.c
@@ -11,6 +11,14 @@
  *  option) any later version.
  */
 
+/*
+ * WARNING:
+ *
+ * Because Analog Devices Inc. discontinued the ad1980 sound chip since
+ * Sep. 2009, this ad1980 driver is not maintained, tested and supported
+ * by ADI now.
+ */
+
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
@@ -298,6 +306,6 @@
 };
 EXPORT_SYMBOL_GPL(soc_codec_dev_ad1980);
 
-MODULE_DESCRIPTION("ASoC ad1980 driver");
+MODULE_DESCRIPTION("ASoC ad1980 driver (Obsolete)");
 MODULE_AUTHOR("Roy Huang, Cliff Cai");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ad1980.h b/sound/soc/codecs/ad1980.h
index db6c850..538f37c 100644
--- a/sound/soc/codecs/ad1980.h
+++ b/sound/soc/codecs/ad1980.h
@@ -1,5 +1,11 @@
 /*
  * ad1980.h  --  ad1980 Soc Audio driver
+ *
+ * WARNING:
+ *
+ * Because Analog Devices Inc. discontinued the ad1980 sound chip since
+ * Sep. 2009, this ad1980 driver is not maintained, tested and supported
+ * by ADI now.
  */
 
 #ifndef _AD1980_H
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index c3571ee..72deeab 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -269,9 +269,9 @@
 SOC_DOUBLE("DAC3 Invert Switch", WM8580_DAC_CONTROL4,  4, 5, 1, 0),
 
 SOC_SINGLE("DAC ZC Switch", WM8580_DAC_CONTROL5, 5, 1, 0),
-SOC_SINGLE("DAC1 Switch", WM8580_DAC_CONTROL5, 0, 1, 0),
-SOC_SINGLE("DAC2 Switch", WM8580_DAC_CONTROL5, 1, 1, 0),
-SOC_SINGLE("DAC3 Switch", WM8580_DAC_CONTROL5, 2, 1, 0),
+SOC_SINGLE("DAC1 Switch", WM8580_DAC_CONTROL5, 0, 1, 1),
+SOC_SINGLE("DAC2 Switch", WM8580_DAC_CONTROL5, 1, 1, 1),
+SOC_SINGLE("DAC3 Switch", WM8580_DAC_CONTROL5, 2, 1, 1),
 
 SOC_DOUBLE("ADC Mute Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 0),
 SOC_SINGLE("ADC High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0),
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
index 1d4e716..3dcd146 100644
--- a/sound/soc/fsl/mpc5200_dma.c
+++ b/sound/soc/fsl/mpc5200_dma.c
@@ -369,7 +369,7 @@
 };
 EXPORT_SYMBOL_GPL(mpc5200_audio_dma_platform);
 
-int mpc5200_audio_dma_create(struct of_device *op)
+int mpc5200_audio_dma_create(struct platform_device *op)
 {
 	phys_addr_t fifo;
 	struct psc_dma *psc_dma;
@@ -488,7 +488,7 @@
 }
 EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create);
 
-int mpc5200_audio_dma_destroy(struct of_device *op)
+int mpc5200_audio_dma_destroy(struct platform_device *op)
 {
 	struct psc_dma *psc_dma = dev_get_drvdata(&op->dev);
 
diff --git a/sound/soc/fsl/mpc5200_dma.h b/sound/soc/fsl/mpc5200_dma.h
index e1ec6d9..ca99586 100644
--- a/sound/soc/fsl/mpc5200_dma.h
+++ b/sound/soc/fsl/mpc5200_dma.h
@@ -81,8 +81,8 @@
 	return &psc_dma->playback;
 }
 
-int mpc5200_audio_dma_create(struct of_device *op);
-int mpc5200_audio_dma_destroy(struct of_device *op);
+int mpc5200_audio_dma_create(struct platform_device *op);
+int mpc5200_audio_dma_destroy(struct platform_device *op);
 
 extern struct snd_soc_platform mpc5200_audio_dma_platform;
 
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c
index e7f5d50..a956023 100644
--- a/sound/soc/fsl/mpc5200_psc_ac97.c
+++ b/sound/soc/fsl/mpc5200_psc_ac97.c
@@ -277,7 +277,7 @@
  * - Probe/remove operations
  * - OF device match table
  */
-static int __devinit psc_ac97_of_probe(struct of_device *op,
+static int __devinit psc_ac97_of_probe(struct platform_device *op,
 				      const struct of_device_id *match)
 {
 	int rc, i;
@@ -317,7 +317,7 @@
 	return 0;
 }
 
-static int __devexit psc_ac97_of_remove(struct of_device *op)
+static int __devexit psc_ac97_of_remove(struct platform_device *op)
 {
 	return mpc5200_audio_dma_destroy(op);
 }
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c
index 676841c..534f04cb 100644
--- a/sound/soc/fsl/mpc5200_psc_i2s.c
+++ b/sound/soc/fsl/mpc5200_psc_i2s.c
@@ -152,7 +152,7 @@
  * - Probe/remove operations
  * - OF device match table
  */
-static int __devinit psc_i2s_of_probe(struct of_device *op,
+static int __devinit psc_i2s_of_probe(struct platform_device *op,
 				      const struct of_device_id *match)
 {
 	int rc;
@@ -205,7 +205,7 @@
 
 }
 
-static int __devexit psc_i2s_of_remove(struct of_device *op)
+static int __devexit psc_i2s_of_remove(struct platform_device *op)
 {
 	return mpc5200_audio_dma_destroy(op);
 }
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index 3a50106..3b13b8d 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -200,7 +200,7 @@
  * SSI devices.  We also probably aren't compatible with the generic Elo DMA
  * device driver.
  */
-static int mpc8610_hpcd_probe(struct of_device *ofdev,
+static int mpc8610_hpcd_probe(struct platform_device *ofdev,
 	const struct of_device_id *match)
 {
 	struct device_node *np = ofdev->dev.of_node;
@@ -534,7 +534,7 @@
  *
  * This function is called when the OF device is removed.
  */
-static int mpc8610_hpcd_remove(struct of_device *ofdev)
+static int mpc8610_hpcd_remove(struct platform_device *ofdev)
 {
 	struct platform_device *sound_device = dev_get_drvdata(&ofdev->dev);
 	struct mpc8610_hpcd_data *machine_data =
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig
index 52dac5e..687c76f 100644
--- a/sound/soc/imx/Kconfig
+++ b/sound/soc/imx/Kconfig
@@ -28,7 +28,9 @@
 
 config SND_SOC_EUKREA_TLV320
 	tristate "Eukrea TLV320"
-	depends on MACH_EUKREA_MBIMX27_BASEBOARD || MACH_EUKREA_MBIMXSD_BASEBOARD
+	depends on MACH_EUKREA_MBIMX27_BASEBOARD \
+		|| MACH_EUKREA_MBIMXSD25_BASEBOARD \
+		|| MACH_EUKREA_MBIMXSD35_BASEBOARD
 	select SND_SOC_TLV320AIC23
 	help
 	  Enable I2S based access to the TLV320AIC23B codec attached
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c
index 472af38..adbc68c 100644
--- a/sound/soc/soc-cache.c
+++ b/sound/soc/soc-cache.c
@@ -340,7 +340,7 @@
 static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
 				     unsigned int reg)
 {
-	u16 *cache = codec->reg_cache;
+	u8 *cache = codec->reg_cache;
 
 	reg &= 0xff;
 	if (reg >= codec->reg_cache_size)
@@ -351,7 +351,7 @@
 static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
 			     unsigned int value)
 {
-	u16 *cache = codec->reg_cache;
+	u8 *cache = codec->reg_cache;
 	u8 data[3];
 	int ret;
 
diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c
index 9eb1a4e..f8bcfc3 100644
--- a/sound/sparc/amd7930.c
+++ b/sound/sparc/amd7930.c
@@ -336,7 +336,7 @@
 	int			pgain;
 	int			mgain;
 
-	struct of_device	*op;
+	struct platform_device	*op;
 	unsigned int		irq;
 	struct snd_amd7930	*next;
 };
@@ -906,7 +906,7 @@
 
 static int snd_amd7930_free(struct snd_amd7930 *amd)
 {
-	struct of_device *op = amd->op;
+	struct platform_device *op = amd->op;
 
 	amd7930_idle(amd);
 
@@ -934,7 +934,7 @@
 };
 
 static int __devinit snd_amd7930_create(struct snd_card *card,
-					struct of_device *op,
+					struct platform_device *op,
 					int irq, int dev,
 					struct snd_amd7930 **ramd)
 {
@@ -1002,7 +1002,7 @@
 	return 0;
 }
 
-static int __devinit amd7930_sbus_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit amd7930_sbus_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	struct resource *rp = &op->resource[0];
 	static int dev_num;
diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c
index 68570ee..c276086 100644
--- a/sound/sparc/cs4231.c
+++ b/sound/sparc/cs4231.c
@@ -111,7 +111,7 @@
 	struct mutex		mce_mutex;	/* mutex for mce register */
 	struct mutex		open_mutex;	/* mutex for ALSA open/close */
 
-	struct of_device	*op;
+	struct platform_device	*op;
 	unsigned int		irq[2];
 	unsigned int		regs_size;
 	struct snd_cs4231	*next;
@@ -1771,7 +1771,7 @@
 
 static int snd_cs4231_sbus_free(struct snd_cs4231 *chip)
 {
-	struct of_device *op = chip->op;
+	struct platform_device *op = chip->op;
 
 	if (chip->irq[0])
 		free_irq(chip->irq[0], chip);
@@ -1794,7 +1794,7 @@
 };
 
 static int __devinit snd_cs4231_sbus_create(struct snd_card *card,
-					    struct of_device *op,
+					    struct platform_device *op,
 					    int dev)
 {
 	struct snd_cs4231 *chip = card->private_data;
@@ -1856,7 +1856,7 @@
 	return 0;
 }
 
-static int __devinit cs4231_sbus_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit cs4231_sbus_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	struct resource *rp = &op->resource[0];
 	struct snd_card *card;
@@ -1931,7 +1931,7 @@
 
 static int snd_cs4231_ebus_free(struct snd_cs4231 *chip)
 {
-	struct of_device *op = chip->op;
+	struct platform_device *op = chip->op;
 
 	if (chip->c_dma.ebus_info.regs) {
 		ebus_dma_unregister(&chip->c_dma.ebus_info);
@@ -1960,7 +1960,7 @@
 };
 
 static int __devinit snd_cs4231_ebus_create(struct snd_card *card,
-					    struct of_device *op,
+					    struct platform_device *op,
 					    int dev)
 {
 	struct snd_cs4231 *chip = card->private_data;
@@ -2048,7 +2048,7 @@
 	return 0;
 }
 
-static int __devinit cs4231_ebus_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit cs4231_ebus_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	struct snd_card *card;
 	int err;
@@ -2072,7 +2072,7 @@
 }
 #endif
 
-static int __devinit cs4231_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit cs4231_probe(struct platform_device *op, const struct of_device_id *match)
 {
 #ifdef EBUS_SUPPORT
 	if (!strcmp(op->dev.of_node->parent->name, "ebus"))
@@ -2086,7 +2086,7 @@
 	return -ENODEV;
 }
 
-static int __devexit cs4231_remove(struct of_device *op)
+static int __devexit cs4231_remove(struct platform_device *op)
 {
 	struct snd_cs4231 *chip = dev_get_drvdata(&op->dev);
 
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c
index c421901..39cd5d6 100644
--- a/sound/sparc/dbri.c
+++ b/sound/sparc/dbri.c
@@ -299,7 +299,7 @@
 /* This structure holds the information for both chips (DBRI & CS4215) */
 struct snd_dbri {
 	int regs_size, irq;	/* Needed for unload */
-	struct of_device *op;	/* OF device info */
+	struct platform_device *op;	/* OF device info */
 	spinlock_t lock;
 
 	struct dbri_dma *dma;	/* Pointer to our DMA block */
@@ -2523,7 +2523,7 @@
 static void snd_dbri_free(struct snd_dbri *dbri);
 
 static int __devinit snd_dbri_create(struct snd_card *card,
-				     struct of_device *op,
+				     struct platform_device *op,
 				     int irq, int dev)
 {
 	struct snd_dbri *dbri = card->private_data;
@@ -2592,7 +2592,7 @@
 				  (void *)dbri->dma, dbri->dma_dvma);
 }
 
-static int __devinit dbri_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit dbri_probe(struct platform_device *op, const struct of_device_id *match)
 {
 	struct snd_dbri *dbri;
 	struct resource *rp;
@@ -2662,7 +2662,7 @@
 	return err;
 }
 
-static int __devexit dbri_remove(struct of_device *op)
+static int __devexit dbri_remove(struct platform_device *op)
 {
 	struct snd_card *card = dev_get_drvdata(&op->dev);