Merge "msm: rpm: RPM stubs to return success on 8064" into msm-3.0
diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt
new file mode 100644
index 0000000..9b4b82a
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/gic.txt
@@ -0,0 +1,59 @@
+* ARM Generic Interrupt Controller
+
+ARM SMP cores are often associated with a GIC, providing per processor
+interrupts (PPI), shared processor interrupts (SPI) and software
+generated interrupts (SGI).
+
+Primary GIC is attached directly to the CPU and typically has PPIs and SGIs.
+Secondary GICs are cascaded into the upward interrupt controller and do not
+have PPIs or SGIs.
+
+Main node required properties:
+
+- compatible : should be one of:
+	"arm,cortex-a9-gic"
+	"arm,arm11mp-gic"
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source.  The type shall be a <u32> and the value shall be 3.
+
+  The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI
+  interrupts.
+
+  The 2nd cell contains the interrupt number for the interrupt type.
+  SPI interrupts are in the range [0-987].  PPI interrupts are in the
+  range [0-15].
+
+  The 3rd cell is the flags, encoded as follows:
+	bits[3:0] trigger type and level flags.
+		1 = low-to-high edge triggered
+		2 = high-to-low edge triggered
+		4 = active high level-sensitive
+		8 = active low level-sensitive
+	bits[15:8] PPI interrupt cpu mask.  Each bit corresponds to each of
+	the 8 possible cpus attached to the GIC.  A bit set to '1' indicated
+	the interrupt is wired to that CPU.  Only valid for PPI interrupts.
+
+- reg : Specifies base physical address(s) and size of the GIC registers. The
+  first region is the GIC distributor register base and size. The 2nd region is
+  the GIC cpu interface register base and size.
+
+Optional
+- interrupts	: Interrupt source of the parent interrupt controller. Only
+  present on secondary GICs.
+
+- cpu-offset	: per-cpu offset within the distributor and cpu interface
+  regions, used when the GIC doesn't have banked registers. The offset is
+  cpu-offset * cpu-nr.
+
+Example:
+
+	intc: interrupt-controller@fff11000 {
+		compatible = "arm,cortex-a9-gic";
+		#interrupt-cells = <3>;
+		#address-cells = <1>;
+		interrupt-controller;
+		reg = <0xfff11000 0x1000>,
+		      <0xfff10100 0x100>;
+	};
+
diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig
index ad180b2..64877d1 100644
--- a/arch/arm/common/Kconfig
+++ b/arch/arm/common/Kconfig
@@ -1,7 +1,11 @@
 config ARM_GIC
+	select IRQ_DOMAIN
 	bool
 	select MSM_SHOW_RESUME_IRQ
 
+config GIC_NON_BANKED
+	bool
+
 config ARM_VIC
 	bool
 
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index fea7044..a6b5d0b 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -24,17 +24,58 @@
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/module.h>
 #include <linux/list.h>
 #include <linux/smp.h>
 #include <linux/cpu_pm.h>
 #include <linux/cpumask.h>
 #include <linux/io.h>
 #include <linux/syscore_ops.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/interrupt.h>
+#include <linux/percpu.h>
+#include <linux/slab.h>
 
 #include <asm/irq.h>
+#include <asm/exception.h>
 #include <asm/mach/irq.h>
 #include <asm/hardware/gic.h>
 #include <asm/system.h>
+#include <asm/localtimer.h>
+
+union gic_base {
+	void __iomem *common_base;
+	void __percpu __iomem **percpu_base;
+};
+
+struct gic_chip_data {
+	unsigned int irq_offset;
+	union gic_base dist_base;
+	union gic_base cpu_base;
+	unsigned int max_irq;
+#ifdef CONFIG_PM
+	unsigned int wakeup_irqs[32];
+	unsigned int enabled_irqs[32];
+#endif
+#ifdef CONFIG_CPU_PM
+	u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)];
+	u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)];
+	u32 saved_spi_target[DIV_ROUND_UP(1020, 4)];
+	u32 __percpu *saved_ppi_enable;
+	u32 __percpu *saved_ppi_conf;
+#endif
+#ifdef CONFIG_IRQ_DOMAIN
+	struct irq_domain domain;
+#endif
+	unsigned int gic_irqs;
+#ifdef CONFIG_GIC_NON_BANKED
+	void __iomem *(*get_base)(union gic_base *);
+#endif
+};
 
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
 
@@ -61,22 +102,53 @@
 
 static struct gic_chip_data gic_data[MAX_GIC_NR] __read_mostly;
 
+#ifdef CONFIG_GIC_NON_BANKED
+static void __iomem *gic_get_percpu_base(union gic_base *base)
+{
+	return *__this_cpu_ptr(base->percpu_base);
+}
+
+static void __iomem *gic_get_common_base(union gic_base *base)
+{
+	return base->common_base;
+}
+
+static inline void __iomem *gic_data_dist_base(struct gic_chip_data *data)
+{
+	return data->get_base(&data->dist_base);
+}
+
+static inline void __iomem *gic_data_cpu_base(struct gic_chip_data *data)
+{
+	return data->get_base(&data->cpu_base);
+}
+
+static inline void gic_set_base_accessor(struct gic_chip_data *data,
+					 void __iomem *(*f)(union gic_base *))
+{
+	data->get_base = f;
+}
+#else
+#define gic_data_dist_base(d)	((d)->dist_base.common_base)
+#define gic_data_cpu_base(d)	((d)->cpu_base.common_base)
+#define gic_set_base_accessor(d,f)
+#endif
+
 static inline void __iomem *gic_dist_base(struct irq_data *d)
 {
 	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
-	return gic_data->dist_base;
+	return gic_data_dist_base(gic_data);
 }
 
 static inline void __iomem *gic_cpu_base(struct irq_data *d)
 {
 	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
-	return gic_data->cpu_base;
+	return gic_data_cpu_base(gic_data);
 }
 
 static inline unsigned int gic_irq(struct irq_data *d)
 {
-	struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
-	return d->irq - gic_data->irq_offset;
+	return d->hwirq;
 }
 
 /*
@@ -84,7 +156,7 @@
  */
 static void gic_mask_irq(struct irq_data *d)
 {
-	u32 mask = 1 << (d->irq % 32);
+	u32 mask = 1 << (gic_irq(d) % 32);
 
 	raw_spin_lock(&irq_controller_lock);
 	writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4);
@@ -95,7 +167,7 @@
 
 static void gic_unmask_irq(struct irq_data *d)
 {
-	u32 mask = 1 << (d->irq % 32);
+	u32 mask = 1 << (gic_irq(d) % 32);
 
 	raw_spin_lock(&irq_controller_lock);
 	if (gic_arch_extn.irq_unmask)
@@ -114,7 +186,7 @@
 static int gic_suspend_one(struct gic_chip_data *gic)
 {
 	unsigned int i;
-	void __iomem *base = gic->dist_base;
+	void __iomem *base = gic_data_dist_base(gic);
 
 	for (i = 0; i * 32 < gic->max_irq; i++) {
 		gic->enabled_irqs[i]
@@ -144,7 +216,7 @@
 	unsigned int i;
 	u32 enabled;
 	unsigned long pending[32];
-	void __iomem *base = gic->dist_base;
+	void __iomem *base = gic_data_dist_base(gic);
 
 	if (!msm_show_resume_irq_mask)
 		return;
@@ -168,7 +240,7 @@
 static void gic_resume_one(struct gic_chip_data *gic)
 {
 	unsigned int i;
-	void __iomem *base = gic->dist_base;
+	void __iomem *base = gic_data_dist_base(gic);
 
 	gic_show_resume_irq(gic);
 	for (i = 0; i * 32 < gic->max_irq; i++) {
@@ -275,7 +347,7 @@
 			    bool force)
 {
 	void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3);
-	unsigned int shift = (d->irq % 4) * 8;
+	unsigned int shift = (gic_irq(d) % 4) * 8;
 	unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
 	u32 val, mask, bit;
 
@@ -326,6 +398,32 @@
 }
 #endif
 
+asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
+{
+	u32 irqstat, irqnr;
+	struct gic_chip_data *gic = &gic_data[0];
+	void __iomem *cpu_base = gic_data_cpu_base(gic);
+
+	do {
+		irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
+		irqnr = irqstat & ~0x1c00;
+
+		if (likely(irqnr > 15 && irqnr < 1021)) {
+			irqnr = irq_domain_to_irq(&gic->domain, irqnr);
+			handle_IRQ(irqnr, regs);
+			continue;
+		}
+		if (irqnr < 16) {
+			writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
+#ifdef CONFIG_SMP
+			handle_IPI(irqnr, regs);
+#endif
+			continue;
+		}
+		break;
+	} while (1);
+}
+
 static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
 {
 	struct gic_chip_data *chip_data = irq_get_handler_data(irq);
@@ -336,14 +434,14 @@
 	chained_irq_enter(chip, desc);
 
 	raw_spin_lock(&irq_controller_lock);
-	status = readl_relaxed(chip_data->cpu_base + GIC_CPU_INTACK);
+	status = readl_relaxed(gic_data_cpu_base(chip_data) + GIC_CPU_INTACK);
 	raw_spin_unlock(&irq_controller_lock);
 
 	gic_irq = (status & 0x3ff);
 	if (gic_irq == 1023)
 		goto out;
 
-	cascade_irq = gic_irq + chip_data->irq_offset;
+	cascade_irq = irq_domain_to_irq(&chip_data->domain, gic_irq);
 	if (unlikely(gic_irq < 32 || gic_irq > 1020 || cascade_irq >= NR_IRQS))
 		do_bad_IRQ(cascade_irq, desc);
 	else
@@ -376,12 +474,13 @@
 	irq_set_chained_handler(irq, gic_handle_cascade_irq);
 }
 
-static void __init gic_dist_init(struct gic_chip_data *gic,
-	unsigned int irq_start)
+static void __init gic_dist_init(struct gic_chip_data *gic)
 {
-	unsigned int gic_irqs, irq_limit, i;
+	unsigned int i, irq;
 	u32 cpumask;
-	void __iomem *base = gic->dist_base;
+	unsigned int gic_irqs = gic->gic_irqs;
+	struct irq_domain *domain = &gic->domain;
+	void __iomem *base = gic_data_dist_base(gic);
 	u32 cpu = 0;
 
 #ifdef CONFIG_SMP
@@ -395,17 +494,6 @@
 	writel_relaxed(0, base + GIC_DIST_CTRL);
 
 	/*
-	 * Find out how many interrupts are supported.
-	 * The GIC only supports up to 1020 interrupt sources.
-	 */
-	gic_irqs = readl_relaxed(base + GIC_DIST_CTR) & 0x1f;
-	gic_irqs = (gic_irqs + 1) * 32;
-	if (gic_irqs > 1020)
-		gic_irqs = 1020;
-
-	gic->gic_irqs = gic_irqs;
-
-	/*
 	 * Set all global interrupts to be level triggered, active low.
 	 */
 	for (i = 32; i < gic_irqs; i += 16)
@@ -431,19 +519,20 @@
 		writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
 
 	/*
-	 * Limit number of interrupts registered to the platform maximum
-	 */
-	irq_limit = gic->irq_offset + gic_irqs;
-	if (WARN_ON(irq_limit > NR_IRQS))
-		irq_limit = NR_IRQS;
-
-	/*
 	 * Setup the Linux IRQ subsystem.
 	 */
-	for (i = irq_start; i < irq_limit; i++) {
-		irq_set_chip_and_handler(i, &gic_chip, handle_fasteoi_irq);
-		irq_set_chip_data(i, gic);
-		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+	irq_domain_for_each_irq(domain, i, irq) {
+		if (i < 32) {
+			irq_set_percpu_devid(irq);
+			irq_set_chip_and_handler(irq, &gic_chip,
+						 handle_percpu_devid_irq);
+			set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
+		} else {
+			irq_set_chip_and_handler(irq, &gic_chip,
+						 handle_fasteoi_irq);
+			set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+		}
+		irq_set_chip_data(irq, gic);
 	}
 
 	gic->max_irq = gic_irqs;
@@ -454,8 +543,8 @@
 
 static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
 {
-	void __iomem *dist_base = gic->dist_base;
-	void __iomem *base = gic->cpu_base;
+	void __iomem *dist_base = gic_data_dist_base(gic);
+	void __iomem *base = gic_data_cpu_base(gic);
 	int i;
 
 	/*
@@ -493,7 +582,7 @@
 		BUG();
 
 	gic_irqs = gic_data[gic_nr].gic_irqs;
-	dist_base = gic_data[gic_nr].dist_base;
+	dist_base = gic_data_dist_base(&gic_data[gic_nr]);
 
 	if (!dist_base)
 		return;
@@ -528,7 +617,7 @@
 		BUG();
 
 	gic_irqs = gic_data[gic_nr].gic_irqs;
-	dist_base = gic_data[gic_nr].dist_base;
+	dist_base = gic_data_dist_base(&gic_data[gic_nr]);
 
 	if (!dist_base)
 		return;
@@ -564,8 +653,8 @@
 	if (gic_nr >= MAX_GIC_NR)
 		BUG();
 
-	dist_base = gic_data[gic_nr].dist_base;
-	cpu_base = gic_data[gic_nr].cpu_base;
+	dist_base = gic_data_dist_base(&gic_data[gic_nr]);
+	cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);
 
 	if (!dist_base || !cpu_base)
 		return;
@@ -590,8 +679,8 @@
 	if (gic_nr >= MAX_GIC_NR)
 		BUG();
 
-	dist_base = gic_data[gic_nr].dist_base;
-	cpu_base = gic_data[gic_nr].cpu_base;
+	dist_base = gic_data_dist_base(&gic_data[gic_nr]);
+	cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);
 
 	if (!dist_base || !cpu_base)
 		return;
@@ -616,6 +705,11 @@
 	int i;
 
 	for (i = 0; i < MAX_GIC_NR; i++) {
+#ifdef CONFIG_GIC_NON_BANKED
+		/* Skip over unused GICs */
+		if (!gic_data[i].get_base)
+			continue;
+#endif
 		switch (cmd) {
 		case CPU_PM_ENTER:
 			gic_cpu_save(i);
@@ -659,23 +753,114 @@
 }
 #endif
 
-void __init gic_init(unsigned int gic_nr, unsigned int irq_start,
-	void __iomem *dist_base, void __iomem *cpu_base)
+#ifdef CONFIG_OF
+static int gic_irq_domain_dt_translate(struct irq_domain *d,
+				       struct device_node *controller,
+				       const u32 *intspec, unsigned int intsize,
+				       unsigned long *out_hwirq, unsigned int *out_type)
+{
+	if (d->of_node != controller)
+		return -EINVAL;
+	if (intsize < 3)
+		return -EINVAL;
+
+	/* Get the interrupt number and add 16 to skip over SGIs */
+	*out_hwirq = intspec[1] + 16;
+
+	/* For SPIs, we need to add 16 more to get the GIC irq ID number */
+	if (!intspec[0])
+		*out_hwirq += 16;
+
+	*out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
+	return 0;
+}
+#endif
+
+const struct irq_domain_ops gic_irq_domain_ops = {
+#ifdef CONFIG_OF
+	.dt_translate = gic_irq_domain_dt_translate,
+#endif
+};
+
+void __init gic_init_bases(unsigned int gic_nr, int irq_start,
+			   void __iomem *dist_base, void __iomem *cpu_base,
+			   u32 percpu_offset)
 {
 	struct gic_chip_data *gic;
+	struct irq_domain *domain;
+	int gic_irqs;
 
 	BUG_ON(gic_nr >= MAX_GIC_NR);
 
 	gic = &gic_data[gic_nr];
-	gic->dist_base = dist_base;
-	gic->cpu_base = cpu_base;
-	gic->irq_offset = (irq_start - 1) & ~31;
+	domain = &gic->domain;
+#ifdef CONFIG_GIC_NON_BANKED
+	if (percpu_offset) { /* Frankein-GIC without banked registers... */
+		unsigned int cpu;
 
-	if (gic_nr == 0)
+		gic->dist_base.percpu_base = alloc_percpu(void __iomem *);
+		gic->cpu_base.percpu_base = alloc_percpu(void __iomem *);
+		if (WARN_ON(!gic->dist_base.percpu_base ||
+			    !gic->cpu_base.percpu_base)) {
+			free_percpu(gic->dist_base.percpu_base);
+			free_percpu(gic->cpu_base.percpu_base);
+			return;
+		}
+
+		for_each_possible_cpu(cpu) {
+			unsigned long offset = percpu_offset * cpu_logical_map(cpu);
+			*per_cpu_ptr(gic->dist_base.percpu_base, cpu) = dist_base + offset;
+			*per_cpu_ptr(gic->cpu_base.percpu_base, cpu) = cpu_base + offset;
+		}
+
+		gic_set_base_accessor(gic, gic_get_percpu_base);
+	} else
+#endif
+	{			/* Normal, sane GIC... */
+		WARN(percpu_offset,
+		     "GIC_NON_BANKED not enabled, ignoring %08x offset!",
+		     percpu_offset);
+		gic->dist_base.common_base = dist_base;
+		gic->cpu_base.common_base = cpu_base;
+		gic_set_base_accessor(gic, gic_get_common_base);
+	}
+
+	/*
+	 * For primary GICs, skip over SGIs.
+	 * For secondary GICs, skip over PPIs, too.
+	 */
+	if (gic_nr == 0) {
 		gic_cpu_base_addr = cpu_base;
+		domain->hwirq_base = 16;
+		if (irq_start > 0)
+			irq_start = (irq_start & ~31) + 16;
+	} else
+		domain->hwirq_base = 32;
+
+	/*
+	 * Find out how many interrupts are supported.
+	 * The GIC only supports up to 1020 interrupt sources.
+	 */
+	gic_irqs = readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_CTR) & 0x1f;
+	gic_irqs = (gic_irqs + 1) * 32;
+	if (gic_irqs > 1020)
+		gic_irqs = 1020;
+	gic->gic_irqs = gic_irqs;
+
+	domain->nr_irq = gic_irqs - domain->hwirq_base;
+	domain->irq_base = irq_alloc_descs(irq_start, 16, domain->nr_irq,
+					   numa_node_id());
+	if (IS_ERR_VALUE(domain->irq_base)) {
+		WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
+		     irq_start);
+		domain->irq_base = irq_start;
+	}
+	domain->priv = gic;
+	domain->ops = &gic_irq_domain_ops;
+	irq_domain_add(domain);
 
 	gic_chip.flags |= gic_arch_extn.flags;
-	gic_dist_init(gic, irq_start);
+	gic_dist_init(gic);
 	gic_cpu_init(gic);
 	gic_pm_init(gic);
 }
@@ -687,16 +872,6 @@
 	gic_cpu_init(&gic_data[gic_nr]);
 }
 
-void __cpuinit gic_enable_ppi(unsigned int irq)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-	irq_set_status_flags(irq, IRQ_NOPROBE);
-	gic_unmask_irq(irq_get_irq_data(irq));
-	local_irq_restore(flags);
-}
-
 #ifdef CONFIG_SMP
 void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 {
@@ -714,7 +889,7 @@
 	dsb();
 
 	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT);
+	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
 	mb();
 }
 #endif
@@ -759,3 +934,38 @@
 			GIC_DIST_PENDING_CLEAR + (gic_irq(d) / 32) * 4);
 	raw_spin_unlock(&irq_controller_lock);
 }
+#ifdef CONFIG_OF
+static int gic_cnt __initdata = 0;
+
+int __init gic_of_init(struct device_node *node, struct device_node *parent)
+{
+	void __iomem *cpu_base;
+	void __iomem *dist_base;
+	u32 percpu_offset;
+	int irq;
+	struct irq_domain *domain = &gic_data[gic_cnt].domain;
+
+	if (WARN_ON(!node))
+		return -ENODEV;
+
+	dist_base = of_iomap(node, 0);
+	WARN(!dist_base, "unable to map gic dist registers\n");
+
+	cpu_base = of_iomap(node, 1);
+	WARN(!cpu_base, "unable to map gic cpu registers\n");
+
+	if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
+		percpu_offset = 0;
+
+	domain->of_node = of_node_get(node);
+
+	gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset);
+
+	if (parent) {
+		irq = irq_of_parse_and_map(node, 0);
+		gic_cascade_irq(gic_cnt, irq);
+	}
+	gic_cnt++;
+	return 0;
+}
+#endif
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
index 4d4c27f..1379334 100644
--- a/arch/arm/configs/msm-copper_defconfig
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -32,19 +32,19 @@
 CONFIG_ARCH_MSMCOPPER=y
 CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
 # CONFIG_MSM_STACKED_MEMORY is not set
-CONFIG_DEBUG_MSMCOPPER_UART=y
 CONFIG_CPU_HAS_L2_PMU=y
-# CONFIG_MSM_JTAG_V7 is not set
 # CONFIG_MSM_FIQ_SUPPORT is not set
 # CONFIG_MSM_PROC_COMM is not set
 # CONFIG_MSM_DALRPC is not set
 # CONFIG_MSM_HW3D is not set
 CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+# CONFIG_MSM_JTAG_V7 is not set
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
 # CONFIG_SMP_ON_UP is not set
 CONFIG_ARM_ARCH_TIMER=y
+CONFIG_HOTPLUG_CPU=y
 CONFIG_PREEMPT=y
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
@@ -56,7 +56,6 @@
 CONFIG_NEON=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 # CONFIG_SUSPEND is not set
-CONFIG_HOTPLUG_CPU=y
 CONFIG_NET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
@@ -111,7 +110,6 @@
 CONFIG_MMC_MSM=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
-# CONFIG_LEDS_MSM_PMIC is not set
 CONFIG_SWITCH=y
 CONFIG_STAGING=y
 CONFIG_ANDROID=y
@@ -133,6 +131,7 @@
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ASCII=y
 CONFIG_NLS_ISO8859_1=y
diff --git a/arch/arm/configs/msm7627-perf_defconfig b/arch/arm/configs/msm7627-perf_defconfig
index 0f2ffc1..ea5c7c9 100644
--- a/arch/arm/configs/msm7627-perf_defconfig
+++ b/arch/arm/configs/msm7627-perf_defconfig
@@ -110,6 +110,8 @@
 CONFIG_NETFILTER_XT_MATCH_POLICY=y
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
 CONFIG_NETFILTER_XT_MATCH_STATE=y
 CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
 CONFIG_NETFILTER_XT_MATCH_STRING=y
@@ -151,6 +153,8 @@
 # CONFIG_WIRELESS_EXT_SYSFS is not set
 CONFIG_RFKILL=y
 # CONFIG_RFKILL_PM is not set
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
 CONFIG_MTD=y
 CONFIG_MTD_TESTS=m
 CONFIG_MTD_CMDLINE_PARTS=y
diff --git a/arch/arm/configs/msm7627_defconfig b/arch/arm/configs/msm7627_defconfig
index d1d0e66..0841f7e 100644
--- a/arch/arm/configs/msm7627_defconfig
+++ b/arch/arm/configs/msm7627_defconfig
@@ -110,6 +110,8 @@
 CONFIG_NETFILTER_XT_MATCH_POLICY=y
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
 CONFIG_NETFILTER_XT_MATCH_STATE=y
 CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
 CONFIG_NETFILTER_XT_MATCH_STRING=y
@@ -151,6 +153,8 @@
 # CONFIG_WIRELESS_EXT_SYSFS is not set
 CONFIG_RFKILL=y
 # CONFIG_RFKILL_PM is not set
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
 CONFIG_MTD=y
 CONFIG_MTD_TESTS=m
 CONFIG_MTD_CMDLINE_PARTS=y
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index 45b6e60..ca974b2 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -124,6 +124,8 @@
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
 CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
 CONFIG_NETFILTER_XT_MATCH_SOCKET=y
 CONFIG_NETFILTER_XT_MATCH_STATE=y
 CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
@@ -249,6 +251,7 @@
 CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_SOC=y
+CONFIG_HID_APPLE=y
 CONFIG_HID_MAGICMOUSE=y
 CONFIG_HID_MICROSOFT=y
 CONFIG_USB=y
@@ -305,6 +308,7 @@
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_YAFFS_FS=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index 7e91971..eb9cd7c 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -122,6 +122,8 @@
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
 CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
 CONFIG_NETFILTER_XT_MATCH_SOCKET=y
 CONFIG_NETFILTER_XT_MATCH_STATE=y
 CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
@@ -248,6 +250,7 @@
 CONFIG_SND=y
 CONFIG_SND_SOC=y
 CONFIG_SND_MSM_SOC=y
+CONFIG_HID_APPLE=y
 CONFIG_HID_MAGICMOUSE=y
 CONFIG_HID_MICROSOFT=y
 CONFIG_USB=y
@@ -300,6 +303,7 @@
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_YAFFS_FS=y
diff --git a/arch/arm/configs/msm7630-perf_defconfig b/arch/arm/configs/msm7630-perf_defconfig
index e5fec35..e319f0d 100644
--- a/arch/arm/configs/msm7630-perf_defconfig
+++ b/arch/arm/configs/msm7630-perf_defconfig
@@ -120,6 +120,8 @@
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
 CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
 CONFIG_NETFILTER_XT_MATCH_SOCKET=y
 CONFIG_NETFILTER_XT_MATCH_STATE=y
 CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
@@ -352,6 +354,7 @@
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_YAFFS_FS=y
diff --git a/arch/arm/configs/msm7630_defconfig b/arch/arm/configs/msm7630_defconfig
index 6e3290b..388bb69 100644
--- a/arch/arm/configs/msm7630_defconfig
+++ b/arch/arm/configs/msm7630_defconfig
@@ -119,6 +119,8 @@
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
 CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
 CONFIG_NETFILTER_XT_MATCH_SOCKET=y
 CONFIG_NETFILTER_XT_MATCH_STATE=y
 CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
@@ -337,6 +339,7 @@
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_YAFFS_FS=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index 3346397..84cd633 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -62,7 +62,9 @@
 CONFIG_MSM_RMT_STORAGE_CLIENT=y
 CONFIG_MSM_SDIO_SMEM=y
 # CONFIG_MSM_HW3D is not set
+CONFIG_MSM_PIL_MODEM=y
 CONFIG_MSM_PIL_QDSP6V3=y
+CONFIG_MSM_PIL_TZAPPS=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_MSM_RPM_LOG=y
 CONFIG_MSM_RPM_STATS_LOG=y
@@ -156,6 +158,8 @@
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
 CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
 CONFIG_NETFILTER_XT_MATCH_SOCKET=y
 CONFIG_NETFILTER_XT_MATCH_STATE=y
 CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
@@ -418,6 +422,7 @@
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_POSIX_ACL=y
 CONFIG_EXT4_FS_SECURITY=y
+CONFIG_FUSE_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_NFS_FS=y
@@ -441,3 +446,6 @@
 CONFIG_DEBUG_USER=y
 CONFIG_CRYPTO_SHA256=y
 CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=m
+CONFIG_CRYPTO_DEV_QCEDEV=m
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index 654edb53..3763bc1 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -54,7 +54,9 @@
 # CONFIG_MSM_RPCSERVER_HANDSET is not set
 CONFIG_MSM_RMT_STORAGE_CLIENT=y
 # CONFIG_MSM_HW3D is not set
+CONFIG_MSM_PIL_MODEM=y
 CONFIG_MSM_PIL_QDSP6V3=y
+CONFIG_MSM_PIL_TZAPPS=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_MSM_RPM_LOG=y
 CONFIG_MSM_RPM_STATS_LOG=y
@@ -146,6 +148,8 @@
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
 CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
 CONFIG_NETFILTER_XT_MATCH_SOCKET=y
 CONFIG_NETFILTER_XT_MATCH_STATE=y
 CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
@@ -403,6 +407,7 @@
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_POSIX_ACL=y
 CONFIG_EXT4_FS_SECURITY=y
+CONFIG_FUSE_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_NFS_FS=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
new file mode 100644
index 0000000..9feca99
--- /dev/null
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -0,0 +1,432 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+# CONFIG_FAIR_GROUP_SCHED is not set
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_KALLSYMS_ALL=y
+CONFIG_ASHMEM=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSM8960=y
+CONFIG_ARCH_MSM8930=y
+CONFIG_ARCH_APQ8064=y
+CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y
+CONFIG_MACH_MSM8960_SIM=y
+CONFIG_MACH_MSM8960_RUMI3=y
+CONFIG_MACH_MSM8960_CDP=y
+CONFIG_MACH_MSM8960_MTP=y
+CONFIG_MACH_MSM8960_FLUID=y
+CONFIG_MACH_MSM8960_LIQUID=y
+CONFIG_MACH_MSM8930_CDP=y
+CONFIG_MACH_MSM8930_MTP=y
+CONFIG_MACH_MSM8930_FLUID=y
+CONFIG_MACH_MSM8627_CDP=y
+CONFIG_MACH_MSM8627_MTP=y
+CONFIG_MACH_APQ8064_SIM=y
+CONFIG_MACH_APQ8064_RUMI3=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_KERNEL_PMEM_EBI_REGION=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_BAM_DMUX=y
+CONFIG_MSM_DSPS=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+# CONFIG_MSM_HW3D is not set
+CONFIG_MSM_PIL_QDSP6V4=y
+CONFIG_MSM_PIL_RIVA=y
+CONFIG_MSM_PIL_TZAPPS=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_MODEM_8960=y
+CONFIG_MSM_LPASS_8960=y
+CONFIG_MSM_WCNSS_SSR_8960=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_MSM_RPM_LOG=y
+CONFIG_MSM_RPM_STATS_LOG=y
+CONFIG_MSM_BUS_SCALING=y
+CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED=y
+CONFIG_MSM_WATCHDOG=y
+CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_QDSS=y
+CONFIG_MSM_SLEEP_STATS=y
+CONFIG_STRICT_MEMORY_RWX=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+# CONFIG_SMP_ON_UP is not set
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_VMALLOC_RESERVE=0x19000000
+CONFIG_CC_STACKPROTECTOR=y
+CONFIG_CP_ACCESS=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_WAKELOCK=y
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_LOG=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCISMD=y
+CONFIG_CFG80211=y
+# CONFIG_CFG80211_WEXT is not set
+CONFIG_RFKILL=y
+CONFIG_GENLOCK=y
+CONFIG_GENLOCK_MISCDEVICE=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_HAPTIC_ISA1200=y
+CONFIG_PMIC8XXX_VIBRATOR=y
+CONFIG_TZCOM=y
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_NET_ETHERNET=y
+CONFIG_SMC91X=y
+CONFIG_SMC911X=y
+CONFIG_SMSC911X=y
+CONFIG_KS8851=m
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+CONFIG_WCNSS_CORE=y
+CONFIG_USB_USBNET=y
+CONFIG_MSM_RMNET_USB=y
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_MSM_RMNET is not set
+CONFIG_MSM_RMNET_BAM=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_KEYBOARD_PMIC8XXX=y
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_CYTTSP_I2C=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_PMIC8XXX_PWRKEY=y
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_HS=y
+# CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_DIAG_CHAR=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_MSM is not set
+CONFIG_I2C_QUP=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_SLIMBUS_MSM_CTRL=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_SX150X=y
+CONFIG_POWER_SUPPLY=y
+# CONFIG_BATTERY_MSM is not set
+CONFIG_ISL9519_CHARGER=y
+CONFIG_PM8921_CHARGER=y
+CONFIG_PM8921_BMS=y
+CONFIG_SENSORS_PM8XXX_ADC=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_TSENS8960=y
+CONFIG_THERMAL_PM8XXX=y
+CONFIG_MFD_PM8921_CORE=y
+CONFIG_MFD_PM8821_CORE=y
+CONFIG_MFD_PM8038_CORE=y
+CONFIG_MFD_PM8XXX_BATT_ALARM=y
+CONFIG_WCD9310_CODEC=y
+CONFIG_REGULATOR_PM8XXX=y
+CONFIG_REGULATOR_GPIO=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+CONFIG_USB_VIDEO_CLASS=y
+CONFIG_MSM_CAMERA_V4L2=y
+CONFIG_MT9M114=y
+CONFIG_MSM_CAMERA_FLASH_SC628A=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_ACTUATOR=y
+CONFIG_MSM_GEMINI=y
+CONFIG_RADIO_IRIS=y
+CONFIG_RADIO_IRIS_TRANSPORT=m
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_MSM_KGSL=y
+CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y
+CONFIG_FB=y
+CONFIG_FB_VIRTUAL=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_TRIPLE_BUFFER=y
+CONFIG_FB_MSM_MDP40=y
+CONFIG_FB_MSM_OVERLAY=y
+CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y
+CONFIG_FB_MSM_MIPI_PANEL_DETECT=y
+CONFIG_FB_MSM_HDMI_MSM_PANEL=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_DYNAMIC_MINORS=y
+# CONFIG_SND_ARM is not set
+# CONFIG_SND_SPI is not set
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_MSM8960=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_EHSET=y
+CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_EHCI_MSM_HSIC=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DEBUG=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_QUALCOMM=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_USB_QCOM_DIAG_BRIDGE=y
+CONFIG_USB_QCOM_MDM_BRIDGE=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_CI13XXX_MSM=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_USB_ANDROID_RMNET_CTRL_SMD=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_MSM=y
+CONFIG_MMC_MSM_CARD_HW_DETECTION=y
+CONFIG_MMC_MSM_SDC1_8_BIT_SUPPORT=y
+# CONFIG_MMC_MSM_SDC2_SUPPORT is not set
+CONFIG_MMC_MSM_SDC3_SUPPORT=y
+CONFIG_MMC_MSM_SDC3_WP_SUPPORT=y
+CONFIG_MMC_MSM_SPS_SUPPORT=y
+CONFIG_LEDS_PM8XXX=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_SWITCH=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_MSM is not set
+CONFIG_RTC_DRV_PM8XXX=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_MSM_SSBI=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_BAMDMA=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_CIFS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=m
+CONFIG_CRYPTO_DEV_QCEDEV=m
+CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 2abe7e9..bb81a33 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -61,6 +61,8 @@
 CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
 # CONFIG_MSM_HW3D is not set
 CONFIG_MSM_PIL_QDSP6V4=y
+CONFIG_MSM_PIL_RIVA=y
+CONFIG_MSM_PIL_TZAPPS=y
 CONFIG_MSM_SUBSYSTEM_RESTART=y
 CONFIG_MSM_MODEM_8960=y
 CONFIG_MSM_LPASS_8960=y
@@ -83,6 +85,7 @@
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
 CONFIG_VMALLOC_RESERVE=0x19000000
+CONFIG_CC_STACKPROTECTOR=y
 CONFIG_CP_ACCESS=y
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
@@ -156,6 +159,8 @@
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
 CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
 CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
 CONFIG_NETFILTER_XT_MATCH_SOCKET=y
 CONFIG_NETFILTER_XT_MATCH_STATE=y
 CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
@@ -236,6 +241,7 @@
 # CONFIG_NETDEV_10000 is not set
 CONFIG_WCNSS_CORE=y
 CONFIG_USB_USBNET=y
+CONFIG_MSM_RMNET_USB=y
 CONFIG_SLIP=y
 CONFIG_SLIP_COMPRESSED=y
 CONFIG_SLIP_MODE_SLIP6=y
@@ -284,6 +290,7 @@
 CONFIG_MFD_PM8038_CORE=y
 CONFIG_MFD_PM8XXX_BATT_ALARM=y
 CONFIG_WCD9310_CODEC=y
+CONFIG_REGULATOR_PM8XXX=y
 CONFIG_REGULATOR_GPIO=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_VIDEO_DEV=y
@@ -322,6 +329,7 @@
 CONFIG_SND_USB_AUDIO=y
 CONFIG_SND_SOC=y
 CONFIG_SND_SOC_MSM8960=y
+CONFIG_HID_APPLE=y
 CONFIG_HID_MAGICMOUSE=y
 CONFIG_HID_MICROSOFT=y
 CONFIG_USB=y
@@ -392,6 +400,7 @@
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_NFS_FS=y
@@ -410,7 +419,8 @@
 CONFIG_LOCKUP_DETECTOR=y
 # CONFIG_SCHED_DEBUG is not set
 CONFIG_TIMER_STATS=y
-CONFIG_SLUB_DEBUG_ON=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
 # CONFIG_DEBUG_PREEMPT is not set
 CONFIG_DEBUG_SPINLOCK=y
 CONFIG_DEBUG_MUTEXES=y
@@ -418,6 +428,11 @@
 CONFIG_DEBUG_INFO=y
 CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_DEBUG_LIST=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAILSLAB=y
+CONFIG_FAIL_PAGE_ALLOC=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
 CONFIG_DEBUG_PAGEALLOC=y
 CONFIG_ENABLE_DEFAULT_TRACERS=y
 CONFIG_DYNAMIC_DEBUG=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index ed9a45b..31bde4d 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -139,7 +139,7 @@
 CONFIG_THERMAL=y
 CONFIG_THERMAL_TSENS8960=y
 CONFIG_MFD_PM8018_CORE=y
-CONFIG_REGULATOR=y
+CONFIG_REGULATOR_PM8XXX=y
 CONFIG_REGULATOR_GPIO=y
 # CONFIG_HID_SUPPORT is not set
 CONFIG_USB=y
diff --git a/arch/arm/include/asm/entry-macro-multi.S b/arch/arm/include/asm/entry-macro-multi.S
index 2f1e209..88d6181 100644
--- a/arch/arm/include/asm/entry-macro-multi.S
+++ b/arch/arm/include/asm/entry-macro-multi.S
@@ -25,13 +25,6 @@
 	movne	r1, sp
 	adrne	lr, BSYM(1b)
 	bne	do_IPI
-
-#ifdef CONFIG_LOCAL_TIMERS
-	test_for_ltirq r0, r2, r6, lr
-	movne	r0, sp
-	adrne	lr, BSYM(1b)
-	bne	do_local_timer
-#endif
 #endif
 9997:
 	.endm
diff --git a/arch/arm/include/asm/exception.h b/arch/arm/include/asm/exception.h
new file mode 100644
index 0000000..5abaf5b
--- /dev/null
+++ b/arch/arm/include/asm/exception.h
@@ -0,0 +1,19 @@
+/*
+ * Annotations for marking C functions as exception handlers.
+ *
+ * These should only be used for C functions that are called from the low
+ * level exception entry code and not any intervening C code.
+ */
+#ifndef __ASM_ARM_EXCEPTION_H
+#define __ASM_ARM_EXCEPTION_H
+
+#include <linux/ftrace.h>
+
+#define __exception	__attribute__((section(".exception.text")))
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+#define __exception_irq_entry	__irq_entry
+#else
+#define __exception_irq_entry	__exception
+#endif
+
+#endif /* __ASM_ARM_EXCEPTION_H */
diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h
index 41c8c06..bb0d03d 100644
--- a/arch/arm/include/asm/hardirq.h
+++ b/arch/arm/include/asm/hardirq.h
@@ -9,9 +9,6 @@
 
 typedef struct {
 	unsigned int __softirq_pending;
-#ifdef CONFIG_LOCAL_TIMERS
-	unsigned int local_timer_irqs;
-#endif
 #ifdef CONFIG_SMP
 	unsigned int ipi_irqs[NR_IPI];
 #endif
diff --git a/arch/arm/include/asm/hardware/entry-macro-gic.S b/arch/arm/include/asm/hardware/entry-macro-gic.S
index c115b82..74ebc80 100644
--- a/arch/arm/include/asm/hardware/entry-macro-gic.S
+++ b/arch/arm/include/asm/hardware/entry-macro-gic.S
@@ -22,15 +22,11 @@
  * interrupt controller spec.  To wit:
  *
  * Interrupts 0-15 are IPI
- * 16-28 are reserved
- * 29-31 are local.  We allow 30 to be used for the watchdog.
+ * 16-31 are local.  We allow 30 to be used for the watchdog.
  * 32-1020 are global
  * 1021-1022 are reserved
  * 1023 is "spurious" (no interrupt)
  *
- * For now, we ignore all local interrupts so only return an interrupt if it's
- * between 30 and 1020.  The test_for_ipi routine below will pick up on IPIs.
- *
  * A simple read from the controller will tell us the number of the highest
  * priority enabled interrupt.  We then just need to check whether it is in the
  * valid range for an IRQ (30-1020 inclusive).
@@ -43,7 +39,7 @@
 
 	ldr	\tmp, =1021
 	bic     \irqnr, \irqstat, #0x1c00
-	cmp     \irqnr, #29
+	cmp     \irqnr, #15
 	cmpcc	\irqnr, \irqnr
 	cmpne	\irqnr, \tmp
 	cmpcs	\irqnr, \irqnr
@@ -62,14 +58,3 @@
 	strcc	\irqstat, [\base, #GIC_CPU_EOI]
 	cmpcs	\irqnr, \irqnr
 	.endm
-
-/* As above, this assumes that irqstat and base are preserved.. */
-
-	.macro test_for_ltirq, irqnr, irqstat, base, tmp
-	bic	\irqnr, \irqstat, #0x1c00
-	mov 	\tmp, #0
-	cmp	\irqnr, #29
-	moveq	\tmp, #1
-	streq	\irqstat, [\base, #GIC_CPU_EOI]
-	cmp	\tmp, #0
-	.endm
diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h
index 9491ab3..8bfbcfa 100644
--- a/arch/arm/include/asm/hardware/gic.h
+++ b/arch/arm/include/asm/hardware/gic.h
@@ -33,35 +33,29 @@
 #define GIC_DIST_SOFTINT		0xf00
 
 #ifndef __ASSEMBLY__
+#include <linux/irqdomain.h>
+struct device_node;
+
 extern void __iomem *gic_cpu_base_addr;
 extern struct irq_chip gic_arch_extn;
 
-void gic_init(unsigned int, unsigned int, void __iomem *, void __iomem *);
+void gic_init_bases(unsigned int, int, void __iomem *, void __iomem *,
+		    u32 offset);
+int gic_of_init(struct device_node *node, struct device_node *parent);
 void gic_secondary_init(unsigned int);
+void gic_handle_irq(struct pt_regs *regs);
 void gic_cascade_irq(unsigned int gic_nr, unsigned int irq);
 void gic_raise_softirq(const struct cpumask *mask, unsigned int irq);
 void gic_enable_ppi(unsigned int);
 bool gic_is_spi_pending(unsigned int irq);
 void gic_clear_spi_pending(unsigned int irq);
 
-struct gic_chip_data {
-	unsigned int irq_offset;
-	void __iomem *dist_base;
-	void __iomem *cpu_base;
-	unsigned int max_irq;
-#ifdef CONFIG_PM
-	unsigned int wakeup_irqs[32];
-	unsigned int enabled_irqs[32];
-#endif
-#ifdef CONFIG_CPU_PM
-	u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)];
-	u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)];
-	u32 saved_spi_target[DIV_ROUND_UP(1020, 4)];
-	u32 __percpu *saved_ppi_enable;
-	u32 __percpu *saved_ppi_conf;
-#endif
-	unsigned int gic_irqs;
-};
+static inline void gic_init(unsigned int nr, int start,
+			    void __iomem *dist , void __iomem *cpu)
+{
+	gic_init_bases(nr, start, dist, cpu, 0);
+}
+
 #endif
 
 #endif
diff --git a/arch/arm/include/asm/localtimer.h b/arch/arm/include/asm/localtimer.h
index 080d74f..f5e1cec 100644
--- a/arch/arm/include/asm/localtimer.h
+++ b/arch/arm/include/asm/localtimer.h
@@ -10,6 +10,8 @@
 #ifndef __ASM_ARM_LOCALTIMER_H
 #define __ASM_ARM_LOCALTIMER_H
 
+#include <linux/interrupt.h>
+
 struct clock_event_device;
 
 /*
@@ -17,27 +19,20 @@
  */
 void percpu_timer_setup(void);
 
-/*
- * Called from assembly, this is the local timer IRQ handler
- */
-asmlinkage void do_local_timer(struct pt_regs *);
-
-
 #ifdef CONFIG_LOCAL_TIMERS
 
 #ifdef CONFIG_HAVE_ARM_TWD
 
 #include "smp_twd.h"
 
-#define local_timer_ack()	twd_timer_ack()
+#define local_timer_stop(c)	twd_timer_stop((c))
 
 #else
 
 /*
- * Platform provides this to acknowledge a local timer IRQ.
- * Returns true if the local timer IRQ is to be processed.
+ * Stop the local timer
  */
-int local_timer_ack(void);
+void local_timer_stop(struct clock_event_device *);
 
 #endif
 
@@ -52,6 +47,10 @@
 {
 	return -ENXIO;
 }
+
+static inline void local_timer_stop(struct clock_event_device *evt)
+{
+}
 #endif
 
 #endif
diff --git a/arch/arm/include/asm/mach/mmc.h b/arch/arm/include/asm/mach/mmc.h
index c86fad9..75ec143 100644
--- a/arch/arm/include/asm/mach/mmc.h
+++ b/arch/arm/include/asm/mach/mmc.h
@@ -130,6 +130,8 @@
 	void (*sdio_lpm_gpio_setup)(struct device *, unsigned int);
         unsigned int status_irq;
 	unsigned int status_gpio;
+	/* Indicates the polarity of the GPIO line when card is inserted */
+	bool is_status_gpio_active_low;
         unsigned int sdiowakeup_irq;
         unsigned long irq_flags;
         unsigned long mmc_bus_width;
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 8145184..f5a72b0 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -99,11 +99,5 @@
 extern void arch_send_call_function_single_ipi(int cpu);
 extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
 
-/*
- * show local interrupt info
- */
-extern void show_local_irqs(struct seq_file *, int);
-
 extern void smp_send_all_cpu_backtrace(void);
-
 #endif /* ifndef __ASM_ARM_SMP_H */
diff --git a/arch/arm/include/asm/smp_twd.h b/arch/arm/include/asm/smp_twd.h
index fed9981..ef9ffba9 100644
--- a/arch/arm/include/asm/smp_twd.h
+++ b/arch/arm/include/asm/smp_twd.h
@@ -22,7 +22,7 @@
 
 extern void __iomem *twd_base;
 
-int twd_timer_ack(void);
 void twd_timer_setup(struct clock_event_device *);
+void twd_timer_stop(struct clock_event_device *);
 
 #endif
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index d3808b5..4dccb04 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -62,13 +62,6 @@
 
 #include <asm/outercache.h>
 
-#define __exception	__attribute__((section(".exception.text")))
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
-#define __exception_irq_entry	__irq_entry
-#else
-#define __exception_irq_entry	__exception
-#endif
-
 void cpu_idle_wait(void);
 
 struct thread_info;
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index 0cd27bc..5070470 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -25,7 +25,6 @@
 #include <asm/sched_clock.h>
 #include <asm/hardware/gic.h>
 
-static struct irqaction arch_irqaction[2];
 static unsigned long arch_timer_rate;
 static int arch_timer_ppi;
 static int arch_timer_ppi2;
@@ -151,9 +150,9 @@
 	clockevents_config_and_register(clk, arch_timer_rate,
 					0xf, 0x7fffffff);
 
-	gic_enable_ppi(arch_timer_ppi);
+	enable_percpu_irq(arch_timer_ppi, 0);
 	if (arch_timer_ppi2 > 0)
-		gic_enable_ppi(arch_timer_ppi2);
+		enable_percpu_irq(arch_timer_ppi2, 0);
 }
 
 /* Is the optional system timer available? */
@@ -256,11 +255,9 @@
 	struct clock_event_device *clk = data;
 	pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n",
 		 clk->irq, smp_processor_id());
-	if (!smp_processor_id()) {
-		remove_irq(arch_timer_ppi, &arch_irqaction[0]);
-		if (arch_timer_ppi2 > 0)
-			remove_irq(arch_timer_ppi2, &arch_irqaction[1]);
-	}
+	disable_percpu_irq(arch_timer_ppi);
+	if (arch_timer_ppi2 > 0)
+		disable_percpu_irq(arch_timer_ppi2);
 	arch_timer_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
 }
 
@@ -291,8 +288,6 @@
 
 int __init arch_timer_register(struct resource *res, int res_nr)
 {
-	struct irqaction *irqa;
-	unsigned int cpu = smp_processor_id();
 	int err;
 
 	if (!res_nr || res[0].start < 0 || !(res[0].flags & IORESOURCE_IRQ))
@@ -319,34 +314,24 @@
 	set_delay_fn(read_current_timer_delay_loop);
 #endif
 
-	irqa = &arch_irqaction[0];
-	irqa->name = "arch_sys_timer";
-	irqa->flags = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_HIGH;
-	irqa->handler = arch_timer_handler;
-	irqa->dev_id = per_cpu_ptr(arch_timer_evt, cpu);
-	irqa->irq = arch_timer_ppi;
-	err = setup_irq(arch_timer_ppi, irqa);
+	err = request_percpu_irq(arch_timer_ppi, arch_timer_handler,
+				"arch_sys_timer", arch_timer_evt);
 	if (err) {
 		pr_err("%s: can't register interrupt %d (%d)\n",
-		       irqa->name, irqa->irq, err);
+		       "arch_sys_timer", arch_timer_ppi, err);
 		return err;
 	}
 
 	if (arch_timer_ppi2 > 0) {
-		irqa = &arch_irqaction[1];
-		irqa->name = "arch_sys_timer";
-		irqa->flags = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_HIGH;
-		irqa->handler = arch_timer_handler;
-		irqa->dev_id = per_cpu_ptr(arch_timer_evt, cpu);
-		irqa->irq = arch_timer_ppi2;
-		err = setup_irq(arch_timer_ppi2, irqa);
+		err = request_percpu_irq(arch_timer_ppi2, arch_timer_handler,
+					"arch_sys_timer", arch_timer_evt);
 		if (err)
 			pr_warn("%s: can't register interrupt %d (%d)\n",
-				irqa->name, irqa->irq, err);
+				"arch_sys_timer", arch_timer_ppi2, err);
 	}
 
 	/* Immediately configure the timer on the boot CPU */
-	arch_timer_setup(per_cpu_ptr(arch_timer_evt, cpu));
+	arch_timer_setup(per_cpu_ptr(arch_timer_evt, smp_processor_id()));
 
 	register_cpu_notifier(&arch_timer_cpu_nb);
 
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index 5bd484f..44681532 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -35,8 +35,8 @@
 #include <linux/list.h>
 #include <linux/kallsyms.h>
 #include <linux/proc_fs.h>
-#include <linux/ftrace.h>
 
+#include <asm/exception.h>
 #include <asm/system.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/irq.h>
@@ -61,9 +61,6 @@
 #ifdef CONFIG_SMP
 	show_ipi_list(p, prec);
 #endif
-#ifdef CONFIG_LOCAL_TIMERS
-	show_local_irqs(p, prec);
-#endif
 	seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count);
 	return 0;
 }
@@ -114,7 +111,7 @@
 {
 	unsigned long clr = 0, set = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
 
-	if (irq >= nr_irqs) {
+	if (irq >= NR_IRQS) {
 		printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq);
 		return;
 	}
diff --git a/arch/arm/kernel/perf_event_msm.c b/arch/arm/kernel/perf_event_msm.c
index 8fa2f30..e37d2a7 100644
--- a/arch/arm/kernel/perf_event_msm.c
+++ b/arch/arm/kernel/perf_event_msm.c
@@ -474,24 +474,31 @@
 {
 	u32 venum_new_val;
 	u32 fp_new_val;
+	u32 v_orig_val;
+	u32 f_orig_val;
 
-	/* CPACR Enable CP10 access*/
-	venum_orig_val = get_copro_access();
-	venum_new_val = venum_orig_val | CPACC_SVC(10);
+	/* CPACR Enable CP10 access */
+	v_orig_val = get_copro_access();
+	venum_new_val = v_orig_val | CPACC_SVC(10);
 	set_copro_access(venum_new_val);
+	/* Store orig venum val */
+	__get_cpu_var(venum_orig_val) = v_orig_val;
+
 	/* Enable FPEXC */
-	fp_orig_val = fmrx(FPEXC);
-	fp_new_val = fp_orig_val | FPEXC_EN;
+	f_orig_val = fmrx(FPEXC);
+	fp_new_val = f_orig_val | FPEXC_EN;
 	fmxr(FPEXC, fp_new_val);
+	/* Store orig fp val */
+	__get_cpu_var(fp_orig_val) = f_orig_val;
 }
 
 static void scorpion_post_vlpm(void)
 {
-	/* Restore FPEXC*/
-	fmxr(FPEXC, fp_orig_val);
+	/* Restore FPEXC */
+	fmxr(FPEXC, __get_cpu_var(fp_orig_val));
 	isb();
-	/* Restore CPACR*/
-	set_copro_access(venum_orig_val);
+	/* Restore CPACR */
+	set_copro_access(__get_cpu_var(venum_orig_val));
 }
 
 struct scorpion_access_funcs {
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 9fe0964..0faa7ea 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -16,7 +16,6 @@
 #include <linux/cache.h>
 #include <linux/profile.h>
 #include <linux/errno.h>
-#include <linux/ftrace.h>
 #include <linux/mm.h>
 #include <linux/err.h>
 #include <linux/cpu.h>
@@ -31,6 +30,8 @@
 #include <asm/cacheflush.h>
 #include <asm/cpu.h>
 #include <asm/cputype.h>
+#include <asm/exception.h>
+#include <asm/topology.h>
 #include <asm/mmu_context.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -449,10 +450,6 @@
 	for (i = 0; i < NR_IPI; i++)
 		sum += __get_irq_stat(cpu, ipi_irqs[i]);
 
-#ifdef CONFIG_LOCAL_TIMERS
-	sum += __get_irq_stat(cpu, local_timer_irqs);
-#endif
-
 	return sum;
 }
 
@@ -469,33 +466,6 @@
 	irq_exit();
 }
 
-#ifdef CONFIG_LOCAL_TIMERS
-asmlinkage void __exception_irq_entry do_local_timer(struct pt_regs *regs)
-{
-	struct pt_regs *old_regs = set_irq_regs(regs);
-	int cpu = smp_processor_id();
-
-	if (local_timer_ack()) {
-		__inc_irq_stat(cpu, local_timer_irqs);
-		ipi_timer();
-	}
-
-	set_irq_regs(old_regs);
-}
-
-void show_local_irqs(struct seq_file *p, int prec)
-{
-	unsigned int cpu;
-
-	seq_printf(p, "%*s: ", prec, "LOC");
-
-	for_each_present_cpu(cpu)
-		seq_printf(p, "%10u ", __get_irq_stat(cpu, local_timer_irqs));
-
-	seq_printf(p, " Local timer interrupts\n");
-}
-#endif
-
 #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
 static void smp_timer_broadcast(const struct cpumask *mask)
 {
@@ -546,7 +516,7 @@
 	unsigned int cpu = smp_processor_id();
 	struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
 
-	evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
+	local_timer_stop(evt);
 }
 #endif
 
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index f62743c..d4c8c36 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -19,6 +19,7 @@
 #include <linux/io.h>
 
 #include <asm/smp_twd.h>
+#include <asm/localtimer.h>
 #include <asm/hardware/gic.h>
 
 /* set up by the platform code */
@@ -26,6 +27,8 @@
 
 static unsigned long twd_timer_rate;
 
+static struct clock_event_device __percpu **twd_evt;
+
 static void twd_set_mode(enum clock_event_mode mode,
 			struct clock_event_device *clk)
 {
@@ -80,6 +83,12 @@
 	return 0;
 }
 
+void twd_timer_stop(struct clock_event_device *clk)
+{
+	twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
+	disable_percpu_irq(clk->irq);
+}
+
 static void __cpuinit twd_calibrate_rate(void)
 {
 	unsigned long count;
@@ -119,11 +128,43 @@
 	}
 }
 
+static irqreturn_t twd_handler(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
+
+	if (twd_timer_ack()) {
+		evt->event_handler(evt);
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
 /*
  * Setup the local clock events for a CPU.
  */
 void __cpuinit twd_timer_setup(struct clock_event_device *clk)
 {
+	struct clock_event_device **this_cpu_clk;
+
+	if (!twd_evt) {
+		int err;
+
+		twd_evt = alloc_percpu(struct clock_event_device *);
+		if (!twd_evt) {
+			pr_err("twd: can't allocate memory\n");
+			return;
+		}
+
+		err = request_percpu_irq(clk->irq, twd_handler,
+					 "twd", twd_evt);
+		if (err) {
+			pr_err("twd: can't register interrupt %d (%d)\n",
+			       clk->irq, err);
+			return;
+		}
+	}
+
 	twd_calibrate_rate();
 
 	clk->name = "local_timer";
@@ -136,8 +177,10 @@
 	clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk);
 	clk->min_delta_ns = clockevent_delta2ns(0xf, clk);
 
-	/* Make sure our local interrupt controller has this enabled */
-	gic_enable_ppi(clk->irq);
+	this_cpu_clk = __this_cpu_ptr(twd_evt);
+	*this_cpu_clk = clk;
 
 	clockevents_register_device(clk);
+
+	enable_percpu_irq(clk->irq, 0);
 }
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index ef37557..76f86d7 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -28,6 +28,7 @@
 
 #include <asm/atomic.h>
 #include <asm/cacheflush.h>
+#include <asm/exception.h>
 #include <asm/system.h>
 #include <asm/unistd.h>
 #include <asm/traps.h>
diff --git a/arch/arm/mach-exynos4/include/mach/entry-macro.S b/arch/arm/mach-exynos4/include/mach/entry-macro.S
index d8f38c2..9be072f 100644
--- a/arch/arm/mach-exynos4/include/mach/entry-macro.S
+++ b/arch/arm/mach-exynos4/include/mach/entry-macro.S
@@ -50,7 +50,7 @@
 
 		bic     \irqnr, \irqstat, #0x1c00
 
-		cmp     \irqnr, #29
+		cmp     \irqnr, #15
 		cmpcc	\irqnr, \irqnr
 		cmpne	\irqnr, \tmp
 		cmpcs	\irqnr, \irqnr
@@ -71,14 +71,3 @@
 		strcc	\irqstat, [\base, #GIC_CPU_EOI]
 		cmpcs	\irqnr, \irqnr
 		.endm
-
-		/* As above, this assumes that irqstat and base are preserved.. */
-
-		.macro test_for_ltirq, irqnr, irqstat, base, tmp
-		bic	\irqnr, \irqstat, #0x1c00
-		mov	\tmp, #0
-		cmp	\irqnr, #29
-		moveq	\tmp, #1
-		streq	\irqstat, [\base, #GIC_CPU_EOI]
-		cmp	\tmp, #0
-		.endm
diff --git a/arch/arm/mach-exynos4/mct.c b/arch/arm/mach-exynos4/mct.c
index 14ac10b..09fea21 100644
--- a/arch/arm/mach-exynos4/mct.c
+++ b/arch/arm/mach-exynos4/mct.c
@@ -380,11 +380,13 @@
 
 	if (cpu == 0) {
 		mct_tick0_event_irq.dev_id = &mct_tick[cpu];
+		evt->irq = IRQ_MCT_L0;
 		setup_irq(IRQ_MCT_L0, &mct_tick0_event_irq);
 	} else {
 		mct_tick1_event_irq.dev_id = &mct_tick[cpu];
-		irq_set_affinity(IRQ_MCT1, cpumask_of(1));
+		evt->irq = IRQ_MCT_L1;
 		setup_irq(IRQ_MCT_L1, &mct_tick1_event_irq);
+		irq_set_affinity(IRQ_MCT1, cpumask_of(1));
 	}
 }
 
@@ -394,9 +396,10 @@
 	exynos4_mct_tick_init(evt);
 }
 
-int local_timer_ack(void)
+void local_timer_stop(struct clock_event_device *evt)
 {
-	return 0;
+	evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
+	disable_irq(evt->irq);
 }
 
 #endif /* CONFIG_LOCAL_TIMERS */
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index a0cf8ca..2c4edb8 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -75,9 +75,9 @@
 	select ARCH_REQUIRE_GPIOLIB
 	select MSM_ADM3
 	select REGULATOR
+	select MSM_RPM_REGULATOR
 	select MSM_V2_TLMM
 	select MSM_PIL
-	select MSM_SCM
 	select ARCH_HAS_CPU_IDLE_WAIT
 	select MSM_DIRECT_SCLK_ACCESS
 	select MSM_RPM
@@ -117,6 +117,8 @@
 	select ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE
 	select CPU_HAS_L2_PMU
 	select MSM_SPM_V1
+	select MSM_SCM if SMP
+	select MULTI_IRQ_HANDLER
 
 config ARCH_MSM8960
 	bool "MSM8960"
@@ -128,6 +130,7 @@
 	select MSM_SCM if SMP
 	select MSM_DIRECT_SCLK_ACCESS
 	select REGULATOR
+	select MSM_RPM_REGULATOR
 	select MSM_RPM
 	select MSM_XO
 	select MSM_QDSP6_APR
@@ -153,6 +156,8 @@
 	select FIX_MOVABLE_ZONE
 	select CLEANCACHE
 	select QCACHE
+	select MSM_MULTIMEDIA_USE_ION
+	select MULTI_IRQ_HANDLER
 
 config ARCH_MSM8930
 	bool "MSM8930"
@@ -187,6 +192,7 @@
 	select ARCH_MEMORY_REMOVE
 	select FIX_MOVABLE_ZONE
 	select MSM_ULTRASOUND
+	select MULTI_IRQ_HANDLER
 
 config ARCH_APQ8064
 	bool "APQ8064"
@@ -201,6 +207,7 @@
 	select MSM_PIL
 	select MSM_QDSP6_APR
 	select MSM_AUDIO_QDSP6 if SND_SOC
+	select MULTI_IRQ_HANDLER
 
 config ARCH_MSMCOPPER
 	bool "MSM Copper"
@@ -210,6 +217,7 @@
 	select CPU_V7
 	select MSM_SCM if SMP
 	select MSM_GPIOMUX
+	select MULTI_IRQ_HANDLER
 
 config ARCH_FSM9XXX
 	bool "FSM9XXX"
@@ -218,6 +226,8 @@
 	select CPU_V7
 	select MSM_REMOTE_SPINLOCK_LDREX
 	select FSM9XXX_TLMM
+	select MULTI_IRQ_HANDLER
+	select MSM_DALRPC
 
 config ARCH_MSM9615
 	bool "MSM9615"
@@ -229,6 +239,10 @@
 	select MSM_RPM
 	select MSM_SPM_V2
 	select MSM_NATIVE_RESTART
+	select REGULATOR
+	select MSM_RPM_REGULATOR
+	select MULTI_IRQ_HANDLER
+
 endmenu
 
 choice
@@ -279,8 +293,10 @@
 	bool
 
 config  ARCH_MSM_CORTEX_A5
-	bool
+	select PERF_EVENTS
+	select HAVE_HW_BREAKPOINT
 	select HAVE_HW_BRKPT_RESERVED_RW_ACCESS
+	bool
 
 config ARCH_MSM7X27A
 	bool
@@ -1296,8 +1312,7 @@
 
 config MSM_DALRPC
 	bool "DAL RPC support"
-	depends on ARCH_MSM_SCORPION || ARCH_MSM_KRAIT
-	default y
+	default n
 	help
 	  Supports RPC calls to DAL devices on remote processor cores.
 
@@ -1571,6 +1586,14 @@
 	  for idle power collapse, wait the number of microseconds in case
 	  Modem becomes ready soon.
 
+config MSM_RPM_REGULATOR
+	bool "RPM regulator driver"
+	depends on MSM_RPM && REGULATOR
+	help
+	  Compile in support for the RPM regulator driver, used for setting
+	  voltages and other parameters of the various power rails supplied
+	  by some Qualcomm PMICs.
+
 config MSM_PIL
 	bool "Peripheral image loading"
 	select FW_LOADER
@@ -1582,6 +1605,12 @@
 
 	  Say yes to support these devices.
 
+config MSM_PIL_MODEM
+	tristate "Modem (ARM11) Boot Support"
+	depends on MSM_PIL
+	help
+	  Support for booting and shutting down ARM11 Modem processors.
+
 config MSM_PIL_QDSP6V3
 	tristate "QDSP6v3 (Hexagon) Boot Support"
 	depends on MSM_PIL
@@ -1597,6 +1626,24 @@
 	  The QDSP6 is a low power DSP used in audio, modem firmware, and modem
 	  software applications.
 
+config MSM_PIL_RIVA
+	tristate "RIVA (WCNSS) Boot Support"
+	depends on MSM_PIL
+	help
+	  Support for booting and shutting down the RIVA processor (WCNSS).
+	  Riva is the wireless subsystem processor used in bluetooth, wireless
+	  LAN, and FM software applications.
+
+config MSM_PIL_TZAPPS
+	tristate "TZApps Boot Support"
+	depends on MSM_PIL
+	help
+	  Support for booting and shutting down TZApps.
+
+	  TZApps is an image that runs in the secure processor state. It is
+	  used to decrypt data and perform secure operations on the behalf of
+	  the kernel.
+
 config MSM_SCM
 	bool "Secure Channel Manager (SCM) support"
 	default n
@@ -1833,7 +1880,8 @@
 
 config MSM_SHOW_RESUME_IRQ
 	bool "Enable logging of interrupts that could have caused resume"
-	depends on (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_MSMCOPPER)
+	depends on (ARM_GIC || PMIC8058)
+	default y if PMIC8058
 	default n
 	help
 		This option logs wake up interrupts that have triggered just before
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index ee15313..95f2535 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -39,6 +39,7 @@
 endif
 
 obj-$(CONFIG_SMP) += headsmp.o platsmp.o
+obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
 
 obj-$(CONFIG_MSM_CPU_AVS) += avs.o
 obj-$(CONFIG_MSM_AVS_HW) += avs_hw.o
@@ -73,6 +74,9 @@
 endif
 obj-$(CONFIG_MSM_PIL_QDSP6V3) += pil-q6v3.o
 obj-$(CONFIG_MSM_PIL_QDSP6V4) += pil-q6v4.o
+obj-$(CONFIG_MSM_PIL_RIVA) += pil-riva.o
+obj-$(CONFIG_MSM_PIL_TZAPPS) += pil-tzapps.o
+obj-$(CONFIG_MSM_PIL_MODEM) += pil-modem.o
 obj-$(CONFIG_ARCH_QSD8X50) += sirc.o
 obj-$(CONFIG_ARCH_FSM9XXX) += sirc-fsm9xxx.o
 obj-$(CONFIG_MSM_FIQ_SUPPORT) += fiq_glue.o
@@ -154,7 +158,7 @@
 	obj-$(CONFIG_ARCH_MSM7X01A) += pm.o
 	obj-y += pm-boot.o
 else
-	obj-y += no-pm.o hotplug.o
+	obj-y += no-pm.o
 endif
 
 obj-$(CONFIG_MSM_SPM_V1) += spm.o
@@ -174,9 +178,15 @@
 obj-$(CONFIG_ARCH_MSM8X60) += devices-msm8x60.o clock-local.o clock-8x60.o acpuclock-8x60.o
 obj-$(CONFIG_ARCH_MSM8X60) += clock-rpm.o
 obj-$(CONFIG_ARCH_MSM8X60) += saw-regulator.o
-obj-$(CONFIG_ARCH_MSM8X60) += rpm-regulator.o rpm-regulator-8660.o
 obj-$(CONFIG_ARCH_MSM8X60) += footswitch-8x60.o
 
+ifdef CONFIG_MSM_RPM_REGULATOR
+obj-y += rpm-regulator.o
+obj-$(CONFIG_ARCH_MSM8X60) += rpm-regulator-8660.o
+obj-$(CONFIG_ARCH_MSM8960) += rpm-regulator-8960.o
+obj-$(CONFIG_ARCH_MSM9615) += rpm-regulator-9615.o
+endif
+
 ifdef CONFIG_MSM_SUBSYSTEM_RESTART
 	obj-y += subsystem_notif.o
 	obj-y += subsystem_restart.o
@@ -215,10 +225,10 @@
 obj-$(CONFIG_MACH_MSM7X27_SURF) += board-msm7x27.o devices-msm7x27.o
 obj-$(CONFIG_MACH_MSM7X27_FFA) += board-msm7x27.o devices-msm7x27.o
 obj-$(CONFIG_ARCH_MSM7X27A) += clock-pcom-lookup.o devices-msm7x27a.o
-obj-$(CONFIG_MACH_MSM7X27A_RUMI3) += board-msm7x27a.o board-msm7627a-storage.o
-obj-$(CONFIG_MACH_MSM7X27A_SURF) += board-msm7x27a.o board-msm7627a-storage.o
-obj-$(CONFIG_MACH_MSM7X27A_FFA) += board-msm7x27a.o board-msm7627a-storage.o
-obj-$(CONFIG_MACH_MSM7627A_QRD1) += board-qrd7627a.o board-msm7627a-storage.o
+obj-$(CONFIG_MACH_MSM7X27A_RUMI3) += board-msm7x27a.o board-msm7627a-storage.o board-msm7627a-bt.o
+obj-$(CONFIG_MACH_MSM7X27A_SURF) += board-msm7x27a.o board-msm7627a-storage.o board-msm7627a-bt.o
+obj-$(CONFIG_MACH_MSM7X27A_FFA) += board-msm7x27a.o board-msm7627a-storage.o board-msm7627a-bt.o
+obj-$(CONFIG_MACH_MSM7627A_QRD1) += board-qrd7627a.o board-msm7627a-storage.o board-msm7627a-bt.o
 obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30.o devices-msm7x30.o memory_topology.o
 obj-$(CONFIG_ARCH_MSM7X30) += clock-local.o clock-7x30.o acpuclock-7x30.o
 obj-$(CONFIG_MACH_MSM7X25_SURF) += board-msm7x27.o devices-msm7x25.o
@@ -227,7 +237,7 @@
 obj-$(CONFIG_ARCH_MSM8960) += footswitch-8x60.o
 obj-$(CONFIG_ARCH_MSM8960) += acpuclock-8960.o
 obj-$(CONFIG_ARCH_MSM8960) += memory_topology.o
-obj-$(CONFIG_ARCH_MSM8960) += saw-regulator.o rpm-regulator.o rpm-regulator-8960.o
+obj-$(CONFIG_ARCH_MSM8960) += saw-regulator.o
 obj-$(CONFIG_ARCH_MSM8960) += devices-8960.o
 obj-$(CONFIG_ARCH_APQ8064) += devices-8960.o devices-8064.o
 board-8960-all-objs += board-8960.o board-8960-camera.o board-8960-display.o board-8960-pmic.o board-8960-storage.o board-8960-gpiomux.o
@@ -238,15 +248,14 @@
 obj-$(CONFIG_MACH_MSM8960_CDP) += board-8960-all.o board-8960-regulator.o
 obj-$(CONFIG_MACH_MSM8960_MTP) += board-8960-all.o board-8960-regulator.o
 obj-$(CONFIG_MACH_MSM8960_FLUID) += board-8960-all.o board-8960-regulator.o
-obj-$(CONFIG_MACH_MSM8930_CDP) += board-8930-all.o board-8960-regulator.o
-obj-$(CONFIG_MACH_MSM8930_MTP) += board-8930-all.o board-8960-regulator.o
-obj-$(CONFIG_MACH_MSM8930_FLUID) += board-8930-all.o board-8960-regulator.o
+obj-$(CONFIG_MACH_MSM8930_CDP) += board-8930-all.o board-8930-regulator.o
+obj-$(CONFIG_MACH_MSM8930_MTP) += board-8930-all.o board-8930-regulator.o
+obj-$(CONFIG_MACH_MSM8930_FLUID) += board-8930-all.o board-8930-regulator.o
 obj-$(CONFIG_ARCH_MSM8960) += bms-batterydata.o
 obj-$(CONFIG_MACH_APQ8064_SIM) += board-8064-all.o board-8064-regulator.o
 obj-$(CONFIG_MACH_APQ8064_RUMI3) += board-8064-all.o board-8064-regulator.o
-obj-$(CONFIG_ARCH_MSM9615) += board-9615.o devices-9615.o board-9615-regulator.o
+obj-$(CONFIG_ARCH_MSM9615) += board-9615.o devices-9615.o board-9615-regulator.o board-9615-gpiomux.o board-9615-storage.o
 obj-$(CONFIG_ARCH_MSM9615) += clock-local.o clock-9615.o acpuclock-9615.o clock-rpm.o
-obj-$(CONFIG_ARCH_MSM9615) += rpm-regulator.o rpm-regulator-9615.o
 obj-$(CONFIG_ARCH_MSMCOPPER) += board-copper.o board-dt.o
 
 obj-$(CONFIG_MACH_SAPPHIRE) += board-sapphire.o board-sapphire-gpio.o
diff --git a/arch/arm/mach-msm/acpuclock-7201.c b/arch/arm/mach-msm/acpuclock-7201.c
index 0338d53..2fece29 100644
--- a/arch/arm/mach-msm/acpuclock-7201.c
+++ b/arch/arm/mach-msm/acpuclock-7201.c
@@ -2,7 +2,7 @@
  * MSM architecture clock driver
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2007-2012, Code Aurora Forum. All rights reserved.
  * Author: San Mehat <san@android.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -33,7 +33,6 @@
 #include <asm/mach-types.h>
 #include <mach/socinfo.h>
 
-#include "proc_comm.h"
 #include "smd_private.h"
 #include "acpuclock.h"
 
@@ -76,7 +75,6 @@
 	struct clkctl_acpu_speed	*current_speed;
 	struct mutex			lock;
 	uint32_t			max_speed_delta_khz;
-	unsigned long			max_axi_khz;
 	struct clk			*ebi1_clk;
 };
 
@@ -127,62 +125,6 @@
  * largest frequency jump that's less than max_speed_delta_khz on each PLL.
  */
 
-/* 7x01/7x25 normal with GSM capable modem */
-static struct clkctl_acpu_speed pll0_245_pll1_768_pll2_1056_pll4_0[] = {
-	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 30720 },
-	{ 1, 122880, ACPU_PLL_0, 4, 1,  61440, 1, 3,  61440 },
-	{ 0, 128000, ACPU_PLL_1, 1, 5,  64000, 1, 3,  61440 },
-	{ 0, 176000, ACPU_PLL_2, 2, 5,  88000, 1, 3,  61440 },
-	{ 1, 245760, ACPU_PLL_0, 4, 0,  81920, 2, 4,  61440 },
-	{ 1, 256000, ACPU_PLL_1, 1, 2, 128000, 1, 5, 128000 },
-	{ 0, 352000, ACPU_PLL_2, 2, 2,  88000, 3, 5, 128000 },
-	{ 1, 384000, ACPU_PLL_1, 1, 1, 128000, 2, 6, 128000 },
-	{ 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 7, 128000 },
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
-};
-
-/* 7x01/7x25 normal with CDMA-only modem */
-static struct clkctl_acpu_speed pll0_196_pll1_768_pll2_1056_pll4_0[] = {
-	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 24576 },
-	{ 1,  98304, ACPU_PLL_0, 4, 1,  49152, 1, 3,  24576 },
-	{ 0, 128000, ACPU_PLL_1, 1, 5,  64000, 1, 3,  24576 },
-	{ 0, 176000, ACPU_PLL_2, 2, 5,  88000, 1, 3,  24576 },
-	{ 1, 196608, ACPU_PLL_0, 4, 0,  65536, 2, 4,  24576 },
-	{ 1, 256000, ACPU_PLL_1, 1, 2, 128000, 1, 5, 128000 },
-	{ 0, 352000, ACPU_PLL_2, 2, 2,  88000, 3, 5, 128000 },
-	{ 1, 384000, ACPU_PLL_1, 1, 1, 128000, 2, 6, 128000 },
-	{ 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 7, 128000 },
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
-};
-
-/* 7x01/7x25 turbo with GSM capable modem */
-static struct clkctl_acpu_speed pll0_245_pll1_960_pll2_1056_pll4_0[] = {
-	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 30720 },
-	{ 0, 120000, ACPU_PLL_1, 1, 7,  60000, 1, 3,  61440 },
-	{ 1, 122880, ACPU_PLL_0, 4, 1,  61440, 1, 3,  61440 },
-	{ 0, 176000, ACPU_PLL_2, 2, 5,  88000, 1, 3,  61440 },
-	{ 1, 245760, ACPU_PLL_0, 4, 0,  81920, 2, 4,  61440 },
-	{ 1, 320000, ACPU_PLL_1, 1, 2, 107000, 2, 5, 120000 },
-	{ 0, 352000, ACPU_PLL_2, 2, 2,  88000, 3, 5, 120000 },
-	{ 1, 480000, ACPU_PLL_1, 1, 1, 120000, 3, 6, 120000 },
-	{ 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 7, 122880 },
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
-};
-
-/* 7x01/7x25 turbo with CDMA-only modem */
-static struct clkctl_acpu_speed pll0_196_pll1_960_pll2_1056_pll4_0[] = {
-	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 24576 },
-	{ 1,  98304, ACPU_PLL_0, 4, 1,  49152, 1, 3,  24576 },
-	{ 0, 120000, ACPU_PLL_1, 1, 7,  60000, 1, 3,  24576 },
-	{ 0, 176000, ACPU_PLL_2, 2, 5,  88000, 1, 3,  24576 },
-	{ 1, 196608, ACPU_PLL_0, 4, 0,  65536, 2, 4,  24576 },
-	{ 1, 320000, ACPU_PLL_1, 1, 2, 107000, 2, 5, 120000 },
-	{ 0, 352000, ACPU_PLL_2, 2, 2,  88000, 3, 5, 120000 },
-	{ 1, 480000, ACPU_PLL_1, 1, 1, 120000, 3, 6, 120000 },
-	{ 1, 528000, ACPU_PLL_2, 2, 1, 132000, 3, 7, 120000 },
-	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
-};
-
 /* 7x27 normal with GSM capable modem */
 static struct clkctl_acpu_speed pll0_245_pll1_960_pll2_1200_pll4_0[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 30720 },
@@ -190,10 +132,10 @@
 	{ 1, 122880, ACPU_PLL_0, 4, 1,  61440, 1, 3,  61440 },
 	{ 0, 200000, ACPU_PLL_2, 2, 5,  66667, 2, 4,  61440 },
 	{ 1, 245760, ACPU_PLL_0, 4, 0, 122880, 1, 4,  61440 },
-	{ 1, 320000, ACPU_PLL_1, 1, 2, 160000, 1, 5, 122880 },
-	{ 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 122880 },
-	{ 1, 480000, ACPU_PLL_1, 1, 1, 160000, 2, 6, 122880 },
-	{ 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 122880 },
+	{ 1, 320000, ACPU_PLL_1, 1, 2, 160000, 1, 5, 160000 },
+	{ 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 160000 },
+	{ 1, 480000, ACPU_PLL_1, 1, 1, 160000, 2, 6, 160000 },
+	{ 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 200000 },
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
@@ -204,10 +146,10 @@
 	{ 0, 120000, ACPU_PLL_1, 1, 7,  60000, 1, 3,  49152 },
 	{ 1, 196608, ACPU_PLL_0, 4, 0,  65536, 2, 4,  98304 },
 	{ 0, 200000, ACPU_PLL_2, 2, 5,  66667, 2, 4,  98304 },
-	{ 1, 320000, ACPU_PLL_1, 1, 2, 160000, 1, 5, 120000 },
-	{ 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 120000 },
-	{ 1, 480000, ACPU_PLL_1, 1, 1, 160000, 2, 6, 120000 },
-	{ 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 120000 },
+	{ 1, 320000, ACPU_PLL_1, 1, 2, 160000, 1, 5, 160000 },
+	{ 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 160000 },
+	{ 1, 480000, ACPU_PLL_1, 1, 1, 160000, 2, 6, 160000 },
+	{ 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 200000 },
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
@@ -218,10 +160,10 @@
 	{ 1, 122880, ACPU_PLL_1, 1, 1,  61440, 1, 3,  61440 },
 	{ 0, 200000, ACPU_PLL_2, 2, 5,  66667, 2, 4,  61440 },
 	{ 1, 245760, ACPU_PLL_1, 1, 0, 122880, 1, 4,  61440 },
-	{ 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 5, 122880 },
-	{ 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 122880 },
-	{ 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 122880 },
-	{ 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 122880 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 5, 160000 },
+	{ 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 160000 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 160000 },
+	{ 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 200000 },
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
@@ -232,10 +174,10 @@
 	{ 0, 120000, ACPU_PLL_0, 4, 7,  60000, 1, 3,  49152 },
 	{ 1, 196608, ACPU_PLL_1, 1, 0,  65536, 2, 4,  98304 },
 	{ 0, 200000, ACPU_PLL_2, 2, 5,  66667, 2, 4,  98304 },
-	{ 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 5, 120000 },
-	{ 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 120000 },
-	{ 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 120000 },
-	{ 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 120000 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 5, 160000 },
+	{ 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 160000 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 160000 },
+	{ 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 200000 },
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
@@ -246,10 +188,10 @@
 	{ 1, 122880, ACPU_PLL_1, 1, 1,  61440, 1, 3,  61440 },
 	{ 0, 200000, ACPU_PLL_2, 2, 3,  66667, 2, 4,  61440 },
 	{ 1, 245760, ACPU_PLL_1, 1, 0, 122880, 1, 4,  61440 },
-	{ 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 5, 122880 },
-	{ 0, 400000, ACPU_PLL_2, 2, 1, 133333, 2, 5, 122880 },
-	{ 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 122880 },
-	{ 1, 800000, ACPU_PLL_2, 2, 0, 200000, 3, 7, 122880 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 5, 160000 },
+	{ 0, 400000, ACPU_PLL_2, 2, 1, 133333, 2, 5, 160000 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 160000 },
+	{ 1, 800000, ACPU_PLL_2, 2, 0, 200000, 3, 7, 200000 },
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
@@ -260,10 +202,10 @@
 	{ 0, 120000, ACPU_PLL_0, 4, 7,  60000, 1, 3,  49152 },
 	{ 1, 196608, ACPU_PLL_1, 1, 0,  65536, 2, 4,  98304 },
 	{ 0, 200000, ACPU_PLL_2, 2, 3,  66667, 2, 4,  98304 },
-	{ 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 5, 120000 },
-	{ 0, 400000, ACPU_PLL_2, 2, 1, 133333, 2, 5, 120000 },
-	{ 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 120000 },
-	{ 1, 800000, ACPU_PLL_2, 2, 0, 200000, 3, 7, 120000 },
+	{ 1, 320000, ACPU_PLL_0, 4, 2, 160000, 1, 5, 160000 },
+	{ 0, 400000, ACPU_PLL_2, 2, 1, 133333, 2, 5, 160000 },
+	{ 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 160000 },
+	{ 1, 800000, ACPU_PLL_2, 2, 0, 200000, 3, 7, 200000 },
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
@@ -328,14 +270,14 @@
 };
 
 /* 7x25a pll2 at 1200mhz with GSM capable modem */
-static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200_pll4_800_25a[] = {
+static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200_25a[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
 	{ 0, 61440, ACPU_PLL_1, 1, 3,  7680, 3, 1,  61440 },
 	{ 1, 122880, ACPU_PLL_1, 1, 1,  15360, 3, 2,  61440 },
 	{ 1, 245760, ACPU_PLL_1, 1, 0, 30720, 3, 3,  61440 },
 	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
 	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
-	{ 0, 400000, ACPU_PLL_4, 6, 1, 50000, 3, 4, 122880 },
+	{ 0, 400000, ACPU_PLL_2, 2, 2, 50000, 3, 4, 122880 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
@@ -402,14 +344,14 @@
 };
 
 /* 7x25a pll2 at 1200mhz with GSM capable modem */
-static struct clkctl_acpu_speed pll0_960_pll1_737_pll2_1200_pll4_800_25a[] = {
+static struct clkctl_acpu_speed pll0_960_pll1_737_pll2_1200_25a[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
 	{ 0, 61440, ACPU_PLL_1, 1, 11,  7680, 3, 1,  61440 },
 	{ 1, 122880, ACPU_PLL_1, 1, 5,  15360, 3, 2,  61440 },
 	{ 1, 245760, ACPU_PLL_1, 1, 2, 30720, 3, 3,  61440 },
 	{ 0, 300000, ACPU_PLL_2, 2, 3, 37500, 3, 4, 150000 },
 	{ 1, 320000, ACPU_PLL_0, 4, 2, 40000, 3, 4, 122880 },
-	{ 0, 400000, ACPU_PLL_4, 6, 1, 50000, 3, 4, 122880 },
+	{ 0, 400000, ACPU_PLL_2, 2, 2, 50000, 3, 4, 122880 },
 	{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
 	{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
@@ -418,14 +360,11 @@
 #define PLL_0_MHZ	0
 #define PLL_196_MHZ	10
 #define PLL_245_MHZ	12
-#define PLL_491_MHZ	25
 #define PLL_589_MHZ	30
 #define PLL_737_MHZ	38
-#define PLL_768_MHZ	40
 #define PLL_800_MHZ	41
 #define PLL_960_MHZ	50
 #define PLL_1008_MHZ	52
-#define PLL_1056_MHZ	55
 #define PLL_1200_MHZ	62
 
 #define PLL_CONFIG(m0, m1, m2, m4) { \
@@ -442,10 +381,6 @@
 };
 
 static struct pll_freq_tbl_map acpu_freq_tbl_list[] = {
-	PLL_CONFIG(196, 768, 1056, 0),
-	PLL_CONFIG(245, 768, 1056, 0),
-	PLL_CONFIG(196, 960, 1056, 0),
-	PLL_CONFIG(245, 960, 1056, 0),
 	PLL_CONFIG(196, 960, 1200, 0),
 	PLL_CONFIG(245, 960, 1200, 0),
 	PLL_CONFIG(960, 196, 1200, 0),
@@ -523,30 +458,22 @@
 	if (id >= ACPU_PLL_END)
 		return -EINVAL;
 
-	if (pll_control) {
-		remote_spin_lock(&pll_lock);
-		if (on) {
-			pll_control->pll[PLL_BASE + id].votes |= 2;
-			if (!pll_control->pll[PLL_BASE + id].on) {
-				pll_enable(soc_pll[id].mod_reg, 1);
-				pll_control->pll[PLL_BASE + id].on = 1;
-			}
-		} else {
-			pll_control->pll[PLL_BASE + id].votes &= ~2;
-			if (pll_control->pll[PLL_BASE + id].on
-			    && !pll_control->pll[PLL_BASE + id].votes) {
-				pll_enable(soc_pll[id].mod_reg, 0);
-				pll_control->pll[PLL_BASE + id].on = 0;
-			}
+	remote_spin_lock(&pll_lock);
+	if (on) {
+		pll_control->pll[PLL_BASE + id].votes |= 2;
+		if (!pll_control->pll[PLL_BASE + id].on) {
+			pll_enable(soc_pll[id].mod_reg, 1);
+			pll_control->pll[PLL_BASE + id].on = 1;
 		}
-		remote_spin_unlock(&pll_lock);
 	} else {
-		res = msm_proc_comm(PCOM_CLKCTL_RPC_PLL_REQUEST, &id, &on);
-		if (res < 0)
-			return res;
-		else if ((int) id < 0)
-			return -EINVAL;
+		pll_control->pll[PLL_BASE + id].votes &= ~2;
+		if (pll_control->pll[PLL_BASE + id].on
+		    && !pll_control->pll[PLL_BASE + id].votes) {
+			pll_enable(soc_pll[id].mod_reg, 0);
+			pll_control->pll[PLL_BASE + id].on = 0;
+		}
 	}
+	remote_spin_unlock(&pll_lock);
 
 	if (on)
 		pr_debug("PLL enabled\n");
@@ -556,21 +483,16 @@
 	return res;
 }
 
-
-/*----------------------------------------------------------------------------
- * ARM11 'owned' clock control
- *---------------------------------------------------------------------------*/
-
 static int acpuclk_set_vdd_level(int vdd)
 {
 	uint32_t current_vdd;
 
 	/*
-	 * NOTE: v1.0 of 7x27a/7x25a chip doesn't have working
-	 * VDD switching support.
-	 */
+	* NOTE: v1.0 of 7x27a/7x25a chip doesn't have working
+	* VDD switching support.
+	*/
 	if ((cpu_is_msm7x27a() || cpu_is_msm7x25a()) &&
-			(SOCINFO_VERSION_MINOR(socinfo_get_version()) < 1))
+		(SOCINFO_VERSION_MINOR(socinfo_get_version()) < 1))
 		return 0;
 
 	current_vdd = readl_relaxed(A11S_VDD_SVS_PLEVEL_ADDR) & 0x07;
@@ -635,7 +557,7 @@
 	}
 }
 
-static int acpuclk_7201_set_rate(int cpu, unsigned long rate,
+static int acpuclk_7627_set_rate(int cpu, unsigned long rate,
 				 enum setrate_reason reason)
 {
 	uint32_t reg_clkctl;
@@ -712,9 +634,9 @@
 
 	while (cur_s != tgt_s) {
 		/*
-		 * Always jump to target freq if within 256mhz, regulardless of
-		 * PLL. If differnece is greater, use the predefinied
-		 * steppings in the table.
+		 * Always jump to target freq if within max_speed_delta_khz,
+		 * regardless of PLL. If differnece is greater, use the
+		 * predefined steppings in the table.
 		 */
 		int d = abs((int)(cur_s->a11clk_khz - tgt_s->a11clk_khz));
 		if (d > drv_state.max_speed_delta_khz) {
@@ -834,11 +756,6 @@
 		div = readl_relaxed(A11S_CLK_CNTL_ADDR) & 0x0f;
 	}
 
-	/* Accomodate bootloaders that might not be implementing the
-	 * workaround for the h/w bug in 7x25. */
-	if (cpu_is_msm7x25() && sel == 2)
-		sel = 3;
-
 	for (speed = acpu_freq_tbl; speed->a11clk_khz != 0; speed++) {
 		if (speed->a11clk_src_sel == sel
 		 && (speed->a11clk_src_div == div))
@@ -872,7 +789,7 @@
 	pr_info("ACPU running at %d KHz\n", speed->a11clk_khz);
 }
 
-static unsigned long acpuclk_7201_get_rate(int cpu)
+static unsigned long acpuclk_7627_get_rate(int cpu)
 {
 	WARN_ONCE(drv_state.current_speed == NULL,
 		  "%s: not initialized\n", __func__);
@@ -886,17 +803,10 @@
  * Clock driver initialization
  *---------------------------------------------------------------------------*/
 
-#define DIV2REG(n)		((n)-1)
-#define REG2DIV(n)		((n)+1)
-#define SLOWER_BY(div, factor)	div = DIV2REG(REG2DIV(div) * factor)
-
 static void __init acpu_freq_tbl_fixup(void)
 {
 	unsigned long pll0_l, pll1_l, pll2_l, pll4_l;
-	int axi_160mhz = 0, axi_200mhz = 0;
 	struct pll_freq_tbl_map *lst;
-	struct clkctl_acpu_speed *t;
-	unsigned int pll0_needs_fixup = 0;
 
 	/* Wait for the PLLs to be initialized and then read their frequency.
 	 */
@@ -934,23 +844,14 @@
 		pll4_l = 0;
 	}
 
-	/* Some configurations run PLL0 twice as fast. Instead of having
-	 * separate tables for this case, we simply fix up the ACPU clock
-	 * source divider since it's a simple fix up.
-	 */
-	if (pll0_l == PLL_491_MHZ) {
-		pll0_l = PLL_245_MHZ;
-		pll0_needs_fixup = 1;
-	}
-
 	/* Fix the tables for 7x25a variant to not conflict with 7x27 ones */
 	if (cpu_is_msm7x25a()) {
 		if (pll1_l == PLL_245_MHZ) {
 			acpu_freq_tbl =
-				pll0_960_pll1_245_pll2_1200_pll4_800_25a;
+				pll0_960_pll1_245_pll2_1200_25a;
 		} else if (pll1_l == PLL_737_MHZ) {
 			acpu_freq_tbl =
-				pll0_960_pll1_737_pll2_1200_pll4_800_25a;
+				pll0_960_pll1_737_pll2_1200_25a;
 		}
 	} else {
 		/* Select the right table to use. */
@@ -969,38 +870,11 @@
 		BUG();
 	}
 
-	/* Fix up PLL0 source divider if necessary. Also, fix up the AXI to
-	 * the max that's supported by the board (RAM used in board).
-	 */
-	axi_160mhz = (pll0_l == PLL_960_MHZ || pll1_l == PLL_960_MHZ);
-	axi_200mhz = (pll2_l == PLL_1200_MHZ || pll2_l == PLL_800_MHZ);
-	for (t = &acpu_freq_tbl[0]; t->a11clk_khz != 0; t++) {
-
-		if (pll0_needs_fixup && t->pll == ACPU_PLL_0)
-			SLOWER_BY(t->a11clk_src_div, 2);
-		if (axi_160mhz && drv_state.max_axi_khz >= 160000
-		    && t->ahbclk_khz > 128000)
-			t->axiclk_khz = 160000;
-		if (axi_200mhz && drv_state.max_axi_khz >= 200000
-		    && t->ahbclk_khz > 160000)
-			t->axiclk_khz = 200000;
-	}
-
-	t--;
-	drv_state.max_axi_khz = t->axiclk_khz;
-
 	/* The default 7x27 ACPU clock plan supports running the AXI bus at
 	 * 200 MHz. So we don't classify it as Turbo mode.
 	 */
 	if (cpu_is_msm7x27())
 		return;
-
-	if (!axi_160mhz)
-		pr_info("Turbo mode not supported.\n");
-	else if (t->axiclk_khz == 160000)
-		pr_info("Turbo mode supported and enabled.\n");
-	else
-		pr_info("Turbo mode supported but not enabled.\n");
 }
 
 /*
@@ -1102,51 +976,42 @@
 	}
 }
 
-static void msm7x25_acpu_pll_hw_bug_fix(void)
-{
-	unsigned int n;
-
-	/* The 7625 has a hardware bug and in order to select PLL2 we
-	 * must program PLL3.  Use the same table, and just fix up the
-	 * numbers on this target. */
-	for (n = 0; acpu_freq_tbl[n].a11clk_khz != 0; n++)
-		if (acpu_freq_tbl[n].pll == ACPU_PLL_2)
-			acpu_freq_tbl[n].a11clk_src_sel = 3;
-}
-
 static void shared_pll_control_init(void)
 {
 #define PLL_REMOTE_SPINLOCK_ID "S:7"
 	unsigned smem_size;
+
 	remote_spin_lock_init(&pll_lock, PLL_REMOTE_SPINLOCK_ID);
 	pll_control = smem_get_entry(SMEM_CLKREGIM_SOURCES, &smem_size);
 
-	if (!pll_control)
-		pr_warning("Can't find shared PLL control data structure!\n");
+	if (!pll_control) {
+		pr_err("Can't find shared PLL control data structure!\n");
+		BUG();
 	/* There might be more PLLs than what the application processor knows
 	 * about. But the index used for each PLL is guaranteed to remain the
 	 * same. */
-	else if (smem_size < sizeof(struct shared_pll_control))
-		pr_warning("Shared PLL control data structure too small!\n");
-	else if (pll_control->version != 0xCCEE0001)
-		pr_warning("Shared PLL control version mismatch!\n");
-	else {
+	} else if (smem_size < sizeof(struct shared_pll_control)) {
+			pr_err("Shared PLL control data"
+					"structure too small!\n");
+			BUG();
+	} else if (pll_control->version != 0xCCEE0001) {
+			pr_err("Shared PLL control version mismatch!\n");
+			BUG();
+	} else {
 		pr_info("Shared PLL control available.\n");
 		return;
 	}
 
-	pll_control = NULL;
-	pr_warning("Falling back to proc_comm PLL control.\n");
 }
 
-static struct acpuclk_data acpuclk_7201_data = {
-	.set_rate = acpuclk_7201_set_rate,
-	.get_rate = acpuclk_7201_get_rate,
+static struct acpuclk_data acpuclk_7627_data = {
+	.set_rate = acpuclk_7627_set_rate,
+	.get_rate = acpuclk_7627_get_rate,
 	.power_collapse_khz = POWER_COLLAPSE_KHZ,
 	.switch_time_us = 50,
 };
 
-static int __init acpuclk_7201_init(struct acpuclk_soc_data *soc_data)
+static int __init acpuclk_7627_init(struct acpuclk_soc_data *soc_data)
 {
 	pr_info("%s()\n", __func__);
 
@@ -1156,16 +1021,13 @@
 	mutex_init(&drv_state.lock);
 	shared_pll_control_init();
 	drv_state.max_speed_delta_khz = soc_data->max_speed_delta_khz;
-	drv_state.max_axi_khz = soc_data->max_axi_khz;
 	acpu_freq_tbl_fixup();
-	acpuclk_7201_data.wait_for_irq_khz = find_wait_for_irq_khz();
+	acpuclk_7627_data.wait_for_irq_khz = find_wait_for_irq_khz();
 	precompute_stepping();
-	if (cpu_is_msm7x25())
-		msm7x25_acpu_pll_hw_bug_fix();
 	acpuclk_hw_init();
 	lpj_init();
 	print_acpu_freq_tbl();
-	acpuclk_register(&acpuclk_7201_data);
+	acpuclk_register(&acpuclk_7627_data);
 
 #ifdef CONFIG_CPU_FREQ_MSM
 	cpufreq_table_init();
@@ -1174,26 +1036,17 @@
 	return 0;
 }
 
-struct acpuclk_soc_data acpuclk_7201_soc_data __initdata = {
-	.max_speed_delta_khz = 400000,
-	.max_axi_khz = 160000,
-	.init = acpuclk_7201_init,
-};
-
 struct acpuclk_soc_data acpuclk_7x27_soc_data __initdata = {
 	.max_speed_delta_khz = 400000,
-	.max_axi_khz = 200000,
-	.init = acpuclk_7201_init,
+	.init = acpuclk_7627_init,
 };
 
 struct acpuclk_soc_data acpuclk_7x27a_soc_data __initdata = {
 	.max_speed_delta_khz = 400000,
-	.max_axi_khz = 200000,
-	.init = acpuclk_7201_init,
+	.init = acpuclk_7627_init,
 };
 
 struct acpuclk_soc_data acpuclk_7x27aa_soc_data __initdata = {
 	.max_speed_delta_khz = 504000,
-	.max_axi_khz = 200000,
-	.init = acpuclk_7201_init,
+	.init = acpuclk_7627_init,
 };
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index c9ca339..4cf75b6 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -295,6 +295,57 @@
 		},
 };
 
+/*TODO: Update the rpm vreg id when the rpm driver is ready */
+static struct scalable scalable_8627[] = {
+	[CPU0] = {
+			.hfpll_base      = MSM_HFPLL_BASE + 0x200,
+			.aux_clk_sel     = MSM_ACC0_BASE  + 0x014,
+			.l2cpmr_iaddr    = L2CPUCPMR_IADDR,
+			.vreg[VREG_CORE] = { "krait0",     1300000 },
+			.vreg[VREG_MEM]  = { "krait0_mem", 1150000,
+					     RPM_VREG_VOTER1,
+					     RPM_VREG_ID_PM8921_L24 },
+			.vreg[VREG_DIG]  = { "krait0_dig", 1150000,
+					     RPM_VREG_VOTER1,
+					     RPM_VREG_ID_PM8921_S3 },
+			.vreg[VREG_HFPLL_A] = { "hfpll", 2100000,
+					     RPM_VREG_VOTER1,
+					     RPM_VREG_ID_PM8921_S8 },
+			.vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
+					     RPM_VREG_VOTER1,
+					     RPM_VREG_ID_PM8921_L23 },
+		},
+	[CPU1] = {
+			.hfpll_base      = MSM_HFPLL_BASE + 0x300,
+			.aux_clk_sel     = MSM_ACC1_BASE  + 0x014,
+			.l2cpmr_iaddr    = L2CPUCPMR_IADDR,
+			.vreg[VREG_CORE] = { "krait1",     1300000 },
+			.vreg[VREG_MEM]  = { "krait0_mem", 1150000,
+					     RPM_VREG_VOTER2,
+					     RPM_VREG_ID_PM8921_L24 },
+			.vreg[VREG_DIG]  = { "krait0_dig", 1150000,
+					     RPM_VREG_VOTER2,
+					     RPM_VREG_ID_PM8921_S3 },
+			.vreg[VREG_HFPLL_A] = { "hfpll", 2100000,
+					     RPM_VREG_VOTER2,
+					     RPM_VREG_ID_PM8921_S8 },
+			.vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
+					     RPM_VREG_VOTER2,
+					     RPM_VREG_ID_PM8921_L23 },
+		},
+	[L2] = {
+			.hfpll_base   = MSM_HFPLL_BASE    + 0x400,
+			.aux_clk_sel  = MSM_APCS_GCC_BASE + 0x028,
+			.l2cpmr_iaddr = L2CPMR_IADDR,
+			.vreg[VREG_HFPLL_A] = { "hfpll", 2100000,
+					     RPM_VREG_VOTER6,
+					     RPM_VREG_ID_PM8921_S8 },
+			.vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
+					     RPM_VREG_VOTER6,
+					     RPM_VREG_ID_PM8921_L23 },
+		},
+};
+
 static struct scalable *scalable;
 static struct l2_level *l2_freq_tbl;
 static struct acpu_level *acpu_freq_tbl;
@@ -422,17 +473,17 @@
 	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(11), 1062500 },
 	{ 1, {   864000, HFPLL, 1, 0, 0x20 }, L2(11), 1062500 },
 	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(11), 1087500 },
-	{ 1, {   972000, HFPLL, 1, 0, 0x24 }, L2(16), 1300000 },
-	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(16), 1300000 },
-	{ 1, {  1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1300000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1300000 },
-	{ 1, {  1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1300000 },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(16), 1300000 },
-	{ 1, {  1296000, HFPLL, 1, 0, 0x30 }, L2(16), 1300000 },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(16), 1300000 },
-	{ 1, {  1404000, HFPLL, 1, 0, 0x34 }, L2(16), 1300000 },
-	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(16), 1300000 },
-	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(16), 1300000 },
+	{ 1, {   972000, HFPLL, 1, 0, 0x24 }, L2(16), 1100000 },
+	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(16), 1100000 },
+	{ 1, {  1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1100000 },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1100000 },
+	{ 1, {  1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1125000 },
+	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(16), 1137500 },
+	{ 1, {  1296000, HFPLL, 1, 0, 0x30 }, L2(16), 1150000 },
+	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(16), 1175000 },
+	{ 1, {  1404000, HFPLL, 1, 0, 0x34 }, L2(16), 1187500 },
+	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(16), 1225000 },
+	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(16), 1250000 },
 	{ 0, { 0 } }
 };
 
@@ -449,17 +500,17 @@
 	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(11), 1012500 },
 	{ 1, {   864000, HFPLL, 1, 0, 0x20 }, L2(11), 1025000 },
 	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(11), 1025000 },
-	{ 1, {   972000, HFPLL, 1, 0, 0x24 }, L2(16), 1300000 },
-	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(16), 1300000 },
-	{ 1, {  1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1300000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1300000 },
-	{ 1, {  1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1300000 },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(16), 1300000 },
-	{ 1, {  1296000, HFPLL, 1, 0, 0x30 }, L2(16), 1300000 },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(16), 1300000 },
-	{ 1, {  1404000, HFPLL, 1, 0, 0x34 }, L2(16), 1300000 },
-	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(16), 1300000 },
-	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(16), 1300000 },
+	{ 1, {   972000, HFPLL, 1, 0, 0x24 }, L2(16), 1100000 },
+	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(16), 1100000 },
+	{ 1, {  1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1100000 },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1100000 },
+	{ 1, {  1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1125000 },
+	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(16), 1137500 },
+	{ 1, {  1296000, HFPLL, 1, 0, 0x30 }, L2(16), 1150000 },
+	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(16), 1175000 },
+	{ 1, {  1404000, HFPLL, 1, 0, 0x34 }, L2(16), 1187500 },
+	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(16), 1225000 },
+	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(16), 1250000 },
 	{ 0, { 0 } }
 };
 
@@ -557,6 +608,43 @@
 	{ 0, { 0 } }
 };
 
+/* TODO: Update vdd_dig, vdd_mem and bw when data is available. */
+#undef L2
+#define L2(x) (&l2_freq_tbl_8627[(x)])
+static struct l2_level l2_freq_tbl_8627[] = {
+	[0]  = { {STBY_KHZ, QSB,   0, 0, 0x00 }, 1050000, 1050000, 0 },
+	[1]  = { {  384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
+	[2]  = { {  432000, HFPLL, 2, 0, 0x20 }, 1050000, 1050000, 1 },
+	[3]  = { {  486000, HFPLL, 2, 0, 0x24 }, 1050000, 1050000, 1 },
+	[4]  = { {  540000, HFPLL, 2, 0, 0x28 }, 1050000, 1050000, 2 },
+	[5]  = { {  594000, HFPLL, 1, 0, 0x16 }, 1050000, 1050000, 2 },
+	[6]  = { {  648000, HFPLL, 1, 0, 0x18 }, 1050000, 1050000, 2 },
+	[7]  = { {  702000, HFPLL, 1, 0, 0x1A }, 1050000, 1050000, 3 },
+	[8]  = { {  756000, HFPLL, 1, 0, 0x1C }, 1150000, 1150000, 3 },
+	[9]  = { {  810000, HFPLL, 1, 0, 0x1E }, 1150000, 1150000, 3 },
+	[10] = { {  864000, HFPLL, 1, 0, 0x20 }, 1150000, 1150000, 4 },
+	[11] = { {  918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 4 },
+	[12] = { {  972000, HFPLL, 1, 0, 0x24 }, 1150000, 1150000, 4 },
+};
+
+/* TODO: Update core voltages when data is available. */
+static struct acpu_level acpu_freq_tbl_8627[] = {
+	{ 0, { STBY_KHZ, QSB,   0, 0, 0x00 }, L2(0),   900000 },
+	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(1),   900000 },
+	{ 1, {   432000, HFPLL, 2, 0, 0x20 }, L2(5),   925000 },
+	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(5),   925000 },
+	{ 1, {   540000, HFPLL, 2, 0, 0x28 }, L2(5),   937500 },
+	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(5),   962500 },
+	{ 1, {   648000, HFPLL, 1, 0, 0x18 }, L2(9),   987500 },
+	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(9),  1000000 },
+	{ 1, {   756000, HFPLL, 1, 0, 0x1C }, L2(9),  1025000 },
+	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(9),  1062500 },
+	{ 1, {   864000, HFPLL, 1, 0, 0x20 }, L2(12), 1062500 },
+	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(12), 1087500 },
+	{ 1, {   972000, HFPLL, 1, 0, 0x24 }, L2(12), 1100000 },
+	{ 0, { 0 } }
+};
+
 static unsigned long acpuclk_8960_get_rate(int cpu)
 {
 	return scalable[cpu].current_speed->khz;
@@ -623,7 +711,7 @@
 {
 	int rc;
 
-	if (cpu_is_msm8960() || cpu_is_msm8930()) {
+	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8627()) {
 		rc = rpm_vreg_set_voltage(sc->vreg[VREG_HFPLL_A].rpm_vreg_id,
 				sc->vreg[VREG_HFPLL_A].rpm_vreg_voter, 2100000,
 				sc->vreg[VREG_HFPLL_A].max_vdd, 0);
@@ -670,7 +758,7 @@
 	 */
 	writel_relaxed(0, sc->hfpll_base + HFPLL_MODE);
 
-	if (cpu_is_msm8960() || cpu_is_msm8930()) {
+	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm8627()) {
 		rc = rpm_vreg_set_voltage(sc->vreg[VREG_HFPLL_B].rpm_vreg_id,
 				sc->vreg[VREG_HFPLL_B].rpm_vreg_voter, 0,
 				0, 0);
@@ -1192,7 +1280,7 @@
 	case CPU_UP_PREPARE:
 	case CPU_UP_PREPARE_FROZEN:
 		if (WARN_ON(!prev_khz[cpu]))
-			prev_khz[cpu] = acpu_freq_tbl->speed.khz;
+			return NOTIFY_BAD;
 		acpuclk_8960_set_rate(cpu, prev_khz[cpu], SETRATE_HOTPLUG);
 		break;
 	case CPU_STARTING:
@@ -1266,6 +1354,11 @@
 		acpu_freq_tbl = acpu_freq_tbl_8064;
 		l2_freq_tbl = l2_freq_tbl_8064;
 		l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8064);
+	} else if (cpu_is_msm8627()) {
+		scalable = scalable_8627;
+		acpu_freq_tbl = acpu_freq_tbl_8627;
+		l2_freq_tbl = l2_freq_tbl_8627;
+		l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8627);
 	} else if (cpu_is_msm8930()) {
 		scalable = scalable_8930;
 		acpu_freq_tbl = acpu_freq_tbl_8930;
diff --git a/arch/arm/mach-msm/acpuclock-8x60.c b/arch/arm/mach-msm/acpuclock-8x60.c
index 6bc841b..7339a4c 100644
--- a/arch/arm/mach-msm/acpuclock-8x60.c
+++ b/arch/arm/mach-msm/acpuclock-8x60.c
@@ -845,7 +845,7 @@
 	case CPU_UP_PREPARE:
 	case CPU_UP_PREPARE_FROZEN:
 		if (WARN_ON(!prev_khz[cpu]))
-			prev_khz[cpu] = acpu_freq_tbl->acpuclk_khz;
+			return NOTIFY_BAD;
 		acpuclk_8x60_set_rate(cpu, prev_khz[cpu], SETRATE_HOTPLUG);
 		break;
 	default:
diff --git a/arch/arm/mach-msm/acpuclock.h b/arch/arm/mach-msm/acpuclock.h
index b12258f..6ea691b 100644
--- a/arch/arm/mach-msm/acpuclock.h
+++ b/arch/arm/mach-msm/acpuclock.h
@@ -102,7 +102,6 @@
 extern struct acpuclk_soc_data acpuclk_7x27_soc_data;
 extern struct acpuclk_soc_data acpuclk_7x27a_soc_data;
 extern struct acpuclk_soc_data acpuclk_7x27aa_soc_data;
-extern struct acpuclk_soc_data acpuclk_7201_soc_data;
 extern struct acpuclk_soc_data acpuclk_7x30_soc_data;
 extern struct acpuclk_soc_data acpuclk_8x50_soc_data;
 extern struct acpuclk_soc_data acpuclk_8x60_soc_data;
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 644a666..e52884f 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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 version 2 and
@@ -416,17 +416,31 @@
 	struct sk_buff *skb;
 	struct bam_mux_hdr *hdr;
 	struct tx_pkt_info *info;
+	struct tx_pkt_info *info_expected;
 	unsigned long event_data;
-	struct list_head *node;
 	unsigned long flags;
 
 	if (in_global_reset)
 		return;
-	spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
-	node = bam_tx_pool.next;
-	list_del(node);
-	spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+
 	info = container_of(work, struct tx_pkt_info, work);
+
+	spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
+	info_expected = list_first_entry(&bam_tx_pool,
+			struct tx_pkt_info, list_node);
+	if (unlikely(info != info_expected)) {
+		struct list_head *node;
+
+		pr_err("%s: bam_tx_pool mismatch .next=%p, list_node=%p\n",
+				__func__, bam_tx_pool.next, &info->list_node);
+		list_for_each(node, &bam_tx_pool)
+			pr_err("%s: node=%p\n", __func__, node);
+		spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+		BUG();
+	}
+	list_del(&info->list_node);
+	spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+
 	if (info->is_cmd) {
 		kfree(info->skb);
 		kfree(info);
@@ -733,78 +747,105 @@
 	return ret;
 }
 
+static void rx_switch_to_interrupt_mode(void)
+{
+	struct sps_connect cur_rx_conn;
+	struct sps_iovec iov;
+	struct rx_pkt_info *info;
+	int ret;
+
+	/*
+	 * Attempt to enable interrupts - if this fails,
+	 * continue polling and we will retry later.
+	 */
+	ret = sps_get_config(bam_rx_pipe, &cur_rx_conn);
+	if (ret) {
+		pr_err("%s: sps_get_config() failed %d\n", __func__, ret);
+		goto fail;
+	}
+
+	rx_register_event.options = SPS_O_EOT;
+	ret = sps_register_event(bam_rx_pipe, &rx_register_event);
+	if (ret) {
+		pr_err("%s: sps_register_event() failed %d\n", __func__, ret);
+		goto fail;
+	}
+
+	cur_rx_conn.options = SPS_O_AUTO_ENABLE |
+		SPS_O_EOT | SPS_O_ACK_TRANSFERS;
+	ret = sps_set_config(bam_rx_pipe, &cur_rx_conn);
+	if (ret) {
+		pr_err("%s: sps_set_config() failed %d\n", __func__, ret);
+		goto fail;
+	}
+	polling_mode = 0;
+
+	/* handle any rx packets before interrupt was enabled */
+	while (bam_connection_is_active && !polling_mode) {
+		ret = sps_get_iovec(bam_rx_pipe, &iov);
+		if (ret) {
+			pr_err("%s: sps_get_iovec failed %d\n",
+					__func__, ret);
+			break;
+		}
+		if (iov.addr == 0)
+			break;
+
+		mutex_lock(&bam_rx_pool_mutexlock);
+		if (unlikely(list_empty(&bam_rx_pool))) {
+			mutex_unlock(&bam_rx_pool_mutexlock);
+			continue;
+		}
+		info = list_first_entry(&bam_rx_pool, struct rx_pkt_info,
+							list_node);
+		list_del(&info->list_node);
+		mutex_unlock(&bam_rx_pool_mutexlock);
+		handle_bam_mux_cmd(&info->work);
+	}
+	return;
+
+fail:
+	pr_err("%s: reverting to polling\n", __func__);
+	queue_work(bam_mux_rx_workqueue, &rx_timer_work);
+}
+
 static void rx_timer_work_func(struct work_struct *work)
 {
 	struct sps_iovec iov;
-	struct list_head *node;
 	struct rx_pkt_info *info;
 	int inactive_cycles = 0;
 	int ret;
-	struct sps_connect cur_rx_conn;
 
-	while (1) { /* timer loop */
+	while (bam_connection_is_active) { /* timer loop */
 		++inactive_cycles;
-		while (1) { /* deplete queue loop */
+		while (bam_connection_is_active) { /* deplete queue loop */
 			if (in_global_reset)
 				return;
-			sps_get_iovec(bam_rx_pipe, &iov);
+
+			ret = sps_get_iovec(bam_rx_pipe, &iov);
+			if (ret) {
+				pr_err("%s: sps_get_iovec failed %d\n",
+						__func__, ret);
+				break;
+			}
 			if (iov.addr == 0)
 				break;
 			inactive_cycles = 0;
 			mutex_lock(&bam_rx_pool_mutexlock);
-			node = bam_rx_pool.next;
-			list_del(node);
+			if (unlikely(list_empty(&bam_rx_pool))) {
+				mutex_unlock(&bam_rx_pool_mutexlock);
+				continue;
+			}
+			info = list_first_entry(&bam_rx_pool,
+					struct rx_pkt_info,	list_node);
+			list_del(&info->list_node);
 			mutex_unlock(&bam_rx_pool_mutexlock);
-			info = container_of(node, struct rx_pkt_info,
-							list_node);
 			handle_bam_mux_cmd(&info->work);
 		}
 
 		if (inactive_cycles == POLLING_INACTIVITY) {
-			/*
-			 * attempt to enable interrupts in this pipe
-			 * if enabling interrupts fails, continue polling
-			 */
-			ret = sps_get_config(bam_rx_pipe, &cur_rx_conn);
-			if (ret) {
-				pr_err("%s: sps_get_config() failed, interrupts"
-						" not enabled\n", __func__);
-				queue_work(bam_mux_rx_workqueue,
-						&rx_timer_work);
-				return;
-			} else {
-				rx_register_event.options = SPS_O_EOT;
-				/* should check return value */
-				sps_register_event(bam_rx_pipe,
-							&rx_register_event);
-				cur_rx_conn.options = SPS_O_AUTO_ENABLE |
-					SPS_O_EOT | SPS_O_ACK_TRANSFERS;
-				ret = sps_set_config(bam_rx_pipe, &cur_rx_conn);
-				if (ret) {
-					pr_err("%s: sps_set_config() failed, "
-						"interrupts not enabled\n",
-						__func__);
-					queue_work(bam_mux_rx_workqueue,
-							&rx_timer_work);
-					return;
-				}
-				polling_mode = 0;
-			}
-			if (in_global_reset)
-				return;
-			/* handle race condition - missed packet? */
-			sps_get_iovec(bam_rx_pipe, &iov);
-			if (iov.addr == 0)
-				return;
-			inactive_cycles = 0;
-			mutex_lock(&bam_rx_pool_mutexlock);
-			node = bam_rx_pool.next;
-			list_del(node);
-			mutex_unlock(&bam_rx_pool_mutexlock);
-			info = container_of(node, struct rx_pkt_info,
-							list_node);
-			handle_bam_mux_cmd(&info->work);
-			return;
+			rx_switch_to_interrupt_mode();
+			break;
 		}
 
 		usleep_range(POLLING_MIN_SLEEP, POLLING_MAX_SLEEP);
@@ -855,16 +896,16 @@
 		if (!polling_mode) {
 			ret = sps_get_config(bam_rx_pipe, &cur_rx_conn);
 			if (ret) {
-				pr_err("%s: sps_get_config() failed, interrupts"
-					" not disabled\n", __func__);
+				pr_err("%s: sps_get_config() failed %d, interrupts"
+					" not disabled\n", __func__, ret);
 				break;
 			}
 			cur_rx_conn.options = SPS_O_AUTO_ENABLE |
 				SPS_O_ACK_TRANSFERS | SPS_O_POLL;
 			ret = sps_set_config(bam_rx_pipe, &cur_rx_conn);
 			if (ret) {
-				pr_err("%s: sps_set_config() failed, interrupts"
-					" not disabled\n", __func__);
+				pr_err("%s: sps_set_config() failed %d, interrupts"
+					" not disabled\n", __func__, ret);
 				break;
 			}
 			polling_mode = 1;
@@ -999,10 +1040,12 @@
 		return;
 	}
 	if (ul_packet_written) {
+		pr_info("%s: packet written\n", __func__);
 		ul_packet_written = 0;
 		schedule_delayed_work(&ul_timeout_work,
 				msecs_to_jiffies(UL_TIMEOUT_DELAY));
 	} else {
+		pr_info("%s: powerdown\n", __func__);
 		wait_for_ack = 1;
 		INIT_COMPLETION(ul_wakeup_ack_completion);
 		smsm_change_state(SMSM_APPS_STATE, SMSM_A2_POWER_CONTROL, 0);
@@ -1020,6 +1063,7 @@
 		mutex_unlock(&wakeup_lock);
 		return;
 	}
+	pr_info("%s\n", __func__);
 	/*
 	 * must wait for the previous power down request to have been acked
 	 * chances are it already came in and this will just fall through
@@ -1066,10 +1110,16 @@
 	i = sps_register_event(bam_rx_pipe, &rx_register_event);
 	if (i)
 		pr_err("%s: rx event reg failed rc = %d\n", __func__, i);
+
+	bam_connection_is_active = 1;
+
+	if (polling_mode)
+		rx_switch_to_interrupt_mode();
+
 	for (i = 0; i < NUM_BUFFERS; ++i)
 		queue_rx();
+
 	toggle_apps_ack();
-	bam_connection_is_active = 1;
 	complete_all(&bam_connection_completion);
 }
 
@@ -1085,6 +1135,8 @@
 	unvote_dfab();
 	__memzero(rx_desc_mem_buf.base, rx_desc_mem_buf.size);
 	__memzero(tx_desc_mem_buf.base, tx_desc_mem_buf.size);
+
+	mutex_lock(&bam_rx_pool_mutexlock);
 	while (!list_empty(&bam_rx_pool)) {
 		node = bam_rx_pool.next;
 		list_del(node);
@@ -1094,6 +1146,7 @@
 		dev_kfree_skb_any(info->skb);
 		kfree(info);
 	}
+	mutex_unlock(&bam_rx_pool_mutexlock);
 }
 
 static void vote_dfab(void)
@@ -1325,6 +1378,7 @@
 static void toggle_apps_ack(void)
 {
 	static unsigned int clear_bit; /* 0 = set the bit, else clear bit */
+	pr_info("%s: clear bit: %d\n", __func__, clear_bit);
 	smsm_change_state(SMSM_APPS_STATE,
 				clear_bit & SMSM_A2_POWER_CONTROL_ACK,
 				~clear_bit & SMSM_A2_POWER_CONTROL_ACK);
@@ -1333,15 +1387,19 @@
 
 static void bam_dmux_smsm_cb(void *priv, uint32_t old_state, uint32_t new_state)
 {
-	DBG("%s: smsm activity\n", __func__);
+	pr_info("%s: smsm activity 0x%08x -> 0x%08x\n", __func__, old_state,
+							new_state);
 	if (bam_mux_initialized && new_state & SMSM_A2_POWER_CONTROL) {
+		pr_info("%s: reconnect\n", __func__);
 		wake_lock(&bam_wakelock);
 		reconnect_to_bam();
 	} else if (bam_mux_initialized &&
 					!(new_state & SMSM_A2_POWER_CONTROL)) {
+		pr_info("%s: disconnect\n", __func__);
 		disconnect_to_bam();
 		wake_unlock(&bam_wakelock);
 	} else if (new_state & SMSM_A2_POWER_CONTROL) {
+		pr_info("%s: init\n", __func__);
 		wake_lock(&bam_wakelock);
 		bam_init();
 	} else {
@@ -1353,6 +1411,7 @@
 static void bam_dmux_smsm_ack_cb(void *priv, uint32_t old_state,
 						uint32_t new_state)
 {
+	pr_info("%s: 0x%08x -> 0x%08x\n", __func__, old_state, new_state);
 	complete_all(&ul_wakeup_ack_completion);
 }
 
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 4873258..47b20e4 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -11,7 +11,7 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/regulator/pm8921-regulator.h>
+#include <linux/regulator/pm8xxx-regulator.h>
 
 #include "board-8064.h"
 
@@ -171,9 +171,9 @@
 	REGULATOR_SUPPLY("8821_s1",		NULL),
 };
 
-#define PM8921_VREG_INIT(_id, _min_uV, _max_uV, _modes, _ops, _apply_uV, \
-			 _pull_down, _always_on, _supply_regulator, \
-			 _system_uA, _enable_time) \
+#define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
+			 _apply_uV, _pull_down, _always_on, _supply_regulator, \
+			 _system_uA, _enable_time, _reg_id) \
 	{ \
 		.init_data = { \
 			.constraints = { \
@@ -184,81 +184,86 @@
 				.input_uV		= _max_uV, \
 				.apply_uV		= _apply_uV, \
 				.always_on		= _always_on, \
+				.name			= _name, \
 			}, \
 			.num_consumer_supplies	= \
 					ARRAY_SIZE(vreg_consumers_##_id), \
 			.consumer_supplies	= vreg_consumers_##_id, \
 			.supply_regulator	= _supply_regulator, \
 		}, \
-		.id			= PM8921_VREG_ID_##_id, \
+		.id			= _reg_id, \
 		.pull_down_enable	= _pull_down, \
 		.system_uA		= _system_uA, \
 		.enable_time		= _enable_time, \
 	}
 
-#define PM8921_VREG_INIT_LDO(_id, _always_on, _pull_down, _min_uV, _max_uV, \
-		_enable_time, _supply_regulator, _system_uA) \
-	PM8921_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+#define PM8XXX_LDO(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+		_enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
 		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
 		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
 		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
-		_supply_regulator, _system_uA, _enable_time)
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
 
-#define PM8921_VREG_INIT_NLDO1200(_id, _always_on, _pull_down, _min_uV, \
-		_max_uV, _enable_time, _supply_regulator, _system_uA) \
-	PM8921_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+#define PM8XXX_NLDO1200(_id, _name, _always_on, _pull_down, _min_uV, \
+		_max_uV, _enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
 		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
 		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
 		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
-		_supply_regulator, _system_uA, _enable_time)
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
 
-#define PM8921_VREG_INIT_SMPS(_id, _always_on, _pull_down, _min_uV, _max_uV, \
-		_enable_time, _supply_regulator, _system_uA) \
-	PM8921_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+#define PM8XXX_SMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+		_enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
 		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
 		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
 		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
-		_supply_regulator, _system_uA, _enable_time)
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
 
-#define PM8921_VREG_INIT_FTSMPS(_id, _always_on, _pull_down, _min_uV, _max_uV, \
-		_enable_time, _supply_regulator, _system_uA) \
-	PM8921_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL, \
+#define PM8XXX_FTSMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+		_enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL, \
 		REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS \
 		| REGULATOR_CHANGE_MODE, 0, _pull_down, _always_on, \
-		_supply_regulator, _system_uA, _enable_time)
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
 
-#define PM8921_VREG_INIT_VS(_id, _always_on, _pull_down, _enable_time, \
-		_supply_regulator) \
-	PM8921_VREG_INIT(_id, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, _pull_down, \
-		_always_on, _supply_regulator, 0, _enable_time)
+#define PM8XXX_VS(_id, _name, _always_on, _pull_down, _enable_time, \
+		_supply_regulator, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \
+		_pull_down, _always_on, _supply_regulator, 0, _enable_time, \
+		_reg_id)
 
-#define PM8921_VREG_INIT_VS300(_id, _always_on, _pull_down, _enable_time, \
-		_supply_regulator) \
-	PM8921_VREG_INIT(_id, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, _pull_down, \
-		_always_on, _supply_regulator, 0, _enable_time)
+#define PM8XXX_VS300(_id, _name, _always_on, _pull_down, _enable_time, \
+		_supply_regulator, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \
+		_pull_down, _always_on, _supply_regulator, 0, _enable_time, \
+		_reg_id)
 
-#define PM8921_VREG_INIT_NCP(_id, _always_on, _min_uV, _max_uV, _enable_time, \
-		_supply_regulator) \
-	PM8921_VREG_INIT(_id, _min_uV, _max_uV, 0, REGULATOR_CHANGE_VOLTAGE | \
-		REGULATOR_CHANGE_STATUS, 0, 0, _always_on, _supply_regulator, \
-		0, _enable_time)
+#define PM8XXX_NCP(_id, _name, _always_on, _min_uV, _max_uV, _enable_time, \
+		_supply_regulator, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, 0, \
+		REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, 0, 0, \
+		_always_on, _supply_regulator, 0, _enable_time, _reg_id)
 
 /* Pin control initialization */
-#define PM8921_PC_INIT(_id, _always_on, _pin_fn, _pin_ctrl, _supply_regulator) \
+#define PM8XXX_PC(_id, _name, _always_on, _pin_fn, _pin_ctrl, \
+		  _supply_regulator, _reg_id) \
 	{ \
 		.init_data = { \
 			.constraints = { \
 				.valid_ops_mask	= REGULATOR_CHANGE_STATUS, \
 				.always_on	= _always_on, \
+				.name		= _name, \
 			}, \
 			.num_consumer_supplies	= \
 					ARRAY_SIZE(vreg_consumers_##_id##_PC), \
 			.consumer_supplies	= vreg_consumers_##_id##_PC, \
 			.supply_regulator  = _supply_regulator, \
 		}, \
-		.id	  = PM8921_VREG_ID_##_id##_PC, \
-		.pin_fn	  = PM8921_VREG_PIN_FN_##_pin_fn, \
-		.pin_ctrl = _pin_ctrl, \
+		.id		= _reg_id, \
+		.pin_fn		= PM8XXX_VREG_PIN_FN_##_pin_fn, \
+		.pin_ctrl	= _pin_ctrl, \
 	}
 
 #define SAW_VREG_INIT(_id, _name, _min_uV, _max_uV) \
@@ -287,59 +292,70 @@
 	SAW_VREG_INIT(8821_S1, "8821_s1",       950000, 1150000);
 
 /* PM8921 regulator constraints */
-struct pm8921_regulator_platform_data
+struct pm8xxx_regulator_platform_data
 msm8064_pm8921_regulator_pdata[] __devinitdata = {
-	/*		      ID  a_on  pd min_uV   max_uV en_t supply sys_uA */
-	PM8921_VREG_INIT_SMPS(S1,    1, 1, 1225000, 1225000, 500, NULL, 100000),
-	PM8921_VREG_INIT_SMPS(S2,    0, 1, 1300000, 1300000, 500, NULL, 0),
-	PM8921_VREG_INIT_SMPS(S3,    1, 1, 1150000, 1150000, 500, NULL, 100000),
-	PM8921_VREG_INIT_SMPS(S4,    1, 1, 1800000, 1800000, 500, NULL, 100000),
-	PM8921_VREG_INIT_SMPS(S7,    0, 1, 1200000, 1200000, 500, NULL, 100000),
+	/*
+	 *	   ID   name always_on pd min_uV   max_uV   en_t supply
+	 *	system_uA reg_ID
+	 */
+	PM8XXX_SMPS(S1, "8921_s1",  1, 1, 1225000, 1225000, 500, NULL, 100000,
+		1),
+	PM8XXX_SMPS(S2, "8921_s2",  0, 1, 1300000, 1300000, 500, NULL, 0, 2),
+	PM8XXX_SMPS(S3, "8921_s3",  1, 1, 1150000, 1150000, 500, NULL, 100000,
+		3),
+	PM8XXX_SMPS(S4, "8921_s4",  1, 1, 1800000, 1800000, 500, NULL, 100000,
+		4),
+	PM8XXX_SMPS(S7, "8921_s7",  0, 1, 1200000, 1200000, 500, NULL, 100000,
+		5),
 
-	PM8921_VREG_INIT_LDO(L1,     1, 1, 1100000, 1100000, 200, "8921_s4", 0),
-	PM8921_VREG_INIT_LDO(L2,     0, 1, 1200000, 1200000, 200, "8921_s4", 0),
-	PM8921_VREG_INIT_LDO(L3,     0, 1, 3075000, 3075000, 200, NULL, 0),
-	PM8921_VREG_INIT_LDO(L4,     1, 1, 1800000, 1800000, 200, NULL, 0),
-	PM8921_VREG_INIT_LDO(L5,     0, 1, 2950000, 2950000, 200, NULL, 0),
-	PM8921_VREG_INIT_LDO(L6,     0, 1, 2950000, 2950000, 200, NULL, 0),
-	PM8921_VREG_INIT_LDO(L7,     1, 1, 1850000, 2950000, 200, NULL, 0),
-	PM8921_VREG_INIT_LDO(L8,     0, 1, 2800000, 2800000, 200, NULL, 0),
-	PM8921_VREG_INIT_LDO(L9,     0, 1, 2850000, 2850000, 200, NULL, 0),
-	PM8921_VREG_INIT_LDO(L10,    0, 1, 2900000, 2900000, 200, NULL, 0),
-	PM8921_VREG_INIT_LDO(L11,    0, 1, 3000000, 3000000, 200, NULL, 0),
-	PM8921_VREG_INIT_LDO(L12,    0, 1, 1200000, 1200000, 200, "8921_s4", 0),
-	PM8921_VREG_INIT_LDO(L14,    0, 1, 1800000, 1800000, 200, NULL, 0),
-	PM8921_VREG_INIT_LDO(L15,    0, 1, 1800000, 2950000, 200, NULL, 0),
-	PM8921_VREG_INIT_LDO(L16,    0, 1, 2800000, 2800000, 200, NULL, 0),
-	PM8921_VREG_INIT_LDO(L17,    0, 1, 2000000, 2000000, 200, NULL, 0),
-	PM8921_VREG_INIT_LDO(L18,    0, 1, 1300000, 1800000, 200, "8921_s4", 0),
-	PM8921_VREG_INIT_LDO(L22,    0, 1, 2600000, 2600000, 200, NULL, 0),
-	PM8921_VREG_INIT_LDO(L23,    0, 1, 1800000, 1800000, 200, NULL, 0),
-	PM8921_VREG_INIT_NLDO1200(L24, 1, 1, 1150000, 1150000, 200, "8921_s1",
-		10000),
-	PM8921_VREG_INIT_NLDO1200(L25, 1, 1, 1225000, 1225000, 200, "8921_s1",
-		0),
-	PM8921_VREG_INIT_NLDO1200(L26, 0, 1, 1050000, 1050000, 200, "8921_s7",
-		0),
-	PM8921_VREG_INIT_NLDO1200(L27, 0, 1, 1000000, 1000000, 200, "8921_s7",
-		0),
-	PM8921_VREG_INIT_NLDO1200(L28, 0, 1, 1050000, 1050000, 200, "8921_s7",
-		0),
+	PM8XXX_LDO(L1,  "8921_l1",  1, 1, 1100000, 1100000, 200, "8921_s4", 0,
+		6),
+	PM8XXX_LDO(L2,  "8921_l2",  0, 1, 1200000, 1200000, 200, "8921_s4", 0,
+		7),
+	PM8XXX_LDO(L3,  "8921_l3",  0, 1, 3075000, 3075000, 200, NULL, 0, 8),
+	PM8XXX_LDO(L4,  "8921_l4",  1, 1, 1800000, 1800000, 200, NULL, 0, 9),
+	PM8XXX_LDO(L5,  "8921_l5",  0, 1, 2950000, 2950000, 200, NULL, 0, 10),
+	PM8XXX_LDO(L6,  "8921_l6",  0, 1, 2950000, 2950000, 200, NULL, 0, 11),
+	PM8XXX_LDO(L7,  "8921_l7",  1, 1, 1850000, 2950000, 200, NULL, 0, 12),
+	PM8XXX_LDO(L8,  "8921_l8",  0, 1, 2800000, 2800000, 200, NULL, 0, 13),
+	PM8XXX_LDO(L9,  "8921_l9",  0, 1, 2850000, 2850000, 200, NULL, 0, 14),
+	PM8XXX_LDO(L10, "8921_l10", 0, 1, 2900000, 2900000, 200, NULL, 0, 15),
+	PM8XXX_LDO(L11, "8921_l11", 0, 1, 3000000, 3000000, 200, NULL, 0, 16),
+	PM8XXX_LDO(L12, "8921_l12", 0, 1, 1200000, 1200000, 200, "8921_s4", 0,
+		17),
+	PM8XXX_LDO(L14, "8921_l14", 0, 1, 1800000, 1800000, 200, NULL, 0, 18),
+	PM8XXX_LDO(L15, "8921_l15", 0, 1, 1800000, 2950000, 200, NULL, 0, 19),
+	PM8XXX_LDO(L16, "8921_l16", 0, 1, 2800000, 2800000, 200, NULL, 0, 20),
+	PM8XXX_LDO(L17, "8921_l17", 0, 1, 2000000, 2000000, 200, NULL, 0, 21),
+	PM8XXX_LDO(L18, "8921_l18", 0, 1, 1300000, 1800000, 200, "8921_s4", 0,
+		22),
+	PM8XXX_LDO(L22, "8921_l22", 0, 1, 2600000, 2600000, 200, NULL, 0, 23),
+	PM8XXX_LDO(L23, "8921_l23", 0, 1, 1800000, 1800000, 200, NULL, 0, 24),
+	PM8XXX_NLDO1200(L24, "8921_l24", 1, 1, 1150000, 1150000, 200, "8921_s1",
+		10000, 25),
+	PM8XXX_NLDO1200(L25, "8921_l25", 1, 1, 1225000, 1225000, 200, "8921_s1",
+		0, 26),
+	PM8XXX_NLDO1200(L26, "8921_l26", 0, 1, 1050000, 1050000, 200, "8921_s7",
+		0, 27),
+	PM8XXX_NLDO1200(L27, "8921_l27", 0, 1, 1000000, 1000000, 200, "8921_s7",
+		0, 28),
+	PM8XXX_NLDO1200(L28, "8921_l28", 0, 1, 1050000, 1050000, 200, "8921_s7",
+		0, 29),
 
-	/*		    ID   always_on  pd			en_t supply */
-	PM8921_VREG_INIT_VS(LVS1,	 0, 1,			 0, "8921_s4"),
-	PM8921_VREG_INIT_VS300(LVS2,	 0, 1,			 0, "8921_s1"),
-	PM8921_VREG_INIT_VS(LVS3,	 0, 1,			 0, "8921_s4"),
-	PM8921_VREG_INIT_VS(LVS4,	 0, 1,			 0, "8921_s4"),
-	PM8921_VREG_INIT_VS(LVS5,	 0, 1,			 0, "8921_s4"),
-	PM8921_VREG_INIT_VS(LVS6,	 0, 1,			 0, "8921_s4"),
-	PM8921_VREG_INIT_VS(LVS7,	 1, 1,			 0, "8921_s4"),
+	/*        ID       name  always_on pd              en_t supply reg_ID */
+	PM8XXX_VS(LVS1,	   "8921_lvs1", 0, 1,                 0, "8921_s4", 30),
+	PM8XXX_VS300(LVS2, "8921_lvs2", 0, 1,                 0, "8921_s1", 31),
+	PM8XXX_VS(LVS3,    "8921_lvs3", 0, 1,                 0, "8921_s4", 32),
+	PM8XXX_VS(LVS4,    "8921_lvs4", 0, 1,                 0, "8921_s4", 33),
+	PM8XXX_VS(LVS5,    "8921_lvs5", 0, 1,                 0, "8921_s4", 34),
+	PM8XXX_VS(LVS6,    "8921_lvs6", 0, 1,                 0, "8921_s4", 35),
+	PM8XXX_VS(LVS7,    "8921_lvs7", 1, 1,                 0, "8921_s4", 36),
 
-	PM8921_VREG_INIT_VS300(USB_OTG,  0, 1,			 0, NULL),
-	PM8921_VREG_INIT_VS300(HDMI_MVS, 0, 1,			 0, NULL),
+	PM8XXX_VS300(USB_OTG,  "8921_usb_otg",  0, 1,         0, NULL, 37),
+	PM8XXX_VS300(HDMI_MVS, "8921_hdmi_mvs", 0, 1,         0, NULL, 38),
 
-	/*		     ID  always_on    min_uV   max_uV  en_t  supply */
-	PM8921_VREG_INIT_NCP(NCP,	 0,   1800000, 1800000, 200, "8921_l6"),
+	/*         ID   name  always_on   min_uV   max_uV  en_t supply reg_ID */
+	PM8XXX_NCP(NCP,	"8921_ncp", 0,    1800000, 1800000, 200, "8921_l6", 39),
 };
 
 int msm8064_pm8921_regulator_pdata_len __devinitdata =
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index b13a48c..d6532d5 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -333,6 +333,7 @@
 	.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
 	.hw_key_support = QCE_HW_KEY_SUPPORT,
 	.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+	.bus_scale_table = NULL,
 };
 
 static struct platform_device qcrypto_device = {
@@ -355,6 +356,7 @@
 	.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
 	.hw_key_support = QCE_HW_KEY_SUPPORT,
 	.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+	.bus_scale_table = NULL,
 };
 
 static struct platform_device qcedev_device = {
@@ -381,7 +383,6 @@
 
 static void __init apq8064_init_irq(void)
 {
-	unsigned int i;
 	gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
 						(void *)MSM_QGIC_CPU_BASE);
 
@@ -390,16 +391,6 @@
 
 	writel_relaxed(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET);
 	mb();
-
-	/*
-	 * FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
-	 * as they are configured as level, which does not play nice with
-	 * handle_percpu_irq.
-	 */
-	for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
-		if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
-			irq_set_handler(i, handle_percpu_irq);
-	}
 }
 
 static struct platform_device msm8064_device_saw_regulator_core0 = {
@@ -498,10 +489,6 @@
 static struct platform_device *rumi3_devices[] __initdata = {
 	&apq8064_device_uart_gsbi1,
 	&msm_device_sps_apq8064,
-	&msm_cpudai_bt_rx,
-	&msm_cpudai_bt_tx,
-	&msm_cpudai_fm_rx,
-	&msm_cpudai_fm_tx,
 };
 
 static struct msm_spi_platform_data apq8064_qup_spi_gsbi5_pdata = {
@@ -609,6 +596,7 @@
 	.map_io = apq8064_map_io,
 	.reserve = apq8064_reserve,
 	.init_irq = apq8064_init_irq,
+	.handle_irq = gic_handle_irq,
 	.timer = &msm_timer,
 	.init_machine = apq8064_sim_init,
 MACHINE_END
@@ -617,6 +605,7 @@
 	.map_io = apq8064_map_io,
 	.reserve = apq8064_reserve,
 	.init_irq = apq8064_init_irq,
+	.handle_irq = gic_handle_irq,
 	.timer = &msm_timer,
 	.init_machine = apq8064_rumi3_init,
 MACHINE_END
diff --git a/arch/arm/mach-msm/board-8064.h b/arch/arm/mach-msm/board-8064.h
index 4a48897..98f453b 100644
--- a/arch/arm/mach-msm/board-8064.h
+++ b/arch/arm/mach-msm/board-8064.h
@@ -27,7 +27,7 @@
 #define PM8821_MPP_PM_TO_SYS(pm_mpp)	(pm_mpp - 1 + PM8821_MPP_BASE)
 #define PM8821_IRQ_BASE			(PM8921_IRQ_BASE + PM8921_NR_IRQS)
 
-extern struct pm8921_regulator_platform_data
+extern struct pm8xxx_regulator_platform_data
 	msm8064_pm8921_regulator_pdata[] __devinitdata;
 
 extern int msm8064_pm8921_regulator_pdata_len __devinitdata;
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
index 9161fbf..6b5f917 100644
--- a/arch/arm/mach-msm/board-8930-camera.c
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -11,8 +11,6 @@
  *
  */
 
-#include <linux/i2c.h>
-#include <linux/i2c/sx150x.h>
 #include <asm/mach-types.h>
 #include <mach/board.h>
 #include <mach/msm_bus_board.h>
@@ -402,14 +400,29 @@
 	.actuator_info = &imx074_actuator_info
 #endif
 };
+#endif
 
-static struct platform_device msm8960_camera_sensor_imx074 = {
-	.name	= "msm_camera_imx074",
-	.dev	= {
-		.platform_data = &msm_camera_sensor_imx074_data,
-	},
+#ifdef CONFIG_MT9M114
+static struct msm_camera_sensor_flash_data flash_mt9m114 = {
+	.flash_type = MSM_CAMERA_FLASH_NONE
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_mt9m114 = {
+	.mount_angle = 90,
+	.sensor_reset = 107,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9m114_data = {
+	.sensor_name = "mt9m114",
+	.pdata = &msm_camera_csi_device_data[0],
+	.flash_data = &flash_mt9m114,
+	.sensor_platform_info = &sensor_board_info_mt9m114,
+	.gpio_conf = &gpio_conf,
+	.csi_if = 1,
+	.camera_type = BACK_CAMERA_2D,
 };
 #endif
+
 #ifdef CONFIG_OV2720
 static struct msm_camera_sensor_flash_data flash_ov2720 = {
 	.flash_type	= MSM_CAMERA_FLASH_NONE,
@@ -432,33 +445,13 @@
 	.csi_if	= 1,
 	.camera_type = FRONT_CAMERA_2D,
 };
-
-static struct platform_device msm8960_camera_sensor_ov2720 = {
-	.name	= "msm_camera_ov2720",
-	.dev	= {
-		.platform_data = &msm_camera_sensor_ov2720_data,
-	},
-};
 #endif
 
 void __init msm8930_init_cam(void)
 {
-	int i;
-	struct platform_device *cam_dev[] = {
-		&msm8960_camera_sensor_imx074,
-		&msm8960_camera_sensor_ov2720,
-	};
-
 	msm_gpiomux_install(msm8960_cam_common_configs,
 			ARRAY_SIZE(msm8960_cam_common_configs));
 
-	for (i = 0; i < ARRAY_SIZE(cam_dev); i++) {
-		struct msm_camera_sensor_info *s_info;
-		s_info = cam_dev[i]->dev.platform_data;
-		msm_get_cam_resources(s_info);
-		platform_device_register(cam_dev[i]);
-	}
-
 	platform_device_register(&msm8960_device_csiphy0);
 	platform_device_register(&msm8960_device_csiphy1);
 	platform_device_register(&msm8960_device_csid0);
@@ -467,4 +460,35 @@
 	platform_device_register(&msm8960_device_vfe);
 	platform_device_register(&msm8960_device_vpe);
 }
+
+#ifdef CONFIG_I2C
+struct i2c_board_info msm8930_camera_i2c_boardinfo[] = {
+#ifdef CONFIG_IMX074
+	{
+	I2C_BOARD_INFO("imx074", 0x1A),
+	.platform_data = &msm_camera_sensor_imx074_data,
+	},
+#endif
+#ifdef CONFIG_OV2720
+	{
+	I2C_BOARD_INFO("ov2720", 0x6C),
+	.platform_data = &msm_camera_sensor_ov2720_data,
+	},
+#endif
+	{
+	I2C_BOARD_INFO("mt9m114", 0x48),
+	.platform_data = &msm_camera_sensor_mt9m114_data,
+	},
+#ifdef CONFIG_MSM_CAMERA_FLASH_SC628A
+	{
+	I2C_BOARD_INFO("sc628a", 0x6E),
+	},
+#endif
+};
+
+struct msm_camera_board_info msm8930_camera_board_info = {
+	.board_info = msm8930_camera_i2c_boardinfo,
+	.num_i2c_board_info = ARRAY_SIZE(msm8930_camera_i2c_boardinfo),
+};
+#endif
 #endif
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index 2fb6153..c1b880c 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -17,6 +17,7 @@
 #include <linux/bootmem.h>
 #include <asm/mach-types.h>
 #include <mach/msm_bus_board.h>
+#include <mach/msm_memtypes.h>
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/gpiomux.h>
@@ -46,25 +47,26 @@
 #define MSM_FB_EXT_BUF_SIZE	0
 #endif
 
-#ifdef CONFIG_FB_MSM_OVERLAY_WRITEBACK
-/* width x height x 3 bpp x 2 frame buffer */
-#define MSM_FB_WRITEBACK_SIZE (1376 * 768 * 3 * 2)
-#define MSM_FB_WRITEBACK_OFFSET  \
-		(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE)
-#else
-#define MSM_FB_WRITEBACK_SIZE   0
-#define MSM_FB_WRITEBACK_OFFSET 0
-#endif
-
 #ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
 /* 4 bpp x 2 page HDMI case */
 #define MSM_FB_SIZE roundup((1920 * 1088 * 4 * 2), 4096)
 #else
 /* Note: must be multiple of 4096 */
-#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE + \
-				MSM_FB_WRITEBACK_SIZE, 4096)
+#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE, 4096)
 #endif
 
+#ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
+#define MSM_FB_OVERLAY0_WRITEBACK_SIZE roundup((1376 * 768 * 3 * 2), 4096)
+#else
+#define MSM_FB_OVERLAY0_WRITEBACK_SIZE (0)
+#endif  /* CONFIG_FB_MSM_OVERLAY0_WRITEBACK */
+
+#ifdef CONFIG_FB_MSM_OVERLAY1_WRITEBACK
+#define MSM_FB_OVERLAY1_WRITEBACK_SIZE roundup((1920 * 1088 * 3 * 2), 4096)
+#else
+#define MSM_FB_OVERLAY1_WRITEBACK_SIZE (0)
+#endif  /* CONFIG_FB_MSM_OVERLAY1_WRITEBACK */
+
 #define MDP_VSYNC_GPIO 0
 
 #define PANEL_NAME_MAX_LEN	30
@@ -77,11 +79,6 @@
 #define HDMI_PANEL_NAME	"hdmi_msm"
 #define TVOUT_PANEL_NAME	"tvout_msm"
 
-static int writeback_offset(void)
-{
-	return MSM_FB_WRITEBACK_OFFSET;
-}
-
 static struct resource msm_fb_resources[] = {
 	{
 		.flags = IORESOURCE_DMA,
@@ -438,9 +435,21 @@
 	.mdp_bus_scale_table = &mdp_bus_scale_pdata,
 #endif
 	.mdp_rev = MDP_REV_42,
-	.writeback_offset = writeback_offset,
+	.mdp_writeback_memtype = MEMTYPE_EBI1,
+	.mdp_writeback_phys = NULL,
 };
 
+void __init msm8930_mdp_writeback(struct memtype_reserve* reserve_table)
+{
+	mdp_pdata.mdp_writeback_size_ov0 = MSM_FB_OVERLAY0_WRITEBACK_SIZE;
+	mdp_pdata.mdp_writeback_size_ov1 = MSM_FB_OVERLAY1_WRITEBACK_SIZE;
+
+	reserve_table[mdp_pdata.mdp_writeback_memtype].size +=
+		mdp_pdata.mdp_writeback_size_ov0;
+	reserve_table[mdp_pdata.mdp_writeback_memtype].size +=
+		mdp_pdata.mdp_writeback_size_ov1;
+}
+
 #define LPM_CHANNEL0 0
 static int toshiba_gpio[] = {LPM_CHANNEL0};
 
diff --git a/arch/arm/mach-msm/board-8930-gpiomux.c b/arch/arm/mach-msm/board-8930-gpiomux.c
index e872d64..476ab93 100644
--- a/arch/arm/mach-msm/board-8930-gpiomux.c
+++ b/arch/arm/mach-msm/board-8930-gpiomux.c
@@ -120,42 +120,70 @@
 	.pull = GPIOMUX_PULL_DOWN,
 };
 
-static struct gpiomux_setting cyts_resout_sus_cfg = {
-	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_6MA,
-	.pull = GPIOMUX_PULL_UP,
-};
-
-static struct gpiomux_setting cyts_resout_act_cfg = {
-	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_6MA,
-	.pull = GPIOMUX_PULL_UP,
-};
-
-static struct gpiomux_setting cyts_sleep_sus_cfg = {
+static struct gpiomux_setting atmel_resout_sus_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_6MA,
 	.pull = GPIOMUX_PULL_DOWN,
 };
 
-static struct gpiomux_setting cyts_sleep_act_cfg = {
+static struct gpiomux_setting atmel_resout_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting atmel_ldo_en_sus_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_6MA,
 	.pull = GPIOMUX_PULL_DOWN,
 };
 
-static struct gpiomux_setting cyts_int_act_cfg = {
+static struct gpiomux_setting atmel_ldo_en_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting atmel_int_act_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_8MA,
 	.pull = GPIOMUX_PULL_UP,
 };
 
-static struct gpiomux_setting cyts_int_sus_cfg = {
+static struct gpiomux_setting atmel_int_sus_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_2MA,
 	.pull = GPIOMUX_PULL_DOWN,
 };
+#ifdef MSM8930_PHASE_2
+static struct gpiomux_setting hsusb_act_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
 
+static struct gpiomux_setting hsusb_sus_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+static struct msm_gpiomux_config msm8930_hsusb_configs[] = {
+	{
+		.gpio = 63,     /* HSUSB_EXTERNAL_5V_LDO_EN */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &hsusb_act_cfg,
+			[GPIOMUX_SUSPENDED] = &hsusb_sus_cfg,
+		},
+	},
+	{
+		.gpio = 97,     /* HSUSB_5V_EN */
+		.settings = {
+			[GPIOMUX_ACTIVE] = &hsusb_act_cfg,
+			[GPIOMUX_SUSPENDED] = &hsusb_sus_cfg,
+		},
+	},
+};
+#endif
 #ifdef CONFIG_USB_EHCI_MSM_HSIC
 static struct gpiomux_setting hsic_act_cfg = {
 	.func = GPIOMUX_FUNC_1,
@@ -455,26 +483,26 @@
 	},
 };
 
-static struct msm_gpiomux_config msm8960_cyts_configs[] __initdata = {
+static struct msm_gpiomux_config msm8960_atmel_configs[] __initdata = {
 	{	/* TS INTERRUPT */
 		.gpio = 11,
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cyts_int_act_cfg,
-			[GPIOMUX_SUSPENDED] = &cyts_int_sus_cfg,
+			[GPIOMUX_ACTIVE]    = &atmel_int_act_cfg,
+			[GPIOMUX_SUSPENDED] = &atmel_int_sus_cfg,
 		},
 	},
-	{	/* TS SLEEP */
+	{	/* TS LDO ENABLE */
 		.gpio = 50,
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cyts_sleep_act_cfg,
-			[GPIOMUX_SUSPENDED] = &cyts_sleep_sus_cfg,
+			[GPIOMUX_ACTIVE]    = &atmel_ldo_en_act_cfg,
+			[GPIOMUX_SUSPENDED] = &atmel_ldo_en_sus_cfg,
 		},
 	},
 	{	/* TS RESOUT */
 		.gpio = 52,
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cyts_resout_act_cfg,
-			[GPIOMUX_SUSPENDED] = &cyts_resout_sus_cfg,
+			[GPIOMUX_ACTIVE]    = &atmel_resout_act_cfg,
+			[GPIOMUX_SUSPENDED] = &atmel_resout_sus_cfg,
 		},
 	},
 };
@@ -619,8 +647,8 @@
 	msm_gpiomux_install(msm8960_gsbi_configs,
 			ARRAY_SIZE(msm8960_gsbi_configs));
 
-	msm_gpiomux_install(msm8960_cyts_configs,
-			ARRAY_SIZE(msm8960_cyts_configs));
+	msm_gpiomux_install(msm8960_atmel_configs,
+			ARRAY_SIZE(msm8960_atmel_configs));
 
 	msm_gpiomux_install(msm8960_slimbus_config,
 			ARRAY_SIZE(msm8960_slimbus_config));
@@ -635,9 +663,14 @@
 			ARRAY_SIZE(wcnss_5wire_interface));
 
 	if (machine_is_msm8930_mtp() || machine_is_msm8930_fluid() ||
-		machine_is_msm8930_cdp())
+		machine_is_msm8930_cdp()) {
 		msm_gpiomux_install(hap_lvl_shft_config,
 			ARRAY_SIZE(hap_lvl_shft_config));
+#ifdef MSM8930_PHASE_2
+		msm_gpiomux_install(msm8930_hsusb_configs,
+			ARRAY_SIZE(msm8930_hsusb_configs));
+#endif
+	}
 
 	if (PLATFORM_IS_CHARM25())
 		msm_gpiomux_install(mdm_configs,
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index 283493d..fcff6ed 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -155,6 +155,7 @@
 	.rtc_pdata              = &pm8xxx_rtc_pdata,
 	.pwrkey_pdata		= &pm8xxx_pwrkey_pdata,
 	.misc_pdata		= &pm8xxx_misc_pdata,
+	.regulator_pdatas	= msm8930_pm8038_regulator_pdata,
 };
 
 static struct msm_ssbi_platform_data msm8930_ssbi_pm8038_pdata __devinitdata = {
@@ -170,4 +171,6 @@
 	pmic_reset_irq = PM8038_IRQ_BASE + PM8038_RESOUT_IRQ;
 	msm8960_device_ssbi_pmic.dev.platform_data =
 				&msm8930_ssbi_pm8038_pdata;
+	pm8038_platform_data.num_regulators
+		= msm8930_pm8038_regulator_pdata_len;
 }
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator.c
new file mode 100644
index 0000000..ff4c808
--- /dev/null
+++ b/arch/arm/mach-msm/board-8930-regulator.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. 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 version 2 and
+ * only 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.
+ */
+
+#include <linux/regulator/pm8xxx-regulator.h>
+
+#include "board-8930.h"
+
+#define VREG_CONSUMERS(_id) \
+	static struct regulator_consumer_supply vreg_consumers_##_id[]
+
+/*
+ * Consumer specific regulator names:
+ *			 regulator name		consumer dev_name
+ */
+VREG_CONSUMERS(L1) = {
+	REGULATOR_SUPPLY("8038_l1",		NULL),
+};
+VREG_CONSUMERS(L2) = {
+	REGULATOR_SUPPLY("8038_l2",		NULL),
+};
+VREG_CONSUMERS(L3) = {
+	REGULATOR_SUPPLY("8038_l3",		NULL),
+	REGULATOR_SUPPLY("HSUSB_3p3",		"msm_otg"),
+};
+VREG_CONSUMERS(L4) = {
+	REGULATOR_SUPPLY("8038_l4",		NULL),
+	REGULATOR_SUPPLY("HSUSB_1p8",		"msm_otg"),
+};
+VREG_CONSUMERS(L5) = {
+	REGULATOR_SUPPLY("8038_l5",		NULL),
+};
+VREG_CONSUMERS(L6) = {
+	REGULATOR_SUPPLY("8038_l6",		NULL),
+};
+VREG_CONSUMERS(L7) = {
+	REGULATOR_SUPPLY("8038_l7",		NULL),
+};
+VREG_CONSUMERS(L8) = {
+	REGULATOR_SUPPLY("8038_l8",		NULL),
+};
+VREG_CONSUMERS(L9) = {
+	REGULATOR_SUPPLY("8038_l9",		NULL),
+};
+VREG_CONSUMERS(L10) = {
+	REGULATOR_SUPPLY("8038_l10",		NULL),
+};
+VREG_CONSUMERS(L11) = {
+	REGULATOR_SUPPLY("8038_l11",		NULL),
+};
+VREG_CONSUMERS(L12) = {
+	REGULATOR_SUPPLY("8038_l12",		NULL),
+};
+VREG_CONSUMERS(L14) = {
+	REGULATOR_SUPPLY("8038_l14",		NULL),
+};
+VREG_CONSUMERS(L15) = {
+	REGULATOR_SUPPLY("8038_l15",		NULL),
+};
+VREG_CONSUMERS(L16) = {
+	REGULATOR_SUPPLY("8038_l16",		NULL),
+};
+VREG_CONSUMERS(L17) = {
+	REGULATOR_SUPPLY("8038_l17",		NULL),
+};
+VREG_CONSUMERS(L18) = {
+	REGULATOR_SUPPLY("8038_l18",		NULL),
+};
+VREG_CONSUMERS(L19) = {
+	REGULATOR_SUPPLY("8038_l19",		NULL),
+};
+VREG_CONSUMERS(L20) = {
+	REGULATOR_SUPPLY("8038_l20",		NULL),
+};
+VREG_CONSUMERS(L21) = {
+	REGULATOR_SUPPLY("8038_l21",		NULL),
+};
+VREG_CONSUMERS(L22) = {
+	REGULATOR_SUPPLY("8038_l22",		NULL),
+};
+VREG_CONSUMERS(L23) = {
+	REGULATOR_SUPPLY("8038_l23",		NULL),
+};
+VREG_CONSUMERS(L24) = {
+	REGULATOR_SUPPLY("8038_l24",		NULL),
+};
+VREG_CONSUMERS(L26) = {
+	REGULATOR_SUPPLY("8038_l26",		NULL),
+};
+VREG_CONSUMERS(L27) = {
+	REGULATOR_SUPPLY("8038_l27",		NULL),
+};
+VREG_CONSUMERS(S1) = {
+	REGULATOR_SUPPLY("8038_s1",		NULL),
+	REGULATOR_SUPPLY("HSUSB_VDDCX",		"msm_otg"),
+};
+VREG_CONSUMERS(S2) = {
+	REGULATOR_SUPPLY("8038_s2",		NULL),
+};
+VREG_CONSUMERS(S3) = {
+	REGULATOR_SUPPLY("8038_s3",		NULL),
+};
+VREG_CONSUMERS(S4) = {
+	REGULATOR_SUPPLY("8038_s4",		NULL),
+};
+VREG_CONSUMERS(S5) = {
+	REGULATOR_SUPPLY("8038_s5",		NULL),
+};
+VREG_CONSUMERS(S6) = {
+	REGULATOR_SUPPLY("8038_s6",		NULL),
+};
+VREG_CONSUMERS(LVS1) = {
+	REGULATOR_SUPPLY("8038_lvs1",		NULL),
+};
+VREG_CONSUMERS(LVS2) = {
+	REGULATOR_SUPPLY("8038_lvs2",		NULL),
+};
+VREG_CONSUMERS(EXT_5V) = {
+	REGULATOR_SUPPLY("ext_5v",		NULL),
+};
+VREG_CONSUMERS(EXT_OTG_SW) = {
+	REGULATOR_SUPPLY("ext_otg_sw",		NULL),
+	REGULATOR_SUPPLY("vbus_otg",          "msm_otg"),
+};
+
+#define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
+			 _apply_uV, _pull_down, _always_on, _supply_regulator, \
+			 _system_uA, _enable_time, _reg_id) \
+	{ \
+		.init_data = { \
+			.constraints = { \
+				.valid_modes_mask	= _modes, \
+				.valid_ops_mask		= _ops, \
+				.min_uV			= _min_uV, \
+				.max_uV			= _max_uV, \
+				.input_uV		= _max_uV, \
+				.apply_uV		= _apply_uV, \
+				.always_on		= _always_on, \
+				.name			= _name, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id), \
+			.consumer_supplies	= vreg_consumers_##_id, \
+			.supply_regulator	= _supply_regulator, \
+		}, \
+		.id			= _reg_id, \
+		.pull_down_enable	= _pull_down, \
+		.system_uA		= _system_uA, \
+		.enable_time		= _enable_time, \
+	}
+
+#define PM8XXX_LDO(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+		_enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
+		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
+
+#define PM8XXX_NLDO1200(_id, _name, _always_on, _pull_down, _min_uV, \
+		_max_uV, _enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
+		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
+
+#define PM8XXX_SMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+		_enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
+		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
+		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
+
+#define PM8XXX_FTSMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+		_enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL, \
+		REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS \
+		| REGULATOR_CHANGE_MODE, 0, _pull_down, _always_on, \
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
+
+#define PM8XXX_VS(_id, _name, _always_on, _pull_down, _enable_time, \
+		_supply_regulator, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \
+		_pull_down, _always_on, _supply_regulator, 0, _enable_time, \
+		_reg_id)
+
+#define PM8XXX_VS300(_id, _name, _always_on, _pull_down, _enable_time, \
+		_supply_regulator, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \
+		_pull_down, _always_on, _supply_regulator, 0, _enable_time, \
+		_reg_id)
+
+#define PM8XXX_NCP(_id, _name, _always_on, _min_uV, _max_uV, _enable_time, \
+		_supply_regulator, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, 0, \
+		REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, 0, 0, \
+		_always_on, _supply_regulator, 0, _enable_time, _reg_id)
+
+/* Pin control initialization */
+#define PM8XXX_PC(_id, _name, _always_on, _pin_fn, _pin_ctrl, \
+		  _supply_regulator, _reg_id) \
+	{ \
+		.init_data = { \
+			.constraints = { \
+				.valid_ops_mask	= REGULATOR_CHANGE_STATUS, \
+				.always_on	= _always_on, \
+				.name		= _name, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id##_PC), \
+			.consumer_supplies	= vreg_consumers_##_id##_PC, \
+			.supply_regulator  = _supply_regulator, \
+		}, \
+		.id		= _reg_id, \
+		.pin_fn		= PM8XXX_VREG_PIN_FN_##_pin_fn, \
+		.pin_ctrl	= _pin_ctrl, \
+	}
+
+#define GPIO_VREG(_id, _reg_name, _gpio_label, _gpio, _supply_regulator) \
+	[MSM8930_GPIO_VREG_ID_##_id] = { \
+		.init_data = { \
+			.constraints = { \
+				.valid_ops_mask	= REGULATOR_CHANGE_STATUS, \
+			}, \
+			.num_consumer_supplies	= \
+					ARRAY_SIZE(vreg_consumers_##_id), \
+			.consumer_supplies	= vreg_consumers_##_id, \
+			.supply_regulator	= _supply_regulator, \
+		}, \
+		.regulator_name = _reg_name, \
+		.gpio_label	= _gpio_label, \
+		.gpio		= _gpio, \
+	}
+
+/* GPIO regulator constraints */
+struct gpio_regulator_platform_data
+msm8930_gpio_regulator_pdata[] __devinitdata = {
+	/*        ID          vreg_name     gpio_label     gpio  supply */
+	GPIO_VREG(EXT_5V,     "ext_5v",     "ext_5v_en",     63, NULL),
+	GPIO_VREG(EXT_OTG_SW, "ext_otg_sw", "ext_otg_sw_en", 97, "ext_5v"),
+};
+
+/* PM8038 regulator constraints */
+struct pm8xxx_regulator_platform_data
+msm8930_pm8038_regulator_pdata[] __devinitdata = {
+	/*
+	 *	    ID  name always_on pd min_uV   max_uV   en_t supply
+	 *	system_uA reg_ID
+	 */
+	PM8XXX_SMPS(S1, "8038_s1", 1, 1,  1150000, 1150000, 500, NULL, 100000,
+		26),
+	PM8XXX_SMPS(S2, "8038_s2", 1, 1,  1400000, 1400000, 500, NULL, 100000,
+		27),
+	PM8XXX_SMPS(S3, "8038_s3", 0, 1,  1150000, 1150000, 500, NULL, 0, 28),
+	PM8XXX_SMPS(S4, "8038_s4", 1, 1,  2200000, 2200000, 500, NULL, 100000,
+		29),
+
+	PM8XXX_FTSMPS(S5, "8038_s5", 0, 1, 950000, 1150000, 500, NULL, 0, 30),
+	PM8XXX_FTSMPS(S6, "8038_s6", 0, 1, 950000, 1150000, 500, NULL, 0, 31),
+
+	PM8XXX_NLDO1200(L1, "8038_l1",  0, 1, 1300000, 1300000, 200, "8038_s2",
+		0, 1),
+	PM8XXX_LDO(L2,  "8038_l2",  0, 1, 1200000, 1200000, 200, "8038_s2", 0,
+		2),
+	PM8XXX_LDO(L3,  "8038_l3",  0, 1, 3075000, 3075000, 200, NULL, 0, 3),
+	PM8XXX_LDO(L4,  "8038_l4",  1, 1, 1800000, 1800000, 200, NULL, 10000,
+		4),
+	PM8XXX_LDO(L5,  "8038_l5",  0, 1, 2950000, 2950000, 200, NULL, 0, 5),
+	PM8XXX_LDO(L6,  "8038_l6",  0, 1, 2950000, 2950000, 200, NULL, 0, 6),
+	PM8XXX_LDO(L7,  "8038_l7",  0, 1, 2050000, 2050000, 200, "8038_s4", 0,
+		7),
+	PM8XXX_LDO(L8,  "8038_l8",  0, 1, 2800000, 2800000, 200, NULL, 0, 8),
+	PM8XXX_LDO(L9,  "8038_l9",  0, 1, 2850000, 2850000, 200, NULL, 0, 9),
+	PM8XXX_LDO(L10, "8038_l10", 0, 1, 2900000, 2900000, 200, NULL, 0, 10),
+	PM8XXX_LDO(L11, "8038_l11", 1, 1, 1800000, 1800000, 200, "8038_s4",
+		10000, 11),
+	PM8XXX_LDO(L12, "8038_l12", 0, 1, 1200000, 1200000, 200, "8038_s2", 0,
+		12),
+	PM8XXX_LDO(L14, "8038_l14", 0, 1, 1800000, 1800000, 200, NULL, 0, 13),
+	PM8XXX_LDO(L15, "8038_l15", 0, 1, 1800000, 2950000, 200, NULL, 0, 14),
+	PM8XXX_NLDO1200(L16, "8038_l16", 0, 1, 1050000, 1050000, 200, "8038_s3",
+		0, 15),
+	PM8XXX_LDO(L17, "8038_l17", 0, 1, 1800000, 2950000, 200, NULL, 0, 16),
+	PM8XXX_LDO(L18, "8038_l18", 0, 1, 1800000, 1800000, 200, NULL, 0, 17),
+	PM8XXX_NLDO1200(L19, "8038_l19", 0, 1, 1050000, 1050000, 200, "8038_s3",
+		0, 18),
+	PM8XXX_NLDO1200(L20, "8038_l20", 1, 1, 1200000, 1200000, 200, "8038_s2",
+		10000, 19),
+	PM8XXX_LDO(L21, "8038_l21", 0, 1, 1900000, 1900000, 200, "8038_s4", 0,
+		20),
+	PM8XXX_LDO(L22, "8038_l22", 1, 1, 2950000, 2950000, 200, NULL, 10000,
+		21),
+	PM8XXX_LDO(L23, "8038_l23", 0, 1, 1800000, 1800000, 200, "8038_s4", 0,
+		22),
+	PM8XXX_NLDO1200(L24, "8038_l24", 1, 1, 1150000, 1150000, 200, "8038_s2",
+		10000, 23),
+	PM8XXX_LDO(L26, "8038_l26", 1, 1, 1050000, 1050000, 200, "8038_s2",
+		10000, 24),
+	PM8XXX_NLDO1200(L27, "8038_l27", 0, 1, 1050000, 1050000, 200, "8038_s3",
+		0, 25),
+
+	/*	  ID	name  always_on pd		   en_t supply reg_ID */
+	PM8XXX_VS(LVS1, "8038_lvs1", 0, 1,		     0, "8038_l11", 32),
+	PM8XXX_VS(LVS2, "8038_lvs2", 0, 1,		     0, "8038_l11", 33),
+
+};
+
+int msm8930_pm8038_regulator_pdata_len __devinitdata =
+	ARRAY_SIZE(msm8930_pm8038_regulator_pdata);
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 620716a..d39f64e 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -326,11 +326,18 @@
 	msm8930_reserve_table[MEMTYPE_EBI1].size += MSM_ION_ADSP_SIZE;
 #endif
 }
+
+static void __init reserve_mdp_memory(void)
+{
+	msm8930_mdp_writeback(msm8930_reserve_table);
+}
+
 static void __init msm8930_calculate_reserve_sizes(void)
 {
 	size_pmem_devices();
 	reserve_pmem_memory();
 	reserve_ion_memory();
+	reserve_mdp_memory();
 }
 
 static struct reserve_info msm8930_reserve_info __initdata = {
@@ -731,8 +738,6 @@
 
 static void __init msm8930_init_irq(void)
 {
-	unsigned int i;
-
 	msm_mpm_irq_extn_init();
 	gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
 						(void *)MSM_QGIC_CPU_BASE);
@@ -742,15 +747,6 @@
 
 	writel_relaxed(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET);
 	mb();
-
-	/* FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
-	 * as they are configured as level, which does not play nice with
-	 * handle_percpu_irq.
-	 */
-	for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
-		if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
-			irq_set_handler(i, handle_percpu_irq);
-	}
 }
 
 static void __init msm8930_init_buses(void)
@@ -776,71 +772,12 @@
 #ifdef CONFIG_USB_MSM_OTG_72K
 static struct msm_otg_platform_data msm_otg_pdata;
 #else
-#define USB_5V_EN		42
-static void msm_hsusb_vbus_power(bool on)
-{
-	int rc;
-	static bool vbus_is_on;
-	static struct regulator *mvs_otg_switch;
-
-	if (vbus_is_on == on)
-		return;
-
-	if (on) {
-		mvs_otg_switch = regulator_get(&msm8960_device_otg.dev,
-					       "vbus_otg");
-		if (IS_ERR(mvs_otg_switch)) {
-			pr_err("Unable to get mvs_otg_switch\n");
-			return;
-		}
-		/* TODO: Replace this with appropriate PM8038 alternative */
-#ifndef MSM8930_PHASE_2
-		rc = gpio_request(PM8921_GPIO_PM_TO_SYS(USB_5V_EN),
-						"usb_5v_en");
-#endif
-		if (rc < 0) {
-			pr_err("failed to request usb_5v_en gpio\n");
-			goto put_mvs_otg;
-		}
-
-		/* TODO: Replace this with appropriate PM8038 alternative */
-#ifndef MSM8930_PHASE_2
-		rc = gpio_direction_output(PM8921_GPIO_PM_TO_SYS(USB_5V_EN), 1);
-		if (rc) {
-			pr_err("%s: unable to set_direction for gpio [%d]\n",
-				__func__, PM8921_GPIO_PM_TO_SYS(USB_5V_EN));
-			goto free_usb_5v_en;
-		}
-#endif
-		if (regulator_enable(mvs_otg_switch)) {
-			pr_err("unable to enable mvs_otg_switch\n");
-			goto err_ldo_gpio_set_dir;
-		}
-
-		vbus_is_on = true;
-		return;
-	}
-	regulator_disable(mvs_otg_switch);
-
-/* TODO: Replace this with appropriate PM8038 alternative */
-#ifndef MSM8930_PHASE_2
-err_ldo_gpio_set_dir:
-	gpio_set_value(PM8921_GPIO_PM_TO_SYS(USB_5V_EN), 0);
-free_usb_5v_en:
-	gpio_free(PM8921_GPIO_PM_TO_SYS(USB_5V_EN));
-#endif
-put_mvs_otg:
-	regulator_put(mvs_otg_switch);
-	vbus_is_on = false;
-}
-
 static struct msm_otg_platform_data msm_otg_pdata = {
 	.mode			= USB_OTG,
 	.otg_control		= OTG_PMIC_CONTROL,
 	.phy_type		= SNPS_28NM_INTEGRATED_PHY,
 	.pclk_src_name		= "dfab_usb_hs_clk",
 	.pmic_id_irq		= PM8038_USB_ID_IN_IRQ(PM8038_IRQ_BASE),
-	.vbus_power		= msm_hsusb_vbus_power,
 	.power_budget		= 750,
 };
 #endif
@@ -1294,98 +1231,136 @@
 	},
 };
 
-/* configuration data */
-static const u8 mxt_config_data[] = {
+#define MXT_TS_GPIO_IRQ			11
+#define MXT_TS_RESET_GPIO		52
+
+static const u8 mxt_config_data_8930[] = {
 	/* T6 Object */
-	0, 0, 0, 0, 0, 0,
+	 0, 0, 0, 0, 0, 0,
 	/* T38 Object */
-	11, 2, 0, 11, 11, 11, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0,
+	 15, 1, 0, 15, 12, 11, 0, 0,
 	/* T7 Object */
-	100, 16, 50,
+	 48, 255, 25,
 	/* T8 Object */
-	8, 0, 0, 0, 0, 0, 8, 14, 50, 215,
+	 27, 0, 5, 1, 0, 0, 8, 8, 0, 0,
 	/* T9 Object */
-	131, 0, 0, 26, 42, 0, 32, 63, 3, 5,
-	0, 2, 1, 113, 10, 10, 8, 10, 255, 2,
-	85, 5, 0, 0, 20, 20, 75, 25, 202, 29,
-	10, 10, 45, 46,
+	 131, 0, 0, 19, 11, 0, 16, 35, 1, 3,
+	 10, 15, 1, 11, 4, 5, 40, 10, 54, 2,
+	 43, 4, 0, 0, 0, 0, 143, 40, 143, 80,
+	 18, 15, 50, 50, 2,
 	/* T15 Object */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0,
-	/* T22 Object */
-	5, 0, 0, 0, 0, 0, 0, 0, 30, 0,
-	0, 0, 5, 8, 10, 13, 0,
-	/* T24 Object */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0,
+	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	 0,
+	/* T18 Object */
+	 0, 0,
+	/* T19 Object */
+	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	 0, 0, 0, 0, 0, 0,
+	/* T23 Object */
+	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	 0, 0, 0, 0, 0,
 	/* T25 Object */
-	3, 0, 188, 52, 52, 33, 0, 0, 0, 0,
-	0, 0, 0, 0,
-	/* T27 Object */
-	0, 0, 0, 0, 0, 0, 0,
-	/* T28 Object */
-	0, 0, 0, 8, 12, 60,
+	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	 0, 0, 0, 0,
 	/* T40 Object */
-	0, 0, 0, 0, 0,
-	/* T41 Object */
-	0, 0, 0, 0, 0, 0,
-	/* T43 Object */
-	0, 0, 0, 0, 0, 0,
+	 0, 0, 0, 0, 0,
+	/* T42 Object */
+	 0, 0, 0, 0, 0, 0, 0, 0,
+	/* T46 Object */
+	 0, 3, 16, 48, 0, 0, 1, 0, 0,
+	/* T47 Object */
+	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	/* T48 Object */
+	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	 0, 0, 0, 0,
 };
 
-#define MXT_TS_GPIO_IRQ		11
-#define MXT_TS_LDO_EN_GPIO	50
-#define MXT_TS_RESET_GPIO	52
+static ssize_t mxt224e_vkeys_show(struct kobject *kobj,
+			struct kobj_attribute *attr, char *buf)
+{
+	return snprintf(buf, 200,
+	__stringify(EV_KEY) ":" __stringify(KEY_BACK) ":65:938:90:90"
+	":" __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":208:938:90:90"
+	":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":348:938:90:90"
+	":" __stringify(EV_KEY) ":" __stringify(KEY_SEARCH) ":490:938:90:90"
+	"\n");
+}
 
-static struct mxt_platform_data mxt_platform_data = {
-	.config			= mxt_config_data,
-	.config_length		= ARRAY_SIZE(mxt_config_data),
-	.x_size			= 1365,
-	.y_size			= 767,
+static struct kobj_attribute mxt224e_vkeys_attr = {
+	.attr = {
+		.mode = S_IRUGO,
+	},
+	.show = &mxt224e_vkeys_show,
+};
+
+static struct attribute *mxt224e_properties_attrs[] = {
+	&mxt224e_vkeys_attr.attr,
+	NULL
+};
+
+static struct attribute_group mxt224e_properties_attr_group = {
+	.attrs = mxt224e_properties_attrs,
+};
+
+static void mxt_init_vkeys_8930(void)
+{
+	int rc;
+	static struct kobject *mxt224e_properties_kobj;
+
+	mxt224e_vkeys_attr.attr.name = "virtualkeys.atmel_mxt_ts";
+	mxt224e_properties_kobj = kobject_create_and_add("board_properties",
+								NULL);
+	if (mxt224e_properties_kobj)
+		rc = sysfs_create_group(mxt224e_properties_kobj,
+					&mxt224e_properties_attr_group);
+	if (!mxt224e_properties_kobj || rc)
+		pr_err("%s: failed to create board_properties\n",
+				__func__);
+
+	return;
+}
+
+static struct mxt_platform_data mxt_platform_data_8930 = {
+	.config			= mxt_config_data_8930,
+	.config_length		= ARRAY_SIZE(mxt_config_data_8930),
+	.x_size			= 1067,
+	.y_size			= 566,
 	.irqflags		= IRQF_TRIGGER_FALLING,
 	.i2c_pull_up		= true,
+	.reset_gpio		= MXT_TS_RESET_GPIO,
+	.irq_gpio		= MXT_TS_GPIO_IRQ,
 };
 
-static struct i2c_board_info mxt_device_info[] __initdata = {
+static struct i2c_board_info mxt_device_info_8930[] __initdata = {
 	{
-		I2C_BOARD_INFO("atmel_mxt_ts", 0x5b),
-		.platform_data = &mxt_platform_data,
+		I2C_BOARD_INFO("atmel_mxt_ts", 0x4a),
+		.platform_data = &mxt_platform_data_8930,
 		.irq = MSM_GPIO_TO_INT(MXT_TS_GPIO_IRQ),
 	},
 };
 
-static void gsbi_qup_i2c_gpio_config(int adap_id, int config_type)
-{
-}
-
 static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi4_pdata = {
 	.clk_freq = 100000,
 	.src_clk_rate = 24000000,
-	.msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
 };
 
 static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi3_pdata = {
 	.clk_freq = 100000,
 	.src_clk_rate = 24000000,
-	.msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
 };
 
 static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi10_pdata = {
 	.clk_freq = 100000,
 	.src_clk_rate = 24000000,
-	.msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
 };
 
 static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi12_pdata = {
 	.clk_freq = 100000,
 	.src_clk_rate = 24000000,
-	.msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
 };
 
 static struct msm_rpm_platform_data msm_rpm_data = {
@@ -1478,21 +1453,14 @@
 };
 #endif
 
+#ifndef MSM8930_PHASE_2
+
+/* 8930 Phase 1 */
 static struct platform_device msm8930_device_ext_5v_vreg __devinitdata = {
 	.name	= GPIO_REGULATOR_DEV_NAME,
-/* TODO: Replace this with right MPP for 8038 */
-#ifndef MSM8930_PHASE_2
 	.id	= PM8921_MPP_PM_TO_SYS(7),
-#endif
 	.dev	= {
-	/*
-	 * TODO: When physical 8930/PM8038 hardware becomes
-	 * available, replace msm_gpio_regulator_pdata
-	 * with 8930 gpio regulator object.
-	 */
-#if     !defined(MSM8930_PHASE_2)
 		.platform_data = &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_5V],
-#endif
 	},
 };
 
@@ -1500,17 +1468,33 @@
 	.name	= GPIO_REGULATOR_DEV_NAME,
 	.id	= 91,
 	.dev	= {
-	 /*
-	 * TODO: When physical 8930/PM8038 hardware becomes
-	 * available, replace msm_gpio_regulator_pdata
-	 * with 8930 gpio regulator object.
-	 */
-#if     !defined(MSM8930_PHASE_2)
 		.platform_data = &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_L2],
-#endif
 	},
 };
 
+#else
+
+/* 8930 Phase 2 */
+static struct platform_device msm8930_device_ext_5v_vreg __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= 63,
+	.dev	= {
+		.platform_data =
+		     &msm8930_gpio_regulator_pdata[MSM8930_GPIO_VREG_ID_EXT_5V],
+	},
+};
+
+static struct platform_device msm8930_device_ext_otg_sw_vreg __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= 97,
+	.dev	= {
+		.platform_data =
+		 &msm8930_gpio_regulator_pdata[MSM8930_GPIO_VREG_ID_EXT_OTG_SW],
+	},
+};
+
+#endif
+
 static struct platform_device msm8930_device_rpm_regulator __devinitdata = {
 	.name	= "rpm-regulator",
 	.id	= -1,
@@ -1554,8 +1538,18 @@
 	&msm_device_saw_core0,
 	&msm_device_saw_core1,
 	&msm8930_device_ext_5v_vreg,
+#ifndef MSM8930_PHASE_2
 	&msm8930_device_ext_l2_vreg,
+#endif
 	&msm8960_device_ssbi_pmic,
+#ifdef MSM8930_PHASE_2
+	&msm8930_device_ext_otg_sw_vreg,
+#endif
+	&msm_8960_q6_lpass,
+	&msm_8960_q6_mss_fw,
+	&msm_8960_q6_mss_sw,
+	&msm_8960_riva,
+	&msm_pil_tzapps,
 	&msm8960_device_qup_spi_gsbi1,
 	&msm8960_device_qup_i2c_gsbi3,
 	&msm8960_device_qup_i2c_gsbi4,
@@ -1646,6 +1640,10 @@
 	&msm_cpudai_afe_02_rx,
 	&msm_cpudai_afe_02_tx,
 	&msm_pcm_afe,
+	&msm_compr_dsp,
+	&msm_cpudai_incall_music_rx,
+	&msm_cpudai_incall_record_rx,
+	&msm_cpudai_incall_record_tx,
 	&msm_pcm_hostless,
 	&msm_bus_apps_fabric,
 	&msm_bus_sys_fabric,
@@ -1825,26 +1823,6 @@
 	int                    len;
 };
 
-#ifdef CONFIG_MSM_CAMERA
-static struct i2c_board_info msm_camera_boardinfo[] __initdata = {
-#ifdef CONFIG_IMX074
-	{
-	I2C_BOARD_INFO("imx074", 0x1A),
-	},
-#endif
-#ifdef CONFIG_OV2720
-	{
-	I2C_BOARD_INFO("ov2720", 0x6C),
-	},
-#endif
-#ifdef CONFIG_MSM_CAMERA_FLASH_SC628A
-	{
-	I2C_BOARD_INFO("sc628a", 0x6E),
-	},
-#endif
-};
-#endif
-
 static void __init msm8930_init_hsic(void)
 {
 #ifdef CONFIG_USB_EHCI_MSM_HSIC
@@ -1884,14 +1862,6 @@
 #endif /* CONFIG_ISL9519_CHARGER */
 
 static struct i2c_registry msm8960_i2c_devices[] __initdata = {
-#ifdef CONFIG_MSM_CAMERA
-	{
-		I2C_SURF | I2C_FFA | I2C_FLUID | I2C_LIQUID | I2C_RUMI,
-		MSM_8930_GSBI4_QUP_I2C_BUS_ID,
-		msm_camera_boardinfo,
-		ARRAY_SIZE(msm_camera_boardinfo),
-	},
-#endif
 #ifdef CONFIG_ISL9519_CHARGER
 	{
 		I2C_LIQUID,
@@ -1908,16 +1878,16 @@
 	},
 	{
 		I2C_LIQUID,
-		MSM_8930_GSBI3_QUP_I2C_BUS_ID,
-		mxt_device_info,
-		ARRAY_SIZE(mxt_device_info),
-	},
-	{
-		I2C_LIQUID,
 		MSM_8930_GSBI10_QUP_I2C_BUS_ID,
 		msm_isa1200_board_info,
 		ARRAY_SIZE(msm_isa1200_board_info),
 	},
+	{
+		I2C_SURF,
+		MSM_8930_GSBI3_QUP_I2C_BUS_ID,
+		mxt_device_info_8930,
+		ARRAY_SIZE(mxt_device_info_8930),
+	},
 };
 #endif /* CONFIG_I2C */
 
@@ -1926,6 +1896,14 @@
 #ifdef CONFIG_I2C
 	u8 mach_mask = 0;
 	int i;
+#ifdef CONFIG_MSM_CAMERA
+	struct i2c_registry msm8930_camera_i2c_devices = {
+		I2C_SURF | I2C_FFA | I2C_FLUID | I2C_LIQUID | I2C_RUMI,
+		MSM_8930_GSBI4_QUP_I2C_BUS_ID,
+		msm8930_camera_board_info.board_info,
+		msm8930_camera_board_info.num_i2c_board_info,
+	};
+#endif
 
 	/* Build the matching 'supported_machs' bitmask */
 	if (machine_is_msm8930_cdp() || machine_is_msm8627_cdp())
@@ -1944,6 +1922,12 @@
 						msm8960_i2c_devices[i].info,
 						msm8960_i2c_devices[i].len);
 	}
+#ifdef CONFIG_MSM_CAMERA
+	if (msm8930_camera_i2c_devices.machs & mach_mask)
+		i2c_register_board_info(msm8930_camera_i2c_devices.bus,
+			msm8930_camera_i2c_devices.info,
+			msm8930_camera_i2c_devices.len);
+#endif
 #endif
 }
 
@@ -2001,6 +1985,8 @@
 	msm8930_init_cam();
 	msm8930_init_mmc();
 	acpuclk_init(&acpuclk_8930_soc_data);
+	if (machine_is_msm8930_cdp() || machine_is_msm8627_cdp())
+		mxt_init_vkeys_8930();
 	register_i2c_devices();
 	msm8930_init_fb();
 	slim_register_board_info(msm_slim_devices,
@@ -2020,6 +2006,7 @@
 	.map_io = msm8930_map_io,
 	.reserve = msm8930_reserve,
 	.init_irq = msm8930_init_irq,
+	.handle_irq = gic_handle_irq,
 	.timer = &msm_timer,
 	.init_machine = msm8930_cdp_init,
 	.init_early = msm8930_allocate_memory_regions,
@@ -2030,6 +2017,7 @@
 	.map_io = msm8930_map_io,
 	.reserve = msm8930_reserve,
 	.init_irq = msm8930_init_irq,
+	.handle_irq = gic_handle_irq,
 	.timer = &msm_timer,
 	.init_machine = msm8930_cdp_init,
 	.init_early = msm8930_allocate_memory_regions,
@@ -2040,6 +2028,7 @@
 	.map_io = msm8930_map_io,
 	.reserve = msm8930_reserve,
 	.init_irq = msm8930_init_irq,
+	.handle_irq = gic_handle_irq,
 	.timer = &msm_timer,
 	.init_machine = msm8930_cdp_init,
 	.init_early = msm8930_allocate_memory_regions,
@@ -2050,6 +2039,7 @@
 	.map_io = msm8930_map_io,
 	.reserve = msm8930_reserve,
 	.init_irq = msm8930_init_irq,
+	.handle_irq = gic_handle_irq,
 	.timer = &msm_timer,
 	.init_machine = msm8930_cdp_init,
 	.init_early = msm8930_allocate_memory_regions,
@@ -2060,6 +2050,7 @@
 	.map_io = msm8930_map_io,
 	.reserve = msm8930_reserve,
 	.init_irq = msm8930_init_irq,
+	.handle_irq = gic_handle_irq,
 	.timer = &msm_timer,
 	.init_machine = msm8930_cdp_init,
 	.init_early = msm8930_allocate_memory_regions,
diff --git a/arch/arm/mach-msm/board-8930.h b/arch/arm/mach-msm/board-8930.h
index ec0b867..d6d3b49 100644
--- a/arch/arm/mach-msm/board-8930.h
+++ b/arch/arm/mach-msm/board-8930.h
@@ -15,9 +15,11 @@
 
 #include <linux/regulator/gpio-regulator.h>
 #include <linux/mfd/pm8xxx/pm8038.h>
+#include <linux/i2c.h>
 #include <linux/i2c/sx150x.h>
 #include <mach/irqs.h>
 #include <mach/rpm-regulator.h>
+#include <mach/msm_memtypes.h>
 
 /*
  * TODO: When physical 8930/PM8038 hardware becomes
@@ -47,7 +49,7 @@
 extern struct regulator_init_data msm_saw_regulator_pdata_s5;
 extern struct regulator_init_data msm_saw_regulator_pdata_s6;
 
-extern struct pm8921_regulator_platform_data
+extern struct pm8xxx_regulator_platform_data
 	msm_pm8921_regulator_pdata[] __devinitdata;
 
 extern int msm_pm8921_regulator_pdata_len __devinitdata;
@@ -56,12 +58,22 @@
 	msm_gpio_regulator_pdata[] __devinitdata;
 
 extern struct rpm_regulator_platform_data msm_rpm_regulator_pdata __devinitdata;
-#endif
 
 #define GPIO_VREG_ID_EXT_5V		0
 #define GPIO_VREG_ID_EXT_L2		1
 #define GPIO_VREG_ID_EXT_3P3V		2
+#endif
 
+extern struct pm8xxx_regulator_platform_data
+	msm8930_pm8038_regulator_pdata[] __devinitdata;
+
+extern int msm8930_pm8038_regulator_pdata_len __devinitdata;
+
+#define MSM8930_GPIO_VREG_ID_EXT_5V		0
+#define MSM8930_GPIO_VREG_ID_EXT_OTG_SW		1
+
+extern struct gpio_regulator_platform_data
+	msm8930_gpio_regulator_pdata[] __devinitdata;
 
 #if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
 enum {
@@ -88,6 +100,7 @@
 #endif
 
 extern struct sx150x_platform_data msm8930_sx150x_data[];
+extern struct msm_camera_board_info msm8930_camera_board_info;
 void msm8930_init_cam(void);
 void msm8930_init_fb(void);
 void msm8930_init_pmic(void);
@@ -106,6 +119,7 @@
 int msm8930_init_gpiomux(void);
 void msm8930_allocate_fb_region(void);
 void msm8930_pm8038_gpio_mpp_init(void);
+void msm8930_mdp_writeback(struct memtype_reserve *reserve_table);
 
 #define PLATFORM_IS_CHARM25() \
 	(machine_is_msm8930_cdp() && \
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index f84944b..4466872 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -11,8 +11,6 @@
  *
  */
 
-#include <linux/i2c.h>
-#include <linux/i2c/sx150x.h>
 #include <asm/mach-types.h>
 #include <mach/board.h>
 #include <mach/msm_bus_board.h>
@@ -407,13 +405,6 @@
 	.actuator_info = &imx074_actuator_info
 #endif
 };
-
-static struct platform_device msm8960_camera_sensor_imx074 = {
-	.name	= "msm_camera_imx074",
-	.dev	= {
-		.platform_data = &msm_camera_sensor_imx074_data,
-	},
-};
 #endif
 
 #ifdef CONFIG_MT9M114
@@ -435,13 +426,6 @@
 	.csi_if = 1,
 	.camera_type = BACK_CAMERA_2D,
 };
-
-struct platform_device msm8960_camera_sensor_mt9m114 = {
-	.name = "msm_camera_mt9m114",
-	.dev = {
-		.platform_data = &msm_camera_sensor_mt9m114_data,
-	},
-};
 #endif
 
 #ifdef CONFIG_OV2720
@@ -466,13 +450,6 @@
 	.csi_if	= 1,
 	.camera_type = FRONT_CAMERA_2D,
 };
-
-static struct platform_device msm8960_camera_sensor_ov2720 = {
-	.name	= "msm_camera_ov2720",
-	.dev	= {
-		.platform_data = &msm_camera_sensor_ov2720_data,
-	},
-};
 #endif
 
 static struct msm8960_privacy_light_cfg privacy_light_info = {
@@ -481,15 +458,6 @@
 
 void __init msm8960_init_cam(void)
 {
-	int i;
-	struct platform_device *cam_dev[] = {
-		&msm8960_camera_sensor_imx074,
-#ifdef CONFIG_MT9M114
-		&msm8960_camera_sensor_mt9m114,
-#endif
-		&msm8960_camera_sensor_ov2720,
-	};
-
 	msm_gpiomux_install(msm8960_cam_common_configs,
 			ARRAY_SIZE(msm8960_cam_common_configs));
 
@@ -509,21 +477,14 @@
 
 	if (machine_is_msm8960_liquid()) {
 		struct msm_camera_sensor_info *s_info;
-		s_info = msm8960_camera_sensor_imx074.dev.platform_data;
+		s_info = &msm_camera_sensor_imx074_data;
 		s_info->sensor_platform_info->mount_angle = 180;
-		s_info = msm8960_camera_sensor_ov2720.dev.platform_data;
+		s_info = &msm_camera_sensor_ov2720_data;
 		s_info->sensor_platform_info->privacy_light = 1;
 		s_info->sensor_platform_info->privacy_light_info =
 			&privacy_light_info;
 	}
 
-	for (i = 0; i < ARRAY_SIZE(cam_dev); i++) {
-		struct msm_camera_sensor_info *s_info;
-		s_info = cam_dev[i]->dev.platform_data;
-		msm_get_cam_resources(s_info);
-		platform_device_register(cam_dev[i]);
-	}
-
 	platform_device_register(&msm8960_device_csiphy0);
 	platform_device_register(&msm8960_device_csiphy1);
 	platform_device_register(&msm8960_device_csid0);
@@ -532,4 +493,35 @@
 	platform_device_register(&msm8960_device_vfe);
 	platform_device_register(&msm8960_device_vpe);
 }
+
+#ifdef CONFIG_I2C
+static struct i2c_board_info msm8960_camera_i2c_boardinfo[] = {
+#ifdef CONFIG_IMX074
+	{
+	I2C_BOARD_INFO("imx074", 0x1A),
+	.platform_data = &msm_camera_sensor_imx074_data,
+	},
+#endif
+#ifdef CONFIG_OV2720
+	{
+	I2C_BOARD_INFO("ov2720", 0x6C),
+	.platform_data = &msm_camera_sensor_ov2720_data,
+	},
+#endif
+	{
+	I2C_BOARD_INFO("mt9m114", 0x48),
+	.platform_data = &msm_camera_sensor_mt9m114_data,
+	},
+#ifdef CONFIG_MSM_CAMERA_FLASH_SC628A
+	{
+	I2C_BOARD_INFO("sc628a", 0x6E),
+	},
+#endif
+};
+
+struct msm_camera_board_info msm8960_camera_board_info = {
+	.board_info = msm8960_camera_i2c_boardinfo,
+	.num_i2c_board_info = ARRAY_SIZE(msm8960_camera_i2c_boardinfo),
+};
+#endif
 #endif
diff --git a/arch/arm/mach-msm/board-8960-display.c b/arch/arm/mach-msm/board-8960-display.c
index 63c51ea..3bc9f0f 100644
--- a/arch/arm/mach-msm/board-8960-display.c
+++ b/arch/arm/mach-msm/board-8960-display.c
@@ -17,6 +17,7 @@
 #include <linux/bootmem.h>
 #include <asm/mach-types.h>
 #include <mach/msm_bus_board.h>
+#include <mach/msm_memtypes.h>
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/gpiomux.h>
@@ -24,9 +25,9 @@
 #include "board-8960.h"
 
 #ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
-#define MSM_FB_PRIM_BUF_SIZE (1376 * 768 * 4 * 3) /* 4 bpp x 3 pages */
+#define MSM_FB_PRIM_BUF_SIZE (1920 * 1200 * 4 * 3) /* 4 bpp x 3 pages */
 #else
-#define MSM_FB_PRIM_BUF_SIZE (1376 * 768 * 4 * 2) /* 4 bpp x 2 pages */
+#define MSM_FB_PRIM_BUF_SIZE (1920 * 1200 * 4 * 2) /* 4 bpp x 2 pages */
 #endif
 
 #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
@@ -37,25 +38,26 @@
 #define MSM_FB_EXT_BUF_SIZE	0
 #endif
 
-#ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
-/* width x height x 3 bpp x 2 frame buffer */
-#define MSM_FB_WRITEBACK_SIZE (1376 * 768 * 3 * 2)
-#define MSM_FB_WRITEBACK_OFFSET  \
-		(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE)
-#else
-#define MSM_FB_WRITEBACK_SIZE   0
-#define MSM_FB_WRITEBACK_OFFSET 0
-#endif
-
 #ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
 /* 4 bpp x 2 page HDMI case */
 #define MSM_FB_SIZE roundup((1920 * 1088 * 4 * 2), 4096)
 #else
 /* Note: must be multiple of 4096 */
-#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE + \
-				MSM_FB_WRITEBACK_SIZE, 4096)
+#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE, 4096)
 #endif
 
+#ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
+#define MSM_FB_OVERLAY0_WRITEBACK_SIZE roundup((1920 * 1200 * 3 * 2), 4096)
+#else
+#define MSM_FB_OVERLAY0_WRITEBACK_SIZE (0)
+#endif  /* CONFIG_FB_MSM_OVERLAY0_WRITEBACK */
+
+#ifdef CONFIG_FB_MSM_OVERLAY1_WRITEBACK
+#define MSM_FB_OVERLAY1_WRITEBACK_SIZE roundup((1920 * 1088 * 3 * 2), 4096)
+#else
+#define MSM_FB_OVERLAY1_WRITEBACK_SIZE (0)
+#endif  /* CONFIG_FB_MSM_OVERLAY1_WRITEBACK */
+
 #define MDP_VSYNC_GPIO 0
 
 #define PANEL_NAME_MAX_LEN	30
@@ -68,11 +70,6 @@
 #define HDMI_PANEL_NAME	"hdmi_msm"
 #define TVOUT_PANEL_NAME	"tvout_msm"
 
-static int writeback_offset(void)
-{
-	return MSM_FB_WRITEBACK_OFFSET;
-}
-
 static struct resource msm_fb_resources[] = {
 	{
 		.flags = IORESOURCE_DMA,
@@ -553,9 +550,21 @@
 	.mdp_bus_scale_table = &mdp_bus_scale_pdata,
 #endif
 	.mdp_rev = MDP_REV_42,
-	.writeback_offset = writeback_offset,
+	.mdp_writeback_memtype = MEMTYPE_EBI1,
+	.mdp_writeback_phys = NULL,
 };
 
+void __init msm8960_mdp_writeback(struct memtype_reserve* reserve_table)
+{
+	mdp_pdata.mdp_writeback_size_ov0 = MSM_FB_OVERLAY0_WRITEBACK_SIZE;
+	mdp_pdata.mdp_writeback_size_ov1 = MSM_FB_OVERLAY1_WRITEBACK_SIZE;
+
+	reserve_table[mdp_pdata.mdp_writeback_memtype].size +=
+		mdp_pdata.mdp_writeback_size_ov0;
+	reserve_table[mdp_pdata.mdp_writeback_memtype].size +=
+		mdp_pdata.mdp_writeback_size_ov1;
+}
+
 static struct platform_device mipi_dsi_renesas_panel_device = {
 	.name = "mipi_renesas",
 	.id = 0,
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index c5d47f4..c7e32c0 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -90,7 +90,7 @@
 
 /* Initial PM8921 GPIO configurations */
 static struct pm8xxx_gpio_init pm8921_gpios[] __initdata = {
-	PM8XXX_GPIO_DISABLE(6),				 /* Disable unused */
+	PM8XXX_GPIO_OUTPUT_VIN(6, 1, PM_GPIO_VIN_VPH),	 /* MHL power EN_N */
 	PM8XXX_GPIO_DISABLE(7),				 /* Disable NFC */
 	PM8XXX_GPIO_INPUT(16,	    PM_GPIO_PULL_UP_30), /* SD_CARD_WP */
     /* External regulator shared by display and touchscreen on LiQUID */
@@ -436,6 +436,7 @@
 };
 
 #define	PM8921_LC_LED_MAX_CURRENT	4	/* I = 4mA */
+#define	PM8921_LC_LED_LOW_CURRENT	1	/* I = 1mA */
 #define PM8XXX_LED_PWM_PERIOD		1000
 #define PM8XXX_LED_PWM_DUTY_MS		20
 /**
@@ -444,6 +445,50 @@
  */
 #define PM8XXX_PWM_CHANNEL_NONE		-1
 
+static struct led_info pm8921_led_info_liquid[] = {
+	{
+		.name		= "led:red",
+		.flags		= PM8XXX_ID_LED_0,
+	},
+	{
+		.name		= "led:green",
+		.flags		= PM8XXX_ID_LED_0,
+	},
+	{
+		.name		= "led:blue",
+		.flags		= PM8XXX_ID_LED_2,
+	},
+};
+
+static struct pm8xxx_led_config pm8921_led_configs_liquid[] = {
+	[0] = {
+		.id = PM8XXX_ID_LED_0,
+		.mode = PM8XXX_LED_MODE_MANUAL,
+		.max_current = PM8921_LC_LED_MAX_CURRENT,
+	},
+	[1] = {
+		.id = PM8XXX_ID_LED_1,
+		.mode = PM8XXX_LED_MODE_MANUAL,
+		.max_current = PM8921_LC_LED_LOW_CURRENT,
+	},
+	[2] = {
+		.id = PM8XXX_ID_LED_2,
+		.mode = PM8XXX_LED_MODE_MANUAL,
+		.max_current = PM8921_LC_LED_MAX_CURRENT,
+	},
+};
+
+static struct led_platform_data pm8xxx_leds_core_liquid = {
+	.num_leds = ARRAY_SIZE(pm8921_led_info_liquid),
+	.leds = pm8921_led_info_liquid,
+};
+
+static struct pm8xxx_led_platform_data pm8xxx_leds_pdata_liquid = {
+	.led_core = &pm8xxx_leds_core_liquid,
+	.configs = pm8921_led_configs_liquid,
+	.num_configs = ARRAY_SIZE(pm8921_led_configs_liquid),
+};
+
 static struct led_info pm8921_led_info[] = {
 	[0] = {
 		.name			= "led:battery_charging",
@@ -539,6 +584,8 @@
 	if (machine_is_msm8960_sim())
 		pm8921_platform_data.keypad_pdata = &keypad_data_sim;
 
-	if (machine_is_msm8960_liquid())
+	if (machine_is_msm8960_liquid()) {
 		pm8921_platform_data.keypad_pdata = &keypad_data_liquid;
+		pm8921_platform_data.leds_pdata = &pm8xxx_leds_pdata_liquid;
+	}
 }
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index de4a6d6..f6212af 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -11,7 +11,7 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/regulator/pm8921-regulator.h>
+#include <linux/regulator/pm8xxx-regulator.h>
 #include <linux/regulator/gpio-regulator.h>
 #include <mach/rpm-regulator.h>
 
@@ -30,9 +30,9 @@
 VREG_CONSUMERS(L2) = {
 	REGULATOR_SUPPLY("8921_l2",		NULL),
 	REGULATOR_SUPPLY("dsi_vdda",		"mipi_dsi.1"),
-	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_camera_imx074.0"),
-	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_camera_ov2720.0"),
-	REGULATOR_SUPPLY("mipi_csi_vdd",	"msm_camera_mt9m114.0"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"4-001a"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"4-006c"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"4-0048"),
 };
 VREG_CONSUMERS(L3) = {
 	REGULATOR_SUPPLY("8921_l3",		NULL),
@@ -62,6 +62,7 @@
 VREG_CONSUMERS(L9) = {
 	REGULATOR_SUPPLY("8921_l9",		NULL),
 	REGULATOR_SUPPLY("vdd",			"3-0024"),
+	REGULATOR_SUPPLY("vdd_ana",		"3-004a"),
 };
 VREG_CONSUMERS(L10) = {
 	REGULATOR_SUPPLY("8921_l10",		NULL),
@@ -70,15 +71,15 @@
 };
 VREG_CONSUMERS(L11) = {
 	REGULATOR_SUPPLY("8921_l11",		NULL),
-	REGULATOR_SUPPLY("cam_vana",		"msm_camera_imx074.0"),
-	REGULATOR_SUPPLY("cam_vana",		"msm_camera_ov2720.0"),
-	REGULATOR_SUPPLY("cam_vana",		"msm_camera_mt9m114.0"),
+	REGULATOR_SUPPLY("cam_vana",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vana",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vana",		"4-0048"),
 };
 VREG_CONSUMERS(L12) = {
 	REGULATOR_SUPPLY("8921_l12",		NULL),
-	REGULATOR_SUPPLY("cam_vdig",		"msm_camera_imx074.0"),
-	REGULATOR_SUPPLY("cam_vdig",		"msm_camera_ov2720.0"),
-	REGULATOR_SUPPLY("cam_vdig",		"msm_camera_mt9m114.0"),
+	REGULATOR_SUPPLY("cam_vdig",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vdig",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vdig",		"4-0048"),
 };
 VREG_CONSUMERS(L14) = {
 	REGULATOR_SUPPLY("8921_l14",		NULL),
@@ -89,9 +90,9 @@
 };
 VREG_CONSUMERS(L16) = {
 	REGULATOR_SUPPLY("8921_l16",		NULL),
-	REGULATOR_SUPPLY("cam_vaf",		"msm_camera_imx074.0"),
-	REGULATOR_SUPPLY("cam_vaf",		"msm_camera_ov2720.0"),
-	REGULATOR_SUPPLY("cam_vaf",		"msm_camera_mt9m114.0"),
+	REGULATOR_SUPPLY("cam_vaf",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vaf",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vaf",		"4-0048"),
 };
 VREG_CONSUMERS(L17) = {
 	REGULATOR_SUPPLY("8921_l17",		NULL),
@@ -196,12 +197,13 @@
 VREG_CONSUMERS(LVS4) = {
 	REGULATOR_SUPPLY("8921_lvs4",		NULL),
 	REGULATOR_SUPPLY("vcc_i2c",		"3-0024"),
+	REGULATOR_SUPPLY("vcc_i2c",		"3-004a"),
 };
 VREG_CONSUMERS(LVS5) = {
 	REGULATOR_SUPPLY("8921_lvs5",		NULL),
-	REGULATOR_SUPPLY("cam_vio",		"msm_camera_imx074.0"),
-	REGULATOR_SUPPLY("cam_vio",		"msm_camera_ov2720.0"),
-	REGULATOR_SUPPLY("cam_vio",		"msm_camera_mt9m114.0"),
+	REGULATOR_SUPPLY("cam_vio",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vio",		"4-006c"),
+	REGULATOR_SUPPLY("cam_vio",		"4-0048"),
 };
 VREG_CONSUMERS(LVS6) = {
 	REGULATOR_SUPPLY("8921_lvs6",		NULL),
@@ -212,7 +214,6 @@
 };
 VREG_CONSUMERS(USB_OTG) = {
 	REGULATOR_SUPPLY("8921_usb_otg",	NULL),
-	REGULATOR_SUPPLY("vbus_otg",		"msm_otg"),
 };
 VREG_CONSUMERS(HDMI_MVS) = {
 	REGULATOR_SUPPLY("8921_hdmi_mvs",	NULL),
@@ -230,14 +231,18 @@
 };
 VREG_CONSUMERS(EXT_3P3V) = {
 	REGULATOR_SUPPLY("ext_3p3v",		NULL),
-	REGULATOR_SUPPLY("vdd",			"3-005b"),
+	REGULATOR_SUPPLY("vdd_ana",		"3-005b"),
 	REGULATOR_SUPPLY("vdd_lvds_3p3v",	"mipi_dsi.1"),
 	REGULATOR_SUPPLY("mhl_ext_3p3v",	"msm_otg"),
 };
+VREG_CONSUMERS(EXT_OTG_SW) = {
+	REGULATOR_SUPPLY("ext_otg_sw",		NULL),
+	REGULATOR_SUPPLY("vbus_otg",		"msm_otg"),
+};
 
-#define PM8921_VREG_INIT(_id, _min_uV, _max_uV, _modes, _ops, _apply_uV, \
-			 _pull_down, _always_on, _supply_regulator, \
-			 _system_uA, _enable_time) \
+#define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
+			 _apply_uV, _pull_down, _always_on, _supply_regulator, \
+			 _system_uA, _enable_time, _reg_id) \
 	{ \
 		.init_data = { \
 			.constraints = { \
@@ -248,84 +253,89 @@
 				.input_uV		= _max_uV, \
 				.apply_uV		= _apply_uV, \
 				.always_on		= _always_on, \
+				.name			= _name, \
 			}, \
 			.num_consumer_supplies	= \
 					ARRAY_SIZE(vreg_consumers_##_id), \
 			.consumer_supplies	= vreg_consumers_##_id, \
 			.supply_regulator	= _supply_regulator, \
 		}, \
-		.id			= PM8921_VREG_ID_##_id, \
+		.id			= _reg_id, \
 		.pull_down_enable	= _pull_down, \
 		.system_uA		= _system_uA, \
 		.enable_time		= _enable_time, \
 	}
 
-#define PM8921_VREG_INIT_LDO(_id, _always_on, _pull_down, _min_uV, _max_uV, \
-		_enable_time, _supply_regulator, _system_uA) \
-	PM8921_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+#define PM8XXX_LDO(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+		_enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
 		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
 		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
 		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
-		_supply_regulator, _system_uA, _enable_time)
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
 
-#define PM8921_VREG_INIT_NLDO1200(_id, _always_on, _pull_down, _min_uV, \
-		_max_uV, _enable_time, _supply_regulator, _system_uA) \
-	PM8921_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+#define PM8XXX_NLDO1200(_id, _name, _always_on, _pull_down, _min_uV, \
+		_max_uV, _enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
 		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
 		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
 		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
-		_supply_regulator, _system_uA, _enable_time)
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
 
-#define PM8921_VREG_INIT_SMPS(_id, _always_on, _pull_down, _min_uV, _max_uV, \
-		_enable_time, _supply_regulator, _system_uA) \
-	PM8921_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+#define PM8XXX_SMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+		_enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
 		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
 		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
 		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
-		_supply_regulator, _system_uA, _enable_time)
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
 
-#define PM8921_VREG_INIT_FTSMPS(_id, _always_on, _pull_down, _min_uV, _max_uV, \
-		_enable_time, _supply_regulator, _system_uA) \
-	PM8921_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL, \
+#define PM8XXX_FTSMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+		_enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL, \
 		REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS \
 		| REGULATOR_CHANGE_MODE, 0, _pull_down, _always_on, \
-		_supply_regulator, _system_uA, _enable_time)
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
 
-#define PM8921_VREG_INIT_VS(_id, _always_on, _pull_down, _enable_time, \
-		_supply_regulator) \
-	PM8921_VREG_INIT(_id, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, _pull_down, \
-		_always_on, _supply_regulator, 0, _enable_time)
+#define PM8XXX_VS(_id, _name, _always_on, _pull_down, _enable_time, \
+		_supply_regulator, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \
+		_pull_down, _always_on, _supply_regulator, 0, _enable_time, \
+		_reg_id)
 
-#define PM8921_VREG_INIT_VS300(_id, _always_on, _pull_down, _enable_time, \
-		_supply_regulator) \
-	PM8921_VREG_INIT(_id, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, _pull_down, \
-		_always_on, _supply_regulator, 0, _enable_time)
+#define PM8XXX_VS300(_id, _name, _always_on, _pull_down, _enable_time, \
+		_supply_regulator, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \
+		_pull_down, _always_on, _supply_regulator, 0, _enable_time, \
+		_reg_id)
 
-#define PM8921_VREG_INIT_NCP(_id, _always_on, _min_uV, _max_uV, _enable_time, \
-		_supply_regulator) \
-	PM8921_VREG_INIT(_id, _min_uV, _max_uV, 0, REGULATOR_CHANGE_VOLTAGE | \
-		REGULATOR_CHANGE_STATUS, 0, 0, _always_on, _supply_regulator, \
-		0, _enable_time)
+#define PM8XXX_NCP(_id, _name, _always_on, _min_uV, _max_uV, _enable_time, \
+		_supply_regulator, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, 0, \
+		REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, 0, 0, \
+		_always_on, _supply_regulator, 0, _enable_time, _reg_id)
 
 /* Pin control initialization */
-#define PM8921_PC_INIT(_id, _always_on, _pin_fn, _pin_ctrl, _supply_regulator) \
+#define PM8XXX_PC(_id, _name, _always_on, _pin_fn, _pin_ctrl, \
+		  _supply_regulator, _reg_id) \
 	{ \
 		.init_data = { \
 			.constraints = { \
 				.valid_ops_mask	= REGULATOR_CHANGE_STATUS, \
 				.always_on	= _always_on, \
+				.name		= _name, \
 			}, \
 			.num_consumer_supplies	= \
 					ARRAY_SIZE(vreg_consumers_##_id##_PC), \
 			.consumer_supplies	= vreg_consumers_##_id##_PC, \
 			.supply_regulator  = _supply_regulator, \
 		}, \
-		.id	  = PM8921_VREG_ID_##_id##_PC, \
-		.pin_fn	  = PM8921_VREG_PIN_FN_##_pin_fn, \
-		.pin_ctrl = _pin_ctrl, \
+		.id		= _reg_id, \
+		.pin_fn		= PM8XXX_VREG_PIN_FN_##_pin_fn, \
+		.pin_ctrl	= _pin_ctrl, \
 	}
 
-#define GPIO_VREG_INIT(_id, _reg_name, _gpio_label, _gpio) \
+#define GPIO_VREG(_id, _reg_name, _gpio_label, _gpio, _supply_regulator) \
 	[GPIO_VREG_ID_##_id] = { \
 		.init_data = { \
 			.constraints = { \
@@ -334,6 +344,7 @@
 			.num_consumer_supplies	= \
 					ARRAY_SIZE(vreg_consumers_##_id), \
 			.consumer_supplies	= vreg_consumers_##_id, \
+			.supply_regulator	= _supply_regulator, \
 		}, \
 		.regulator_name = _reg_name, \
 		.gpio_label	= _gpio_label, \
@@ -445,10 +456,13 @@
 
 /* GPIO regulator constraints */
 struct gpio_regulator_platform_data msm_gpio_regulator_pdata[] __devinitdata = {
-	GPIO_VREG_INIT(EXT_5V, "ext_5v", "ext_5v_en", PM8921_MPP_PM_TO_SYS(7)),
-	GPIO_VREG_INIT(EXT_L2, "ext_l2", "ext_l2_en", 91),
-	GPIO_VREG_INIT(EXT_3P3V, "ext_3p3v", "ext_3p3v_en",
-			PM8921_GPIO_PM_TO_SYS(17)),
+	/*        ID      vreg_name gpio_label   gpio                  supply */
+	GPIO_VREG(EXT_5V, "ext_5v", "ext_5v_en", PM8921_MPP_PM_TO_SYS(7), NULL),
+	GPIO_VREG(EXT_L2, "ext_l2", "ext_l2_en", 91, NULL),
+	GPIO_VREG(EXT_3P3V, "ext_3p3v", "ext_3p3v_en",
+		PM8921_GPIO_PM_TO_SYS(17), NULL),
+	GPIO_VREG(EXT_OTG_SW, "ext_otg_sw", "ext_otg_sw_en",
+		PM8921_GPIO_PM_TO_SYS(42), "8921_usb_otg"),
 };
 
 /* SAW regulator constraints */
@@ -459,24 +473,24 @@
 	SAW_VREG_INIT(S6, "8921_s6",	       850000, 1300000);
 
 /* PM8921 regulator constraints */
-struct pm8921_regulator_platform_data
+struct pm8xxx_regulator_platform_data
 msm_pm8921_regulator_pdata[] __devinitdata = {
 	/*
-	 *			  ID a_on pd min_uV   max_uV   en_t  supply
-	 *	system_uA
+	 *		ID   name always_on pd min_uV   max_uV   en_t supply
+	 *	system_uA reg_ID
 	 */
-	PM8921_VREG_INIT_NLDO1200(L26, 0, 1, 1050000, 1050000, 200, "8921_s7",
-		0),
-	PM8921_VREG_INIT_NLDO1200(L27, 0, 1, 1050000, 1050000, 200, "8921_s7",
-		0),
-	PM8921_VREG_INIT_NLDO1200(L28, 0, 1, 1050000, 1050000, 200, "8921_s7",
-		0),
-	PM8921_VREG_INIT_LDO(L29,      0, 1, 2050000, 2100000, 200, "8921_s8",
-		0),
+	PM8XXX_NLDO1200(L26, "8921_l26", 0, 1, 1050000, 1050000, 200, "8921_s7",
+		0, 1),
+	PM8XXX_NLDO1200(L27, "8921_l27", 0, 1, 1050000, 1050000, 200, "8921_s7",
+		0, 2),
+	PM8XXX_NLDO1200(L28, "8921_l28", 0, 1, 1050000, 1050000, 200, "8921_s7",
+		0, 3),
+	PM8XXX_LDO(L29,      "8921_l29", 0, 1, 2050000, 2100000, 200, "8921_s8",
+		0, 4),
 
-	/*			ID       always_on pd enable_time supply */
-	PM8921_VREG_INIT_VS300(USB_OTG,  0,	   1, 0,	  "ext_5v"),
-	PM8921_VREG_INIT_VS300(HDMI_MVS, 0,	   1, 0,	  "ext_5v"),
+	/*	     ID        name      always_on pd en_t supply    reg_ID */
+	PM8XXX_VS300(USB_OTG,  "8921_usb_otg",  0, 1, 0,   "ext_5v", 5),
+	PM8XXX_VS300(HDMI_MVS, "8921_hdmi_mvs", 0, 1, 0,   "ext_5v", 6),
 };
 
 static struct rpm_regulator_init_data
diff --git a/arch/arm/mach-msm/board-8960-storage.c b/arch/arm/mach-msm/board-8960-storage.c
index dfcafd4..8b43d38 100644
--- a/arch/arm/mach-msm/board-8960-storage.c
+++ b/arch/arm/mach-msm/board-8960-storage.c
@@ -211,7 +211,7 @@
 };
 
 static unsigned int sdc3_sup_clk_rates[] = {
-	400000, 24000000, 48000000, 96000000
+	400000, 24000000, 48000000, 96000000, 192000000
 };
 
 #ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
@@ -247,11 +247,12 @@
 	.status_gpio	= PM8921_GPIO_PM_TO_SYS(26),
 	.status_irq	= PM8921_GPIO_IRQ(PM8921_IRQ_BASE, 26),
 	.irq_flags	= IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+	.is_status_gpio_active_low = true,
 #endif
 	.xpc_cap	= 1,
 	.uhs_caps	= (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
 			MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50 |
-			MMC_CAP_MAX_CURRENT_600)
+			MMC_CAP_UHS_SDR104 | MMC_CAP_MAX_CURRENT_600),
 };
 #endif
 
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 3ef7dea..a9424d6 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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 version 2 and
@@ -78,6 +78,7 @@
 #include <linux/ion.h>
 #include <mach/ion.h>
 #include <mach/mdm2.h>
+#include <mach/mdm-peripheral.h>
 
 #include <linux/fmem.h>
 
@@ -134,7 +135,7 @@
 #ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
 #define MSM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
 #else
-#define MSM_PMEM_SIZE 0x1C00000 /* 28 Mbytes */
+#define MSM_PMEM_SIZE 0x2800000 /* 40 Mbytes */
 #endif
 #define MSM_LIQUID_PMEM_SIZE 0x4000000 /* 64 Mbytes */
 
@@ -377,12 +378,19 @@
 	msm8960_reserve_table[MEMTYPE_EBI1].size += MSM_ION_ADSP_SIZE;
 #endif
 }
+
+static void __init reserve_mdp_memory(void)
+{
+	msm8960_mdp_writeback(msm8960_reserve_table);
+}
+
 static void __init msm8960_calculate_reserve_sizes(void)
 {
 	size_pmem_devices();
 	reserve_pmem_memory();
 	reserve_ion_memory();
 	reserve_fmem_memory();
+	reserve_mdp_memory();
 }
 
 static struct reserve_info msm8960_reserve_info __initdata = {
@@ -598,6 +606,55 @@
 #define QCE_SHARE_CE_RESOURCE	1
 #define QCE_CE_SHARED		0
 
+/* Begin Bus scaling definitions */
+static struct msm_bus_vectors crypto_hw_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_ADM_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_ADM_PORT1,
+		.dst = MSM_BUS_SLAVE_GSBI1_UART,
+		.ab = 0,
+		.ib = 0,
+	},
+};
+
+static struct msm_bus_vectors crypto_hw_active_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_ADM_PORT0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 70000000UL,
+		.ib = 70000000UL,
+	},
+	{
+		.src = MSM_BUS_MASTER_ADM_PORT1,
+		.dst = MSM_BUS_SLAVE_GSBI1_UART,
+		.ab = 2480000000UL,
+		.ib = 2480000000UL,
+	},
+};
+
+static struct msm_bus_paths crypto_hw_bus_scale_usecases[] = {
+	{
+		ARRAY_SIZE(crypto_hw_init_vectors),
+		crypto_hw_init_vectors,
+	},
+	{
+		ARRAY_SIZE(crypto_hw_active_vectors),
+		crypto_hw_active_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata crypto_hw_bus_scale_pdata = {
+		crypto_hw_bus_scale_usecases,
+		ARRAY_SIZE(crypto_hw_bus_scale_usecases),
+		.name = "cryptohw",
+};
+/* End Bus Scaling Definitions*/
+
 static struct resource qcrypto_resources[] = {
 	[0] = {
 		.start = QCE_0_BASE,
@@ -660,6 +717,7 @@
 	.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
 	.hw_key_support = QCE_HW_KEY_SUPPORT,
 	.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+	.bus_scale_table = &crypto_hw_bus_scale_pdata,
 };
 
 static struct platform_device qcrypto_device = {
@@ -682,6 +740,7 @@
 	.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
 	.hw_key_support = QCE_HW_KEY_SUPPORT,
 	.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+	.bus_scale_table = &crypto_hw_bus_scale_pdata,
 };
 
 static struct platform_device qcedev_device = {
@@ -773,8 +832,6 @@
 
 static void __init msm8960_init_irq(void)
 {
-	unsigned int i;
-
 	msm_mpm_irq_extn_init();
 	gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
 						(void *)MSM_QGIC_CPU_BASE);
@@ -784,15 +841,6 @@
 
 	writel_relaxed(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET);
 	mb();
-
-	/* FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
-	 * as they are configured as level, which does not play nice with
-	 * handle_percpu_irq.
-	 */
-	for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
-		if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
-			irq_set_handler(i, handle_percpu_irq);
-	}
 }
 
 static void __init msm8960_init_buses(void)
@@ -818,56 +866,6 @@
 #ifdef CONFIG_USB_MSM_OTG_72K
 static struct msm_otg_platform_data msm_otg_pdata;
 #else
-#define USB_5V_EN		42
-static void msm_hsusb_vbus_power(bool on)
-{
-	int rc;
-	static bool vbus_is_on;
-	static struct regulator *mvs_otg_switch;
-
-	if (vbus_is_on == on)
-		return;
-
-	if (on) {
-		mvs_otg_switch = regulator_get(&msm8960_device_otg.dev,
-					       "vbus_otg");
-		if (IS_ERR(mvs_otg_switch)) {
-			pr_err("Unable to get mvs_otg_switch\n");
-			return;
-		}
-
-		rc = gpio_request(PM8921_GPIO_PM_TO_SYS(USB_5V_EN),
-						"usb_5v_en");
-		if (rc < 0) {
-			pr_err("failed to request usb_5v_en gpio\n");
-			goto put_mvs_otg;
-		}
-
-		rc = gpio_direction_output(PM8921_GPIO_PM_TO_SYS(USB_5V_EN), 1);
-		if (rc) {
-			pr_err("%s: unable to set_direction for gpio [%d]\n",
-				__func__, PM8921_GPIO_PM_TO_SYS(USB_5V_EN));
-			goto free_usb_5v_en;
-		}
-
-		if (regulator_enable(mvs_otg_switch)) {
-			pr_err("unable to enable mvs_otg_switch\n");
-			goto err_ldo_gpio_set_dir;
-		}
-
-		vbus_is_on = true;
-		return;
-	}
-	regulator_disable(mvs_otg_switch);
-err_ldo_gpio_set_dir:
-	gpio_set_value_cansleep(PM8921_GPIO_PM_TO_SYS(USB_5V_EN), 0);
-free_usb_5v_en:
-	gpio_free(PM8921_GPIO_PM_TO_SYS(USB_5V_EN));
-put_mvs_otg:
-	regulator_put(mvs_otg_switch);
-	vbus_is_on = false;
-}
-
 static int wr_phy_init_seq[] = {
 	0x44, 0x80, /* set VBUS valid threshold
 			and disconnect valid threshold */
@@ -890,7 +888,6 @@
 	.phy_type		= SNPS_28NM_INTEGRATED_PHY,
 	.pclk_src_name		= "dfab_usb_hs_clk",
 	.pmic_id_irq		= PM8921_USB_ID_IN_IRQ(PM8921_IRQ_BASE),
-	.vbus_power		= msm_hsusb_vbus_power,
 	.power_budget		= 750,
 };
 #endif
@@ -1383,66 +1380,32 @@
 	0, 0, 0, 0, 0, 0,
 };
 
-#define MXT_TS_GPIO_IRQ		11
-#define MXT_TS_LDO_EN_GPIO	50
-#define MXT_TS_RESET_GPIO	52
+#define MXT_TS_GPIO_IRQ			11
+#define MXT_TS_LDO_EN_GPIO		50
+#define MXT_TS_RESET_GPIO		52
 
 static void mxt_init_hw_liquid(void)
 {
 	int rc;
 
-	rc = gpio_request(MXT_TS_GPIO_IRQ, "mxt_ts_irq_gpio");
-	if (rc) {
-		pr_err("%s: unable to request mxt_ts_irq gpio [%d]\n",
-				__func__, MXT_TS_GPIO_IRQ);
-		return;
-	}
-
-	rc = gpio_direction_input(MXT_TS_GPIO_IRQ);
-	if (rc) {
-		pr_err("%s: unable to set_direction for mxt_ts_irq gpio [%d]\n",
-				__func__, MXT_TS_GPIO_IRQ);
-		goto err_irq_gpio_req;
-	}
-
 	rc = gpio_request(MXT_TS_LDO_EN_GPIO, "mxt_ldo_en_gpio");
 	if (rc) {
-		pr_err("%s: unable to request mxt_ldo_en gpio [%d]\n",
-				__func__, MXT_TS_LDO_EN_GPIO);
-		goto err_irq_gpio_req;
+		pr_err("%s: unable to request mxt_ldo_en_gpio [%d]\n",
+			__func__, MXT_TS_LDO_EN_GPIO);
+		return;
 	}
 
 	rc = gpio_direction_output(MXT_TS_LDO_EN_GPIO, 1);
 	if (rc) {
-		pr_err("%s: unable to set_direction for mxt_ldo_en gpio [%d]\n",
-				__func__, MXT_TS_LDO_EN_GPIO);
+		pr_err("%s: unable to set_direction for mxt_ldo_en_gpio [%d]\n",
+			__func__, MXT_TS_LDO_EN_GPIO);
 		goto err_ldo_gpio_req;
 	}
 
-	rc = gpio_request(MXT_TS_RESET_GPIO, "mxt_reset_gpio");
-	if (rc) {
-		pr_err("%s: unable to request mxt_reset gpio [%d]\n",
-				__func__, MXT_TS_RESET_GPIO);
-		goto err_ldo_gpio_set_dir;
-	}
-
-	rc = gpio_direction_output(MXT_TS_RESET_GPIO, 1);
-	if (rc) {
-		pr_err("%s: unable to set_direction for mxt_reset gpio [%d]\n",
-				__func__, MXT_TS_RESET_GPIO);
-		goto err_reset_gpio_req;
-	}
-
 	return;
 
-err_reset_gpio_req:
-	gpio_free(MXT_TS_RESET_GPIO);
-err_ldo_gpio_set_dir:
-	gpio_set_value(MXT_TS_LDO_EN_GPIO, 0);
 err_ldo_gpio_req:
 	gpio_free(MXT_TS_LDO_EN_GPIO);
-err_irq_gpio_req:
-	gpio_free(MXT_TS_GPIO_IRQ);
 }
 
 static struct mxt_platform_data mxt_platform_data = {
@@ -1452,6 +1415,8 @@
 	.y_size			= 767,
 	.irqflags		= IRQF_TRIGGER_FALLING,
 	.i2c_pull_up		= true,
+	.reset_gpio		= MXT_TS_RESET_GPIO,
+	.irq_gpio		= MXT_TS_GPIO_IRQ,
 };
 
 static struct i2c_board_info mxt_device_info[] __initdata = {
@@ -1470,32 +1435,24 @@
 	},
 };
 
-static void gsbi_qup_i2c_gpio_config(int adap_id, int config_type)
-{
-}
-
 static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi4_pdata = {
 	.clk_freq = 100000,
 	.src_clk_rate = 24000000,
-	.msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
 };
 
 static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi3_pdata = {
 	.clk_freq = 100000,
 	.src_clk_rate = 24000000,
-	.msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
 };
 
 static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi10_pdata = {
 	.clk_freq = 100000,
 	.src_clk_rate = 24000000,
-	.msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
 };
 
 static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi12_pdata = {
 	.clk_freq = 100000,
 	.src_clk_rate = 24000000,
-	.msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
 };
 
 static struct msm_rpm_platform_data msm_rpm_data = {
@@ -1599,6 +1556,15 @@
 	},
 };
 
+static struct platform_device msm8960_device_ext_otg_sw_vreg __devinitdata = {
+	.name	= GPIO_REGULATOR_DEV_NAME,
+	.id	= PM8921_GPIO_PM_TO_SYS(42),
+	.dev	= {
+		.platform_data =
+			&msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_OTG_SW],
+	},
+};
+
 static struct platform_device msm8960_device_rpm_regulator __devinitdata = {
 	.name	= "rpm-regulator",
 	.id	= -1,
@@ -1635,6 +1601,7 @@
 	&msm_device_saw_core1,
 	&msm8960_device_ext_5v_vreg,
 	&msm8960_device_ssbi_pmic,
+	&msm8960_device_ext_otg_sw_vreg,
 	&msm8960_device_qup_spi_gsbi1,
 	&msm8960_device_qup_i2c_gsbi3,
 	&msm8960_device_qup_i2c_gsbi4,
@@ -1723,6 +1690,9 @@
 	&msm_voip,
 	&msm_lpa_pcm,
 	&msm_compr_dsp,
+	&msm_cpudai_incall_music_rx,
+	&msm_cpudai_incall_record_rx,
+	&msm_cpudai_incall_record_tx,
 
 #if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
 		defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
@@ -1748,6 +1718,8 @@
 	&msm_8960_q6_lpass,
 	&msm_8960_q6_mss_fw,
 	&msm_8960_q6_mss_sw,
+	&msm_8960_riva,
+	&msm_pil_tzapps,
 	&msm8960_device_otg,
 	&msm8960_device_gadget_peripheral,
 	&msm_device_hsusb_host,
@@ -1782,6 +1754,9 @@
 	&msm_cpudai_afe_02_tx,
 	&msm_pcm_afe,
 	&msm_compr_dsp,
+	&msm_cpudai_incall_music_rx,
+	&msm_cpudai_incall_record_rx,
+	&msm_cpudai_incall_record_tx,
 	&msm_pcm_hostless,
 	&msm_bus_apps_fabric,
 	&msm_bus_sys_fabric,
@@ -1961,31 +1936,6 @@
 	int                    len;
 };
 
-#ifdef CONFIG_MSM_CAMERA
-static struct i2c_board_info msm_camera_boardinfo[] __initdata = {
-#ifdef CONFIG_IMX074
-	{
-	I2C_BOARD_INFO("imx074", 0x1A),
-	},
-#endif
-#ifdef CONFIG_OV2720
-	{
-	I2C_BOARD_INFO("ov2720", 0x6C),
-	},
-#endif
-#ifdef CONFIG_MT9M114
-	{
-	I2C_BOARD_INFO("mt9m114", 0x48),
-	},
-#endif
-#ifdef CONFIG_MSM_CAMERA_FLASH_SC628A
-	{
-	I2C_BOARD_INFO("sc628a", 0x6E),
-	},
-#endif
-};
-#endif
-
 /* Sensors DSPS platform data */
 #ifdef CONFIG_MSM_DSPS
 #define DSPS_PIL_GENERIC_NAME		"dsps"
@@ -2004,6 +1954,33 @@
 #endif /* CONFIG_MSM_DSPS */
 }
 
+static int hsic_peripheral_status = 1;
+static DEFINE_MUTEX(hsic_status_lock);
+
+void peripheral_connect()
+{
+	mutex_lock(&hsic_status_lock);
+	if (hsic_peripheral_status)
+		goto out;
+	platform_device_add(&msm_device_hsic_host);
+	hsic_peripheral_status = 1;
+out:
+	mutex_unlock(&hsic_status_lock);
+}
+EXPORT_SYMBOL(peripheral_connect);
+
+void peripheral_disconnect()
+{
+	mutex_lock(&hsic_status_lock);
+	if (!hsic_peripheral_status)
+		goto out;
+	platform_device_del(&msm_device_hsic_host);
+	hsic_peripheral_status = 0;
+out:
+	mutex_unlock(&hsic_status_lock);
+}
+EXPORT_SYMBOL(peripheral_disconnect);
+
 static void __init msm8960_init_hsic(void)
 {
 #ifdef CONFIG_USB_EHCI_MSM_HSIC
@@ -2045,14 +2022,6 @@
 };
 
 static struct i2c_registry msm8960_i2c_devices[] __initdata = {
-#ifdef CONFIG_MSM_CAMERA
-	{
-		I2C_SURF | I2C_FFA | I2C_FLUID | I2C_LIQUID | I2C_RUMI,
-		MSM_8960_GSBI4_QUP_I2C_BUS_ID,
-		msm_camera_boardinfo,
-		ARRAY_SIZE(msm_camera_boardinfo),
-	},
-#endif
 #ifdef CONFIG_ISL9519_CHARGER
 	{
 		I2C_LIQUID,
@@ -2099,6 +2068,14 @@
 #ifdef CONFIG_I2C
 	u8 mach_mask = 0;
 	int i;
+#ifdef CONFIG_MSM_CAMERA
+	struct i2c_registry msm8960_camera_i2c_devices = {
+		I2C_SURF | I2C_FFA | I2C_FLUID | I2C_LIQUID | I2C_RUMI,
+		MSM_8960_GSBI4_QUP_I2C_BUS_ID,
+		msm8960_camera_board_info.board_info,
+		msm8960_camera_board_info.num_i2c_board_info,
+	};
+#endif
 
 	/* Build the matching 'supported_machs' bitmask */
 	if (machine_is_msm8960_cdp())
@@ -2123,6 +2100,12 @@
 						msm8960_i2c_devices[i].info,
 						msm8960_i2c_devices[i].len);
 	}
+#ifdef CONFIG_MSM_CAMERA
+	if (msm8960_camera_i2c_devices.machs & mach_mask)
+		i2c_register_board_info(msm8960_camera_i2c_devices.bus,
+			msm8960_camera_i2c_devices.info,
+			msm8960_camera_i2c_devices.len);
+#endif
 #endif
 }
 
@@ -2278,6 +2261,7 @@
 	.map_io = msm8960_map_io,
 	.reserve = msm8960_reserve,
 	.init_irq = msm8960_init_irq,
+	.handle_irq = gic_handle_irq,
 	.timer = &msm_timer,
 	.init_machine = msm8960_sim_init,
 	.init_early = msm8960_allocate_memory_regions,
@@ -2288,6 +2272,7 @@
 	.map_io = msm8960_map_io,
 	.reserve = msm8960_reserve,
 	.init_irq = msm8960_init_irq,
+	.handle_irq = gic_handle_irq,
 	.timer = &msm_timer,
 	.init_machine = msm8960_rumi3_init,
 	.init_early = msm8960_allocate_memory_regions,
@@ -2298,6 +2283,7 @@
 	.map_io = msm8960_map_io,
 	.reserve = msm8960_reserve,
 	.init_irq = msm8960_init_irq,
+	.handle_irq = gic_handle_irq,
 	.timer = &msm_timer,
 	.init_machine = msm8960_cdp_init,
 	.init_early = msm8960_allocate_memory_regions,
@@ -2308,6 +2294,7 @@
 	.map_io = msm8960_map_io,
 	.reserve = msm8960_reserve,
 	.init_irq = msm8960_init_irq,
+	.handle_irq = gic_handle_irq,
 	.timer = &msm_timer,
 	.init_machine = msm8960_cdp_init,
 	.init_early = msm8960_allocate_memory_regions,
@@ -2318,6 +2305,7 @@
 	.map_io = msm8960_map_io,
 	.reserve = msm8960_reserve,
 	.init_irq = msm8960_init_irq,
+	.handle_irq = gic_handle_irq,
 	.timer = &msm_timer,
 	.init_machine = msm8960_cdp_init,
 	.init_early = msm8960_allocate_memory_regions,
@@ -2328,6 +2316,7 @@
 	.map_io = msm8960_map_io,
 	.reserve = msm8960_reserve,
 	.init_irq = msm8960_init_irq,
+	.handle_irq = gic_handle_irq,
 	.timer = &msm_timer,
 	.init_machine = msm8960_cdp_init,
 	.init_early = msm8960_allocate_memory_regions,
diff --git a/arch/arm/mach-msm/board-8960.h b/arch/arm/mach-msm/board-8960.h
index e22868f..5f4f3a0 100644
--- a/arch/arm/mach-msm/board-8960.h
+++ b/arch/arm/mach-msm/board-8960.h
@@ -15,9 +15,11 @@
 
 #include <linux/regulator/gpio-regulator.h>
 #include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/i2c.h>
 #include <linux/i2c/sx150x.h>
 #include <mach/irqs.h>
 #include <mach/rpm-regulator.h>
+#include <mach/msm_memtypes.h>
 
 /* Macros assume PMIC GPIOs and MPPs start at 1 */
 #define PM8921_GPIO_BASE		NR_GPIO_IRQS
@@ -26,7 +28,7 @@
 #define PM8921_MPP_PM_TO_SYS(pm_gpio)	(pm_gpio - 1 + PM8921_MPP_BASE)
 #define PM8921_IRQ_BASE			(NR_MSM_IRQS + NR_GPIO_IRQS)
 
-extern struct pm8921_regulator_platform_data
+extern struct pm8xxx_regulator_platform_data
 	msm_pm8921_regulator_pdata[] __devinitdata;
 
 extern int msm_pm8921_regulator_pdata_len __devinitdata;
@@ -34,6 +36,7 @@
 #define GPIO_VREG_ID_EXT_5V		0
 #define GPIO_VREG_ID_EXT_L2		1
 #define GPIO_VREG_ID_EXT_3P3V		2
+#define GPIO_VREG_ID_EXT_OTG_SW		3
 
 extern struct gpio_regulator_platform_data
 	msm_gpio_regulator_pdata[] __devinitdata;
@@ -69,6 +72,7 @@
 #endif
 
 extern struct sx150x_platform_data msm8960_sx150x_data[];
+extern struct msm_camera_board_info msm8960_camera_board_info;
 void msm8960_init_cam(void);
 void msm8960_init_fb(void);
 void msm8960_init_pmic(void);
@@ -76,7 +80,7 @@
 int msm8960_init_gpiomux(void);
 void msm8960_allocate_fb_region(void);
 void msm8960_pm8921_gpio_mpp_init(void);
-
+void msm8960_mdp_writeback(struct memtype_reserve *reserve_table);
 #define PLATFORM_IS_CHARM25() \
 	(machine_is_msm8960_cdp() && \
 		(socinfo_get_platform_subtype() == 1) \
diff --git a/arch/arm/mach-msm/board-9615-gpiomux.c b/arch/arm/mach-msm/board-9615-gpiomux.c
new file mode 100644
index 0000000..4baa851
--- /dev/null
+++ b/arch/arm/mach-msm/board-9615-gpiomux.c
@@ -0,0 +1,252 @@
+/* Copyright (c) 2011, Code Aurora Forum. 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 version 2 and
+ * only 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.
+ *
+ */
+
+#include <linux/init.h>
+#include <mach/gpiomux.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include "board-9615.h"
+
+static struct gpiomux_setting ps_hold = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi4 = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi5 = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi3 = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gsbi3_cs1_config = {
+	.func = GPIOMUX_FUNC_4,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+#ifdef CONFIG_LTC4088_CHARGER
+static struct gpiomux_setting ltc4088_chg_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+#endif
+
+static struct gpiomux_setting sdcc2_clk_actv_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_16MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting sdcc2_cmd_data_0_3_actv_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting sdcc2_suspend_cfg = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct msm_gpiomux_config msm9615_sdcc2_configs[] __initdata = {
+	{
+		/* SDC2_DATA_0 */
+		.gpio      = 25,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+		},
+	},
+	{
+		/* SDC2_DATA_1 */
+		.gpio      = 26,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_cmd_data_0_3_actv_cfg,
+		},
+	},
+	{
+		/* SDC2_DATA_2 */
+		.gpio      = 27,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+		},
+	},
+	{
+		/* SDC2_DATA_3 */
+		.gpio      = 28,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+		},
+	},
+	{
+		/* SDC2_CMD */
+		.gpio      = 29,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_cmd_data_0_3_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+		},
+	},
+	{
+		/* SDC2_CLK */
+		.gpio      = 30,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &sdcc2_clk_actv_cfg,
+			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+		},
+	},
+};
+
+struct msm_gpiomux_config msm9615_ps_hold_config[] __initdata = {
+	{
+		.gpio = 83,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ps_hold,
+		},
+	},
+};
+
+#ifdef CONFIG_LTC4088_CHARGER
+static struct msm_gpiomux_config
+	msm9615_ltc4088_charger_config[] __initdata = {
+	{
+		.gpio = 4,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ltc4088_chg_cfg,
+		},
+	},
+	{
+		.gpio = 6,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ltc4088_chg_cfg,
+		},
+	},
+	{
+		.gpio = 7,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &ltc4088_chg_cfg,
+		},
+	},
+};
+#endif
+
+struct msm_gpiomux_config msm9615_gsbi_configs[] __initdata = {
+	{
+		.gpio      = 8,		/* GSBI3 QUP SPI_CLK */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi3,
+		},
+	},
+	{
+		.gpio      = 9,		/* GSBI3 QUP SPI_CS_N */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi3,
+		},
+	},
+	{
+		.gpio      = 10,	/* GSBI3 QUP SPI_DATA_MISO */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi3,
+		},
+	},
+	{
+		.gpio      = 11,	/* GSBI3 QUP SPI_DATA_MOSI */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi3,
+		},
+	},
+	{
+		.gpio      = 12,	/* GSBI4 UART */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi4,
+		},
+	},
+	{
+		.gpio      = 13,	/* GSBI4 UART */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi4,
+		},
+	},
+	{
+		.gpio      = 14,	/* GSBI4 UART */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi4,
+		},
+	},
+	{
+		.gpio      = 15,	/* GSBI4 UART */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi4,
+		},
+	},
+	{
+		.gpio      = 16,	/* GSBI5 I2C QUP SCL */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi5,
+		},
+	},
+	{
+		.gpio      = 17,	/* GSBI5 I2C QUP SDA */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi5,
+		},
+	},
+	{
+		/* GPIO 19 can be used for I2C/UART on GSBI5 */
+		.gpio      = 19,	/* GSBI3 QUP SPI_CS_1 */
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &gsbi3_cs1_config,
+		},
+	},
+};
+
+int __init msm9615_init_gpiomux(void)
+{
+	int rc;
+
+	rc = msm_gpiomux_init(NR_GPIO_IRQS);
+	if (rc) {
+		pr_err(KERN_ERR "msm_gpiomux_init failed %d\n", rc);
+		return rc;
+	}
+	msm_gpiomux_install(msm9615_gsbi_configs,
+			ARRAY_SIZE(msm9615_gsbi_configs));
+
+	msm_gpiomux_install(msm9615_ps_hold_config,
+			ARRAY_SIZE(msm9615_ps_hold_config));
+	msm_gpiomux_install(msm9615_sdcc2_configs,
+			ARRAY_SIZE(msm9615_sdcc2_configs));
+#ifdef CONFIG_LTC4088_CHARGER
+	msm_gpiomux_install(msm9615_ltc4088_charger_config,
+			ARRAY_SIZE(msm9615_ltc4088_charger_config));
+#endif
+
+	return 0;
+}
diff --git a/arch/arm/mach-msm/board-9615-regulator.c b/arch/arm/mach-msm/board-9615-regulator.c
index 7cf4a8c..14e84a6 100644
--- a/arch/arm/mach-msm/board-9615-regulator.c
+++ b/arch/arm/mach-msm/board-9615-regulator.c
@@ -11,7 +11,7 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/regulator/pm8018-regulator.h>
+#include <linux/regulator/pm8xxx-regulator.h>
 #include <linux/regulator/gpio-regulator.h>
 #include <mach/rpm-regulator.h>
 
@@ -91,9 +91,9 @@
 	REGULATOR_SUPPLY("sdc_vdd",		"msm_sdcc.1"),
 };
 
-#define PM8018_VREG_INIT(_id, _min_uV, _max_uV, _modes, _ops, _apply_uV, \
-			 _pull_down, _always_on, _supply_regulator, \
-			 _system_uA, _enable_time) \
+#define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
+			 _apply_uV, _pull_down, _always_on, _supply_regulator, \
+			 _system_uA, _enable_time, _reg_id) \
 	{ \
 		.init_data = { \
 			.constraints = { \
@@ -104,63 +104,67 @@
 				.input_uV		= _max_uV, \
 				.apply_uV		= _apply_uV, \
 				.always_on		= _always_on, \
+				.name			= _name, \
 			}, \
 			.num_consumer_supplies	= \
 					ARRAY_SIZE(vreg_consumers_##_id), \
 			.consumer_supplies	= vreg_consumers_##_id, \
 			.supply_regulator	= _supply_regulator, \
 		}, \
-		.id			= PM8018_VREG_ID_##_id, \
+		.id			= _reg_id, \
 		.pull_down_enable	= _pull_down, \
 		.system_uA		= _system_uA, \
 		.enable_time		= _enable_time, \
 	}
 
-#define PM8018_VREG_INIT_LDO(_id, _always_on, _pull_down, _min_uV, _max_uV, \
-		_enable_time, _supply_regulator, _system_uA) \
-	PM8018_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+#define PM8XXX_LDO(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+		_enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
 		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
 		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
 		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
-		_supply_regulator, _system_uA, _enable_time)
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
 
-#define PM8018_VREG_INIT_NLDO1200(_id, _always_on, _pull_down, _min_uV, \
-		_max_uV, _enable_time, _supply_regulator, _system_uA) \
-	PM8018_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+#define PM8XXX_NLDO1200(_id, _name, _always_on, _pull_down, _min_uV, \
+		_max_uV, _enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
 		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
 		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
 		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
-		_supply_regulator, _system_uA, _enable_time)
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
 
-#define PM8018_VREG_INIT_SMPS(_id, _always_on, _pull_down, _min_uV, _max_uV, \
-		_enable_time, _supply_regulator, _system_uA) \
-	PM8018_VREG_INIT(_id, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
+#define PM8XXX_SMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
+		_enable_time, _supply_regulator, _system_uA, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL \
 		| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
 		REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
 		REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
-		_supply_regulator, _system_uA, _enable_time)
+		_supply_regulator, _system_uA, _enable_time, _reg_id)
 
-#define PM8018_VREG_INIT_VS(_id, _always_on, _pull_down, _enable_time, \
-		_supply_regulator) \
-	PM8018_VREG_INIT(_id, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, _pull_down, \
-		_always_on, _supply_regulator, 0, _enable_time)
+#define PM8XXX_VS(_id, _name, _always_on, _pull_down, _enable_time, \
+		_supply_regulator, _reg_id) \
+	PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \
+		_pull_down, _always_on, _supply_regulator, 0, _enable_time, \
+		_reg_id)
 
 /* Pin control initialization */
-#define PM8018_PC_INIT(_id, _always_on, _pin_fn, _pin_ctrl, _supply_regulator) \
+#define PM8XXX_PC(_id, _name, _always_on, _pin_fn, _pin_ctrl, \
+		  _supply_regulator, _reg_id) \
 	{ \
 		.init_data = { \
 			.constraints = { \
 				.valid_ops_mask	= REGULATOR_CHANGE_STATUS, \
 				.always_on	= _always_on, \
+				.name		= _name, \
 			}, \
 			.num_consumer_supplies	= \
 					ARRAY_SIZE(vreg_consumers_##_id##_PC), \
 			.consumer_supplies	= vreg_consumers_##_id##_PC, \
 			.supply_regulator  = _supply_regulator, \
 		}, \
-		.id	  = PM8018_VREG_ID_##_id##_PC, \
-		.pin_fn	  = PM8018_VREG_PIN_FN_##_pin_fn, \
-		.pin_ctrl = _pin_ctrl, \
+		.id		= _reg_id, \
+		.pin_fn		= PM8XXX_VREG_PIN_FN_##_pin_fn, \
+		.pin_ctrl	= _pin_ctrl, \
 	}
 
 #define RPM_INIT(_id, _min_uV, _max_uV, _modes, _ops, _apply_uV, _default_uV, \
@@ -266,7 +270,7 @@
 };
 
 /* PM8018 regulator constraints */
-struct pm8018_regulator_platform_data
+struct pm8xxx_regulator_platform_data
 msm_pm8018_regulator_pdata[] __devinitdata = {
 };
 
diff --git a/arch/arm/mach-msm/board-9615-storage.c b/arch/arm/mach-msm/board-9615-storage.c
new file mode 100644
index 0000000..95c87bf
--- /dev/null
+++ b/arch/arm/mach-msm/board-9615-storage.c
@@ -0,0 +1,228 @@
+/* Copyright (c) 2011, Code Aurora Forum. 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 version 2 and
+ * only 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.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <asm/mach-types.h>
+#include <asm/mach/mmc.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+#include "devices.h"
+
+#if (defined(CONFIG_MMC_MSM_SDC1_SUPPORT) \
+		|| defined(CONFIG_MMC_MSM_SDC2_SUPPORT))
+
+#define GPIO_SDC1_HW_DET	80
+#define GPIO_SDC2_DAT1_WAKEUP	26
+
+/* MDM9x15 has 2 SDCC controllers */
+enum sdcc_controllers {
+	SDCC1,
+	SDCC2,
+	MAX_SDCC_CONTROLLER
+};
+
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+/* All SDCC controllers requires VDD/VCC voltage */
+static struct msm_mmc_reg_data mmc_vdd_reg_data[MAX_SDCC_CONTROLLER] = {
+	/* SDCC1 : External card slot connected */
+	[SDCC1] = {
+		.name = "sdc_vdd",
+		/*
+		 * This is a gpio-regulator and does not support
+		 * regulator_set_voltage and regulator_set_optimum_mode
+		 */
+		.high_vol_level = 2950000,
+		.low_vol_level = 2950000,
+		.hpm_uA = 600000, /* 600mA */
+	}
+};
+
+/* All SDCC controllers may require voting for VDD PAD voltage */
+static struct msm_mmc_reg_data mmc_vddp_reg_data[MAX_SDCC_CONTROLLER] = {
+	/* SDCC1 : External card slot connected */
+	[SDCC1] = {
+		.name = "sdc_vddp",
+		.high_vol_level = 2950000,
+		.low_vol_level = 1850000,
+		.always_on = true,
+		.lpm_sup = true,
+		/* Max. Active current required is 16 mA */
+		.hpm_uA = 16000,
+		/*
+		 * Sleep current required is ~300 uA. But min. vote can be
+		 * in terms of mA (min. 1 mA). So let's vote for 2 mA
+		 * during sleep.
+		 */
+		.lpm_uA = 2000,
+	}
+};
+
+static struct msm_mmc_slot_reg_data mmc_slot_vreg_data[MAX_SDCC_CONTROLLER] = {
+	/* SDCC1 : External card slot connected */
+	[SDCC1] = {
+		.vdd_data = &mmc_vdd_reg_data[SDCC1],
+		.vddp_data = &mmc_vddp_reg_data[SDCC1],
+	}
+};
+
+/* SDC1 pad data */
+static struct msm_mmc_pad_drv sdc1_pad_drv_on_cfg[] = {
+	{TLMM_HDRV_SDC1_CLK, GPIO_CFG_16MA},
+	{TLMM_HDRV_SDC1_CMD, GPIO_CFG_10MA},
+	{TLMM_HDRV_SDC1_DATA, GPIO_CFG_10MA}
+};
+
+static struct msm_mmc_pad_drv sdc1_pad_drv_off_cfg[] = {
+	{TLMM_HDRV_SDC1_CLK, GPIO_CFG_2MA},
+	{TLMM_HDRV_SDC1_CMD, GPIO_CFG_2MA},
+	{TLMM_HDRV_SDC1_DATA, GPIO_CFG_2MA}
+};
+
+static struct msm_mmc_pad_pull sdc1_pad_pull_on_cfg[] = {
+	{TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
+	{TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_UP},
+	{TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_UP}
+};
+
+static struct msm_mmc_pad_pull sdc1_pad_pull_off_cfg[] = {
+	{TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
+	{TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_DOWN},
+	{TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_DOWN}
+};
+
+static struct msm_mmc_pad_pull_data mmc_pad_pull_data[MAX_SDCC_CONTROLLER] = {
+	[SDCC1] = {
+		.on = sdc1_pad_pull_on_cfg,
+		.off = sdc1_pad_pull_off_cfg,
+		.size = ARRAY_SIZE(sdc1_pad_pull_on_cfg)
+	},
+};
+
+static struct msm_mmc_pad_drv_data mmc_pad_drv_data[MAX_SDCC_CONTROLLER] = {
+	[SDCC1] = {
+		.on = sdc1_pad_drv_on_cfg,
+		.off = sdc1_pad_drv_off_cfg,
+		.size = ARRAY_SIZE(sdc1_pad_drv_on_cfg)
+	},
+};
+
+static struct msm_mmc_pad_data mmc_pad_data[MAX_SDCC_CONTROLLER] = {
+	[SDCC1] = {
+		.pull = &mmc_pad_pull_data[SDCC1],
+		.drv = &mmc_pad_drv_data[SDCC1]
+	},
+};
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+
+static struct msm_mmc_gpio sdc2_gpio_cfg[] = {
+	{25, "sdc2_dat_0"},
+	{26, "sdc2_dat_1"},
+	{27, "sdc2_dat_2"},
+	{28, "sdc2_dat_3"},
+	{29, "sdc2_cmd"},
+	{30, "sdc2_clk"},
+};
+
+static struct msm_mmc_gpio_data mmc_gpio_data[MAX_SDCC_CONTROLLER] = {
+	[SDCC2] = {
+		.gpio = sdc2_gpio_cfg,
+		.size = ARRAY_SIZE(sdc2_gpio_cfg),
+	},
+};
+#endif
+
+static struct msm_mmc_pin_data mmc_slot_pin_data[MAX_SDCC_CONTROLLER] = {
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+	[SDCC1] = {
+		.is_gpio = 0,
+		.pad_data = &mmc_pad_data[SDCC1],
+	},
+#endif
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+	[SDCC2] = {
+		.is_gpio = 1,
+		.gpio_data = &mmc_gpio_data[SDCC2],
+	},
+#endif
+};
+
+#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+static unsigned int sdc1_sup_clk_rates[] = {
+	400000, 24000000, 48000000
+};
+
+static struct mmc_platform_data sdc1_data = {
+	.ocr_mask       = MMC_VDD_27_28 | MMC_VDD_28_29,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.sup_clk_table	= sdc1_sup_clk_rates,
+	.sup_clk_cnt	= ARRAY_SIZE(sdc1_sup_clk_rates),
+	.pclk_src_dfab	= true,
+	.vreg_data	= &mmc_slot_vreg_data[SDCC1],
+	.pin_data	= &mmc_slot_pin_data[SDCC1],
+#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
+	.status_gpio	= GPIO_SDC1_HW_DET,
+	.status_irq	= MSM_GPIO_TO_INT(GPIO_SDC1_HW_DET),
+	.irq_flags	= IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+#endif
+	.xpc_cap	= 1,
+	.uhs_caps	= (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+			   MMC_CAP_MAX_CURRENT_400)
+};
+static struct mmc_platform_data *msm9615_sdc1_pdata = &sdc1_data;
+#else
+static struct mmc_platform_data *msm9615_sdc1_pdata;
+#endif
+
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+static unsigned int sdc2_sup_clk_rates[] = {
+	400000, 24000000, 48000000
+};
+
+static struct mmc_platform_data sdc2_data = {
+	.ocr_mask       = MMC_VDD_27_28 | MMC_VDD_28_29,
+	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
+	.sup_clk_table	= sdc2_sup_clk_rates,
+	.sup_clk_cnt	= ARRAY_SIZE(sdc2_sup_clk_rates),
+	.pclk_src_dfab	= 1,
+	.pin_data	= &mmc_slot_pin_data[SDCC2],
+#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
+	.sdiowakeup_irq = MSM_GPIO_TO_INT(GPIO_SDC2_DAT1_WAKEUP),
+#endif
+};
+static struct mmc_platform_data *msm9615_sdc2_pdata = &sdc2_data;
+#else
+static struct mmc_platform_data *msm9615_sdc2_pdata;
+#endif
+
+void __init msm9615_init_mmc(void)
+{
+	if (msm9615_sdc1_pdata) {
+		/* SDC1: External card slot for SD/MMC cards */
+		msm_add_sdcc(1, msm9615_sdc1_pdata);
+	}
+
+	if (msm9615_sdc2_pdata) {
+		/* SDC2: External card slot used for WLAN */
+		msm_add_sdcc(2, msm9615_sdc2_pdata);
+	}
+}
+#else
+void __init msm9615_init_mmc(void)
+{
+}
+#endif
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index f5bd44d..ec2a71d 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -15,19 +15,19 @@
 #include <linux/i2c.h>
 #include <linux/msm_ssbi.h>
 #include <linux/memblock.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/mmc.h>
-#include <mach/board.h>
-#include <mach/msm_iomap.h>
-#include <mach/gpio.h>
-#include <mach/gpiomux.h>
-#include <mach/msm_spi.h>
 #include <linux/usb/android.h>
 #include <linux/usb/msm_hsusb.h>
 #include <linux/mfd/pm8xxx/pm8xxx-adc.h>
 #include <linux/leds.h>
 #include <linux/leds-pm8xxx.h>
+#include <linux/power/ltc4088-charger.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/hardware/gic.h>
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+#include <mach/gpio.h>
+#include <mach/msm_spi.h>
 #include <mach/msm_bus_board.h>
 #include "timer.h"
 #include "devices.h"
@@ -35,7 +35,6 @@
 #include "cpuidle.h"
 #include "pm.h"
 #include "acpuclock.h"
-#include <linux/power/ltc4088-charger.h>
 #include "pm-boot.h"
 
 static struct pm8xxx_adc_amux pm8018_adc_channels_data[] = {
@@ -181,423 +180,6 @@
 	},
 };
 
-static struct gpiomux_setting ps_hold = {
-	.func = GPIOMUX_FUNC_1,
-	.drv = GPIOMUX_DRV_8MA,
-	.pull = GPIOMUX_PULL_NONE,
-};
-
-static struct gpiomux_setting gsbi4 = {
-	.func = GPIOMUX_FUNC_1,
-	.drv = GPIOMUX_DRV_8MA,
-	.pull = GPIOMUX_PULL_NONE,
-};
-
-static struct gpiomux_setting gsbi5 = {
-	.func = GPIOMUX_FUNC_1,
-	.drv = GPIOMUX_DRV_8MA,
-	.pull = GPIOMUX_PULL_NONE,
-};
-
-static struct gpiomux_setting gsbi3 = {
-	.func = GPIOMUX_FUNC_1,
-	.drv = GPIOMUX_DRV_8MA,
-	.pull = GPIOMUX_PULL_NONE,
-};
-
-static struct gpiomux_setting gsbi3_cs1_config = {
-	.func = GPIOMUX_FUNC_4,
-	.drv = GPIOMUX_DRV_8MA,
-	.pull = GPIOMUX_PULL_NONE,
-};
-
-#ifdef CONFIG_LTC4088_CHARGER
-static struct gpiomux_setting ltc4088_chg_cfg = {
-	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_8MA,
-	.pull = GPIOMUX_PULL_NONE,
-};
-#endif
-
-struct msm_gpiomux_config msm9615_ps_hold_config[] __initdata = {
-	{
-		.gpio = 83,
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &ps_hold,
-		},
-	},
-};
-
-#ifdef CONFIG_LTC4088_CHARGER
-static struct msm_gpiomux_config
-	msm9615_ltc4088_charger_config[] __initdata = {
-	{
-		.gpio = 4,
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &ltc4088_chg_cfg,
-		},
-	},
-	{
-		.gpio = 6,
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &ltc4088_chg_cfg,
-		},
-	},
-	{
-		.gpio = 7,
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &ltc4088_chg_cfg,
-		},
-	},
-};
-#endif
-
-struct msm_gpiomux_config msm9615_gsbi_configs[] __initdata = {
-	{
-		.gpio      = 8,		/* GSBI3 QUP SPI_CLK */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gsbi3,
-		},
-	},
-	{
-		.gpio      = 9,		/* GSBI3 QUP SPI_CS_N */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gsbi3,
-		},
-	},
-	{
-		.gpio      = 10,	/* GSBI3 QUP SPI_DATA_MISO */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gsbi3,
-		},
-	},
-	{
-		.gpio      = 11,	/* GSBI3 QUP SPI_DATA_MOSI */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gsbi3,
-		},
-	},
-	{
-		.gpio      = 12,	/* GSBI4 UART */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gsbi4,
-		},
-	},
-	{
-		.gpio      = 13,	/* GSBI4 UART */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gsbi4,
-		},
-	},
-	{
-		.gpio      = 14,	/* GSBI4 UART */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gsbi4,
-		},
-	},
-	{
-		.gpio      = 15,	/* GSBI4 UART */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gsbi4,
-		},
-	},
-	{
-		.gpio      = 16,	/* GSBI5 I2C QUP SCL */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gsbi5,
-		},
-	},
-	{
-		.gpio      = 17,	/* GSBI5 I2C QUP SDA */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gsbi5,
-		},
-	},
-	{
-		/* GPIO 19 can be used for I2C/UART on GSBI5 */
-		.gpio      = 19,	/* GSBI3 QUP SPI_CS_1 */
-		.settings = {
-			[GPIOMUX_SUSPENDED] = &gsbi3_cs1_config,
-		},
-	},
-};
-
-#if (defined(CONFIG_MMC_MSM_SDC1_SUPPORT)\
-	|| defined(CONFIG_MMC_MSM_SDC2_SUPPORT))
-
-#define GPIO_SDC1_HW_DET	80
-#define GPIO_SDC2_DAT1_WAKEUP	26
-
-/* MDM9x15 has 2 SDCC controllers */
-enum sdcc_controllers {
-	SDCC1,
-	SDCC2,
-	MAX_SDCC_CONTROLLER
-};
-
-#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
-/* All SDCC controllers requires VDD/VCC voltage */
-static struct msm_mmc_reg_data mmc_vdd_reg_data[MAX_SDCC_CONTROLLER] = {
-	/* SDCC1 : External card slot connected */
-	[SDCC1] = {
-		.name = "sdc_vdd",
-		/*
-		 * This is a gpio-regulator and does not support
-		 * regulator_set_voltage and regulator_set_optimum_mode
-		 */
-		.high_vol_level = 2950000,
-		.low_vol_level = 2950000,
-		.hpm_uA = 600000, /* 600mA */
-	}
-};
-
-/* All SDCC controllers may require voting for VDD PAD voltage */
-static struct msm_mmc_reg_data mmc_vddp_reg_data[MAX_SDCC_CONTROLLER] = {
-	/* SDCC1 : External card slot connected */
-	[SDCC1] = {
-		.name = "sdc_vddp",
-		.high_vol_level = 2950000,
-		.low_vol_level = 1850000,
-		.always_on = true,
-		.lpm_sup = true,
-		/* Max. Active current required is 16 mA */
-		.hpm_uA = 16000,
-		/*
-		 * Sleep current required is ~300 uA. But min. vote can be
-		 * in terms of mA (min. 1 mA). So let's vote for 2 mA
-		 * during sleep.
-		 */
-		.lpm_uA = 2000,
-	}
-};
-
-static struct msm_mmc_slot_reg_data mmc_slot_vreg_data[MAX_SDCC_CONTROLLER] = {
-	/* SDCC1 : External card slot connected */
-	[SDCC1] = {
-		.vdd_data = &mmc_vdd_reg_data[SDCC1],
-		.vddp_data = &mmc_vddp_reg_data[SDCC1],
-	}
-};
-
-/* SDC1 pad data */
-static struct msm_mmc_pad_drv sdc1_pad_drv_on_cfg[] = {
-	{TLMM_HDRV_SDC1_CLK, GPIO_CFG_16MA},
-	{TLMM_HDRV_SDC1_CMD, GPIO_CFG_10MA},
-	{TLMM_HDRV_SDC1_DATA, GPIO_CFG_10MA}
-};
-
-static struct msm_mmc_pad_drv sdc1_pad_drv_off_cfg[] = {
-	{TLMM_HDRV_SDC1_CLK, GPIO_CFG_2MA},
-	{TLMM_HDRV_SDC1_CMD, GPIO_CFG_2MA},
-	{TLMM_HDRV_SDC1_DATA, GPIO_CFG_2MA}
-};
-
-static struct msm_mmc_pad_pull sdc1_pad_pull_on_cfg[] = {
-	{TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
-	{TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_UP},
-	{TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_UP}
-};
-
-static struct msm_mmc_pad_pull sdc1_pad_pull_off_cfg[] = {
-	{TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
-	{TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_DOWN},
-	{TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_DOWN}
-};
-
-static struct msm_mmc_pad_pull_data mmc_pad_pull_data[MAX_SDCC_CONTROLLER] = {
-	[SDCC1] = {
-		.on = sdc1_pad_pull_on_cfg,
-		.off = sdc1_pad_pull_off_cfg,
-		.size = ARRAY_SIZE(sdc1_pad_pull_on_cfg)
-	},
-};
-
-static struct msm_mmc_pad_drv_data mmc_pad_drv_data[MAX_SDCC_CONTROLLER] = {
-	[SDCC1] = {
-		.on = sdc1_pad_drv_on_cfg,
-		.off = sdc1_pad_drv_off_cfg,
-		.size = ARRAY_SIZE(sdc1_pad_drv_on_cfg)
-	},
-};
-
-static struct msm_mmc_pad_data mmc_pad_data[MAX_SDCC_CONTROLLER] = {
-	[SDCC1] = {
-		.pull = &mmc_pad_pull_data[SDCC1],
-		.drv = &mmc_pad_drv_data[SDCC1]
-	},
-};
-#endif
-
-#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
-static struct gpiomux_setting sdcc2_clk_actv_cfg = {
-	.func = GPIOMUX_FUNC_1,
-	.drv = GPIOMUX_DRV_16MA,
-	.pull = GPIOMUX_PULL_NONE,
-};
-
-static struct gpiomux_setting sdcc2_cmd_data_0_3_actv_cfg = {
-	.func = GPIOMUX_FUNC_1,
-	.drv = GPIOMUX_DRV_8MA,
-	.pull = GPIOMUX_PULL_UP,
-};
-
-static struct gpiomux_setting sdcc2_suspend_cfg = {
-	.func = GPIOMUX_FUNC_1,
-	.drv = GPIOMUX_DRV_2MA,
-	.pull = GPIOMUX_PULL_DOWN,
-};
-
-static struct msm_gpiomux_config msm9615_sdcc2_configs[] __initdata = {
-	{
-		/* SDC2_DATA_0 */
-		.gpio      = 25,
-		.settings = {
-			[GPIOMUX_ACTIVE]    = &sdcc2_cmd_data_0_3_actv_cfg,
-			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
-		},
-	},
-	{
-		/* SDC2_DATA_1 */
-		.gpio      = 26,
-		.settings = {
-			[GPIOMUX_ACTIVE]    = &sdcc2_cmd_data_0_3_actv_cfg,
-			[GPIOMUX_SUSPENDED] = &sdcc2_cmd_data_0_3_actv_cfg,
-		},
-	},
-	{
-		/* SDC2_DATA_2 */
-		.gpio      = 27,
-		.settings = {
-			[GPIOMUX_ACTIVE]    = &sdcc2_cmd_data_0_3_actv_cfg,
-			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
-		},
-	},
-	{
-		/* SDC2_DATA_3 */
-		.gpio      = 28,
-		.settings = {
-			[GPIOMUX_ACTIVE]    = &sdcc2_cmd_data_0_3_actv_cfg,
-			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
-		},
-	},
-	{
-		/* SDC2_CMD */
-		.gpio      = 29,
-		.settings = {
-			[GPIOMUX_ACTIVE]    = &sdcc2_cmd_data_0_3_actv_cfg,
-			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
-		},
-	},
-	{
-		/* SDC2_CLK */
-		.gpio      = 30,
-		.settings = {
-			[GPIOMUX_ACTIVE]    = &sdcc2_clk_actv_cfg,
-			[GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
-		},
-	},
-};
-
-static struct msm_mmc_gpio sdc2_gpio_cfg[] = {
-	{25, "sdc2_dat_0"},
-	{26, "sdc2_dat_1"},
-	{27, "sdc2_dat_2"},
-	{28, "sdc2_dat_3"},
-	{29, "sdc2_cmd"},
-	{30, "sdc2_clk"},
-};
-
-static struct msm_mmc_gpio_data mmc_gpio_data[MAX_SDCC_CONTROLLER] = {
-	[SDCC2] = {
-		.gpio = sdc2_gpio_cfg,
-		.size = ARRAY_SIZE(sdc2_gpio_cfg),
-	},
-};
-#else
-static struct msm_gpiomux_config msm9615_sdcc2_configs[0];
-#endif
-
-static struct msm_mmc_pin_data mmc_slot_pin_data[MAX_SDCC_CONTROLLER] = {
-#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
-	[SDCC1] = {
-		.is_gpio = 0,
-		.pad_data = &mmc_pad_data[SDCC1],
-	},
-#endif
-#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
-	[SDCC2] = {
-		.is_gpio = 1,
-		.gpio_data = &mmc_gpio_data[SDCC2],
-	},
-#endif
-};
-
-#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
-static unsigned int sdc1_sup_clk_rates[] = {
-	400000, 24000000, 48000000
-};
-
-static struct mmc_platform_data sdc1_data = {
-	.ocr_mask       = MMC_VDD_27_28 | MMC_VDD_28_29,
-	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
-	.sup_clk_table	= sdc1_sup_clk_rates,
-	.sup_clk_cnt	= ARRAY_SIZE(sdc1_sup_clk_rates),
-	.pclk_src_dfab	= true,
-	.vreg_data	= &mmc_slot_vreg_data[SDCC1],
-	.pin_data	= &mmc_slot_pin_data[SDCC1],
-#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
-	.status_gpio	= GPIO_SDC1_HW_DET,
-	.status_irq	= MSM_GPIO_TO_INT(GPIO_SDC1_HW_DET),
-	.irq_flags	= IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-#endif
-	.xpc_cap	= 1,
-	.uhs_caps	= (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
-			   MMC_CAP_MAX_CURRENT_400)
-};
-static struct mmc_platform_data *msm9615_sdc1_pdata = &sdc1_data;
-#else
-static struct mmc_platform_data *msm9615_sdc1_pdata;
-#endif
-
-#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
-static unsigned int sdc2_sup_clk_rates[] = {
-	400000, 24000000, 48000000
-};
-
-static struct mmc_platform_data sdc2_data = {
-	.ocr_mask       = MMC_VDD_27_28 | MMC_VDD_28_29,
-	.mmc_bus_width  = MMC_CAP_4_BIT_DATA,
-	.sup_clk_table	= sdc2_sup_clk_rates,
-	.sup_clk_cnt	= ARRAY_SIZE(sdc2_sup_clk_rates),
-	.pclk_src_dfab	= 1,
-	.pin_data	= &mmc_slot_pin_data[SDCC2],
-#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
-	.sdiowakeup_irq = MSM_GPIO_TO_INT(GPIO_SDC2_DAT1_WAKEUP),
-#endif
-};
-static struct mmc_platform_data *msm9615_sdc2_pdata = &sdc2_data;
-#else
-static struct mmc_platform_data *msm9615_sdc2_pdata;
-#endif
-
-static void __init msm9615_init_mmc(void)
-{
-	if (msm9615_sdc1_pdata) {
-		/* SDC1: External card slot for SD/MMC cards */
-		msm_add_sdcc(1, msm9615_sdc1_pdata);
-	}
-
-	if (msm9615_sdc2_pdata) {
-		msm_gpiomux_install(msm9615_sdcc2_configs,
-			ARRAY_SIZE(msm9615_sdcc2_configs));
-
-		/* SDC2: External card slot used for WLAN */
-		msm_add_sdcc(2, msm9615_sdc2_pdata);
-	}
-}
-#else
-static void __init msm9615_init_mmc(void) { }
-#endif
 static  struct msm_cpuidle_state msm_cstates[] __initdata = {
 	{0, 0, "C0", "WFI",
 		MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
@@ -634,27 +216,6 @@
 	.v_addr = MSM_APCS_GLB_BASE +  0x24,
 };
 
-static int __init gpiomux_init(void)
-{
-	int rc;
-
-	rc = msm_gpiomux_init(NR_GPIO_IRQS);
-	if (rc) {
-		pr_err(KERN_ERR "msm_gpiomux_init failed %d\n", rc);
-		return rc;
-	}
-	msm_gpiomux_install(msm9615_gsbi_configs,
-			ARRAY_SIZE(msm9615_gsbi_configs));
-
-	msm_gpiomux_install(msm9615_ps_hold_config,
-			ARRAY_SIZE(msm9615_ps_hold_config));
-#ifdef CONFIG_LTC4088_CHARGER
-	msm_gpiomux_install(msm9615_ltc4088_charger_config,
-			ARRAY_SIZE(msm9615_ltc4088_charger_config));
-#endif
-	return 0;
-}
-
 static void __init msm9615_init_buses(void)
 {
 #ifdef CONFIG_MSM_BUS_SCALING
@@ -865,7 +426,7 @@
 static void __init msm9615_common_init(void)
 {
 	msm9615_device_init();
-	gpiomux_init();
+	msm9615_init_gpiomux();
 	msm9615_i2c_init();
 	regulator_suppress_info_printing();
 	platform_device_register(&msm9615_device_rpm_regulator);
@@ -908,6 +469,7 @@
 MACHINE_START(MSM9615_CDP, "QCT MSM9615 CDP")
 	.map_io = msm9615_map_io,
 	.init_irq = msm9615_init_irq,
+	.handle_irq = gic_handle_irq,
 	.timer = &msm_timer,
 	.init_machine = msm9615_cdp_init,
 	.reserve = msm9615_reserve,
@@ -916,6 +478,7 @@
 MACHINE_START(MSM9615_MTP, "QCT MSM9615 MTP")
 	.map_io = msm9615_map_io,
 	.init_irq = msm9615_init_irq,
+	.handle_irq = gic_handle_irq,
 	.timer = &msm_timer,
 	.init_machine = msm9615_mtp_init,
 	.reserve = msm9615_reserve,
diff --git a/arch/arm/mach-msm/board-9615.h b/arch/arm/mach-msm/board-9615.h
index 0f5adf0..4759f8c 100644
--- a/arch/arm/mach-msm/board-9615.h
+++ b/arch/arm/mach-msm/board-9615.h
@@ -25,7 +25,7 @@
 #define PM8018_IRQ_BASE			(NR_MSM_IRQS + NR_GPIO_IRQS)
 #define PM8018_MPP_IRQ_BASE		(PM8018_IRQ_BASE + NR_GPIO_IRQS)
 
-extern struct pm8018_regulator_platform_data
+extern struct pm8xxx_regulator_platform_data
 	msm_pm8018_regulator_pdata[] __devinitdata;
 
 extern int msm_pm8018_regulator_pdata_len __devinitdata;
@@ -37,4 +37,6 @@
 
 extern struct gpio_regulator_platform_data msm_gpio_regulator_pdata[];
 
+int msm9615_init_gpiomux(void);
+void msm9615_init_mmc(void);
 #endif
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index 13d63d3..f4fcb75 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -50,8 +50,6 @@
 
 void __init msm_copper_init_irq(void)
 {
-	unsigned int i;
-
 	gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
 			(void *)MSM_QGIC_CPU_BASE);
 
@@ -61,14 +59,6 @@
 	writel_relaxed(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET);
 	mb();
 
-	/* FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
-	 * as they are configured as level, which does not play nice with
-	 * handle_percpu_irq.
-	 */
-	for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
-		if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
-			irq_set_handler(i, handle_percpu_irq);
-	}
 	irq_domain_generate_simple(msm_copper_gic_match,
 		COPPER_QGIC_DIST_PHYS, GIC_SPI_START);
 }
diff --git a/arch/arm/mach-msm/board-dt.c b/arch/arm/mach-msm/board-dt.c
index ebe884de..19f54cf 100644
--- a/arch/arm/mach-msm/board-dt.c
+++ b/arch/arm/mach-msm/board-dt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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 version 2 and
@@ -17,6 +17,7 @@
 #include <linux/of_platform.h>
 #include <linux/of_fdt.h>
 #include <linux/of_irq.h>
+#include <asm/hardware/gic.h>
 #include <asm/arch_timer.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
@@ -54,9 +55,9 @@
 	return 0;
 }
 
-int local_timer_ack(void)
+void local_timer_stop(void)
 {
-	return 1;
+	return;
 }
 
 static void __init msm_dt_init_irq(void)
@@ -94,6 +95,7 @@
 	.map_io = msm_dt_map_io,
 	.init_irq = msm_dt_init_irq,
 	.init_machine = msm_dt_init,
+	.handle_irq = gic_handle_irq,
 	.timer = &msm_dt_timer,
 	.dt_compat = msm_dt_match,
 MACHINE_END
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
index 550e288..87fea3f 100644
--- a/arch/arm/mach-msm/board-fsm9xxx.c
+++ b/arch/arm/mach-msm/board-fsm9xxx.c
@@ -696,6 +696,7 @@
 	.shared_ce_resource = QCE_NO_SHARE_CE_RESOURCE,
 	.hw_key_support = QCE_NO_HW_KEY_SUPPORT,
 	.sha_hmac = QCE_NO_SHA_HMAC_SUPPORT,
+	.bus_scale_table = NULL,
 };
 
 struct platform_device qcrypto_device = {
@@ -746,6 +747,7 @@
 	.shared_ce_resource = QCE_NO_SHARE_CE_RESOURCE,
 	.hw_key_support = QCE_NO_HW_KEY_SUPPORT,
 	.sha_hmac = QCE_NO_SHA_HMAC_SUPPORT,
+	.bus_scale_table = NULL,
 };
 
 static struct platform_device qcedev_device = {
@@ -917,6 +919,7 @@
 	.boot_params = PHYS_OFFSET + 0x100,
 	.map_io = fsm9xxx_map_io,
 	.init_irq = fsm9xxx_init_irq,
+	.handle_irq = vic_handle_irq,
 	.init_machine = fsm9xxx_init,
 	.timer = &msm_timer,
 MACHINE_END
diff --git a/arch/arm/mach-msm/board-msm7627a-bt.c b/arch/arm/mach-msm/board-msm7627a-bt.c
new file mode 100644
index 0000000..d4f06fa
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm7627a-bt.c
@@ -0,0 +1,966 @@
+/* Copyright (c) 2011, Code Aurora Forum. 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 version 2 and
+ * only 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.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/rfkill.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mfd/marimba.h>
+#include <linux/io.h>
+#include <asm/gpio.h>
+#include <asm/mach-types.h>
+#include <mach/rpc_pmapp.h>
+
+#include "board-msm7627a.h"
+#include "devices-msm7x2xa.h"
+
+#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
+
+
+static struct bt_vreg_info bt_vregs[] = {
+	{"msme1", 2, 1800000, 1800000, 0, NULL},
+	{"bt", 21, 2900000, 3300000, 1, NULL}
+};
+
+struct platform_device msm_bt_power_device = {
+	.name = "bt_power",
+};
+
+static unsigned bt_config_power_on[] = {
+	/*RFR*/
+	GPIO_CFG(43, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	/*CTS*/
+	GPIO_CFG(44, 2, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	/*RX*/
+	GPIO_CFG(45, 2, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	/*TX*/
+	GPIO_CFG(46, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+};
+static unsigned bt_config_pcm_on[] = {
+	/*PCM_DOUT*/
+	GPIO_CFG(68, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	/*PCM_DIN*/
+	GPIO_CFG(69, 1, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	/*PCM_SYNC*/
+	GPIO_CFG(70, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	/*PCM_CLK*/
+	GPIO_CFG(71, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+};
+static unsigned bt_config_power_off[] = {
+	/*RFR*/
+	GPIO_CFG(43, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/*CTS*/
+	GPIO_CFG(44, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/*RX*/
+	GPIO_CFG(45, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/*TX*/
+	GPIO_CFG(46, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+};
+static unsigned bt_config_pcm_off[] = {
+	/*PCM_DOUT*/
+	GPIO_CFG(68, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/*PCM_DIN*/
+	GPIO_CFG(69, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/*PCM_SYNC*/
+	GPIO_CFG(70, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/*PCM_CLK*/
+	GPIO_CFG(71, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+};
+
+static unsigned fm_i2s_config_power_on[] = {
+	/*FM_I2S_SD*/
+	GPIO_CFG(68, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	/*FM_I2S_WS*/
+	GPIO_CFG(70, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+	/*FM_I2S_SCK*/
+	GPIO_CFG(71, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
+};
+
+static unsigned fm_i2s_config_power_off[] = {
+	/*FM_I2S_SD*/
+	GPIO_CFG(68, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/*FM_I2S_WS*/
+	GPIO_CFG(70, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+	/*FM_I2S_SCK*/
+	GPIO_CFG(71, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+};
+
+int gpio_bt_sys_rest_en = 133;
+static void gpio_bt_config(void)
+{
+	if (machine_is_msm7627a_qrd1())
+		gpio_bt_sys_rest_en = 114;
+}
+
+static int bt_set_gpio(int on)
+{
+	int rc = 0;
+	struct marimba config = { .mod_id =  SLAVE_ID_BAHAMA};
+
+	if (on) {
+		rc = gpio_direction_output(gpio_bt_sys_rest_en, 1);
+		msleep(100);
+	} else {
+		if (!marimba_get_fm_status(&config) &&
+				!marimba_get_bt_status(&config)) {
+			gpio_set_value_cansleep(gpio_bt_sys_rest_en, 0);
+			rc = gpio_direction_input(gpio_bt_sys_rest_en);
+			msleep(100);
+		}
+	}
+	if (rc)
+		pr_err("%s: BT sys_reset_en GPIO : Error", __func__);
+
+	return rc;
+}
+
+static struct regulator *fm_regulator;
+static int fm_radio_setup(struct marimba_fm_platform_data *pdata)
+{
+	int rc = 0;
+	const char *id = "FMPW";
+	uint32_t irqcfg;
+	struct marimba config = { .mod_id =  SLAVE_ID_BAHAMA};
+	u8 value;
+
+	/* Voting for 1.8V Regulator */
+	fm_regulator = regulator_get(NULL , "msme1");
+	if (IS_ERR(fm_regulator)) {
+		rc = PTR_ERR(fm_regulator);
+		pr_err("%s: could not get regulator: %d\n", __func__, rc);
+		goto out;
+	}
+
+	/* Set the voltage level to 1.8V */
+	rc = regulator_set_voltage(fm_regulator, 1800000, 1800000);
+	if (rc < 0) {
+		pr_err("%s: could not set voltage: %d\n", __func__, rc);
+		goto reg_free;
+	}
+
+	/* Enabling the 1.8V regulator */
+	rc = regulator_enable(fm_regulator);
+	if (rc) {
+		pr_err("%s: could not enable regulator: %d\n", __func__, rc);
+		goto reg_free;
+	}
+
+	/* Voting for 19.2MHz clock */
+	rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
+			PMAPP_CLOCK_VOTE_ON);
+	if (rc < 0) {
+		pr_err("%s: clock vote failed with :(%d)\n",
+			__func__, rc);
+		goto reg_disable;
+	}
+
+	rc = bt_set_gpio(1);
+	if (rc) {
+		pr_err("%s: bt_set_gpio = %d", __func__, rc);
+		goto gpio_deconfig;
+	}
+	/*re-write FM Slave Id, after reset*/
+	value = BAHAMA_SLAVE_ID_FM_ADDR;
+	rc = marimba_write_bit_mask(&config,
+			BAHAMA_SLAVE_ID_FM_REG, &value, 1, 0xFF);
+	if (rc < 0) {
+		pr_err("%s: FM Slave ID rewrite Failed = %d", __func__, rc);
+		goto gpio_deconfig;
+	}
+	/* Configuring the FM GPIO */
+	irqcfg = GPIO_CFG(FM_GPIO, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL,
+			GPIO_CFG_2MA);
+
+	rc = gpio_tlmm_config(irqcfg, GPIO_CFG_ENABLE);
+	if (rc) {
+		pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
+			 __func__, irqcfg, rc);
+		goto gpio_deconfig;
+	}
+
+	return 0;
+
+gpio_deconfig:
+	pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
+		PMAPP_CLOCK_VOTE_OFF);
+	bt_set_gpio(0);
+reg_disable:
+	regulator_disable(fm_regulator);
+reg_free:
+	regulator_put(fm_regulator);
+	fm_regulator = NULL;
+out:
+	return rc;
+};
+
+static void fm_radio_shutdown(struct marimba_fm_platform_data *pdata)
+{
+	int rc;
+	const char *id = "FMPW";
+
+	/* Releasing the GPIO line used by FM */
+	uint32_t irqcfg = GPIO_CFG(FM_GPIO, 0, GPIO_CFG_INPUT,
+		GPIO_CFG_PULL_UP, GPIO_CFG_2MA);
+
+	rc = gpio_tlmm_config(irqcfg, GPIO_CFG_ENABLE);
+	if (rc)
+		pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
+			 __func__, irqcfg, rc);
+
+	/* Releasing the 1.8V Regulator */
+	if (!IS_ERR_OR_NULL(fm_regulator)) {
+		rc = regulator_disable(fm_regulator);
+		if (rc)
+			pr_err("%s: could not disable regulator: %d\n",
+					__func__, rc);
+		regulator_put(fm_regulator);
+		fm_regulator = NULL;
+	}
+
+	/* Voting off the clock */
+	rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
+		PMAPP_CLOCK_VOTE_OFF);
+	if (rc < 0)
+		pr_err("%s: voting off failed with :(%d)\n",
+			__func__, rc);
+	rc = bt_set_gpio(0);
+	if (rc)
+		pr_err("%s: bt_set_gpio = %d", __func__, rc);
+}
+static int switch_pcm_i2s_reg_mode(int mode)
+{
+	unsigned char reg = 0;
+	int rc = -1;
+	unsigned char set = I2C_PIN_CTL; /*SET PIN CTL mode*/
+	unsigned char unset = I2C_NORMAL; /* UNSET PIN CTL MODE*/
+	struct marimba config = { .mod_id =  SLAVE_ID_BAHAMA};
+
+	if (mode == 0) {
+		/* as we need to switch path to FM we need to move
+		BT AUX PCM lines to PIN CONTROL mode then move
+		FM to normal mode.*/
+		for (reg = BT_PCM_BCLK_MODE; reg <= BT_PCM_SYNC_MODE; reg++) {
+			rc = marimba_write(&config, reg, &set, 1);
+			if (rc < 0) {
+				pr_err("pcm pinctl failed = %d", rc);
+				goto err_all;
+			}
+		}
+		for (reg = FM_I2S_SD_MODE; reg <= FM_I2S_SCK_MODE; reg++) {
+			rc = marimba_write(&config, reg, &unset, 1);
+			if (rc < 0) {
+				pr_err("i2s normal failed = %d", rc);
+				goto err_all;
+			}
+		}
+	} else {
+		/* as we need to switch path to AUXPCM we need to move
+		FM I2S lines to PIN CONTROL mode then move
+		BT AUX_PCM to normal mode.*/
+		for (reg = FM_I2S_SD_MODE; reg <= FM_I2S_SCK_MODE; reg++) {
+			rc = marimba_write(&config, reg, &set, 1);
+			if (rc < 0) {
+				pr_err("i2s pinctl failed = %d", rc);
+				goto err_all;
+			}
+		}
+		for (reg = BT_PCM_BCLK_MODE; reg <= BT_PCM_SYNC_MODE; reg++) {
+			rc = marimba_write(&config, reg, &unset, 1);
+			if (rc < 0) {
+				pr_err("pcm normal failed = %d", rc);
+				goto err_all;
+			}
+		}
+	}
+
+	return 0;
+
+err_all:
+	return rc;
+}
+
+
+static void config_pcm_i2s_mode(int mode)
+{
+	void __iomem *cfg_ptr;
+	u8 reg2;
+
+	cfg_ptr = ioremap_nocache(FPGA_MSM_CNTRL_REG2, sizeof(char));
+
+	if (!cfg_ptr)
+		return;
+	if (mode) {
+		/*enable the pcm mode in FPGA*/
+		reg2 = readb_relaxed(cfg_ptr);
+		if (reg2 == 0) {
+			reg2 = 1;
+			writeb_relaxed(reg2, cfg_ptr);
+		}
+	} else {
+		/*enable i2s mode in FPGA*/
+		reg2 = readb_relaxed(cfg_ptr);
+		if (reg2 == 1) {
+			reg2 = 0;
+			writeb_relaxed(reg2, cfg_ptr);
+		}
+	}
+	iounmap(cfg_ptr);
+}
+
+static int config_i2s(int mode)
+{
+	int pin, rc = 0;
+
+	if (mode == FM_I2S_ON) {
+		if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf())
+			config_pcm_i2s_mode(0);
+		pr_err("%s mode = FM_I2S_ON", __func__);
+
+		rc = switch_pcm_i2s_reg_mode(0);
+		if (rc) {
+			pr_err("switch mode failed");
+			return rc;
+		}
+		for (pin = 0; pin < ARRAY_SIZE(fm_i2s_config_power_on);
+			pin++) {
+				rc = gpio_tlmm_config(
+					fm_i2s_config_power_on[pin],
+					GPIO_CFG_ENABLE
+					);
+				if (rc < 0)
+					return rc;
+			}
+	} else if (mode == FM_I2S_OFF) {
+		pr_err("%s mode = FM_I2S_OFF", __func__);
+		rc = switch_pcm_i2s_reg_mode(1);
+		if (rc) {
+			pr_err("switch mode failed");
+			return rc;
+		}
+		for (pin = 0; pin < ARRAY_SIZE(fm_i2s_config_power_off);
+			pin++) {
+				rc = gpio_tlmm_config(
+					fm_i2s_config_power_off[pin],
+					GPIO_CFG_ENABLE
+					);
+				if (rc < 0)
+					return rc;
+			}
+	}
+	return rc;
+}
+
+static int config_pcm(int mode)
+{
+	int pin, rc = 0;
+
+	if (mode == BT_PCM_ON) {
+		if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf())
+			config_pcm_i2s_mode(1);
+		pr_err("%s mode =BT_PCM_ON", __func__);
+		rc = switch_pcm_i2s_reg_mode(1);
+		if (rc) {
+			pr_err("switch mode failed");
+			return rc;
+		}
+		for (pin = 0; pin < ARRAY_SIZE(bt_config_pcm_on);
+			pin++) {
+				rc = gpio_tlmm_config(bt_config_pcm_on[pin],
+					GPIO_CFG_ENABLE);
+				if (rc < 0)
+					return rc;
+		}
+	} else if (mode == BT_PCM_OFF) {
+		pr_err("%s mode =BT_PCM_OFF", __func__);
+		rc = switch_pcm_i2s_reg_mode(0);
+		if (rc) {
+			pr_err("switch mode failed");
+			return rc;
+		}
+		for (pin = 0; pin < ARRAY_SIZE(bt_config_pcm_off);
+			pin++) {
+				rc = gpio_tlmm_config(bt_config_pcm_off[pin],
+					GPIO_CFG_ENABLE);
+				if (rc < 0)
+					return rc;
+		}
+
+	}
+
+	return rc;
+}
+
+static int msm_bahama_setup_pcm_i2s(int mode)
+{
+	int fm_state = 0, bt_state = 0;
+	int rc = 0;
+	struct marimba config = { .mod_id =  SLAVE_ID_BAHAMA};
+
+	fm_state = marimba_get_fm_status(&config);
+	bt_state = marimba_get_bt_status(&config);
+
+	switch (mode) {
+	case BT_PCM_ON:
+	case BT_PCM_OFF:
+		if (!fm_state)
+			rc = config_pcm(mode);
+		break;
+	case FM_I2S_ON:
+		rc = config_i2s(mode);
+		break;
+	case FM_I2S_OFF:
+		if (bt_state)
+			rc = config_pcm(BT_PCM_ON);
+		else
+			rc = config_i2s(mode);
+		break;
+	default:
+		rc = -EIO;
+		pr_err("%s:Unsupported mode", __func__);
+	}
+	return rc;
+}
+
+static int bahama_bt(int on)
+{
+	int rc = 0;
+	int i;
+
+	struct marimba config = { .mod_id =  SLAVE_ID_BAHAMA};
+
+	struct bahama_variant_register {
+		const size_t size;
+		const struct bahama_config_register *set;
+	};
+
+	const struct bahama_config_register *p;
+
+	u8 version;
+
+	const struct bahama_config_register v10_bt_on[] = {
+		{ 0xE9, 0x00, 0xFF },
+		{ 0xF4, 0x80, 0xFF },
+		{ 0xE4, 0x00, 0xFF },
+		{ 0xE5, 0x00, 0x0F },
+#ifdef CONFIG_WLAN
+		{ 0xE6, 0x38, 0x7F },
+		{ 0xE7, 0x06, 0xFF },
+#endif
+		{ 0xE9, 0x21, 0xFF },
+		{ 0x01, 0x0C, 0x1F },
+		{ 0x01, 0x08, 0x1F },
+	};
+
+	const struct bahama_config_register v20_bt_on_fm_off[] = {
+		{ 0x11, 0x0C, 0xFF },
+		{ 0x13, 0x01, 0xFF },
+		{ 0xF4, 0x80, 0xFF },
+		{ 0xF0, 0x00, 0xFF },
+		{ 0xE9, 0x00, 0xFF },
+#ifdef CONFIG_WLAN
+		{ 0x81, 0x00, 0x7F },
+		{ 0x82, 0x00, 0xFF },
+		{ 0xE6, 0x38, 0x7F },
+		{ 0xE7, 0x06, 0xFF },
+#endif
+		{ 0x8E, 0x15, 0xFF },
+		{ 0x8F, 0x15, 0xFF },
+		{ 0x90, 0x15, 0xFF },
+
+		{ 0xE9, 0x21, 0xFF },
+	};
+
+	const struct bahama_config_register v20_bt_on_fm_on[] = {
+		{ 0x11, 0x0C, 0xFF },
+		{ 0x13, 0x01, 0xFF },
+		{ 0xF4, 0x86, 0xFF },
+		{ 0xF0, 0x06, 0xFF },
+		{ 0xE9, 0x00, 0xFF },
+#ifdef CONFIG_WLAN
+		{ 0x81, 0x00, 0x7F },
+		{ 0x82, 0x00, 0xFF },
+		{ 0xE6, 0x38, 0x7F },
+		{ 0xE7, 0x06, 0xFF },
+#endif
+		{ 0xE9, 0x21, 0xFF },
+	};
+
+	const struct bahama_config_register v10_bt_off[] = {
+		{ 0xE9, 0x00, 0xFF },
+	};
+
+	const struct bahama_config_register v20_bt_off_fm_off[] = {
+		{ 0xF4, 0x84, 0xFF },
+		{ 0xF0, 0x04, 0xFF },
+		{ 0xE9, 0x00, 0xFF }
+	};
+
+	const struct bahama_config_register v20_bt_off_fm_on[] = {
+		{ 0xF4, 0x86, 0xFF },
+		{ 0xF0, 0x06, 0xFF },
+		{ 0xE9, 0x00, 0xFF }
+	};
+
+	const struct bahama_variant_register bt_bahama[2][3] = {
+	{
+		{ ARRAY_SIZE(v10_bt_off), v10_bt_off },
+		{ ARRAY_SIZE(v20_bt_off_fm_off), v20_bt_off_fm_off },
+		{ ARRAY_SIZE(v20_bt_off_fm_on), v20_bt_off_fm_on }
+	},
+	{
+		{ ARRAY_SIZE(v10_bt_on), v10_bt_on },
+		{ ARRAY_SIZE(v20_bt_on_fm_off), v20_bt_on_fm_off },
+		{ ARRAY_SIZE(v20_bt_on_fm_on), v20_bt_on_fm_on }
+	}
+	};
+
+	u8 offset = 0; /* index into bahama configs */
+	on = on ? 1 : 0;
+	version = marimba_read_bahama_ver(&config);
+	if ((int)version < 0 || version == BAHAMA_VER_UNSUPPORTED) {
+		dev_err(&msm_bt_power_device.dev, "%s : Bahama "
+			"version read Error, version = %d\n",
+			__func__, version);
+		return -EIO;
+	}
+
+	if (version == BAHAMA_VER_2_0) {
+		if (marimba_get_fm_status(&config))
+			offset = 0x01;
+	}
+
+	p = bt_bahama[on][version + offset].set;
+
+	dev_info(&msm_bt_power_device.dev,
+		"%s: found version %d\n", __func__, version);
+
+	for (i = 0; i < bt_bahama[on][version + offset].size; i++) {
+		u8 value = (p+i)->value;
+		rc = marimba_write_bit_mask(&config,
+			(p+i)->reg,
+			&value,
+			sizeof((p+i)->value),
+			(p+i)->mask);
+		if (rc < 0) {
+			dev_err(&msm_bt_power_device.dev,
+				"%s: reg %x write failed: %d\n",
+				__func__, (p+i)->reg, rc);
+			return rc;
+		}
+		dev_dbg(&msm_bt_power_device.dev,
+			"%s: reg 0x%02x write value 0x%02x mask 0x%02x\n",
+				__func__, (p+i)->reg,
+				value, (p+i)->mask);
+		value = 0;
+		rc = marimba_read_bit_mask(&config,
+				(p+i)->reg, &value,
+				sizeof((p+i)->value), (p+i)->mask);
+		if (rc < 0)
+			dev_err(&msm_bt_power_device.dev,
+				"%s marimba_read_bit_mask- error",
+				__func__);
+		dev_dbg(&msm_bt_power_device.dev,
+			"%s: reg 0x%02x read value 0x%02x mask 0x%02x\n",
+				__func__, (p+i)->reg,
+				value, (p+i)->mask);
+	}
+	/* Update BT Status */
+	if (on)
+		marimba_set_bt_status(&config, true);
+	else
+		marimba_set_bt_status(&config, false);
+	return rc;
+}
+
+static int bluetooth_switch_regulators(int on)
+{
+	int i, rc = 0;
+	const char *id = "BTPW";
+
+	for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
+		if (IS_ERR_OR_NULL(bt_vregs[i].reg)) {
+			rc = bt_vregs[i].reg ?
+				PTR_ERR(bt_vregs[i].reg) :
+				-ENODEV;
+			dev_err(&msm_bt_power_device.dev,
+				"%s: invalid regulator handle for %s: %d\n",
+					__func__, bt_vregs[i].name, rc);
+			goto reg_disable;
+		}
+
+		rc = on ? regulator_set_voltage(bt_vregs[i].reg,
+					bt_vregs[i].min_level,
+						bt_vregs[i].max_level) : 0;
+		if (rc) {
+			dev_err(&msm_bt_power_device.dev,
+				"%s: could not set voltage for %s: %d\n",
+					__func__, bt_vregs[i].name, rc);
+			goto reg_disable;
+		}
+
+		rc = on ? regulator_enable(bt_vregs[i].reg) : 0;
+		if (rc) {
+			dev_err(&msm_bt_power_device.dev,
+				"%s: could not %sable regulator %s: %d\n",
+					__func__, "en", bt_vregs[i].name, rc);
+			goto reg_disable;
+		}
+
+		if (bt_vregs[i].is_pin_controlled) {
+			rc = pmapp_vreg_lpm_pincntrl_vote(id,
+				bt_vregs[i].pmapp_id,
+					PMAPP_CLOCK_ID_D1,
+					on ? PMAPP_CLOCK_VOTE_ON :
+						PMAPP_CLOCK_VOTE_OFF);
+			if (rc) {
+				dev_err(&msm_bt_power_device.dev,
+					"%s: pin control failed for %s: %d\n",
+					__func__, bt_vregs[i].name, rc);
+				goto pin_cnt_fail;
+			}
+		}
+		rc = on ? 0 : regulator_disable(bt_vregs[i].reg);
+
+		if (rc) {
+			dev_err(&msm_bt_power_device.dev,
+				"%s: could not %sable regulator %s: %d\n",
+					__func__, "dis", bt_vregs[i].name, rc);
+			goto reg_disable;
+		}
+	}
+
+	return rc;
+pin_cnt_fail:
+	if (on)
+		regulator_disable(bt_vregs[i].reg);
+reg_disable:
+	while (i) {
+		if (on) {
+			i--;
+			regulator_disable(bt_vregs[i].reg);
+			regulator_put(bt_vregs[i].reg);
+		}
+	}
+	return rc;
+}
+
+static struct regulator *reg_s3;
+static unsigned int msm_bahama_setup_power(void)
+{
+	int rc = 0;
+
+	reg_s3 = regulator_get(NULL, "msme1");
+	if (IS_ERR(reg_s3)) {
+		rc = PTR_ERR(reg_s3);
+		pr_err("%s: could not get regulator: %d\n", __func__, rc);
+		goto out;
+	}
+
+	rc = regulator_set_voltage(reg_s3, 1800000, 1800000);
+	if (rc < 0) {
+		pr_err("%s: could not set voltage: %d\n", __func__, rc);
+		goto reg_fail;
+	}
+
+	rc = regulator_enable(reg_s3);
+	if (rc < 0) {
+		pr_err("%s: could not enable regulator: %d\n", __func__, rc);
+		goto reg_fail;
+	}
+	if (machine_is_msm7627a_qrd1())
+		gpio_tlmm_config(GPIO_CFG(gpio_bt_sys_rest_en, 0,
+			GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
+			GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+
+
+	/*setup Bahama_sys_reset_n*/
+	rc = gpio_request(gpio_bt_sys_rest_en, "bahama sys_rst_n");
+	if (rc < 0) {
+		pr_err("%s: gpio_request %d = %d\n", __func__,
+			gpio_bt_sys_rest_en, rc);
+		goto reg_disable;
+	}
+
+	rc = bt_set_gpio(1);
+	if (rc < 0) {
+		pr_err("%s: bt_set_gpio %d = %d\n", __func__,
+			gpio_bt_sys_rest_en, rc);
+		goto gpio_fail;
+	}
+
+	return rc;
+
+gpio_fail:
+	gpio_free(gpio_bt_sys_rest_en);
+reg_disable:
+	regulator_disable(reg_s3);
+reg_fail:
+	regulator_put(reg_s3);
+out:
+	reg_s3 = NULL;
+	return rc;
+}
+
+static unsigned int msm_bahama_shutdown_power(int value)
+{
+	int rc = 0;
+
+	if (IS_ERR_OR_NULL(reg_s3)) {
+		rc = reg_s3 ? PTR_ERR(reg_s3) : -ENODEV;
+		goto out;
+	}
+
+	rc = regulator_disable(reg_s3);
+	if (rc) {
+		pr_err("%s: could not disable regulator: %d\n", __func__, rc);
+		goto out;
+	}
+
+	if (value == BAHAMA_ID) {
+		rc = bt_set_gpio(0);
+		if (rc) {
+			pr_err("%s: bt_set_gpio = %d\n",
+					__func__, rc);
+			goto reg_enable;
+		}
+		gpio_free(gpio_bt_sys_rest_en);
+	}
+
+	regulator_put(reg_s3);
+	reg_s3 = NULL;
+
+	return 0;
+
+reg_enable:
+	regulator_enable(reg_s3);
+out:
+	return rc;
+}
+
+static unsigned int msm_bahama_core_config(int type)
+{
+	int rc = 0;
+
+	if (type == BAHAMA_ID) {
+		int i;
+		struct marimba config = { .mod_id =  SLAVE_ID_BAHAMA};
+		const struct bahama_config_register v20_init[] = {
+			/* reg, value, mask */
+			{ 0xF4, 0x84, 0xFF }, /* AREG */
+			{ 0xF0, 0x04, 0xFF } /* DREG */
+		};
+		if (marimba_read_bahama_ver(&config) == BAHAMA_VER_2_0) {
+			for (i = 0; i < ARRAY_SIZE(v20_init); i++) {
+				u8 value = v20_init[i].value;
+				rc = marimba_write_bit_mask(&config,
+					v20_init[i].reg,
+					&value,
+					sizeof(v20_init[i].value),
+					v20_init[i].mask);
+				if (rc < 0) {
+					pr_err("%s: reg %d write failed: %d\n",
+						__func__, v20_init[i].reg, rc);
+					return rc;
+				}
+				pr_debug("%s: reg 0x%02x value 0x%02x"
+					" mask 0x%02x\n",
+					__func__, v20_init[i].reg,
+					v20_init[i].value, v20_init[i].mask);
+			}
+		}
+	}
+	rc = bt_set_gpio(0);
+	if (rc) {
+		pr_err("%s: bt_set_gpio = %d\n",
+		       __func__, rc);
+	}
+	pr_debug("core type: %d\n", type);
+	return rc;
+}
+
+static int bluetooth_power(int on)
+{
+	int pin, rc = 0;
+	const char *id = "BTPW";
+	int cid = 0;
+
+	cid = adie_get_detected_connectivity_type();
+	if (cid != BAHAMA_ID) {
+		pr_err("%s: unexpected adie connectivity type: %d\n",
+					__func__, cid);
+		return -ENODEV;
+	}
+	if (on) {
+		/*setup power for BT SOC*/
+		rc = bt_set_gpio(on);
+		if (rc) {
+			pr_err("%s: bt_set_gpio = %d\n",
+					__func__, rc);
+			goto exit;
+		}
+		rc = bluetooth_switch_regulators(on);
+		if (rc < 0) {
+			pr_err("%s: bluetooth_switch_regulators rc = %d",
+					__func__, rc);
+			goto exit;
+		}
+		/*setup BT GPIO lines*/
+		for (pin = 0; pin < ARRAY_SIZE(bt_config_power_on);
+			pin++) {
+			rc = gpio_tlmm_config(bt_config_power_on[pin],
+					GPIO_CFG_ENABLE);
+			if (rc < 0) {
+				pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
+						__func__,
+						bt_config_power_on[pin],
+						rc);
+				goto fail_power;
+			}
+		}
+		/*Setup BT clocks*/
+		rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
+			PMAPP_CLOCK_VOTE_ON);
+		if (rc < 0) {
+			pr_err("Failed to vote for TCXO_D1 ON\n");
+			goto fail_clock;
+		}
+		msleep(20);
+
+		/*I2C config for Bahama*/
+		rc = bahama_bt(1);
+		if (rc < 0) {
+			pr_err("%s: bahama_bt rc = %d", __func__, rc);
+			goto fail_i2c;
+		}
+		msleep(20);
+
+		/*setup BT PCM lines*/
+		rc = msm_bahama_setup_pcm_i2s(BT_PCM_ON);
+		if (rc < 0) {
+			pr_err("%s: msm_bahama_setup_pcm_i2s , rc =%d\n",
+				__func__, rc);
+				goto fail_power;
+			}
+		rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
+				  PMAPP_CLOCK_VOTE_PIN_CTRL);
+		if (rc < 0)
+			pr_err("%s:Pin Control Failed, rc = %d",
+					__func__, rc);
+
+	} else {
+		rc = bahama_bt(0);
+		if (rc < 0)
+			pr_err("%s: bahama_bt rc = %d", __func__, rc);
+
+		rc = msm_bahama_setup_pcm_i2s(BT_PCM_OFF);
+		if (rc < 0) {
+			pr_err("%s: msm_bahama_setup_pcm_i2s, rc =%d\n",
+				__func__, rc);
+		}
+		rc = bt_set_gpio(on);
+		if (rc) {
+			pr_err("%s: bt_set_gpio = %d\n",
+					__func__, rc);
+		}
+fail_i2c:
+		rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
+				  PMAPP_CLOCK_VOTE_OFF);
+		if (rc < 0)
+			pr_err("%s: Failed to vote Off D1\n", __func__);
+fail_clock:
+		for (pin = 0; pin < ARRAY_SIZE(bt_config_power_off);
+			pin++) {
+			rc = gpio_tlmm_config(bt_config_power_off[pin],
+				GPIO_CFG_ENABLE);
+			if (rc < 0) {
+				pr_err("%s:"
+					" gpio_tlmm_config(%#x)=%d\n",
+					__func__,
+					bt_config_power_off[pin], rc);
+			}
+		}
+fail_power:
+		rc = bluetooth_switch_regulators(0);
+		if (rc < 0) {
+			pr_err("%s: switch_regulators : rc = %d",\
+				__func__, rc);
+			goto exit;
+		}
+	}
+	return rc;
+exit:
+	pr_err("%s: failed with rc = %d", __func__, rc);
+	return rc;
+}
+
+static struct marimba_fm_platform_data marimba_fm_pdata = {
+	.fm_setup = fm_radio_setup,
+	.fm_shutdown = fm_radio_shutdown,
+	.irq = MSM_GPIO_TO_INT(FM_GPIO),
+	.vreg_s2 = NULL,
+	.vreg_xo_out = NULL,
+	/* Configuring the FM SoC as I2S Master */
+	.is_fm_soc_i2s_master = true,
+	.config_i2s_gpio = msm_bahama_setup_pcm_i2s,
+};
+
+static struct marimba_platform_data marimba_pdata = {
+	.slave_id[SLAVE_ID_BAHAMA_FM]	= BAHAMA_SLAVE_ID_FM_ADDR,
+	.slave_id[SLAVE_ID_BAHAMA_QMEMBIST] = BAHAMA_SLAVE_ID_QMEMBIST_ADDR,
+	.bahama_setup			= msm_bahama_setup_power,
+	.bahama_shutdown		= msm_bahama_shutdown_power,
+	.bahama_core_config		= msm_bahama_core_config,
+	.fm			        = &marimba_fm_pdata,
+};
+
+static struct i2c_board_info bahama_devices[] = {
+{
+	I2C_BOARD_INFO("marimba", 0xc),
+	.platform_data = &marimba_pdata,
+},
+};
+
+void __init msm7627a_bt_power_init(void)
+{
+	int i, rc = 0;
+	struct device *dev;
+
+	gpio_bt_config();
+
+	i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
+			bahama_devices,
+			ARRAY_SIZE(bahama_devices));
+	dev = &msm_bt_power_device.dev;
+
+	for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
+		bt_vregs[i].reg = regulator_get(dev, bt_vregs[i].name);
+		if (IS_ERR(bt_vregs[i].reg)) {
+			rc = PTR_ERR(bt_vregs[i].reg);
+			dev_err(dev, "%s: could not get regulator %s: %d\n",
+					__func__, bt_vregs[i].name, rc);
+			goto reg_get_fail;
+		}
+	}
+
+	dev->platform_data = &bluetooth_power;
+
+	return;
+
+reg_get_fail:
+	while (i--) {
+		regulator_put(bt_vregs[i].reg);
+		bt_vregs[i].reg = NULL;
+	}
+	return;
+}
+#endif
diff --git a/arch/arm/mach-msm/board-msm7627a.h b/arch/arm/mach-msm/board-msm7627a.h
index 6b22c71..4680a31 100644
--- a/arch/arm/mach-msm/board-msm7627a.h
+++ b/arch/arm/mach-msm/board-msm7627a.h
@@ -15,4 +15,41 @@
 
 void __init msm7627a_init_mmc(void);
 
+#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
+
+#define FPGA_MSM_CNTRL_REG2 0x90008010
+#define BAHAMA_SLAVE_ID_FM_REG 0x02
+#define BAHAMA_SLAVE_ID_FM_ADDR  0x2A
+#define BAHAMA_SLAVE_ID_QMEMBIST_ADDR   0x7B
+#define FM_GPIO 83
+#define BT_PCM_BCLK_MODE  0x88
+#define BT_PCM_DIN_MODE   0x89
+#define BT_PCM_DOUT_MODE  0x8A
+#define BT_PCM_SYNC_MODE  0x8B
+#define FM_I2S_SD_MODE    0x8E
+#define FM_I2S_WS_MODE    0x8F
+#define FM_I2S_SCK_MODE   0x90
+#define I2C_PIN_CTL       0x15
+#define I2C_NORMAL        0x40
+
+struct bahama_config_register {
+	u8 reg;
+	u8 value;
+	u8 mask;
+};
+
+struct bt_vreg_info {
+	const char *name;
+	unsigned int pmapp_id;
+	unsigned int min_level;
+	unsigned int max_level;
+	unsigned int is_pin_controlled;
+	struct regulator *reg;
+};
+
+extern struct platform_device msm_bt_power_device;
+
+void __init msm7627a_bt_power_init(void);
+#endif
+
 #endif
diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c
index d8efcfe..53ea8c1 100644
--- a/arch/arm/mach-msm/board-msm7x27.c
+++ b/arch/arm/mach-msm/board-msm7x27.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -1626,8 +1626,8 @@
 };
 
 static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
-	.mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT,
-	.v_addr = (uint32_t *)PAGE_OFFSET,
+	.mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS,
+	.p_addr = 0,
 };
 
 static void
@@ -1757,10 +1757,7 @@
 		}
 	}
 #endif
-	if (cpu_is_msm7x27())
-		acpuclk_init(&acpuclk_7x27_soc_data);
-	else
-		acpuclk_init(&acpuclk_7201_soc_data);
+	acpuclk_init(&acpuclk_7x27_soc_data);
 
 	usb_mpp_init();
 
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index dcb12bb3..389b071 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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 version 2 and
@@ -42,7 +42,6 @@
 #include <linux/power_supply.h>
 #include <linux/regulator/consumer.h>
 #include <mach/rpc_pmapp.h>
-
 #include <mach/msm_battery.h>
 #include <linux/smsc911x.h>
 #include <linux/atmel_maxtouch.h>
@@ -58,19 +57,6 @@
 
 #define PMEM_KERNEL_EBI1_SIZE	0x3A000
 #define MSM_PMEM_AUDIO_SIZE	0x5B000
-#define BAHAMA_SLAVE_ID_FM_ADDR         0x2A
-#define BAHAMA_SLAVE_ID_QMEMBIST_ADDR   0x7B
-#define BAHAMA_SLAVE_ID_FM_REG 0x02
-#define FM_GPIO	83
-#define BT_PCM_BCLK_MODE  0x88
-#define BT_PCM_DIN_MODE   0x89
-#define BT_PCM_DOUT_MODE  0x8A
-#define BT_PCM_SYNC_MODE  0x8B
-#define FM_I2S_SD_MODE    0x8E
-#define FM_I2S_WS_MODE    0x8F
-#define FM_I2S_SCK_MODE   0x90
-#define I2C_PIN_CTL       0x15
-#define I2C_NORMAL        0x40
 
 enum {
 	GPIO_EXPANDER_IRQ_BASE	= NR_MSM_IRQS + NR_GPIO_IRQS,
@@ -131,930 +117,12 @@
 };
 #endif
 
-#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
-
-	/* FM Platform power and shutdown routines */
-#define FPGA_MSM_CNTRL_REG2 0x90008010
-static int switch_pcm_i2s_reg_mode(int mode)
-{
-	unsigned char reg = 0;
-	int rc = -1;
-	unsigned char set = I2C_PIN_CTL; /*SET PIN CTL mode*/
-	unsigned char unset = I2C_NORMAL; /* UNSET PIN CTL MODE*/
-	struct marimba config = { .mod_id =  SLAVE_ID_BAHAMA};
-
-	if (mode == 0) {
-		/* as we need to switch path to FM we need to move
-		 BT AUX PCM lines to PIN CONTROL mode then move
-		 FM to normal mode.*/
-		for (reg = BT_PCM_BCLK_MODE; reg <= BT_PCM_SYNC_MODE; reg++) {
-			rc = marimba_write(&config, reg, &set, 1);
-			if (rc < 0) {
-				pr_err("pcm pinctl failed = %d", rc);
-				goto err_all;
-			}
-		}
-		for (reg = FM_I2S_SD_MODE; reg <= FM_I2S_SCK_MODE; reg++) {
-			rc = marimba_write(&config, reg, &unset, 1);
-			if (rc < 0) {
-				pr_err("i2s normal failed = %d", rc);
-				goto err_all;
-			}
-		}
-	} else {
-		/* as we need to switch path to AUXPCM we need to move
-		 FM I2S lines to PIN CONTROL mode then move
-		 BT AUX_PCM to normal mode.*/
-		for (reg = FM_I2S_SD_MODE; reg <= FM_I2S_SCK_MODE; reg++) {
-			rc = marimba_write(&config, reg, &set, 1);
-			if (rc < 0) {
-				pr_err("i2s pinctl failed = %d", rc);
-				goto err_all;
-			}
-		}
-		for (reg = BT_PCM_BCLK_MODE; reg <= BT_PCM_SYNC_MODE; reg++) {
-			rc = marimba_write(&config, reg, &unset, 1);
-			if (rc < 0) {
-				pr_err("pcm normal failed = %d", rc);
-				goto err_all;
-			}
-		}
-	}
-
-	return 0;
-
-err_all:
-	return rc;
-}
-
-static void config_pcm_i2s_mode(int mode)
-{
-	void __iomem *cfg_ptr;
-	u8 reg2;
-
-	cfg_ptr = ioremap_nocache(FPGA_MSM_CNTRL_REG2, sizeof(char));
-
-	if (!cfg_ptr)
-		return;
-	if (mode) {
-		/*enable the pcm mode in FPGA*/
-		reg2 = readb_relaxed(cfg_ptr);
-		if (reg2 == 0) {
-			reg2 = 1;
-			writeb_relaxed(reg2, cfg_ptr);
-		}
-	} else {
-		/*enable i2s mode in FPGA*/
-		reg2 = readb_relaxed(cfg_ptr);
-		if (reg2 == 1) {
-			reg2 = 0;
-			writeb_relaxed(reg2, cfg_ptr);
-		}
-	}
-	iounmap(cfg_ptr);
-}
-
-static unsigned fm_i2s_config_power_on[] = {
-	/*FM_I2S_SD*/
-	GPIO_CFG(68, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-	/*FM_I2S_WS*/
-	GPIO_CFG(70, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-	/*FM_I2S_SCK*/
-	GPIO_CFG(71, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-};
-
-static unsigned fm_i2s_config_power_off[] = {
-	/*FM_I2S_SD*/
-	GPIO_CFG(68, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-	/*FM_I2S_WS*/
-	GPIO_CFG(70, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-	/*FM_I2S_SCK*/
-	GPIO_CFG(71, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-};
-
-static unsigned bt_config_power_on[] = {
-	/*RFR*/
-	GPIO_CFG(43, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-	/*CTS*/
-	GPIO_CFG(44, 2, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-	/*RX*/
-	GPIO_CFG(45, 2, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-	/*TX*/
-	GPIO_CFG(46, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-};
-static unsigned bt_config_pcm_on[] = {
-	/*PCM_DOUT*/
-	GPIO_CFG(68, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-	/*PCM_DIN*/
-	GPIO_CFG(69, 1, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-	/*PCM_SYNC*/
-	GPIO_CFG(70, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-	/*PCM_CLK*/
-	GPIO_CFG(71, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-};
-static unsigned bt_config_power_off[] = {
-	/*RFR*/
-	GPIO_CFG(43, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-	/*CTS*/
-	GPIO_CFG(44, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-	/*RX*/
-	GPIO_CFG(45, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-	/*TX*/
-	GPIO_CFG(46, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-};
-static unsigned bt_config_pcm_off[] = {
-	/*PCM_DOUT*/
-	GPIO_CFG(68, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-	/*PCM_DIN*/
-	GPIO_CFG(69, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-	/*PCM_SYNC*/
-	GPIO_CFG(70, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-	/*PCM_CLK*/
-	GPIO_CFG(71, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-};
-
-static int config_i2s(int mode)
-{
-	int pin, rc = 0;
-
-	if (mode == FM_I2S_ON) {
-		if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf())
-			config_pcm_i2s_mode(0);
-		pr_err("%s mode = FM_I2S_ON", __func__);
-
-		rc = switch_pcm_i2s_reg_mode(0);
-		if (rc) {
-			pr_err("switch mode failed");
-			return rc;
-		}
-		for (pin = 0; pin < ARRAY_SIZE(fm_i2s_config_power_on);
-			pin++) {
-				rc = gpio_tlmm_config(
-					fm_i2s_config_power_on[pin],
-					GPIO_CFG_ENABLE
-					);
-				if (rc < 0)
-					return rc;
-			}
-	} else if (mode == FM_I2S_OFF) {
-		pr_err("%s mode = FM_I2S_OFF", __func__);
-		rc = switch_pcm_i2s_reg_mode(1);
-		if (rc) {
-			pr_err("switch mode failed");
-			return rc;
-		}
-		for (pin = 0; pin < ARRAY_SIZE(fm_i2s_config_power_off);
-			pin++) {
-				rc = gpio_tlmm_config(
-					fm_i2s_config_power_off[pin],
-					GPIO_CFG_ENABLE
-					);
-				if (rc < 0)
-					return rc;
-			}
-	}
-	return rc;
-}
-static int config_pcm(int mode)
-{
-	int pin, rc = 0;
-
-	if (mode == BT_PCM_ON) {
-		if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf())
-			config_pcm_i2s_mode(1);
-		pr_err("%s mode =BT_PCM_ON", __func__);
-		rc = switch_pcm_i2s_reg_mode(1);
-		if (rc) {
-			pr_err("switch mode failed");
-			return rc;
-		}
-		for (pin = 0; pin < ARRAY_SIZE(bt_config_pcm_on);
-			pin++) {
-				rc = gpio_tlmm_config(bt_config_pcm_on[pin],
-					GPIO_CFG_ENABLE);
-				if (rc < 0)
-					return rc;
-			}
-	} else if (mode == BT_PCM_OFF) {
-		pr_err("%s mode =BT_PCM_OFF", __func__);
-		rc = switch_pcm_i2s_reg_mode(0);
-		if (rc) {
-			pr_err("switch mode failed");
-			return rc;
-		}
-		for (pin = 0; pin < ARRAY_SIZE(bt_config_pcm_off);
-			pin++) {
-				rc = gpio_tlmm_config(bt_config_pcm_off[pin],
-					GPIO_CFG_ENABLE);
-				if (rc < 0)
-					return rc;
-			}
-
-	}
-
-	return rc;
-}
-
-static int msm_bahama_setup_pcm_i2s(int mode)
-{
-	int fm_state = 0, bt_state = 0;
-	int rc = 0;
-	struct marimba config = { .mod_id =  SLAVE_ID_BAHAMA};
-
-	fm_state = marimba_get_fm_status(&config);
-	bt_state = marimba_get_bt_status(&config);
-
-	switch (mode) {
-	case BT_PCM_ON:
-	case BT_PCM_OFF:
-		if (!fm_state)
-			rc = config_pcm(mode);
-		break;
-	case FM_I2S_ON:
-		rc = config_i2s(mode);
-		break;
-	case FM_I2S_OFF:
-		if (bt_state)
-			rc = config_pcm(BT_PCM_ON);
-		else
-			rc = config_i2s(mode);
-		break;
-	default:
-		rc = -EIO;
-		pr_err("%s:Unsupported mode", __func__);
-	}
-	return rc;
-}
-
-static int bt_set_gpio(int on)
-{
-	int rc = 0;
-	struct marimba config = { .mod_id =  SLAVE_ID_BAHAMA};
-
-	if (on) {
-		rc = gpio_direction_output(GPIO_BT_SYS_REST_EN, 1);
-		msleep(100);
-	} else {
-		if (!marimba_get_fm_status(&config) &&
-				!marimba_get_bt_status(&config)) {
-			gpio_set_value_cansleep(GPIO_BT_SYS_REST_EN, 0);
-			rc = gpio_direction_input(GPIO_BT_SYS_REST_EN);
-			msleep(100);
-		}
-	}
-	if (rc)
-		pr_err("%s: BT sys_reset_en GPIO : Error", __func__);
-
-	return rc;
-}
-static struct regulator *fm_regulator;
-static int fm_radio_setup(struct marimba_fm_platform_data *pdata)
-{
-	int rc = 0;
-	const char *id = "FMPW";
-	uint32_t irqcfg;
-	struct marimba config = { .mod_id =  SLAVE_ID_BAHAMA};
-	u8 value;
-
-	/* Voting for 1.8V Regulator */
-	fm_regulator = regulator_get(NULL, "msme1");
-	if (IS_ERR(fm_regulator)) {
-		rc = PTR_ERR(fm_regulator);
-		pr_err("%s: could not get regulator: %d\n", __func__, rc);
-		goto out;
-	}
-
-	/* Set the voltage level to 1.8V */
-	rc = regulator_set_voltage(fm_regulator, 1800000, 1800000);
-	if (rc < 0) {
-		pr_err("%s: could not set voltage: %d\n", __func__, rc);
-		goto reg_free;
-	}
-
-	/* Enabling the 1.8V regulator */
-	rc = regulator_enable(fm_regulator);
-	if (rc) {
-		pr_err("%s: could not enable regulator: %d\n", __func__, rc);
-		goto reg_free;
-	}
-
-	/* Voting for 19.2MHz clock */
-	rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
-			PMAPP_CLOCK_VOTE_ON);
-	if (rc < 0) {
-		pr_err("%s: clock vote failed with :(%d)\n",
-			 __func__, rc);
-		goto reg_disable;
-	}
-
-	rc = bt_set_gpio(1);
-	if (rc) {
-		pr_err("%s: bt_set_gpio = %d", __func__, rc);
-		goto gpio_deconfig;
-	}
-	/*re-write FM Slave Id, after reset*/
-	value = BAHAMA_SLAVE_ID_FM_ADDR;
-	rc = marimba_write_bit_mask(&config,
-			BAHAMA_SLAVE_ID_FM_REG, &value, 1, 0xFF);
-	if (rc < 0) {
-		pr_err("%s: FM Slave ID rewrite Failed = %d", __func__, rc);
-		goto gpio_deconfig;
-	}
-	/* Configuring the FM GPIO */
-	irqcfg = GPIO_CFG(FM_GPIO, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL,
-			GPIO_CFG_2MA);
-
-	rc = gpio_tlmm_config(irqcfg, GPIO_CFG_ENABLE);
-	if (rc) {
-		pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
-			 __func__, irqcfg, rc);
-		goto gpio_deconfig;
-	}
-
-	return 0;
-
-gpio_deconfig:
-	pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
-		PMAPP_CLOCK_VOTE_OFF);
-	bt_set_gpio(0);
-reg_disable:
-	regulator_disable(fm_regulator);
-reg_free:
-	regulator_put(fm_regulator);
-	fm_regulator = NULL;
-out:
-	return rc;
-};
-
-static void fm_radio_shutdown(struct marimba_fm_platform_data *pdata)
-{
-	int rc;
-	const char *id = "FMPW";
-
-	/* Releasing the GPIO line used by FM */
-	uint32_t irqcfg = GPIO_CFG(FM_GPIO, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_UP,
-		GPIO_CFG_2MA);
-
-	rc = gpio_tlmm_config(irqcfg, GPIO_CFG_ENABLE);
-	if (rc)
-		pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
-			 __func__, irqcfg, rc);
-
-	/* Releasing the 1.8V Regulator */
-	if (!IS_ERR_OR_NULL(fm_regulator)) {
-		rc = regulator_disable(fm_regulator);
-		if (rc)
-			pr_err("%s: could not disable regulator: %d\n",
-					__func__, rc);
-		regulator_put(fm_regulator);
-		fm_regulator = NULL;
-	}
-
-	/* Voting off the clock */
-	rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
-		PMAPP_CLOCK_VOTE_OFF);
-	if (rc < 0)
-		pr_err("%s: voting off failed with :(%d)\n",
-			__func__, rc);
-	rc = bt_set_gpio(0);
-	if (rc)
-		pr_err("%s: bt_set_gpio = %d", __func__, rc);
-}
-
-static struct marimba_fm_platform_data marimba_fm_pdata = {
-	.fm_setup = fm_radio_setup,
-	.fm_shutdown = fm_radio_shutdown,
-	.irq = MSM_GPIO_TO_INT(FM_GPIO),
-	.vreg_s2 = NULL,
-	.vreg_xo_out = NULL,
-	/* Configuring the FM SoC as I2S Master */
-	.is_fm_soc_i2s_master = true,
-	.config_i2s_gpio = msm_bahama_setup_pcm_i2s,
-};
 
 static struct platform_device msm_wlan_ar6000_pm_device = {
 	.name           = "wlan_ar6000_pm_dev",
 	.id             = -1,
 };
 
-static struct platform_device msm_bt_power_device = {
-	.name = "bt_power",
-};
-struct bahama_config_register {
-		u8 reg;
-		u8 value;
-		u8 mask;
-};
-struct bt_vreg_info {
-	const char *name;
-	unsigned int pmapp_id;
-	unsigned int min_level;
-	unsigned int max_level;
-	unsigned int is_pin_controlled;
-	struct regulator *reg;
-};
-static struct bt_vreg_info bt_vregs[] = {
-	{"msme1", 2, 1800000, 1800000, 0, NULL},
-	{"bt", 21, 2900000, 3300000, 1, NULL}
-};
-
-static int bahama_bt(int on)
-{
-	int rc = 0;
-	int i;
-
-	struct marimba config = { .mod_id =  SLAVE_ID_BAHAMA};
-
-	struct bahama_variant_register {
-		const size_t size;
-		const struct bahama_config_register *set;
-	};
-
-	const struct bahama_config_register *p;
-
-	u8 version;
-
-	const struct bahama_config_register v10_bt_on[] = {
-		{ 0xE9, 0x00, 0xFF },
-		{ 0xF4, 0x80, 0xFF },
-		{ 0xE4, 0x00, 0xFF },
-		{ 0xE5, 0x00, 0x0F },
-#ifdef CONFIG_WLAN
-		{ 0xE6, 0x38, 0x7F },
-		{ 0xE7, 0x06, 0xFF },
-#endif
-		{ 0xE9, 0x21, 0xFF },
-		{ 0x01, 0x0C, 0x1F },
-		{ 0x01, 0x08, 0x1F },
-	};
-
-	const struct bahama_config_register v20_bt_on_fm_off[] = {
-		{ 0x11, 0x0C, 0xFF },
-		{ 0x13, 0x01, 0xFF },
-		{ 0xF4, 0x80, 0xFF },
-		{ 0xF0, 0x00, 0xFF },
-		{ 0xE9, 0x00, 0xFF },
-#ifdef CONFIG_WLAN
-		{ 0x81, 0x00, 0x7F },
-		{ 0x82, 0x00, 0xFF },
-		{ 0xE6, 0x38, 0x7F },
-		{ 0xE7, 0x06, 0xFF },
-#endif
-		{ 0x8E, 0x15, 0xFF },
-		{ 0x8F, 0x15, 0xFF },
-		{ 0x90, 0x15, 0xFF },
-
-		{ 0xE9, 0x21, 0xFF },
-	};
-
-	const struct bahama_config_register v20_bt_on_fm_on[] = {
-		{ 0x11, 0x0C, 0xFF },
-		{ 0x13, 0x01, 0xFF },
-		{ 0xF4, 0x86, 0xFF },
-		{ 0xF0, 0x06, 0xFF },
-		{ 0xE9, 0x00, 0xFF },
-#ifdef CONFIG_WLAN
-		{ 0x81, 0x00, 0x7F },
-		{ 0x82, 0x00, 0xFF },
-		{ 0xE6, 0x38, 0x7F },
-		{ 0xE7, 0x06, 0xFF },
-#endif
-		{ 0xE9, 0x21, 0xFF },
-	};
-
-	const struct bahama_config_register v10_bt_off[] = {
-		{ 0xE9, 0x00, 0xFF },
-	};
-
-	const struct bahama_config_register v20_bt_off_fm_off[] = {
-		{ 0xF4, 0x84, 0xFF },
-		{ 0xF0, 0x04, 0xFF },
-		{ 0xE9, 0x00, 0xFF }
-	};
-
-	const struct bahama_config_register v20_bt_off_fm_on[] = {
-		{ 0xF4, 0x86, 0xFF },
-		{ 0xF0, 0x06, 0xFF },
-		{ 0xE9, 0x00, 0xFF }
-	};
-	const struct bahama_variant_register bt_bahama[2][3] = {
-	{
-		{ ARRAY_SIZE(v10_bt_off), v10_bt_off },
-		{ ARRAY_SIZE(v20_bt_off_fm_off), v20_bt_off_fm_off },
-		{ ARRAY_SIZE(v20_bt_off_fm_on), v20_bt_off_fm_on }
-	},
-	{
-		{ ARRAY_SIZE(v10_bt_on), v10_bt_on },
-		{ ARRAY_SIZE(v20_bt_on_fm_off), v20_bt_on_fm_off },
-		{ ARRAY_SIZE(v20_bt_on_fm_on), v20_bt_on_fm_on }
-	}
-	};
-
-	u8 offset = 0; /* index into bahama configs */
-	on = on ? 1 : 0;
-	version = marimba_read_bahama_ver(&config);
-	if ((int)version < 0 || version == BAHAMA_VER_UNSUPPORTED) {
-		dev_err(&msm_bt_power_device.dev, "%s: Bahama \
-				version read Error, version = %d \n",
-				__func__, version);
-		return -EIO;
-	}
-
-	if (version == BAHAMA_VER_2_0) {
-		if (marimba_get_fm_status(&config))
-			offset = 0x01;
-	}
-
-	p = bt_bahama[on][version + offset].set;
-
-	dev_info(&msm_bt_power_device.dev,
-		"%s: found version %d\n", __func__, version);
-
-	for (i = 0; i < bt_bahama[on][version + offset].size; i++) {
-		u8 value = (p+i)->value;
-		rc = marimba_write_bit_mask(&config,
-			(p+i)->reg,
-			&value,
-			sizeof((p+i)->value),
-			(p+i)->mask);
-		if (rc < 0) {
-			dev_err(&msm_bt_power_device.dev,
-				"%s: reg %x write failed: %d\n",
-				__func__, (p+i)->reg, rc);
-			return rc;
-		}
-		dev_dbg(&msm_bt_power_device.dev,
-			"%s: reg 0x%02x write value 0x%02x mask 0x%02x\n",
-				__func__, (p+i)->reg,
-				value, (p+i)->mask);
-		value = 0;
-		rc = marimba_read_bit_mask(&config,
-				(p+i)->reg, &value,
-				sizeof((p+i)->value), (p+i)->mask);
-		if (rc < 0)
-			dev_err(&msm_bt_power_device.dev, "%s marimba_read_bit_mask- error",
-					__func__);
-		dev_dbg(&msm_bt_power_device.dev,
-			"%s: reg 0x%02x read value 0x%02x mask 0x%02x\n",
-				__func__, (p+i)->reg,
-				value, (p+i)->mask);
-	}
-	/* Update BT Status */
-	if (on)
-		marimba_set_bt_status(&config, true);
-	else
-		marimba_set_bt_status(&config, false);
-	return rc;
-}
-static int bluetooth_switch_regulators(int on)
-{
-	int i, rc = 0;
-	const char *id = "BTPW";
-
-	for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
-		if (IS_ERR_OR_NULL(bt_vregs[i].reg)) {
-			rc = bt_vregs[i].reg ?
-				PTR_ERR(bt_vregs[i].reg) :
-				-ENODEV;
-			dev_err(&msm_bt_power_device.dev,
-				"%s: invalid regulator handle for %s: %d\n",
-					__func__, bt_vregs[i].name, rc);
-			goto reg_disable;
-		}
-
-		rc = on ? regulator_set_voltage(bt_vregs[i].reg,
-				bt_vregs[i].min_level,
-					bt_vregs[i].max_level) : 0;
-		if (rc) {
-			dev_err(&msm_bt_power_device.dev,
-				"%s: could not set voltage for %s: %d\n",
-					__func__, bt_vregs[i].name, rc);
-			goto reg_disable;
-		}
-
-		rc = on ? regulator_enable(bt_vregs[i].reg) : 0;
-		if (rc) {
-			dev_err(&msm_bt_power_device.dev,
-				"%s: could not %sable regulator %s: %d\n",
-					__func__, "en", bt_vregs[i].name, rc);
-			goto reg_disable;
-		}
-
-		if (bt_vregs[i].is_pin_controlled) {
-			rc = pmapp_vreg_lpm_pincntrl_vote(id,
-					bt_vregs[i].pmapp_id,
-					PMAPP_CLOCK_ID_D1,
-					on ? PMAPP_CLOCK_VOTE_ON :
-						PMAPP_CLOCK_VOTE_OFF);
-			if (rc) {
-				dev_err(&msm_bt_power_device.dev,
-					"%s: pin control failed for %s: %d\n",
-					__func__, bt_vregs[i].name, rc);
-				goto pin_cnt_fail;
-			}
-		}
-		rc = on ? 0 : regulator_disable(bt_vregs[i].reg);
-
-		if (rc) {
-			dev_err(&msm_bt_power_device.dev,
-				"%s: could not %sable regulator %s: %d\n",
-				__func__, "dis", bt_vregs[i].name, rc);
-			goto reg_disable;
-		}
-	}
-
-	return rc;
-pin_cnt_fail:
-	if (on)
-		regulator_disable(bt_vregs[i].reg);
-reg_disable:
-	while (i) {
-		if (on) {
-			i--;
-			regulator_disable(bt_vregs[i].reg);
-			regulator_put(bt_vregs[i].reg);
-		}
-	}
-	return rc;
-}
-
-static struct regulator *reg_s3;
-static unsigned int msm_bahama_setup_power(void)
-{
-	int rc = 0;
-
-	reg_s3 = regulator_get(NULL, "msme1");
-	if (IS_ERR(reg_s3)) {
-		rc = PTR_ERR(reg_s3);
-		pr_err("%s: could not get regulator: %d\n", __func__, rc);
-		goto out;
-	}
-
-	rc = regulator_set_voltage(reg_s3, 1800000, 1800000);
-	if (rc) {
-		pr_err("%s: could not set voltage: %d\n", __func__, rc);
-		goto reg_fail;
-	}
-
-	rc = regulator_enable(reg_s3);
-	if (rc < 0) {
-		pr_err("%s: could not enable regulator: %d\n", __func__, rc);
-		goto reg_fail;
-	}
-
-	/*setup Bahama_sys_reset_n*/
-	rc = gpio_request(GPIO_BT_SYS_REST_EN, "bahama sys_rst_n");
-	if (rc) {
-		pr_err("%s: gpio_request %d = %d\n", __func__,
-			GPIO_BT_SYS_REST_EN, rc);
-		goto reg_disable;
-	}
-
-	rc = bt_set_gpio(1);
-	if (rc) {
-		pr_err("%s: bt_set_gpio %d = %d\n", __func__,
-			GPIO_BT_SYS_REST_EN, rc);
-		goto gpio_fail;
-	}
-
-	return rc;
-
-gpio_fail:
-	gpio_free(GPIO_BT_SYS_REST_EN);
-reg_disable:
-	regulator_disable(reg_s3);
-reg_fail:
-	regulator_put(reg_s3);
-out:
-	reg_s3 = NULL;
-	return rc;
-}
-
-static unsigned int msm_bahama_shutdown_power(int value)
-{
-	int rc = 0;
-
-	if (IS_ERR_OR_NULL(reg_s3)) {
-		rc = reg_s3 ? PTR_ERR(reg_s3) : -ENODEV;
-		goto out;
-	}
-
-	rc = regulator_disable(reg_s3);
-	if (rc) {
-		pr_err("%s: could not disable regulator: %d\n", __func__, rc);
-		goto out;
-	}
-
-	if (value == BAHAMA_ID) {
-		rc = bt_set_gpio(0);
-		if (rc) {
-			pr_err("%s: bt_set_gpio = %d\n",
-					__func__, rc);
-		}
-		gpio_free(GPIO_BT_SYS_REST_EN);
-	}
-
-	regulator_put(reg_s3);
-	reg_s3 = NULL;
-
-	return 0;
-
-out:
-	return rc;
-}
-
-static unsigned int msm_bahama_core_config(int type)
-{
-	int rc = 0;
-
-	if (type == BAHAMA_ID) {
-		int i;
-		struct marimba config = { .mod_id =  SLAVE_ID_BAHAMA};
-		const struct bahama_config_register v20_init[] = {
-			/* reg, value, mask */
-			{ 0xF4, 0x84, 0xFF }, /* AREG */
-			{ 0xF0, 0x04, 0xFF } /* DREG */
-		};
-		if (marimba_read_bahama_ver(&config) == BAHAMA_VER_2_0) {
-			for (i = 0; i < ARRAY_SIZE(v20_init); i++) {
-				u8 value = v20_init[i].value;
-				rc = marimba_write_bit_mask(&config,
-					v20_init[i].reg,
-					&value,
-					sizeof(v20_init[i].value),
-					v20_init[i].mask);
-				if (rc < 0) {
-					pr_err("%s: reg %d write failed: %d\n",
-						__func__, v20_init[i].reg, rc);
-					return rc;
-				}
-				pr_debug("%s: reg 0x%02x value 0x%02x"
-					" mask 0x%02x\n",
-					__func__, v20_init[i].reg,
-					v20_init[i].value, v20_init[i].mask);
-			}
-		}
-	}
-	rc = bt_set_gpio(0);
-	if (rc) {
-		pr_err("%s: bt_set_gpio = %d\n",
-		       __func__, rc);
-	}
-	pr_debug("core type: %d\n", type);
-	return rc;
-}
-
-static int bluetooth_power(int on)
-{
-	int pin, rc = 0;
-	const char *id = "BTPW";
-	int cid = 0;
-
-	cid = adie_get_detected_connectivity_type();
-	if (cid != BAHAMA_ID) {
-		pr_err("%s: unexpected adie connectivity type: %d\n",
-					__func__, cid);
-		return -ENODEV;
-	}
-	if (on) {
-		/*setup power for BT SOC*/
-		rc = bt_set_gpio(on);
-		if (rc) {
-			pr_err("%s: bt_set_gpio = %d\n",
-					__func__, rc);
-			goto exit;
-		}
-		rc = bluetooth_switch_regulators(on);
-		if (rc < 0) {
-			pr_err("%s: bluetooth_switch_regulators rc = %d",
-					__func__, rc);
-			goto exit;
-		}
-		/*setup BT GPIO lines*/
-		for (pin = 0; pin < ARRAY_SIZE(bt_config_power_on);
-			pin++) {
-			rc = gpio_tlmm_config(bt_config_power_on[pin],
-					GPIO_CFG_ENABLE);
-			if (rc < 0) {
-				pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
-						__func__,
-						bt_config_power_on[pin],
-						rc);
-				goto fail_power;
-			}
-		}
-		/*Setup BT clocks*/
-		rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
-			PMAPP_CLOCK_VOTE_ON);
-		if (rc < 0) {
-			pr_err("Failed to vote for TCXO_D1 ON\n");
-			goto fail_clock;
-		}
-		msleep(20);
-
-		/*I2C config for Bahama*/
-		rc = bahama_bt(1);
-		if (rc < 0) {
-			pr_err("%s: bahama_bt rc = %d", __func__, rc);
-			goto fail_i2c;
-		}
-		msleep(20);
-
-		/*setup BT PCM lines*/
-		rc = msm_bahama_setup_pcm_i2s(BT_PCM_ON);
-		if (rc < 0) {
-			pr_err("%s: msm_bahama_setup_pcm_i2s , rc =%d\n",
-				__func__, rc);
-				goto fail_power;
-			}
-		rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
-				  PMAPP_CLOCK_VOTE_PIN_CTRL);
-		if (rc < 0)
-			pr_err("%s:Pin Control Failed, rc = %d",
-					__func__, rc);
-
-	} else {
-		rc = bahama_bt(0);
-		if (rc < 0)
-			pr_err("%s: bahama_bt rc = %d", __func__, rc);
-
-		rc = bt_set_gpio(on);
-		if (rc) {
-			pr_err("%s: bt_set_gpio = %d\n",
-					__func__, rc);
-		}
-fail_i2c:
-		rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
-				  PMAPP_CLOCK_VOTE_OFF);
-		if (rc < 0)
-			pr_err("%s: Failed to vote Off D1\n", __func__);
-fail_clock:
-		for (pin = 0; pin < ARRAY_SIZE(bt_config_power_off);
-			pin++) {
-				rc = gpio_tlmm_config(bt_config_power_off[pin],
-					GPIO_CFG_ENABLE);
-				if (rc < 0) {
-					pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
-					__func__, bt_config_power_off[pin], rc);
-				}
-			}
-		rc = msm_bahama_setup_pcm_i2s(BT_PCM_OFF);
-		if (rc < 0) {
-			pr_err("%s: msm_bahama_setup_pcm_i2s, rc =%d\n",
-					__func__, rc);
-				}
-fail_power:
-		rc = bluetooth_switch_regulators(0);
-		if (rc < 0) {
-			pr_err("%s: switch_regulators : rc = %d",\
-					__func__, rc);
-			goto exit;
-		}
-	}
-	return rc;
-exit:
-	pr_err("%s: failed with rc = %d", __func__, rc);
-	return rc;
-}
-
-static int __init bt_power_init(void)
-{
-	int i, rc = 0;
-	struct device *dev = &msm_bt_power_device.dev;
-
-	for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
-		bt_vregs[i].reg = regulator_get(dev, bt_vregs[i].name);
-		if (IS_ERR(bt_vregs[i].reg)) {
-			rc = PTR_ERR(bt_vregs[i].reg);
-			dev_err(dev, "%s: could not get regulator %s: %d\n",
-					__func__, bt_vregs[i].name, rc);
-			goto reg_get_fail;
-		}
-	}
-
-	dev->platform_data = &bluetooth_power;
-
-	return rc;
-
-reg_get_fail:
-	while (i--) {
-		regulator_put(bt_vregs[i].reg);
-		bt_vregs[i].reg = NULL;
-	}
-	return rc;
-}
-
-static struct marimba_platform_data marimba_pdata = {
-	.slave_id[SLAVE_ID_BAHAMA_FM]        = BAHAMA_SLAVE_ID_FM_ADDR,
-	.slave_id[SLAVE_ID_BAHAMA_QMEMBIST]  = BAHAMA_SLAVE_ID_QMEMBIST_ADDR,
-	.bahama_setup                        = msm_bahama_setup_power,
-	.bahama_shutdown                     = msm_bahama_shutdown_power,
-	.bahama_core_config                  = msm_bahama_core_config,
-	.fm				     = &marimba_fm_pdata,
-};
-
-#endif
-
 #if defined(CONFIG_I2C) && defined(CONFIG_GPIO_SX150X)
 static struct i2c_board_info core_exp_i2c_info[] __initdata = {
 	{
@@ -1068,14 +136,6 @@
 	},
 };
 #endif
-#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
-static struct i2c_board_info bahama_devices[] = {
-{
-	I2C_BOARD_INFO("marimba", 0xc),
-	.platform_data = &marimba_pdata,
-},
-};
-#endif
 
 #if defined(CONFIG_I2C) && defined(CONFIG_GPIO_SX150X)
 static void __init register_i2c_devices(void)
@@ -1094,11 +154,6 @@
 	i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
 				core_exp_i2c_info,
 				ARRAY_SIZE(core_exp_i2c_info));
-#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
-	i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
-				bahama_devices,
-				ARRAY_SIZE(bahama_devices));
-#endif
 }
 #endif
 
@@ -1163,7 +218,7 @@
 #define MSM7x25A_MSM_FB_SIZE	0xE1000
 #else
 #define MSM_FB_SIZE		0x195000
-#define MSM7x25A_MSM_FB_SIZE	0xE1000
+#define MSM7x25A_MSM_FB_SIZE	0x96000
 
 #endif
 
@@ -1366,8 +421,8 @@
 };
 
 static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
-	.mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT,
-	.v_addr = (uint32_t *)PAGE_OFFSET,
+	.mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS,
+	.p_addr = 0,
 };
 
 static struct android_pmem_platform_data android_pmem_adsp_pdata = {
@@ -2959,7 +2014,7 @@
 	register_i2c_devices();
 #endif
 #if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
-	bt_power_init();
+	msm7627a_bt_power_init();
 #endif
 	if (machine_is_msm7625a_surf() || machine_is_msm7625a_ffa()) {
 		atmel_ts_pdata.min_x = 0;
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 857c88a..883404f 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -3862,6 +3862,8 @@
 	.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
 	.hw_key_support = QCE_HW_KEY_SUPPORT,
 	.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+	/* Bus Scaling declaration*/
+	.bus_scale_table = NULL,
 };
 
 static struct platform_device qcrypto_device = {
@@ -3884,6 +3886,8 @@
 	.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
 	.hw_key_support = QCE_HW_KEY_SUPPORT,
 	.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+	/* Bus Scaling declaration*/
+	.bus_scale_table = NULL,
 };
 static struct platform_device qcedev_device = {
 	.name		= "qce",
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 75c1b80..ba7e658 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -53,6 +53,7 @@
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/setup.h>
+#include <asm/hardware/gic.h>
 
 #include <mach/dma.h>
 #include <mach/board.h>
@@ -602,6 +603,7 @@
 	.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
 	.hw_key_support = QCE_HW_KEY_SUPPORT,
 	.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+	.bus_scale_table = NULL,
 };
 
 static struct platform_device qcrypto_device = {
@@ -624,6 +626,7 @@
 	.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
 	.hw_key_support = QCE_HW_KEY_SUPPORT,
 	.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+	.bus_scale_table = NULL,
 };
 
 static struct platform_device qcedev_device = {
@@ -2627,23 +2630,12 @@
 #define MSM_FB_EXT_BUFT_SIZE	0
 #endif
 
-#ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
-/* width x height x 3 bpp x 2 frame buffer */
-#define MSM_FB_WRITEBACK_SIZE (1024 * 600 * 3 * 2)
-#define MSM_FB_WRITEBACK_OFFSET  \
-		(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE)
-#else
-#define MSM_FB_WRITEBACK_SIZE	0
-#define MSM_FB_WRITEBACK_OFFSET 0
-#endif
-
 #ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
 /* 4 bpp x 2 page HDMI case */
 #define MSM_FB_SIZE roundup((1920 * 1088 * 4 * 2), 4096)
 #else
 /* Note: must be multiple of 4096 */
 #define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE + \
-				MSM_FB_WRITEBACK_SIZE + \
 				MSM_FB_DSUB_PMEM_ADDER, 4096)
 #endif
 
@@ -2653,10 +2645,17 @@
 #define MSM_PMEM_SF_SIZE 0x4000000 /* 64 Mbytes */
 #endif
 
-static int writeback_offset(void)
-{
-	return MSM_FB_WRITEBACK_OFFSET;
-}
+#ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
+#define MSM_FB_OVERLAY0_WRITEBACK_SIZE roundup((1376 * 768 * 3 * 2), 4096)
+#else
+#define MSM_FB_OVERLAY0_WRITEBACK_SIZE (0)
+#endif  /* CONFIG_FB_MSM_OVERLAY0_WRITEBACK */
+
+#ifdef CONFIG_FB_MSM_OVERLAY1_WRITEBACK
+#define MSM_FB_OVERLAY1_WRITEBACK_SIZE roundup((1920 * 1088 * 3 * 2), 4096)
+#else
+#define MSM_FB_OVERLAY1_WRITEBACK_SIZE (0)
+#endif  /* CONFIG_FB_MSM_OVERLAY1_WRITEBACK */
 
 #define MSM_PMEM_KERNEL_EBI1_SIZE  0x600000
 #define MSM_PMEM_ADSP_SIZE         0x2000000
@@ -2861,36 +2860,39 @@
 		}, \
 	.num_paths = 1, \
 	}
-#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
-static struct msm_bus_paths pmem_smi_table[] = {
+
+static struct msm_bus_paths mem_smi_table[] = {
 	[0] = PMEM_BUS_WIDTH(0), /* Off */
 	[1] = PMEM_BUS_WIDTH(1), /* On */
 };
 
 static struct msm_bus_scale_pdata smi_client_pdata = {
-	.usecase = pmem_smi_table,
-	.num_usecases = ARRAY_SIZE(pmem_smi_table),
-	.name = "pmem_smi",
+	.usecase = mem_smi_table,
+	.num_usecases = ARRAY_SIZE(mem_smi_table),
+	.name = "mem_smi",
 };
 
-void request_smi_region(void *data)
+int request_smi_region(void *data)
 {
 	int bus_id = (int) data;
 
 	msm_bus_scale_client_update_request(bus_id, 1);
+	return 0;
 }
 
-void release_smi_region(void *data)
+int release_smi_region(void *data)
 {
 	int bus_id = (int) data;
 
 	msm_bus_scale_client_update_request(bus_id, 0);
+	return 0;
 }
 
 void *setup_smi_region(void)
 {
 	return (void *)msm_bus_scale_register_client(&smi_client_pdata);
 }
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
 static struct android_pmem_platform_data android_pmem_smipool_pdata = {
 	.name = "pmem_smipool",
 	.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
@@ -5087,6 +5089,8 @@
 	&msm_device_smd,
 	&msm_device_uart_dm12,
 	&msm_pil_q6v3,
+	&msm_pil_modem,
+	&msm_pil_tzapps,
 #ifdef CONFIG_I2C_QUP
 	&msm_gsbi3_qup_i2c_device,
 	&msm_gsbi4_qup_i2c_device,
@@ -5268,6 +5272,9 @@
 			.name	= ION_SMI_HEAP_NAME,
 			.size	= MSM_ION_SMI_SIZE,
 			.memory_type = ION_SMI_TYPE,
+			.request_region = request_smi_region,
+			.release_region = release_smi_region,
+			.setup_region = setup_smi_region,
 		},
 #endif
 	}
@@ -5347,13 +5354,14 @@
 #endif
 }
 
-
+static void __init reserve_mdp_memory(void);
 
 static void __init msm8x60_calculate_reserve_sizes(void)
 {
 	size_pmem_devices();
 	reserve_pmem_memory();
 	reserve_ion_memory();
+	reserve_mdp_memory();
 }
 
 static int msm8x60_paddr_to_memtype(unsigned int paddr)
@@ -9421,9 +9429,21 @@
 	.mdp_bus_scale_table = &mdp_bus_scale_pdata,
 #endif
 	.mdp_rev = MDP_REV_41,
-	.writeback_offset = writeback_offset,
+	.mdp_writeback_memtype = MEMTYPE_EBI1,
+	.mdp_writeback_phys = NULL,
 };
 
+static void __init reserve_mdp_memory(void)
+{
+	mdp_pdata.mdp_writeback_size_ov0 = MSM_FB_OVERLAY0_WRITEBACK_SIZE;
+	mdp_pdata.mdp_writeback_size_ov1 = MSM_FB_OVERLAY1_WRITEBACK_SIZE;
+
+	msm8x60_reserve_table[mdp_pdata.mdp_writeback_memtype].size +=
+		mdp_pdata.mdp_writeback_size_ov0;
+	msm8x60_reserve_table[mdp_pdata.mdp_writeback_memtype].size +=
+		mdp_pdata.mdp_writeback_size_ov1;
+}
+
 #ifdef CONFIG_FB_MSM_TVOUT
 
 #ifdef CONFIG_MSM_BUS_SCALING
@@ -10259,6 +10279,7 @@
 	.map_io = msm8x60_map_io,
 	.reserve = msm8x60_reserve,
 	.init_irq = msm8x60_init_irq,
+	.handle_irq = gic_handle_irq,
 	.init_machine = msm8x60_rumi3_init,
 	.timer = &msm_timer,
 	.init_early = msm8x60_charm_init_early,
@@ -10268,6 +10289,7 @@
 	.map_io = msm8x60_map_io,
 	.reserve = msm8x60_reserve,
 	.init_irq = msm8x60_init_irq,
+	.handle_irq = gic_handle_irq,
 	.init_machine = msm8x60_sim_init,
 	.timer = &msm_timer,
 	.init_early = msm8x60_charm_init_early,
@@ -10277,6 +10299,7 @@
 	.map_io = msm8x60_map_io,
 	.reserve = msm8x60_reserve,
 	.init_irq = msm8x60_init_irq,
+	.handle_irq = gic_handle_irq,
 	.init_machine = msm8x60_surf_init,
 	.timer = &msm_timer,
 	.init_early = msm8x60_charm_init_early,
@@ -10286,6 +10309,7 @@
 	.map_io = msm8x60_map_io,
 	.reserve = msm8x60_reserve,
 	.init_irq = msm8x60_init_irq,
+	.handle_irq = gic_handle_irq,
 	.init_machine = msm8x60_ffa_init,
 	.timer = &msm_timer,
 	.init_early = msm8x60_charm_init_early,
@@ -10295,6 +10319,7 @@
 	.map_io = msm8x60_map_io,
 	.reserve = msm8x60_reserve,
 	.init_irq = msm8x60_init_irq,
+	.handle_irq = gic_handle_irq,
 	.init_machine = msm8x60_fluid_init,
 	.timer = &msm_timer,
 	.init_early = msm8x60_charm_init_early,
@@ -10304,6 +10329,7 @@
 	.map_io = msm8x60_map_io,
 	.reserve = msm8x60_reserve,
 	.init_irq = msm8x60_init_irq,
+	.handle_irq = gic_handle_irq,
 	.init_machine = msm8x60_charm_surf_init,
 	.timer = &msm_timer,
 	.init_early = msm8x60_charm_init_early,
@@ -10313,6 +10339,7 @@
 	.map_io = msm8x60_map_io,
 	.reserve = msm8x60_reserve,
 	.init_irq = msm8x60_init_irq,
+	.handle_irq = gic_handle_irq,
 	.init_machine = msm8x60_charm_ffa_init,
 	.timer = &msm_timer,
 	.init_early = msm8x60_charm_init_early,
@@ -10322,6 +10349,7 @@
 	.map_io = msm8x60_map_io,
 	.reserve = msm8x60_reserve,
 	.init_irq = msm8x60_init_irq,
+	.handle_irq = gic_handle_irq,
 	.init_machine = msm8x60_dragon_init,
 	.timer = &msm_timer,
 	.init_early = msm8x60_charm_init_early,
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 889ac00..08ec05e 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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 version 2 and
@@ -56,10 +56,17 @@
 
 #define PMEM_KERNEL_EBI1_SIZE	0x3A000
 #define MSM_PMEM_AUDIO_SIZE	0x5B000
-#define BAHAMA_SLAVE_ID_FM_ADDR         0x2A
-#define BAHAMA_SLAVE_ID_QMEMBIST_ADDR   0x7B
 #define BAHAMA_SLAVE_ID_FM_REG 0x02
 #define FM_GPIO	83
+#define BT_PCM_BCLK_MODE  0x88
+#define BT_PCM_DIN_MODE   0x89
+#define BT_PCM_DOUT_MODE  0x8A
+#define BT_PCM_SYNC_MODE  0x8B
+#define FM_I2S_SD_MODE    0x8E
+#define FM_I2S_WS_MODE    0x8F
+#define FM_I2S_SCK_MODE   0x90
+#define I2C_PIN_CTL       0x15
+#define I2C_NORMAL        0x40
 
 enum {
 	GPIO_HOST_VBUS_EN	= 107,
@@ -75,877 +82,11 @@
 	GPIO_CAM_GP_CAMIF_RESET,
 };
 
-	/* FM Platform power and shutdown routines */
-#define FPGA_MSM_CNTRL_REG2 0x90008010
-
-#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
-static void config_pcm_i2s_mode(int mode)
-{
-	void __iomem *cfg_ptr;
-	u8 reg2;
-
-	cfg_ptr = ioremap_nocache(FPGA_MSM_CNTRL_REG2, sizeof(char));
-
-	if (!cfg_ptr)
-		return;
-	if (mode) {
-		/*enable the pcm mode in FPGA*/
-		reg2 = readb_relaxed(cfg_ptr);
-		if (reg2 == 0) {
-			reg2 = 1;
-			writeb_relaxed(reg2, cfg_ptr);
-		}
-	} else {
-		/*enable i2s mode in FPGA*/
-		reg2 = readb_relaxed(cfg_ptr);
-		if (reg2 == 1) {
-			reg2 = 0;
-			writeb_relaxed(reg2, cfg_ptr);
-		}
-	}
-	iounmap(cfg_ptr);
-}
-
-static unsigned fm_i2s_config_power_on[] = {
-	/*FM_I2S_SD*/
-	GPIO_CFG(68, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-	/*FM_I2S_WS*/
-	GPIO_CFG(70, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-	/*FM_I2S_SCK*/
-	GPIO_CFG(71, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-};
-
-static unsigned fm_i2s_config_power_off[] = {
-	/*FM_I2S_SD*/
-	GPIO_CFG(68, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-	/*FM_I2S_WS*/
-	GPIO_CFG(70, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-	/*FM_I2S_SCK*/
-	GPIO_CFG(71, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-};
-
-static unsigned bt_config_power_on[] = {
-	/*RFR*/
-	GPIO_CFG(43, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-	/*CTS*/
-	GPIO_CFG(44, 2, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-	/*RX*/
-	GPIO_CFG(45, 2, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-	/*TX*/
-	GPIO_CFG(46, 2, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-};
-static unsigned bt_config_pcm_on[] = {
-	/*PCM_DOUT*/
-	GPIO_CFG(68, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-	/*PCM_DIN*/
-	GPIO_CFG(69, 1, GPIO_CFG_INPUT,  GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-	/*PCM_SYNC*/
-	GPIO_CFG(70, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-	/*PCM_CLK*/
-	GPIO_CFG(71, 1, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
-};
-static unsigned bt_config_power_off[] = {
-	/*RFR*/
-	GPIO_CFG(43, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-	/*CTS*/
-	GPIO_CFG(44, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-	/*RX*/
-	GPIO_CFG(45, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-	/*TX*/
-	GPIO_CFG(46, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-};
-static unsigned bt_config_pcm_off[] = {
-	/*PCM_DOUT*/
-	GPIO_CFG(68, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-	/*PCM_DIN*/
-	GPIO_CFG(69, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-	/*PCM_SYNC*/
-	GPIO_CFG(70, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-	/*PCM_CLK*/
-	GPIO_CFG(71, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-};
-
-
-static int config_i2s(int mode)
-{
-	int pin, rc = 0;
-
-	if (mode == FM_I2S_ON) {
-		if (machine_is_msm7627a_qrd1())
-			config_pcm_i2s_mode(0);
-		pr_err("%s mode = FM_I2S_ON", __func__);
-		for (pin = 0; pin < ARRAY_SIZE(fm_i2s_config_power_on);
-			pin++) {
-				rc = gpio_tlmm_config(
-					fm_i2s_config_power_on[pin],
-					GPIO_CFG_ENABLE
-					);
-				if (rc < 0)
-					return rc;
-			}
-	} else if (mode == FM_I2S_OFF) {
-		pr_err("%s mode = FM_I2S_OFF", __func__);
-		for (pin = 0; pin < ARRAY_SIZE(fm_i2s_config_power_off);
-			pin++) {
-				rc = gpio_tlmm_config(
-					fm_i2s_config_power_off[pin],
-					GPIO_CFG_ENABLE
-					);
-				if (rc < 0)
-					return rc;
-			}
-	}
-	return rc;
-}
-static int config_pcm(int mode)
-{
-	int pin, rc = 0;
-
-	if (mode == BT_PCM_ON) {
-		if (machine_is_msm7627a_qrd1())
-			config_pcm_i2s_mode(1);
-		pr_err("%s mode =BT_PCM_ON", __func__);
-		for (pin = 0; pin < ARRAY_SIZE(bt_config_pcm_on);
-			pin++) {
-				rc = gpio_tlmm_config(bt_config_pcm_on[pin],
-					GPIO_CFG_ENABLE);
-				if (rc < 0)
-					return rc;
-			}
-	} else if (mode == BT_PCM_OFF) {
-		pr_err("%s mode =BT_PCM_OFF", __func__);
-		for (pin = 0; pin < ARRAY_SIZE(bt_config_pcm_off);
-			pin++) {
-				rc = gpio_tlmm_config(bt_config_pcm_off[pin],
-					GPIO_CFG_ENABLE);
-				if (rc < 0)
-					return rc;
-			}
-
-	}
-
-	return rc;
-}
-
-static int msm_bahama_setup_pcm_i2s(int mode)
-{
-	int fm_state = 0, bt_state = 0;
-	int rc = 0;
-	struct marimba config = { .mod_id =  SLAVE_ID_BAHAMA};
-
-	fm_state = marimba_get_fm_status(&config);
-	bt_state = marimba_get_bt_status(&config);
-
-	switch (mode) {
-	case BT_PCM_ON:
-	case BT_PCM_OFF:
-		if (!fm_state)
-			rc = config_pcm(mode);
-		break;
-	case FM_I2S_ON:
-		rc = config_i2s(mode);
-		break;
-	case FM_I2S_OFF:
-		if (bt_state)
-			rc = config_pcm(BT_PCM_ON);
-		else
-			rc = config_i2s(mode);
-		break;
-	default:
-		rc = -EIO;
-		pr_err("%s:Unsupported mode", __func__);
-	}
-	return rc;
-}
-
-static int bt_set_gpio(int on)
-{
-	int rc = 0;
-	struct marimba config = { .mod_id =  SLAVE_ID_BAHAMA};
-
-	if (on) {
-		rc = gpio_direction_output(GPIO_BT_SYS_REST_EN, 1);
-		msleep(100);
-	} else {
-		if (!marimba_get_fm_status(&config) &&
-				!marimba_get_bt_status(&config)) {
-			gpio_set_value_cansleep(GPIO_BT_SYS_REST_EN, 0);
-			rc = gpio_direction_input(GPIO_BT_SYS_REST_EN);
-			msleep(100);
-		}
-	}
-	if (rc)
-		pr_err("%s: BT sys_reset_en GPIO : Error", __func__);
-
-	return rc;
-}
-static struct regulator *fm_regulator;
-static int fm_radio_setup(struct marimba_fm_platform_data *pdata)
-{
-	int rc = 0;
-	const char *id = "FMPW";
-	uint32_t irqcfg;
-	struct marimba config = { .mod_id =  SLAVE_ID_BAHAMA};
-	u8 value;
-
-	/* Voting for 1.8V Regulator */
-	fm_regulator = regulator_get(NULL , "msme1");
-	if (IS_ERR(fm_regulator)) {
-		rc = PTR_ERR(fm_regulator);
-		pr_err("%s: could not get regulator: %d\n", __func__, rc);
-		goto out;
-	}
-
-	/* Set the voltage level to 1.8V */
-	rc = regulator_set_voltage(fm_regulator, 1800000, 1800000);
-	if (rc < 0) {
-		pr_err("%s: could not set voltage: %d\n", __func__, rc);
-		goto reg_free;
-	}
-
-	/* Enabling the 1.8V regulator */
-	rc = regulator_enable(fm_regulator);
-	if (rc) {
-		pr_err("%s: could not enable regulator: %d\n", __func__, rc);
-		goto reg_free;
-	}
-
-	/* Voting for 19.2MHz clock */
-	rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
-			PMAPP_CLOCK_VOTE_ON);
-	if (rc < 0) {
-		pr_err("%s: clock vote failed with :(%d)\n",
-			 __func__, rc);
-		goto reg_disable;
-	}
-
-	rc = bt_set_gpio(1);
-	if (rc) {
-		pr_err("%s: bt_set_gpio = %d", __func__, rc);
-		goto gpio_deconfig;
-	}
-	/*re-write FM Slave Id, after reset*/
-	value = BAHAMA_SLAVE_ID_FM_ADDR;
-	rc = marimba_write_bit_mask(&config,
-			BAHAMA_SLAVE_ID_FM_REG, &value, 1, 0xFF);
-	if (rc < 0) {
-		pr_err("%s: FM Slave ID rewrite Failed = %d", __func__, rc);
-		goto gpio_deconfig;
-	}
-	/* Configuring the FM GPIO */
-	irqcfg = GPIO_CFG(FM_GPIO, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL,
-			GPIO_CFG_2MA);
-
-	rc = gpio_tlmm_config(irqcfg, GPIO_CFG_ENABLE);
-	if (rc) {
-		pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
-			 __func__, irqcfg, rc);
-		goto gpio_deconfig;
-	}
-
-	return 0;
-
-gpio_deconfig:
-	pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
-		PMAPP_CLOCK_VOTE_OFF);
-	bt_set_gpio(0);
-reg_disable:
-	regulator_disable(fm_regulator);
-reg_free:
-	regulator_put(fm_regulator);
-	fm_regulator = NULL;
-out:
-	return rc;
-};
-
-static void fm_radio_shutdown(struct marimba_fm_platform_data *pdata)
-{
-	int rc;
-	const char *id = "FMPW";
-
-	/* Releasing the GPIO line used by FM */
-	uint32_t irqcfg = GPIO_CFG(FM_GPIO, 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_UP,
-		GPIO_CFG_2MA);
-
-	rc = gpio_tlmm_config(irqcfg, GPIO_CFG_ENABLE);
-	if (rc)
-		pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
-			 __func__, irqcfg, rc);
-
-	/* Releasing the 1.8V Regulator */
-	if (!IS_ERR_OR_NULL(fm_regulator)) {
-		rc = regulator_disable(fm_regulator);
-		if (rc)
-			pr_err("%s: could not disable regulator: %d\n",
-					__func__, rc);
-		regulator_put(fm_regulator);
-		fm_regulator = NULL;
-	}
-
-	/* Voting off the clock */
-	rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
-		PMAPP_CLOCK_VOTE_OFF);
-	if (rc < 0)
-		pr_err("%s: voting off failed with :(%d)\n",
-			__func__, rc);
-	rc = bt_set_gpio(0);
-	if (rc)
-		pr_err("%s: bt_set_gpio = %d", __func__, rc);
-}
-
-static struct marimba_fm_platform_data marimba_fm_pdata = {
-	.fm_setup = fm_radio_setup,
-	.fm_shutdown = fm_radio_shutdown,
-	.irq = MSM_GPIO_TO_INT(FM_GPIO),
-	.vreg_s2 = NULL,
-	.vreg_xo_out = NULL,
-	/* Configuring the FM SoC as I2S Master */
-	.is_fm_soc_i2s_master = true,
-	.config_i2s_gpio = msm_bahama_setup_pcm_i2s,
-};
-#endif
-
 static struct platform_device msm_wlan_ar6000_pm_device = {
 	.name           = "wlan_ar6000_pm_dev",
 	.id             = -1,
 };
 
-#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
-
-static struct platform_device msm_bt_power_device = {
-	.name = "bt_power",
-};
-struct bahama_config_register {
-		u8 reg;
-		u8 value;
-		u8 mask;
-};
-struct bt_vreg_info {
-	const char *name;
-	unsigned int pmapp_id;
-	unsigned int min_level;
-	unsigned int max_level;
-	unsigned int is_pin_controlled;
-	struct regulator *reg;
-};
-static struct bt_vreg_info bt_vregs[] = {
-	{"msme1", 2, 1800000, 1800000, 0, NULL},
-	{"bt", 21, 2900000, 3050000, 1, NULL}
-};
-
-static int bahama_bt(int on)
-{
-	int rc = 0;
-	int i;
-
-	struct marimba config = { .mod_id =  SLAVE_ID_BAHAMA};
-
-	struct bahama_variant_register {
-		const size_t size;
-		const struct bahama_config_register *set;
-	};
-
-	const struct bahama_config_register *p;
-
-	u8 version;
-
-	const struct bahama_config_register v10_bt_on[] = {
-		{ 0xE9, 0x00, 0xFF },
-		{ 0xF4, 0x80, 0xFF },
-		{ 0xE4, 0x00, 0xFF },
-		{ 0xE5, 0x00, 0x0F },
-#ifdef CONFIG_WLAN
-		{ 0xE6, 0x38, 0x7F },
-		{ 0xE7, 0x06, 0xFF },
-#endif
-		{ 0xE9, 0x21, 0xFF },
-		{ 0x01, 0x0C, 0x1F },
-		{ 0x01, 0x08, 0x1F },
-	};
-
-	const struct bahama_config_register v20_bt_on_fm_off[] = {
-		{ 0x11, 0x0C, 0xFF },
-		{ 0x13, 0x01, 0xFF },
-		{ 0xF4, 0x80, 0xFF },
-		{ 0xF0, 0x00, 0xFF },
-		{ 0xE9, 0x00, 0xFF },
-#ifdef CONFIG_WLAN
-		{ 0x81, 0x00, 0x7F },
-		{ 0x82, 0x00, 0xFF },
-		{ 0xE6, 0x38, 0x7F },
-		{ 0xE7, 0x06, 0xFF },
-#endif
-		{ 0x8E, 0x15, 0xFF },
-		{ 0x8F, 0x15, 0xFF },
-		{ 0x90, 0x15, 0xFF },
-
-		{ 0xE9, 0x21, 0xFF },
-	};
-
-	const struct bahama_config_register v20_bt_on_fm_on[] = {
-		{ 0x11, 0x0C, 0xFF },
-		{ 0x13, 0x01, 0xFF },
-		{ 0xF4, 0x86, 0xFF },
-		{ 0xF0, 0x06, 0xFF },
-		{ 0xE9, 0x00, 0xFF },
-#ifdef CONFIG_WLAN
-		{ 0x81, 0x00, 0x7F },
-		{ 0x82, 0x00, 0xFF },
-		{ 0xE6, 0x38, 0x7F },
-		{ 0xE7, 0x06, 0xFF },
-#endif
-		{ 0xE9, 0x21, 0xFF },
-	};
-
-	const struct bahama_config_register v10_bt_off[] = {
-		{ 0xE9, 0x00, 0xFF },
-	};
-
-	const struct bahama_config_register v20_bt_off_fm_off[] = {
-		{ 0xF4, 0x84, 0xFF },
-		{ 0xF0, 0x04, 0xFF },
-		{ 0xE9, 0x00, 0xFF }
-	};
-
-	const struct bahama_config_register v20_bt_off_fm_on[] = {
-		{ 0xF4, 0x86, 0xFF },
-		{ 0xF0, 0x06, 0xFF },
-		{ 0xE9, 0x00, 0xFF }
-	};
-	const struct bahama_variant_register bt_bahama[2][3] = {
-	{
-		{ ARRAY_SIZE(v10_bt_off), v10_bt_off },
-		{ ARRAY_SIZE(v20_bt_off_fm_off), v20_bt_off_fm_off },
-		{ ARRAY_SIZE(v20_bt_off_fm_on), v20_bt_off_fm_on }
-	},
-	{
-		{ ARRAY_SIZE(v10_bt_on), v10_bt_on },
-		{ ARRAY_SIZE(v20_bt_on_fm_off), v20_bt_on_fm_off },
-		{ ARRAY_SIZE(v20_bt_on_fm_on), v20_bt_on_fm_on }
-	}
-	};
-
-	u8 offset = 0; /* index into bahama configs */
-	on = on ? 1 : 0;
-	version = marimba_read_bahama_ver(&config);
-	if ((int)version < 0 || version == BAHAMA_VER_UNSUPPORTED) {
-		dev_err(&msm_bt_power_device.dev, "%s: Bahama \
-				version read Error, version = %d \n",
-				__func__, version);
-		return -EIO;
-	}
-
-	if (version == BAHAMA_VER_2_0) {
-		if (marimba_get_fm_status(&config))
-			offset = 0x01;
-	}
-
-	p = bt_bahama[on][version + offset].set;
-
-	dev_info(&msm_bt_power_device.dev,
-		"%s: found version %d\n", __func__, version);
-
-	for (i = 0; i < bt_bahama[on][version + offset].size; i++) {
-		u8 value = (p+i)->value;
-		rc = marimba_write_bit_mask(&config,
-			(p+i)->reg,
-			&value,
-			sizeof((p+i)->value),
-			(p+i)->mask);
-		if (rc < 0) {
-			dev_err(&msm_bt_power_device.dev,
-				"%s: reg %x write failed: %d\n",
-				__func__, (p+i)->reg, rc);
-			return rc;
-		}
-		dev_dbg(&msm_bt_power_device.dev,
-			"%s: reg 0x%02x write value 0x%02x mask 0x%02x\n",
-				__func__, (p+i)->reg,
-				value, (p+i)->mask);
-		value = 0;
-		rc = marimba_read_bit_mask(&config,
-				(p+i)->reg, &value,
-				sizeof((p+i)->value), (p+i)->mask);
-		if (rc < 0)
-			dev_err(&msm_bt_power_device.dev, "%s marimba_read_bit_mask- error",
-					__func__);
-		dev_dbg(&msm_bt_power_device.dev,
-			"%s: reg 0x%02x read value 0x%02x mask 0x%02x\n",
-				__func__, (p+i)->reg,
-				value, (p+i)->mask);
-	}
-	/* Update BT Status */
-	if (on)
-		marimba_set_bt_status(&config, true);
-	else
-		marimba_set_bt_status(&config, false);
-	return rc;
-}
-static int bluetooth_switch_regulators(int on)
-{
-	int i, rc = 0;
-	const char *id = "BTPW";
-
-	for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
-		if (IS_ERR_OR_NULL(bt_vregs[i].reg)) {
-			rc = bt_vregs[i].reg ?
-				PTR_ERR(bt_vregs[i].reg) :
-				-ENODEV;
-			dev_err(&msm_bt_power_device.dev,
-				"%s: invalid regulator handle for %s: %d\n",
-					__func__, bt_vregs[i].name, rc);
-			goto reg_disable;
-		}
-
-		rc = on ? regulator_set_voltage(bt_vregs[i].reg,
-					bt_vregs[i].min_level,
-						bt_vregs[i].max_level) : 0;
-		if (rc) {
-			dev_err(&msm_bt_power_device.dev,
-				"%s: could not set voltage for %s: %d\n",
-					__func__, bt_vregs[i].name, rc);
-			goto reg_disable;
-		}
-
-		rc = on ? regulator_enable(bt_vregs[i].reg) : 0;
-		if (rc) {
-			dev_err(&msm_bt_power_device.dev,
-				"%s: could not %sable regulator %s: %d\n",
-					__func__, "en", bt_vregs[i].name, rc);
-			goto reg_disable;
-		}
-
-		if (bt_vregs[i].is_pin_controlled) {
-			rc = pmapp_vreg_lpm_pincntrl_vote(id,
-				bt_vregs[i].pmapp_id,
-					PMAPP_CLOCK_ID_D1,
-					on ? PMAPP_CLOCK_VOTE_ON :
-						PMAPP_CLOCK_VOTE_OFF);
-			if (rc) {
-				dev_err(&msm_bt_power_device.dev,
-					"%s: pin control failed for %s: %d\n",
-						__func__, bt_vregs[i].name, rc);
-				goto pin_cnt_fail;
-			}
-		}
-		rc = on ? 0 : regulator_disable(bt_vregs[i].reg);
-
-		if (rc) {
-			dev_err(&msm_bt_power_device.dev,
-				"%s: could not %sable regulator %s: %d\n",
-					__func__, "dis", bt_vregs[i].name, rc);
-			goto reg_disable;
-		}
-	}
-
-	return rc;
-pin_cnt_fail:
-	if (on)
-		regulator_disable(bt_vregs[i].reg);
-reg_disable:
-	while (i) {
-		if (on) {
-			i--;
-			regulator_disable(bt_vregs[i].reg);
-			regulator_put(bt_vregs[i].reg);
-		}
-	}
-	return rc;
-}
-
-static struct regulator *reg_s3;
-static unsigned int msm_bahama_setup_power(void)
-{
-	int rc = 0;
-
-	reg_s3 = regulator_get(NULL, "msme1");
-	if (IS_ERR(reg_s3)) {
-		rc = PTR_ERR(reg_s3);
-		pr_err("%s: could not get regulator: %d\n", __func__, rc);
-		goto out;
-	}
-
-	rc = regulator_set_voltage(reg_s3, 1800000, 1800000);
-	if (rc < 0) {
-		pr_err("%s: could not set voltage: %d\n", __func__, rc);
-		goto reg_fail;
-	}
-
-	rc = regulator_enable(reg_s3);
-	if (rc < 0) {
-		pr_err("%s: could not enable regulator: %d\n", __func__, rc);
-		goto reg_fail;
-	}
-
-	gpio_tlmm_config(GPIO_CFG(GPIO_BT_SYS_REST_EN, 0,
-				GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
-				GPIO_CFG_2MA), GPIO_CFG_ENABLE);
-
-	/*setup Bahama_sys_reset_n*/
-	rc = gpio_request(GPIO_BT_SYS_REST_EN, "bahama sys_rst_n");
-	if (rc < 0) {
-		pr_err("%s: gpio_request %d = %d\n", __func__,
-			GPIO_BT_SYS_REST_EN, rc);
-		goto reg_disable;
-	}
-
-	rc = bt_set_gpio(1);
-	if (rc < 0) {
-		pr_err("%s: bt_set_gpio %d = %d\n", __func__,
-			GPIO_BT_SYS_REST_EN, rc);
-		goto gpio_fail;
-	}
-
-	return rc;
-
-gpio_fail:
-	gpio_free(GPIO_BT_SYS_REST_EN);
-reg_disable:
-	regulator_disable(reg_s3);
-reg_fail:
-	regulator_put(reg_s3);
-out:
-	reg_s3 = NULL;
-	return rc;
-}
-
-static unsigned int msm_bahama_shutdown_power(int value)
-{
-	int rc = 0;
-
-	if (IS_ERR_OR_NULL(reg_s3)) {
-		rc = reg_s3 ? PTR_ERR(reg_s3) : -ENODEV;
-		goto out;
-	}
-
-	rc = regulator_disable(reg_s3);
-	if (rc) {
-		pr_err("%s: could not disable regulator: %d\n", __func__, rc);
-		goto out;
-	}
-
-	if (value == BAHAMA_ID) {
-		rc = bt_set_gpio(0);
-		if (rc) {
-			pr_err("%s: bt_set_gpio = %d\n",
-					__func__, rc);
-			goto reg_enable;
-		}
-		gpio_free(GPIO_BT_SYS_REST_EN);
-	}
-
-	regulator_put(reg_s3);
-	reg_s3 = NULL;
-
-	return 0;
-
-reg_enable:
-	regulator_enable(reg_s3);
-out:
-	return rc;
-}
-
-static unsigned int msm_bahama_core_config(int type)
-{
-	int rc = 0;
-
-	if (type == BAHAMA_ID) {
-		int i;
-		struct marimba config = { .mod_id =  SLAVE_ID_BAHAMA};
-		const struct bahama_config_register v20_init[] = {
-			/* reg, value, mask */
-			{ 0xF4, 0x84, 0xFF }, /* AREG */
-			{ 0xF0, 0x04, 0xFF } /* DREG */
-		};
-		if (marimba_read_bahama_ver(&config) == BAHAMA_VER_2_0) {
-			for (i = 0; i < ARRAY_SIZE(v20_init); i++) {
-				u8 value = v20_init[i].value;
-				rc = marimba_write_bit_mask(&config,
-					v20_init[i].reg,
-					&value,
-					sizeof(v20_init[i].value),
-					v20_init[i].mask);
-				if (rc < 0) {
-					pr_err("%s: reg %d write failed: %d\n",
-						__func__, v20_init[i].reg, rc);
-					return rc;
-				}
-				pr_debug("%s: reg 0x%02x value 0x%02x"
-					" mask 0x%02x\n",
-					__func__, v20_init[i].reg,
-					v20_init[i].value, v20_init[i].mask);
-			}
-		}
-	}
-	rc = bt_set_gpio(0);
-	if (rc) {
-		pr_err("%s: bt_set_gpio = %d\n",
-		       __func__, rc);
-	}
-	pr_debug("core type: %d\n", type);
-	return rc;
-}
-
-static int bluetooth_power(int on)
-{
-	int pin, rc = 0;
-	const char *id = "BTPW";
-	int cid = 0;
-
-	cid = adie_get_detected_connectivity_type();
-	if (cid != BAHAMA_ID) {
-		pr_err("%s: unexpected adie connectivity type: %d\n",
-					__func__, cid);
-		return -ENODEV;
-	}
-	if (on) {
-		/*setup power for BT SOC*/
-		rc = bt_set_gpio(on);
-		if (rc) {
-			pr_err("%s: bt_set_gpio = %d\n",
-					__func__, rc);
-			goto exit;
-		}
-		rc = bluetooth_switch_regulators(on);
-		if (rc < 0) {
-			pr_err("%s: bluetooth_switch_regulators rc = %d",
-					__func__, rc);
-			goto exit;
-		}
-		/*setup BT GPIO lines*/
-		for (pin = 0; pin < ARRAY_SIZE(bt_config_power_on);
-			pin++) {
-			rc = gpio_tlmm_config(bt_config_power_on[pin],
-					GPIO_CFG_ENABLE);
-			if (rc < 0) {
-				pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
-						__func__,
-						bt_config_power_on[pin],
-						rc);
-				goto fail_power;
-			}
-		}
-		/*Setup BT clocks*/
-		rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
-			PMAPP_CLOCK_VOTE_ON);
-		if (rc < 0) {
-			pr_err("Failed to vote for TCXO_D1 ON\n");
-			goto fail_clock;
-		}
-		msleep(20);
-
-		/*I2C config for Bahama*/
-		rc = bahama_bt(1);
-		if (rc < 0) {
-			pr_err("%s: bahama_bt rc = %d", __func__, rc);
-			goto fail_i2c;
-		}
-		msleep(20);
-
-		/*setup BT PCM lines*/
-		rc = msm_bahama_setup_pcm_i2s(BT_PCM_ON);
-		if (rc < 0) {
-			pr_err("%s: msm_bahama_setup_pcm_i2s , rc =%d\n",
-				__func__, rc);
-				goto fail_power;
-			}
-		rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
-				  PMAPP_CLOCK_VOTE_PIN_CTRL);
-		if (rc < 0)
-			pr_err("%s:Pin Control Failed, rc = %d",
-					__func__, rc);
-
-	} else {
-		rc = bahama_bt(0);
-		if (rc < 0)
-			pr_err("%s: bahama_bt rc = %d", __func__, rc);
-
-		rc = bt_set_gpio(on);
-		if (rc) {
-			pr_err("%s: bt_set_gpio = %d\n",
-					__func__, rc);
-		}
-fail_i2c:
-		rc = pmapp_clock_vote(id, PMAPP_CLOCK_ID_D1,
-				  PMAPP_CLOCK_VOTE_OFF);
-		if (rc < 0)
-			pr_err("%s: Failed to vote Off D1\n", __func__);
-fail_clock:
-		for (pin = 0; pin < ARRAY_SIZE(bt_config_power_off);
-			pin++) {
-				rc = gpio_tlmm_config(bt_config_power_off[pin],
-					GPIO_CFG_ENABLE);
-				if (rc < 0) {
-					pr_err("%s: gpio_tlmm_config(%#x)=%d\n",
-					__func__, bt_config_power_off[pin], rc);
-				}
-			}
-		rc = msm_bahama_setup_pcm_i2s(BT_PCM_OFF);
-		if (rc < 0) {
-			pr_err("%s: msm_bahama_setup_pcm_i2s, rc =%d\n",
-					__func__, rc);
-				}
-fail_power:
-		rc = bluetooth_switch_regulators(0);
-		if (rc < 0) {
-			pr_err("%s: switch_regulators : rc = %d",\
-					__func__, rc);
-			goto exit;
-		}
-	}
-	return rc;
-exit:
-	pr_err("%s: failed with rc = %d", __func__, rc);
-	return rc;
-}
-
-static int __init bt_power_init(void)
-{
-	int i, rc = 0;
-	struct device *dev = &msm_bt_power_device.dev;
-
-	for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
-		bt_vregs[i].reg = regulator_get(dev, bt_vregs[i].name);
-		if (IS_ERR(bt_vregs[i].reg)) {
-			rc = PTR_ERR(bt_vregs[i].reg);
-			dev_err(dev, "%s: could not get regulator %s: %d\n",
-					__func__, bt_vregs[i].name, rc);
-			goto reg_get_fail;
-		}
-	}
-
-	dev->platform_data = &bluetooth_power;
-
-	return rc;
-
-reg_get_fail:
-	while (i--) {
-		regulator_put(bt_vregs[i].reg);
-		bt_vregs[i].reg = NULL;
-	}
-	return rc;
-}
-
-static struct marimba_platform_data marimba_pdata = {
-	.slave_id[SLAVE_ID_BAHAMA_FM]        = BAHAMA_SLAVE_ID_FM_ADDR,
-	.slave_id[SLAVE_ID_BAHAMA_QMEMBIST]  = BAHAMA_SLAVE_ID_QMEMBIST_ADDR,
-	.bahama_setup                        = msm_bahama_setup_power,
-	.bahama_shutdown                     = msm_bahama_shutdown_power,
-	.bahama_core_config                  = msm_bahama_core_config,
-	.fm				     = &marimba_fm_pdata,
-};
-
-#endif
-
-#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
-static struct i2c_board_info bahama_devices[] = {
-{
-	I2C_BOARD_INFO("marimba", 0xc),
-	.platform_data = &marimba_pdata,
-},
-};
-#endif
-
 static struct msm_gpio qup_i2c_gpios_io[] = {
 	{ GPIO_CFG(60, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
 		"qup_scl" },
@@ -1313,8 +454,8 @@
 };
 
 static struct msm_pm_boot_platform_data msm_pm_boot_pdata __initdata = {
-	.mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT,
-	.v_addr = (uint32_t *)PAGE_OFFSET,
+	.mode = MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS,
+	.p_addr = 0,
 };
 
 static struct android_pmem_platform_data android_pmem_adsp_pdata = {
@@ -2218,10 +1359,7 @@
 	msm_fb_add_devices();
 
 #if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
-	i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
-			bahama_devices,
-			ARRAY_SIZE(bahama_devices));
-	bt_power_init();
+	msm7627a_bt_power_init();
 #endif
 
 	msm_camera_vreg_init();
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index ed5f265..667ac62 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -742,6 +742,8 @@
 		.en_mask = BIT(23),
 		.hwcg_reg = MAXI_EN4_REG,
 		.hwcg_mask = BIT(22),
+		.reset_reg = SW_RESET_AXI_REG,
+		.reset_mask = BIT(4),
 		.halt_reg = DBG_BUS_VEC_I_REG,
 		.halt_bit = 25,
 	},
@@ -758,6 +760,8 @@
 		.en_mask = BIT(25),
 		.hwcg_reg = MAXI_EN4_REG,
 		.hwcg_mask = BIT(24),
+		.reset_reg = SW_RESET_AXI_REG,
+		.reset_mask = BIT(5),
 		.halt_reg = DBG_BUS_VEC_I_REG,
 		.halt_bit = 26,
 	},
@@ -776,7 +780,7 @@
 		.hwcg_reg = MAXI_EN_REG,
 		.hwcg_mask = BIT(13),
 		.reset_reg = SW_RESET_AXI_REG,
-		.reset_mask = BIT(4)|BIT(5)|BIT(7),
+		.reset_mask = BIT(7),
 		.halt_reg = DBG_BUS_VEC_E_REG,
 		.halt_bit = 3,
 	},
@@ -4753,6 +4757,7 @@
 static DEFINE_CLK_VOTER(dfab_sdc5_clk, &dfab_clk.c);
 static DEFINE_CLK_VOTER(dfab_sps_clk, &dfab_clk.c);
 static DEFINE_CLK_VOTER(dfab_bam_dmux_clk, &dfab_clk.c);
+static DEFINE_CLK_VOTER(dfab_scm_clk, &dfab_clk.c);
 
 static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c);
 /*
@@ -5297,13 +5302,16 @@
 	CLK_LOOKUP("mdp_clk",		mdp_clk.c,		NULL),
 	CLK_LOOKUP("core_clk",		mdp_clk.c,	 "footswitch-8x60.4"),
 	CLK_LOOKUP("mdp_vsync_clk",	mdp_vsync_clk.c,	NULL),
+	CLK_LOOKUP("vsync_clk",		mdp_vsync_clk.c, "footswitch-8x60.4"),
 	CLK_LOOKUP("lut_mdp",		lut_mdp_clk.c,		NULL),
+	CLK_LOOKUP("lut_clk",		lut_mdp_clk.c,	"footswitch-8x60.4"),
 	CLK_LOOKUP("core_clk",		rot_clk.c,	"msm_rotator.0"),
 	CLK_LOOKUP("core_clk",		rot_clk.c,	"footswitch-8x60.6"),
 	CLK_DUMMY("tv_src_clk",		TV_SRC_CLK,		NULL, OFF),
 	CLK_LOOKUP("core_clk",		vcodec_clk.c,		"msm_vidc.0"),
 	CLK_LOOKUP("core_clk",		vcodec_clk.c,	"footswitch-8x60.7"),
 	CLK_DUMMY("mdp_tv_clk",		MDP_TV_CLK,		NULL, OFF),
+	CLK_DUMMY("tv_clk",		MDP_TV_CLK, "footswitch-8x60.4", OFF),
 	CLK_DUMMY("hdmi_clk",		HDMI_TV_CLK,		NULL, OFF),
 	CLK_LOOKUP("core_clk",		hdmi_app_clk.c,		NULL),
 	CLK_LOOKUP("vpe_clk",		vpe_clk.c,		NULL),
@@ -5375,6 +5383,7 @@
 	CLK_DUMMY("bus_clk",		DFAB_SDC3_CLK,		NULL, 0),
 	CLK_DUMMY("bus_clk",		DFAB_SDC4_CLK,		NULL, 0),
 	CLK_DUMMY("dfab_clk",		DFAB_CLK,		NULL, 0),
+	CLK_DUMMY("bus_clk",		DFAB_SCM_CLK,	"scm", 0),
 	CLK_LOOKUP("usb_hsic_xcvr_fs_clk", usb_hsic_xcvr_fs_clk.c,	NULL),
 	CLK_LOOKUP("usb_hsic_hsic_clk", usb_hsic_hsic_clk.c,	NULL),
 	CLK_LOOKUP("usb_hsic_hsio_cal_clk", usb_hsic_hsio_cal_clk.c,	NULL),
@@ -5494,11 +5503,9 @@
 	CLK_LOOKUP("core_clk",		pmic_ssbi2_clk.c,	NULL),
 	CLK_LOOKUP("mem_clk",		rpm_msg_ram_p_clk.c,	NULL),
 	CLK_LOOKUP("core_clk",		amp_clk.c,		NULL),
-	CLK_LOOKUP("cam_clk",		cam0_clk.c,		NULL),
-	CLK_LOOKUP("cam_clk",		cam1_clk.c,		NULL),
-	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"msm_camera_imx074.0"),
-	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"msm_camera_mt9m114.0"),
-	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"msm_camera_ov2720.0"),
+	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-001a"),
+	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-006c"),
+	CLK_LOOKUP("cam_clk",		cam0_clk.c,	"4-0048"),
 	CLK_LOOKUP("csi_src_clk",	csi0_src_clk.c,		"msm_csid.0"),
 	CLK_LOOKUP("csi_src_clk",	csi1_src_clk.c,		"msm_csid.1"),
 	CLK_LOOKUP("csi_clk",		csi0_clk.c,		"msm_csid.0"),
@@ -5531,7 +5538,9 @@
 	CLK_LOOKUP("mdp_clk",		mdp_clk.c,		NULL),
 	CLK_LOOKUP("core_clk",		mdp_clk.c,	"footswitch-8x60.4"),
 	CLK_LOOKUP("mdp_vsync_clk",	mdp_vsync_clk.c,	NULL),
+	CLK_LOOKUP("vsync_clk",		mdp_vsync_clk.c, "footswitch-8x60.4"),
 	CLK_LOOKUP("lut_mdp",		lut_mdp_clk.c,		NULL),
+	CLK_LOOKUP("lut_clk",		lut_mdp_clk.c,	"footswitch-8x60.4"),
 	CLK_LOOKUP("qdss_pclk",		qdss_p_clk.c,		NULL),
 	CLK_LOOKUP("qdss_at_clk",	qdss_at_clk.c,		NULL),
 	CLK_LOOKUP("qdss_pclkdbg_clk",	qdss_pclkdbg_clk.c,	NULL),
@@ -5541,11 +5550,13 @@
 	CLK_LOOKUP("core_clk",		rot_clk.c,	"msm_rotator.0"),
 	CLK_LOOKUP("core_clk",		rot_clk.c,	"footswitch-8x60.6"),
 	CLK_LOOKUP("tv_src_clk",	tv_src_clk.c,		NULL),
+	CLK_LOOKUP("tv_src_clk",	tv_src_clk.c,	"footswitch-8x60.4"),
 	CLK_LOOKUP("tv_enc_clk",	tv_enc_clk.c,		NULL),
 	CLK_LOOKUP("tv_dac_clk",	tv_dac_clk.c,		NULL),
 	CLK_LOOKUP("core_clk",		vcodec_clk.c,	"msm_vidc.0"),
 	CLK_LOOKUP("core_clk",		vcodec_clk.c,	"footswitch-8x60.7"),
 	CLK_LOOKUP("mdp_tv_clk",	mdp_tv_clk.c,		NULL),
+	CLK_LOOKUP("tv_clk",		mdp_tv_clk.c,	"footswitch-8x60.4"),
 	CLK_LOOKUP("hdmi_clk",		hdmi_tv_clk.c,		NULL),
 	CLK_LOOKUP("core_clk",		hdmi_app_clk.c,	"hdmi_msm.1"),
 	CLK_LOOKUP("vpe_clk",		vpe_clk.c,		"msm_vpe.0"),
@@ -5625,6 +5636,7 @@
 	CLK_LOOKUP("bus_clk",		dfab_sdc5_clk.c, "msm_sdcc.5"),
 	CLK_LOOKUP("dfab_clk",		dfab_sps_clk.c,	"msm_sps"),
 	CLK_LOOKUP("bus_clk",		dfab_bam_dmux_clk.c,	"BAM_RMNT"),
+	CLK_LOOKUP("bus_clk",		dfab_scm_clk.c,	"scm"),
 
 	CLK_LOOKUP("mem_clk",		ebi1_adm_clk.c, "msm_dmov"),
 
@@ -5732,7 +5744,7 @@
 			SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 3) {
 		rmwreg(0x0003AFF9, MAXI_EN_REG,  0x0803FFFF);
 		rmwreg(0x3A27FCFF, MAXI_EN2_REG, 0x3A3FFFFF);
-		rmwreg(0x0027FCFF, MAXI_EN4_REG, 0x017FFFFF);
+		rmwreg(0x0167FCFF, MAXI_EN4_REG, 0x017FFFFF);
 	} else {
 		rmwreg(0x000007F9, MAXI_EN_REG,  0x0803FFFF);
 		rmwreg(0x3027FCFF, MAXI_EN2_REG, 0x3A3FFFFF);
@@ -5996,7 +6008,7 @@
 		pr_err("%s: msm_xo_get(PXO) failed.\n", __func__);
 		BUG();
 	}
-	xo_cxo = msm_xo_get(MSM_XO_TCXO_D0, "clock-8960");
+	xo_cxo = msm_xo_get(MSM_XO_CXO, "clock-8960");
 	if (IS_ERR(xo_cxo)) {
 		pr_err("%s: msm_xo_get(CXO) failed.\n", __func__);
 		BUG();
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index 45094d9..9da8bb4 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -3209,6 +3209,7 @@
 static DEFINE_CLK_VOTER(dfab_sdc3_clk, &dfab_clk.c);
 static DEFINE_CLK_VOTER(dfab_sdc4_clk, &dfab_clk.c);
 static DEFINE_CLK_VOTER(dfab_sdc5_clk, &dfab_clk.c);
+static DEFINE_CLK_VOTER(dfab_scm_clk, &dfab_clk.c);
 
 static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c);
 static DEFINE_CLK_VOTER(ebi1_adm0_clk,   &ebi1_clk.c);
@@ -3703,8 +3704,11 @@
 	CLK_LOOKUP("mdp_clk",		mdp_clk.c,		NULL),
 	CLK_LOOKUP("core_clk",		mdp_clk.c,	"footswitch-8x60.4"),
 	CLK_LOOKUP("mdp_vsync_clk",	mdp_vsync_clk.c,		NULL),
+	CLK_LOOKUP("vsync_clk",		mdp_vsync_clk.c, "footswitch-8x60.4"),
 	CLK_LOOKUP("pixel_lcdc_clk",	pixel_lcdc_clk.c,		NULL),
+	CLK_LOOKUP("pixel_lcdc_clk",	pixel_lcdc_clk.c, "footswitch-8x60.4"),
 	CLK_LOOKUP("pixel_mdp_clk",	pixel_mdp_clk.c,		NULL),
+	CLK_LOOKUP("pixel_mdp_clk",	pixel_mdp_clk.c, "footswitch-8x60.4"),
 	CLK_LOOKUP("core_clk",		rot_clk.c,	"msm_rotator.0"),
 	CLK_LOOKUP("core_clk",		rot_clk.c,	"footswitch-8x60.6"),
 	CLK_LOOKUP("tv_enc_clk",	tv_enc_clk.c,		NULL),
@@ -3712,8 +3716,10 @@
 	CLK_LOOKUP("core_clk",		vcodec_clk.c,	"msm_vidc.0"),
 	CLK_LOOKUP("core_clk",		vcodec_clk.c,	"footswitch-8x60.7"),
 	CLK_LOOKUP("mdp_tv_clk",	mdp_tv_clk.c,		NULL),
+	CLK_LOOKUP("tv_clk",		mdp_tv_clk.c,	"footswitch-8x60.4"),
 	CLK_LOOKUP("hdmi_clk",		hdmi_tv_clk.c,		NULL),
 	CLK_LOOKUP("tv_src_clk",	tv_src_clk.c,		NULL),
+	CLK_LOOKUP("tv_src_clk",	tv_src_clk.c,	"footswitch-8x60.4"),
 	CLK_LOOKUP("core_clk",		hdmi_app_clk.c,	"hdmi_msm.1"),
 	CLK_LOOKUP("vpe_clk",		vpe_clk.c,		NULL),
 	CLK_LOOKUP("core_clk",		vpe_clk.c,	"footswitch-8x60.9"),
@@ -3788,6 +3794,7 @@
 	CLK_LOOKUP("bus_clk",		dfab_sdc3_clk.c, "msm_sdcc.3"),
 	CLK_LOOKUP("bus_clk",		dfab_sdc4_clk.c, "msm_sdcc.4"),
 	CLK_LOOKUP("bus_clk",		dfab_sdc5_clk.c, "msm_sdcc.5"),
+	CLK_LOOKUP("bus_clk",		dfab_scm_clk.c,	"scm"),
 
 	CLK_LOOKUP("mem_clk",		ebi1_adm0_clk.c, "msm_dmov.0"),
 	CLK_LOOKUP("mem_clk",		ebi1_adm1_clk.c, "msm_dmov.1"),
@@ -3903,7 +3910,7 @@
 		pr_err("%s: msm_xo_get(PXO) failed.\n", __func__);
 		BUG();
 	}
-	xo_cxo = msm_xo_get(MSM_XO_TCXO_D1, "clock-8x60");
+	xo_cxo = msm_xo_get(MSM_XO_CXO, "clock-8x60");
 	if (IS_ERR(xo_cxo)) {
 		pr_err("%s: msm_xo_get(CXO) failed.\n", __func__);
 		BUG();
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index 8c5f027..40a880e 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -729,6 +729,12 @@
 	F_END
 };
 
+static struct clk_freq_tbl clk_tbl_usb_hsic_sys[] = {
+	F_USB(       0, gnd,  1, 0, 0),
+	F_USB(64000000, pll8, 1, 1, 6),
+	F_END
+};
+
 static struct rcg_clk usb_hs1_xcvr_clk = {
 	.b = {
 		.ctl_reg = USB_HS1_XCVR_FS_CLK_NS_REG,
@@ -796,7 +802,7 @@
 	.c = {
 		.dbg_name = "usb_hsic_xcvr_clk",
 		.ops = &clk_ops_rcg_9615,
-		VDD_DIG_FMAX_MAP1(NOMINAL, 60000000),
+		VDD_DIG_FMAX_MAP1(LOW, 60000000),
 		CLK_INIT(usb_hsic_xcvr_clk.c),
 	},
 };
@@ -815,19 +821,19 @@
 	.root_en_mask = BIT(11),
 	.ns_mask = (BM(23, 16) | BM(6, 0)),
 	.set_rate = set_rate_mnd,
-	.freq_tbl = clk_tbl_usb,
+	.freq_tbl = clk_tbl_usb_hsic_sys,
 	.current_freq = &rcg_dummy_freq,
 	.c = {
 		.dbg_name = "usb_hsic_sys_clk",
 		.ops = &clk_ops_rcg_9615,
-		VDD_DIG_FMAX_MAP1(NOMINAL, 60000000),
+		VDD_DIG_FMAX_MAP1(LOW, 64000000),
 		CLK_INIT(usb_hsic_sys_clk.c),
 	},
 };
 
 static struct clk_freq_tbl clk_tbl_usb_hsic[] = {
 	F_USB(        0, gnd,   1, 0, 0),
-	F_USB(480000000, pll14, 1, 0, 1),
+	F_USB(480000000, pll14, 1, 0, 0),
 	F_END
 };
 
@@ -837,8 +843,7 @@
 		.en_mask = BIT(9),
 		.reset_reg = USB_HSIC_RESET_REG,
 		.reset_mask = BIT(0),
-		.halt_reg = CLK_HALT_DFAB_STATE_REG,
-		.halt_bit = 7,
+		.halt_check = DELAY,
 	},
 	.ns_reg = USB_HSIC_CLK_NS_REG,
 	.md_reg = USB_HSIC_CLK_MD_REG,
@@ -850,7 +855,7 @@
 	.c = {
 		.dbg_name = "usb_hsic_clk",
 		.ops = &clk_ops_rcg_9615,
-		VDD_DIG_FMAX_MAP1(NOMINAL, 480000000),
+		VDD_DIG_FMAX_MAP1(LOW, 480000000),
 		CLK_INIT(usb_hsic_clk.c),
 	},
 };
@@ -1448,6 +1453,7 @@
 	{ TEST_PER_HS(0x2A), &adm0_clk.c },
 	{ TEST_PER_HS(0x34), &ebi1_clk.c },
 	{ TEST_PER_HS(0x34), &ebi1_a_clk.c },
+	{ TEST_PER_HS(0x3E), &usb_hsic_clk.c },
 	{ TEST_LPA(0x0F), &mi2s_bit_clk.c },
 	{ TEST_LPA(0x10), &codec_i2s_mic_bit_clk.c },
 	{ TEST_LPA(0x11), &codec_i2s_spkr_bit_clk.c },
@@ -1671,6 +1677,7 @@
 	CLK_LOOKUP("usb_hsic_hsio_cal_clk", usb_hsic_hsio_cal_clk.c,	NULL),
 	CLK_LOOKUP("usb_hsic_sys_clk",		usb_hsic_sys_clk.c,	NULL),
 	CLK_LOOKUP("usb_hsic_p_clk",		usb_hsic_p_clk.c,	NULL),
+	CLK_LOOKUP("usb_hsic_clk",		usb_hsic_clk.c,		NULL),
 
 	CLK_LOOKUP("iface_clk",		sdc1_p_clk.c,		"msm_sdcc.1"),
 	CLK_LOOKUP("iface_clk",		sdc2_p_clk.c,		"msm_sdcc.2"),
@@ -1852,7 +1859,7 @@
 /* Local clock driver initialization. */
 static void __init msm9615_clock_init(void)
 {
-	xo_cxo = msm_xo_get(MSM_XO_TCXO_D0, "clock-9615");
+	xo_cxo = msm_xo_get(MSM_XO_CXO, "clock-9615");
 	if (IS_ERR(xo_cxo)) {
 		pr_err("%s: msm_xo_get(CXO) failed.\n", __func__);
 		BUG();
@@ -1871,8 +1878,8 @@
 	clk_set_rate(&usb_hs1_xcvr_clk.c, 60000000);
 	clk_set_rate(&usb_hs1_sys_clk.c, 60000000);
 	clk_set_rate(&usb_hsic_xcvr_clk.c, 60000000);
-	clk_set_rate(&usb_hsic_sys_clk.c, 60000000);
-	clk_set_rate(&usb_hsic_clk.c, 48000000);
+	clk_set_rate(&usb_hsic_sys_clk.c, 64000000);
+	clk_set_rate(&usb_hsic_clk.c, 480000000);
 
 	/*
 	 * The halt status bits for PDM may be incorrect at boot.
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 8c251ba..26bb7ae 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -172,6 +172,12 @@
 		.end	= USB_HSIC_IRQ,
 		.flags	= IORESOURCE_IRQ,
 	},
+	{
+		.start	= MSM_GPIO_TO_INT(69),
+		.end	= MSM_GPIO_TO_INT(69),
+		.name	= "peripheral_status_irq",
+		.flags	= IORESOURCE_IRQ,
+	},
 };
 
 struct platform_device msm_device_hsic_host = {
@@ -873,7 +879,7 @@
 	.strap_ahb_lower = 0x00000080,
 	.aclk_reg = SFAB_MSS_Q6_FW_ACLK_CTL,
 	.jtag_clk_reg = MSS_Q6FW_JTAG_CLK_CTL,
-	.xo_id = MSM_XO_TCXO_D0,
+	.xo_id = MSM_XO_CXO,
 	.name = "modem_fw",
 	.depends = "q6",
 	.pas_id = PAS_MODEM_FW,
@@ -911,7 +917,7 @@
 	.strap_ahb_lower = 0x00000080,
 	.aclk_reg = SFAB_MSS_Q6_SW_ACLK_CTL,
 	.jtag_clk_reg = MSS_Q6SW_JTAG_CLK_CTL,
-	.xo_id = MSM_XO_TCXO_D0,
+	.xo_id = MSM_XO_CXO,
 	.name = "modem",
 	.depends = "modem_fw",
 	.pas_id = PAS_MODEM_SW,
@@ -926,6 +932,26 @@
 	.dev.platform_data = &msm_8960_q6_mss_sw_data,
 };
 
+static struct resource msm_8960_riva_resources[] = {
+	{
+		.start  = 0x03204000,
+		.end    = 0x03204000 + SZ_256 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_8960_riva = {
+	.name = "pil_riva",
+	.id = -1,
+	.num_resources  = ARRAY_SIZE(msm_8960_riva_resources),
+	.resource       = msm_8960_riva_resources,
+};
+
+struct platform_device msm_pil_tzapps = {
+	.name = "pil_tzapps",
+	.id = -1,
+};
+
 struct platform_device msm_device_smd = {
 	.name		= "msm_smd",
 	.id		= -1,
@@ -1405,6 +1431,21 @@
 	.id     = 0x3005,
 };
 
+struct platform_device msm_cpudai_incall_music_rx = {
+	.name   = "msm-dai-q6",
+	.id     = 0x8005,
+};
+
+struct platform_device msm_cpudai_incall_record_rx = {
+	.name   = "msm-dai-q6",
+	.id     = 0x8004,
+};
+
+struct platform_device msm_cpudai_incall_record_tx = {
+	.name   = "msm-dai-q6",
+	.id     = 0x8003,
+};
+
 /*
  * Machine specific data for AUX PCM Interface
  * which the driver will  be unware of.
@@ -1494,7 +1535,6 @@
 };
 
 struct platform_device *msm_footswitch_devices[] = {
-	FS_8X60(FS_MDP,    "fs_mdp"),
 	FS_8X60(FS_ROT,    "fs_rot"),
 	FS_8X60(FS_IJPEG,  "fs_ijpeg"),
 	FS_8X60(FS_VFE,    "fs_vfe"),
@@ -2090,7 +2130,7 @@
 	},
 };
 
-static struct msm_bus_vectors grp2d0_max_vectors[] = {
+static struct msm_bus_vectors grp2d0_nominal_vectors[] = {
 	{
 		.src = MSM_BUS_MASTER_GRAPHICS_2D_CORE0,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
@@ -2099,12 +2139,25 @@
 	},
 };
 
+static struct msm_bus_vectors grp2d0_max_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_2D_CORE0,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(2048),
+	},
+};
+
 static struct msm_bus_paths grp2d0_bus_scale_usecases[] = {
 	{
 		ARRAY_SIZE(grp2d0_init_vectors),
 		grp2d0_init_vectors,
 	},
 	{
+		ARRAY_SIZE(grp2d0_nominal_vectors),
+		grp2d0_nominal_vectors,
+	},
+	{
 		ARRAY_SIZE(grp2d0_max_vectors),
 		grp2d0_max_vectors,
 	},
@@ -2125,7 +2178,7 @@
 	},
 };
 
-static struct msm_bus_vectors grp2d1_max_vectors[] = {
+static struct msm_bus_vectors grp2d1_nominal_vectors[] = {
 	{
 		.src = MSM_BUS_MASTER_GRAPHICS_2D_CORE1,
 		.dst = MSM_BUS_SLAVE_EBI_CH0,
@@ -2134,12 +2187,25 @@
 	},
 };
 
+static struct msm_bus_vectors grp2d1_max_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_GRAPHICS_2D_CORE1,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab = 0,
+		.ib = KGSL_CONVERT_TO_MBPS(2048),
+	},
+};
+
 static struct msm_bus_paths grp2d1_bus_scale_usecases[] = {
 	{
 		ARRAY_SIZE(grp2d1_init_vectors),
 		grp2d1_init_vectors,
 	},
 	{
+		ARRAY_SIZE(grp2d1_nominal_vectors),
+		grp2d1_nominal_vectors,
+	},
+	{
 		ARRAY_SIZE(grp2d1_max_vectors),
 		grp2d1_max_vectors,
 	},
@@ -2236,17 +2302,21 @@
 	.pwrlevel = {
 		{
 			.gpu_freq = 200000000,
+			.bus_freq = 2,
+		},
+		{
+			.gpu_freq = 96000000,
 			.bus_freq = 1,
 		},
 		{
-			.gpu_freq = 200000000,
+			.gpu_freq = 27000000,
 			.bus_freq = 0,
 		},
 	},
 	.init_level = 0,
-	.num_levels = 2,
+	.num_levels = 3,
 	.set_grp_async = NULL,
-	.idle_timeout = HZ/10,
+	.idle_timeout = HZ/5,
 	.nap_allowed = true,
 	.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE,
 #ifdef CONFIG_MSM_BUS_SCALING
@@ -2285,17 +2355,21 @@
 	.pwrlevel = {
 		{
 			.gpu_freq = 200000000,
+			.bus_freq = 2,
+		},
+		{
+			.gpu_freq = 96000000,
 			.bus_freq = 1,
 		},
 		{
-			.gpu_freq = 200000000,
+			.gpu_freq = 27000000,
 			.bus_freq = 0,
 		},
 	},
 	.init_level = 0,
-	.num_levels = 2,
+	.num_levels = 3,
 	.set_grp_async = NULL,
-	.idle_timeout = HZ/10,
+	.idle_timeout = HZ/5,
 	.nap_allowed = true,
 	.clk_map = KGSL_CLK_CORE | KGSL_CLK_IFACE,
 #ifdef CONFIG_MSM_BUS_SCALING
@@ -2419,8 +2493,9 @@
 	MSM_RPM_MAP(USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
 	MSM_RPM_MAP(HDMI_SWITCH, HDMI_SWITCH, 1),
 	MSM_RPM_MAP(DDR_DMM_0, DDR_DMM, 2),
-
+	MSM_RPM_MAP(QDSS_CLK, QDSS_CLK, 1),
 };
+
 unsigned int rpm_map_data_size = ARRAY_SIZE(rpm_map_data);
 
 struct platform_device msm_rpm_device = {
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 63a86cb..0d3abb6 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -480,6 +480,7 @@
 	.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
 	.hw_key_support = QCE_HW_KEY_SUPPORT,
 	.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+	.bus_scale_table = NULL,
 };
 
 struct platform_device msm9615_qcrypto_device = {
@@ -502,6 +503,7 @@
 	.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
 	.hw_key_support = QCE_HW_KEY_SUPPORT,
 	.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+	.bus_scale_table = NULL,
 };
 
 struct platform_device msm9615_qcedev_device = {
@@ -735,7 +737,6 @@
 	[20] = MSM_GPIO_TO_INT(28),
 	[23] = MSM_GPIO_TO_INT(19),
 	[24] = MSM_GPIO_TO_INT(23),
-	[25] = USB1_HS_IRQ,
 	[26] = MSM_GPIO_TO_INT(3),
 	[27] = MSM_GPIO_TO_INT(68),
 	[29] = MSM_GPIO_TO_INT(78),
@@ -745,6 +746,7 @@
 	[34] = MSM_GPIO_TO_INT(17),
 	[37] = MSM_GPIO_TO_INT(20),
 	[39] = MSM_GPIO_TO_INT(84),
+	[40] = USB1_HS_IRQ,
 	[42] = MSM_GPIO_TO_INT(24),
 	[43] = MSM_GPIO_TO_INT(79),
 	[44] = MSM_GPIO_TO_INT(80),
@@ -767,10 +769,13 @@
 	RPM_APCC_CPU0_GP_MEDIUM_IRQ,
 	RPM_APCC_CPU0_GP_LOW_IRQ,
 	RPM_APCC_CPU0_WAKE_UP_IRQ,
+	MSS_TO_APPS_IRQ_0,
+	MSS_TO_APPS_IRQ_1,
 	LPASS_SCSS_GP_LOW_IRQ,
 	LPASS_SCSS_GP_MEDIUM_IRQ,
 	LPASS_SCSS_GP_HIGH_IRQ,
 	SPS_MTI_31,
+	A2_BAM_IRQ,
 };
 
 struct msm_mpm_device_data msm_mpm_dev_data = {
@@ -883,8 +888,6 @@
 
 void __init msm9615_init_irq(void)
 {
-	unsigned int i;
-
 	msm_mpm_irq_extn_init();
 	gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
 						(void *)MSM_QGIC_CPU_BASE);
@@ -894,16 +897,6 @@
 
 	writel_relaxed(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET);
 	mb();
-
-	/*
-	 * FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
-	 * as they are configured as level, which does not play nice with
-	 * handle_percpu_irq.
-	 */
-	for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
-		if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
-			irq_set_handler(i, handle_percpu_irq);
-	}
 }
 
 struct platform_device msm_bus_9615_sys_fabric = {
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index aa9e380..8f1709b 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -170,22 +170,11 @@
 
 void __init msm8x60_init_irq(void)
 {
-	unsigned int i;
-
 	msm_mpm_irq_extn_init();
 	gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE, (void *)MSM_QGIC_CPU_BASE);
 
 	/* Edge trigger PPIs except AVS_SVICINT and AVS_SVICINTSWDONE */
 	writel(0xFFFFD7FF, MSM_QGIC_DIST_BASE + GIC_DIST_CONFIG + 4);
-
-	/* FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
-	 * as they are configured as level, which does not play nice with
-	 * handle_percpu_irq.
-	 */
-	for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
-		if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
-			irq_set_handler(i, handle_percpu_irq);
-	}
 }
 
 #define MSM_LPASS_QDSP6SS_PHYS 0x28800000
@@ -205,6 +194,28 @@
 	.resource       = msm_8660_q6_resources,
 };
 
+#define MSM_MSS_REGS_PHYS 0x10200000
+
+static struct resource msm_8660_modem_resources[] = {
+	{
+		.start  = MSM_MSS_REGS_PHYS,
+		.end    = MSM_MSS_REGS_PHYS + SZ_256 - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device msm_pil_modem = {
+	.name = "pil_modem",
+	.id = -1,
+	.num_resources  = ARRAY_SIZE(msm_8660_modem_resources),
+	.resource       = msm_8660_modem_resources,
+};
+
+struct platform_device msm_pil_tzapps = {
+	.name = "pil_tzapps",
+	.id = -1,
+};
+
 static struct resource msm_uart1_dm_resources[] = {
 	{
 		.start = MSM_UART1DM_PHYS,
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 264e9a9..0de0694 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -173,11 +173,17 @@
 extern struct platform_device msm_cpudai_afe_02_tx;
 extern struct platform_device msm_pcm_afe;
 extern struct platform_device msm_compr_dsp;
+extern struct platform_device msm_cpudai_incall_music_rx;
+extern struct platform_device msm_cpudai_incall_record_rx;
+extern struct platform_device msm_cpudai_incall_record_tx;
 
 extern struct platform_device msm_pil_q6v3;
+extern struct platform_device msm_pil_modem;
+extern struct platform_device msm_pil_tzapps;
 extern struct platform_device msm_8960_q6_lpass;
 extern struct platform_device msm_8960_q6_mss_fw;
 extern struct platform_device msm_8960_q6_mss_sw;
+extern struct platform_device msm_8960_riva;
 
 extern struct platform_device apq_pcm;
 extern struct platform_device apq_pcm_routing;
diff --git a/arch/arm/mach-msm/footswitch-8x60.c b/arch/arm/mach-msm/footswitch-8x60.c
index 5006419..d8326e4 100644
--- a/arch/arm/mach-msm/footswitch-8x60.c
+++ b/arch/arm/mach-msm/footswitch-8x60.c
@@ -10,6 +10,8 @@
  * GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
 #include <linux/kernel.h>
 #include <linux/io.h>
 #include <linux/delay.h>
@@ -22,6 +24,7 @@
 #include <mach/msm_bus_board.h>
 #include <mach/msm_bus.h>
 #include <mach/scm-io.h>
+#include <mach/socinfo.h>
 #include "clock.h"
 #include "footswitch.h"
 
@@ -49,8 +52,9 @@
 #define RETENTION_BIT		BIT(9)
 
 #define RESET_DELAY_US		1
-/* Core clock rate to use if one has not previously been set. */
-#define DEFAULT_CLK_RATE	27000000
+/* Clock rate to use if one has not previously been set. */
+#define DEFAULT_RATE		27000000
+#define MAX_CLKS		10
 
 /*
  * Lock is only needed to protect against the first footswitch_enable()
@@ -58,72 +62,76 @@
  */
 static DEFINE_MUTEX(claim_lock);
 
-struct clock_state {
-	int ahb_clk_en;
-	int axi_clk_en;
-	int core_clk_rate;
+struct clk_data {
+	const char *name;
+	struct clk *clk;
+	unsigned long rate;
+	unsigned long reset_rate;
+	bool enabled;
 };
 
 struct footswitch {
 	struct regulator_dev	*rdev;
 	struct regulator_desc	desc;
 	void			*gfs_ctl_reg;
-	int			bus_port1, bus_port2;
+	int			bus_port0, bus_port1;
 	bool			is_enabled;
 	bool			is_claimed;
-	const bool		has_axi_clk;
+	struct clk_data		*clk_data;
 	struct clk		*core_clk;
-	struct clk		*ahb_clk;
-	struct clk		*axi_clk;
-	unsigned int		reset_rate;
-	struct clock_state	clk_state;
 	unsigned int		gfs_delay_cnt:5;
 };
 
 static int setup_clocks(struct footswitch *fs)
 {
 	int rc = 0;
+	struct clk_data *clock;
+	long rate;
 
 	/*
-	 * Enable all clocks in the power domain. If a core requires a
-	 * specific clock rate when being reset, apply it.
+	 * Enable all clocks in the power domain. If a specific clock rate is
+	 * required for reset timing, set that rate before enabling the clocks.
 	 */
-	fs->clk_state.core_clk_rate = clk_get_rate(fs->core_clk);
-	if (!fs->clk_state.core_clk_rate || fs->reset_rate) {
-		int rate = fs->reset_rate ? fs->reset_rate : DEFAULT_CLK_RATE;
-		rc = clk_set_rate(fs->core_clk, rate);
-		if (rc) {
-			pr_err("%s: Failed to set core_clk rate to %d Hz.\n",
-				__func__, fs->reset_rate);
-			return rc;
+	for (clock = fs->clk_data; clock->clk; clock++) {
+		clock->rate = clk_get_rate(clock->clk);
+		if (!clock->rate || clock->reset_rate) {
+			rate = clock->reset_rate ?
+					clock->reset_rate : DEFAULT_RATE;
+			rc = clk_set_rate(clock->clk, rate);
+			if (rc && rc != -ENOSYS) {
+				pr_err("Failed to set %s rate to %lu Hz.\n",
+					clock->name, clock->rate);
+				for (clock--; clock >= fs->clk_data; clock--) {
+					if (clock->enabled)
+						clk_disable(clock->clk);
+					clk_set_rate(clock->clk, clock->rate);
+				}
+				return rc;
+			}
 		}
+		/*
+		 * Some clocks are for reset purposes only. These clocks will
+		 * fail to enable. Ignore the failures but keep track of them so
+		 * we don't try to disable them later and crash due to
+		 * unbalanced calls.
+		 */
+		clock->enabled = !clk_enable(clock->clk);
 	}
-	clk_enable(fs->core_clk);
 
-	/*
-	 * Some AHB and AXI clocks are for reset purposes only. These clocks
-	 * will fail to enable. Keep track of them so we don't try to disable
-	 * them later and crash.
-	 */
-	fs->clk_state.ahb_clk_en = !clk_enable(fs->ahb_clk);
-	if (fs->axi_clk)
-		fs->clk_state.axi_clk_en = !clk_enable(fs->axi_clk);
-
-	return rc;
+	return 0;
 }
 
 static void restore_clocks(struct footswitch *fs)
 {
+	struct clk_data *clock;
+
 	/* Restore clocks to their orignal states before setup_clocks(). */
-	if (fs->axi_clk && fs->clk_state.axi_clk_en)
-		clk_disable(fs->axi_clk);
-	if (fs->clk_state.ahb_clk_en)
-		clk_disable(fs->ahb_clk);
-	clk_disable(fs->core_clk);
-	if (fs->clk_state.core_clk_rate) {
-		if (clk_set_rate(fs->core_clk, fs->clk_state.core_clk_rate))
-			pr_err("%s: Failed to restore core_clk rate.\n",
-				__func__);
+	for (clock = fs->clk_data; clock->clk; clock++) {
+		if (clock->enabled)
+			clk_disable(clock->clk);
+		if (clock->rate && clk_set_rate(clock->clk, clock->rate))
+			pr_err("Failed to restore %s rate to %lu Hz.\n",
+				clock->name, clock->rate);
 	}
 }
 
@@ -137,6 +145,7 @@
 static int footswitch_enable(struct regulator_dev *rdev)
 {
 	struct footswitch *fs = rdev_get_drvdata(rdev);
+	struct clk_data *clock;
 	uint32_t regval, rc = 0;
 
 	mutex_lock(&claim_lock);
@@ -154,17 +163,17 @@
 		return rc;
 
 	/* Un-halt all bus ports in the power domain. */
-	if (fs->bus_port1) {
-		rc = msm_bus_axi_portunhalt(fs->bus_port1);
+	if (fs->bus_port0) {
+		rc = msm_bus_axi_portunhalt(fs->bus_port0);
 		if (rc) {
-			pr_err("%s: Port 1 unhalt failed.\n", __func__);
+			pr_err("Port 0 unhalt failed.\n");
 			goto err;
 		}
 	}
-	if (fs->bus_port2) {
-		rc = msm_bus_axi_portunhalt(fs->bus_port2);
+	if (fs->bus_port1) {
+		rc = msm_bus_axi_portunhalt(fs->bus_port1);
 		if (rc) {
-			pr_err("%s: Port 2 unhalt failed.\n", __func__);
+			pr_err("Port 1 unhalt failed.\n");
 			goto err_port2_halt;
 		}
 	}
@@ -174,10 +183,10 @@
 	 * footswitch_enable() is first called before footswitch_disable()
 	 * and resets should be asserted before power is restored.
 	 */
-	if (fs->axi_clk)
-		clk_reset(fs->axi_clk, CLK_RESET_ASSERT);
-	clk_reset(fs->ahb_clk, CLK_RESET_ASSERT);
-	clk_reset(fs->core_clk, CLK_RESET_ASSERT);
+	for (clock = fs->clk_data; clock->clk; clock++)
+		; /* Do nothing */
+	for (clock--; clock >= fs->clk_data; clock--)
+		clk_reset(clock->clk, CLK_RESET_ASSERT);
 	/* Wait for synchronous resets to propagate. */
 	udelay(RESET_DELAY_US);
 
@@ -193,10 +202,8 @@
 	writel_relaxed(regval, fs->gfs_ctl_reg);
 
 	/* Deassert resets for all clocks in the power domain. */
-	clk_reset(fs->core_clk, CLK_RESET_DEASSERT);
-	clk_reset(fs->ahb_clk, CLK_RESET_DEASSERT);
-	if (fs->axi_clk)
-		clk_reset(fs->axi_clk, CLK_RESET_DEASSERT);
+	for (clock = fs->clk_data; clock->clk; clock++)
+		clk_reset(clock->clk, CLK_RESET_DEASSERT);
 	/* Toggle core reset again after first power-on (required for GFX3D). */
 	if (fs->desc.id == FS_GFX3D) {
 		clk_reset(fs->core_clk, CLK_RESET_ASSERT);
@@ -212,7 +219,7 @@
 	return 0;
 
 err_port2_halt:
-	msm_bus_axi_porthalt(fs->bus_port1);
+	msm_bus_axi_porthalt(fs->bus_port0);
 err:
 	restore_clocks(fs);
 	return rc;
@@ -221,6 +228,7 @@
 static int footswitch_disable(struct regulator_dev *rdev)
 {
 	struct footswitch *fs = rdev_get_drvdata(rdev);
+	struct clk_data *clock;
 	uint32_t regval, rc = 0;
 
 	/* Return early if already disabled. */
@@ -234,17 +242,17 @@
 		return rc;
 
 	/* Halt all bus ports in the power domain. */
-	if (fs->bus_port1) {
-		rc = msm_bus_axi_porthalt(fs->bus_port1);
+	if (fs->bus_port0) {
+		rc = msm_bus_axi_porthalt(fs->bus_port0);
 		if (rc) {
-			pr_err("%s: Port 1 halt failed.\n", __func__);
+			pr_err("Port 0 halt failed.\n");
 			goto err;
 		}
 	}
-	if (fs->bus_port2) {
-		rc = msm_bus_axi_porthalt(fs->bus_port2);
+	if (fs->bus_port1) {
+		rc = msm_bus_axi_porthalt(fs->bus_port1);
 		if (rc) {
-			pr_err("%s: Port 1 halt failed.\n", __func__);
+			pr_err("Port 1 halt failed.\n");
 			goto err_port2_halt;
 		}
 	}
@@ -253,10 +261,10 @@
 	 * Assert resets for all clocks in the clock domain so that
 	 * outputs settle prior to clamping.
 	 */
-	if (fs->axi_clk)
-		clk_reset(fs->axi_clk, CLK_RESET_ASSERT);
-	clk_reset(fs->ahb_clk, CLK_RESET_ASSERT);
-	clk_reset(fs->core_clk, CLK_RESET_ASSERT);
+	for (clock = fs->clk_data; clock->clk; clock++)
+		; /* Do nothing */
+	for (clock--; clock >= fs->clk_data; clock--)
+		clk_reset(clock->clk, CLK_RESET_ASSERT);
 	/* Wait for synchronous resets to propagate. */
 	udelay(RESET_DELAY_US);
 
@@ -283,7 +291,7 @@
 	return 0;
 
 err_port2_halt:
-	msm_bus_axi_portunhalt(fs->bus_port1);
+	msm_bus_axi_portunhalt(fs->bus_port0);
 err:
 	restore_clocks(fs);
 	return rc;
@@ -292,6 +300,7 @@
 static int gfx2d_footswitch_enable(struct regulator_dev *rdev)
 {
 	struct footswitch *fs = rdev_get_drvdata(rdev);
+	struct clk_data *clock;
 	uint32_t regval, rc = 0;
 
 	mutex_lock(&claim_lock);
@@ -309,10 +318,10 @@
 		return rc;
 
 	/* Un-halt all bus ports in the power domain. */
-	if (fs->bus_port1) {
-		rc = msm_bus_axi_portunhalt(fs->bus_port1);
+	if (fs->bus_port0) {
+		rc = msm_bus_axi_portunhalt(fs->bus_port0);
 		if (rc) {
-			pr_err("%s: Port 1 unhalt failed.\n", __func__);
+			pr_err("Port 0 unhalt failed.\n");
 			goto err;
 		}
 	}
@@ -325,12 +334,12 @@
 	 * footswitch_enable() is first called before footswitch_disable()
 	 * and resets should be asserted before power is restored.
 	 */
-	if (fs->axi_clk)
-		clk_reset(fs->axi_clk, CLK_RESET_ASSERT);
-	clk_reset(fs->ahb_clk, CLK_RESET_ASSERT);
-	clk_reset(fs->core_clk, CLK_RESET_ASSERT);
+	for (clock = fs->clk_data; clock->clk; clock++)
+		; /* Do nothing */
+	for (clock--; clock >= fs->clk_data; clock--)
+		clk_reset(clock->clk, CLK_RESET_ASSERT);
 	/* Wait for synchronous resets to propagate. */
-	udelay(20);
+	udelay(RESET_DELAY_US);
 
 	/* Enable the power rail at the footswitch. */
 	regval |= ENABLE_BIT;
@@ -343,11 +352,9 @@
 	writel_relaxed(regval, fs->gfs_ctl_reg);
 
 	/* Deassert resets for all clocks in the power domain. */
-	if (fs->axi_clk)
-		clk_reset(fs->axi_clk, CLK_RESET_DEASSERT);
-	clk_reset(fs->ahb_clk, CLK_RESET_DEASSERT);
-	clk_reset(fs->core_clk, CLK_RESET_DEASSERT);
-	udelay(20);
+	for (clock = fs->clk_data; clock->clk; clock++)
+		clk_reset(clock->clk, CLK_RESET_DEASSERT);
+	udelay(RESET_DELAY_US);
 
 	/* Re-enable core clock. */
 	clk_enable(fs->core_clk);
@@ -366,6 +373,7 @@
 static int gfx2d_footswitch_disable(struct regulator_dev *rdev)
 {
 	struct footswitch *fs = rdev_get_drvdata(rdev);
+	struct clk_data *clock;
 	uint32_t regval, rc = 0;
 
 	/* Return early if already disabled. */
@@ -379,10 +387,10 @@
 		return rc;
 
 	/* Halt all bus ports in the power domain. */
-	if (fs->bus_port1) {
-		rc = msm_bus_axi_porthalt(fs->bus_port1);
+	if (fs->bus_port0) {
+		rc = msm_bus_axi_porthalt(fs->bus_port0);
 		if (rc) {
-			pr_err("%s: Port 1 halt failed.\n", __func__);
+			pr_err("Port 0 halt failed.\n");
 			goto err;
 		}
 	}
@@ -394,12 +402,12 @@
 	 * Assert resets for all clocks in the clock domain so that
 	 * outputs settle prior to clamping.
 	 */
-	if (fs->axi_clk)
-		clk_reset(fs->axi_clk, CLK_RESET_ASSERT);
-	clk_reset(fs->ahb_clk, CLK_RESET_ASSERT);
-	clk_reset(fs->core_clk, CLK_RESET_ASSERT);
+	for (clock = fs->clk_data; clock->clk; clock++)
+		; /* Do nothing */
+	for (clock--; clock >= fs->clk_data; clock--)
+		clk_reset(clock->clk, CLK_RESET_ASSERT);
 	/* Wait for synchronous resets to propagate. */
-	udelay(20);
+	udelay(5);
 
 	/*
 	 * Clamp the I/O ports of the core to ensure the values
@@ -438,8 +446,111 @@
 	.disable = gfx2d_footswitch_disable,
 };
 
-#define FOOTSWITCH(_id, _name, _ops, _gfs_ctl_reg, _dc, _axi_clk, \
-		   _reset_rate, _bp1, _bp2) \
+/*
+ * Lists of required clocks for the collapse and restore sequences.
+ *
+ * Order matters here. Clocks are listed in the same order as their
+ * resets will be de-asserted when the core is restored. Also, rate-
+ * settable clocks must be listed before any of the branches that
+ * are derived from them. Otherwise, the branches may fail to enable
+ * if their parent's rate is not yet set.
+ */
+
+static struct clk_data gfx2d0_clks[] = {
+	{ .name = "core_clk" },
+	{ .name = "iface_clk" },
+	{ 0 }
+};
+
+static struct clk_data gfx2d1_clks[] = {
+	{ .name = "core_clk" },
+	{ .name = "iface_clk" },
+	{ 0 }
+};
+
+static struct clk_data gfx3d_clks[] = {
+	{ .name = "core_clk", .reset_rate = 27000000 },
+	{ .name = "iface_clk" },
+	{ 0 }
+};
+
+
+static struct clk_data ijpeg_clks[] = {
+	{ .name = "core_clk" },
+	{ .name = "iface_clk" },
+	{ .name = "bus_clk" },
+	{ 0 }
+};
+
+static struct clk_data mdp_8960_clks[] = {
+	{ .name = "core_clk" },
+	{ .name = "iface_clk" },
+	{ .name = "bus_clk" },
+	{ .name = "vsync_clk" },
+	{ .name = "lut_clk" },
+	{ .name = "tv_src_clk" },
+	{ .name = "tv_clk" },
+	{ 0 }
+};
+
+static struct clk_data mdp_8660_clks[] = {
+	{ .name = "core_clk" },
+	{ .name = "iface_clk" },
+	{ .name = "bus_clk" },
+	{ .name = "vsync_clk" },
+	{ .name = "tv_src_clk" },
+	{ .name = "tv_clk" },
+	{ .name = "pixel_mdp_clk" },
+	{ .name = "pixel_lcdc_clk" },
+	{ 0 }
+};
+
+static struct clk_data rot_clks[] = {
+	{ .name = "core_clk" },
+	{ .name = "iface_clk" },
+	{ .name = "bus_clk" },
+	{ 0 }
+};
+
+static struct clk_data ved_8660_clks[] = {
+	{ .name = "core_clk" },
+	{ .name = "iface_clk" },
+	{ .name = "bus_clk" },
+	{ 0 }
+};
+
+static struct clk_data ved_8960_clks[] = {
+	{ .name = "core_clk" },
+	{ .name = "iface_clk" },
+	{ .name = "bus_clk" },
+	{ .name = "bus_a_clk" },
+	{ .name = "bus_b_clk" },
+	{ 0 }
+};
+
+static struct clk_data vfe_clks[] = {
+	{ .name = "core_clk" },
+	{ .name = "iface_clk" },
+	{ .name = "bus_clk" },
+	{ 0 }
+};
+
+static struct clk_data vpe_clks[] = {
+	{ .name = "core_clk" },
+	{ .name = "iface_clk" },
+	{ .name = "bus_clk" },
+	{ 0 }
+};
+
+static struct clk_data vcap_clks[] = {
+	{ .name = "core_clk" },
+	{ .name = "iface_clk" },
+	{ .name = "bus_clk" },
+	{ 0 }
+};
+
+#define FOOTSWITCH(_id, _name, _ops, _gfs_ctl_reg, _dc, _clk_data, \
+		   _bp1, _bp2) \
 	[(_id)] = { \
 		.desc = { \
 			.id = (_id), \
@@ -450,43 +561,42 @@
 		}, \
 		.gfs_ctl_reg = (_gfs_ctl_reg), \
 		.gfs_delay_cnt = (_dc), \
-		.bus_port1 = (_bp1), \
-		.bus_port2 = (_bp2), \
-		.has_axi_clk = (_axi_clk), \
-		.reset_rate = (_reset_rate), \
+		.clk_data = (_clk_data), \
+		.bus_port0 = (_bp1), \
+		.bus_port1 = (_bp2), \
 	}
 static struct footswitch footswitches[] = {
 	FOOTSWITCH(FS_GFX2D0, "fs_gfx2d0", &gfx2d_fs_ops,
-		GFX2D0_GFS_CTL_REG, 31, false, 0,
+		GFX2D0_GFS_CTL_REG, 31, gfx2d0_clks,
 		MSM_BUS_MASTER_GRAPHICS_2D_CORE0, 0),
 	FOOTSWITCH(FS_GFX2D1, "fs_gfx2d1", &gfx2d_fs_ops,
-		GFX2D1_GFS_CTL_REG, 31, false, 0,
+		GFX2D1_GFS_CTL_REG, 31, gfx2d1_clks,
 		MSM_BUS_MASTER_GRAPHICS_2D_CORE1, 0),
 	FOOTSWITCH(FS_GFX3D, "fs_gfx3d", &standard_fs_ops,
-		GFX3D_GFS_CTL_REG, 31, false, 27000000,
+		GFX3D_GFS_CTL_REG, 31, gfx3d_clks,
 		MSM_BUS_MASTER_GRAPHICS_3D, 0),
 	FOOTSWITCH(FS_IJPEG, "fs_ijpeg", &standard_fs_ops,
-		GEMINI_GFS_CTL_REG, 31, true, 0,
+		GEMINI_GFS_CTL_REG, 31, ijpeg_clks,
 		MSM_BUS_MASTER_JPEG_ENC, 0),
 	FOOTSWITCH(FS_MDP, "fs_mdp", &standard_fs_ops,
-		MDP_GFS_CTL_REG, 31, true, 0,
+		MDP_GFS_CTL_REG, 31, NULL,
 		MSM_BUS_MASTER_MDP_PORT0,
 		MSM_BUS_MASTER_MDP_PORT1),
 	FOOTSWITCH(FS_ROT, "fs_rot", &standard_fs_ops,
-		ROT_GFS_CTL_REG, 31, true, 0,
+		ROT_GFS_CTL_REG, 31, rot_clks,
 		MSM_BUS_MASTER_ROTATOR, 0),
 	FOOTSWITCH(FS_VED, "fs_ved", &standard_fs_ops,
-		VED_GFS_CTL_REG, 31, true, 0,
+		VED_GFS_CTL_REG, 31, NULL,
 		MSM_BUS_MASTER_HD_CODEC_PORT0,
 		MSM_BUS_MASTER_HD_CODEC_PORT1),
 	FOOTSWITCH(FS_VFE, "fs_vfe", &standard_fs_ops,
-		VFE_GFS_CTL_REG, 31, true, 0,
+		VFE_GFS_CTL_REG, 31, vfe_clks,
 		MSM_BUS_MASTER_VFE, 0),
 	FOOTSWITCH(FS_VPE, "fs_vpe", &standard_fs_ops,
-		VPE_GFS_CTL_REG, 31, true, 0,
+		VPE_GFS_CTL_REG, 31, vpe_clks,
 		MSM_BUS_MASTER_VPE, 0),
 	FOOTSWITCH(FS_VCAP, "fs_vcap", &standard_fs_ops,
-		VCAP_GFS_CTL_REG, 31, true, 0,
+		VCAP_GFS_CTL_REG, 31, vcap_clks,
 		MSM_BUS_MASTER_VIDEO_CAP, 0),
 };
 
@@ -494,6 +604,7 @@
 {
 	struct footswitch *fs;
 	struct regulator_init_data *init_data;
+	struct clk_data *clock;
 	uint32_t regval, rc = 0;
 
 	if (pdev == NULL)
@@ -505,30 +616,32 @@
 	fs = &footswitches[pdev->id];
 	init_data = pdev->dev.platform_data;
 
-	/* Setup core clock. */
-	fs->core_clk = clk_get(&pdev->dev, "core_clk");
-	if (IS_ERR(fs->core_clk)) {
-		pr_err("%s: clk_get(core_clk) failed\n", __func__);
-		rc = PTR_ERR(fs->core_clk);
-		goto err_core_clk;
+	if (pdev->id == FS_MDP) {
+		if (cpu_is_msm8960() || cpu_is_msm8930())
+			fs->clk_data = mdp_8960_clks;
+		else if (cpu_is_msm8x60())
+			fs->clk_data = mdp_8660_clks;
+		else
+			BUG();
+	}
+	if (pdev->id == FS_VED) {
+		if (cpu_is_msm8960() || cpu_is_msm8930())
+			fs->clk_data = ved_8960_clks;
+		else if (cpu_is_msm8x60())
+			fs->clk_data = ved_8660_clks;
+		else
+			BUG();
 	}
 
-	/* Setup AHB clock. */
-	fs->ahb_clk = clk_get(&pdev->dev, "iface_clk");
-	if (IS_ERR(fs->ahb_clk)) {
-		pr_err("%s: clk_get(iface_clk) failed\n", __func__);
-		rc = PTR_ERR(fs->ahb_clk);
-		goto err_ahb_clk;
-	}
-
-	/* Setup AXI clock. */
-	if (fs->has_axi_clk) {
-		fs->axi_clk = clk_get(&pdev->dev, "bus_clk");
-		if (IS_ERR(fs->axi_clk)) {
-			pr_err("%s: clk_get(bus_clk) failed\n", __func__);
-			rc = PTR_ERR(fs->axi_clk);
-			goto err_axi_clk;
+	for (clock = fs->clk_data; clock->name; clock++) {
+		clock->clk = clk_get(&pdev->dev, clock->name);
+		if (IS_ERR(clock->clk)) {
+			rc = PTR_ERR(clock->clk);
+			pr_err("clk_get(%s) failed\n", clock->name);
+			goto err;
 		}
+		if (!strncmp(clock->name, "core_clk", 8))
+			fs->core_clk = clock->clk;
 	}
 
 	/*
@@ -543,34 +656,28 @@
 
 	fs->rdev = regulator_register(&fs->desc, &pdev->dev, init_data, fs);
 	if (IS_ERR(footswitches[pdev->id].rdev)) {
-		pr_err("%s: regulator_register(\"%s\") failed\n",
-			__func__, fs->desc.name);
+		pr_err("regulator_register(\"%s\") failed\n",
+			fs->desc.name);
 		rc = PTR_ERR(footswitches[pdev->id].rdev);
-		goto err_register;
+		goto err;
 	}
 
 	return 0;
 
-err_register:
-	if (fs->has_axi_clk)
-		clk_put(fs->axi_clk);
-err_axi_clk:
-	clk_put(fs->ahb_clk);
-err_ahb_clk:
-	clk_put(fs->core_clk);
-err_core_clk:
+err:
+	for (clock = fs->clk_data; clock->clk; clock++)
+		clk_put(clock->clk);
+
 	return rc;
 }
 
 static int __devexit footswitch_remove(struct platform_device *pdev)
 {
 	struct footswitch *fs = &footswitches[pdev->id];
+	struct clk_data *clock;
 
-	clk_put(fs->core_clk);
-	clk_put(fs->ahb_clk);
-	if (fs->axi_clk)
-		clk_put(fs->axi_clk);
-
+	for (clock = fs->clk_data; clock->clk; clock++)
+		clk_put(clock->clk);
 	regulator_unregister(fs->rdev);
 
 	return 0;
diff --git a/arch/arm/mach-msm/gpio.c b/arch/arm/mach-msm/gpio.c
index 5ad62265..a942862 100644
--- a/arch/arm/mach-msm/gpio.c
+++ b/arch/arm/mach-msm/gpio.c
@@ -20,6 +20,7 @@
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/module.h>
+#include <asm/mach/irq.h>
 #include <mach/gpiomux.h>
 #include "gpio_hw.h"
 #include "proc_comm.h"
@@ -337,6 +338,9 @@
 {
 	int i, j, mask;
 	unsigned val;
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+
+	chained_irq_enter(chip, desc);
 
 	for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
 		struct msm_gpio_chip *msm_chip = &msm_gpio_chips[i];
@@ -353,7 +357,8 @@
 					   msm_chip->chip.base + j);
 		}
 	}
-	desc->irq_data.chip->irq_ack(&desc->irq_data);
+
+	chained_irq_exit(chip, desc);
 }
 
 static struct irq_chip msm_gpio_irq_chip = {
diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c
index e8aa38e..86a2374 100644
--- a/arch/arm/mach-msm/hotplug.c
+++ b/arch/arm/mach-msm/hotplug.c
@@ -11,10 +11,22 @@
 #include <linux/smp.h>
 
 #include <asm/cacheflush.h>
+#include <asm/vfp.h>
 
-#ifdef CONFIG_SMP
+#include "qdss.h"
+#include "spm.h"
+#include "pm.h"
+
 extern volatile int pen_release;
 
+struct msm_hotplug_device {
+	struct completion cpu_killed;
+	unsigned int warm_boot;
+};
+
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_hotplug_device,
+			msm_hotplug_devices);
+
 static inline void cpu_enter_lowpower(void)
 {
 	/* Just flush the cache. Changing the coherency is not yet
@@ -30,14 +42,8 @@
 {
 	/* Just enter wfi for now. TODO: Properly shut off the cpu. */
 	for (;;) {
-		/*
-		 * here's the WFI
-		 */
-		asm("wfi"
-		    :
-		    :
-		    : "memory", "cc");
 
+		msm_pm_cpu_enter_lowpower(cpu);
 		if (pen_release == cpu) {
 			/*
 			 * OK, proper wakeup, we're done
@@ -56,11 +62,13 @@
 		pr_debug("CPU%u: spurious wakeup call\n", cpu);
 	}
 }
-#endif
 
 int platform_cpu_kill(unsigned int cpu)
 {
-	return 1;
+	struct completion *killed =
+		&per_cpu(msm_hotplug_devices, cpu).cpu_killed;
+
+	return wait_for_completion_timeout(killed, HZ * 5);
 }
 
 /*
@@ -70,19 +78,20 @@
  */
 void platform_cpu_die(unsigned int cpu)
 {
-#ifdef CONFIG_SMP
+	if (unlikely(cpu != smp_processor_id())) {
+		pr_crit("%s: running on %u, should be %u\n",
+			__func__, smp_processor_id(), cpu);
+		BUG();
+	}
+	complete(&__get_cpu_var(msm_hotplug_devices).cpu_killed);
 	/*
 	 * we're ready for shutdown now, so do it
 	 */
 	cpu_enter_lowpower();
 	platform_do_lowpower(cpu);
 
-	/*
-	 * bring this CPU back into the world of cache
-	 * coherency, and then restore interrupts
-	 */
+	pr_notice("CPU%u: %s: normal wakeup\n", cpu, __func__);
 	cpu_leave_lowpower();
-#endif
 }
 
 int platform_cpu_disable(unsigned int cpu)
@@ -93,3 +102,23 @@
 	 */
 	return cpu == 0 ? -EPERM : 0;
 }
+
+int msm_platform_secondary_init(unsigned int cpu)
+{
+	int ret;
+	struct msm_hotplug_device *dev = &__get_cpu_var(msm_hotplug_devices);
+
+	if (!dev->warm_boot) {
+		dev->warm_boot = 1;
+		init_completion(&dev->cpu_killed);
+		return 0;
+	}
+	etm_restore_reg_check();
+	msm_restore_jtag_debug();
+#ifdef CONFIG_VFP
+	vfp_reinit();
+#endif
+	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
+
+	return ret;
+}
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 06a389e..ae68036 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -219,6 +219,11 @@
 	struct msm_actuator_info *actuator_info;
 };
 
+struct msm_camera_board_info {
+	struct i2c_board_info *board_info;
+	uint8_t num_i2c_board_info;
+};
+
 int msm_get_cam_resources(struct msm_camera_sensor_info *);
 
 struct clk_lookup;
@@ -311,9 +316,14 @@
 	struct msm_bus_scale_pdata *mdp_bus_scale_table;
 #endif
 	int mdp_rev;
-	int (*writeback_offset)(void);
+	int mdp_writeback_memtype;
+	void *mdp_writeback_phys;    /* writeback physical addr */
+	int mdp_writeback_size_ov0;  /* overlay0 writeback size */
+	int mdp_writeback_size_ov1;  /* overlay1 writeback size */
 };
 
+
+
 struct lcdc_platform_data {
 	int (*lcdc_gpio_config)(int on);
 	int (*lcdc_power_save)(int);
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index ae1f753..1dc6758 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -667,6 +667,8 @@
 void msm_io_dump(void __iomem *addr, int size);
 void msm_io_memcpy(void __iomem *dest_addr, void __iomem *src_addr, u32 len);
 void msm_camio_set_perf_lvl(enum msm_bus_perf_setting);
+void msm_camio_bus_scale_cfg(
+	struct msm_bus_scale_pdata *, enum msm_bus_perf_setting);
 
 void *msm_isp_sync_alloc(int size, gfp_t gfp);
 
@@ -674,4 +676,7 @@
 
 int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info,
 		struct clk **clk_ptr, int num_clk, int enable);
+
+int msm_sensor_probe_on(struct device *);
+int msm_sensor_probe_off(struct device *);
 #endif
diff --git a/arch/arm/mach-msm/include/mach/diag_bridge.h b/arch/arm/mach-msm/include/mach/diag_bridge.h
index 281a1a6..a39ed25 100644
--- a/arch/arm/mach-msm/include/mach/diag_bridge.h
+++ b/arch/arm/mach-msm/include/mach/diag_bridge.h
@@ -16,27 +16,27 @@
 struct diag_bridge_ops {
 	void *ctxt;
 	void (*read_complete_cb)(void *ctxt, char *buf,
-			size_t buf_size, size_t actual);
+			int buf_size, int actual);
 	void (*write_complete_cb)(void *ctxt, char *buf,
-			size_t buf_size, size_t actual);
+			int buf_size, int actual);
 };
 
 #if defined(CONFIG_USB_QCOM_DIAG_BRIDGE) \
 	|| defined(CONFIG_USB_QCOM_DIAG_BRIDGE_MODULE)
 
-extern int diag_bridge_read(char *data, size_t size);
-extern int diag_bridge_write(char *data, size_t size);
+extern int diag_bridge_read(char *data, int size);
+extern int diag_bridge_write(char *data, int size);
 extern int diag_bridge_open(struct diag_bridge_ops *ops);
 extern void diag_bridge_close(void);
 
 #else
 
-static int __maybe_unused diag_bridge_read(char *data, size_t size)
+static int __maybe_unused diag_bridge_read(char *data, int size)
 {
 	return -ENODEV;
 }
 
-static int __maybe_unused diag_bridge_write(char *data, size_t size)
+static int __maybe_unused diag_bridge_write(char *data, int size)
 {
 	return -ENODEV;
 }
diff --git a/arch/arm/mach-msm/include/mach/entry-macro-qgic.S b/arch/arm/mach-msm/include/mach/entry-macro-qgic.S
deleted file mode 100644
index 092e48e..0000000
--- a/arch/arm/mach-msm/include/mach/entry-macro-qgic.S
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Low-level IRQ helper macros
- *
- * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
- *
- * 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 <mach/hardware.h>
-#include <asm/hardware/gic.h>
-
-	.macro	disable_fiq
-	.endm
-
-	.macro  get_irqnr_preamble, base, tmp
-	ldr	\base, =gic_cpu_base_addr
-	ldr	\base, [\base]
-	.endm
-
-	.macro  arch_ret_to_user, tmp1, tmp2
-	.endm
-
-	/*
-	 * The interrupt numbering scheme is defined in the
-	 * interrupt controller spec.  To wit:
-	 *
-	 * Migrated the code from ARM MP port to be more consistant
-	 * with interrupt processing , the following still holds true
-	 * however, all interrupts are treated the same regardless of
-	 * if they are local IPI or PPI
-	 *
-	 * Interrupts 0-15 are IPI
-	 * 16-31 are PPI
-	 *   (16-18 are the timers)
-	 * 32-1020 are global
-	 * 1021-1022 are reserved
-	 * 1023 is "spurious" (no interrupt)
-	 *
-	 * A simple read from the controller will tell us the number of the
-	 * highest priority enabled interrupt.  We then just need to check
-	 * whether it is in the valid range for an IRQ (0-1020 inclusive).
-	 *
-	 * Base ARM code assumes that the local (private) peripheral interrupts
-	 * are not valid, we treat them differently, in that the privates are
-	 * handled like normal shared interrupts with the exception that only
-	 * one processor can register the interrupt and the handler must be
-	 * the same for all processors.
-	 */
-
-	.macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
-
-	ldr  \irqstat, [\base, #GIC_CPU_INTACK] /* bits 12-10 =srcCPU,
-						   9-0 =int # */
-
-	bic     \irqnr, \irqstat, #0x1c00	@mask src
-#ifdef CONFIG_REQUEST_IPI
-	cmp     \irqnr, #0
-#else
-	cmp     \irqnr, #15
-#endif
-	ldr		\tmp, =1021
-	cmpcc	\irqnr, \irqnr
-	cmpne	\irqnr, \tmp
-	cmpcs	\irqnr, \irqnr
-
-	.endm
-
-	/* We assume that irqstat (the raw value of the IRQ acknowledge
-	 * register) is preserved from the macro above.
-	 * If there is an IPI, we immediately signal end of interrupt on the
-	 * controller, since this requires the original irqstat value which
-	 * we won't easily be able to recreate later.
-	 */
-	.macro test_for_ipi, irqnr, irqstat, base, tmp
-#ifndef CONFIG_REQUEST_IPI
-    bic \irqnr, \irqstat, #0x1c00
-    cmp \irqnr, #16
-    strcc   \irqstat, [\base, #GIC_CPU_EOI]
-    cmpcs   \irqnr, \irqnr
-#endif
-	.endm
-
-	/* As above, this assumes that irqstat and base are preserved.. */
-
-	.macro test_for_ltirq, irqnr, irqstat, base, tmp
-#ifndef CONFIG_REQUEST_IPI
-    bic \irqnr, \irqstat, #0x1c00
-    mov     \tmp, #0
-    cmp \irqnr, #16
-    moveq   \tmp, #1
-    streq   \irqstat, [\base, #GIC_CPU_EOI]
-    cmp \tmp, #0
-#endif
-	.endm
diff --git a/arch/arm/mach-msm/include/mach/entry-macro-vic.S b/arch/arm/mach-msm/include/mach/entry-macro-vic.S
deleted file mode 100644
index 70563ed..0000000
--- a/arch/arm/mach-msm/include/mach/entry-macro-vic.S
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2007 Google, Inc.
- * Author: Brian Swetland <swetland@google.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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.
- *
- */
-
-#include <mach/msm_iomap.h>
-
-	.macro	disable_fiq
-	.endm
-
-	.macro	get_irqnr_preamble, base, tmp
-	@ enable imprecise aborts
-	cpsie	a
-	mov	\base, #MSM_VIC_BASE
-	.endm
-
-	.macro	arch_ret_to_user, tmp1, tmp2
-	.endm
-
-	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
-	@ 0xD0 has irq# or old irq# if the irq has been handled
-	@ 0xD4 has irq# or -1 if none pending *but* if you just
-	@ read 0xD4 you never get the first irq for some reason
-	ldr	\irqnr, [\base, #0xD0]
-	ldr	\irqnr, [\base, #0xD4]
-	cmp	\irqnr, #0xffffffff
-	.endm
diff --git a/arch/arm/mach-msm/include/mach/entry-macro.S b/arch/arm/mach-msm/include/mach/entry-macro.S
index d384366..de696ca8 100644
--- a/arch/arm/mach-msm/include/mach/entry-macro.S
+++ b/arch/arm/mach-msm/include/mach/entry-macro.S
@@ -10,15 +10,27 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
-#if defined(CONFIG_MSM_VIC) && !defined(CONFIG_MULTI_IRQ_HANDLER)
-#include <mach/entry-macro-vic.S>
-#elif defined(CONFIG_ARM_GIC)
-#include <mach/entry-macro-qgic.S>
-#else
 	.macro	disable_fiq
 	.endm
 
 	.macro	arch_ret_to_user, tmp1, tmp2
 	.endm
 
+#if !defined(CONFIG_ARM_GIC) && !defined(CONFIG_MULTI_IRQ_HANDLER)
+#include <mach/msm_iomap.h>
+
+	.macro	get_irqnr_preamble, base, tmp
+	@ enable imprecise aborts
+	cpsie	a
+	mov	\base, #MSM_VIC_BASE
+	.endm
+
+	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
+	@ 0xD0 has irq# or old irq# if the irq has been handled
+	@ 0xD4 has irq# or -1 if none pending *but* if you just
+	@ read 0xD4 you never get the first irq for some reason
+	ldr	\irqnr, [\base, #0xD0]
+	ldr	\irqnr, [\base, #0xD4]
+	cmp	\irqnr, #0xffffffff
+	.endm
 #endif
diff --git a/include/linux/rtc/rtc-pm8058.h b/arch/arm/mach-msm/include/mach/mdm-peripheral.h
similarity index 65%
rename from include/linux/rtc/rtc-pm8058.h
rename to arch/arm/mach-msm/include/mach/mdm-peripheral.h
index 340fb2d..0f3bd33 100644
--- a/include/linux/rtc/rtc-pm8058.h
+++ b/arch/arm/mach-msm/include/mach/mdm-peripheral.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011, Code Aurora Forum. 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 version 2 and
@@ -8,14 +8,12 @@
  * 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.
- *
  */
 
-#ifndef __RTC_PM8058_H__
-#define __RTC_PM8058_H__
+#ifndef _ARCH_ARM_MACH_MSM_MDM_PERIPHERAL_H
+#define _ARCH_ARM_MACH_MSM_MDM_PERIPHERAL_H_
 
-struct pm8058_rtc_platform_data {
-	bool rtc_alarm_powerup;
-};
+extern void peripheral_connect(void);
+extern void peripheral_disconnect(void);
 
-#endif /* __RTC_PM8058_H__ */
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_xo.h b/arch/arm/mach-msm/include/mach/msm_xo.h
index 30c3272..77606474 100644
--- a/arch/arm/mach-msm/include/mach/msm_xo.h
+++ b/arch/arm/mach-msm/include/mach/msm_xo.h
@@ -20,6 +20,7 @@
 	MSM_XO_TCXO_A2,
 	MSM_XO_CORE,
 	MSM_XO_PXO,
+	MSM_XO_CXO,
 	NUM_MSM_XO_IDS
 };
 
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h
index 444d7ad..487e814 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/apr_us.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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 version 2 and
@@ -124,17 +124,6 @@
 } __packed;
 
 #define USM_DATA_EVENT_READ_DONE			0x0001230F
-struct usm_data_event_read_done {
-	u32            status;
-	u32            buffer_add;
-	u32            enc_frame_size;
-	u32            offset;
-	u32            msw_ts;
-	u32            lsw_ts;
-	u32            flags;
-	u32            num_frames;
-	u32            id;
-} __packed;
 
 #define USM_DATA_CMD_WRITE				0x00011273
 struct usm_stream_cmd_write {
@@ -148,9 +137,18 @@
 } __packed;
 
 #define USM_DATA_EVENT_WRITE_DONE			0x00011274
-struct usm_data_event_write_done {
-	u32 buf_add;
-	u32 status;
+
+/* Start/stop US signal detection */
+#define USM_SESSION_CMD_SIGNAL_DETECT_MODE		0x00012719
+
+struct usm_session_cmd_detect_info {
+	struct apr_hdr hdr;
+	u32 detect_mode;
+	u32 skip_interval;
+	u32 algorithm_cfg_size;
 } __packed;
 
+/* US signal detection result */
+#define USM_SESSION_EVENT_SIGNAL_DETECT_RESULT		0x00012720
+
 #endif /* __APR_US_H__ */
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/audio_acdb.h b/arch/arm/mach-msm/include/mach/qdsp6v2/audio_acdb.h
index 1251e5b8..16751fe 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/audio_acdb.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/audio_acdb.h
@@ -16,8 +16,6 @@
 #include <linux/msm_audio_acdb.h>
 #include <sound/q6adm.h>
 
-#define NUM_AUDPROC_BUFFERS	6
-
 enum {
 	RX_CAL,
 	TX_CAL,
@@ -35,12 +33,6 @@
 	struct acdb_cal_block	*cal_blocks;
 };
 
-struct audproc_buffer_data {
-	uint32_t	buf_size[NUM_AUDPROC_BUFFERS];
-	uint32_t	phys_addr[NUM_AUDPROC_BUFFERS];
-};
-
-
 uint32_t get_voice_rx_topology(void);
 uint32_t get_voice_tx_topology(void);
 uint32_t get_adm_rx_topology(void);
@@ -52,7 +44,6 @@
 void get_all_vocstrm_cal(struct acdb_cal_block *cal_block);
 void get_all_vocvol_cal(struct acdb_cal_block *cal_block);
 void get_anc_cal(struct acdb_cal_block *cal_block);
-void get_audproc_buffer_data(struct audproc_buffer_data *cal_buffers);
 void get_audproc_cal(int32_t path, struct acdb_cal_block *cal_block);
 void get_audstrm_cal(int32_t path, struct acdb_cal_block *cal_block);
 void get_audvol_cal(int32_t path, struct acdb_cal_block *cal_block);
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
index 346dc0d..884c5d0 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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 version 2 and
@@ -33,12 +33,40 @@
 #define US_STOP_TX      _IO(USF_IOCTL_MAGIC, 6)
 #define US_STOP_RX      _IO(USF_IOCTL_MAGIC, 7)
 
+#define US_SET_DETECTION _IOWR(USF_IOCTL_MAGIC, 8, \
+				struct us_detect_info_type)
+
+/* Special timeout values */
+#define USF_NO_WAIT_TIMEOUT	0x00000000
+/* Infinitive */
+#define USF_INFINITIVE_TIMEOUT	0xffffffff
+/* Default value, used by the driver */
+#define USF_DEFAULT_TIMEOUT	0xfffffffe
+
+/* US detection place (HW|FW) */
+enum us_detect_place_enum {
+/* US is detected in HW */
+	US_DETECT_HW,
+/* US is detected in FW */
+	US_DETECT_FW
+};
+
+/* US detection mode */
+enum us_detect_mode_enum {
+/* US detection is disabled */
+	US_DETECT_DISABLED_MODE,
+/* US detection is enabled in continue mode */
+	US_DETECT_CONTINUE_MODE,
+/* US detection is enabled in one shot mode */
+	US_DETECT_SHOT_MODE
+};
 
 /* Encoder (TX), decoder (RX) supported US data formats */
 #define USF_POINT_EPOS_FORMAT	0
-#define USF_RAW_FORMAT		    1
+#define USF_RAW_FORMAT		1
 
 /* Types of events, produced by the calculators */
+#define USF_NO_EVENT 0
 #define USF_TSC_EVENT 1
 #define USF_MOUSE_EVENT 2
 #define USF_KEYBOARD_EVENT 4
@@ -155,6 +183,10 @@
 /* Pointer (read index) to the end of available region */
 /* in the shared US data memory */
 	uint32_t free_region;
+/* Time (sec) to wait for data or special values: */
+/* USF_NO_WAIT_TIMEOUT, USF_INFINITIVE_TIMEOUT, USF_DEFAULT_TIMEOUT */
+	uint32_t timeout;
+
 /* Input  transparent data: */
 /* Parameters size */
 	uint16_t params_data_size;
@@ -182,4 +214,22 @@
 	uint32_t free_region;
 };
 
+struct us_detect_info_type {
+/* US detection place (HW|FW) */
+/* NA in the Active and OFF states */
+	enum us_detect_place_enum us_detector;
+/* US detection mode */
+	enum us_detect_mode_enum  us_detect_mode;
+/* US data dropped during this time (msec) */
+	uint32_t skip_time;
+/* Transparent data size */
+	uint16_t params_data_size;
+/* Pointer to the transparent data */
+	uint8_t *params_data;
+/* Time (sec) to wait for US presence event */
+	uint32_t detect_timeout;
+/* Out parameter: US presence */
+	bool is_us;
+};
+
 #endif /* __USF_H__ */
diff --git a/arch/arm/mach-msm/include/mach/rpm-8960.h b/arch/arm/mach-msm/include/mach/rpm-8960.h
index 11862ea..41b94ae 100644
--- a/arch/arm/mach-msm/include/mach/rpm-8960.h
+++ b/arch/arm/mach-msm/include/mach/rpm-8960.h
@@ -44,6 +44,7 @@
 
 	MSM_RPM_SEL_CXO_CLK					= 5,
 	MSM_RPM_SEL_PXO_CLK					= 6,
+	MSM_RPM_SEL_QDSS_CLK					= 7,
 	MSM_RPM_SEL_APPS_FABRIC_CLK				= 8,
 	MSM_RPM_SEL_SYSTEM_FABRIC_CLK				= 9,
 	MSM_RPM_SEL_MM_FABRIC_CLK				= 10,
@@ -281,8 +282,9 @@
 	MSM_RPM_ID_HDMI_SWITCH					= 206,
 	MSM_RPM_ID_DDR_DMM_0					= 207,
 	MSM_RPM_ID_DDR_DMM_1					= 208,
+	MSM_RPM_ID_QDSS_CLK					= 209,
 
-	MSM_RPM_ID_LAST = MSM_RPM_ID_DDR_DMM_1
+	MSM_RPM_ID_LAST = MSM_RPM_ID_QDSS_CLK,
 };
 
 /* RPM resources RPM_ID aliases */
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator-copper.h b/arch/arm/mach-msm/include/mach/rpm-regulator-copper.h
new file mode 100644
index 0000000..2006ad3
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator-copper.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. 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 version 2 and
+ * only 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.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_COPPER_H
+#define __ARCH_ARM_MACH_MSM_INCLUDE_MACH_RPM_REGULATOR_COPPER_H
+
+/**
+ * enum rpm_vreg_id - RPM regulator ID numbers (both real and pin control)
+ */
+enum rpm_vreg_id_copper {
+	RPM_VREG_ID_PM8941_S1,
+	RPM_VREG_ID_PM8941_S2,
+	RPM_VREG_ID_PM8941_L12,
+	RPM_VREG_ID_PM8941_MAX,
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator.h b/arch/arm/mach-msm/include/mach/rpm-regulator.h
index f857ab8..1095078 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator.h
@@ -20,6 +20,7 @@
 #include <mach/rpm-regulator-8660.h>
 #include <mach/rpm-regulator-8960.h>
 #include <mach/rpm-regulator-9615.h>
+#include <mach/rpm-regulator-copper.h>
 
 /**
  * enum rpm_vreg_version - supported RPM regulator versions
@@ -136,6 +137,7 @@
 	RPM_VREG_VOTER_COUNT,
 };
 
+#ifdef CONFIG_MSM_RPM_REGULATOR
 /**
  * rpm_vreg_set_voltage - vote for a min_uV value of specified regualtor
  * @vreg: ID for regulator
@@ -172,4 +174,25 @@
  */
 int rpm_vreg_set_frequency(int vreg_id, enum rpm_vreg_freq freq);
 
+#else
+
+/*
+ * These stubs exist to allow consumers of these APIs to compile and run
+ * in absence of a real RPM regulator driver. It is assumed that they are
+ * aware of the state of their regulators and have either set them
+ * correctly by some other means or don't care about their state at all.
+ */
+static inline int rpm_vreg_set_voltage(int vreg_id, enum rpm_vreg_voter voter,
+				       int min_uV, int max_uV, int sleep_also)
+{
+	return 0;
+}
+
+static inline int rpm_vreg_set_frequency(int vreg_id, enum rpm_vreg_freq freq)
+{
+	return 0;
+}
+
+#endif /* CONFIG_MSM_RPM_REGULATOR */
+
 #endif
diff --git a/arch/arm/mach-msm/include/mach/usb_bridge.h b/arch/arm/mach-msm/include/mach/usb_bridge.h
index 2b7e754..effa395 100644
--- a/arch/arm/mach-msm/include/mach/usb_bridge.h
+++ b/arch/arm/mach-msm/include/mach/usb_bridge.h
@@ -22,10 +22,6 @@
  */
 #define MAX_BRIDGE_DEVICES 2
 
-/*PID 9001*/
-#define DUN_IFACE_NUM 2
-#define TETHERED_RMNET_IFACE_NUM 3
-
 struct bridge_ops {
 	int (*send_pkt)(void *, void *, size_t actual);
 	void (*send_cbits)(void *, unsigned int);
diff --git a/arch/arm/mach-msm/iommu.c b/arch/arm/mach-msm/iommu.c
index 16c0790..463d6c9 100644
--- a/arch/arm/mach-msm/iommu.c
+++ b/arch/arm/mach-msm/iommu.c
@@ -979,6 +979,12 @@
 	return 0;
 }
 
+static phys_addr_t msm_iommu_get_pt_base_addr(struct iommu_domain *domain)
+{
+	struct msm_priv *priv = domain->priv;
+	return __pa(priv->pgtable);
+}
+
 static struct iommu_ops msm_iommu_ops = {
 	.domain_init = msm_iommu_domain_init,
 	.domain_destroy = msm_iommu_domain_destroy,
@@ -989,7 +995,8 @@
 	.map_range = msm_iommu_map_range,
 	.unmap_range = msm_iommu_unmap_range,
 	.iova_to_phys = msm_iommu_iova_to_phys,
-	.domain_has_cap = msm_iommu_domain_has_cap
+	.domain_has_cap = msm_iommu_domain_has_cap,
+	.get_pt_base_addr = msm_iommu_get_pt_base_addr
 };
 
 static int __init get_tex_class(int icp, int ocp, int mt, int nos)
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 8e9cc0f..15ea8ba 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -1183,7 +1183,15 @@
 	}
 
 	temp_ptr = skb_peek(pkt->pkt_fragment_q);
+	if (!temp_ptr) {
+		pr_err("%s: pkt_fragment_q is empty\n", __func__);
+		return -EINVAL;
+	}
 	hdr = (struct rr_header *)temp_ptr->data;
+	if (!hdr) {
+		pr_err("%s: No data inside the skb\n", __func__);
+		return -EINVAL;
+	}
 	msg = (union rr_control_msg *)((char *)hdr + IPC_ROUTER_HDR_SIZE);
 
 	switch (msg->cmd) {
@@ -1595,6 +1603,10 @@
 	}
 
 	head_skb = skb_peek(pkt->pkt_fragment_q);
+	if (!head_skb) {
+		pr_err("%s: pkt_fragment_q is empty\n", __func__);
+		return -EINVAL;
+	}
 	hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
 	if (!hdr) {
 		pr_err("%s: Prepend Header failed\n", __func__);
@@ -1642,6 +1654,10 @@
 		return -EINVAL;
 
 	head_skb = skb_peek(pkt->pkt_fragment_q);
+	if (!head_skb) {
+		pr_err("%s: pkt_fragment_q is empty\n", __func__);
+		return -EINVAL;
+	}
 	hdr = (struct rr_header *)skb_push(head_skb, IPC_ROUTER_HDR_SIZE);
 	if (!hdr) {
 		pr_err("%s: Prepend Header failed\n", __func__);
diff --git a/arch/arm/mach-msm/irq-vic.c b/arch/arm/mach-msm/irq-vic.c
index 660d530..1bfa776 100644
--- a/arch/arm/mach-msm/irq-vic.c
+++ b/arch/arm/mach-msm/irq-vic.c
@@ -24,6 +24,7 @@
 
 #include <asm/cacheflush.h>
 #include <asm/io.h>
+#include <asm/exception.h>
 
 #include <mach/hardware.h>
 
diff --git a/arch/arm/mach-msm/mdm.c b/arch/arm/mach-msm/mdm.c
index 01cc48a..cbdc92a 100644
--- a/arch/arm/mach-msm/mdm.c
+++ b/arch/arm/mach-msm/mdm.c
@@ -29,9 +29,9 @@
 #include <linux/completion.h>
 #include <linux/workqueue.h>
 #include <linux/clk.h>
-#include <linux/mfd/pmic8058.h>
 #include <asm/mach-types.h>
 #include <asm/uaccess.h>
+#include <linux/mfd/pm8xxx/misc.h>
 #include <mach/mdm.h>
 #include <mach/restart.h>
 #include <mach/subsystem_notif.h>
@@ -120,7 +120,7 @@
 	CHARM_DBG("%s: setting AP2MDM_ERRFATAL high for a non graceful reset\n",
 			 __func__);
 	if (get_restart_level() == RESET_SOC)
-		pm8058_stay_on();
+		pm8xxx_stay_on();
 
 	charm_disable_irqs();
 	gpio_set_value(AP2MDM_ERRFATAL, 1);
@@ -238,7 +238,7 @@
 {
 	pr_info("Reseting the charm due to an errfatal\n");
 	if (get_restart_level() == RESET_SOC)
-		pm8058_stay_on();
+		pm8xxx_stay_on();
 	subsystem_restart("external_modem");
 }
 
diff --git a/arch/arm/mach-msm/mdm2.c b/arch/arm/mach-msm/mdm2.c
index 0737a81..bf4e6a4 100644
--- a/arch/arm/mach-msm/mdm2.c
+++ b/arch/arm/mach-msm/mdm2.c
@@ -33,6 +33,7 @@
 #include <asm/mach-types.h>
 #include <asm/uaccess.h>
 #include <mach/mdm2.h>
+#include <mach/mdm-peripheral.h>
 #include <mach/restart.h>
 #include <mach/subsystem_notif.h>
 #include <mach/subsystem_restart.h>
@@ -49,7 +50,6 @@
 #define IFLINE_DOWN			0
 
 static int mdm_debug_on;
-static int ifline_status = IFLINE_UP;
 static struct mdm_callbacks mdm_cb;
 
 #define MDM_DBG(...)	do { if (mdm_debug_on) \
@@ -58,12 +58,7 @@
 
 static void power_on_mdm(struct mdm_modem_drv *mdm_drv)
 {
-	/* Remove hsic driver before powering on the modem. */
-	if (ifline_status == IFLINE_UP) {
-		MDM_DBG("%s: Removing hsic device\n", __func__);
-		platform_device_del(&msm_device_hsic_host);
-		ifline_status = IFLINE_DOWN;
-	}
+	peripheral_disconnect();
 
 	/* Pull both ERR_FATAL and RESET low */
 	MDM_DBG("Pulling PWR and RESET gpio's low\n");
@@ -82,10 +77,7 @@
 	gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 1);
 	usleep(1000);
 
-	/* Add back hsic device after modem power up */
-	MDM_DBG("%s: Adding hsic device\n", __func__);
-	platform_device_add(&msm_device_hsic_host);
-	ifline_status = IFLINE_UP;
+	peripheral_connect();
 
 	msleep(200);
 }
@@ -111,12 +103,8 @@
 			msleep(MDM_MODEM_DELTA);
 		}
 	}
-	/* Also remove the hsic device on 9k power down. */
-	MDM_DBG("%s: Removing hsic device\n", __func__);
-	if (ifline_status == IFLINE_UP) {
-		platform_device_del(&msm_device_hsic_host);
-		ifline_status = IFLINE_DOWN;
-	}
+
+	peripheral_disconnect();
 }
 
 static void normal_boot_done(struct mdm_modem_drv *mdm_drv)
@@ -128,6 +116,16 @@
 	mdm_debug_on = value;
 }
 
+static void mdm_status_changed(int value)
+{
+	MDM_DBG("%s: value:%d\n", __func__, value);
+
+	if (value) {
+		peripheral_disconnect();
+		peripheral_connect();
+	}
+}
+
 static int __init mdm_modem_probe(struct platform_device *pdev)
 {
 	/* Instantiate driver object. */
@@ -135,6 +133,7 @@
 	mdm_cb.power_down_mdm_cb = power_down_mdm;
 	mdm_cb.normal_boot_done_cb = normal_boot_done;
 	mdm_cb.debug_state_changed_cb = debug_state_changed;
+	mdm_cb.status_cb = mdm_status_changed;
 	return mdm_common_create(pdev, &mdm_cb);
 }
 
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index 1262ce3..023df69 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -136,8 +136,18 @@
 
 static void mdm_status_fn(struct work_struct *work)
 {
-	MDM_DBG("%s: Reseting the mdm because status changed\n", __func__);
-	subsystem_restart(EXTERNAL_MODEM);
+	int value = gpio_get_value(mdm_drv->mdm2ap_status_gpio);
+
+	mdm_drv->status_cb(value);
+
+	MDM_DBG("%s: status:%d\n", __func__, value);
+
+	if ((value == 0) && mdm_drv->mdm_ready) {
+		MDM_DBG("%s: scheduling work now\n", __func__);
+		subsystem_restart(EXTERNAL_MODEM);
+	} else if (value == 1) {
+		MDM_DBG("%s: mdm is now ready\n", __func__);
+	}
 }
 
 static DECLARE_WORK(mdm_status_work, mdm_status_fn);
@@ -209,13 +219,9 @@
 static irqreturn_t mdm_status_change(int irq, void *dev_id)
 {
 	MDM_DBG("%s: mdm sent status change interrupt\n", __func__);
-	if ((gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
-		 && mdm_drv->mdm_ready) {
-		MDM_DBG("%s: scheduling work now\n", __func__);
-		queue_work(mdm_queue, &mdm_status_work);
-	} else if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 1) {
-		MDM_DBG("%s: mdm is now ready\n", __func__);
-	}
+
+	queue_work(mdm_queue, &mdm_status_work);
+
 	return IRQ_HANDLED;
 }
 
@@ -350,6 +356,7 @@
 	mdm_drv->power_down_mdm_cb          = p_mdm_cb->power_down_mdm_cb;
 	mdm_drv->normal_boot_done_cb        = p_mdm_cb->normal_boot_done_cb;
 	mdm_drv->debug_state_changed_cb     = p_mdm_cb->debug_state_changed_cb;
+	mdm_drv->status_cb                  = p_mdm_cb->status_cb;
 }
 
 int mdm_common_create(struct platform_device  *pdev,
@@ -432,8 +439,8 @@
 	}
 
 	ret = request_threaded_irq(irq, NULL, mdm_status_change,
-		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-		"mdm status", NULL);
+		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_SHARED,
+		"mdm status", mdm_drv);
 
 	if (ret < 0) {
 		pr_err("%s: MDM2AP_STATUS IRQ#%d request failed with error=%d"
diff --git a/arch/arm/mach-msm/mdm_private.h b/arch/arm/mach-msm/mdm_private.h
index 701eb7a..bc8541e 100644
--- a/arch/arm/mach-msm/mdm_private.h
+++ b/arch/arm/mach-msm/mdm_private.h
@@ -38,6 +38,7 @@
 	void (*normal_boot_done_cb)(struct mdm_modem_drv *mdm_drv);
 	void (*power_down_mdm_cb)(struct mdm_modem_drv *mdm_drv);
 	void (*debug_state_changed_cb)(int value);
+	void (*status_cb)(int value);
 };
 
 struct mdm_callbacks {
@@ -45,6 +46,7 @@
 	void (*normal_boot_done_cb)(struct mdm_modem_drv *mdm_drv);
 	void (*power_down_mdm_cb)(struct mdm_modem_drv *mdm_drv);
 	void (*debug_state_changed_cb)(int value);
+	void (*status_cb)(int value);
 };
 
 int mdm_common_create(struct platform_device  *pdev,
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index 33db3fa..46695c4 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -37,6 +37,7 @@
 #include <mach/msm_iomap.h>
 #include <mach/socinfo.h>
 #include <../../mm/mm.h>
+#include <linux/fmem.h>
 
 void *strongly_ordered_page;
 char strongly_ordered_mem[PAGE_SIZE*2-4];
@@ -439,3 +440,13 @@
 	asm("mrc p15, 0, %0, c2, c0, 0\n"
 		: "=r" (msm_ttbr0));
 }
+
+int request_fmem_c_region(void *unused)
+{
+	return fmem_set_state(FMEM_C_STATE);
+}
+
+int release_fmem_c_region(void *unused)
+{
+	return fmem_set_state(FMEM_T_STATE);
+}
diff --git a/arch/arm/mach-msm/modem-8660.c b/arch/arm/mach-msm/modem-8660.c
index 19711a2..0b7b768 100644
--- a/arch/arm/mach-msm/modem-8660.c
+++ b/arch/arm/mach-msm/modem-8660.c
@@ -40,6 +40,7 @@
 #if defined(SUBSYS_FATAL_DEBUG)
 static void debug_crash_modem_fn(struct work_struct *);
 static int reset_modem;
+static int ignore_smsm_ack;
 
 static DECLARE_DELAYED_WORK(debug_crash_modem_work,
 				debug_crash_modem_fn);
@@ -129,26 +130,30 @@
 				void *_cmd)
 {
 	if (code == MODEM_NOTIFIER_START_RESET) {
-
+		if (ignore_smsm_ack) {
+			ignore_smsm_ack = 0;
+			goto out;
+		}
 		pr_err("%s: Modem error fatal'ed.", MODULE_NAME);
 		subsystem_restart("modem");
 	}
+out:
 	return NOTIFY_DONE;
 }
 
 static int modem_shutdown(const struct subsys_data *crashed_subsys)
 {
 	void __iomem *modem_wdog_addr;
-	int smsm_notif_unregistered = 0;
 
 	/* If the modem didn't already crash, setting SMSM_RESET
-	 * here will help flush caches etc. Unregister for SMSM
-	 * notifications to prevent unnecessary secondary calls to
-	 * subsystem_restart.
+	 * here will help flush caches etc. The ignore_smsm_ack
+	 * flag is set to ignore the SMSM_RESET notification
+	 * that is generated due to the modem settings its own
+	 * SMSM_RESET bit in response to the apps setting the
+	 * apps SMSM_RESET bit.
 	 */
 	if (!(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RESET)) {
-		modem_unregister_notifier(&modem_notif_nb);
-		smsm_notif_unregistered = 1;
+		ignore_smsm_ack = 1;
 		smsm_reset_modem(SMSM_RESET);
 	}
 
@@ -168,9 +173,6 @@
 	pil_force_shutdown("modem");
 	disable_irq_nosync(MARM_WDOG_EXPIRED);
 
-	/* Re-register for SMSM notifications if necessary */
-	if (smsm_notif_unregistered)
-		modem_register_notifier(&modem_notif_nb);
 
 
 	return 0;
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_core.h b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
index c4c01e8..50afa81 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_core.h
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
@@ -24,13 +24,9 @@
 
 #define MSM_BUS_DBG(msg, ...) \
 	printk(KERN_DEBUG "AXI: %s(): " msg, __func__, ## __VA_ARGS__)
-#define MSM_FAB_DBG(msg, ...) \
-	dev_dbg(&fabric->fabdev.dev, "AXI: %s(): " msg, __func__, ## \
-	__VA_ARGS__)
 
 #else
 #define MSM_BUS_DBG(msg, ...) no_printk("AXI")
-#define MSM_FAB_DBG(msg, ...) no_printk("AXI")
 #endif
 
 #define MSM_BUS_ERR(msg, ...) \
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
index 02dfed6..b06e5dd 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -57,7 +57,7 @@
 	struct msm_bus_inode_info *info)
 {
 	int status = -ENOMEM;
-	MSM_FAB_DBG("msm_bus_fabric_add_node: ID %d Gw: %d\n",
+	MSM_BUS_DBG("msm_bus_fabric_add_node: ID %d Gw: %d\n",
 		info->node_info->priv_id, info->node_info->gateway);
 	status = radix_tree_preload(GFP_ATOMIC);
 	if (status)
@@ -96,7 +96,7 @@
 	struct msm_bus_inode_info *info)
 {
 	struct msm_bus_fabnodeinfo *fabnodeinfo;
-	MSM_FAB_DBG("msm_bus_fabric_add_fab: ID %d Gw: %d\n",
+	MSM_BUS_DBG("msm_bus_fabric_add_fab: ID %d Gw: %d\n",
 		info->node_info->priv_id, info->node_info->gateway);
 	fabnodeinfo = kzalloc(sizeof(struct msm_bus_fabnodeinfo), GFP_KERNEL);
 	if (fabnodeinfo == NULL) {
@@ -125,7 +125,7 @@
 {
 	int i, ret = 0, err = 0;
 
-	MSM_FAB_DBG("id:%d pdata-id: %d len: %d\n", fabric->fabdev.id,
+	MSM_BUS_DBG("id:%d pdata-id: %d len: %d\n", fabric->fabdev.id,
 		fabric->pdata->id, fabric->pdata->len);
 
 	for (i = 0; i < fabric->pdata->len; i++) {
@@ -179,12 +179,12 @@
 
 	fabric->rpm_data = allocate_rpm_data(fabric->pdata);
 
-	MSM_FAB_DBG("Fabric: %d nmasters: %d nslaves: %d\n"
+	MSM_BUS_DBG("Fabric: %d nmasters: %d nslaves: %d\n"
 		" ntieredslaves: %d, rpm_enabled: %d\n",
 		fabric->fabdev.id, fabric->pdata->nmasters,
 		fabric->pdata->nslaves, fabric->pdata->ntieredslaves,
 		fabric->pdata->rpm_enabled);
-	MSM_FAB_DBG("msm_bus_register_fabric_info i: %d\n", i);
+	MSM_BUS_DBG("msm_bus_register_fabric_info i: %d\n", i);
 	fabric->num_nodes = fabric->pdata->len;
 error:
 	fabric->num_nodes = i;
@@ -238,7 +238,7 @@
 			info->link_info.sel_clk = &info->link_info.clk[ctx];
 			max_pclk = max(max_pclk, *info->link_info.sel_clk);
 		}
-		MSM_FAB_DBG("max_pclk from gateways: %lu\n", max_pclk);
+		MSM_BUS_DBG("max_pclk from gateways: %lu\n", max_pclk);
 
 		/* Maximum of all slave clocks. */
 
@@ -255,7 +255,7 @@
 		}
 
 
-		MSM_FAB_DBG("max_pclk from slaves & gws: %lu\n", max_pclk);
+		MSM_BUS_DBG("max_pclk from slaves & gws: %lu\n", max_pclk);
 		fabric->info.link_info.sel_clk =
 			&fabric->info.link_info.clk[ctx];
 		pclk = fabric->info.link_info.sel_clk;
@@ -325,7 +325,7 @@
 
 	/* If it's an ahb fabric, don't calculate arb values */
 	if (fabric->ahb) {
-		MSM_FAB_DBG("AHB fabric, skipping bw calculation\n");
+		MSM_BUS_DBG("AHB fabric, skipping bw calculation\n");
 		return;
 	}
 	if (!add_bw) {
@@ -486,9 +486,9 @@
 	rpm_data[1].id = haltid + 1;
 	rpm_data[1].value = hvector.haltmask;
 
-	MSM_FAB_DBG("ctx: %d, id: %d, value: %d\n",
+	MSM_BUS_DBG("ctx: %d, id: %d, value: %d\n",
 		MSM_RPM_CTX_SET_0, rpm_data[0].id, rpm_data[0].value);
-	MSM_FAB_DBG("ctx: %d, id: %d, value: %d\n",
+	MSM_BUS_DBG("ctx: %d, id: %d, value: %d\n",
 		MSM_RPM_CTX_SET_0, rpm_data[1].id, rpm_data[1].value);
 
 	if (fabric->pdata->rpm_enabled)
@@ -529,9 +529,9 @@
 	rpm_data[1].id = haltid + 1;
 	rpm_data[1].value = hvector.haltmask;
 
-	MSM_FAB_DBG("unalt: ctx: %d, id: %d, value: %d\n",
+	MSM_BUS_DBG("unalt: ctx: %d, id: %d, value: %d\n",
 		MSM_RPM_CTX_SET_SLEEP, rpm_data[0].id, rpm_data[0].value);
-	MSM_FAB_DBG("unhalt: ctx: %d, id: %d, value: %d\n",
+	MSM_BUS_DBG("unhalt: ctx: %d, id: %d, value: %d\n",
 		MSM_RPM_CTX_SET_SLEEP, rpm_data[1].id, rpm_data[1].value);
 
 	if (fabric->pdata->rpm_enabled)
@@ -582,7 +582,7 @@
 	struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
 	info = radix_tree_lookup(&fabric->fab_tree, id);
 	if (!info)
-		MSM_FAB_DBG("Null info found for id %d\n", id);
+		MSM_BUS_ERR("Null info found for id %d\n", id);
 	return info;
 }
 
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c b/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c
index 84e2da5..a8dc7c8 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c
@@ -540,14 +540,14 @@
 
 	*cd = kzalloc(sizeof(struct commit_data), GFP_KERNEL);
 	if (!*cdata) {
-		MSM_FAB_DBG("Couldn't alloc mem for cdata\n");
+		MSM_BUS_DBG("Couldn't alloc mem for cdata\n");
 		goto cdata_err;
 	}
 
 	(*cd)->bwsum = kzalloc((sizeof(uint16_t) * fab_pdata->nslaves),
 			GFP_KERNEL);
 	if (!(*cd)->bwsum) {
-		MSM_FAB_DBG("Couldn't alloc mem for slaves\n");
+		MSM_BUS_DBG("Couldn't alloc mem for slaves\n");
 		goto bwsum_err;
 	}
 
@@ -556,7 +556,7 @@
 			(fab_pdata->ntieredslaves * fab_pdata->nmasters) + 1),
 			GFP_KERNEL);
 		if (!(*cd)->arb[i]) {
-			MSM_FAB_DBG("Couldn't alloc memory for"
+			MSM_BUS_DBG("Couldn't alloc memory for"
 				" slaves\n");
 			goto arb_err;
 		}
@@ -565,7 +565,7 @@
 			(fab_pdata->ntieredslaves * fab_pdata->nmasters) + 1),
 			GFP_KERNEL);
 		if (!(*cd)->actarb[i]) {
-			MSM_FAB_DBG("Couldn't alloc memory for"
+			MSM_BUS_DBG("Couldn't alloc memory for"
 					" slaves\n");
 			kfree((*cd)->arb[i]);
 			goto arb_err;
@@ -691,11 +691,11 @@
 
 	MSM_BUS_DBG("rpm data for fab: %d\n", fab_pdata->id);
 	for (i = 0; i < count; i++)
-		MSM_FAB_DBG("%d %x\n", rpm_data[i].id, rpm_data[i].value);
+		MSM_BUS_DBG("%d %x\n", rpm_data[i].id, rpm_data[i].value);
 
 	MSM_BUS_DBG("Commit Data: Fab: %d BWSum:\n", fab_pdata->id);
 	for (i = 0; i < fab_pdata->nslaves; i++)
-		MSM_FAB_DBG("fab_slaves:0x%x\n", cd->bwsum[i]);
+		MSM_BUS_DBG("fab_slaves:0x%x\n", cd->bwsum[i]);
 	MSM_BUS_DBG("Commit Data: Fab: %d Arb:\n", fab_pdata->id);
 	for (k = 0; k < NUM_TIERS; k++) {
 		MSM_BUS_DBG("Tier: %d\n", k);
@@ -708,7 +708,7 @@
 		}
 	}
 
-	MSM_FAB_DBG("calling msm_rpm_set:  %d\n", status);
+	MSM_BUS_DBG("calling msm_rpm_set:  %d\n", status);
 	msm_bus_dbg_commit_data(fab_pdata->name, (void *)cd, fab_pdata->
 		nmasters, fab_pdata->nslaves, fab_pdata->ntieredslaves,
 		MSM_BUS_DBG_OP);
diff --git a/arch/arm/mach-msm/msm_dsps.c b/arch/arm/mach-msm/msm_dsps.c
index 5419087..4e487a7f 100644
--- a/arch/arm/mach-msm/msm_dsps.c
+++ b/arch/arm/mach-msm/msm_dsps.c
@@ -103,7 +103,7 @@
 		pr_err("%s: fail to load DSPS firmware %s.\n", __func__, name);
 		return -ENODEV;
 	}
-
+	msleep(20);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/msm_rq_stats.c b/arch/arm/mach-msm/msm_rq_stats.c
index da7fb51..492612f 100644
--- a/arch/arm/mach-msm/msm_rq_stats.c
+++ b/arch/arm/mach-msm/msm_rq_stats.c
@@ -95,10 +95,7 @@
 static ssize_t show_def_timer_ms(struct kobject *kobj,
 		struct kobj_attribute *attr, char *buf)
 {
-	int64_t diff_ms;
-	diff_ms = ktime_to_ns(ktime_get()) - rq_info.def_start_time;
-	do_div(diff_ms, 1000 * 1000);
-	return snprintf(buf, MAX_LONG_SIZE, "%lld\n", diff_ms);
+	return snprintf(buf, MAX_LONG_SIZE, "%u\n", rq_info.def_interval);
 }
 
 static ssize_t store_def_timer_ms(struct kobject *kobj,
diff --git a/arch/arm/mach-msm/msm_watchdog.c b/arch/arm/mach-msm/msm_watchdog.c
index a1316b7..5877fbf 100644
--- a/arch/arm/mach-msm/msm_watchdog.c
+++ b/arch/arm/mach-msm/msm_watchdog.c
@@ -21,6 +21,7 @@
 #include <linux/mfd/pmic8058.h>
 #include <linux/jiffies.h>
 #include <linux/suspend.h>
+#include <linux/percpu.h>
 #include <linux/interrupt.h>
 #include <mach/msm_iomap.h>
 #include <asm/mach-types.h>
@@ -35,6 +36,7 @@
 
 #define WDT0_RST	0x38
 #define WDT0_EN		0x40
+#define WDT0_STS	0x44
 #define WDT0_BARK_TIME	0x4C
 #define WDT0_BITE_TIME	0x5C
 
@@ -86,6 +88,8 @@
 /* Area for context dump in secure mode */
 static void *scm_regsave;
 
+static struct msm_watchdog_pdata __percpu **percpu_pdata;
+
 static void pet_watchdog_work(struct work_struct *work);
 static void init_watchdog_work(struct work_struct *work);
 static DECLARE_DELAYED_WORK(dogwork_struct, pet_watchdog_work);
@@ -157,7 +161,9 @@
 		if (!old_val) {
 			__raw_writel(0, msm_tmr0_base + WDT0_EN);
 			mb();
-			free_irq(WDT0_ACCSCSSNBARK_INT, 0);
+			disable_percpu_irq(WDT0_ACCSCSSNBARK_INT);
+			free_percpu_irq(WDT0_ACCSCSSNBARK_INT, percpu_pdata);
+			free_percpu(percpu_pdata);
 			enable = 0;
 			atomic_notifier_chain_unregister(&panic_notifier_list,
 			       &panic_blk);
@@ -180,10 +186,26 @@
 	return ret;
 }
 
+unsigned min_slack_ticks = UINT_MAX;
+unsigned long long min_slack_ns = ULLONG_MAX;
+
 void pet_watchdog(void)
 {
+	int slack;
+	unsigned long long time_ns;
+	unsigned long long slack_ns;
+	unsigned long long bark_time_ns = bark_time * 1000000ULL;
+
+	slack = __raw_readl(msm_tmr0_base + WDT0_STS) >> 3;
+	slack = ((bark_time*WDT_HZ)/1000) - slack;
+	if (slack < min_slack_ticks)
+		min_slack_ticks = slack;
 	__raw_writel(1, msm_tmr0_base + WDT0_RST);
-	last_pet = sched_clock();
+	time_ns = sched_clock();
+	slack_ns = (last_pet + bark_time_ns) - time_ns;
+	if (slack_ns < min_slack_ns)
+		min_slack_ns = slack_ns;
+	last_pet = time_ns;
 }
 
 static void pet_watchdog_work(struct work_struct *work)
@@ -199,7 +221,9 @@
 	if (enable) {
 		__raw_writel(0, msm_tmr0_base + WDT0_EN);
 		mb();
-		free_irq(WDT0_ACCSCSSNBARK_INT, 0);
+		disable_percpu_irq(WDT0_ACCSCSSNBARK_INT);
+		free_percpu_irq(WDT0_ACCSCSSNBARK_INT, percpu_pdata);
+		free_percpu(percpu_pdata);
 		enable = 0;
 		/* In case we got suspended mid-exit */
 		__raw_writel(0, msm_tmr0_base + WDT0_EN);
@@ -314,11 +338,23 @@
 
 	msm_tmr0_base = msm_timer_get_timer0_base();
 
+	percpu_pdata = alloc_percpu(struct msm_watchdog_pdata *);
+	if (!percpu_pdata) {
+		pr_err("%s: memory allocation failed for percpu data\n",
+				__func__);
+		return -ENOMEM;
+	}
+
+	*__this_cpu_ptr(percpu_pdata) = pdata;
 	/* Must request irq before sending scm command */
-	ret = request_irq(WDT0_ACCSCSSNBARK_INT, wdog_bark_handler, 0,
-			  "apps_wdog_bark", NULL);
-	if (ret)
-		return -EINVAL;
+	ret = request_percpu_irq(WDT0_ACCSCSSNBARK_INT, wdog_bark_handler,
+			  "apps_wdog_bark", percpu_pdata);
+	if (ret) {
+		free_percpu(percpu_pdata);
+		return ret;
+	}
+
+	enable_percpu_irq(WDT0_ACCSCSSNBARK_INT, 0);
 
 	/*
 	 * This is only temporary till SBLs turn on the XPUs
diff --git a/arch/arm/mach-msm/msm_xo.c b/arch/arm/mach-msm/msm_xo.c
index 29cb1a8..802ee2a 100644
--- a/arch/arm/mach-msm/msm_xo.c
+++ b/arch/arm/mach-msm/msm_xo.c
@@ -83,6 +83,7 @@
 	msm_xo_dump_xo(m, &msm_xo_sources[MSM_XO_TCXO_A2], "TCXO A2");
 	msm_xo_dump_xo(m, &msm_xo_sources[MSM_XO_CORE], "TCXO Core");
 	msm_xo_dump_xo(m, &msm_xo_sources[MSM_XO_PXO], "PXO during sleep");
+	msm_xo_dump_xo(m, &msm_xo_sources[MSM_XO_CXO], "CXO");
 	spin_unlock_irqrestore(&msm_xo_lock, flags);
 
 	return 0;
@@ -137,6 +138,10 @@
 		cmd.id = MSM_RPM_ID_PXO_CLK;
 		cmd.value = msm_xo_sources[MSM_XO_PXO].mode ? 1 : 0;
 		ret = msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_SLEEP, &cmd, 1);
+	} else if (xo == &msm_xo_sources[MSM_XO_CXO]) {
+		cmd.id = MSM_RPM_ID_CXO_CLK;
+		cmd.value = msm_xo_sources[MSM_XO_CXO].mode ? 1 : 0;
+		ret = msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_0, &cmd, 1);
 	} else {
 		cmd.id = MSM_RPM_ID_CXO_BUFFERS;
 		cmd.value = (msm_xo_sources[MSM_XO_TCXO_D0].mode << 0)  |
@@ -223,10 +228,10 @@
 
 	/*
 	 * TODO: Remove early return for 8064 once RPM XO voting support
-	 * is available. Remove early return for 8960 TCXO_D0 once all
-	 * voters for it are in place.
+	 * is available. Remove early return for 8960 CXO once all voters
+	 * for it are in place.
 	 */
-	if (cpu_is_apq8064() || (cpu_is_msm8960() && xo_id == MSM_XO_TCXO_D0))
+	if (cpu_is_apq8064() || (cpu_is_msm8960() && xo_id == MSM_XO_CXO))
 		return NULL;
 
 	if (xo_id >= NUM_MSM_XO_IDS) {
diff --git a/arch/arm/mach-msm/no-pm.c b/arch/arm/mach-msm/no-pm.c
index d6cdbe7..366b282 100644
--- a/arch/arm/mach-msm/no-pm.c
+++ b/arch/arm/mach-msm/no-pm.c
@@ -23,5 +23,13 @@
 void msm_pm_set_platform_data(struct msm_pm_platform_data *data, int count)
 { }
 
+void msm_pm_cpu_enter_lowpower(unsigned cpu)
+{
+	asm("wfi"
+		:
+		:
+		: "memory", "cc");
+}
+
 void msm_pm_set_max_sleep_time(int64_t max_sleep_time_ns) { }
 EXPORT_SYMBOL(msm_pm_set_max_sleep_time);
diff --git a/arch/arm/mach-msm/peripheral-reset-8960.c b/arch/arm/mach-msm/peripheral-reset-8960.c
index fa22e4e..6fd8464 100644
--- a/arch/arm/mach-msm/peripheral-reset-8960.c
+++ b/arch/arm/mach-msm/peripheral-reset-8960.c
@@ -17,7 +17,6 @@
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/regulator/consumer.h>
 #include <linux/platform_device.h>
 
 #include <asm/mach-types.h>
@@ -28,195 +27,15 @@
 #include "peripheral-loader.h"
 #include "scm-pas.h"
 
-#define MSM_RIVA_PHYS			0x03204000
-#define RIVA_PMU_A2XB_CFG		(msm_riva_base + 0xB8)
-#define RIVA_PMU_A2XB_CFG_EN		BIT(0)
-
-#define RIVA_PMU_CFG			(msm_riva_base + 0x28)
-#define RIVA_PMU_CFG_WARM_BOOT		BIT(0)
-#define RIVA_PMU_CFG_IRIS_XO_MODE	0x6
-#define RIVA_PMU_CFG_IRIS_XO_MODE_48	(3 << 1)
-
-#define RIVA_PMU_OVRD_VAL		(msm_riva_base + 0x30)
-#define RIVA_PMU_OVRD_VAL_CCPU_RESET	BIT(0)
-#define RIVA_PMU_OVRD_VAL_CCPU_CLK	BIT(1)
-
-#define RIVA_PMU_CCPU_CTL		(msm_riva_base + 0x9C)
-#define RIVA_PMU_CCPU_CTL_HIGH_IVT	BIT(0)
-#define RIVA_PMU_CCPU_CTL_REMAP_EN	BIT(2)
-
-#define RIVA_PMU_CCPU_BOOT_REMAP_ADDR	(msm_riva_base + 0xA0)
-
-#define RIVA_PLL_MODE			(MSM_CLK_CTL_BASE + 0x31A0)
-#define PLL_MODE_OUTCTRL		BIT(0)
-#define PLL_MODE_BYPASSNL		BIT(1)
-#define PLL_MODE_RESET_N		BIT(2)
-#define PLL_MODE_REF_XO_SEL		0x30
-#define PLL_MODE_REF_XO_SEL_CXO		(2 << 4)
-#define PLL_MODE_REF_XO_SEL_RF		(3 << 4)
-#define RIVA_PLL_L_VAL			(MSM_CLK_CTL_BASE + 0x31A4)
-#define RIVA_PLL_M_VAL			(MSM_CLK_CTL_BASE + 0x31A8)
-#define RIVA_PLL_N_VAL			(MSM_CLK_CTL_BASE + 0x31Ac)
-#define RIVA_PLL_CONFIG			(MSM_CLK_CTL_BASE + 0x31B4)
-#define RIVA_PLL_STATUS			(MSM_CLK_CTL_BASE + 0x31B8)
-
-#define RIVA_PMU_ROOT_CLK_SEL		(msm_riva_base + 0xC8)
-#define RIVA_PMU_ROOT_CLK_SEL_3		BIT(2)
-
-#define RIVA_PMU_CLK_ROOT3			(msm_riva_base + 0x78)
-#define RIVA_PMU_CLK_ROOT3_ENA			BIT(0)
-#define RIVA_PMU_CLK_ROOT3_SRC0_DIV		0x3C
-#define RIVA_PMU_CLK_ROOT3_SRC0_DIV_2		(1 << 2)
-#define RIVA_PMU_CLK_ROOT3_SRC0_SEL		0x1C0
-#define RIVA_PMU_CLK_ROOT3_SRC0_SEL_RIVA	(1 << 6)
-#define RIVA_PMU_CLK_ROOT3_SRC1_DIV		0x1E00
-#define RIVA_PMU_CLK_ROOT3_SRC1_DIV_2		(1 << 9)
-#define RIVA_PMU_CLK_ROOT3_SRC1_SEL		0xE000
-#define RIVA_PMU_CLK_ROOT3_SRC1_SEL_RIVA	(1 << 13)
-
 #define PPSS_RESET			(MSM_CLK_CTL_BASE + 0x2594)
 #define PPSS_PROC_CLK_CTL		(MSM_CLK_CTL_BASE + 0x2588)
 #define PPSS_HCLK_CTL			(MSM_CLK_CTL_BASE + 0x2580)
 
-static void __iomem *msm_riva_base;
-static unsigned long riva_start;
-
 static int verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
 {
 	return 0;
 }
 
-static int init_image_riva_untrusted(struct pil_desc *pil, const u8 *metadata,
-				     size_t size)
-{
-	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
-	riva_start = ehdr->e_entry;
-	return 0;
-}
-
-static int reset_riva_untrusted(struct pil_desc *pil)
-{
-	u32 reg;
-	bool xo;
-
-	/* Enable A2XB bridge */
-	reg = readl_relaxed(RIVA_PMU_A2XB_CFG);
-	reg |= RIVA_PMU_A2XB_CFG_EN;
-	writel_relaxed(reg, RIVA_PMU_A2XB_CFG);
-
-	/* Determine which XO to use */
-	reg = readl_relaxed(RIVA_PMU_CFG);
-	xo = (reg & RIVA_PMU_CFG_IRIS_XO_MODE) == RIVA_PMU_CFG_IRIS_XO_MODE_48;
-
-	/* Program PLL 13 to 960 MHz */
-	reg = readl_relaxed(RIVA_PLL_MODE);
-	reg &= ~(PLL_MODE_BYPASSNL | PLL_MODE_OUTCTRL | PLL_MODE_RESET_N);
-	writel_relaxed(reg, RIVA_PLL_MODE);
-
-	if (xo)
-		writel_relaxed(0x40000C00 | 40, RIVA_PLL_L_VAL);
-	else
-		writel_relaxed(0x40000C00 | 50, RIVA_PLL_L_VAL);
-	writel_relaxed(0, RIVA_PLL_M_VAL);
-	writel_relaxed(1, RIVA_PLL_N_VAL);
-	writel_relaxed(0x01495227, RIVA_PLL_CONFIG);
-
-	reg = readl_relaxed(RIVA_PLL_MODE);
-	reg &= ~(PLL_MODE_REF_XO_SEL);
-	reg |= xo ? PLL_MODE_REF_XO_SEL_RF : PLL_MODE_REF_XO_SEL_CXO;
-	writel_relaxed(reg, RIVA_PLL_MODE);
-
-	/* Enable PLL 13 */
-	reg |= PLL_MODE_BYPASSNL;
-	writel_relaxed(reg, RIVA_PLL_MODE);
-
-	/*
-	 * H/W requires a 5us delay between disabling the bypass and
-	 * de-asserting the reset. Delay 10us just to be safe.
-	 */
-	mb();
-	usleep_range(10, 20);
-
-	reg |= PLL_MODE_RESET_N;
-	writel_relaxed(reg, RIVA_PLL_MODE);
-	reg |= PLL_MODE_OUTCTRL;
-	writel_relaxed(reg, RIVA_PLL_MODE);
-
-	/* Wait for PLL to settle */
-	mb();
-	usleep_range(50, 100);
-
-	/* Configure cCPU for 240 MHz */
-	reg = readl_relaxed(RIVA_PMU_CLK_ROOT3);
-	if (readl_relaxed(RIVA_PMU_ROOT_CLK_SEL) & RIVA_PMU_ROOT_CLK_SEL_3) {
-		reg &= ~(RIVA_PMU_CLK_ROOT3_SRC0_SEL |
-			 RIVA_PMU_CLK_ROOT3_SRC0_DIV);
-		reg |= RIVA_PMU_CLK_ROOT3_SRC0_SEL_RIVA |
-		       RIVA_PMU_CLK_ROOT3_SRC0_DIV_2;
-	} else {
-		reg &= ~(RIVA_PMU_CLK_ROOT3_SRC1_SEL |
-			 RIVA_PMU_CLK_ROOT3_SRC1_DIV);
-		reg |= RIVA_PMU_CLK_ROOT3_SRC1_SEL_RIVA |
-		       RIVA_PMU_CLK_ROOT3_SRC1_DIV_2;
-	}
-	writel_relaxed(reg, RIVA_PMU_CLK_ROOT3);
-	reg |= RIVA_PMU_CLK_ROOT3_ENA;
-	writel_relaxed(reg, RIVA_PMU_CLK_ROOT3);
-	reg = readl_relaxed(RIVA_PMU_ROOT_CLK_SEL);
-	reg ^= RIVA_PMU_ROOT_CLK_SEL_3;
-	writel_relaxed(reg, RIVA_PMU_ROOT_CLK_SEL);
-
-	/* Use the high vector table */
-	reg = readl_relaxed(RIVA_PMU_CCPU_CTL);
-	reg |= RIVA_PMU_CCPU_CTL_HIGH_IVT | RIVA_PMU_CCPU_CTL_REMAP_EN;
-	writel_relaxed(reg, RIVA_PMU_CCPU_CTL);
-
-	/* Set base memory address */
-	writel_relaxed(riva_start >> 16, RIVA_PMU_CCPU_BOOT_REMAP_ADDR);
-
-	/* Clear warmboot bit indicating this is a cold boot */
-	reg = readl_relaxed(RIVA_PMU_CFG);
-	reg &= ~(RIVA_PMU_CFG_WARM_BOOT);
-	writel_relaxed(reg, RIVA_PMU_CFG);
-
-	/* Enable the cCPU clock */
-	reg = readl_relaxed(RIVA_PMU_OVRD_VAL);
-	reg |= RIVA_PMU_OVRD_VAL_CCPU_CLK;
-	writel_relaxed(reg, RIVA_PMU_OVRD_VAL);
-
-	/* Take cCPU out of reset */
-	reg |= RIVA_PMU_OVRD_VAL_CCPU_RESET;
-	writel_relaxed(reg, RIVA_PMU_OVRD_VAL);
-
-	return 0;
-}
-
-static int shutdown_riva_untrusted(struct pil_desc *pil)
-{
-	u32 reg;
-	/* Put riva into reset */
-	reg = readl_relaxed(RIVA_PMU_OVRD_VAL);
-	reg &= ~(RIVA_PMU_OVRD_VAL_CCPU_RESET | RIVA_PMU_OVRD_VAL_CCPU_CLK);
-	writel_relaxed(reg, RIVA_PMU_OVRD_VAL);
-	return 0;
-}
-
-static int init_image_riva_trusted(struct pil_desc *pil, const u8 *metadata,
-				   size_t size)
-{
-	return pas_init_image(PAS_RIVA, metadata, size);
-}
-
-static int reset_riva_trusted(struct pil_desc *pil)
-{
-	return pas_auth_and_reset(PAS_RIVA);
-}
-
-static int shutdown_riva_trusted(struct pil_desc *pil)
-{
-	return pas_shutdown(PAS_RIVA);
-}
-
 static int init_image_dsps_untrusted(struct pil_desc *pil, const u8 *metadata,
 				     size_t size)
 {
@@ -236,7 +55,7 @@
 
 static int shutdown_dsps_untrusted(struct pil_desc *pil)
 {
-	writel_relaxed(0x2, PPSS_RESET);
+	writel_relaxed(0x3, PPSS_RESET);
 	writel_relaxed(0x0, PPSS_PROC_CLK_CTL);
 	return 0;
 }
@@ -257,29 +76,6 @@
 	return pas_shutdown(PAS_DSPS);
 }
 
-static int init_image_tzapps(struct pil_desc *pil, const u8 *metadata,
-			     size_t size)
-{
-	return pas_init_image(PAS_TZAPPS, metadata, size);
-}
-
-static int reset_tzapps(struct pil_desc *pil)
-{
-	return pas_auth_and_reset(PAS_TZAPPS);
-}
-
-static int shutdown_tzapps(struct pil_desc *pil)
-{
-	return pas_shutdown(PAS_TZAPPS);
-}
-
-static struct pil_reset_ops pil_riva_ops = {
-	.init_image = init_image_riva_untrusted,
-	.verify_blob = verify_blob,
-	.auth_and_reset = reset_riva_untrusted,
-	.shutdown = shutdown_riva_untrusted,
-};
-
 struct pil_reset_ops pil_dsps_ops = {
 	.init_image = init_image_dsps_untrusted,
 	.verify_blob = verify_blob,
@@ -287,23 +83,6 @@
 	.shutdown = shutdown_dsps_untrusted,
 };
 
-struct pil_reset_ops pil_tzapps_ops = {
-	.init_image = init_image_tzapps,
-	.verify_blob = verify_blob,
-	.auth_and_reset = reset_tzapps,
-	.shutdown = shutdown_tzapps,
-};
-
-static struct platform_device pil_riva = {
-	.name = "pil_riva",
-};
-
-static struct pil_desc pil_riva_desc = {
-	.name = "wcnss",
-	.dev = &pil_riva.dev,
-	.ops = &pil_riva_ops,
-};
-
 static struct platform_device pil_dsps = {
 	.name = "pil_dsps",
 };
@@ -314,16 +93,6 @@
 	.ops = &pil_dsps_ops,
 };
 
-static struct platform_device pil_tzapps = {
-	.name = "pil_tzapps",
-};
-
-static struct pil_desc pil_tzapps_desc = {
-	.name = "tzapps",
-	.dev = &pil_tzapps.dev,
-	.ops = &pil_tzapps_ops,
-};
-
 static void __init use_secure_pil(void)
 {
 	if (pas_supported(PAS_DSPS) > 0) {
@@ -331,12 +100,6 @@
 		pil_dsps_ops.auth_and_reset = reset_dsps_trusted;
 		pil_dsps_ops.shutdown = shutdown_dsps_trusted;
 	}
-
-	if (pas_supported(PAS_RIVA) > 0) {
-		pil_riva_ops.init_image = init_image_riva_trusted;
-		pil_riva_ops.auth_and_reset = reset_riva_trusted;
-		pil_riva_ops.shutdown = shutdown_riva_trusted;
-	}
 }
 
 static int __init msm_peripheral_reset_init(void)
@@ -352,14 +115,6 @@
 
 	BUG_ON(platform_device_register(&pil_dsps));
 	BUG_ON(msm_pil_register(&pil_dsps_desc));
-	BUG_ON(platform_device_register(&pil_tzapps));
-	BUG_ON(msm_pil_register(&pil_tzapps_desc));
-
-	msm_riva_base = ioremap(MSM_RIVA_PHYS, SZ_256);
-	if (!msm_riva_base)
-		return -ENOMEM;
-	BUG_ON(platform_device_register(&pil_riva));
-	BUG_ON(msm_pil_register(&pil_riva_desc));
 
 	return 0;
 }
diff --git a/arch/arm/mach-msm/peripheral-reset.c b/arch/arm/mach-msm/peripheral-reset.c
index 2d60a7e..88b07a5 100644
--- a/arch/arm/mach-msm/peripheral-reset.c
+++ b/arch/arm/mach-msm/peripheral-reset.c
@@ -26,57 +26,15 @@
 
 #include <mach/scm.h>
 #include <mach/msm_iomap.h>
-#include <mach/msm_xo.h>
 
 #include "peripheral-loader.h"
 #include "scm-pas.h"
 
-#define PROXY_VOTE_TIMEOUT		10000
-
-#define MSM_MMS_REGS_BASE		0x10200000
-
-#define MARM_RESET			(MSM_CLK_CTL_BASE + 0x2BD4)
-#define MARM_BOOT_CONTROL		(msm_mms_regs_base + 0x0010)
-#define MAHB0_SFAB_PORT_RESET		(MSM_CLK_CTL_BASE + 0x2304)
-#define MARM_CLK_BRANCH_ENA_VOTE	(MSM_CLK_CTL_BASE + 0x3000)
-#define MARM_CLK_SRC0_NS		(MSM_CLK_CTL_BASE + 0x2BC0)
-#define MARM_CLK_SRC1_NS		(MSM_CLK_CTL_BASE + 0x2BC4)
-#define MARM_CLK_SRC_CTL		(MSM_CLK_CTL_BASE + 0x2BC8)
-#define MARM_CLK_CTL			(MSM_CLK_CTL_BASE + 0x2BCC)
-#define SFAB_MSS_S_HCLK_CTL		(MSM_CLK_CTL_BASE + 0x2C00)
-#define MSS_MODEM_CXO_CLK_CTL		(MSM_CLK_CTL_BASE + 0x2C44)
-#define MSS_SLP_CLK_CTL			(MSM_CLK_CTL_BASE + 0x2C60)
-#define MSS_MARM_SYS_REF_CLK_CTL	(MSM_CLK_CTL_BASE + 0x2C64)
-#define MAHB0_CLK_CTL			(MSM_CLK_CTL_BASE + 0x2300)
-#define MAHB1_CLK_CTL			(MSM_CLK_CTL_BASE + 0x2BE4)
-#define MAHB2_CLK_CTL			(MSM_CLK_CTL_BASE + 0x2C20)
-#define MAHB1_NS			(MSM_CLK_CTL_BASE + 0x2BE0)
-#define MARM_CLK_FS			(MSM_CLK_CTL_BASE + 0x2BD0)
-#define MAHB2_CLK_FS			(MSM_CLK_CTL_BASE + 0x2C24)
-#define PLL_ENA_MARM			(MSM_CLK_CTL_BASE + 0x3500)
-#define PLL8_STATUS			(MSM_CLK_CTL_BASE + 0x3158)
-#define CLK_HALT_MSS_SMPSS_MISC_STATE	(MSM_CLK_CTL_BASE + 0x2FDC)
-
 #define PPSS_RESET			(MSM_CLK_CTL_BASE + 0x2594)
 #define PPSS_PROC_CLK_CTL		(MSM_CLK_CTL_BASE + 0x2588)
 #define CLK_HALT_DFAB_STATE		(MSM_CLK_CTL_BASE + 0x2FC8)
 
-static int modem_start, dsps_start;
-static void __iomem *msm_mms_regs_base;
-
-static int init_image_modem_trusted(struct pil_desc *pil, const u8 *metadata,
-				    size_t size)
-{
-	return pas_init_image(PAS_MODEM, metadata, size);
-}
-
-static int init_image_modem_untrusted(struct pil_desc *pil,
-				      const u8 *metadata, size_t size)
-{
-	struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
-	modem_start = ehdr->e_entry;
-	return 0;
-}
+static int dsps_start;
 
 static int init_image_dsps_trusted(struct pil_desc *pil, const u8 *metadata,
 				   size_t size)
@@ -100,176 +58,6 @@
 	return 0;
 }
 
-static struct msm_xo_voter *pxo;
-static void remove_modem_proxy_votes(unsigned long data)
-{
-	msm_xo_mode_vote(pxo, MSM_XO_MODE_OFF);
-}
-static DEFINE_TIMER(modem_timer, remove_modem_proxy_votes, 0, 0);
-
-static void make_modem_proxy_votes(void)
-{
-	/* Make proxy votes for modem and set up timer to disable it. */
-	msm_xo_mode_vote(pxo, MSM_XO_MODE_ON);
-	mod_timer(&modem_timer, jiffies + msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
-}
-
-static void remove_modem_proxy_votes_now(void)
-{
-	/*
-	 * If the modem proxy vote hasn't been removed yet, them remove the
-	 * votes immediately.
-	 */
-	if (del_timer(&modem_timer))
-		remove_modem_proxy_votes(0);
-}
-
-static int reset_modem_untrusted(struct pil_desc *pil)
-{
-	u32 reg;
-
-	make_modem_proxy_votes();
-
-	/* Put modem AHB0,1,2 clocks into reset */
-	__raw_writel(BIT(0) | BIT(1), MAHB0_SFAB_PORT_RESET);
-	__raw_writel(BIT(7), MAHB1_CLK_CTL);
-	__raw_writel(BIT(7), MAHB2_CLK_CTL);
-
-	/* Vote for pll8 on behalf of the modem */
-	reg = __raw_readl(PLL_ENA_MARM);
-	reg |= BIT(8);
-	__raw_writel(reg, PLL_ENA_MARM);
-
-	/* Wait for PLL8 to enable */
-	while (!(__raw_readl(PLL8_STATUS) & BIT(16)))
-		cpu_relax();
-
-	/* Set MAHB1 divider to Div-5 to run MAHB1,2 and sfab at 79.8 Mhz*/
-	__raw_writel(0x4, MAHB1_NS);
-
-	/* Vote for modem AHB1 and 2 clocks to be on on behalf of the modem */
-	reg = __raw_readl(MARM_CLK_BRANCH_ENA_VOTE);
-	reg |= BIT(0) | BIT(1);
-	__raw_writel(reg, MARM_CLK_BRANCH_ENA_VOTE);
-
-	/* Source marm_clk off of PLL8 */
-	reg = __raw_readl(MARM_CLK_SRC_CTL);
-	if ((reg & 0x1) == 0) {
-		__raw_writel(0x3, MARM_CLK_SRC1_NS);
-		reg |= 0x1;
-	} else {
-		__raw_writel(0x3, MARM_CLK_SRC0_NS);
-		reg &= ~0x1;
-	}
-	__raw_writel(reg | 0x2, MARM_CLK_SRC_CTL);
-
-	/*
-	 * Force core on and periph on signals to remain active during halt
-	 * for marm_clk and mahb2_clk
-	 */
-	__raw_writel(0x6F, MARM_CLK_FS);
-	__raw_writel(0x6F, MAHB2_CLK_FS);
-
-	/*
-	 * Enable all of the marm_clk branches, cxo sourced marm branches,
-	 * and sleep clock branches
-	 */
-	__raw_writel(0x10, MARM_CLK_CTL);
-	__raw_writel(0x10, MAHB0_CLK_CTL);
-	__raw_writel(0x10, SFAB_MSS_S_HCLK_CTL);
-	__raw_writel(0x10, MSS_MODEM_CXO_CLK_CTL);
-	__raw_writel(0x10, MSS_SLP_CLK_CTL);
-	__raw_writel(0x10, MSS_MARM_SYS_REF_CLK_CTL);
-
-	/* Wait for above clocks to be turned on */
-	while (__raw_readl(CLK_HALT_MSS_SMPSS_MISC_STATE) & (BIT(7) | BIT(8) |
-				BIT(9) | BIT(10) | BIT(4) | BIT(6)))
-		cpu_relax();
-
-	/* Take MAHB0,1,2 clocks out of reset */
-	__raw_writel(0x0, MAHB2_CLK_CTL);
-	__raw_writel(0x0, MAHB1_CLK_CTL);
-	__raw_writel(0x0, MAHB0_SFAB_PORT_RESET);
-
-	/* Setup exception vector table base address */
-	__raw_writel(modem_start | 0x1, MARM_BOOT_CONTROL);
-
-	/* Wait for vector table to be setup */
-	mb();
-
-	/* Bring modem out of reset */
-	__raw_writel(0x0, MARM_RESET);
-
-	return 0;
-}
-
-static int reset_modem_trusted(struct pil_desc *pil)
-{
-	int ret;
-
-	make_modem_proxy_votes();
-
-	ret = pas_auth_and_reset(PAS_MODEM);
-	if (ret)
-		remove_modem_proxy_votes_now();
-
-	return ret;
-}
-
-static int shutdown_modem_untrusted(struct pil_desc *pil)
-{
-	u32 reg;
-
-	/* Put modem into reset */
-	__raw_writel(0x1, MARM_RESET);
-	mb();
-
-	/* Put modem AHB0,1,2 clocks into reset */
-	__raw_writel(BIT(0) | BIT(1), MAHB0_SFAB_PORT_RESET);
-	__raw_writel(BIT(7), MAHB1_CLK_CTL);
-	__raw_writel(BIT(7), MAHB2_CLK_CTL);
-	mb();
-
-	/*
-	 * Disable all of the marm_clk branches, cxo sourced marm branches,
-	 * and sleep clock branches
-	 */
-	__raw_writel(0x0, MARM_CLK_CTL);
-	__raw_writel(0x0, MAHB0_CLK_CTL);
-	__raw_writel(0x0, SFAB_MSS_S_HCLK_CTL);
-	__raw_writel(0x0, MSS_MODEM_CXO_CLK_CTL);
-	__raw_writel(0x0, MSS_SLP_CLK_CTL);
-	__raw_writel(0x0, MSS_MARM_SYS_REF_CLK_CTL);
-
-	/* Disable marm_clk */
-	reg = __raw_readl(MARM_CLK_SRC_CTL);
-	reg &= ~0x2;
-	__raw_writel(reg, MARM_CLK_SRC_CTL);
-
-	/* Clear modem's votes for ahb clocks */
-	__raw_writel(0x0, MARM_CLK_BRANCH_ENA_VOTE);
-
-	/* Clear modem's votes for PLLs */
-	__raw_writel(0x0, PLL_ENA_MARM);
-
-	remove_modem_proxy_votes_now();
-
-	return 0;
-}
-
-static int shutdown_modem_trusted(struct pil_desc *pil)
-{
-	int ret;
-
-	ret = pas_shutdown(PAS_MODEM);
-	if (ret)
-		return ret;
-
-	remove_modem_proxy_votes_now();
-
-	return 0;
-}
-
 static int reset_dsps_untrusted(struct pil_desc *pil)
 {
 	__raw_writel(0x10, PPSS_PROC_CLK_CTL);
@@ -293,34 +81,11 @@
 
 static int shutdown_dsps_untrusted(struct pil_desc *pil)
 {
-	__raw_writel(0x2, PPSS_RESET);
+	__raw_writel(0x3, PPSS_RESET);
 	__raw_writel(0x0, PPSS_PROC_CLK_CTL);
 	return 0;
 }
 
-static int init_image_playready(struct pil_desc *pil, const u8 *metadata,
-		size_t size)
-{
-	return pas_init_image(PAS_PLAYREADY, metadata, size);
-}
-
-static int reset_playready(struct pil_desc *pil)
-{
-	return pas_auth_and_reset(PAS_PLAYREADY);
-}
-
-static int shutdown_playready(struct pil_desc *pil)
-{
-	return pas_shutdown(PAS_PLAYREADY);
-}
-
-struct pil_reset_ops pil_modem_ops = {
-	.init_image = init_image_modem_untrusted,
-	.verify_blob = verify_blob,
-	.auth_and_reset = reset_modem_untrusted,
-	.shutdown = shutdown_modem_untrusted,
-};
-
 struct pil_reset_ops pil_dsps_ops = {
 	.init_image = init_image_dsps_untrusted,
 	.verify_blob = verify_blob,
@@ -328,34 +93,6 @@
 	.shutdown = shutdown_dsps_untrusted,
 };
 
-struct pil_reset_ops pil_playready_ops = {
-	.init_image = init_image_playready,
-	.verify_blob = verify_blob,
-	.auth_and_reset = reset_playready,
-	.shutdown = shutdown_playready,
-};
-
-static struct platform_device pil_modem = {
-	.name = "pil_modem",
-};
-
-static struct pil_desc pil_modem_desc = {
-	.name = "modem",
-	.depends_on = "q6",
-	.dev = &pil_modem.dev,
-	.ops = &pil_modem_ops,
-};
-
-static struct platform_device pil_playready = {
-	.name = "pil_playready",
-};
-
-static struct pil_desc pil_playready_desc = {
-	.name = "tzapps",
-	.dev = &pil_playready.dev,
-	.ops = &pil_playready_ops,
-};
-
 static struct platform_device pil_dsps = {
 	.name = "pil_dsps",
 };
@@ -368,51 +105,21 @@
 
 static int __init msm_peripheral_reset_init(void)
 {
-	msm_mms_regs_base = ioremap(MSM_MMS_REGS_BASE, SZ_256);
-	if (!msm_mms_regs_base)
-		goto err;
-
-	pxo = msm_xo_get(MSM_XO_PXO, "pil");
-	if (IS_ERR(pxo))
-		goto err_pxo;
-
-	if (pas_supported(PAS_MODEM) > 0) {
-		pil_modem_ops.init_image = init_image_modem_trusted;
-		pil_modem_ops.auth_and_reset = reset_modem_trusted;
-		pil_modem_ops.shutdown = shutdown_modem_trusted;
-	}
-
 	if (pas_supported(PAS_DSPS) > 0) {
 		pil_dsps_ops.init_image = init_image_dsps_trusted;
 		pil_dsps_ops.auth_and_reset = reset_dsps_trusted;
 		pil_dsps_ops.shutdown = shutdown_dsps_trusted;
 	}
 
-	BUG_ON(platform_device_register(&pil_modem));
-	BUG_ON(msm_pil_register(&pil_modem_desc));
-	BUG_ON(platform_device_register(&pil_playready));
-	BUG_ON(msm_pil_register(&pil_playready_desc));
-
 	if (machine_is_msm8x60_fluid())
 		pil_dsps_desc.name = "dsps_fluid";
 	BUG_ON(platform_device_register(&pil_dsps));
 	BUG_ON(msm_pil_register(&pil_dsps_desc));
 
 	return 0;
-
-err_pxo:
-	iounmap(msm_mms_regs_base);
-err:
-	return -ENOMEM;
-}
-
-static void __exit msm_peripheral_reset_exit(void)
-{
-	iounmap(msm_mms_regs_base);
 }
 
 arch_initcall(msm_peripheral_reset_init);
-module_exit(msm_peripheral_reset_exit);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Validate and bring peripherals out of reset");
diff --git a/arch/arm/mach-msm/pil-modem.c b/arch/arm/mach-msm/pil-modem.c
new file mode 100644
index 0000000..5aa38345
--- /dev/null
+++ b/arch/arm/mach-msm/pil-modem.c
@@ -0,0 +1,344 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. 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 version 2 and
+ * only 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/elf.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+
+#include <mach/msm_iomap.h>
+#include <mach/msm_xo.h>
+
+#include "peripheral-loader.h"
+#include "scm-pas.h"
+
+#define MARM_BOOT_CONTROL		0x0010
+#define MARM_RESET			(MSM_CLK_CTL_BASE + 0x2BD4)
+#define MAHB0_SFAB_PORT_RESET		(MSM_CLK_CTL_BASE + 0x2304)
+#define MARM_CLK_BRANCH_ENA_VOTE	(MSM_CLK_CTL_BASE + 0x3000)
+#define MARM_CLK_SRC0_NS		(MSM_CLK_CTL_BASE + 0x2BC0)
+#define MARM_CLK_SRC1_NS		(MSM_CLK_CTL_BASE + 0x2BC4)
+#define MARM_CLK_SRC_CTL		(MSM_CLK_CTL_BASE + 0x2BC8)
+#define MARM_CLK_CTL			(MSM_CLK_CTL_BASE + 0x2BCC)
+#define SFAB_MSS_S_HCLK_CTL		(MSM_CLK_CTL_BASE + 0x2C00)
+#define MSS_MODEM_CXO_CLK_CTL		(MSM_CLK_CTL_BASE + 0x2C44)
+#define MSS_SLP_CLK_CTL			(MSM_CLK_CTL_BASE + 0x2C60)
+#define MSS_MARM_SYS_REF_CLK_CTL	(MSM_CLK_CTL_BASE + 0x2C64)
+#define MAHB0_CLK_CTL			(MSM_CLK_CTL_BASE + 0x2300)
+#define MAHB1_CLK_CTL			(MSM_CLK_CTL_BASE + 0x2BE4)
+#define MAHB2_CLK_CTL			(MSM_CLK_CTL_BASE + 0x2C20)
+#define MAHB1_NS			(MSM_CLK_CTL_BASE + 0x2BE0)
+#define MARM_CLK_FS			(MSM_CLK_CTL_BASE + 0x2BD0)
+#define MAHB2_CLK_FS			(MSM_CLK_CTL_BASE + 0x2C24)
+#define PLL_ENA_MARM			(MSM_CLK_CTL_BASE + 0x3500)
+#define PLL8_STATUS			(MSM_CLK_CTL_BASE + 0x3158)
+#define CLK_HALT_MSS_SMPSS_MISC_STATE	(MSM_CLK_CTL_BASE + 0x2FDC)
+
+#define PROXY_VOTE_TIMEOUT		10000
+
+struct modem_data {
+	void __iomem *base;
+	unsigned long start_addr;
+	struct msm_xo_voter *pxo;
+	struct timer_list timer;
+};
+
+static int nop_verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
+{
+	return 0;
+}
+
+static void remove_proxy_votes(unsigned long data)
+{
+	struct modem_data *drv = (struct modem_data *)data;
+	msm_xo_mode_vote(drv->pxo, MSM_XO_MODE_OFF);
+}
+
+static void make_modem_proxy_votes(struct device *dev)
+{
+	int ret;
+	struct modem_data *drv = dev_get_drvdata(dev);
+
+	ret = msm_xo_mode_vote(drv->pxo, MSM_XO_MODE_ON);
+	if (ret)
+		dev_err(dev, "Failed to enable PXO\n");
+	mod_timer(&drv->timer, jiffies + msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
+}
+
+static void remove_modem_proxy_votes_now(struct modem_data *drv)
+{
+	/* If the proxy vote hasn't been removed yet, remove it immediately. */
+	if (del_timer(&drv->timer))
+		remove_proxy_votes((unsigned long)drv);
+}
+
+static int modem_init_image(struct pil_desc *pil, const u8 *metadata,
+		size_t size)
+{
+	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
+	struct modem_data *drv = dev_get_drvdata(pil->dev);
+	drv->start_addr = ehdr->e_entry;
+	return 0;
+}
+
+static int modem_reset(struct pil_desc *pil)
+{
+	u32 reg;
+	const struct modem_data *drv = dev_get_drvdata(pil->dev);
+
+	make_modem_proxy_votes(pil->dev);
+
+	/* Put modem AHB0,1,2 clocks into reset */
+	writel_relaxed(BIT(0) | BIT(1), MAHB0_SFAB_PORT_RESET);
+	writel_relaxed(BIT(7), MAHB1_CLK_CTL);
+	writel_relaxed(BIT(7), MAHB2_CLK_CTL);
+
+	/* Vote for pll8 on behalf of the modem */
+	reg = readl_relaxed(PLL_ENA_MARM);
+	reg |= BIT(8);
+	writel_relaxed(reg, PLL_ENA_MARM);
+
+	/* Wait for PLL8 to enable */
+	while (!(readl_relaxed(PLL8_STATUS) & BIT(16)))
+		cpu_relax();
+
+	/* Set MAHB1 divider to Div-5 to run MAHB1,2 and sfab at 79.8 Mhz*/
+	writel_relaxed(0x4, MAHB1_NS);
+
+	/* Vote for modem AHB1 and 2 clocks to be on on behalf of the modem */
+	reg = readl_relaxed(MARM_CLK_BRANCH_ENA_VOTE);
+	reg |= BIT(0) | BIT(1);
+	writel_relaxed(reg, MARM_CLK_BRANCH_ENA_VOTE);
+
+	/* Source marm_clk off of PLL8 */
+	reg = readl_relaxed(MARM_CLK_SRC_CTL);
+	if ((reg & 0x1) == 0) {
+		writel_relaxed(0x3, MARM_CLK_SRC1_NS);
+		reg |= 0x1;
+	} else {
+		writel_relaxed(0x3, MARM_CLK_SRC0_NS);
+		reg &= ~0x1;
+	}
+	writel_relaxed(reg | 0x2, MARM_CLK_SRC_CTL);
+
+	/*
+	 * Force core on and periph on signals to remain active during halt
+	 * for marm_clk and mahb2_clk
+	 */
+	writel_relaxed(0x6F, MARM_CLK_FS);
+	writel_relaxed(0x6F, MAHB2_CLK_FS);
+
+	/*
+	 * Enable all of the marm_clk branches, cxo sourced marm branches,
+	 * and sleep clock branches
+	 */
+	writel_relaxed(0x10, MARM_CLK_CTL);
+	writel_relaxed(0x10, MAHB0_CLK_CTL);
+	writel_relaxed(0x10, SFAB_MSS_S_HCLK_CTL);
+	writel_relaxed(0x10, MSS_MODEM_CXO_CLK_CTL);
+	writel_relaxed(0x10, MSS_SLP_CLK_CTL);
+	writel_relaxed(0x10, MSS_MARM_SYS_REF_CLK_CTL);
+
+	/* Wait for above clocks to be turned on */
+	while (readl_relaxed(CLK_HALT_MSS_SMPSS_MISC_STATE) & (BIT(7) | BIT(8) |
+				BIT(9) | BIT(10) | BIT(4) | BIT(6)))
+		cpu_relax();
+
+	/* Take MAHB0,1,2 clocks out of reset */
+	writel_relaxed(0x0, MAHB2_CLK_CTL);
+	writel_relaxed(0x0, MAHB1_CLK_CTL);
+	writel_relaxed(0x0, MAHB0_SFAB_PORT_RESET);
+	mb();
+
+	/* Setup exception vector table base address */
+	writel_relaxed(drv->start_addr | 0x1, drv->base + MARM_BOOT_CONTROL);
+
+	/* Wait for vector table to be setup */
+	mb();
+
+	/* Bring modem out of reset */
+	writel_relaxed(0x0, MARM_RESET);
+
+	return 0;
+}
+
+static int modem_shutdown(struct pil_desc *pil)
+{
+	u32 reg;
+	struct modem_data *drv = dev_get_drvdata(pil->dev);
+
+	/* Put modem into reset */
+	writel_relaxed(0x1, MARM_RESET);
+	mb();
+
+	/* Put modem AHB0,1,2 clocks into reset */
+	writel_relaxed(BIT(0) | BIT(1), MAHB0_SFAB_PORT_RESET);
+	writel_relaxed(BIT(7), MAHB1_CLK_CTL);
+	writel_relaxed(BIT(7), MAHB2_CLK_CTL);
+	mb();
+
+	/*
+	 * Disable all of the marm_clk branches, cxo sourced marm branches,
+	 * and sleep clock branches
+	 */
+	writel_relaxed(0x0, MARM_CLK_CTL);
+	writel_relaxed(0x0, MAHB0_CLK_CTL);
+	writel_relaxed(0x0, SFAB_MSS_S_HCLK_CTL);
+	writel_relaxed(0x0, MSS_MODEM_CXO_CLK_CTL);
+	writel_relaxed(0x0, MSS_SLP_CLK_CTL);
+	writel_relaxed(0x0, MSS_MARM_SYS_REF_CLK_CTL);
+
+	/* Disable marm_clk */
+	reg = readl_relaxed(MARM_CLK_SRC_CTL);
+	reg &= ~0x2;
+	writel_relaxed(reg, MARM_CLK_SRC_CTL);
+
+	/* Clear modem's votes for ahb clocks */
+	writel_relaxed(0x0, MARM_CLK_BRANCH_ENA_VOTE);
+
+	/* Clear modem's votes for PLLs */
+	writel_relaxed(0x0, PLL_ENA_MARM);
+
+	remove_modem_proxy_votes_now(drv);
+
+	return 0;
+}
+
+static struct pil_reset_ops pil_modem_ops = {
+	.init_image = modem_init_image,
+	.verify_blob = nop_verify_blob,
+	.auth_and_reset = modem_reset,
+	.shutdown = modem_shutdown,
+};
+
+static int modem_init_image_trusted(struct pil_desc *pil, const u8 *metadata,
+		size_t size)
+{
+	return pas_init_image(PAS_MODEM, metadata, size);
+}
+
+static int modem_reset_trusted(struct pil_desc *pil)
+{
+	int ret;
+	struct modem_data *drv = dev_get_drvdata(pil->dev);
+
+	make_modem_proxy_votes(pil->dev);
+
+	ret = pas_auth_and_reset(PAS_MODEM);
+	if (ret)
+		remove_modem_proxy_votes_now(drv);
+
+	return ret;
+}
+
+static int modem_shutdown_trusted(struct pil_desc *pil)
+{
+	int ret;
+	struct modem_data *drv = dev_get_drvdata(pil->dev);
+
+	ret = pas_shutdown(PAS_MODEM);
+	if (ret)
+		return ret;
+
+	remove_modem_proxy_votes_now(drv);
+	return 0;
+}
+
+static struct pil_reset_ops pil_modem_ops_trusted = {
+	.init_image = modem_init_image_trusted,
+	.verify_blob = nop_verify_blob,
+	.auth_and_reset = modem_reset_trusted,
+	.shutdown = modem_shutdown_trusted,
+};
+
+static int __devinit pil_modem_driver_probe(struct platform_device *pdev)
+{
+	struct modem_data *drv;
+	struct resource *res;
+	struct pil_desc *desc;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -EINVAL;
+
+	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+	if (!drv)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, drv);
+
+	drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!drv->base)
+		return -ENOMEM;
+
+	drv->pxo = msm_xo_get(MSM_XO_PXO, dev_name(&pdev->dev));
+	if (IS_ERR(drv->pxo))
+		return PTR_ERR(drv->pxo);
+
+	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	setup_timer(&drv->timer, remove_proxy_votes, (unsigned long)drv);
+	desc->name = "modem";
+	desc->depends_on = "q6";
+	desc->dev = &pdev->dev;
+
+	if (pas_supported(PAS_MODEM) > 0) {
+		desc->ops = &pil_modem_ops_trusted;
+		dev_info(&pdev->dev, "using secure boot\n");
+	} else {
+		desc->ops = &pil_modem_ops;
+		dev_info(&pdev->dev, "using non-secure boot\n");
+	}
+
+	if (msm_pil_register(desc)) {
+		msm_xo_put(drv->pxo);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int __devexit pil_modem_driver_exit(struct platform_device *pdev)
+{
+	struct modem_data *drv = platform_get_drvdata(pdev);
+	del_timer_sync(&drv->timer);
+	msm_xo_put(drv->pxo);
+	return 0;
+}
+
+static struct platform_driver pil_modem_driver = {
+	.probe = pil_modem_driver_probe,
+	.remove = __devexit_p(pil_modem_driver_exit),
+	.driver = {
+		.name = "pil_modem",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init pil_modem_init(void)
+{
+	return platform_driver_register(&pil_modem_driver);
+}
+module_init(pil_modem_init);
+
+static void __exit pil_modem_exit(void)
+{
+	platform_driver_unregister(&pil_modem_driver);
+}
+module_exit(pil_modem_exit);
+
+MODULE_DESCRIPTION("Support for booting modem processors");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-q6v4.c b/arch/arm/mach-msm/pil-q6v4.c
index 24c479c..d8ebab5 100644
--- a/arch/arm/mach-msm/pil-q6v4.c
+++ b/arch/arm/mach-msm/pil-q6v4.c
@@ -28,7 +28,7 @@
 #include "pil-q6v4.h"
 #include "scm-pas.h"
 
-#define PROXY_VOTE_TIMEOUT	10000
+#define PROXY_VOTE_TIMEOUT	40000
 
 #define QDSP6SS_RST_EVB		0x0
 #define QDSP6SS_RESET		0x04
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
new file mode 100644
index 0000000..de61041
--- /dev/null
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -0,0 +1,352 @@
+/* Copyright (c) 2011, Code Aurora Forum. 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 version 2 and
+ * only 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/elf.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#include <mach/msm_iomap.h>
+#include <mach/msm_xo.h>
+
+#include "peripheral-loader.h"
+#include "scm-pas.h"
+
+#define PROXY_VOTE_TIMEOUT		10000
+
+#define RIVA_PMU_A2XB_CFG		0xB8
+#define RIVA_PMU_A2XB_CFG_EN		BIT(0)
+
+#define RIVA_PMU_CFG			0x28
+#define RIVA_PMU_CFG_WARM_BOOT		BIT(0)
+#define RIVA_PMU_CFG_IRIS_XO_MODE	0x6
+#define RIVA_PMU_CFG_IRIS_XO_MODE_48	(3 << 1)
+
+#define RIVA_PMU_OVRD_VAL		0x30
+#define RIVA_PMU_OVRD_VAL_CCPU_RESET	BIT(0)
+#define RIVA_PMU_OVRD_VAL_CCPU_CLK	BIT(1)
+
+#define RIVA_PMU_CCPU_CTL		0x9C
+#define RIVA_PMU_CCPU_CTL_HIGH_IVT	BIT(0)
+#define RIVA_PMU_CCPU_CTL_REMAP_EN	BIT(2)
+
+#define RIVA_PMU_CCPU_BOOT_REMAP_ADDR	0xA0
+
+#define RIVA_PLL_MODE			(MSM_CLK_CTL_BASE + 0x31A0)
+#define PLL_MODE_OUTCTRL		BIT(0)
+#define PLL_MODE_BYPASSNL		BIT(1)
+#define PLL_MODE_RESET_N		BIT(2)
+#define PLL_MODE_REF_XO_SEL		0x30
+#define PLL_MODE_REF_XO_SEL_CXO		(2 << 4)
+#define PLL_MODE_REF_XO_SEL_RF		(3 << 4)
+#define RIVA_PLL_L_VAL			(MSM_CLK_CTL_BASE + 0x31A4)
+#define RIVA_PLL_M_VAL			(MSM_CLK_CTL_BASE + 0x31A8)
+#define RIVA_PLL_N_VAL			(MSM_CLK_CTL_BASE + 0x31Ac)
+#define RIVA_PLL_CONFIG			(MSM_CLK_CTL_BASE + 0x31B4)
+#define RIVA_PLL_STATUS			(MSM_CLK_CTL_BASE + 0x31B8)
+
+#define RIVA_PMU_ROOT_CLK_SEL		0xC8
+#define RIVA_PMU_ROOT_CLK_SEL_3		BIT(2)
+
+#define RIVA_PMU_CLK_ROOT3			0x78
+#define RIVA_PMU_CLK_ROOT3_ENA			BIT(0)
+#define RIVA_PMU_CLK_ROOT3_SRC0_DIV		0x3C
+#define RIVA_PMU_CLK_ROOT3_SRC0_DIV_2		(1 << 2)
+#define RIVA_PMU_CLK_ROOT3_SRC0_SEL		0x1C0
+#define RIVA_PMU_CLK_ROOT3_SRC0_SEL_RIVA	(1 << 6)
+#define RIVA_PMU_CLK_ROOT3_SRC1_DIV		0x1E00
+#define RIVA_PMU_CLK_ROOT3_SRC1_DIV_2		(1 << 9)
+#define RIVA_PMU_CLK_ROOT3_SRC1_SEL		0xE000
+#define RIVA_PMU_CLK_ROOT3_SRC1_SEL_RIVA	(1 << 13)
+
+struct riva_data {
+	void __iomem *base;
+	unsigned long start_addr;
+	struct msm_xo_voter *xo;
+	struct timer_list xo_timer;
+};
+
+static void pil_riva_make_xo_proxy_votes(struct device *dev)
+{
+	struct riva_data *drv = dev_get_drvdata(dev);
+
+	msm_xo_mode_vote(drv->xo, MSM_XO_MODE_ON);
+	mod_timer(&drv->xo_timer, jiffies+msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
+}
+
+static void pil_riva_remove_xo_proxy_votes(unsigned long data)
+{
+	struct riva_data *drv = (struct riva_data *)data;
+
+	msm_xo_mode_vote(drv->xo, MSM_XO_MODE_OFF);
+}
+
+static void pil_riva_remove_xo_proxy_votes_now(struct device *dev)
+{
+	struct riva_data *drv = dev_get_drvdata(dev);
+
+	if (del_timer(&drv->xo_timer))
+		pil_riva_remove_xo_proxy_votes((unsigned long)drv);
+}
+
+static bool cxo_is_needed(struct riva_data *drv)
+{
+	u32 reg = readl_relaxed(drv->base + RIVA_PMU_CFG);
+	return (reg & RIVA_PMU_CFG_IRIS_XO_MODE)
+		!= RIVA_PMU_CFG_IRIS_XO_MODE_48;
+}
+
+static int nop_verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
+{
+	return 0;
+}
+
+static int pil_riva_init_image(struct pil_desc *pil, const u8 *metadata,
+		size_t size)
+{
+	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
+	struct riva_data *drv = dev_get_drvdata(pil->dev);
+	drv->start_addr = ehdr->e_entry;
+	return 0;
+}
+
+static int pil_riva_reset(struct pil_desc *pil)
+{
+	u32 reg, sel;
+	bool use_cxo;
+	struct riva_data *drv = dev_get_drvdata(pil->dev);
+	void __iomem *base = drv->base;
+	unsigned long start_addr = drv->start_addr;
+
+	/* Enable A2XB bridge */
+	reg = readl_relaxed(base + RIVA_PMU_A2XB_CFG);
+	reg |= RIVA_PMU_A2XB_CFG_EN;
+	writel_relaxed(reg, base + RIVA_PMU_A2XB_CFG);
+
+	/* Proxy-vote for CXO if it's needed */
+	use_cxo = cxo_is_needed(drv);
+	if (use_cxo)
+		pil_riva_make_xo_proxy_votes(pil->dev);
+
+	/* Program PLL 13 to 960 MHz */
+	reg = readl_relaxed(RIVA_PLL_MODE);
+	reg &= ~(PLL_MODE_BYPASSNL | PLL_MODE_OUTCTRL | PLL_MODE_RESET_N);
+	writel_relaxed(reg, RIVA_PLL_MODE);
+
+	if (use_cxo)
+		writel_relaxed(0x40000C00 | 50, RIVA_PLL_L_VAL);
+	else
+		writel_relaxed(0x40000C00 | 40, RIVA_PLL_L_VAL);
+	writel_relaxed(0, RIVA_PLL_M_VAL);
+	writel_relaxed(1, RIVA_PLL_N_VAL);
+	writel_relaxed(0x01495227, RIVA_PLL_CONFIG);
+
+	reg = readl_relaxed(RIVA_PLL_MODE);
+	reg &= ~(PLL_MODE_REF_XO_SEL);
+	reg |= use_cxo ? PLL_MODE_REF_XO_SEL_CXO : PLL_MODE_REF_XO_SEL_RF;
+	writel_relaxed(reg, RIVA_PLL_MODE);
+
+	/* Enable PLL 13 */
+	reg |= PLL_MODE_BYPASSNL;
+	writel_relaxed(reg, RIVA_PLL_MODE);
+
+	/*
+	 * H/W requires a 5us delay between disabling the bypass and
+	 * de-asserting the reset. Delay 10us just to be safe.
+	 */
+	mb();
+	usleep_range(10, 20);
+
+	reg |= PLL_MODE_RESET_N;
+	writel_relaxed(reg, RIVA_PLL_MODE);
+	reg |= PLL_MODE_OUTCTRL;
+	writel_relaxed(reg, RIVA_PLL_MODE);
+
+	/* Wait for PLL to settle */
+	mb();
+	usleep_range(50, 100);
+
+	/* Configure cCPU for 240 MHz */
+	sel = readl_relaxed(base + RIVA_PMU_ROOT_CLK_SEL);
+	reg = readl_relaxed(base + RIVA_PMU_CLK_ROOT3);
+	if (sel & RIVA_PMU_ROOT_CLK_SEL_3) {
+		reg &= ~(RIVA_PMU_CLK_ROOT3_SRC0_SEL |
+			 RIVA_PMU_CLK_ROOT3_SRC0_DIV);
+		reg |= RIVA_PMU_CLK_ROOT3_SRC0_SEL_RIVA |
+		       RIVA_PMU_CLK_ROOT3_SRC0_DIV_2;
+	} else {
+		reg &= ~(RIVA_PMU_CLK_ROOT3_SRC1_SEL |
+			 RIVA_PMU_CLK_ROOT3_SRC1_DIV);
+		reg |= RIVA_PMU_CLK_ROOT3_SRC1_SEL_RIVA |
+		       RIVA_PMU_CLK_ROOT3_SRC1_DIV_2;
+	}
+	writel_relaxed(reg, base + RIVA_PMU_CLK_ROOT3);
+	reg |= RIVA_PMU_CLK_ROOT3_ENA;
+	writel_relaxed(reg, base + RIVA_PMU_CLK_ROOT3);
+	reg = readl_relaxed(base + RIVA_PMU_ROOT_CLK_SEL);
+	reg ^= RIVA_PMU_ROOT_CLK_SEL_3;
+	writel_relaxed(reg, base + RIVA_PMU_ROOT_CLK_SEL);
+
+	/* Use the high vector table */
+	reg = readl_relaxed(base + RIVA_PMU_CCPU_CTL);
+	reg |= RIVA_PMU_CCPU_CTL_HIGH_IVT | RIVA_PMU_CCPU_CTL_REMAP_EN;
+	writel_relaxed(reg, base + RIVA_PMU_CCPU_CTL);
+
+	/* Set base memory address */
+	writel_relaxed(start_addr >> 16, base + RIVA_PMU_CCPU_BOOT_REMAP_ADDR);
+
+	/* Clear warmboot bit indicating this is a cold boot */
+	reg = readl_relaxed(base + RIVA_PMU_CFG);
+	reg &= ~(RIVA_PMU_CFG_WARM_BOOT);
+	writel_relaxed(reg, base + RIVA_PMU_CFG);
+
+	/* Enable the cCPU clock */
+	reg = readl_relaxed(base + RIVA_PMU_OVRD_VAL);
+	reg |= RIVA_PMU_OVRD_VAL_CCPU_CLK;
+	writel_relaxed(reg, base + RIVA_PMU_OVRD_VAL);
+
+	/* Take cCPU out of reset */
+	reg |= RIVA_PMU_OVRD_VAL_CCPU_RESET;
+	writel_relaxed(reg, base + RIVA_PMU_OVRD_VAL);
+
+	return 0;
+}
+
+static int pil_riva_shutdown(struct pil_desc *pil)
+{
+	struct riva_data *drv = dev_get_drvdata(pil->dev);
+	u32 reg;
+
+	reg = readl_relaxed(drv->base + RIVA_PMU_OVRD_VAL);
+	reg &= ~(RIVA_PMU_OVRD_VAL_CCPU_RESET | RIVA_PMU_OVRD_VAL_CCPU_CLK);
+	writel_relaxed(reg, drv->base + RIVA_PMU_OVRD_VAL);
+
+	pil_riva_remove_xo_proxy_votes_now(pil->dev);
+
+	return 0;
+}
+
+static struct pil_reset_ops pil_riva_ops = {
+	.init_image = pil_riva_init_image,
+	.verify_blob = nop_verify_blob,
+	.auth_and_reset = pil_riva_reset,
+	.shutdown = pil_riva_shutdown,
+};
+
+static int pil_riva_init_image_trusted(struct pil_desc *pil,
+		const u8 *metadata, size_t size)
+{
+	return pas_init_image(PAS_RIVA, metadata, size);
+}
+
+static int pil_riva_reset_trusted(struct pil_desc *pil)
+{
+	struct riva_data *drv = dev_get_drvdata(pil->dev);
+
+	/* Proxy-vote for CXO if it's needed */
+	if (cxo_is_needed(drv))
+		pil_riva_make_xo_proxy_votes(pil->dev);
+
+	return pas_auth_and_reset(PAS_RIVA);
+}
+
+static int pil_riva_shutdown_trusted(struct pil_desc *pil)
+{
+	int ret = pas_shutdown(PAS_RIVA);
+
+	pil_riva_remove_xo_proxy_votes_now(pil->dev);
+
+	return ret;
+}
+
+static struct pil_reset_ops pil_riva_ops_trusted = {
+	.init_image = pil_riva_init_image_trusted,
+	.verify_blob = nop_verify_blob,
+	.auth_and_reset = pil_riva_reset_trusted,
+	.shutdown = pil_riva_shutdown_trusted,
+};
+
+static int __devinit pil_riva_probe(struct platform_device *pdev)
+{
+	struct riva_data *drv;
+	struct resource *res;
+	struct pil_desc *desc;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -EINVAL;
+
+	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+	if (!drv)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, drv);
+
+	drv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+	if (!drv->base)
+		return -ENOMEM;
+
+	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	desc->name = "wcnss";
+	desc->dev = &pdev->dev;
+
+	if (pas_supported(PAS_RIVA) > 0) {
+		desc->ops = &pil_riva_ops_trusted;
+		dev_info(&pdev->dev, "using secure boot\n");
+	} else {
+		desc->ops = &pil_riva_ops;
+		dev_info(&pdev->dev, "using non-secure boot\n");
+	}
+
+	setup_timer(&drv->xo_timer, pil_riva_remove_xo_proxy_votes,
+		    (unsigned long)drv);
+	drv->xo = msm_xo_get(MSM_XO_CXO, desc->name);
+	if (IS_ERR(drv->xo))
+		return PTR_ERR(drv->xo);
+
+	return msm_pil_register(desc);
+}
+
+static int __devexit pil_riva_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct platform_driver pil_riva_driver = {
+	.probe = pil_riva_probe,
+	.remove = __devexit_p(pil_riva_remove),
+	.driver = {
+		.name = "pil_riva",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init pil_riva_init(void)
+{
+	return platform_driver_register(&pil_riva_driver);
+}
+module_init(pil_riva_init);
+
+static void __exit pil_riva_exit(void)
+{
+	platform_driver_unregister(&pil_riva_driver);
+}
+module_exit(pil_riva_exit);
+
+MODULE_DESCRIPTION("Support for booting RIVA (WCNSS) processors");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-tzapps.c b/arch/arm/mach-msm/pil-tzapps.c
new file mode 100644
index 0000000..90ac1d9
--- /dev/null
+++ b/arch/arm/mach-msm/pil-tzapps.c
@@ -0,0 +1,96 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. 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 version 2 and
+ * only 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/elf.h>
+#include <linux/err.h>
+
+#include "peripheral-loader.h"
+#include "scm-pas.h"
+
+static int nop_verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
+{
+	return 0;
+}
+
+static int pil_tzapps_init_image(struct pil_desc *pil, const u8 *metadata,
+		size_t size)
+{
+	return pas_init_image(PAS_TZAPPS, metadata, size);
+}
+
+static int pil_tzapps_reset(struct pil_desc *pil)
+{
+	return pas_auth_and_reset(PAS_TZAPPS);
+}
+
+static int pil_tzapps_shutdown(struct pil_desc *pil)
+{
+	return pas_shutdown(PAS_TZAPPS);
+}
+
+static struct pil_reset_ops pil_tzapps_ops = {
+	.init_image = pil_tzapps_init_image,
+	.verify_blob = nop_verify_blob,
+	.auth_and_reset = pil_tzapps_reset,
+	.shutdown = pil_tzapps_shutdown,
+};
+
+static int __devinit pil_tzapps_driver_probe(struct platform_device *pdev)
+{
+	struct pil_desc *desc;
+
+	if (pas_supported(PAS_TZAPPS) < 0)
+		return -ENOSYS;
+
+	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return -ENOMEM;
+
+	desc->name = "tzapps";
+	desc->dev = &pdev->dev;
+	desc->ops = &pil_tzapps_ops;
+	if (msm_pil_register(desc))
+		return -EINVAL;
+	return 0;
+}
+
+static int __devexit pil_tzapps_driver_exit(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct platform_driver pil_tzapps_driver = {
+	.probe = pil_tzapps_driver_probe,
+	.remove = __devexit_p(pil_tzapps_driver_exit),
+	.driver = {
+		.name = "pil_tzapps",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init pil_tzapps_init(void)
+{
+	return platform_driver_register(&pil_tzapps_driver);
+}
+module_init(pil_tzapps_init);
+
+static void __exit pil_tzapps_exit(void)
+{
+	platform_driver_unregister(&pil_tzapps_driver);
+}
+module_exit(pil_tzapps_exit);
+
+MODULE_DESCRIPTION("Support for booting TZApps images");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index 3f40a12..0838c2c 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -8,6 +8,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/cpumask.h>
 #include <linux/delay.h>
@@ -56,12 +57,14 @@
 
 	/* KraitMP or ScorpionMP ? */
 	if ((read_cpuid_id() & 0xFF0) >> 4 != 0x2D) {
-		base_ptr = ioremap_nocache(0x02098000, SZ_4K);
+		base_ptr = ioremap_nocache(0x02088000 + (cpu * 0x10000), SZ_4K);
 		if (base_ptr) {
 			if (machine_is_msm8960_sim() ||
 			    machine_is_msm8960_rumi3()) {
 				writel_relaxed(0x10, base_ptr+0x04);
 				writel_relaxed(0x80, base_ptr+0x04);
+			} else if (machine_is_apq8064_sim()) {
+				writel_relaxed(0xf0000, base_ptr+0x04);
 			} else if (get_core_count() == 2) {
 				writel_relaxed(0x109, base_ptr+0x04);
 				writel_relaxed(0x101, base_ptr+0x04);
@@ -95,6 +98,12 @@
 }
 
 DEFINE_PER_CPU(int, cold_boot_done);
+static int cold_boot_flags[] = {
+	0,
+	SCM_FLAG_COLDBOOT_CPU1,
+	SCM_FLAG_COLDBOOT_CPU2,
+	SCM_FLAG_COLDBOOT_CPU3,
+};
 
 /* Executed by primary CPU, brings other CPUs out of reset. Called at boot
    as well as when a CPU is coming out of shutdown induced by echo 0 >
@@ -104,16 +113,22 @@
 {
 	int cnt = 0;
 	int ret;
+	int flag = 0;
 
 	pr_debug("Starting secondary CPU %d\n", cpu);
 
 	/* Set preset_lpj to avoid subsequent lpj recalculations */
 	preset_lpj = loops_per_jiffy;
 
+	if (cpu > 0 && cpu < ARRAY_SIZE(cold_boot_flags))
+		flag = cold_boot_flags[cpu];
+	else
+		__WARN();
+
 	if (per_cpu(cold_boot_done, cpu) == false) {
 		ret = scm_set_boot_addr((void *)
 					virt_to_phys(msm_secondary_startup),
-					SCM_FLAG_COLDBOOT_CPU1);
+					flag);
 		if (ret == 0)
 			release_secondary(cpu);
 		else
@@ -151,9 +166,7 @@
 {
 	pr_debug("CPU%u: Booted secondary processor\n", cpu);
 
-#ifdef CONFIG_HOTPLUG_CPU
-	WARN_ON(msm_pm_platform_secondary_init(cpu));
-#endif
+	WARN_ON(msm_platform_secondary_init(cpu));
 
 	trace_hardirqs_off();
 
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index f479dafb..adf5471 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -620,15 +620,6 @@
  *
  *****************************************************************************/
 
-struct msm_pm_device {
-	unsigned int cpu;
-#ifdef CONFIG_HOTPLUG_CPU
-	struct completion cpu_killed;
-	unsigned int warm_boot;
-#endif
-};
-
-static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_pm_device, msm_pm_devices);
 static struct msm_rpmrs_limits *msm_pm_idle_rs_limits;
 
 static void msm_pm_swfi(void)
@@ -656,7 +647,7 @@
 #endif
 
 static bool msm_pm_spm_power_collapse(
-	struct msm_pm_device *dev, bool from_idle, bool notify_rpm)
+	unsigned int cpu, bool from_idle, bool notify_rpm)
 {
 	void *entry;
 	bool collapsed = 0;
@@ -664,19 +655,19 @@
 
 	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
 		pr_info("CPU%u: %s: notify_rpm %d\n",
-			dev->cpu, __func__, (int) notify_rpm);
+			cpu, __func__, (int) notify_rpm);
 
 	ret = msm_spm_set_low_power_mode(
 			MSM_SPM_MODE_POWER_COLLAPSE, notify_rpm);
 	WARN_ON(ret);
 
-	entry = (!dev->cpu || from_idle) ?
+	entry = (!cpu || from_idle) ?
 		msm_pm_collapse_exit : msm_secondary_startup;
-	msm_pm_boot_config_before_pc(dev->cpu, virt_to_phys(entry));
+	msm_pm_boot_config_before_pc(cpu, virt_to_phys(entry));
 
 	if (MSM_PM_DEBUG_RESET_VECTOR & msm_pm_debug_mask)
 		pr_info("CPU%u: %s: program vector to %p\n",
-			dev->cpu, __func__, entry);
+			cpu, __func__, entry);
 
 #ifdef CONFIG_VFP
 	vfp_flush_context();
@@ -684,7 +675,7 @@
 
 	collapsed = msm_pm_l2x0_power_collapse();
 
-	msm_pm_boot_config_after_pc(dev->cpu);
+	msm_pm_boot_config_after_pc(cpu);
 
 	if (collapsed) {
 #ifdef CONFIG_VFP
@@ -698,7 +689,7 @@
 
 	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
 		pr_info("CPU%u: %s: msm_pm_collapse returned, collapsed %d\n",
-			dev->cpu, __func__, collapsed);
+			cpu, __func__, collapsed);
 
 	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
 	WARN_ON(ret);
@@ -707,60 +698,60 @@
 
 static bool msm_pm_power_collapse_standalone(bool from_idle)
 {
-	struct msm_pm_device *dev = &__get_cpu_var(msm_pm_devices);
+	unsigned int cpu = smp_processor_id();
 	unsigned int avsdscr_setting;
 	bool collapsed;
 
 	avsdscr_setting = avs_get_avsdscr();
 	avs_disable();
-	collapsed = msm_pm_spm_power_collapse(dev, from_idle, false);
+	collapsed = msm_pm_spm_power_collapse(cpu, from_idle, false);
 	avs_reset_delays(avsdscr_setting);
 	return collapsed;
 }
 
 static bool msm_pm_power_collapse(bool from_idle)
 {
-	struct msm_pm_device *dev = &__get_cpu_var(msm_pm_devices);
+	unsigned int cpu = smp_processor_id();
 	unsigned long saved_acpuclk_rate;
 	unsigned int avsdscr_setting;
 	bool collapsed;
 
 	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
 		pr_info("CPU%u: %s: idle %d\n",
-			dev->cpu, __func__, (int)from_idle);
+			cpu, __func__, (int)from_idle);
 
 	msm_pm_config_hw_before_power_down();
 	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
-		pr_info("CPU%u: %s: pre power down\n", dev->cpu, __func__);
+		pr_info("CPU%u: %s: pre power down\n", cpu, __func__);
 
 	avsdscr_setting = avs_get_avsdscr();
 	avs_disable();
 
-	if (cpu_online(dev->cpu))
+	if (cpu_online(cpu))
 		saved_acpuclk_rate = acpuclk_power_collapse();
 	else
 		saved_acpuclk_rate = 0;
 
 	if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
 		pr_info("CPU%u: %s: change clock rate (old rate = %lu)\n",
-			dev->cpu, __func__, saved_acpuclk_rate);
+			cpu, __func__, saved_acpuclk_rate);
 
-	collapsed = msm_pm_spm_power_collapse(dev, from_idle, true);
+	collapsed = msm_pm_spm_power_collapse(cpu, from_idle, true);
 
 	if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
 		pr_info("CPU%u: %s: restore clock rate to %lu\n",
-			dev->cpu, __func__, saved_acpuclk_rate);
-	if (acpuclk_set_rate(dev->cpu, saved_acpuclk_rate, SETRATE_PC) < 0)
+			cpu, __func__, saved_acpuclk_rate);
+	if (acpuclk_set_rate(cpu, saved_acpuclk_rate, SETRATE_PC) < 0)
 		pr_err("CPU%u: %s: failed to restore clock rate(%lu)\n",
-			dev->cpu, __func__, saved_acpuclk_rate);
+			cpu, __func__, saved_acpuclk_rate);
 
 	avs_reset_delays(avsdscr_setting);
 	msm_pm_config_hw_after_power_up();
 	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
-		pr_info("CPU%u: %s: post power up\n", dev->cpu, __func__);
+		pr_info("CPU%u: %s: post power up\n", cpu, __func__);
 
 	if (MSM_PM_DEBUG_POWER_COLLAPSE & msm_pm_debug_mask)
-		pr_info("CPU%u: %s: return\n", dev->cpu, __func__);
+		pr_info("CPU%u: %s: return\n", cpu, __func__);
 	return collapsed;
 }
 
@@ -962,6 +953,31 @@
 	return 0;
 }
 
+void msm_pm_cpu_enter_lowpower(unsigned int cpu)
+{
+	int i;
+	bool allow[MSM_PM_SLEEP_MODE_NR];
+
+	for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
+		struct msm_pm_platform_data *mode;
+
+		mode = &msm_pm_modes[MSM_PM_MODE(cpu, i)];
+		allow[i] = mode->suspend_supported && mode->suspend_enabled;
+	}
+
+	if (MSM_PM_DEBUG_HOTPLUG & msm_pm_debug_mask)
+		pr_notice("CPU%u: %s: shutting down cpu\n", cpu, __func__);
+
+	if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE])
+		msm_pm_power_collapse(false);
+	else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE])
+		msm_pm_power_collapse_standalone(false);
+	else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT])
+		msm_pm_swfi();
+
+
+}
+
 static int msm_pm_enter(suspend_state_t state)
 {
 	bool allow[MSM_PM_SLEEP_MODE_NR];
@@ -1069,79 +1085,6 @@
 	.valid = suspend_valid_only_mem,
 };
 
-#ifdef CONFIG_HOTPLUG_CPU
-int platform_cpu_disable(unsigned int cpu)
-{
-	return cpu == 0 ? -EPERM : 0;
-}
-
-int platform_cpu_kill(unsigned int cpu)
-{
-	struct completion *killed = &per_cpu(msm_pm_devices, cpu).cpu_killed;
-	return wait_for_completion_timeout(killed, HZ * 5);
-}
-
-void platform_cpu_die(unsigned int cpu)
-{
-	bool allow[MSM_PM_SLEEP_MODE_NR];
-	int i;
-
-	if (unlikely(cpu != smp_processor_id())) {
-		pr_crit("%s: running on %u, should be %u\n",
-			__func__, smp_processor_id(), cpu);
-		BUG();
-	}
-
-	for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
-		struct msm_pm_platform_data *mode;
-
-		mode = &msm_pm_modes[MSM_PM_MODE(cpu, i)];
-		allow[i] = mode->suspend_supported && mode->suspend_enabled;
-	}
-
-	if (MSM_PM_DEBUG_HOTPLUG & msm_pm_debug_mask)
-		pr_notice("CPU%u: %s: shutting down cpu\n", cpu, __func__);
-	complete(&__get_cpu_var(msm_pm_devices).cpu_killed);
-
-	flush_cache_all();
-
-	for (;;) {
-		if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE])
-			msm_pm_power_collapse(false);
-		else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE])
-			msm_pm_power_collapse_standalone(false);
-		else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT])
-			msm_pm_swfi();
-
-		if (pen_release == cpu) {
-			/* OK, proper wakeup, we're done */
-			break;
-		}
-	}
-
-	pen_release = -1;
-	pr_notice("CPU%u: %s: normal wakeup\n", cpu, __func__);
-}
-
-int msm_pm_platform_secondary_init(unsigned int cpu)
-{
-	int ret;
-	struct msm_pm_device *dev = &__get_cpu_var(msm_pm_devices);
-
-	if (!dev->warm_boot) {
-		dev->warm_boot = 1;
-		return 0;
-	}
-	etm_restore_reg_check();
-	msm_restore_jtag_debug();
-#ifdef CONFIG_VFP
-	vfp_reinit();
-#endif
-	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
-
-	return ret;
-}
-#endif  /* CONFIG_HOTPLUG_CPU */
 
 /******************************************************************************
  * Initialization routine
@@ -1197,15 +1140,6 @@
 		return ret;
 	}
 
-	for_each_possible_cpu(cpu) {
-		struct msm_pm_device *dev = &per_cpu(msm_pm_devices, cpu);
-
-		dev->cpu = cpu;
-#ifdef CONFIG_HOTPLUG_CPU
-		init_completion(&dev->cpu_killed);
-#endif
-	}
-
 #ifdef CONFIG_MSM_IDLE_STATS
 	for_each_possible_cpu(cpu) {
 		struct msm_pm_time_stats *stats =
diff --git a/arch/arm/mach-msm/pm-boot.c b/arch/arm/mach-msm/pm-boot.c
index 6b92d1e..ce09f9f 100644
--- a/arch/arm/mach-msm/pm-boot.c
+++ b/arch/arm/mach-msm/pm-boot.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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 version 2 and
@@ -36,6 +36,9 @@
 		flag = SCM_FLAG_WARMBOOT_CPU0;
 	else if (num_possible_cpus() == 2)
 		flag = SCM_FLAG_WARMBOOT_CPU0 | SCM_FLAG_WARMBOOT_CPU1;
+	else if (num_possible_cpus() == 4)
+		flag = SCM_FLAG_WARMBOOT_CPU0 | SCM_FLAG_WARMBOOT_CPU1 |
+				SCM_FLAG_WARMBOOT_CPU2 | SCM_FLAG_WARMBOOT_CPU3;
 	else
 		__WARN();
 
@@ -106,8 +109,6 @@
 		msm_pm_boot_after_pc = NULL;
 		break;
 	case MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS:
-		if (!pdata->p_addr)
-			return -ENODEV;
 		pdata->v_addr = ioremap(pdata->p_addr, PAGE_SIZE);
 		/* Fall through */
 	case MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT:
diff --git a/arch/arm/mach-msm/pm-boot.h b/arch/arm/mach-msm/pm-boot.h
index 8a7238a..185d542 100644
--- a/arch/arm/mach-msm/pm-boot.h
+++ b/arch/arm/mach-msm/pm-boot.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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 version 2 and
@@ -30,7 +30,7 @@
 int __init msm_pm_boot_init(struct msm_pm_boot_platform_data *pdata);
 #else
 static inline int __init msm_pm_boot_init(
-		struct msm_pm_boot_platform_data *pdata);
+		struct msm_pm_boot_platform_data *pdata)
 {
 	return 0;
 }
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index ad0bc7d..813ece1 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -22,7 +22,6 @@
 #include <linux/cpuidle.h>
 
 #ifdef CONFIG_SMP
-extern int pen_release;
 extern void msm_secondary_startup(void);
 #else
 #define msm_secondary_startup NULL
@@ -55,13 +54,17 @@
 void msm_pm_set_platform_data(struct msm_pm_platform_data *data, int count);
 int msm_pm_idle_prepare(struct cpuidle_device *dev);
 int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode);
+void msm_pm_cpu_enter_lowpower(unsigned int cpu);
 
 #ifdef CONFIG_PM
 void msm_pm_set_rpm_wakeup_irq(unsigned int irq);
-int msm_pm_platform_secondary_init(unsigned int cpu);
 #else
 static inline void msm_pm_set_rpm_wakeup_irq(unsigned int irq) {}
-static inline int msm_pm_platform_secondary_init(unsigned int cpu)
-{ return -ENOSYS; }
+#endif
+
+#ifdef CONFIG_HOTPLUG_CPU
+int msm_platform_secondary_init(unsigned int cpu);
+#else
+static inline int msm_platform_secondary_init(unsigned int cpu) { return 0; }
 #endif
 #endif  /* __ARCH_ARM_MACH_MSM_PM_H */
diff --git a/arch/arm/mach-msm/pmic8058-gpio.c b/arch/arm/mach-msm/pmic8058-gpio.c
deleted file mode 100644
index 63a26de..0000000
--- a/arch/arm/mach-msm/pmic8058-gpio.c
+++ /dev/null
@@ -1,705 +0,0 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. 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 version 2 and
- * only 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.
- */
-/*
- * Qualcomm PMIC8058 GPIO driver
- *
- */
-
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/mfd/pmic8058.h>
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
-#include <linux/fs.h>
-#include <linux/seq_file.h>
-
-#ifndef CONFIG_GPIOLIB
-#include "gpio_chip.h"
-#endif
-
-/* GPIO registers */
-#define	SSBI_REG_ADDR_GPIO_BASE		0x150
-#define	SSBI_REG_ADDR_GPIO(n)		(SSBI_REG_ADDR_GPIO_BASE + n)
-
-/* GPIO */
-#define	PM8058_GPIO_BANK_MASK		0x70
-#define	PM8058_GPIO_BANK_SHIFT		4
-#define	PM8058_GPIO_WRITE		0x80
-
-/* Bank 0 */
-#define	PM8058_GPIO_VIN_MASK		0x0E
-#define	PM8058_GPIO_VIN_SHIFT		1
-#define	PM8058_GPIO_MODE_ENABLE		0x01
-
-/* Bank 1 */
-#define	PM8058_GPIO_MODE_MASK		0x0C
-#define	PM8058_GPIO_MODE_SHIFT		2
-#define	PM8058_GPIO_OUT_BUFFER		0x02
-#define	PM8058_GPIO_OUT_INVERT		0x01
-
-#define	PM8058_GPIO_MODE_OFF		3
-#define	PM8058_GPIO_MODE_OUTPUT		2
-#define	PM8058_GPIO_MODE_INPUT		0
-#define	PM8058_GPIO_MODE_BOTH		1
-
-/* Bank 2 */
-#define	PM8058_GPIO_PULL_MASK		0x0E
-#define	PM8058_GPIO_PULL_SHIFT		1
-
-/* Bank 3 */
-#define	PM8058_GPIO_OUT_STRENGTH_MASK	0x0C
-#define	PM8058_GPIO_OUT_STRENGTH_SHIFT	2
-#define	PM8058_GPIO_PIN_ENABLE		0x00
-#define	PM8058_GPIO_PIN_DISABLE		0x01
-
-/* Bank 4 */
-#define	PM8058_GPIO_FUNC_MASK		0x0E
-#define	PM8058_GPIO_FUNC_SHIFT		1
-
-/* Bank 5 */
-#define	PM8058_GPIO_NON_INT_POL_INV	0x08
-#define PM8058_GPIO_BANKS		6
-
-struct pm8058_gpio_chip {
-	struct gpio_chip	gpio_chip;
-	struct pm8058_chip	*pm_chip;
-	struct mutex		pm_lock;
-	u8			bank1[PM8058_GPIOS];
-};
-
-static int pm8058_gpio_get(struct pm8058_gpio_chip *chip, unsigned gpio)
-{
-	struct pm8058_gpio_platform_data	*pdata;
-	int	mode;
-
-	if (gpio >= PM8058_GPIOS || chip == NULL)
-		return -EINVAL;
-
-	pdata = chip->gpio_chip.dev->platform_data;
-
-	/* Get gpio value from config bank 1 if output gpio.
-	   Get gpio value from IRQ RT status register for all other gpio modes.
-	 */
-	mode = (chip->bank1[gpio] & PM8058_GPIO_MODE_MASK) >>
-		PM8058_GPIO_MODE_SHIFT;
-	if (mode == PM8058_GPIO_MODE_OUTPUT)
-		return chip->bank1[gpio] & PM8058_GPIO_OUT_INVERT;
-	else
-		return pm8058_irq_get_rt_status(chip->pm_chip,
-				pdata->irq_base + gpio);
-}
-
-static int pm8058_gpio_set(struct pm8058_gpio_chip *chip,
-		unsigned gpio, int value)
-{
-	int	rc;
-	u8	bank1;
-
-	if (gpio >= PM8058_GPIOS || chip == NULL)
-		return -EINVAL;
-
-	mutex_lock(&chip->pm_lock);
-	bank1 = chip->bank1[gpio] & ~PM8058_GPIO_OUT_INVERT;
-
-	if (value)
-		bank1 |= PM8058_GPIO_OUT_INVERT;
-
-	chip->bank1[gpio] = bank1;
-	rc = pm8058_write(chip->pm_chip, SSBI_REG_ADDR_GPIO(gpio), &bank1, 1);
-	mutex_unlock(&chip->pm_lock);
-
-	if (rc)
-		pr_err("%s: FAIL pm8058_write(): rc=%d. "
-		       "(gpio=%d, value=%d)\n",
-		       __func__, rc, gpio, value);
-
-	return rc;
-}
-
-static int pm8058_gpio_set_direction(struct pm8058_gpio_chip *chip,
-			      unsigned gpio, int direction)
-{
-	int	rc;
-	u8	bank1;
-	static int	dir_map[] = {
-		PM8058_GPIO_MODE_OFF,
-		PM8058_GPIO_MODE_OUTPUT,
-		PM8058_GPIO_MODE_INPUT,
-		PM8058_GPIO_MODE_BOTH,
-	};
-
-	if (!direction || chip == NULL)
-		return -EINVAL;
-
-	mutex_lock(&chip->pm_lock);
-	bank1 = chip->bank1[gpio] & ~PM8058_GPIO_MODE_MASK;
-
-	bank1 |= ((dir_map[direction] << PM8058_GPIO_MODE_SHIFT)
-		  & PM8058_GPIO_MODE_MASK);
-
-	chip->bank1[gpio] = bank1;
-	rc = pm8058_write(chip->pm_chip, SSBI_REG_ADDR_GPIO(gpio), &bank1, 1);
-	mutex_unlock(&chip->pm_lock);
-
-	if (rc)
-		pr_err("%s: Failed on pm8058_write(): rc=%d (GPIO config)\n",
-				__func__, rc);
-
-	return rc;
-}
-
-static int pm8058_gpio_init_bank1(struct pm8058_gpio_chip *chip)
-{
-	int i, rc;
-	u8 bank;
-
-	for (i = 0; i < PM8058_GPIOS; i++) {
-		bank = 1 << PM8058_GPIO_BANK_SHIFT;
-		rc = pm8058_write(chip->pm_chip,
-				SSBI_REG_ADDR_GPIO(i),
-				&bank, 1);
-		if (rc) {
-			pr_err("%s: error setting bank\n", __func__);
-			return rc;
-		}
-
-		rc = pm8058_read(chip->pm_chip,
-				SSBI_REG_ADDR_GPIO(i),
-				&chip->bank1[i], 1);
-		if (rc) {
-			pr_err("%s: error reading bank 1\n", __func__);
-			return rc;
-		}
-	}
-	return 0;
-}
-
-#ifndef CONFIG_GPIOLIB
-static int pm8058_gpio_configure(struct gpio_chip *chip,
-				 unsigned int gpio,
-				 unsigned long flags)
-{
-	int	rc = 0, direction;
-	struct pm8058_gpio_chip	*gpio_chip;
-
-	gpio -= chip->start;
-
-	if (flags & (GPIOF_INPUT | GPIOF_DRIVE_OUTPUT)) {
-		direction = 0;
-		if (flags & GPIOF_INPUT)
-			direction |= PM_GPIO_DIR_IN;
-		if (flags & GPIOF_DRIVE_OUTPUT)
-			direction |= PM_GPIO_DIR_OUT;
-
-		gpio_chip = dev_get_drvdata(chip->dev);
-
-		if (flags & (GPIOF_OUTPUT_LOW | GPIOF_OUTPUT_HIGH)) {
-			if (flags & GPIOF_OUTPUT_HIGH)
-				rc = pm8058_gpio_set(gpio_chip,
-						gpio, 1);
-			else
-				rc = pm8058_gpio_set(gpio_chip,
-						gpio, 0);
-
-			if (rc) {
-				pr_err("%s: FAIL pm8058_gpio_set(): rc=%d.\n",
-					__func__, rc);
-				goto bail_out;
-			}
-		}
-
-		rc = pm8058_gpio_set_direction(gpio_chip,
-				gpio, direction);
-		if (rc)
-			pr_err("%s: FAIL pm8058_gpio_config(): rc=%d.\n",
-				__func__, rc);
-	}
-
-bail_out:
-	return rc;
-}
-
-static int pm8058_gpio_get_irq_num(struct gpio_chip *chip,
-				   unsigned int gpio,
-				   unsigned int *irqp,
-				   unsigned long *irqnumflagsp)
-{
-	struct pm8058_gpio_platform_data *pdata;
-
-	pdata = chip->dev->platform_data;
-	gpio -= chip->start;
-	*irqp = pdata->irq_base + gpio;
-	if (irqnumflagsp)
-		*irqnumflagsp = 0;
-	return 0;
-}
-
-static int pm8058_gpio_read(struct gpio_chip *chip, unsigned n)
-{
-	struct pm8058_gpio_chip	*gpio_chip;
-
-	n -= chip->start;
-	gpio_chip = dev_get_drvdata(chip->dev);
-	return pm8058_gpio_get(gpio_chip, n);
-}
-
-static int pm8058_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on)
-{
-	struct pm8058_gpio_chip	*gpio_chip;
-
-	n -= chip->start;
-	gpio_chip = dev_get_drvdata(chip->dev);
-	return pm8058_gpio_set(gpio_chip, n, on);
-}
-
-static struct pm8058_gpio_chip pm8058_gpio_chip = {
-	.gpio_chip = {
-		.configure = pm8058_gpio_configure,
-		.get_irq_num = pm8058_gpio_get_irq_num,
-		.read = pm8058_gpio_read,
-		.write = pm8058_gpio_write,
-	},
-};
-
-static int __devinit pm8058_gpio_probe(struct platform_device *pdev)
-{
-	int	rc = 0;
-	struct pm8058_gpio_platform_data *pdata = pdev->dev.platform_data;
-
-	mutex_init(&pm8058_gpio_chip.pm_lock);
-	pm8058_gpio_chip.gpio_chip.dev = &pdev->dev;
-	pm8058_gpio_chip.gpio_chip.start = pdata->gpio_base;
-	pm8058_gpio_chip.gpio_chip.end = pdata->gpio_base +
-		PM8058_GPIOS - 1;
-	pm8058_gpio_chip.pm_chip = platform_get_drvdata(pdev);
-	platform_set_drvdata(pdev, &pm8058_gpio_chip);
-
-	rc = register_gpio_chip(&pm8058_gpio_chip.gpio_chip);
-	if (!rc)
-		goto bail;
-
-	rc = pm8058_gpio_init_bank1(&pm8058_gpio_chip);
-	if (rc)
-		goto bail;
-
-	if (pdata->init)
-		rc = pdata->init();
-
-bail:
-	if (rc)
-		platform_set_drvdata(pdev, pm8058_gpio_chip.pm_chip);
-
-	pr_info("%s: register_gpio_chip(): rc=%d\n", __func__, rc);
-	return rc;
-}
-
-static int __devexit pm8058_gpio_remove(struct platform_device *pdev)
-{
-	return 0;
-}
-
-#else
-
-static int pm8058_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
-	struct pm8058_gpio_platform_data *pdata;
-	pdata = chip->dev->platform_data;
-	return pdata->irq_base + offset;
-}
-
-static int pm8058_gpio_read(struct gpio_chip *chip, unsigned offset)
-{
-	struct pm8058_gpio_chip *gpio_chip;
-	gpio_chip = dev_get_drvdata(chip->dev);
-	return pm8058_gpio_get(gpio_chip, offset);
-}
-
-static void pm8058_gpio_write(struct gpio_chip *chip,
-		unsigned offset, int val)
-{
-	struct pm8058_gpio_chip *gpio_chip;
-	gpio_chip = dev_get_drvdata(chip->dev);
-	pm8058_gpio_set(gpio_chip, offset, val);
-}
-
-static int pm8058_gpio_direction_input(struct gpio_chip *chip,
-		unsigned offset)
-{
-	struct pm8058_gpio_chip *gpio_chip;
-	gpio_chip = dev_get_drvdata(chip->dev);
-	return pm8058_gpio_set_direction(gpio_chip, offset, PM_GPIO_DIR_IN);
-}
-
-static int pm8058_gpio_direction_output(struct gpio_chip *chip,
-		unsigned offset,
-		int val)
-{
-	struct pm8058_gpio_chip *gpio_chip;
-	int ret;
-
-	gpio_chip = dev_get_drvdata(chip->dev);
-	ret = pm8058_gpio_set_direction(gpio_chip, offset, PM_GPIO_DIR_OUT);
-	if (!ret)
-		ret = pm8058_gpio_set(gpio_chip, offset, val);
-
-	return ret;
-}
-
-static void pm8058_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
-{
-	static const char *cmode[] = { "in", "in/out", "out", "off" };
-	struct pm8058_gpio_chip *gpio_chip = dev_get_drvdata(chip->dev);
-	u8 mode, state, bank;
-	const char *label;
-	int i, j;
-
-	for (i = 0; i < PM8058_GPIOS; i++) {
-		label = gpiochip_is_requested(chip, i);
-		mode = (gpio_chip->bank1[i] & PM8058_GPIO_MODE_MASK) >>
-			PM8058_GPIO_MODE_SHIFT;
-		state = pm8058_gpio_get(gpio_chip, i);
-		seq_printf(s, "gpio-%-3d (%-12.12s) %-10.10s"
-				" %s",
-				chip->base + i,
-				label ? label : "--",
-				cmode[mode],
-				state ? "hi" : "lo");
-		for (j = 0; j < PM8058_GPIO_BANKS; j++) {
-			bank = j << PM8058_GPIO_BANK_SHIFT;
-			pm8058_write(gpio_chip->pm_chip,
-					SSBI_REG_ADDR_GPIO(i),
-					&bank, 1);
-			pm8058_read(gpio_chip->pm_chip,
-					SSBI_REG_ADDR_GPIO(i),
-					&bank, 1);
-			seq_printf(s, " 0x%02x", bank);
-		}
-		seq_printf(s, "\n");
-	}
-}
-
-static struct pm8058_gpio_chip pm8058_gpio_chip = {
-	.gpio_chip = {
-		.label			= "pm8058-gpio",
-		.direction_input	= pm8058_gpio_direction_input,
-		.direction_output	= pm8058_gpio_direction_output,
-		.to_irq			= pm8058_gpio_to_irq,
-		.get			= pm8058_gpio_read,
-		.set			= pm8058_gpio_write,
-		.dbg_show		= pm8058_gpio_dbg_show,
-		.ngpio			= PM8058_GPIOS,
-		.can_sleep		= 1,
-	},
-};
-
-static int __devinit pm8058_gpio_probe(struct platform_device *pdev)
-{
-	int ret;
-	struct pm8058_gpio_platform_data *pdata = pdev->dev.platform_data;
-
-	mutex_init(&pm8058_gpio_chip.pm_lock);
-	pm8058_gpio_chip.gpio_chip.dev = &pdev->dev;
-	pm8058_gpio_chip.gpio_chip.base = pdata->gpio_base;
-	pm8058_gpio_chip.pm_chip = dev_get_drvdata(pdev->dev.parent);
-	platform_set_drvdata(pdev, &pm8058_gpio_chip);
-
-	ret = gpiochip_add(&pm8058_gpio_chip.gpio_chip);
-	if (ret)
-		goto unset_drvdata;
-
-	ret = pm8058_gpio_init_bank1(&pm8058_gpio_chip);
-	if (ret)
-		goto remove_chip;
-
-	if (pdata->init)
-		ret = pdata->init();
-	if (!ret)
-		goto ok;
-
-remove_chip:
-	if (gpiochip_remove(&pm8058_gpio_chip.gpio_chip))
-		pr_err("%s: failed to remove gpio chip\n", __func__);
-unset_drvdata:
-	platform_set_drvdata(pdev, pm8058_gpio_chip.pm_chip);
-ok:
-	pr_info("%s: gpiochip_add(): rc=%d\n", __func__, ret);
-
-	return ret;
-}
-
-static int __devexit pm8058_gpio_remove(struct platform_device *pdev)
-{
-	return gpiochip_remove(&pm8058_gpio_chip.gpio_chip);
-}
-
-#endif
-
-int pm8058_gpio_config(int gpio, struct pm8058_gpio *param)
-{
-	int	rc;
-	u8	bank[8];
-	static int	dir_map[] = {
-		PM8058_GPIO_MODE_OFF,
-		PM8058_GPIO_MODE_OUTPUT,
-		PM8058_GPIO_MODE_INPUT,
-		PM8058_GPIO_MODE_BOTH,
-	};
-
-	if (param == NULL)
-		return -EINVAL;
-
-	/* Select banks and configure the gpio */
-	bank[0] = PM8058_GPIO_WRITE |
-		((param->vin_sel << PM8058_GPIO_VIN_SHIFT) &
-			PM8058_GPIO_VIN_MASK) |
-		PM8058_GPIO_MODE_ENABLE;
-	bank[1] = PM8058_GPIO_WRITE |
-		((1 << PM8058_GPIO_BANK_SHIFT) &
-			PM8058_GPIO_BANK_MASK) |
-		((dir_map[param->direction] <<
-			PM8058_GPIO_MODE_SHIFT) &
-			PM8058_GPIO_MODE_MASK) |
-		((param->direction & PM_GPIO_DIR_OUT) ?
-			((param->output_buffer & 1) ?
-			 PM8058_GPIO_OUT_BUFFER : 0) : 0) |
-		((param->direction & PM_GPIO_DIR_OUT) ?
-			param->output_value & 0x01 : 0);
-	bank[2] = PM8058_GPIO_WRITE |
-		((2 << PM8058_GPIO_BANK_SHIFT) &
-			PM8058_GPIO_BANK_MASK) |
-		((param->pull << PM8058_GPIO_PULL_SHIFT) &
-			PM8058_GPIO_PULL_MASK);
-	bank[3] = PM8058_GPIO_WRITE |
-		((3 << PM8058_GPIO_BANK_SHIFT) &
-			PM8058_GPIO_BANK_MASK) |
-		((param->out_strength <<
-			PM8058_GPIO_OUT_STRENGTH_SHIFT) &
-			PM8058_GPIO_OUT_STRENGTH_MASK) |
-		(param->disable_pin ?
-			PM8058_GPIO_PIN_DISABLE : PM8058_GPIO_PIN_ENABLE);
-	bank[4] = PM8058_GPIO_WRITE |
-		((4 << PM8058_GPIO_BANK_SHIFT) &
-			PM8058_GPIO_BANK_MASK) |
-		((param->function << PM8058_GPIO_FUNC_SHIFT) &
-			PM8058_GPIO_FUNC_MASK);
-	bank[5] = PM8058_GPIO_WRITE |
-		((5 << PM8058_GPIO_BANK_SHIFT) & PM8058_GPIO_BANK_MASK) |
-		(param->inv_int_pol ? 0 : PM8058_GPIO_NON_INT_POL_INV);
-
-	mutex_lock(&pm8058_gpio_chip.pm_lock);
-	/* Remember bank1 for later use */
-	pm8058_gpio_chip.bank1[gpio] = bank[1];
-	rc = pm8058_write(pm8058_gpio_chip.pm_chip,
-			SSBI_REG_ADDR_GPIO(gpio), bank, 6);
-	mutex_unlock(&pm8058_gpio_chip.pm_lock);
-
-	if (rc)
-		pr_err("%s: Failed on pm8058_write(): rc=%d (GPIO config)\n",
-				__func__, rc);
-
-	return rc;
-}
-EXPORT_SYMBOL(pm8058_gpio_config);
-
-static struct platform_driver pm8058_gpio_driver = {
-	.probe		= pm8058_gpio_probe,
-	.remove		= __devexit_p(pm8058_gpio_remove),
-	.driver		= {
-		.name = "pm8058-gpio",
-		.owner = THIS_MODULE,
-	},
-};
-
-#if defined(CONFIG_DEBUG_FS)
-
-#define DEBUG_MAX_RW_BUF   128
-#define DEBUG_MAX_FNAME    8
-
-static struct dentry *debug_dent;
-
-static char debug_read_buf[DEBUG_MAX_RW_BUF];
-static char debug_write_buf[DEBUG_MAX_RW_BUF];
-
-static int debug_gpios[PM8058_GPIOS];
-
-static int debug_open(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
-static int debug_read_gpio_bank(int gpio, int bank, u8 *data)
-{
-	int rc;
-
-	mutex_lock(&pm8058_gpio_chip.pm_lock);
-
-	*data = bank << PM8058_GPIO_BANK_SHIFT;
-	rc = pm8058_write(pm8058_gpio_chip.pm_chip,
-			SSBI_REG_ADDR_GPIO(gpio), data, 1);
-	if (rc)
-		goto bail_out;
-
-	*data = bank << PM8058_GPIO_BANK_SHIFT;
-	rc = pm8058_read(pm8058_gpio_chip.pm_chip,
-			SSBI_REG_ADDR_GPIO(gpio), data, 1);
-
-bail_out:
-	mutex_unlock(&pm8058_gpio_chip.pm_lock);
-
-	return rc;
-}
-
-static ssize_t debug_read(struct file *file, char __user *buf,
-			  size_t count, loff_t *ppos)
-{
-	int gpio = *((int *) file->private_data);
-	int len = 0;
-	int rc = -EINVAL;
-	u8 bank[PM8058_GPIO_BANKS];
-	int val = -1;
-	int mode;
-	int i;
-
-	for (i = 0; i < PM8058_GPIO_BANKS; i++) {
-		rc = debug_read_gpio_bank(gpio, i, &bank[i]);
-		if (rc)
-			pr_err("pmic failed to read bank %d\n", i);
-	}
-
-	if (rc) {
-		len = snprintf(debug_read_buf, DEBUG_MAX_RW_BUF - 1, "-1\n");
-		goto bail_out;
-	}
-
-	val = pm8058_gpio_get(&pm8058_gpio_chip, gpio);
-
-	/* print the mode and the value */
-	mode = (bank[1] & PM8058_GPIO_MODE_MASK) >>  PM8058_GPIO_MODE_SHIFT;
-	if (mode == PM8058_GPIO_MODE_BOTH)
-		len = snprintf(debug_read_buf, DEBUG_MAX_RW_BUF - 1,
-			       "BOTH %d ", val);
-	else if (mode == PM8058_GPIO_MODE_INPUT)
-		len = snprintf(debug_read_buf, DEBUG_MAX_RW_BUF - 1,
-			       "IN   %d ", val);
-	else if (mode == PM8058_GPIO_MODE_OUTPUT)
-		len = snprintf(debug_read_buf, DEBUG_MAX_RW_BUF - 1,
-			       "OUT  %d ", val);
-	else
-		len = snprintf(debug_read_buf, DEBUG_MAX_RW_BUF - 1,
-			       "OFF  %d ", val);
-
-	/* print the control register values */
-	len += snprintf(debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
-			"[0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x]\n",
-			bank[0], bank[1], bank[2], bank[3], bank[4], bank[5]);
-
-bail_out:
-	rc = simple_read_from_buffer((void __user *) buf, len,
-				     ppos, (void *) debug_read_buf, len);
-
-	return rc;
-}
-
-static ssize_t debug_write(struct file *file, const char __user *buf,
-			   size_t count, loff_t *ppos)
-{
-	int gpio = *((int *) file->private_data);
-	unsigned long val;
-	int mode, rc;
-
-	mode = (pm8058_gpio_chip.bank1[gpio] & PM8058_GPIO_MODE_MASK) >>
-		PM8058_GPIO_MODE_SHIFT;
-	if (mode == PM8058_GPIO_MODE_OFF || mode == PM8058_GPIO_MODE_INPUT)
-		return count;
-
-	if (count > sizeof(debug_write_buf))
-		return -EFAULT;
-
-	if (copy_from_user(debug_write_buf, buf, count)) {
-		pr_err("failed to copy from user\n");
-		return -EFAULT;
-	}
-	debug_write_buf[count] = '\0';
-
-	rc = strict_strtoul(debug_write_buf, 10, &val);
-	if (rc)
-		return rc;
-
-	if (pm8058_gpio_set(&pm8058_gpio_chip, gpio, val)) {
-		pr_err("gpio write failed\n");
-		return -EINVAL;
-	}
-
-	return count;
-}
-
-static const struct file_operations debug_ops = {
-	.open =         debug_open,
-	.read =         debug_read,
-	.write =        debug_write,
-};
-
-static void debug_init(void)
-{
-	int i;
-	char name[DEBUG_MAX_FNAME];
-
-	debug_dent = debugfs_create_dir("pm_gpio", NULL);
-	if (IS_ERR(debug_dent)) {
-		pr_err("pmic8058 debugfs_create_dir fail, error %ld\n",
-		       PTR_ERR(debug_dent));
-		return;
-	}
-
-	for (i = 0; i < PM8058_GPIOS; i++) {
-		snprintf(name, DEBUG_MAX_FNAME-1, "%d", i+1);
-		debug_gpios[i] = i;
-		if (debugfs_create_file(name, 0644, debug_dent,
-					&debug_gpios[i], &debug_ops) == NULL) {
-			pr_err("pmic8058 debugfs_create_file %s failed\n",
-			       name);
-		}
-	}
-}
-
-static void debug_exit(void)
-{
-	debugfs_remove_recursive(debug_dent);
-}
-
-#else
-static void debug_init(void) { }
-static void debug_exit(void) { }
-#endif
-
-static int __init pm8058_gpio_init(void)
-{
-	int rc = platform_driver_register(&pm8058_gpio_driver);
-	if (!rc)
-		debug_init();
-	return rc;
-}
-
-static void __exit pm8058_gpio_exit(void)
-{
-	platform_driver_unregister(&pm8058_gpio_driver);
-	debug_exit();
-}
-
-subsys_initcall(pm8058_gpio_init);
-module_exit(pm8058_gpio_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("PMIC8058 GPIO driver");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:pm8058-gpio");
diff --git a/arch/arm/mach-msm/pmic8058-mpp.c b/arch/arm/mach-msm/pmic8058-mpp.c
deleted file mode 100644
index 78a132a5..0000000
--- a/arch/arm/mach-msm/pmic8058-mpp.c
+++ /dev/null
@@ -1,258 +0,0 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. 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 version 2 and
- * only 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.
- *
- */
-/*
- * Qualcomm PMIC8058 MPP driver
- *
- */
-
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/mfd/pmic8058.h>
-#include <mach/mpp.h>
-#include <linux/seq_file.h>
-
-#ifndef CONFIG_GPIOLIB
-#include "gpio_chip.h"
-#endif
-
-/* MPP Control Registers */
-#define	SSBI_MPP_CNTRL_BASE		0x50
-#define	SSBI_MPP_CNTRL(n)		(SSBI_MPP_CNTRL_BASE + (n))
-
-/* MPP Type */
-#define	PM8058_MPP_TYPE_MASK		0xE0
-#define	PM8058_MPP_TYPE_SHIFT		5
-
-/* MPP Config Level */
-#define	PM8058_MPP_CONFIG_LVL_MASK	0x1C
-#define	PM8058_MPP_CONFIG_LVL_SHIFT	2
-
-/* MPP Config Control */
-#define	PM8058_MPP_CONFIG_CTL_MASK	0x03
-
-static int pm8058_mpp_get(struct gpio_chip *chip, unsigned mpp)
-{
-	struct pm8058_gpio_platform_data *pdata;
-	struct pm8058_chip *pm_chip;
-
-	if (mpp >= PM8058_MPPS || chip == NULL)
-		return -EINVAL;
-
-	pdata = chip->dev->platform_data;
-	pm_chip = dev_get_drvdata(chip->dev->parent);
-
-	return pm8058_irq_get_rt_status(pm_chip,
-		pdata->irq_base + mpp);
-}
-
-#ifndef CONFIG_GPIOLIB
-static int pm8058_mpp_get_irq_num(struct gpio_chip *chip,
-				   unsigned int gpio,
-				   unsigned int *irqp,
-				   unsigned long *irqnumflagsp)
-{
-	struct pm8058_gpio_platform_data *pdata;
-
-	pdata = chip->dev->platform_data;
-	gpio -= chip->start;
-	*irqp = pdata->irq_base + gpio;
-	if (irqnumflagsp)
-		*irqnumflagsp = 0;
-	return 0;
-}
-
-static int pm8058_mpp_read(struct gpio_chip *chip, unsigned n)
-{
-	n -= chip->start;
-	return pm8058_mpp_get(chip, n);
-}
-
-struct msm_gpio_chip pm8058_mpp_chip = {
-	.chip = {
-		.get_irq_num = pm8058_mpp_get_irq_num,
-		.read = pm8058_mpp_read,
-	}
-};
-
-int pm8058_mpp_config(unsigned mpp, unsigned type, unsigned level,
-		      unsigned control)
-{
-	u8	config;
-	int	rc;
-	struct pm8058_chip *pm_chip;
-
-	if (mpp >= PM8058_MPPS)
-		return -EINVAL;
-
-	pm_chip = dev_get_drvdata(pm8058_mpp_chip->dev->parent);
-
-	config = (type << PM8058_MPP_TYPE_SHIFT) & PM8058_MPP_TYPE_MASK;
-	config |= (level << PM8058_MPP_CONFIG_LVL_SHIFT) &
-			PM8058_MPP_CONFIG_LVL_MASK;
-	config |= control & PM8058_MPP_CONFIG_CTL_MASK;
-
-	rc = pm8058_write(pm_chip, SSBI_MPP_CNTRL(mpp), &config, 1);
-	if (rc)
-		pr_err("%s: pm8058_write(): rc=%d\n", __func__, rc);
-
-	return rc;
-}
-EXPORT_SYMBOL(pm8058_mpp_config);
-
-static int __devinit pm8058_mpp_probe(struct platform_device *pdev)
-{
-	int	rc;
-	struct pm8058_gpio_platform_data *pdata = pdev->dev.platform_data;
-
-	pm8058_mpp_chip.chip.dev = &pdev->dev;
-	pm8058_mpp_chip.chip.start = pdata->gpio_base;
-	pm8058_mpp_chip.chip.end = pdata->gpio_base + PM8058_MPPS - 1;
-	rc = register_gpio_chip(&pm8058_mpp_chip.chip);
-	if (!rc) {
-		if (pdata->init)
-			ret = pdata->init();
-	}
-	pr_info("%s: register_gpio_chip(): rc=%d\n", __func__, rc);
-
-	return rc;
-}
-
-static int __devexit pm8058_mpp_remove(struct platform_device *pdev)
-{
-	return 0;
-}
-
-#else
-
-static int pm8058_mpp_to_irq(struct gpio_chip *chip, unsigned offset)
-{
-	struct pm8058_gpio_platform_data *pdata;
-	pdata = chip->dev->platform_data;
-	return pdata->irq_base + offset;
-}
-
-static int pm8058_mpp_read(struct gpio_chip *chip, unsigned offset)
-{
-	return pm8058_mpp_get(chip, offset);
-}
-
-static void pm8058_mpp_dbg_show(struct seq_file *s, struct gpio_chip *chip)
-{
-	static const char *ctype[] = { "d_in", "d_out", "bi_dir", "a_in",
-		"a_out", "sink", "dtest_sink", "dtest_out" };
-	struct pm8058_chip *pm_chip = dev_get_drvdata(chip->dev->parent);
-	u8 type, state, ctrl;
-	const char *label;
-	int i;
-
-	for (i = 0; i < PM8058_MPPS; i++) {
-		pm8058_read(pm_chip, SSBI_MPP_CNTRL(i), &ctrl, 1);
-		label = gpiochip_is_requested(chip, i);
-		type = (ctrl & PM8058_MPP_TYPE_MASK) >>
-			PM8058_MPP_TYPE_SHIFT;
-		state = pm8058_mpp_get(chip, i);
-		seq_printf(s, "gpio-%-3d (%-12.12s) %-10.10s"
-				" %s 0x%02x\n",
-				chip->base + i,
-				label ? label : "--",
-				ctype[type],
-				state ? "hi" : "lo",
-				ctrl);
-	}
-}
-
-static struct gpio_chip pm8058_mpp_chip = {
-	.label		= "pm8058-mpp",
-	.to_irq		= pm8058_mpp_to_irq,
-	.get		= pm8058_mpp_read,
-	.dbg_show	= pm8058_mpp_dbg_show,
-	.ngpio		= PM8058_MPPS,
-	.can_sleep	= 1,
-};
-
-int pm8058_mpp_config(unsigned mpp, unsigned type, unsigned level,
-		      unsigned control)
-{
-	u8	config;
-	int	rc;
-	struct pm8058_chip *pm_chip;
-
-	if (mpp >= PM8058_MPPS)
-		return -EINVAL;
-
-	pm_chip = dev_get_drvdata(pm8058_mpp_chip.dev->parent);
-
-	config = (type << PM8058_MPP_TYPE_SHIFT) & PM8058_MPP_TYPE_MASK;
-	config |= (level << PM8058_MPP_CONFIG_LVL_SHIFT) &
-			PM8058_MPP_CONFIG_LVL_MASK;
-	config |= control & PM8058_MPP_CONFIG_CTL_MASK;
-
-	rc = pm8058_write(pm_chip, SSBI_MPP_CNTRL(mpp), &config, 1);
-	if (rc)
-		pr_err("%s: pm8058_write(): rc=%d\n", __func__, rc);
-
-	return rc;
-}
-EXPORT_SYMBOL(pm8058_mpp_config);
-
-static int __devinit pm8058_mpp_probe(struct platform_device *pdev)
-{
-	int ret;
-	struct pm8058_gpio_platform_data *pdata = pdev->dev.platform_data;
-
-	pm8058_mpp_chip.dev = &pdev->dev;
-	pm8058_mpp_chip.base = pdata->gpio_base;
-	ret = gpiochip_add(&pm8058_mpp_chip);
-	if (!ret) {
-		if (pdata->init)
-			ret = pdata->init();
-	}
-
-	pr_info("%s: gpiochip_add(): ret=%d\n", __func__, ret);
-	return ret;
-}
-
-static int __devexit pm8058_mpp_remove(struct platform_device *pdev)
-{
-	return gpiochip_remove(&pm8058_mpp_chip);
-}
-
-#endif
-
-static struct platform_driver pm8058_mpp_driver = {
-	.probe		= pm8058_mpp_probe,
-	.remove		= __devexit_p(pm8058_mpp_remove),
-	.driver		= {
-		.name = "pm8058-mpp",
-		.owner = THIS_MODULE,
-	},
-};
-
-static int __init pm8058_mpp_init(void)
-{
-	return platform_driver_register(&pm8058_mpp_driver);
-}
-
-static void __exit pm8058_mpp_exit(void)
-{
-	platform_driver_unregister(&pm8058_mpp_driver);
-}
-
-subsys_initcall(pm8058_mpp_init);
-module_exit(pm8058_mpp_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("PMIC8058 MPP driver");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:pm8058-mpp");
-
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c b/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c
index 6166de2..60b5c20 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c
@@ -372,10 +372,8 @@
 	memset(&cmd, 0, sizeof(cmd));
 	if (audio->build_id[17] == '1') {
 		cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ENC_CFG_2;
-		MM_ERR("sending AUDPREPROC_AUDREC_CMD_ENC_CFG_2 command");
 	} else {
 		cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ENC_CFG;
-		MM_ERR("sending AUDPREPROC_AUDREC_CMD_ENC_CFG command");
 	}
 	cmd.stream_id = audio->enc_id;
 
@@ -950,7 +948,7 @@
 		goto evt_error;
 	}
 	audio->build_id = socinfo_get_build_id();
-	MM_ERR("build id used is = %s\n", audio->build_id);
+	MM_DBG("Modem build id = %s\n", audio->build_id);
 	file->private_data = audio;
 	audio->opened = 1;
 	rc = 0;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_aac_in.c b/arch/arm/mach-msm/qdsp5v2/audio_aac_in.c
index da77140..010fd90 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_aac_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_aac_in.c
@@ -575,7 +575,6 @@
 {
 	struct audpreproc_audrec_cmd_enc_cfg cmd;
 	memset(&cmd, 0, sizeof(cmd));
-	MM_ERR("build_id[17] = %c", audio->build_id[17]);
 	if (audio->build_id[17] == '1') {
 		cmd.cmd_id = AUDPREPROC_AUDREC_CMD_ENC_CFG_2;
 		MM_ERR("sending AUDPREPROC_AUDREC_CMD_ENC_CFG_2 command");
@@ -1412,9 +1411,8 @@
 		MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
 				audio->out_phys, (int)audio->out_data);
 	}
-	MM_ERR("trying to get the build id\n");
 	audio->build_id = socinfo_get_build_id();
-	MM_ERR("build id used is = %s\n", audio->build_id);
+	MM_DBG("Modem build id = %s\n", audio->build_id);
 
 		/* Initialize buffer */
 	audio->out[0].data = audio->out_data + 0;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_acdb.c b/arch/arm/mach-msm/qdsp5v2/audio_acdb.c
index ec275b4..90373f9 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_acdb.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_acdb.c
@@ -3288,7 +3288,6 @@
 	result = acdb_initialize_data();
 	if (result)
 		goto done;
-	MM_ERR("acdb_data.build_id[17] = %c\n", acdb_data.build_id[17]);
 	if (acdb_data.build_id[17] != '0') {
 		result = initialize_modem_acdb();
 		if (result < 0)
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c b/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
index e1af44f..bdb5bb1 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
@@ -863,7 +863,7 @@
 		goto evt_error;
 	}
 	audio->build_id = socinfo_get_build_id();
-	MM_ERR("build id used is = %s\n", audio->build_id);
+	MM_DBG("Modem build id = %s\n", audio->build_id);
 
 	file->private_data = audio;
 	audio->opened = 1;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c b/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c
index c086153..50621c9 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c
@@ -1470,7 +1470,7 @@
 	audio->opened = 1;
 	audio->out_frame_cnt++;
 	audio->build_id = socinfo_get_build_id();
-	MM_ERR("build id used is = %s\n", audio->build_id);
+	MM_DBG("Modem build id = %s\n", audio->build_id);
 
 done:
 	mutex_unlock(&audio->lock);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c b/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
index 43f3d26..a5a9bd2 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
@@ -638,7 +638,6 @@
 			rc = -EFAULT;
 			break;
 		}
-		MM_ERR("build_id[17] = %c\n", audio->build_id[17]);
 		if (audio->build_id[17] == '1') {
 			audio->enc_type = ENC_TYPE_EXT_WAV | audio->mode;
 			if (cfg.channel_count == 1) {
@@ -683,7 +682,6 @@
 			MM_ERR("wrong build_id = %s\n", audio->build_id);
 			return -ENODEV;
 		}
-		MM_ERR("buffer size configured is = %d\n", audio->buffer_size);
 		audio->samp_rate = cfg.sample_rate;
 		audio->channel_mode = cfg.channel_count;
 		break;
@@ -941,7 +939,7 @@
 	audio->opened = 1;
 	rc = 0;
 	audio->build_id = socinfo_get_build_id();
-	MM_ERR("build id used is = %s\n", audio->build_id);
+	MM_DBG("Modem build id = %s\n", audio->build_id);
 done:
 	mutex_unlock(&audio->lock);
 	return rc;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
index 11599f8..d34499d 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
@@ -1475,7 +1475,7 @@
 	audio->opened = 1;
 	audio->out_frame_cnt++;
 	audio->build_id = socinfo_get_build_id();
-	MM_ERR("build id used is = %s\n", audio->build_id);
+	MM_DBG("Modem build id = %s\n", audio->build_id);
 done:
 	mutex_unlock(&audio->lock);
 	return rc;
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
index 196808e..2ad7f86 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
@@ -21,8 +21,6 @@
 
 
 #define MAX_NETWORKS		12
-#define ACDB_BLOCK_SIZE		4096
-#define NUM_VOCPROC_BLOCKS	(3 * MAX_NETWORKS)
 
 struct acdb_data {
 	struct mutex		acdb_mutex;
@@ -200,26 +198,6 @@
 	return;
 }
 
-void get_audproc_buffer_data(struct audproc_buffer_data *cal_buffers)
-{
-	int i;
-	pr_debug("%s\n", __func__);
-
-	if (cal_buffers == NULL) {
-		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
-		goto done;
-	}
-
-	for (i = 0; i < NUM_AUDPROC_BUFFERS; i++) {
-		cal_buffers->phys_addr[i] = (uint32_t)
-			(acdb_data.paddr +
-			(NUM_VOCPROC_BLOCKS + i) * ACDB_BLOCK_SIZE);
-		cal_buffers->buf_size[i] = ACDB_BLOCK_SIZE;
-	}
-done:
-	return;
-}
-
 void store_audproc_cal(int32_t path, struct cal_block *cal_block)
 {
 	pr_debug("%s, path = %d\n", __func__, path);
@@ -612,12 +590,9 @@
 static int deregister_pmem(void)
 {
 	int result;
-	struct audproc_buffer_data buffer;
 
-	get_audproc_buffer_data(&buffer);
-
-	result = adm_memory_unmap_regions(buffer.phys_addr,
-			buffer.buf_size, NUM_AUDPROC_BUFFERS);
+	result = adm_memory_unmap_regions((uint32_t *)&acdb_data.paddr,
+			(uint32_t *)&acdb_data.pmem_len, 1);
 
 	if (result < 0)
 		pr_err("Audcal unmap did not work!\n");
@@ -632,7 +607,6 @@
 static int register_pmem(void)
 {
 	int result;
-	struct audproc_buffer_data buffer;
 
 	result = get_pmem_file(acdb_data.pmem_fd, &acdb_data.paddr,
 				&acdb_data.kvaddr, &acdb_data.pmem_len,
@@ -646,10 +620,8 @@
 	pr_debug("AUDIO_REGISTER_PMEM done! paddr = 0x%lx, "
 		"kvaddr = 0x%lx, len = x%lx\n", acdb_data.paddr,
 		acdb_data.kvaddr, acdb_data.pmem_len);
-	get_audproc_buffer_data(&buffer);
-	result = adm_memory_map_regions(buffer.phys_addr, 0,
-			buffer.buf_size,
-			NUM_AUDPROC_BUFFERS);
+	result = adm_memory_map_regions((uint32_t *)&acdb_data.paddr, 0,
+			(uint32_t *)&acdb_data.pmem_len, 1);
 	if (result < 0)
 		pr_err("Audcal mmap did not work!\n");
 	goto done;
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c
index d48df06..b60140e 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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 version 2 and
@@ -21,7 +21,7 @@
 #include "q6usm.h"
 
 /* The driver version*/
-#define DRV_VERSION "1.0"
+#define DRV_VERSION "1.1"
 
 #define SESSION_MAX 0x02 /* aDSP:USM limit */
 
@@ -40,9 +40,6 @@
 /* Standard timeout in the asynchronous ops */
 #define Q6USM_TIMEOUT_JIFFIES	(3*HZ) /* 3 sec */
 
-/* cyclic buffer with 1 gap support */
-#define USM_MIN_BUF_CNT 3
-
 static DEFINE_MUTEX(session_lock);
 
 static struct us_client *session[SESSION_MAX];
@@ -236,8 +233,7 @@
 
 	if ((usc == NULL) ||
 	    ((dir != IN) && (dir != OUT)) || (size == 0) ||
-	    (usc->session <= 0 || usc->session > SESSION_MAX) ||
-	    (bufcnt < USM_MIN_BUF_CNT)) {
+	    (usc->session <= 0 || usc->session > SESSION_MAX)) {
 		pr_err("%s: wrong parameters: size=%d; bufcnt=%d\n",
 		       __func__, size, bufcnt);
 		return -EINVAL;
@@ -345,6 +341,7 @@
 			case USM_STREAM_CMD_OPEN_WRITE:
 			case USM_STREAM_CMD_SET_ENC_PARAM:
 			case USM_DATA_CMD_MEDIA_FORMAT_UPDATE:
+			case USM_SESSION_CMD_SIGNAL_DETECT_MODE:
 				if (atomic_read(&usc->cmd_state)) {
 					atomic_set(&usc->cmd_state, 0);
 					wake_up(&usc->cmd_wait);
@@ -449,6 +446,14 @@
 		break;
 	} /* case USM_DATA_EVENT_WRITE_DONE */
 
+	case USM_SESSION_EVENT_SIGNAL_DETECT_RESULT: {
+		pr_debug("%s: US detect result: result=%d",
+			 __func__,
+			 payload[0]);
+
+		break;
+	} /* case USM_SESSION_EVENT_SIGNAL_DETECT_RESULT */
+
 	default:
 		pr_debug("%s: not supported code [0x%x]",
 			 __func__, data->opcode);
@@ -1147,6 +1152,46 @@
 	return rc;
 }
 
+int q6usm_set_us_detection(struct us_client *usc,
+			   struct usm_session_cmd_detect_info *detect_info,
+			   uint16_t detect_info_size)
+{
+	int rc = 0;
+
+	if ((usc == NULL) ||
+	    (detect_info_size == 0) ||
+	    (detect_info == NULL)) {
+		pr_err("%s: wrong input: usc=0x%p, inf_size=%d; info=0x%p",
+		       __func__,
+		       usc,
+		       detect_info_size,
+		       detect_info);
+		return -EINVAL;
+	}
+
+	q6usm_add_hdr(usc, &detect_info->hdr,
+		      detect_info_size - APR_HDR_SIZE, true);
+
+	detect_info->hdr.opcode = USM_SESSION_CMD_SIGNAL_DETECT_MODE;
+
+	rc = apr_send_pkt(usc->apr, (uint32_t *)detect_info);
+	if (rc < 0) {
+		pr_err("%s:Comamnd signal detect failed\n", __func__);
+		return -EINVAL;
+	}
+	rc = wait_event_timeout(usc->cmd_wait,
+				(atomic_read(&usc->cmd_state) == 0),
+				Q6USM_TIMEOUT_JIFFIES);
+	if (!rc) {
+		rc = -ETIME;
+		pr_err("%s: CMD_SIGNAL_DETECT_MODE: timeout=%d\n",
+		       __func__, Q6USM_TIMEOUT_JIFFIES);
+	} else
+		rc = 0;
+
+	return rc;
+}
+
 static int __init q6usm_init(void)
 {
 	pr_debug("%s\n", __func__);
@@ -1159,4 +1204,3 @@
 
 MODULE_DESCRIPTION("Interface with QDSP6:USM");
 MODULE_VERSION(DRV_VERSION);
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
index fe12ee1..1338e86 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/q6usm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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 version 2 and
@@ -15,6 +15,9 @@
 
 #include <mach/qdsp6v2/apr_us.h>
 
+/* cyclic buffer with 1 gap support */
+#define USM_MIN_BUF_CNT 3
+
 #define FORMAT_USPS_EPOS	0x00000000
 #define FORMAT_USRAW		0x00000001
 #define INVALID_FORMAT		0xffffffff
@@ -106,4 +109,8 @@
 int q6usm_write(struct us_client *usc, uint32_t write_ind);
 bool q6usm_is_write_buf_full(struct us_client *usc, uint32_t* free_region);
 
+int q6usm_set_us_detection(struct us_client *usc,
+			   struct usm_session_cmd_detect_info *detect_info,
+			   uint16_t detect_info_size);
+
 #endif /* __Q6_USM_H__ */
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
index bfe0006..bc0706e 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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 version 2 and
@@ -26,7 +26,7 @@
 #include "q6usm.h"
 
 /* The driver version*/
-#define DRV_VERSION "1.0"
+#define DRV_VERSION "1.1.1"
 
 /* Standard timeout in the asynchronous ops */
 #define USF_TIMEOUT_JIFFIES (3*HZ) /* 3 sec */
@@ -37,6 +37,9 @@
 /* RX memory mapping flag */
 #define	USF_VM_WRITE	2
 
+/* Number of events, copied from the user space to kernel one */
+#define USF_EVENTS_PORTION_SIZE 20
+
 /* The driver states */
 enum usf_state_type {
 	USF_IDLE_STATE,
@@ -46,6 +49,13 @@
 	USF_ERROR_STATE
 };
 
+/* The US detection status upon FW/HW based US detection results */
+enum usf_us_detect_type {
+	USF_US_DETECT_UNDEF,
+	USF_US_DETECT_YES,
+	USF_US_DETECT_NO
+};
+
 struct usf_xx_type {
 	/* Name of the client - event calculator */
 	char client_name[USF_MAX_CLIENT_NAME_SIZE];
@@ -66,6 +76,8 @@
 	uint32_t prev_region;
 	/* Q6:USM's events handler */
 	void (*cb)(uint32_t, uint32_t, uint32_t *, void *);
+	/* US detection result */
+	enum usf_us_detect_type us_detect_type;
 	/* User's update info isn't acceptable */
 	u8 user_upd_info_na;
 };
@@ -127,6 +139,14 @@
 		wake_up(&usf_xx->wait);
 		break;
 
+	case USM_SESSION_EVENT_SIGNAL_DETECT_RESULT:
+		usf_xx->us_detect_type = (payload[0]) ?
+					USF_US_DETECT_YES :
+					USF_US_DETECT_NO;
+
+		wake_up(&usf_xx->wait);
+		break;
+
 	case APR_BASIC_RSP_RESULT:
 		if (payload[1]) {
 			usf_xx->usf_state = USF_ERROR_STATE;
@@ -250,7 +270,7 @@
 			       __func__);
 			kfree(usf_xx->encdec_cfg.params);
 			usf_xx->encdec_cfg.params = NULL;
-			return -EINVAL;
+			return -EFAULT;
 		}
 		pr_debug("%s: params_size[%d]; params[%d,%d,%d,%d, %d]\n",
 			 __func__,
@@ -330,7 +350,9 @@
 		input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
 							BIT_MASK(BTN_RIGHT) |
 							BIT_MASK(BTN_MIDDLE);
-		input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
+		input_dev->relbit[0] =  BIT_MASK(REL_X) |
+					BIT_MASK(REL_Y) |
+					BIT_MASK(REL_Z);
 	}
 
 	if (input_info->event_types & USF_KEYBOARD_EVENT) {
@@ -386,6 +408,7 @@
 
 	input_report_rel(input_if, REL_X, me->rels[0]);
 	input_report_rel(input_if, REL_Y, me->rels[1]);
+	input_report_rel(input_if, REL_Z, me->rels[2]);
 
 	input_report_key(input_if, BTN_LEFT,
 			 me->buttons_states & USF_BUTTON_LEFT_MASK);
@@ -423,6 +446,9 @@
 {
 	struct input_dev *input_if = NULL;
 	uint16_t ind = 0;
+	uint16_t events_num = 0;
+	struct usf_event_type usf_events[USF_EVENTS_PORTION_SIZE];
+	int rc = 0;
 
 	if ((usf_info == NULL) || (usf_info->input_if == NULL) ||
 	    (event == NULL) || (!event_counter)) {
@@ -431,40 +457,49 @@
 
 	input_if = usf_info->input_if;
 
-	for (ind = 0; ind < event_counter; ++ind) {
-		event += ind;
-		if (event->event_type & usf_info->event_types) {
-			/* the event is supported */
-			if (event->event_type & USF_TSC_EVENT) {
+	while (event_counter > 0) {
+		if (event_counter > USF_EVENTS_PORTION_SIZE) {
+			events_num = USF_EVENTS_PORTION_SIZE;
+			event_counter -= USF_EVENTS_PORTION_SIZE;
+		} else {
+			events_num = event_counter;
+			event_counter = 0;
+		}
+		rc = copy_from_user(usf_events,
+				event,
+				events_num * sizeof(struct usf_event_type));
+		if (rc) {
+			pr_err("%s: copy upd_rx_info from user; rc=%d\n",
+				__func__, rc);
+			return;
+		}
+		for (ind = 0; ind < events_num; ++ind) {
+			struct usf_event_type *p_event = &usf_events[ind];
+			if (p_event->event_type & USF_TSC_EVENT) {
 				struct point_event_type *pe =
-					&(event->event_data.point_event);
+					&(p_event->event_data.point_event);
 				if (pe->coordinates_type ==
-				    USF_PIX_COORDINATE) {
+					USF_PIX_COORDINATE)
 					notify_tsc_event(input_if,
-							 pe->coordinates[0],
-							 pe->coordinates[1],
-							 pe->pressure);
-				} else
-					pr_debug("%s: wrong coord type:%d\n",
-						 __func__,
-						 pe->coordinates_type);
-
+						pe->coordinates[0],
+						pe->coordinates[1],
+						pe->pressure);
+				else
+					pr_debug("%s: wrong coord type: %d",
+						__func__,
+						pe->coordinates_type);
 				continue;
 			}
-
-			if (event->event_type & USF_MOUSE_EVENT) {
+			if (p_event->event_type & USF_MOUSE_EVENT) {
 				notify_mouse_event(input_if,
-					&(event->event_data.mouse_event));
+					&(p_event->event_data.mouse_event));
 				continue;
 			}
-
-			if (event->event_type & USF_KEYBOARD_EVENT) {
+			if (event->event_type & USF_KEYBOARD_EVENT)
 				notify_key_event(input_if,
 					&(event->event_data.key_event));
-				continue;
-			}
-		} /* the event is supported */
-	}
+		} /* loop in the portion */
+	} /* all events loop */
 }
 
 static int usf_start_tx(struct usf_xx_type *usf_xx)
@@ -473,16 +508,20 @@
 
 	pr_debug("%s: tx: q6usm_run; rc=%d\n", __func__, rc);
 	if (!rc) {
-		/* supply all buffers */
-		rc = q6usm_read(usf_xx->usc,
-				usf_xx->buffer_count);
-		pr_debug("%s: q6usm_read[%d]\n",
-			 __func__, rc);
+		if (usf_xx->buffer_count >= USM_MIN_BUF_CNT) {
+			/* supply all buffers */
+			rc = q6usm_read(usf_xx->usc,
+					usf_xx->buffer_count);
+			pr_debug("%s: q6usm_read[%d]\n",
+				 __func__, rc);
 
-		if (rc)
-			pr_err("%s: buf read failed",
-			       __func__);
-		else
+			if (rc)
+				pr_err("%s: buf read failed",
+				       __func__);
+			else
+				usf_xx->usf_state =
+					USF_WORK_STATE;
+		} else
 			usf_xx->usf_state =
 				USF_WORK_STATE;
 	}
@@ -502,6 +541,109 @@
 	return rc;
 } /* usf_start_rx */
 
+static int usf_set_us_detection(struct usf_type *usf, unsigned long arg)
+{
+	uint32_t timeout = 0;
+	struct us_detect_info_type detect_info;
+	struct usm_session_cmd_detect_info usm_detect_info;
+	struct usm_session_cmd_detect_info *p_usm_detect_info =
+						&usm_detect_info;
+	uint32_t detect_info_size = sizeof(struct usm_session_cmd_detect_info);
+	struct usf_xx_type *usf_xx =  &usf->usf_tx;
+	int rc = copy_from_user(&detect_info,
+				(void *) arg,
+				sizeof(detect_info));
+
+	if (rc) {
+		pr_err("%s: copy detect_info from user; rc=%d\n",
+			__func__, rc);
+		return -EFAULT;
+	}
+
+	if (detect_info.us_detector != US_DETECT_FW) {
+		pr_err("%s: unsupported detector: %d\n",
+			__func__, detect_info.us_detector);
+		return -EINVAL;
+	}
+
+	if ((detect_info.params_data_size != 0) &&
+	    (detect_info.params_data != NULL)) {
+		uint8_t *p_data = NULL;
+
+		detect_info_size += detect_info.params_data_size;
+		p_usm_detect_info = kzalloc(detect_info_size, GFP_KERNEL);
+		if (p_usm_detect_info == NULL) {
+			pr_err("%s: detect_info[%d] allocation failed\n",
+			       __func__, detect_info_size);
+			return -ENOMEM;
+		}
+		p_data = (uint8_t *)p_usm_detect_info +
+			sizeof(struct usm_session_cmd_detect_info);
+
+		rc = copy_from_user(p_data,
+				    (void *)detect_info.params_data,
+				    detect_info.params_data_size);
+		if (rc) {
+			pr_err("%s: copy params from user; rc=%d\n",
+				__func__, rc);
+			kfree(p_usm_detect_info);
+			return -EFAULT;
+		}
+		p_usm_detect_info->algorithm_cfg_size = detect_info_size;
+	} else
+		usm_detect_info.algorithm_cfg_size = 0;
+
+	p_usm_detect_info->detect_mode = detect_info.us_detect_mode;
+	p_usm_detect_info->skip_interval = detect_info.skip_time;
+
+	usf_xx->us_detect_type = USF_US_DETECT_UNDEF;
+
+	rc = q6usm_set_us_detection(usf_xx->usc,
+				    p_usm_detect_info,
+				    detect_info_size);
+	if (rc || (detect_info.detect_timeout == USF_NO_WAIT_TIMEOUT)) {
+		if (detect_info_size >
+		    sizeof(struct usm_session_cmd_detect_info))
+			kfree(p_usm_detect_info);
+		return rc;
+	}
+
+	/* Get US detection result */
+	if (detect_info.detect_timeout == USF_INFINITIVE_TIMEOUT) {
+		wait_event(usf_xx->wait,
+				(usf_xx->us_detect_type !=
+				 USF_US_DETECT_UNDEF));
+	} else {
+		if (detect_info.detect_timeout == USF_DEFAULT_TIMEOUT)
+			timeout = USF_TIMEOUT_JIFFIES;
+		else
+			timeout = detect_info.detect_timeout * HZ;
+
+		rc = wait_event_timeout(usf_xx->wait,
+					(usf_xx->us_detect_type !=
+					 USF_US_DETECT_UNDEF),
+					timeout);
+		/* In the case of timeout, "no US" is assumed */
+	}
+
+	usf->usf_rx.us_detect_type = usf->usf_tx.us_detect_type;
+
+	detect_info.is_us = (usf_xx->us_detect_type == USF_US_DETECT_YES);
+	rc = copy_to_user((void __user *)arg,
+			  &detect_info,
+			  sizeof(detect_info));
+	if (rc) {
+		pr_err("%s: copy detect_info to user; rc=%d\n",
+			__func__, rc);
+		rc = -EFAULT;
+	}
+
+	if (detect_info_size > sizeof(struct usm_session_cmd_detect_info))
+		kfree(p_usm_detect_info);
+
+	return rc;
+} /* usf_set_us_detection */
+
 static int usf_set_tx_info(struct usf_type *usf, unsigned long arg)
 {
 	struct us_tx_info_type config_tx;
@@ -512,9 +654,9 @@
 			    sizeof(config_tx));
 
 	if (rc) {
-		pr_err("%s: copy error[%d]\n",
+		pr_err("%s: copy config_tx from user; rc=%d\n",
 			__func__, rc);
-		return -EINVAL;
+		return -EFAULT;
 	}
 
 	name = config_tx.us_xx_info.client_name;
@@ -554,13 +696,15 @@
 
 	rc = q6usm_enc_cfg_blk(usf_xx->usc,
 			       &usf_xx->encdec_cfg);
-	if (!rc) {
+	if (!rc &&
+	     (config_tx.input_info.event_types != USF_NO_EVENT)) {
 		rc = register_input_device(usf,
 					   &config_tx.input_info);
-		if (!rc)
-			usf_xx->usf_state = USF_CONFIGURED_STATE;
 	}
 
+	if (!rc)
+		usf_xx->usf_state = USF_CONFIGURED_STATE;
+
 	return rc;
 } /* usf_set_tx_info */
 
@@ -573,9 +717,9 @@
 			    sizeof(config_rx));
 
 	if (rc) {
-		pr_err("%s: copy_from_user() failed[%d]\n",
+		pr_err("%s: copy config_rx from user; rc=%d\n",
 			__func__, rc);
-		return -EINVAL;
+		return -EFAULT;
 	}
 
 	usf_xx->new_region = USM_UNDEF_TOKEN;
@@ -617,14 +761,15 @@
 {
 	struct us_tx_update_info_type upd_tx_info;
 	unsigned long prev_jiffies = 0;
+	uint32_t timeout = 0;
 	struct usf_xx_type *usf_xx =  &usf->usf_tx;
 	int rc = copy_from_user(&upd_tx_info, (void *) arg,
 			    sizeof(upd_tx_info));
 
 	if (rc) {
-		pr_err("%s: get_update: copy_from_user() failed[%d]\n",
-		       __func__, rc);
-		return -EINVAL;
+		pr_err("%s: copy upd_tx_info from user; rc=%d\n",
+			__func__, rc);
+		return -EFAULT;
 	}
 
 	if (!usf_xx->user_upd_info_na) {
@@ -641,27 +786,43 @@
 		usf_xx->user_upd_info_na = 0;
 
 	/* Get data ready regions */
-	prev_jiffies = jiffies;
-	rc = wait_event_timeout(usf_xx->wait,
-				(usf_xx->prev_region !=
-				 usf_xx->new_region) ||
-				(usf_xx->usf_state !=
-				 USF_WORK_STATE),
-				USF_TIMEOUT_JIFFIES);
+	if (upd_tx_info.timeout == USF_INFINITIVE_TIMEOUT) {
+		wait_event(usf_xx->wait,
+			   (usf_xx->prev_region !=
+			    usf_xx->new_region) ||
+			   (usf_xx->usf_state !=
+			    USF_WORK_STATE));
+	} else {
+		if (upd_tx_info.timeout == USF_NO_WAIT_TIMEOUT)
+			rc = (usf_xx->prev_region != usf_xx->new_region);
+		else {
+			if (upd_tx_info.timeout == USF_DEFAULT_TIMEOUT)
+				timeout = USF_TIMEOUT_JIFFIES;
+			else
+				timeout = upd_tx_info.timeout * HZ;
 
-	if (!rc) {
-		pr_debug("%s: timeout. prev_j=%lu; j=%lu\n",
-			__func__, prev_jiffies, jiffies);
-		pr_debug("%s: timeout. prev=%d; new=%d\n",
-			__func__, usf_xx->prev_region,
-			usf_xx->new_region);
-		pr_debug("%s: timeout. free_region=%d;\n",
-			__func__, upd_tx_info.free_region);
-		if (usf_xx->prev_region ==
-		    usf_xx->new_region) {
-			pr_err("%s:read data: timeout\n",
-			       __func__);
-			return -ETIME;
+			prev_jiffies = jiffies;
+			rc = wait_event_timeout(usf_xx->wait,
+						(usf_xx->prev_region !=
+						 usf_xx->new_region) ||
+						(usf_xx->usf_state !=
+						 USF_WORK_STATE),
+						timeout);
+		}
+		if (!rc) {
+			pr_debug("%s: timeout. prev_j=%lu; j=%lu\n",
+				__func__, prev_jiffies, jiffies);
+			pr_debug("%s: timeout. prev=%d; new=%d\n",
+				__func__, usf_xx->prev_region,
+				usf_xx->new_region);
+			pr_debug("%s: timeout. free_region=%d;\n",
+				__func__, upd_tx_info.free_region);
+			if (usf_xx->prev_region ==
+			    usf_xx->new_region) {
+				pr_err("%s:read data: timeout\n",
+				       __func__);
+				return -ETIME;
+			}
 		}
 	}
 
@@ -672,14 +833,21 @@
 	}
 
 	upd_tx_info.ready_region = usf_xx->new_region;
-	rc = copy_to_user((void __user *)arg, &upd_tx_info,
-			  sizeof(upd_tx_info));
+	usf_xx->prev_region = upd_tx_info.ready_region;
+
 	if (upd_tx_info.ready_region == USM_WRONG_TOKEN) {
 		pr_err("%s: TX path corrupted; prev=%d\n",
 		       __func__, usf_xx->prev_region);
-		rc = -EIO;
+		return -EIO;
 	}
-	usf_xx->prev_region = upd_tx_info.ready_region;
+
+	rc = copy_to_user((void __user *)arg, &upd_tx_info,
+			  sizeof(upd_tx_info));
+	if (rc) {
+		pr_err("%s: copy upd_tx_info to user; rc=%d\n",
+			__func__, rc);
+		rc = -EFAULT;
+	}
 
 	return rc;
 } /* usf_get_tx_update */
@@ -691,9 +859,9 @@
 			    sizeof(upd_rx_info));
 
 	if (rc) {
-		pr_err("%s: get_update: copy_from_user() failed[%d]\n",
-		       __func__, rc);
-		return -EINVAL;
+		pr_err("%s: copy upd_rx_info from user; rc=%d\n",
+			__func__, rc);
+		return -EFAULT;
 	}
 
 	/* Send available data regions */
@@ -726,11 +894,17 @@
 			       __func__,
 			       usf_xx->usf_state);
 			rc = -EINTR;
-		} else
+		} else {
 			rc = copy_to_user(
 				(void __user *)arg,
 				&upd_rx_info,
 				sizeof(upd_rx_info));
+			if (rc) {
+				pr_err("%s: copy rx_info to user; rc=%d\n",
+					__func__, rc);
+				rc = -EFAULT;
+			}
+		}
 	}
 
 	return rc;
@@ -863,6 +1037,19 @@
 		break;
 	} /* US_STOP_RX */
 
+	case US_SET_DETECTION: {
+		struct usf_xx_type *usf_xx = &usf->usf_tx;
+		if (usf_xx->usf_state == USF_WORK_STATE)
+			rc = usf_set_us_detection(usf, arg);
+		else {
+			pr_err("%s: set us detection: wrong state[%d]\n",
+			       __func__,
+			       usf_xx->usf_state);
+			rc = -EBADFD;
+		}
+		break;
+	} /* US_GET_TX_UPDATE */
+
 	default:
 		rc = -EINVAL;
 		break;
@@ -936,6 +1123,9 @@
 	usf->usf_tx.usf_state = USF_OPENED_STATE;
 	usf->usf_rx.usf_state = USF_OPENED_STATE;
 
+	usf->usf_tx.us_detect_type = USF_US_DETECT_UNDEF;
+	usf->usf_rx.us_detect_type = USF_US_DETECT_UNDEF;
+
 	pr_info("%s:usf in open\n", __func__);
 	return 0;
 }
@@ -1003,4 +1193,3 @@
 
 MODULE_DESCRIPTION("Ultrasound framework driver");
 MODULE_VERSION(DRV_VERSION);
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/scm-boot.h b/arch/arm/mach-msm/scm-boot.h
index c2c473b..b14c968 100644
--- a/arch/arm/mach-msm/scm-boot.h
+++ b/arch/arm/mach-msm/scm-boot.h
@@ -12,10 +12,14 @@
 #ifndef __MACH_SCM_BOOT_H
 #define __MACH_SCM_BOOT_H
 
-#define SCM_BOOT_ADDR			0x1
-#define SCM_FLAG_COLDBOOT_CPU1		0x1
-#define SCM_FLAG_WARMBOOT_CPU1		0x2
-#define SCM_FLAG_WARMBOOT_CPU0		0x4
+#define SCM_BOOT_ADDR				0x1
+#define SCM_FLAG_COLDBOOT_CPU1		0x01
+#define SCM_FLAG_COLDBOOT_CPU2		0x08
+#define SCM_FLAG_COLDBOOT_CPU3		0x20
+#define SCM_FLAG_WARMBOOT_CPU1		0x02
+#define SCM_FLAG_WARMBOOT_CPU0		0x04
+#define SCM_FLAG_WARMBOOT_CPU2		0x10
+#define SCM_FLAG_WARMBOOT_CPU3		0x40
 
 int scm_set_boot_addr(void *addr, int flags);
 
diff --git a/arch/arm/mach-msm/scm-pas.c b/arch/arm/mach-msm/scm-pas.c
index 5bbffd3..0a9b27c 100644
--- a/arch/arm/mach-msm/scm-pas.c
+++ b/arch/arm/mach-msm/scm-pas.c
@@ -10,12 +10,17 @@
  * GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt) "scm-pas: " fmt
+
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/clk.h>
 
 #include <mach/scm.h>
 #include <mach/socinfo.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
 #include "scm-pas.h"
 
 #define PAS_INIT_IMAGE_CMD	1
@@ -50,15 +55,89 @@
 }
 EXPORT_SYMBOL(pas_init_image);
 
+static struct msm_bus_paths scm_pas_bw_tbl[] = {
+	{
+		.vectors = (struct msm_bus_vectors[]){
+			{
+				.src = MSM_BUS_MASTER_SPS,
+				.dst = MSM_BUS_SLAVE_EBI_CH0,
+			},
+		},
+		.num_paths = 1,
+	},
+	{
+		.vectors = (struct msm_bus_vectors[]){
+			{
+				.src = MSM_BUS_MASTER_SPS,
+				.dst = MSM_BUS_SLAVE_EBI_CH0,
+				.ib = 492 * 8 * 1000000UL,
+				.ab = 492 * 8 *  100000UL,
+			},
+		},
+		.num_paths = 1,
+	},
+};
+
+static struct msm_bus_scale_pdata scm_pas_bus_pdata = {
+	.usecase = scm_pas_bw_tbl,
+	.num_usecases = ARRAY_SIZE(scm_pas_bw_tbl),
+	.name = "scm_pas",
+};
+
+static uint32_t scm_perf_client;
+static struct clk *scm_bus_clk;
+
+static DEFINE_MUTEX(scm_pas_bw_mutex);
+static int scm_pas_bw_count;
+
+static int scm_pas_enable_bw(void)
+{
+	int ret = 0;
+
+	if (!scm_perf_client || scm_bus_clk)
+		return -EINVAL;
+
+	mutex_lock(&scm_pas_bw_mutex);
+	if (!scm_pas_bw_count) {
+		ret = msm_bus_scale_client_update_request(scm_perf_client, 1);
+		if (ret) {
+			pr_err("bandwidth request failed (%d)\n", ret);
+		} else {
+			ret = clk_enable(scm_bus_clk);
+			if (ret)
+				pr_err("clock enable failed\n");
+		}
+	}
+	if (ret)
+		msm_bus_scale_client_update_request(scm_perf_client, 0);
+	else
+		scm_pas_bw_count++;
+	mutex_unlock(&scm_pas_bw_mutex);
+	return ret;
+}
+
+static void scm_pas_disable_bw(void)
+{
+	mutex_lock(&scm_pas_bw_mutex);
+	if (scm_pas_bw_count-- == 1) {
+		msm_bus_scale_client_update_request(scm_perf_client, 0);
+		clk_disable(scm_bus_clk);
+	}
+	mutex_unlock(&scm_pas_bw_mutex);
+}
+
 int pas_auth_and_reset(enum pas_id id)
 {
-	int ret;
+	int ret, bus_ret;
 	u32 proc = id, scm_ret = 0;
 
+	bus_ret = scm_pas_enable_bw();
 	ret = scm_call(SCM_SVC_PIL, PAS_AUTH_AND_RESET_CMD, &proc,
 			sizeof(proc), &scm_ret, sizeof(scm_ret));
 	if (ret)
-		return ret;
+		scm_ret = ret;
+	if (!bus_ret)
+		scm_pas_disable_bw();
 
 	return scm_ret;
 }
@@ -108,3 +187,22 @@
 	return ret_val;
 }
 EXPORT_SYMBOL(pas_supported);
+
+static int __init scm_pas_init(void)
+{
+	/* TODO: Remove once bus scaling driver is in place */
+	if (!cpu_is_apq8064())
+		scm_perf_client = msm_bus_scale_register_client(
+				&scm_pas_bus_pdata);
+	if (!scm_perf_client)
+		pr_warn("unable to register bus client\n");
+	scm_bus_clk = clk_get_sys("scm", "bus_clk");
+	if (!IS_ERR(scm_bus_clk)) {
+		clk_set_rate(scm_bus_clk, 64000000);
+	} else {
+		scm_bus_clk = NULL;
+		pr_warn("unable to get bus clock\n");
+	}
+	return 0;
+}
+module_init(scm_pas_init);
diff --git a/arch/arm/mach-msm/scm-pas.h b/arch/arm/mach-msm/scm-pas.h
index 4a3f4c5..67a0992 100644
--- a/arch/arm/mach-msm/scm-pas.h
+++ b/arch/arm/mach-msm/scm-pas.h
@@ -16,14 +16,12 @@
 	PAS_MODEM,
 	PAS_Q6,
 	PAS_DSPS,
-	PAS_PLAYREADY,
+	PAS_TZAPPS,
 	PAS_MODEM_SW,
 	PAS_MODEM_FW,
 	PAS_RIVA,
 };
 
-#define PAS_TZAPPS PAS_PLAYREADY
-
 extern int pas_init_image(enum pas_id id, const u8 *metadata, size_t size);
 extern int pas_auth_and_reset(enum pas_id id);
 extern int pas_shutdown(enum pas_id id);
diff --git a/arch/arm/mach-msm/sdio_tty.c b/arch/arm/mach-msm/sdio_tty.c
index e249d06..2aaa41ea 100644
--- a/arch/arm/mach-msm/sdio_tty.c
+++ b/arch/arm/mach-msm/sdio_tty.c
@@ -18,6 +18,7 @@
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
+#include <linux/debugfs.h>
 #include <mach/sdio_al.h>
 
 #define INPUT_SPEED			4800
@@ -77,10 +78,17 @@
 	enum sdio_tty_state sdio_tty_state;
 	int is_sdio_open;
 	int tty_open_count;
+	int total_rx;
+	int total_tx;
 };
 
 static struct sdio_tty *sdio_tty[MAX_SDIO_TTY_DEVS];
 
+#ifdef CONFIG_DEBUG_FS
+struct dentry *sdio_tty_debug_root;
+struct dentry *sdio_tty_debug_info;
+#endif
+
 #define DEBUG_MSG(sdio_tty_drv, x...) if (sdio_tty_drv->debug_msg_on) pr_info(x)
 
 /*
@@ -183,10 +191,11 @@
 		}
 
 		tty_flip_buffer_push(sdio_tty_drv->tty_str);
+		sdio_tty_drv->total_rx += read_avail;
 
-		DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME
-				": %s: End of read %d bytes for dev %s",
-				__func__, read_avail,
+		DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: Rx: %d, "
+				"Total Rx = %d bytes for dev %s", __func__,
+				read_avail, sdio_tty_drv->total_rx,
 				sdio_tty_drv->tty_dev_name);
 	}
 }
@@ -302,10 +311,11 @@
 		return 0;
 	}
 
-	DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: End of function, "
-			"dev=%s, len=%d bytes\n", __func__,
-			sdio_tty_drv->tty_dev_name, len);
+	sdio_tty_drv->total_tx += len;
 
+	DEBUG_MSG(sdio_tty_drv, SDIO_TTY_MODULE_NAME ": %s: Tx: %d, "
+			"Total Tx = %d for dev %s", __func__, len,
+			sdio_tty_drv->total_tx, sdio_tty_drv->tty_dev_name);
 	return len;
 }
 
@@ -407,8 +417,8 @@
 			return ret;
 		}
 
-		pr_info(SDIO_TTY_MODULE_NAME ": %s: SDIO_TTY channel(%s) opened "
-			"\n", __func__, sdio_tty_drv->sdio_ch_name);
+		pr_info(SDIO_TTY_MODULE_NAME ": %s: SDIO_TTY channel(%s) "
+			"opened\n", __func__, sdio_tty_drv->sdio_ch_name);
 
 		sdio_tty_drv->is_sdio_open = 1;
 	} else {
@@ -748,6 +758,39 @@
 	},
 };
 
+#ifdef CONFIG_DEBUG_FS
+void sdio_tty_print_info(void)
+{
+	int i = 0;
+
+	for (i = 0; i < MAX_SDIO_TTY_DEVS; i++) {
+		if (sdio_tty[i] == NULL)
+			continue;
+		pr_info(SDIO_TTY_MODULE_NAME ": %s: Total Rx=%d, Tx = %d "
+			"for dev %s", __func__, sdio_tty[i]->total_rx,
+			sdio_tty[i]->total_tx, sdio_tty[i]->tty_dev_name);
+	}
+}
+
+static int tty_debug_info_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t tty_debug_info_write(struct file *file,
+		const char __user *buf, size_t count, loff_t *ppos)
+{
+	sdio_tty_print_info();
+	return count;
+}
+
+const struct file_operations tty_debug_info_ops = {
+	.open = tty_debug_info_open,
+	.write = tty_debug_info_write,
+};
+#endif
+
 /*
  *  Module Init.
  *
@@ -763,6 +806,19 @@
 		pr_err(SDIO_TTY_MODULE_NAME ": %s: platform_driver_register "
 					    "failed", __func__);
 	}
+#ifdef CONFIG_DEBUG_FS
+	else {
+		sdio_tty_debug_root = debugfs_create_dir("sdio_tty", NULL);
+		if (sdio_tty_debug_root) {
+			sdio_tty_debug_info = debugfs_create_file(
+							"sdio_tty_debug",
+							S_IRUGO | S_IWUGO,
+							sdio_tty_debug_root,
+							NULL,
+							&tty_debug_info_ops);
+		}
+	}
+#endif
 	return ret;
 };
 
@@ -774,6 +830,10 @@
  */
 static void __exit sdio_tty_exit(void)
 {
+#ifdef CONFIG_DEBUG_FS
+	debugfs_remove(sdio_tty_debug_info);
+	debugfs_remove(sdio_tty_debug_root);
+#endif
 	platform_driver_unregister(&sdio_tty_pdrv);
 }
 
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index 691dad2..b31550a 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -1,7 +1,7 @@
 /* arch/arm/mach-msm/smd.c
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -31,6 +31,7 @@
 #include <linux/ctype.h>
 #include <linux/remote_spinlock.h>
 #include <linux/uaccess.h>
+#include <linux/kfifo.h>
 #include <mach/msm_smd.h>
 #include <mach/msm_iomap.h>
 #include <mach/system.h>
@@ -61,6 +62,7 @@
 #define MODULE_NAME "msm_smd"
 #define SMEM_VERSION 0x000B
 #define SMD_VERSION 0x00020000
+#define SMSM_SNAPSHOT_CNT 64
 
 uint32_t SMSM_NUM_ENTRIES = 8;
 uint32_t SMSM_NUM_HOSTS = 3;
@@ -79,6 +81,7 @@
 };
 
 static struct smsm_shared_info smsm_info;
+struct kfifo smsm_snapshot_fifo;
 
 struct smsm_size_info_type {
 	uint32_t num_hosts;
@@ -239,6 +242,7 @@
 static LIST_HEAD(smd_ch_list_loopback);
 static irqreturn_t smsm_irq_handler(int irq, void *data);
 static void smd_fake_irq_handler(unsigned long arg);
+static void smsm_cb_snapshot(void);
 
 static void notify_smsm_cb_clients_worker(struct work_struct *work);
 static DECLARE_WORK(smsm_cb_work, notify_smsm_cb_clients_worker);
@@ -308,7 +312,7 @@
 		MSM_TRIG_A2DSPS_SMSM_INT;
 	}
 
-	schedule_work(&smsm_cb_work);
+	smsm_cb_snapshot();
 }
 
 static inline void notify_modem_smd(void)
@@ -1955,6 +1959,14 @@
 		SMSM_NUM_HOSTS = smsm_size_info->num_hosts;
 	}
 
+	i = kfifo_alloc(&smsm_snapshot_fifo,
+			sizeof(uint32_t) * SMSM_NUM_ENTRIES * SMSM_SNAPSHOT_CNT,
+			GFP_KERNEL);
+	if (i) {
+		pr_err("%s: SMSM state fifo alloc failed %d\n", __func__, i);
+		return i;
+	}
+
 	if (!smsm_info.state) {
 		smsm_info.state = smem_alloc2(ID_SHARED_STATE,
 					      SMSM_NUM_ENTRIES *
@@ -2024,6 +2036,31 @@
 }
 EXPORT_SYMBOL(smsm_reset_modem_cont);
 
+static void smsm_cb_snapshot(void)
+{
+	int n;
+	uint32_t new_state;
+	int ret;
+
+	ret = kfifo_avail(&smsm_snapshot_fifo);
+	if (ret < (SMSM_NUM_ENTRIES * 4)) {
+		pr_err("%s: SMSM snapshot full %d\n", __func__, ret);
+		return;
+	}
+
+	for (n = 0; n < SMSM_NUM_ENTRIES; n++) {
+		new_state = __raw_readl(SMSM_STATE_ADDR(n));
+
+		ret = kfifo_in(&smsm_snapshot_fifo,
+				&new_state, sizeof(new_state));
+		if (ret != sizeof(new_state)) {
+			pr_err("%s: SMSM snapshot failure %d\n", __func__, ret);
+			return;
+		}
+	}
+	schedule_work(&smsm_cb_work);
+}
+
 static irqreturn_t smsm_irq_handler(int irq, void *data)
 {
 	unsigned long flags;
@@ -2039,7 +2076,9 @@
 				prev_smem_q6_apps_smsm = mux_val;
 		}
 
-		schedule_work(&smsm_cb_work);
+		spin_lock_irqsave(&smem_lock, flags);
+		smsm_cb_snapshot();
+		spin_unlock_irqrestore(&smem_lock, flags);
 		return IRQ_HANDLED;
 	}
 
@@ -2097,7 +2136,7 @@
 			notify_other_smsm(SMSM_APPS_STATE, (old_apps ^ apps));
 		}
 
-		schedule_work(&smsm_cb_work);
+		smsm_cb_snapshot();
 	}
 	spin_unlock_irqrestore(&smem_lock, flags);
 	return IRQ_HANDLED;
@@ -2212,35 +2251,41 @@
 	int n;
 	uint32_t new_state;
 	uint32_t state_changes;
+	int ret;
+	int snapshot_size = SMSM_NUM_ENTRIES * sizeof(uint32_t);
 
-	mutex_lock(&smsm_lock);
-
-	if (!smsm_states) {
-		/* smsm not yet initialized */
-		mutex_unlock(&smsm_lock);
+	if (!smd_initialized)
 		return;
-	}
 
-	for (n = 0; n < SMSM_NUM_ENTRIES; n++) {
-		state_info = &smsm_states[n];
-		new_state = __raw_readl(SMSM_STATE_ADDR(n));
+	while (kfifo_len(&smsm_snapshot_fifo) >= snapshot_size) {
+		mutex_lock(&smsm_lock);
+		for (n = 0; n < SMSM_NUM_ENTRIES; n++) {
+			state_info = &smsm_states[n];
 
-		if (new_state != state_info->last_value) {
-			state_changes = state_info->last_value ^ new_state;
-
-			list_for_each_entry(cb_info,
-				&state_info->callbacks, cb_list) {
-
-				if (cb_info->mask & state_changes)
-					cb_info->notify(cb_info->data,
-						state_info->last_value,
-						new_state);
+			ret = kfifo_out(&smsm_snapshot_fifo, &new_state,
+					sizeof(new_state));
+			if (ret != sizeof(new_state)) {
+				pr_err("%s: snapshot underflow %d\n",
+					__func__, ret);
+				mutex_unlock(&smsm_lock);
+				return;
 			}
-			state_info->last_value = new_state;
-		}
-	}
 
-	mutex_unlock(&smsm_lock);
+			state_changes = state_info->last_value ^ new_state;
+			if (state_changes) {
+				list_for_each_entry(cb_info,
+					&state_info->callbacks, cb_list) {
+
+					if (cb_info->mask & state_changes)
+						cb_info->notify(cb_info->data,
+							state_info->last_value,
+							new_state);
+				}
+				state_info->last_value = new_state;
+			}
+		}
+		mutex_unlock(&smsm_lock);
+	}
 }
 
 
diff --git a/arch/arm/mach-msm/smd_debug.c b/arch/arm/mach-msm/smd_debug.c
index d7602f2..b95a35c 100644
--- a/arch/arm/mach-msm/smd_debug.c
+++ b/arch/arm/mach-msm/smd_debug.c
@@ -1,7 +1,7 @@
 /* arch/arm/mach-msm/smd_debug.c
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -18,6 +18,7 @@
 #include <linux/debugfs.h>
 #include <linux/list.h>
 #include <linux/ctype.h>
+#include <linux/jiffies.h>
 
 #include <mach/msm_iomap.h>
 
@@ -246,6 +247,7 @@
 	uint32_t new_state;
 };
 static struct SMSM_CB_DATA smsm_cb_data;
+static struct completion smsm_cb_completion;
 
 static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
 {
@@ -253,6 +255,7 @@
 	smsm_cb_data.old_state = old_state;
 	smsm_cb_data.new_state = new_state;
 	smsm_cb_data.data = data;
+	complete_all(&smsm_cb_completion);
 }
 
 #define UT_EQ_INT(a, b) \
@@ -265,6 +268,16 @@
 	} \
 	do {} while (0)
 
+#define UT_GT_INT(a, b) \
+	if ((a) <= (b)) { \
+		i += scnprintf(buf + i, max - i, \
+			"%s:%d " #a "(%d) > " #b "(%d)\n", \
+				__func__, __LINE__, \
+				a, b); \
+		break; \
+	} \
+	do {} while (0)
+
 #define SMSM_CB_TEST_INIT() \
 	do { \
 		smsm_cb_data.cb_count = 0; \
@@ -290,16 +303,21 @@
 
 		/* de-assert SMSM_SMD_INIT to trigger state update */
 		UT_EQ_INT(smsm_cb_data.cb_count, 0);
+		INIT_COMPLETION(smsm_cb_completion);
 		smsm_change_state(SMSM_APPS_STATE, SMSM_SMDINIT, 0x0);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
 
 		UT_EQ_INT(smsm_cb_data.cb_count, 1);
-		UT_EQ_INT(smsm_cb_data.cb_count, 1);
 		UT_EQ_INT(smsm_cb_data.old_state & SMSM_SMDINIT, SMSM_SMDINIT);
 		UT_EQ_INT(smsm_cb_data.new_state & SMSM_SMDINIT, 0x0);
 		UT_EQ_INT((int)smsm_cb_data.data, 0x1234);
 
 		/* re-assert SMSM_SMD_INIT to trigger state update */
+		INIT_COMPLETION(smsm_cb_completion);
 		smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_SMDINIT);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
 		UT_EQ_INT(smsm_cb_data.cb_count, 2);
 		UT_EQ_INT(smsm_cb_data.old_state & SMSM_SMDINIT, 0x0);
 		UT_EQ_INT(smsm_cb_data.new_state & SMSM_SMDINIT, SMSM_SMDINIT);
@@ -310,8 +328,11 @@
 		UT_EQ_INT(ret, 2);
 
 		/* make sure state change doesn't cause any more callbacks */
+		INIT_COMPLETION(smsm_cb_completion);
 		smsm_change_state(SMSM_APPS_STATE, SMSM_SMDINIT, 0x0);
 		smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_SMDINIT);
+		UT_EQ_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
 		UT_EQ_INT(smsm_cb_data.cb_count, 2);
 
 		i += scnprintf(buf + i, max - i, "Test %d - PASS\n", test_num);
@@ -329,28 +350,49 @@
 		UT_EQ_INT(ret, 1);
 
 		/* verify both callback bits work */
+		INIT_COMPLETION(smsm_cb_completion);
 		UT_EQ_INT(smsm_cb_data.cb_count, 0);
 		smsm_change_state(SMSM_APPS_STATE, SMSM_SMDINIT, 0x0);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
 		UT_EQ_INT(smsm_cb_data.cb_count, 1);
+		INIT_COMPLETION(smsm_cb_completion);
 		smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_SMDINIT);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
 		UT_EQ_INT(smsm_cb_data.cb_count, 2);
 
+		INIT_COMPLETION(smsm_cb_completion);
 		smsm_change_state(SMSM_APPS_STATE, SMSM_INIT, 0x0);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
 		UT_EQ_INT(smsm_cb_data.cb_count, 3);
+		INIT_COMPLETION(smsm_cb_completion);
 		smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_INIT);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
 		UT_EQ_INT(smsm_cb_data.cb_count, 4);
 
 		/* deregister 1st callback */
 		ret = smsm_state_cb_deregister(SMSM_APPS_STATE, SMSM_SMDINIT,
 				smsm_state_cb, (void *)0x1234);
 		UT_EQ_INT(ret, 1);
+		INIT_COMPLETION(smsm_cb_completion);
 		smsm_change_state(SMSM_APPS_STATE, SMSM_SMDINIT, 0x0);
 		smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_SMDINIT);
+		UT_EQ_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
 		UT_EQ_INT(smsm_cb_data.cb_count, 4);
 
+		INIT_COMPLETION(smsm_cb_completion);
 		smsm_change_state(SMSM_APPS_STATE, SMSM_INIT, 0x0);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
 		UT_EQ_INT(smsm_cb_data.cb_count, 5);
+		INIT_COMPLETION(smsm_cb_completion);
 		smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_INIT);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
 		UT_EQ_INT(smsm_cb_data.cb_count, 6);
 
 		/* deregister 2nd callback */
@@ -359,8 +401,11 @@
 		UT_EQ_INT(ret, 2);
 
 		/* make sure state change doesn't cause any more callbacks */
+		INIT_COMPLETION(smsm_cb_completion);
 		smsm_change_state(SMSM_APPS_STATE, SMSM_INIT, 0x0);
 		smsm_change_state(SMSM_APPS_STATE, 0x0, SMSM_INIT);
+		UT_EQ_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
 		UT_EQ_INT(smsm_cb_data.cb_count, 6);
 
 		i += scnprintf(buf + i, max - i, "Test %d - PASS\n", test_num);
@@ -378,12 +423,18 @@
 		UT_EQ_INT(ret, 0);
 
 		/* verify both callbacks work */
+		INIT_COMPLETION(smsm_cb_completion);
 		UT_EQ_INT(smsm_cb_data.cb_count, 0);
 		smsm_change_state(SMSM_APPS_STATE, SMSM_SMDINIT, 0x0);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
 		UT_EQ_INT(smsm_cb_data.cb_count, 1);
 		UT_EQ_INT((int)smsm_cb_data.data, 0x1234);
 
+		INIT_COMPLETION(smsm_cb_completion);
 		smsm_change_state(SMSM_APPS_STATE, SMSM_INIT, 0x0);
+		UT_GT_INT((int)wait_for_completion_timeout(&smsm_cb_completion,
+					msecs_to_jiffies(20)), 0);
 		UT_EQ_INT(smsm_cb_data.cb_count, 2);
 		UT_EQ_INT((int)smsm_cb_data.data, 0x3456);
 
@@ -599,7 +650,12 @@
 			  size_t count, loff_t *ppos)
 {
 	int (*fill)(char *buf, int max) = file->private_data;
-	int bsize = fill(debug_buffer, DEBUG_BUFMAX);
+	int bsize;
+
+	if (*ppos != 0)
+		return 0;
+
+	bsize = fill(debug_buffer, DEBUG_BUFMAX);
 	return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
 }
 
@@ -659,6 +715,8 @@
 	debug_create("version", 0444, dent, debug_read_smem_version);
 	debug_create("smsm_test", 0444, dent, debug_test_smsm);
 
+	init_completion(&smsm_cb_completion);
+
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 87b6d3f..0c2d4f7 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -31,6 +31,7 @@
 	HW_PLATFORM_FLUID   = 3,
 	HW_PLATFORM_SVLTE_FFA	= 4,
 	HW_PLATFORM_SVLTE_SURF	= 5,
+	HW_PLATFORM_MTP  = 8,
 	HW_PLATFORM_LIQUID  = 9,
 	/* Dragonboard platform id is assigned as 10 in CDT */
 	HW_PLATFORM_DRAGON	= 10,
@@ -42,9 +43,10 @@
 	[HW_PLATFORM_SURF] = "Surf",
 	[HW_PLATFORM_FFA] = "FFA",
 	[HW_PLATFORM_FLUID] = "Fluid",
-	[HW_PLATFORM_LIQUID] = "Liquid",
 	[HW_PLATFORM_SVLTE_FFA] = "SVLTE_FFA",
 	[HW_PLATFORM_SVLTE_SURF] = "SLVTE_SURF",
+	[HW_PLATFORM_MTP] = "MTP",
+	[HW_PLATFORM_LIQUID] = "Liquid",
 	[HW_PLATFORM_DRAGON] = "Dragon"
 };
 
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 7e61e8b..6f04470 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -102,7 +102,7 @@
 struct msm_clock {
 	struct clock_event_device   clockevent;
 	struct clocksource          clocksource;
-	struct irqaction            irq;
+	unsigned int		    irq;
 	void __iomem                *regbase;
 	uint32_t                    freq;
 	uint32_t                    shift;
@@ -110,6 +110,12 @@
 	uint32_t                    write_delay;
 	uint32_t                    rollover_offset;
 	uint32_t                    index;
+	void __iomem                *global_counter;
+	void __iomem                *local_counter;
+	union {
+		struct clock_event_device		*evt;
+		struct clock_event_device __percpu	**percpu_evt;
+	};
 };
 
 enum {
@@ -117,7 +123,6 @@
 	MSM_CLOCK_DGT,
 };
 
-
 struct msm_clock_percpu_data {
 	uint32_t                  last_set;
 	uint32_t                  sleep_offset;
@@ -155,14 +160,7 @@
 			.shift          = 17,
 			.flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 		},
-		.irq = {
-			.name    = "gp_timer",
-			.flags   = IRQF_DISABLED | IRQF_TIMER |
-				   IRQF_TRIGGER_RISING,
-			.handler = msm_timer_interrupt,
-			.dev_id  = &msm_clocks[0].clockevent,
-			.irq     = INT_GP_TIMER_EXP
-		},
+		.irq = INT_GP_TIMER_EXP,
 		.regbase = MSM_TMR_BASE + 0x4,
 		.freq = 32768,
 		.index = MSM_CLOCK_GPT,
@@ -185,22 +183,13 @@
 			.shift          = 24,
 			.flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 		},
-		.irq = {
-			.name    = "dg_timer",
-			.flags   = IRQF_DISABLED | IRQF_TIMER |
-				   IRQF_TRIGGER_RISING,
-			.handler = msm_timer_interrupt,
-			.dev_id  = &msm_clocks[1].clockevent,
-			.irq     = INT_DEBUG_TIMER_EXP
-		},
+		.irq = INT_DEBUG_TIMER_EXP,
 		.regbase = MSM_TMR_BASE + 0x24,
 		.index = MSM_CLOCK_DGT,
 		.write_delay = 9,
 	}
 };
 
-static DEFINE_PER_CPU(struct clock_event_device*, local_clock_event);
-
 static DEFINE_PER_CPU(struct msm_clock_percpu_data[NR_TIMERS],
     msm_clocks_percpu);
 
@@ -208,9 +197,7 @@
 
 static irqreturn_t msm_timer_interrupt(int irq, void *dev_id)
 {
-	struct clock_event_device *evt = dev_id;
-	if (smp_processor_id() != 0)
-		evt = __get_cpu_var(local_clock_event);
+	struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
 	if (evt->event_handler == NULL)
 		return IRQ_HANDLED;
 	evt->event_handler(evt);
@@ -356,9 +343,9 @@
 		get_cpu_var(msm_active_clock) = clock;
 		put_cpu_var(msm_active_clock);
 		__raw_writel(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE);
-		chip = irq_get_chip(clock->irq.irq);
+		chip = irq_get_chip(clock->irq);
 		if (chip && chip->irq_unmask)
-			chip->irq_unmask(irq_get_irq_data(clock->irq.irq));
+			chip->irq_unmask(irq_get_irq_data(clock->irq));
 		if (clock != &msm_clocks[MSM_CLOCK_GPT])
 			__raw_writel(TIMER_ENABLE_EN,
 				msm_clocks[MSM_CLOCK_GPT].regbase +
@@ -374,9 +361,9 @@
 			msm_read_timer_count(clock, LOCAL_TIMER) +
 			clock_state->sleep_offset;
 		__raw_writel(0, clock->regbase + TIMER_MATCH_VAL);
-		chip = irq_get_chip(clock->irq.irq);
+		chip = irq_get_chip(clock->irq);
 		if (chip && chip->irq_mask)
-			chip->irq_mask(irq_get_irq_data(clock->irq.irq));
+			chip->irq_mask(irq_get_irq_data(clock->irq));
 
 		if (!is_smp() || clock != &msm_clocks[MSM_CLOCK_DGT]
 				|| smp_processor_id())
@@ -1073,14 +1060,35 @@
 			printk(KERN_ERR "msm_timer_init: clocksource_register "
 			       "failed for %s\n", cs->name);
 
-		res = setup_irq(clock->irq.irq, &clock->irq);
-		if (res)
-			printk(KERN_ERR "msm_timer_init: setup_irq "
-			       "failed for %s\n", cs->name);
+		ce->irq = clock->irq;
+		if (cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_apq8064() ||
+				cpu_is_msm8930() || cpu_is_msm9615()) {
+			clock->percpu_evt = alloc_percpu(struct clock_event_device *);
+			if (!clock->percpu_evt) {
+				pr_err("msm_timer_init: memory allocation "
+				       "failed for %s\n", ce->name);
+				continue;
+			}
 
-		chip = irq_get_chip(clock->irq.irq);
+			*__this_cpu_ptr(clock->percpu_evt) = ce;
+			res = request_percpu_irq(ce->irq, msm_timer_interrupt,
+						 ce->name, clock->percpu_evt);
+			if (!res)
+				enable_percpu_irq(ce->irq, 0);
+		} else {
+			clock->evt = ce;
+			res = request_irq(ce->irq, msm_timer_interrupt,
+					  IRQF_TIMER | IRQF_NOBALANCING | IRQF_TRIGGER_RISING,
+					  ce->name, &clock->evt);
+		}
+
+		if (res)
+			pr_err("msm_timer_init: request_irq failed for %s\n",
+			       ce->name);
+
+		chip = irq_get_chip(clock->irq);
 		if (chip && chip->irq_mask)
-			chip->irq_mask(irq_get_irq_data(clock->irq.irq));
+			chip->irq_mask(irq_get_irq_data(clock->irq));
 
 		clockevents_register_device(ce);
 	}
@@ -1097,7 +1105,6 @@
 
 int __cpuinit local_timer_setup(struct clock_event_device *evt)
 {
-	unsigned long flags;
 	static DEFINE_PER_CPU(bool, first_boot) = true;
 	struct msm_clock *clock = &msm_clocks[msm_global_timer];
 
@@ -1115,7 +1122,7 @@
 		__raw_writel(~0, clock->regbase + TIMER_MATCH_VAL);
 		__get_cpu_var(first_boot) = false;
 	}
-	evt->irq = clock->irq.irq;
+	evt->irq = clock->irq;
 	evt->name = "local_timer";
 	evt->features = CLOCK_EVT_FEAT_ONESHOT;
 	evt->rating = clock->clockevent.rating;
@@ -1127,21 +1134,18 @@
 		clockevent_delta2ns(0xf0000000 >> clock->shift, evt);
 	evt->min_delta_ns = clockevent_delta2ns(4, evt);
 
-	__get_cpu_var(local_clock_event) = evt;
-
-	local_irq_save(flags);
-	gic_clear_spi_pending(clock->irq.irq);
-	local_irq_restore(flags);
-	gic_enable_ppi(clock->irq.irq);
+	*__this_cpu_ptr(clock->percpu_evt) = evt;
 
 	clockevents_register_device(evt);
+	enable_percpu_irq(evt->irq, 0);
 
 	return 0;
 }
 
-int local_timer_ack(void)
+void local_timer_stop(struct clock_event_device *evt)
 {
-	return 1;
+	evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
+	disable_percpu_irq(evt->irq);
 }
 #endif
 
diff --git a/arch/arm/mach-omap2/include/mach/entry-macro.S b/arch/arm/mach-omap2/include/mach/entry-macro.S
index a48690b..22d86ef 100644
--- a/arch/arm/mach-omap2/include/mach/entry-macro.S
+++ b/arch/arm/mach-omap2/include/mach/entry-macro.S
@@ -78,7 +78,7 @@
 4401:		ldr     \irqstat, [\base, #GIC_CPU_INTACK]
 		ldr     \tmp, =1021
 		bic     \irqnr, \irqstat, #0x1c00
-		cmp     \irqnr, #29
+		cmp     \irqnr, #15
 		cmpcc   \irqnr, \irqnr
 		cmpne   \irqnr, \tmp
 		cmpcs   \irqnr, \irqnr
@@ -101,18 +101,6 @@
 		it	cs
 		cmpcs	\irqnr, \irqnr
 		.endm
-
-		/* As above, this assumes that irqstat and base are preserved */
-
-		.macro test_for_ltirq, irqnr, irqstat, base, tmp
-		bic	\irqnr, \irqstat, #0x1c00
-		mov 	\tmp, #0
-		cmp	\irqnr, #29
-		itt	eq
-		moveq	\tmp, #1
-		streq	\irqstat, [\base, #GIC_CPU_EOI]
-		cmp	\tmp, #0
-		.endm
 #endif	/* CONFIG_SMP */
 
 #else	/* MULTI_OMAP2 */
diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
index 32ed551..85df15c 100644
--- a/arch/arm/mach-pxa/irq.c
+++ b/arch/arm/mach-pxa/irq.c
@@ -19,6 +19,8 @@
 #include <linux/io.h>
 #include <linux/irq.h>
 
+#include <asm/exception.h>
+
 #include <mach/hardware.h>
 #include <mach/irqs.h>
 #include <mach/gpio.h>
diff --git a/arch/arm/mach-shmobile/entry-intc.S b/arch/arm/mach-shmobile/entry-intc.S
index cac0a7a..1a1c00c 100644
--- a/arch/arm/mach-shmobile/entry-intc.S
+++ b/arch/arm/mach-shmobile/entry-intc.S
@@ -51,7 +51,4 @@
 	.macro  test_for_ipi, irqnr, irqstat, base, tmp
 	.endm
 
-	.macro  test_for_ltirq, irqnr, irqstat, base, tmp
-	.endm
-
 	arch_irq_handler shmobile_handle_irq_intc
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 7475c2e..d7561bb 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -20,6 +20,7 @@
 #include <linux/highmem.h>
 #include <linux/perf_event.h>
 
+#include <asm/exception.h>
 #include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index db80bd3..da31deb3 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -329,11 +329,12 @@
 #else
 static void arm_memory_present(void)
 {
-	struct memblock_region *reg;
-
-	for_each_memblock(memory, reg)
-		memory_present(0, memblock_region_memory_base_pfn(reg),
-			       memblock_region_memory_end_pfn(reg));
+	struct meminfo *mi = &meminfo;
+	int i;
+	for_each_bank(i, mi) {
+		memory_present(0, bank_pfn_start(&mi->bank[i]),
+				bank_pfn_end(&mi->bank[i]));
+	}
 }
 #endif
 
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 6d589e2..7f15e65 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -796,13 +796,8 @@
 	int i, j, highmem = 0;
 
 #if (defined CONFIG_HIGHMEM) && (defined CONFIG_FIX_MOVABLE_ZONE)
-	void *v_movable_start;
-	if (movable_reserved_size) {
-		v_movable_start = __va(movable_reserved_start);
-
-		if (vmalloc_min > v_movable_start)
-			vmalloc_min = v_movable_start;
-	}
+	if (movable_reserved_size && __pa(vmalloc_min) > movable_reserved_start)
+		vmalloc_min = __va(movable_reserved_start);
 #endif
 	for (i = 0, j = 0; i < meminfo.nr_banks; i++) {
 		struct membank *bank = &meminfo.bank[j];
diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
index e98f5c5..c5ebe6f 100644
--- a/arch/arm/plat-s5p/Kconfig
+++ b/arch/arm/plat-s5p/Kconfig
@@ -11,6 +11,7 @@
 	default y
 	select ARM_VIC if !ARCH_EXYNOS4
 	select ARM_GIC if ARCH_EXYNOS4
+	select GIC_NON_BANKED if ARCH_EXYNOS4
 	select NO_IOPORT
 	select ARCH_REQUIRE_GPIOLIB
 	select S3C_GPIO_TRACK
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index baf3170..b4ca325 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -1132,3 +1132,7 @@
 msm8627_cdp		MACH_MSM8627_CDP	MSM8627_CDP		3861
 msm8627_mtp		MACH_MSM8627_MTP	MSM8627_MTP		3862
 msm8625_rumi3		MACH_MSM8625_RUMI3	MSM8625_RUMI3		3871
+msm7627a_evb		MACH_MSM7627A_EVB	MSM7627A_EVB		3934
+apq8064_cdp		MACH_APQ8064_CDP	APQ8064_CDP		3948
+apq8064_mtp		MACH_APQ8064_MTP	APQ8064_MTP		3949
+apq8064_liquid		MACH_APQ8064_LIQUID	APQ8064_LIQUID		3951
diff --git a/drivers/base/genlock.c b/drivers/base/genlock.c
index 41bbd3a..7e25684 100644
--- a/drivers/base/genlock.c
+++ b/drivers/base/genlock.c
@@ -31,6 +31,9 @@
 #define _RDLOCK  GENLOCK_RDLOCK
 #define _WRLOCK GENLOCK_WRLOCK
 
+#define GENLOCK_LOG_ERR(fmt, args...) \
+pr_err("genlock: %s: " fmt, __func__, ##args)
+
 struct genlock {
 	struct list_head active;  /* List of handles holding lock */
 	spinlock_t lock;          /* Spinlock to protect the lock internals */
@@ -48,11 +51,28 @@
 				     taken */
 };
 
+/*
+ * Create a spinlock to protect against a race condition when a lock gets
+ * released while another process tries to attach it
+ */
+
+static DEFINE_SPINLOCK(genlock_file_lock);
+
 static void genlock_destroy(struct kref *kref)
 {
 	struct genlock *lock = container_of(kref, struct genlock,
 			refcount);
 
+	/*
+	 * Clear the private data for the file descriptor in case the fd is
+	 * still active after the lock gets released
+	 */
+
+	spin_lock(&genlock_file_lock);
+	if (lock->file)
+		lock->file->private_data = NULL;
+	spin_unlock(&genlock_file_lock);
+
 	kfree(lock);
 }
 
@@ -63,6 +83,15 @@
 
 static int genlock_release(struct inode *inodep, struct file *file)
 {
+	struct genlock *lock = file->private_data;
+	/*
+	 * Clear the refrence back to this file structure to avoid
+	 * somehow reusing the lock after the file has been destroyed
+	 */
+
+	if (lock)
+		lock->file = NULL;
+
 	return 0;
 }
 
@@ -81,12 +110,16 @@
 {
 	struct genlock *lock;
 
-	if (handle->lock != NULL)
+	if (handle->lock != NULL) {
+		GENLOCK_LOG_ERR("Handle already has a lock attached\n");
 		return ERR_PTR(-EINVAL);
+	}
 
 	lock = kzalloc(sizeof(*lock), GFP_KERNEL);
-	if (lock == NULL)
+	if (lock == NULL) {
+		GENLOCK_LOG_ERR("Unable to allocate memory for a lock\n");
 		return ERR_PTR(-ENOMEM);
+	}
 
 	INIT_LIST_HEAD(&lock->active);
 	init_waitqueue_head(&lock->queue);
@@ -119,8 +152,10 @@
 {
 	int ret;
 
-	if (!lock->file)
+	if (!lock->file) {
+		GENLOCK_LOG_ERR("No file attached to the lock\n");
 		return -EINVAL;
+	}
 
 	ret = get_unused_fd_flags(0);
 	if (ret < 0)
@@ -142,19 +177,32 @@
 	struct file *file;
 	struct genlock *lock;
 
-	if (handle->lock != NULL)
+	if (handle->lock != NULL) {
+		GENLOCK_LOG_ERR("Handle already has a lock attached\n");
 		return ERR_PTR(-EINVAL);
+	}
 
 	file = fget(fd);
-	if (file == NULL)
+	if (file == NULL) {
+		GENLOCK_LOG_ERR("Bad file descriptor\n");
 		return ERR_PTR(-EBADF);
+	}
 
+	/*
+	 * take a spinlock to avoid a race condition if the lock is
+	 * released and then attached
+	 */
+
+	spin_lock(&genlock_file_lock);
 	lock = file->private_data;
+	spin_unlock(&genlock_file_lock);
 
 	fput(file);
 
-	if (lock == NULL)
+	if (lock == NULL) {
+		GENLOCK_LOG_ERR("File descriptor is invalid\n");
 		return ERR_PTR(-EINVAL);
+	}
 
 	handle->lock = lock;
 	kref_get(&lock->refcount);
@@ -198,13 +246,16 @@
 
 	spin_lock_irqsave(&lock->lock, irqflags);
 
-	if (lock->state == _UNLOCKED)
+	if (lock->state == _UNLOCKED) {
+		GENLOCK_LOG_ERR("Trying to unlock an unlocked handle\n");
 		goto done;
+	}
 
 	/* Make sure this handle is an owner of the lock */
-	if (!handle_has_lock(lock, handle))
+	if (!handle_has_lock(lock, handle)) {
+		GENLOCK_LOG_ERR("handle does not have lock attached to it\n");
 		goto done;
-
+	}
 	/* If the handle holds no more references to the lock then
 	   release it (maybe) */
 
@@ -273,7 +324,8 @@
 		 * Otherwise the user tried to turn a read into a write, and we
 		 * don't allow that.
 		 */
-
+		GENLOCK_LOG_ERR("Trying to upgrade a read lock to a write"
+				"lock\n");
 		ret = -EINVAL;
 		goto done;
 	}
@@ -343,8 +395,10 @@
 	struct genlock *lock = handle->lock;
 	int ret = 0;
 
-	if (lock == NULL)
+	if (lock == NULL) {
+		GENLOCK_LOG_ERR("Handle does not have a lock attached\n");
 		return -EINVAL;
+	}
 
 	switch (op) {
 	case GENLOCK_UNLOCK:
@@ -355,6 +409,7 @@
 		ret = _genlock_lock(lock, handle, op, flags, timeout);
 		break;
 	default:
+		GENLOCK_LOG_ERR("Invalid lock operation\n");
 		ret = -EINVAL;
 		break;
 	}
@@ -376,8 +431,10 @@
 	int ret = 0;
 	unsigned int ticks = msecs_to_jiffies(timeout);
 
-	if (lock == NULL)
+	if (lock == NULL) {
+		GENLOCK_LOG_ERR("Handle does not have a lock attached\n");
 		return -EINVAL;
+	}
 
 	spin_lock_irqsave(&lock->lock, irqflags);
 
@@ -467,8 +524,10 @@
 static struct genlock_handle *_genlock_get_handle(void)
 {
 	struct genlock_handle *handle = kzalloc(sizeof(*handle), GFP_KERNEL);
-	if (handle == NULL)
+	if (handle == NULL) {
+		GENLOCK_LOG_ERR("Unable to allocate memory for the handle\n");
 		return ERR_PTR(-ENOMEM);
+	}
 
 	return handle;
 }
@@ -539,8 +598,11 @@
 		return 0;
 	}
 	case GENLOCK_IOC_EXPORT: {
-		if (handle->lock == NULL)
+		if (handle->lock == NULL) {
+			GENLOCK_LOG_ERR("Handle does not have a lock"
+					"attached\n");
 			return -EINVAL;
+		}
 
 		ret = genlock_get_fd(handle->lock);
 		if (ret < 0)
@@ -585,6 +647,7 @@
 		return 0;
 	}
 	default:
+		GENLOCK_LOG_ERR("Invalid ioctl\n");
 		return -EINVAL;
 	}
 }
diff --git a/drivers/base/iommu.c b/drivers/base/iommu.c
index 6507d8b..ea2a1df6 100644
--- a/drivers/base/iommu.c
+++ b/drivers/base/iommu.c
@@ -171,3 +171,12 @@
 	return iommu_ops->unmap_range(domain, iova, len);
 }
 EXPORT_SYMBOL_GPL(iommu_unmap_range);
+
+phys_addr_t iommu_get_pt_base_addr(struct iommu_domain *domain)
+{
+	if (!iommu_found())
+		return 0;
+
+	return iommu_ops->get_pt_base_addr(domain);
+}
+EXPORT_SYMBOL_GPL(iommu_get_pt_base_addr);
diff --git a/drivers/bluetooth/hci_smd.c b/drivers/bluetooth/hci_smd.c
index 3c4aa8f..101697f 100644
--- a/drivers/bluetooth/hci_smd.c
+++ b/drivers/bluetooth/hci_smd.c
@@ -419,6 +419,7 @@
 	if (rc < 0) {
 		BT_ERR("Cannot open the command channel");
 		hci_free_dev(hdev);
+		hdev = NULL;
 		return -ENODEV;
 	}
 
@@ -427,6 +428,7 @@
 	if (rc < 0) {
 		BT_ERR("Failed to open the Data channel");
 		hci_free_dev(hdev);
+		hdev = NULL;
 		return -ENODEV;
 	}
 
@@ -443,6 +445,15 @@
 
 static void hci_smd_deregister_dev(struct hci_smd_data *hsmd)
 {
+	if (hsmd->hdev) {
+		if (hci_unregister_dev(hsmd->hdev) < 0)
+			BT_ERR("Can't unregister HCI device %s",
+				hsmd->hdev->name);
+
+		hci_free_dev(hsmd->hdev);
+		hsmd->hdev = NULL;
+	}
+
 	smd_close(hs.event_channel);
 	smd_close(hs.data_channel);
 
@@ -452,13 +463,14 @@
 		wake_unlock(&hs.wake_lock_tx);
 
 	/*Destroy the timer used to monitor the Rx queue for emptiness */
-	del_timer_sync(&hs.rx_q_timer);
+	if (hs.rx_q_timer.function) {
+		del_timer_sync(&hs.rx_q_timer);
+		hs.rx_q_timer.function = NULL;
+		hs.rx_q_timer.data = 0;
+	}
+
 	tasklet_kill(&hs.hci_event_task);
 	tasklet_kill(&hs.hci_data_task);
-	if (hci_unregister_dev(hsmd->hdev) < 0)
-		BT_ERR("Can't unregister HCI device %s", hsmd->hdev->name);
-
-	hci_free_dev(hsmd->hdev);
 }
 
 static int hcismd_set_enable(const char *val, struct kernel_param *kp)
diff --git a/drivers/char/diag/Kconfig b/drivers/char/diag/Kconfig
index eb0b21e..53df29b 100644
--- a/drivers/char/diag/Kconfig
+++ b/drivers/char/diag/Kconfig
@@ -29,3 +29,13 @@
 	help
 	 SDIO Transport Layer for DIAG Router
 endmenu
+
+menu "HSIC support for DIAG"
+
+config DIAG_HSIC_PIPE
+	depends on USB_QCOM_DIAG_BRIDGE
+	default y
+	bool "Enable 9K DIAG traffic over HSIC"
+	help
+	 HSIC Transport Layer for DIAG Router
+endmenu
diff --git a/drivers/char/diag/Makefile b/drivers/char/diag/Makefile
index 52ab2b9..c62b7fd 100644
--- a/drivers/char/diag/Makefile
+++ b/drivers/char/diag/Makefile
@@ -1,3 +1,4 @@
 obj-$(CONFIG_DIAG_CHAR) := diagchar.o
 obj-$(CONFIG_DIAG_SDIO_PIPE) += diagfwd_sdio.o
+obj-$(CONFIG_DIAG_HSIC_PIPE) += diagfwd_hsic.o
 diagchar-objs := diagchar_core.o diagchar_hdlc.o diagfwd.o diagmem.o diagfwd_cntl.o
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 292fbc3..f493f79 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2012, Code Aurora Forum. 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 version 2 and
@@ -39,6 +39,7 @@
 #define APPS_DATA  		3
 #define SDIO_DATA		4
 #define WCNSS_DATA		5
+#define HSIC_DATA		6
 #define MODEM_PROC		0
 #define APPS_PROC		1
 #define QDSP_PROC		2
@@ -214,11 +215,30 @@
 	struct work_struct diag_read_mdm_work;
 	struct workqueue_struct *diag_sdio_wq;
 	struct work_struct diag_read_sdio_work;
-	struct work_struct diag_remove_sdio_work;
 	struct work_struct diag_close_sdio_work;
 	struct diag_request *usb_read_mdm_ptr;
 	struct diag_request *write_ptr_mdm;
 #endif
+#ifdef CONFIG_DIAG_HSIC_PIPE
+	unsigned char *buf_in_hsic;
+	unsigned char *usb_buf_mdm_out;
+	int hsic_initialized;
+	int hsic_ch;
+	int hsic_device_enabled;
+	int hsic_device_opened;
+	int read_len_mdm;
+	int in_busy_hsic_read_on_mdm;
+	int in_busy_hsic_write_on_mdm;
+	int in_busy_hsic_write;
+	int in_busy_hsic_read;
+	int usb_mdm_connected;
+	struct usb_diag_ch *mdm_ch;
+	struct workqueue_struct *diag_hsic_wq;
+	struct work_struct diag_read_mdm_work;
+	struct work_struct diag_read_hsic_work;
+	struct diag_request *usb_read_mdm_ptr;
+	struct diag_request *write_ptr_mdm;
+#endif
 };
 
 extern struct diagchar_dev *driver;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 0729753..799be72 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2012, Code Aurora Forum. 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 version 2 and
@@ -31,6 +31,9 @@
 #ifdef CONFIG_DIAG_SDIO_PIPE
 #include "diagfwd_sdio.h"
 #endif
+#ifdef CONFIG_DIAG_HSIC_PIPE
+#include "diagfwd_hsic.h"
+#endif
 #include <linux/timer.h>
 
 MODULE_DESCRIPTION("Diag Char Driver");
@@ -377,6 +380,9 @@
 			driver->in_busy_qdsp_1 = 1;
 			driver->in_busy_qdsp_2 = 1;
 			driver->in_busy_wcnss = 1;
+#ifdef CONFIG_DIAG_SDIO_PIPE
+			driver->in_busy_sdio = 1;
+#endif
 		} else if (temp == NO_LOGGING_MODE && driver->logging_mode
 							== MEMORY_DEVICE_MODE) {
 			driver->in_busy_1 = 0;
@@ -394,6 +400,13 @@
 			if (driver->ch_wcnss)
 				queue_work(driver->diag_wq,
 					&(driver->diag_read_smd_wcnss_work));
+#ifdef CONFIG_DIAG_SDIO_PIPE
+			driver->in_busy_sdio = 0;
+			/* Poll SDIO channel to check for data */
+			if (driver->sdio_ch)
+				queue_work(driver->diag_sdio_wq,
+					&(driver->diag_read_sdio_work));
+#endif
 		}
 #ifdef CONFIG_DIAG_OVER_USB
 		else if (temp == USB_MODE && driver->logging_mode
@@ -420,9 +433,16 @@
 			if (driver->ch_wcnss)
 				queue_work(driver->diag_wq,
 					&(driver->diag_read_smd_wcnss_work));
-		} else if (temp == MEMORY_DEVICE_MODE && driver->logging_mode
-								== USB_MODE)
-			diagfwd_connect();
+#ifdef CONFIG_DIAG_SDIO_PIPE
+			driver->in_busy_sdio = 0;
+			/* Poll SDIO channel to check for data */
+			if (driver->sdio_ch)
+				queue_work(driver->diag_sdio_wq,
+					&(driver->diag_read_sdio_work));
+#endif
+			} else if (temp == MEMORY_DEVICE_MODE &&
+					 driver->logging_mode == USB_MODE)
+				diagfwd_connect();
 #endif /* DIAG over USB */
 		success = 1;
 	}
@@ -553,6 +573,20 @@
 					 driver->write_ptr_wcnss->length);
 			driver->in_busy_wcnss = 0;
 		}
+#ifdef CONFIG_DIAG_SDIO_PIPE
+		/* copy 9K data over SDIO */
+		if (driver->in_busy_sdio == 1) {
+			num_data++;
+			/*Copy the length of data being passed*/
+			COPY_USER_SPACE_OR_EXIT(buf+ret,
+				 (driver->write_ptr_mdm->length), 4);
+			/*Copy the actual data being passed*/
+			COPY_USER_SPACE_OR_EXIT(buf+ret,
+					*(driver->buf_in_sdio),
+					 driver->write_ptr_mdm->length);
+			driver->in_busy_sdio = 0;
+		}
+#endif
 		/* copy number of data fields */
 		COPY_USER_SPACE_OR_EXIT(buf+4, num_data, 4);
 		ret -= 4;
@@ -566,6 +600,11 @@
 		if (driver->ch_wcnss)
 			queue_work(driver->diag_wq,
 					 &(driver->diag_read_smd_wcnss_work));
+#ifdef CONFIG_DIAG_SDIO_PIPE
+		if (driver->sdio_ch)
+			queue_work(driver->diag_sdio_wq,
+					   &(driver->diag_read_sdio_work));
+#endif
 		APPEND_DEBUG('n');
 		goto exit;
 	} else if (driver->data_ready[index] & USER_SPACE_LOG_TYPE) {
@@ -655,7 +694,7 @@
 							 payload_size);
 		/* Check masks for On-Device logging */
 		if (pkt_type == USER_SPACE_LOG_TYPE) {
-			if (!mask_request_validate((unsigned char *)buf)) {
+			if (!mask_request_validate(driver->user_space_data)) {
 				pr_alert("diag: mask request Invalid\n");
 				return -EFAULT;
 			}
@@ -664,8 +703,21 @@
 #ifdef DIAG_DEBUG
 		pr_debug("diag: user space data %d\n", payload_size);
 		for (i = 0; i < payload_size; i++)
-			printk(KERN_DEBUG "\t %x", *(((unsigned char *)buf)+i));
+			pr_debug("\t %x", *((driver->user_space_data)+i));
 #endif
+#ifdef CONFIG_DIAG_SDIO_PIPE
+		/* send masks to 9k too */
+		if (driver->sdio_ch) {
+			wait_event_interruptible(driver->wait_q,
+				 (sdio_write_avail(driver->sdio_ch) >=
+					 payload_size));
+			if (driver->sdio_ch && (payload_size > 0)) {
+				sdio_write(driver->sdio_ch, (void *)
+				   (driver->user_space_data), payload_size);
+			}
+		}
+#endif
+		/* send masks to modem now */
 		diag_process_hdlc((void *)(driver->user_space_data),
 							 payload_size);
 		return 0;
@@ -803,11 +855,11 @@
 	uint8_t subsys_id;
 	uint16_t ss_cmd;
 
-	packet_id = mask_buf[4];
+	packet_id = mask_buf[0];
 
 	if (packet_id == 0x4B) {
-		subsys_id = mask_buf[5];
-		ss_cmd = *(uint16_t *)(mask_buf + 6);
+		subsys_id = mask_buf[1];
+		ss_cmd = *(uint16_t *)(mask_buf + 2);
 		/* Packets with SSID which are allowed */
 		switch (subsys_id) {
 		case 0x04: /* DIAG_SUBSYS_WCDMA */
@@ -933,6 +985,18 @@
 inline void diag_sdio_fn(int type) {}
 #endif
 
+#ifdef CONFIG_DIAG_HSIC_PIPE
+void diag_hsic_fn(int type)
+{
+	if (type == INIT)
+		diagfwd_hsic_init();
+	else if (type == EXIT)
+		diagfwd_hsic_exit();
+}
+#else
+inline void diag_hsic_fn(int type) {}
+#endif
+
 static int __init diagchar_init(void)
 {
 	dev_t dev;
@@ -971,6 +1035,7 @@
 		diagfwd_init();
 		diagfwd_cntl_init();
 		diag_sdio_fn(INIT);
+		diag_hsic_fn(INIT);
 		pr_debug("diagchar initializing ..\n");
 		driver->num = 1;
 		driver->name = ((void *)driver) + sizeof(struct diagchar_dev);
@@ -1003,6 +1068,7 @@
 	diagfwd_exit();
 	diagfwd_cntl_exit();
 	diag_sdio_fn(EXIT);
+	diag_hsic_fn(EXIT);
 	return -1;
 }
 
@@ -1015,6 +1081,7 @@
 	diagfwd_exit();
 	diagfwd_cntl_exit();
 	diag_sdio_fn(EXIT);
+	diag_hsic_fn(EXIT);
 	diagchar_cleanup();
 	printk(KERN_INFO "done diagchar exit\n");
 }
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index c8555cd..6853654 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2012, Code Aurora Forum. 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 version 2 and
@@ -9,7 +9,6 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
-
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/module.h>
@@ -43,7 +42,7 @@
 unsigned char diag_debug_buf[1024];
 static unsigned int buf_tbl_size = 8; /*Number of entries in table of buffers */
 struct diag_master_table entry;
-smd_channel_t *ch_temp;
+smd_channel_t *ch_temp, *chqdsp_temp, *ch_wcnss_temp;
 struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
 struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
 
@@ -72,6 +71,10 @@
 
 int chk_config_get_id(void)
 {
+	/* For all Fusion targets, Modem will always be present */
+	if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
+		return 0;
+
 	switch (socinfo_get_id()) {
 	case APQ8060_MACHINE_ID:
 	case MSM8660_MACHINE_ID:
@@ -80,6 +83,8 @@
 		return AO8960_TOOLS_ID;
 	case APQ8064_MACHINE_ID:
 		return APQ8064_TOOLS_ID;
+	case MSM8930_MACHINE_ID:
+		return MSM8930_TOOLS_ID;
 	default:
 		return 0;
 	}
@@ -94,6 +99,12 @@
 	switch (socinfo_get_id()) {
 	case AO8960_MACHINE_ID:
 	case APQ8064_MACHINE_ID:
+	case MSM8930_MACHINE_ID:
+	case MSM8630_MACHINE_ID:
+	case MSM8230_MACHINE_ID:
+	case APQ8030_MACHINE_ID:
+	case MSM8627_MACHINE_ID:
+	case MSM8227_MACHINE_ID:
 		return 1;
 	default:
 		return 0;
@@ -191,6 +202,13 @@
 			queue_work(driver->diag_wq, &(driver->
 				diag_read_smd_wcnss_work));
 		}
+#ifdef CONFIG_DIAG_SDIO_PIPE
+		else if (proc_num == SDIO_DATA) {
+			driver->in_busy_sdio = 0;
+			queue_work(driver->diag_sdio_wq,
+				&(driver->diag_read_sdio_work));
+		}
+#endif
 		err = -1;
 	}
 #ifdef CONFIG_DIAG_OVER_USB
@@ -226,11 +244,22 @@
 #ifdef CONFIG_DIAG_SDIO_PIPE
 		else if (proc_num == SDIO_DATA) {
 			if (machine_is_msm8x60_fusion() ||
-					machine_is_msm8x60_fusn_ffa()) {
+					 machine_is_msm8x60_fusn_ffa()) {
 				write_ptr->buf = buf;
 				err = usb_diag_write(driver->mdm_ch, write_ptr);
 			} else
-				pr_err("diag: Incorrect data while USB write");
+				pr_err("diag: Incorrect sdio data "
+						"while USB write\n");
+		}
+#endif
+#ifdef CONFIG_DIAG_HSIC_PIPE
+		else if (proc_num == HSIC_DATA) {
+			if (driver->hsic_device_enabled) {
+				write_ptr->buf = buf;
+				err = usb_diag_write(driver->mdm_ch, write_ptr);
+			} else
+				pr_err("diag: Incorrect hsic data "
+						"while USB write\n");
 		}
 #endif
 		APPEND_DEBUG('d');
@@ -885,6 +914,11 @@
 void diag_send_error_rsp(int index)
 {
 	int i;
+
+	if (index > 490) {
+		pr_err("diag: error response too huge, aborting\n");
+		return;
+	}
 	driver->apps_rsp_buf[0] = 0x13; /* error code 13 */
 	for (i = 0; i < index; i++)
 		driver->apps_rsp_buf[i+1] = *(driver->hdlc_buf+i);
@@ -1051,7 +1085,7 @@
 #ifdef CONFIG_DIAG_SDIO_PIPE
 	else if (buf == (void *)driver->buf_in_sdio)
 		if (machine_is_msm8x60_fusion() ||
-					 machine_is_msm8x60_fusn_ffa())
+			 machine_is_msm8x60_fusn_ffa())
 			diagfwd_write_complete_sdio();
 		else
 			pr_err("diag: Incorrect buffer pointer while WRITE");
@@ -1093,7 +1127,7 @@
 #ifdef CONFIG_DIAG_SDIO_PIPE
 	else if (buf == (void *)driver->usb_buf_mdm_out) {
 		if (machine_is_msm8x60_fusion() ||
-					 machine_is_msm8x60_fusn_ffa()) {
+				 machine_is_msm8x60_fusn_ffa()) {
 			driver->read_len_mdm = diag_read_ptr->actual;
 			diagfwd_read_complete_sdio();
 		} else
@@ -1163,12 +1197,28 @@
 #if defined(CONFIG_MSM_N_WAY_SMD)
 static void diag_smd_qdsp_notify(void *ctxt, unsigned event)
 {
+	if (event == SMD_EVENT_CLOSE) {
+		pr_info("diag: clean lpass registration\n");
+		diag_clear_reg(QDSP_PROC);
+		driver->chqdsp = 0;
+		return;
+	} else if (event == SMD_EVENT_OPEN) {
+		driver->chqdsp = chqdsp_temp;
+	}
 	queue_work(driver->diag_wq, &(driver->diag_read_smd_qdsp_work));
 }
 #endif
 
 static void diag_smd_wcnss_notify(void *ctxt, unsigned event)
 {
+	if (event == SMD_EVENT_CLOSE) {
+		pr_info("diag: clean wcnss registration\n");
+		diag_clear_reg(WCNSS_PROC);
+		driver->ch_wcnss = 0;
+		return;
+	} else if (event == SMD_EVENT_OPEN) {
+		driver->ch_wcnss = ch_wcnss_temp;
+	}
 	queue_work(driver->diag_wq, &(driver->diag_read_smd_wcnss_work));
 }
 
@@ -1181,13 +1231,17 @@
 		ch_temp = driver->ch;
 	}
 #if defined(CONFIG_MSM_N_WAY_SMD)
-	if (pdev->id == SMD_APPS_QDSP)
+	if (pdev->id == SMD_APPS_QDSP) {
 		r = smd_named_open_on_edge("DIAG", SMD_APPS_QDSP
 			, &driver->chqdsp, driver, diag_smd_qdsp_notify);
+		chqdsp_temp = driver->chqdsp;
+	}
 #endif
-	if (pdev->id == SMD_APPS_WCNSS)
+	if (pdev->id == SMD_APPS_WCNSS) {
 		r = smd_named_open_on_edge("APPS_RIVA_DATA", SMD_APPS_WCNSS
 			, &driver->ch_wcnss, driver, diag_smd_wcnss_notify);
+		ch_wcnss_temp = driver->ch_wcnss;
+	}
 	pm_runtime_set_active(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
 	pr_debug("diag: open SMD port, Id = %d, r = %d\n", pdev->id, r);
diff --git a/drivers/char/diag/diagfwd_hsic.c b/drivers/char/diag/diagfwd_hsic.c
new file mode 100644
index 0000000..ac5722f
--- /dev/null
+++ b/drivers/char/diag/diagfwd_hsic.c
@@ -0,0 +1,530 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 version 2 and
+ * only 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.
+ */
+
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/uaccess.h>
+#include <linux/diagchar.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/workqueue.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
+#include <asm/current.h>
+#ifdef CONFIG_DIAG_OVER_USB
+#include <mach/usbdiag.h>
+#endif
+#include "diagchar_hdlc.h"
+#include "diagmem.h"
+#include "diagchar.h"
+#include "diagfwd.h"
+#include "diagfwd_hsic.h"
+
+static void diag_read_hsic_work_fn(struct work_struct *work)
+{
+	if (!driver->hsic_ch) {
+		pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
+		return;
+	}
+
+	/*
+	 * If there is no hsic data being read from the hsic and there
+	 * is no hsic data being written to the usb mdm channel
+	 */
+	if (!driver->in_busy_hsic_read && !driver->in_busy_hsic_write_on_mdm) {
+		/*
+		 * Initiate the read from the hsic.  The hsic read is
+		 * asynchronous.  Once the read is complete the read
+		 * callback function will be called.
+		 */
+		int err;
+		driver->in_busy_hsic_read = 1;
+		APPEND_DEBUG('i');
+		err = diag_bridge_read((char *)driver->buf_in_hsic,
+					IN_BUF_SIZE);
+		if (err) {
+			pr_err("DIAG: Error initiating HSIC read, err: %d\n",
+				err);
+			/*
+			 * If the error is recoverable, then clear
+			 * the read flag, so we will resubmit a
+			 * read on the next frame.  Otherwise, don't
+			 * resubmit a read on the next frame.
+			 */
+			if ((-ESHUTDOWN) != err)
+				driver->in_busy_hsic_read = 0;
+		}
+	}
+
+	/*
+	 * If for some reason there was no hsic data, set up
+	 * the next read
+	 */
+	if (!driver->in_busy_hsic_read)
+		queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+}
+
+static void diag_hsic_read_complete_callback(void *ctxt, char *buf,
+					int buf_size, int actual_size)
+{
+	/* The read of the data from the HSIC bridge is complete */
+	driver->in_busy_hsic_read = 0;
+
+	if (!driver->hsic_ch) {
+		pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
+		return;
+	}
+
+	APPEND_DEBUG('j');
+	if (actual_size > 0) {
+		if (!buf) {
+			pr_err("Out of diagmem for HSIC\n");
+		} else {
+			driver->write_ptr_mdm->length = actual_size;
+			/*
+			 * Set flag to denote hsic data is currently
+			 * being written to the usb mdm channel.
+			 * driver->buf_in_hsic was given to
+			 * diag_bridge_read(), so buf here should be
+			 * driver->buf_in_hsic
+			 */
+			driver->in_busy_hsic_write_on_mdm = 1;
+			diag_device_write((void *)buf, HSIC_DATA,
+						driver->write_ptr_mdm);
+		}
+	} else {
+		pr_err("DIAG in %s: actual_size: %d\n", __func__, actual_size);
+	}
+
+	/*
+	 * If for some reason there was no hsic data to write to the
+	 * mdm channel, set up another read
+	 */
+	if (!driver->in_busy_hsic_write_on_mdm)
+		queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+}
+
+static void diag_hsic_write_complete_callback(void *ctxt, char *buf,
+					int buf_size, int actual_size)
+{
+	/* The write of the data to the HSIC bridge is complete */
+	driver->in_busy_hsic_write = 0;
+
+	if (!driver->hsic_ch) {
+		pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
+		return;
+	}
+
+	if (actual_size < 0)
+		pr_err("DIAG in %s: actual_size: %d\n", __func__, actual_size);
+
+	queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
+}
+
+static struct diag_bridge_ops hsic_diag_bridge_ops = {
+	.ctxt = NULL,
+	.read_complete_cb = diag_hsic_read_complete_callback,
+	.write_complete_cb = diag_hsic_write_complete_callback,
+};
+
+static int diag_hsic_close(void)
+{
+	if (driver->hsic_device_enabled) {
+		driver->hsic_ch = 0;
+		if (driver->hsic_device_opened) {
+			driver->hsic_device_opened = 0;
+			diag_bridge_close();
+		}
+		pr_debug("DIAG in %s: closed successfully\n", __func__);
+	} else {
+		pr_debug("DIAG in %s: already closed\n", __func__);
+	}
+
+	return 0;
+}
+
+/* diagfwd_connect_hsic is called when the USB mdm channel is connected */
+static int diagfwd_connect_hsic(void)
+{
+	int err;
+
+	pr_debug("DIAG in %s\n", __func__);
+
+	err = usb_diag_alloc_req(driver->mdm_ch, N_MDM_WRITE, N_MDM_READ);
+	if (err)
+		pr_err("DIAG: unable to alloc USB req on mdm ch err:%d\n", err);
+
+	driver->usb_mdm_connected = 1;
+	driver->in_busy_hsic_write_on_mdm = 0;
+	driver->in_busy_hsic_read_on_mdm = 0;
+	driver->in_busy_hsic_write = 0;
+	driver->in_busy_hsic_read = 0;
+
+	/* If the hsic (diag_bridge) platform device is not open */
+	if (driver->hsic_device_enabled) {
+		if (!driver->hsic_device_opened) {
+			err = diag_bridge_open(&hsic_diag_bridge_ops);
+			if (err) {
+				pr_err("DIAG: HSIC channel open error: %d\n",
+					err);
+			} else {
+				pr_info("DIAG: opened HSIC channel\n");
+				driver->hsic_device_opened = 1;
+			}
+		} else {
+			pr_info("DIAG: HSIC channel already open\n");
+		}
+
+		/*
+		 * Turn on communication over usb mdm and hsic, if the hsic
+		 * device driver is enabled and opened
+		 */
+		if (driver->hsic_device_opened)
+			driver->hsic_ch = 1;
+
+		/* Poll USB mdm channel to check for data */
+		queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
+
+		/* Poll HSIC channel to check for data */
+		queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+	} else {
+		/* The hsic device driver has not yet been enabled */
+		pr_info("DIAG: HSIC channel not yet enabled\n");
+	}
+
+	return 0;
+}
+
+/*
+ * diagfwd_disconnect_hsic is called when the USB mdm channel
+ * is disconnected
+ */
+static int diagfwd_disconnect_hsic(void)
+{
+	pr_debug("DIAG in %s\n", __func__);
+
+	driver->usb_mdm_connected = 0;
+	usb_diag_free_req(driver->mdm_ch);
+	driver->in_busy_hsic_write_on_mdm = 1;
+	driver->in_busy_hsic_read_on_mdm = 1;
+	driver->in_busy_hsic_write = 1;
+	driver->in_busy_hsic_read = 1;
+
+	/* Turn off communication over usb mdm and hsic */
+	driver->hsic_ch = 0;
+
+	return 0;
+}
+
+/*
+ * diagfwd_write_complete_hsic is called after the asynchronous
+ * usb_diag_write() on mdm channel is complete
+ */
+static int diagfwd_write_complete_hsic(void)
+{
+	/*
+	 * Clear flag to denote that the write of the hsic data on the
+	 * usb mdm channel is complete
+	 */
+	driver->in_busy_hsic_write_on_mdm = 0;
+
+	if (!driver->hsic_ch) {
+		pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
+		return 0;
+	}
+
+	APPEND_DEBUG('q');
+
+	/* Read data from the hsic */
+	queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+
+	return 0;
+}
+
+/* Called after the asychronous usb_diag_read() on mdm channel is complete */
+static int diagfwd_read_complete_hsic(struct diag_request *diag_read_ptr)
+{
+	/* The read of the usb driver on the mdm (not hsic) has completed */
+	driver->in_busy_hsic_read_on_mdm = 0;
+	driver->read_len_mdm = diag_read_ptr->actual;
+
+	if (!driver->hsic_ch) {
+		pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
+		return 0;
+	}
+
+	/*
+	 * The read of the usb driver on the mdm channel has completed.
+	 * If there is no write on the hsic in progress, check if the
+	 * read has data to pass on to the hsic. If so, pass the usb
+	 * mdm data on to the hsic.
+	 */
+	if (!driver->in_busy_hsic_write && driver->usb_buf_mdm_out &&
+		(driver->read_len_mdm > 0)) {
+
+		/*
+		 * Initiate the hsic write. The hsic write is
+		 * asynchronous. When complete the write
+		 * complete callback function will be called
+		 */
+		int err;
+		driver->in_busy_hsic_write = 1;
+		err = diag_bridge_write(driver->usb_buf_mdm_out,
+					driver->read_len_mdm);
+		if (err) {
+			pr_err("DIAG: mdm data on hsic write err: %d\n", err);
+			/*
+			 * If the error is recoverable, then clear
+			 * the write flag, so we will resubmit a
+			 * write on the next frame.  Otherwise, don't
+			 * resubmit a write on the next frame.
+			 */
+			if ((-ESHUTDOWN) != err)
+				driver->in_busy_hsic_write = 0;
+		}
+	}
+
+	/*
+	 * If there is no write of the usb mdm data on the
+	 * hsic channel
+	 */
+	if (!driver->in_busy_hsic_write)
+		queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
+
+	return 0;
+}
+
+static void diagfwd_hsic_notifier(void *priv, unsigned event,
+					struct diag_request *d_req)
+{
+	switch (event) {
+	case USB_DIAG_CONNECT:
+		diagfwd_connect_hsic();
+		break;
+	case USB_DIAG_DISCONNECT:
+		diagfwd_disconnect_hsic();
+		break;
+	case USB_DIAG_READ_DONE:
+		diagfwd_read_complete_hsic(d_req);
+		break;
+	case USB_DIAG_WRITE_DONE:
+		diagfwd_write_complete_hsic();
+		break;
+	default:
+		pr_err("DIAG in %s: Unknown event from USB diag:%u\n",
+			__func__, event);
+		break;
+	}
+}
+
+static void diag_read_mdm_work_fn(struct work_struct *work)
+{
+	if (!driver->hsic_ch) {
+		pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
+		return;
+	}
+
+	/*
+	 * If there is no data being read from the usb mdm channel
+	 * and there is no mdm channel data currently being written
+	 * to the hsic
+	 */
+	if (!driver->in_busy_hsic_read_on_mdm && !driver->in_busy_hsic_write) {
+		APPEND_DEBUG('x');
+
+		/* Setup the next read from usb mdm channel */
+		driver->in_busy_hsic_read_on_mdm = 1;
+		driver->usb_read_mdm_ptr->buf = driver->usb_buf_mdm_out;
+		driver->usb_read_mdm_ptr->length = USB_MAX_OUT_BUF;
+		usb_diag_read(driver->mdm_ch, driver->usb_read_mdm_ptr);
+		APPEND_DEBUG('y');
+	}
+
+	/*
+	 * If for some reason there was no mdm channel read initiated,
+	 * queue up the reading of data from the mdm channel
+	 */
+	if (!driver->in_busy_hsic_read_on_mdm)
+		queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
+}
+
+int diag_hsic_enable(void)
+{
+	pr_debug("DIAG in %s\n", __func__);
+
+	driver->read_len_mdm = 0;
+	if (driver->buf_in_hsic == NULL)
+		driver->buf_in_hsic = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
+	if (driver->buf_in_hsic == NULL)
+		goto err;
+	if (driver->usb_buf_mdm_out  == NULL)
+		driver->usb_buf_mdm_out = kzalloc(USB_MAX_OUT_BUF, GFP_KERNEL);
+	if (driver->usb_buf_mdm_out == NULL)
+		goto err;
+	if (driver->write_ptr_mdm == NULL)
+		driver->write_ptr_mdm = kzalloc(
+		sizeof(struct diag_request), GFP_KERNEL);
+	if (driver->write_ptr_mdm == NULL)
+		goto err;
+	if (driver->usb_read_mdm_ptr == NULL)
+		driver->usb_read_mdm_ptr = kzalloc(
+		sizeof(struct diag_request), GFP_KERNEL);
+	if (driver->usb_read_mdm_ptr == NULL)
+		goto err;
+	driver->diag_hsic_wq = create_singlethread_workqueue("diag_hsic_wq");
+#ifdef CONFIG_DIAG_OVER_USB
+	INIT_WORK(&(driver->diag_read_mdm_work), diag_read_mdm_work_fn);
+#endif
+	INIT_WORK(&(driver->diag_read_hsic_work), diag_read_hsic_work_fn);
+
+	driver->hsic_device_enabled = 1;
+
+	return 0;
+err:
+	pr_err("DIAG could not initialize buf for HSIC\n");
+	kfree(driver->buf_in_hsic);
+	kfree(driver->usb_buf_mdm_out);
+	kfree(driver->write_ptr_mdm);
+	kfree(driver->usb_read_mdm_ptr);
+	if (driver->diag_hsic_wq)
+		destroy_workqueue(driver->diag_hsic_wq);
+
+	return -ENOMEM;
+}
+
+static int diag_hsic_probe(struct platform_device *pdev)
+{
+	int err;
+
+	if (!driver->hsic_device_enabled) {
+		err = diag_hsic_enable();
+		if (err) {
+			pr_err("DIAG could not enable HSIC, err: %d\n", err);
+			return err;
+		}
+	}
+
+	/* The hsic (diag_bridge) platform device driver is enabled */
+	err = diag_bridge_open(&hsic_diag_bridge_ops);
+	if (err) {
+		pr_err("DIAG could not open HSIC channel, err: %d\n", err);
+		driver->hsic_device_opened = 0;
+		return err;
+	}
+
+	pr_info("DIAG opened HSIC channel\n");
+	driver->hsic_device_opened = 1;
+
+	/*
+	 * The probe function was called after the usb was connected
+	 * on the legacy channel. Communication over usb mdm and hsic
+	 * needs to be turned on.
+	 */
+	if (driver->usb_connected) {
+		driver->hsic_ch = 1;
+		driver->in_busy_hsic_write_on_mdm = 0;
+		driver->in_busy_hsic_read_on_mdm = 0;
+		driver->in_busy_hsic_write = 0;
+		driver->in_busy_hsic_read = 0;
+
+		/* Poll USB mdm channel to check for data */
+		queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
+
+		/* Poll HSIC channel to check for data */
+		queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+	}
+
+	return err;
+}
+
+static int diag_hsic_remove(struct platform_device *pdev)
+{
+	pr_info("DIAG: %s called\n", __func__);
+	diag_hsic_close();
+	return 0;
+}
+
+static int diagfwd_hsic_runtime_suspend(struct device *dev)
+{
+	dev_dbg(dev, "pm_runtime: suspending...\n");
+	return 0;
+}
+
+static int diagfwd_hsic_runtime_resume(struct device *dev)
+{
+	dev_dbg(dev, "pm_runtime: resuming...\n");
+	return 0;
+}
+
+static const struct dev_pm_ops diagfwd_hsic_dev_pm_ops = {
+	.runtime_suspend = diagfwd_hsic_runtime_suspend,
+	.runtime_resume = diagfwd_hsic_runtime_resume,
+};
+
+static struct platform_driver msm_hsic_ch_driver = {
+	.probe = diag_hsic_probe,
+	.remove = diag_hsic_remove,
+	.driver = {
+		   .name = "diag_bridge",
+		   .owner = THIS_MODULE,
+		   .pm   = &diagfwd_hsic_dev_pm_ops,
+		   },
+};
+
+
+void __init diagfwd_hsic_init(void)
+{
+	int ret;
+
+	pr_debug("DIAG in %s\n", __func__);
+
+#ifdef CONFIG_DIAG_OVER_USB
+	driver->mdm_ch = usb_diag_open(DIAG_MDM, driver, diagfwd_hsic_notifier);
+	if (IS_ERR(driver->mdm_ch)) {
+		pr_err("DIAG Unable to open USB diag MDM channel\n");
+		goto err;
+	}
+#endif
+	ret = platform_driver_register(&msm_hsic_ch_driver);
+	if (ret)
+		pr_err("DIAG could not register HSIC device, ret: %d\n", ret);
+	else
+		driver->hsic_initialized = 1;
+
+	return;
+err:
+	pr_err("DIAG could not initialize for HSIC execution\n");
+}
+
+void __exit diagfwd_hsic_exit(void)
+{
+	pr_debug("DIAG in %s\n", __func__);
+
+	if (driver->hsic_initialized)
+		diag_hsic_close();
+
+#ifdef CONFIG_DIAG_OVER_USB
+	if (driver->usb_mdm_connected)
+		usb_diag_free_req(driver->mdm_ch);
+#endif
+	platform_driver_unregister(&msm_hsic_ch_driver);
+#ifdef CONFIG_DIAG_OVER_USB
+	usb_diag_close(driver->mdm_ch);
+#endif
+	kfree(driver->buf_in_hsic);
+	kfree(driver->usb_buf_mdm_out);
+	kfree(driver->write_ptr_mdm);
+	kfree(driver->usb_read_mdm_ptr);
+	destroy_workqueue(driver->diag_hsic_wq);
+
+	driver->hsic_device_enabled = 0;
+}
diff --git a/drivers/char/diag/diagfwd_hsic.h b/drivers/char/diag/diagfwd_hsic.h
new file mode 100644
index 0000000..6769052
--- /dev/null
+++ b/drivers/char/diag/diagfwd_hsic.h
@@ -0,0 +1,23 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 version 2 and
+ * only 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.
+ */
+
+#ifndef DIAGFWD_HSIC_H
+#define DIAGFWD_HSIC_H
+
+#include <mach/diag_bridge.h>
+#define N_MDM_WRITE	1 /* Upgrade to 2 with ping pong buffer */
+#define N_MDM_READ	1
+
+void __init diagfwd_hsic_init(void);
+void __exit diagfwd_hsic_exit(void);
+
+#endif
diff --git a/drivers/char/diag/diagfwd_sdio.c b/drivers/char/diag/diagfwd_sdio.c
index f3873aa..a145c06 100644
--- a/drivers/char/diag/diagfwd_sdio.c
+++ b/drivers/char/diag/diagfwd_sdio.c
@@ -54,6 +54,13 @@
 			else {
 				APPEND_DEBUG('i');
 				sdio_read(driver->sdio_ch, buf, r);
+				if (((!driver->usb_connected) && (driver->
+					logging_mode == USB_MODE)) || (driver->
+					logging_mode == NO_LOGGING_MODE)) {
+					/* Drop the diag payload */
+					driver->in_busy_sdio = 0;
+					return;
+				}
 				APPEND_DEBUG('j');
 				driver->write_ptr_mdm->length = r;
 				driver->in_busy_sdio = 1;
@@ -149,8 +156,13 @@
 void diag_read_mdm_work_fn(struct work_struct *work)
 {
 	if (driver->sdio_ch) {
-		wait_event_interruptible(driver->wait_q, (sdio_write_avail
-				(driver->sdio_ch) >= driver->read_len_mdm));
+		wait_event_interruptible(driver->wait_q, ((sdio_write_avail
+			(driver->sdio_ch) >= driver->read_len_mdm) ||
+				 !(driver->sdio_ch)));
+		if (!(driver->sdio_ch)) {
+			pr_alert("diag: sdio channel not valid");
+			return;
+		}
 		if (driver->sdio_ch && driver->usb_buf_mdm_out &&
 						 (driver->read_len_mdm > 0))
 			sdio_write(driver->sdio_ch, driver->usb_buf_mdm_out,
@@ -181,15 +193,10 @@
 
 static int diag_sdio_remove(struct platform_device *pdev)
 {
-	queue_work(driver->diag_sdio_wq, &(driver->diag_remove_sdio_work));
-	return 0;
-}
-
-static void diag_remove_sdio_work_fn(struct work_struct *work)
-{
-	pr_debug("diag: sdio remove called\n");
-	/*Disable SDIO channel to prevent further read/write */
+	pr_debug("\n diag: sdio remove called");
+	/* Disable SDIO channel to prevent further read/write */
 	driver->sdio_ch = NULL;
+	return 0;
 }
 
 static int diagfwd_sdio_runtime_suspend(struct device *dev)
@@ -253,7 +260,6 @@
 	INIT_WORK(&(driver->diag_read_mdm_work), diag_read_mdm_work_fn);
 #endif
 	INIT_WORK(&(driver->diag_read_sdio_work), diag_read_sdio_work_fn);
-	INIT_WORK(&(driver->diag_remove_sdio_work), diag_remove_sdio_work_fn);
 	INIT_WORK(&(driver->diag_close_sdio_work), diag_close_sdio_work_fn);
 	ret = platform_driver_register(&msm_sdio_ch_driver);
 	if (ret)
diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c
index edf5c27..7b77fa3 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. 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 version 2 and
@@ -82,6 +82,7 @@
 #define MAX_SESSIONS 16
 #define INVALID_SESSION -1
 #define VERSION_KEY_MASK 0xFFFFFF00
+#define MAX_DOWNSCALE_RATIO 3
 
 struct tile_parm {
 	unsigned int width;  /* tile's width */
@@ -428,7 +429,9 @@
 		}
 		iowrite32((1  << 18) | 		/* chroma sampling 1=H2V1 */
 			  (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
-			  1 << 8,      		/* ROT_EN */
+			  1 << 8 |			/* ROT_EN */
+			  info->downscale_ratio << 2 |	/* downscale v ratio */
+			  info->downscale_ratio,	/* downscale h ratio */
 			  MSM_ROTATOR_SUB_BLOCK_CFG);
 		iowrite32(0 << 29 | 		/* frame format 0 = linear */
 			  (use_imem ? 0 : 1) << 22 | /* tile size */
@@ -480,6 +483,11 @@
 	if (info->dst.format  != dst_format)
 		return -EINVAL;
 
+	/* rotator expects YCbCr for planar input format */
+	if (info->src.format == MDP_Y_CR_CB_H2V2 ||
+	    info->src.format == MDP_Y_CR_CB_GH2V2)
+		swap(in_chroma_paddr, in_chroma2_paddr);
+
 	iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
 	iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
 	iowrite32(in_chroma2_paddr, MSM_ROTATOR_SRCP2_ADDR);
@@ -528,7 +536,9 @@
 		}
 		iowrite32((3  << 18) | 		/* chroma sampling 3=4:2:0 */
 			  (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
-			  1 << 8,      		/* ROT_EN */
+			  1 << 8 |			/* ROT_EN */
+			  info->downscale_ratio << 2 |	/* downscale v ratio */
+			  info->downscale_ratio,	/* downscale h ratio */
 			  MSM_ROTATOR_SUB_BLOCK_CFG);
 
 		iowrite32((is_tile ? 2 : 0) << 29 |  /* frame format */
@@ -579,7 +589,9 @@
 			  MSM_ROTATOR_OUT_PACK_PATTERN1);
 		iowrite32((1  << 18) | 		/* chroma sampling 1=H2V1 */
 			  (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
-			  1 << 8,      		/* ROT_EN */
+			  1 << 8 |			/* ROT_EN */
+			  info->downscale_ratio << 2 |	/* downscale v ratio */
+			  info->downscale_ratio,	/* downscale h ratio */
 			  MSM_ROTATOR_SUB_BLOCK_CFG);
 		iowrite32(0 << 29 | 		/* frame format 0 = linear */
 			  (use_imem ? 0 : 1) << 22 | /* tile size */
@@ -624,7 +636,9 @@
 		iowrite32(info->dst.width * bpp, MSM_ROTATOR_OUT_YSTRIDE1);
 		iowrite32((0  << 18) | 		/* chroma sampling 0=rgb */
 			  (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
-			  1 << 8,      		/* ROT_EN */
+			  1 << 8 |			/* ROT_EN */
+			  info->downscale_ratio << 2 |	/* downscale v ratio */
+			  info->downscale_ratio,	/* downscale h ratio */
 			  MSM_ROTATOR_SUB_BLOCK_CFG);
 		switch (info->src.format) {
 		case MDP_RGB_565:
@@ -1068,24 +1082,31 @@
 	if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
 		return -EFAULT;
 
-	if (info.rotations & MDP_ROT_90) {
-		dst_w = info.src_rect.h;
-		dst_h = info.src_rect.w;
-	} else {
-		dst_w = info.src_rect.w;
-		dst_h = info.src_rect.h;
-	}
-
 	if ((info.rotations > MSM_ROTATOR_MAX_ROT) ||
 	    (info.src.height > MSM_ROTATOR_MAX_H) ||
 	    (info.src.width > MSM_ROTATOR_MAX_W) ||
 	    (info.dst.height > MSM_ROTATOR_MAX_H) ||
 	    (info.dst.width > MSM_ROTATOR_MAX_W) ||
-	    checkoffset(info.src_rect.x, info.src_rect.w, info.src.width) ||
+	    (info.downscale_ratio > MAX_DOWNSCALE_RATIO)) {
+		pr_err("%s: Invalid parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	if (info.rotations & MDP_ROT_90) {
+		dst_w = info.src_rect.h >> info.downscale_ratio;
+		dst_h = info.src_rect.w >> info.downscale_ratio;
+	} else {
+		dst_w = info.src_rect.w >> info.downscale_ratio;
+		dst_h = info.src_rect.h >> info.downscale_ratio;
+	}
+
+	if (checkoffset(info.src_rect.x, info.src_rect.w, info.src.width) ||
 	    checkoffset(info.src_rect.y, info.src_rect.h, info.src.height) ||
 	    checkoffset(info.dst_x, dst_w, info.dst.width) ||
-	    checkoffset(info.dst_y, dst_h, info.dst.height))
-		return -EINVAL;
+	    checkoffset(info.dst_y, dst_h, info.dst.height)) {
+		pr_err("%s: Invalid src or dst rect\n", __func__);
+		return -ERANGE;
+	}
 
 	switch (info.src.format) {
 	case MDP_RGB_565:
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 3ae1647..c1a65fc 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -31,6 +31,7 @@
 #include <crypto/hash.h>
 #include <linux/platform_data/qcom_crypto_device.h>
 #include <mach/scm.h>
+#include <mach/msm_bus.h>
 #include <linux/qcedev.h>
 #include "qce.h"
 
@@ -97,7 +98,7 @@
 };
 
 static DEFINE_MUTEX(send_cmd_lock);
-
+static DEFINE_MUTEX(sent_bw_req);
 /**********************************************************************
  * Register ourselves as a misc device to be able to access the dev driver
  * from userspace. */
@@ -111,9 +112,13 @@
 	struct msm_ce_hw_support platform_support;
 
 	uint32_t ce_lock_count;
+	uint32_t high_bw_req_count;
+
 	/* CE features/algorithms supported by HW engine*/
 	struct ce_hw_support ce_support;
 
+	uint32_t  bus_scale_handle;
+
 	/* misc device */
 	struct miscdevice miscdevice;
 
@@ -167,6 +172,29 @@
 #endif
 }
 
+static int qcedev_ce_high_bw_req(struct qcedev_control *podev,
+							bool high_bw_req)
+{
+	int ret = 0;
+
+	mutex_lock(&sent_bw_req);
+	if (high_bw_req) {
+		if (podev->high_bw_req_count == 0)
+			msm_bus_scale_client_update_request(
+					podev->bus_scale_handle, 1);
+		podev->high_bw_req_count++;
+	} else {
+		if (podev->high_bw_req_count == 1)
+			msm_bus_scale_client_update_request(
+					podev->bus_scale_handle, 0);
+		podev->high_bw_req_count--;
+	}
+	mutex_unlock(&sent_bw_req);
+
+	return ret;
+}
+
+
 static int qcedev_unlock_ce(struct qcedev_control *podev)
 {
 	int ret = 0;
@@ -302,7 +330,8 @@
 
 	handle->cntl = podev;
 	file->private_data = handle;
-
+	if (podev->platform_support.bus_scale_table != NULL)
+		return qcedev_ce_high_bw_req(podev, true);
 	return 0;
 }
 
@@ -319,7 +348,8 @@
 	}
 	kzfree(handle);
 	file->private_data = NULL;
-
+	if (podev->platform_support.bus_scale_table != NULL)
+		return qcedev_ce_high_bw_req(podev, false);
 	return 0;
 }
 
@@ -1992,7 +2022,10 @@
 				platform_support->shared_ce_resource;
 	podev->platform_support.hw_key_support =
 				platform_support->hw_key_support;
+	podev->platform_support.bus_scale_table =
+				platform_support->bus_scale_table;
 	podev->ce_lock_count = 0;
+	podev->high_bw_req_count = 0;
 	INIT_LIST_HEAD(&podev->ready_commands);
 	podev->active_command = NULL;
 
@@ -2011,10 +2044,28 @@
 	podev->pdev = pdev;
 	platform_set_drvdata(pdev, podev);
 	qce_hw_support(podev->qce, &podev->ce_support);
+
+	if (podev->platform_support.bus_scale_table != NULL) {
+		podev->bus_scale_handle =
+			msm_bus_scale_register_client(
+				(struct msm_bus_scale_pdata *)
+				podev->platform_support.bus_scale_table);
+		if (!podev->bus_scale_handle) {
+			printk(KERN_ERR "%s not able to get bus scale\n",
+								__func__);
+			rc =  -ENOMEM;
+			goto err;
+		}
+	}
 	rc = misc_register(&podev->miscdevice);
 
 	if (rc >= 0)
 		return 0;
+	else
+		if (podev->platform_support.bus_scale_table != NULL)
+			msm_bus_scale_unregister_client(
+						podev->bus_scale_handle);
+err:
 
 	if (handle)
 		qce_close(handle);
@@ -2034,6 +2085,9 @@
 	if (podev->qce)
 		qce_close(podev->qce);
 
+	if (podev->platform_support.bus_scale_table != NULL)
+		msm_bus_scale_unregister_client(podev->bus_scale_handle);
+
 	if (podev->miscdevice.minor != MISC_DYNAMIC_MINOR)
 		misc_deregister(&podev->miscdevice);
 	tasklet_kill(&podev->done_tasklet);
@@ -2164,7 +2218,7 @@
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Mona Hossain <mhossain@codeaurora.org>");
 MODULE_DESCRIPTION("Qualcomm DEV Crypto driver");
-MODULE_VERSION("1.24");
+MODULE_VERSION("1.25");
 
 module_init(qcedev_init);
 module_exit(qcedev_exit);
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index 67301877..3fff05c 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -37,6 +37,7 @@
 
 #include <mach/scm.h>
 #include <linux/platform_data/qcom_crypto_device.h>
+#include <mach/msm_bus.h>
 #include "qce.h"
 
 
@@ -80,6 +81,8 @@
 
 	/* CE features/algorithms supported by HW engine*/
 	struct ce_hw_support ce_support;
+
+	uint32_t  bus_scale_handle;
 	/* the lock protects queue and req*/
 	spinlock_t lock;
 
@@ -100,6 +103,7 @@
 	struct crypto_queue queue;
 
 	uint32_t ce_lock_count;
+	uint32_t high_bw_req_count;
 
 	struct work_struct unlock_ce_ws;
 
@@ -116,6 +120,8 @@
 #define NUM_RETRY				1000
 #define CE_BUSY				        55
 
+static DEFINE_MUTEX(sent_bw_req);
+
 static int qcrypto_scm_cmd(int resource, int cmd, int *response)
 {
 #ifdef CONFIG_MSM_SCM
@@ -323,6 +329,27 @@
 	}
 }
 
+static int qcrypto_ce_high_bw_req(struct crypto_priv *cp, bool high_bw_req)
+{
+	int ret = 0;
+
+	mutex_lock(&sent_bw_req);
+	if (high_bw_req) {
+		if (cp->high_bw_req_count == 0)
+			ret = msm_bus_scale_client_update_request(
+				cp->bus_scale_handle, 1);
+		cp->high_bw_req_count++;
+	} else {
+		if (cp->high_bw_req_count == 1)
+			ret = msm_bus_scale_client_update_request(
+				cp->bus_scale_handle, 0);
+		cp->high_bw_req_count--;
+	}
+	mutex_unlock(&sent_bw_req);
+
+	return ret;
+}
+
 static void _start_qcrypto_process(struct crypto_priv *cp);
 
 static struct qcrypto_alg *_qcrypto_sha_alg_alloc(struct crypto_priv *cp,
@@ -375,6 +402,8 @@
 
 	/* random first IV */
 	get_random_bytes(ctx->iv, QCRYPTO_MAX_IV_LENGTH);
+	if (ctx->cp->platform_support.bus_scale_table != NULL)
+		return  qcrypto_ce_high_bw_req(ctx->cp, true);
 
 	return 0;
 };
@@ -410,6 +439,9 @@
 	}
 
 	sha_ctx->ahash_req = NULL;
+	if (sha_ctx->cp->platform_support.bus_scale_table != NULL)
+		return qcrypto_ce_high_bw_req(sha_ctx->cp, true);
+
 	return 0;
 };
 
@@ -429,6 +461,8 @@
 		ahash_request_free(sha_ctx->ahash_req);
 		sha_ctx->ahash_req = NULL;
 	}
+	if (sha_ctx->cp->platform_support.bus_scale_table != NULL)
+		qcrypto_ce_high_bw_req(sha_ctx->cp, false);
 };
 
 
@@ -458,6 +492,9 @@
 				&sha_ctx->ahash_req_complete);
 	crypto_ahash_clear_flags(ahash, ~0);
 
+	if (sha_ctx->cp->platform_support.bus_scale_table != NULL)
+		qcrypto_ce_high_bw_req(sha_ctx->cp, true);
+
 	return 0;
 };
 
@@ -473,6 +510,22 @@
 	return _qcrypto_cipher_cra_init(tfm);
 };
 
+static void _qcrypto_cra_ablkcipher_exit(struct crypto_tfm *tfm)
+{
+	struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	if (ctx->cp->platform_support.bus_scale_table != NULL)
+		qcrypto_ce_high_bw_req(ctx->cp, false);
+};
+
+static void _qcrypto_cra_aead_exit(struct crypto_tfm *tfm)
+{
+	struct qcrypto_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	if (ctx->cp->platform_support.bus_scale_table != NULL)
+		qcrypto_ce_high_bw_req(ctx->cp, false);
+};
+
 static int _disp_stats(int id)
 {
 	struct crypto_stat *pstat;
@@ -577,6 +630,9 @@
 	if (!cp)
 		return 0;
 
+	if (cp->platform_support.bus_scale_table != NULL)
+		msm_bus_scale_unregister_client(cp->bus_scale_handle);
+
 	list_for_each_entry_safe(q_alg, n, &cp->alg_list, entry) {
 		if (q_alg->alg_type == QCRYPTO_ALG_CIPHER)
 			crypto_unregister_alg(&q_alg->cipher_alg);
@@ -2676,6 +2732,7 @@
 		.cra_type	= &crypto_ablkcipher_type,
 		.cra_module	= THIS_MODULE,
 		.cra_init	= _qcrypto_cra_ablkcipher_init,
+		.cra_exit	= _qcrypto_cra_ablkcipher_exit,
 		.cra_u		= {
 			.ablkcipher = {
 				.min_keysize	= AES_MIN_KEY_SIZE,
@@ -2697,6 +2754,7 @@
 		.cra_type	= &crypto_ablkcipher_type,
 		.cra_module	= THIS_MODULE,
 		.cra_init	= _qcrypto_cra_ablkcipher_init,
+		.cra_exit	= _qcrypto_cra_ablkcipher_exit,
 		.cra_u		= {
 			.ablkcipher = {
 				.ivsize		= AES_BLOCK_SIZE,
@@ -2719,6 +2777,7 @@
 		.cra_type	= &crypto_ablkcipher_type,
 		.cra_module	= THIS_MODULE,
 		.cra_init	= _qcrypto_cra_ablkcipher_init,
+		.cra_exit	= _qcrypto_cra_ablkcipher_exit,
 		.cra_u		= {
 			.ablkcipher = {
 				.ivsize		= AES_BLOCK_SIZE,
@@ -2741,6 +2800,7 @@
 		.cra_type	= &crypto_ablkcipher_type,
 		.cra_module	= THIS_MODULE,
 		.cra_init	= _qcrypto_cra_ablkcipher_init,
+		.cra_exit	= _qcrypto_cra_ablkcipher_exit,
 		.cra_u		= {
 			.ablkcipher = {
 				.min_keysize	= DES_KEY_SIZE,
@@ -2762,6 +2822,7 @@
 		.cra_type	= &crypto_ablkcipher_type,
 		.cra_module	= THIS_MODULE,
 		.cra_init	= _qcrypto_cra_ablkcipher_init,
+		.cra_exit	= _qcrypto_cra_ablkcipher_exit,
 		.cra_u		= {
 			.ablkcipher = {
 				.ivsize		= DES_BLOCK_SIZE,
@@ -2784,6 +2845,7 @@
 		.cra_type	= &crypto_ablkcipher_type,
 		.cra_module	= THIS_MODULE,
 		.cra_init	= _qcrypto_cra_ablkcipher_init,
+		.cra_exit	= _qcrypto_cra_ablkcipher_exit,
 		.cra_u		= {
 			.ablkcipher = {
 				.min_keysize	= DES3_EDE_KEY_SIZE,
@@ -2805,6 +2867,7 @@
 		.cra_type	= &crypto_ablkcipher_type,
 		.cra_module	= THIS_MODULE,
 		.cra_init	= _qcrypto_cra_ablkcipher_init,
+		.cra_exit	= _qcrypto_cra_ablkcipher_exit,
 		.cra_u		= {
 			.ablkcipher = {
 				.ivsize		= DES3_EDE_BLOCK_SIZE,
@@ -2829,6 +2892,7 @@
 	.cra_type	= &crypto_ablkcipher_type,
 	.cra_module	= THIS_MODULE,
 	.cra_init	= _qcrypto_cra_ablkcipher_init,
+	.cra_exit	= _qcrypto_cra_ablkcipher_exit,
 	.cra_u		= {
 		.ablkcipher = {
 			.ivsize		= AES_BLOCK_SIZE,
@@ -2853,6 +2917,7 @@
 		.cra_type	= &crypto_aead_type,
 		.cra_module	= THIS_MODULE,
 		.cra_init	= _qcrypto_cra_aead_init,
+		.cra_exit	= _qcrypto_cra_aead_exit,
 		.cra_u		= {
 			.aead = {
 				.ivsize         = AES_BLOCK_SIZE,
@@ -2879,6 +2944,7 @@
 		.cra_type	= &crypto_aead_type,
 		.cra_module	= THIS_MODULE,
 		.cra_init	= _qcrypto_cra_aead_init,
+		.cra_exit	= _qcrypto_cra_aead_exit,
 		.cra_u		= {
 			.aead = {
 				.ivsize         = AES_BLOCK_SIZE,
@@ -2904,6 +2970,7 @@
 		.cra_type	= &crypto_aead_type,
 		.cra_module	= THIS_MODULE,
 		.cra_init	= _qcrypto_cra_aead_init,
+		.cra_exit	= _qcrypto_cra_aead_exit,
 		.cra_u		= {
 			.aead = {
 				.ivsize         = DES_BLOCK_SIZE,
@@ -2928,6 +2995,7 @@
 		.cra_type	= &crypto_aead_type,
 		.cra_module	= THIS_MODULE,
 		.cra_init	= _qcrypto_cra_aead_init,
+		.cra_exit	= _qcrypto_cra_aead_exit,
 		.cra_u		= {
 			.aead = {
 				.ivsize         = DES3_EDE_BLOCK_SIZE,
@@ -2954,6 +3022,7 @@
 	.cra_type	= &crypto_aead_type,
 	.cra_module	= THIS_MODULE,
 	.cra_init	= _qcrypto_cra_aead_init,
+	.cra_exit	= _qcrypto_cra_aead_exit,
 	.cra_u		= {
 		.aead = {
 			.ivsize         = AES_BLOCK_SIZE,
@@ -3011,12 +3080,28 @@
 				platform_support->shared_ce_resource;
 	cp->platform_support.hw_key_support =
 				platform_support->hw_key_support;
+	cp->platform_support.bus_scale_table =
+				platform_support->bus_scale_table;
+	cp->high_bw_req_count = 0;
 	cp->ce_lock_count = 0;
 	cp->platform_support.sha_hmac = platform_support->sha_hmac;
 
 	if (cp->platform_support.ce_shared)
 		INIT_WORK(&cp->unlock_ce_ws, qcrypto_unlock_ce);
 
+	if (cp->platform_support.bus_scale_table != NULL) {
+		cp->bus_scale_handle =
+			msm_bus_scale_register_client(
+				(struct msm_bus_scale_pdata *)
+					cp->platform_support.bus_scale_table);
+		if (!cp->bus_scale_handle) {
+			printk(KERN_ERR "%s not able to get bus scale\n",
+				__func__);
+			rc =  -ENOMEM;
+			goto err;
+		}
+	}
+
 	/* register crypto cipher algorithms the device supports */
 	for (i = 0; i < ARRAY_SIZE(_qcrypto_ablk_cipher_algos); i++) {
 		struct qcrypto_alg *q_alg;
@@ -3274,4 +3359,4 @@
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Mona Hossain <mhossain@codeaurora.org>");
 MODULE_DESCRIPTION("Qualcomm Crypto driver");
-MODULE_VERSION("1.19");
+MODULE_VERSION("1.20");
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 385e9c7..8f3263e 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -454,16 +454,6 @@
 	  Select this option to enable GPIO driver for the TPS65910
 	  chip family.
 
-config MPP_PMIC8901
-        tristate "Qualcomm PMIC8901 MPP"
-        depends on GPIOLIB && PMIC8901
-        default y
-        help
-          Say yes here to support GPIO functionality on Qualcomm's
-          PM8901 chip for MPP(Multi-Purpose Pin) pins. These pins
-          work like GPIO pins when configured as digital input and/or
-          output signals.
-
 config GPIO_PM8XXX
 	tristate "Qualcomm PM8xxx GPIO support"
 	depends on MFD_PM8XXX
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 1b2c4b1..83972f1 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -48,7 +48,6 @@
 obj-$(CONFIG_GPIO_ML_IOH)	+= ml_ioh_gpio.o
 obj-$(CONFIG_AB8500_GPIO)       += ab8500-gpio.o
 obj-$(CONFIG_GPIO_TPS65910)	+= tps65910-gpio.o
-obj-$(CONFIG_MPP_PMIC8901)      += pmic8901-mpp.o
 obj-$(CONFIG_GPIO_PM8XXX)	+= pm8xxx-gpio.o
 obj-$(CONFIG_GPIO_PM8XXX_MPP) 	+= pm8xxx-mpp.o
 obj-$(CONFIG_GPIO_PM8XXX_RPC)	+= gpio-pm8xxx-rpc.o
diff --git a/drivers/gpio/pmic8901-mpp.c b/drivers/gpio/pmic8901-mpp.c
deleted file mode 100644
index 85e6539..0000000
--- a/drivers/gpio/pmic8901-mpp.c
+++ /dev/null
@@ -1,231 +0,0 @@
-/* Copyright (c) 2010, Code Aurora Forum. 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 version 2 and
- * only 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.
- *
- */
-/*
- * Qualcomm PMIC8901 MPP driver
- *
- */
-
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/mfd/pmic8901.h>
-#include <mach/mpp.h>
-#include <linux/seq_file.h>
-
-/* MPP Control Registers */
-#define	SSBI_MPP_CNTRL_BASE		0x27
-#define	SSBI_MPP_CNTRL(n)		(SSBI_MPP_CNTRL_BASE + (n))
-
-/* MPP Type */
-#define	PM8901_MPP_TYPE_MASK		0xE0
-#define	PM8901_MPP_TYPE_SHIFT		5
-
-/* MPP Config Level */
-#define	PM8901_MPP_CONFIG_LVL_MASK	0x1C
-#define	PM8901_MPP_CONFIG_LVL_SHIFT	2
-
-/* MPP Config Control */
-#define	PM8901_MPP_CONFIG_CTL_MASK	0x03
-
-struct pm8901_mpp_chip {
-	struct gpio_chip	chip;
-	struct pm8901_chip	*pm_chip;
-	u8			ctrl[PM8901_MPPS];
-};
-
-static int pm8901_mpp_write(struct pm8901_chip *chip, u16 addr, u8 val,
-		u8 mask, u8 *bak)
-{
-	u8 reg = (*bak & ~mask) | (val & mask);
-	int rc = pm8901_write(chip, addr, &reg, 1);
-	if (!rc)
-		*bak = reg;
-	return rc;
-}
-
-static int pm8901_mpp_to_irq(struct gpio_chip *chip, unsigned offset)
-{
-	struct pm8901_gpio_platform_data *pdata;
-	pdata = chip->dev->platform_data;
-	return pdata->irq_base + offset;
-}
-
-static int pm8901_mpp_get(struct gpio_chip *chip, unsigned offset)
-{
-	struct pm8901_mpp_chip *mpp_chip = dev_get_drvdata(chip->dev);
-	int ret;
-
-	if ((mpp_chip->ctrl[offset] & PM8901_MPP_TYPE_MASK) >>
-			PM8901_MPP_TYPE_SHIFT == PM_MPP_TYPE_D_OUTPUT)
-		ret = mpp_chip->ctrl[offset] & PM8901_MPP_CONFIG_CTL_MASK;
-	else
-		ret = pm8901_irq_get_rt_status(mpp_chip->pm_chip,
-				pm8901_mpp_to_irq(chip, offset));
-	return ret;
-}
-
-static void pm8901_mpp_set(struct gpio_chip *chip, unsigned offset, int val)
-{
-	struct pm8901_mpp_chip *mpp_chip = dev_get_drvdata(chip->dev);
-	u8 reg = val ? PM_MPP_DOUT_CTL_HIGH : PM_MPP_DOUT_CTL_LOW;
-	int rc;
-
-	rc = pm8901_mpp_write(mpp_chip->pm_chip, SSBI_MPP_CNTRL(offset),
-			reg, PM8901_MPP_CONFIG_CTL_MASK,
-			&mpp_chip->ctrl[offset]);
-	if (rc)
-		pr_err("%s: pm8901_mpp_write(): rc=%d\n", __func__, rc);
-}
-
-static int pm8901_mpp_dir_input(struct gpio_chip *chip, unsigned offset)
-{
-	struct pm8901_mpp_chip *mpp_chip = dev_get_drvdata(chip->dev);
-	int rc = pm8901_mpp_write(mpp_chip->pm_chip,
-			SSBI_MPP_CNTRL(offset),
-			PM_MPP_TYPE_D_INPUT << PM8901_MPP_TYPE_SHIFT,
-			PM8901_MPP_TYPE_MASK, &mpp_chip->ctrl[offset]);
-	if (rc)
-		pr_err("%s: pm8901_mpp_write(): rc=%d\n", __func__, rc);
-	return rc;
-}
-
-static int pm8901_mpp_dir_output(struct gpio_chip *chip,
-		unsigned offset, int val)
-{
-	struct pm8901_mpp_chip *mpp_chip = dev_get_drvdata(chip->dev);
-	u8 reg = (PM_MPP_TYPE_D_OUTPUT << PM8901_MPP_TYPE_SHIFT) |
-		(val & PM8901_MPP_CONFIG_CTL_MASK);
-	u8 mask = PM8901_MPP_TYPE_MASK | PM8901_MPP_CONFIG_CTL_MASK;
-	int rc = pm8901_mpp_write(mpp_chip->pm_chip,
-			SSBI_MPP_CNTRL(offset), reg, mask,
-			&mpp_chip->ctrl[offset]);
-	if (rc)
-		pr_err("%s: pm8901_mpp_write(): rc=%d\n", __func__, rc);
-	return rc;
-}
-
-static void pm8901_mpp_dbg_show(struct seq_file *s, struct gpio_chip *chip)
-{
-	static const char *ctype[] = { "d_in", "d_out", "bi_dir", "a_in",
-		"a_out", "sink", "dtest_sink", "dtest_out" };
-	struct pm8901_mpp_chip *mpp_chip = dev_get_drvdata(chip->dev);
-	u8 type, state;
-	const char *label;
-	int i;
-
-	for (i = 0; i < PM8901_MPPS; i++) {
-		label = gpiochip_is_requested(chip, i);
-		type = (mpp_chip->ctrl[i] & PM8901_MPP_TYPE_MASK) >>
-			PM8901_MPP_TYPE_SHIFT;
-		state = pm8901_mpp_get(chip, i);
-		seq_printf(s, "gpio-%-3d (%-12.12s) %-10.10s"
-				" %s 0x%02x\n",
-				chip->base + i,
-				label ? label : "--",
-				ctype[type],
-				state ? "hi" : "lo",
-				mpp_chip->ctrl[i]);
-	}
-}
-
-static struct pm8901_mpp_chip pm8901_mpp_chip = {
-	.chip = {
-		.label			= "pm8901-mpp",
-		.to_irq			= pm8901_mpp_to_irq,
-		.get			= pm8901_mpp_get,
-		.set			= pm8901_mpp_set,
-		.direction_input	= pm8901_mpp_dir_input,
-		.direction_output	= pm8901_mpp_dir_output,
-		.dbg_show		= pm8901_mpp_dbg_show,
-		.ngpio			= PM8901_MPPS,
-	},
-};
-
-int pm8901_mpp_config(unsigned mpp, unsigned type, unsigned level,
-		      unsigned control)
-{
-	u8	config, mask;
-	int	rc;
-
-	if (mpp >= PM8901_MPPS)
-		return -EINVAL;
-
-	mask = PM8901_MPP_TYPE_MASK | PM8901_MPP_CONFIG_LVL_MASK |
-		PM8901_MPP_CONFIG_CTL_MASK;
-	config = (type << PM8901_MPP_TYPE_SHIFT) & PM8901_MPP_TYPE_MASK;
-	config |= (level << PM8901_MPP_CONFIG_LVL_SHIFT) &
-			PM8901_MPP_CONFIG_LVL_MASK;
-	config |= control & PM8901_MPP_CONFIG_CTL_MASK;
-
-	rc = pm8901_mpp_write(pm8901_mpp_chip.pm_chip, SSBI_MPP_CNTRL(mpp),
-			config, mask, &pm8901_mpp_chip.ctrl[mpp]);
-	if (rc)
-		pr_err("%s: pm8901_mpp_write(): rc=%d\n", __func__, rc);
-
-	return rc;
-}
-EXPORT_SYMBOL(pm8901_mpp_config);
-
-static int __devinit pm8901_mpp_probe(struct platform_device *pdev)
-{
-	int ret, i;
-	struct pm8901_gpio_platform_data *pdata = pdev->dev.platform_data;
-
-	pm8901_mpp_chip.pm_chip = dev_get_drvdata(pdev->dev.parent);
-	for (i = 0; i < PM8901_MPPS; i++) {
-		ret = pm8901_read(pm8901_mpp_chip.pm_chip,
-				SSBI_MPP_CNTRL(i), &pm8901_mpp_chip.ctrl[i], 1);
-		if (ret)
-			goto bail;
-
-	}
-	platform_set_drvdata(pdev, &pm8901_mpp_chip);
-	pm8901_mpp_chip.chip.dev = &pdev->dev;
-	pm8901_mpp_chip.chip.base = pdata->gpio_base;
-	ret = gpiochip_add(&pm8901_mpp_chip.chip);
-
-bail:
-	pr_info("%s: gpiochip_add(): rc=%d\n", __func__, ret);
-	return ret;
-}
-
-static int __devexit pm8901_mpp_remove(struct platform_device *pdev)
-{
-	return gpiochip_remove(&pm8901_mpp_chip.chip);
-}
-
-static struct platform_driver pm8901_mpp_driver = {
-	.probe		= pm8901_mpp_probe,
-	.remove		= __devexit_p(pm8901_mpp_remove),
-	.driver		= {
-		.name = "pm8901-mpp",
-		.owner = THIS_MODULE,
-	},
-};
-
-static int __init pm8901_mpp_init(void)
-{
-	return platform_driver_register(&pm8901_mpp_driver);
-}
-
-static void __exit pm8901_mpp_exit(void)
-{
-	platform_driver_unregister(&pm8901_mpp_driver);
-}
-
-subsys_initcall(pm8901_mpp_init);
-module_exit(pm8901_mpp_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("PMIC8901 MPP driver");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:pm8901-mpp");
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index 9cb338a..f1d40ef 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -36,8 +36,8 @@
 	ion_phys_addr_t base;
 	unsigned long allocated_bytes;
 	unsigned long total_size;
-	void (*request_region)(void *);
-	void (*release_region)(void *);
+	int (*request_region)(void *);
+	int (*release_region)(void *);
 	atomic_t map_count;
 	void *bus_id;
 };
@@ -138,10 +138,17 @@
 	struct ion_carveout_heap *carveout_heap =
 		container_of(heap, struct ion_carveout_heap, heap);
 
-	if (atomic_inc_return(&carveout_heap->map_count) == 1)
-		if (carveout_heap->request_region)
-			carveout_heap->request_region(carveout_heap->bus_id);
-
+	if (atomic_inc_return(&carveout_heap->map_count) == 1) {
+		if (carveout_heap->request_region) {
+			int ret = carveout_heap->request_region(
+						carveout_heap->bus_id);
+			if (ret) {
+				pr_err("Unable to request SMI region");
+				atomic_dec(&carveout_heap->map_count);
+				return NULL;
+			}
+		}
+	}
 	if (ION_IS_CACHED(flags))
 		return ioremap_cached(buffer->priv_phys, buffer->size);
 	else
@@ -157,9 +164,14 @@
 	__arch_iounmap(buffer->vaddr);
 	buffer->vaddr = NULL;
 
-	if (atomic_dec_and_test(&carveout_heap->map_count))
-		if (carveout_heap->release_region)
-			carveout_heap->release_region(carveout_heap->bus_id);
+	if (atomic_dec_and_test(&carveout_heap->map_count)) {
+		if (carveout_heap->release_region) {
+			int ret = carveout_heap->release_region(
+						carveout_heap->bus_id);
+			if (ret)
+				pr_err("Unable to release SMI region");
+		}
+	}
 
 	return;
 }
@@ -170,9 +182,17 @@
 	struct ion_carveout_heap *carveout_heap =
 		container_of(heap, struct ion_carveout_heap, heap);
 
-	if (atomic_inc_return(&carveout_heap->map_count) == 1)
-		if (carveout_heap->request_region)
-			carveout_heap->request_region(carveout_heap->bus_id);
+	if (atomic_inc_return(&carveout_heap->map_count) == 1) {
+		if (carveout_heap->request_region) {
+			int ret = carveout_heap->request_region(
+						carveout_heap->bus_id);
+			if (ret) {
+				pr_err("Unable to request SMI region");
+				atomic_dec(&carveout_heap->map_count);
+				return -EINVAL;
+			}
+		}
+	}
 
 	if (ION_IS_CACHED(flags))
 		return remap_pfn_range(vma, vma->vm_start,
@@ -192,9 +212,14 @@
 	struct ion_carveout_heap *carveout_heap =
 		container_of(heap, struct ion_carveout_heap, heap);
 
-	if (atomic_dec_and_test(&carveout_heap->map_count))
-		if (carveout_heap->release_region)
-			carveout_heap->release_region(carveout_heap->bus_id);
+	if (atomic_dec_and_test(&carveout_heap->map_count)) {
+		if (carveout_heap->release_region) {
+			int ret = carveout_heap->release_region(
+						carveout_heap->bus_id);
+			if (ret)
+				pr_err("Unable to release SMI region");
+		}
+	}
 }
 
 int ion_carveout_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer,
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index d2e4e4b..a8a0e59 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -194,7 +194,7 @@
 
 	if (device->requested_state == KGSL_STATE_NONE) {
 		if (device->pwrctrl.nap_allowed == true) {
-			device->requested_state = KGSL_STATE_NAP;
+			kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
 			queue_work(device->work_queue, &device->idle_check_ws);
 		} else if (device->pwrscale.policy != NULL) {
 			queue_work(device->work_queue, &device->idle_check_ws);
@@ -495,8 +495,7 @@
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	int init_reftimestamp = 0x7fffffff;
 
-	device->state = KGSL_STATE_INIT;
-	device->requested_state = KGSL_STATE_NONE;
+	kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
 
 	/* Power up the device */
 	kgsl_pwrctrl_enable(device);
@@ -716,33 +715,27 @@
 static int
 adreno_dump_and_recover(struct kgsl_device *device)
 {
-	static int recovery;
 	int result = -ETIMEDOUT;
 
 	if (device->state == KGSL_STATE_HUNG)
 		goto done;
-	if (device->state == KGSL_STATE_DUMP_AND_RECOVER && !recovery) {
+	if (device->state == KGSL_STATE_DUMP_AND_RECOVER) {
 		mutex_unlock(&device->mutex);
 		wait_for_completion(&device->recovery_gate);
 		mutex_lock(&device->mutex);
-		if (!(device->state & KGSL_STATE_HUNG))
-			/* recovery success */
+		if (device->state != KGSL_STATE_HUNG)
 			result = 0;
 	} else {
+		kgsl_pwrctrl_set_state(device, KGSL_STATE_DUMP_AND_RECOVER);
 		INIT_COMPLETION(device->recovery_gate);
 		/* Detected a hang - trigger an automatic dump */
 		adreno_postmortem_dump(device, 0);
-		if (!recovery) {
-			recovery = 1;
-			result = adreno_recover_hang(device);
-			if (result)
-				device->state = KGSL_STATE_HUNG;
-			recovery = 0;
-			complete_all(&device->recovery_gate);
-		} else
-			KGSL_DRV_ERR(device,
-				"Cannot recover from another hang while "
-				"recovering from a hang\n");
+		result = adreno_recover_hang(device);
+		if (result)
+			kgsl_pwrctrl_set_state(device, KGSL_STATE_HUNG);
+		else
+			kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
+		complete_all(&device->recovery_gate);
 	}
 done:
 	return result;
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 9e49e6a..aafef21 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -21,6 +21,7 @@
 #include "adreno_postmortem.h"
 #include "adreno_debugfs.h"
 #include "kgsl_cffdump.h"
+#include "kgsl_pwrctrl.h"
 
 #include "a2xx_reg.h"
 
@@ -828,11 +829,9 @@
 
 	/* Disable the idle timer so we don't get interrupted */
 	del_timer_sync(&device->idle_timer);
-
 	mutex_unlock(&device->mutex);
 	flush_workqueue(device->work_queue);
 	mutex_lock(&device->mutex);
-	adreno_dump(device);
 
 	/* Turn off napping to make sure we have the clocks full
 	   attention through the following process */
@@ -845,15 +844,7 @@
 	/* Disable the irq */
 	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
 
-	/* If this is not a manual trigger, then set up the
-	   state to try to recover */
-
-	if (!manual) {
-		device->state = KGSL_STATE_DUMP_AND_RECOVER;
-		KGSL_PWR_WARN(device,
-				"state -> DUMP_AND_RECOVER, device %d\n",
-				device->id);
-	}
+	adreno_dump(device);
 
 	/* Restore nap mode */
 	device->pwrctrl.nap_allowed = saved_nap;
@@ -867,7 +858,7 @@
 		kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
 
 		/* try to go into a sleep mode until the next event */
-		device->requested_state = KGSL_STATE_SLEEP;
+		kgsl_pwrctrl_request_state(device, KGSL_STATE_SLEEP);
 		kgsl_pwrctrl_sleep(device);
 	}
 
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index a0982006..7ace67a 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -393,7 +393,6 @@
 	if (rb->flags & KGSL_FLAGS_STARTED) {
 		/* ME_HALT */
 		adreno_regwrite(rb->device, REG_CP_ME_CNTL, 0x10000000);
-
 		rb->flags &= ~KGSL_FLAGS_STARTED;
 	}
 }
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 7a42dcd..3207040 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -302,7 +302,7 @@
 	if (device->pwrctrl.nap_allowed == true &&
 	    device->state == KGSL_STATE_ACTIVE &&
 		device->requested_state == KGSL_STATE_NONE) {
-		device->requested_state = KGSL_STATE_NAP;
+		kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
 		if (kgsl_pwrctrl_sleep(device) != 0)
 			mod_timer(&device->idle_timer,
 				  jiffies +
@@ -395,7 +395,7 @@
 	device->pwrctrl.nap_allowed = false;
 	policy_saved = device->pwrscale.policy;
 	device->pwrscale.policy = NULL;
-	device->requested_state = KGSL_STATE_SUSPEND;
+	kgsl_pwrctrl_request_state(device, KGSL_STATE_SUSPEND);
 	/* Make sure no user process is waiting for a timestamp *
 	 * before supending */
 	if (device->active_cnt != 0) {
@@ -417,22 +417,18 @@
 			INIT_COMPLETION(device->hwaccess_gate);
 			device->ftbl->suspend_context(device);
 			device->ftbl->stop(device);
-			device->state = KGSL_STATE_SUSPEND;
-			KGSL_PWR_WARN(device, "state -> SUSPEND, device %d\n",
-				device->id);
+			kgsl_pwrctrl_set_state(device, KGSL_STATE_SUSPEND);
 			break;
 		case KGSL_STATE_SLUMBER:
 			INIT_COMPLETION(device->hwaccess_gate);
-			device->state = KGSL_STATE_SUSPEND;
-			KGSL_PWR_WARN(device, "state -> SUSPEND, device %d\n",
-				device->id);
+			kgsl_pwrctrl_set_state(device, KGSL_STATE_SUSPEND);
 			break;
 		default:
 			KGSL_PWR_ERR(device, "suspend fail, device %d\n",
 					device->id);
 			goto end;
 	}
-	device->requested_state = KGSL_STATE_NONE;
+	kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
 	device->pwrctrl.nap_allowed = nap_allowed_saved;
 	device->pwrscale.policy = policy_saved;
 	status = 0;
@@ -453,14 +449,11 @@
 	KGSL_PWR_WARN(device, "resume start\n");
 	mutex_lock(&device->mutex);
 	if (device->state == KGSL_STATE_SUSPEND) {
-		device->state = KGSL_STATE_SLUMBER;
+		kgsl_pwrctrl_set_state(device, KGSL_STATE_SLUMBER);
 		status = 0;
-		KGSL_PWR_WARN(device,
-				"state -> SLUMBER, device %d\n",
-				device->id);
 		complete_all(&device->hwaccess_gate);
 	}
-	device->requested_state = KGSL_STATE_NONE;
+	kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
 
 	mutex_unlock(&device->mutex);
 	KGSL_PWR_WARN(device, "resume end\n");
@@ -505,7 +498,7 @@
 					struct kgsl_device, display_off);
 	KGSL_PWR_WARN(device, "early suspend start\n");
 	mutex_lock(&device->mutex);
-	device->requested_state = KGSL_STATE_SLUMBER;
+	kgsl_pwrctrl_request_state(device, KGSL_STATE_SLUMBER);
 	kgsl_pwrctrl_sleep(device);
 	mutex_unlock(&device->mutex);
 	KGSL_PWR_WARN(device, "early suspend end\n");
@@ -535,6 +528,7 @@
 	mutex_lock(&device->mutex);
 	kgsl_pwrctrl_wake(device);
 	device->pwrctrl.restore_slumber = 0;
+	kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_TURBO);
 	mutex_unlock(&device->mutex);
 	kgsl_check_idle(device);
 	KGSL_PWR_WARN(device, "late resume end\n");
@@ -651,8 +645,7 @@
 	device->open_count--;
 	if (device->open_count == 0) {
 		result = device->ftbl->stop(device);
-		device->state = KGSL_STATE_INIT;
-		KGSL_PWR_WARN(device, "state -> INIT, device %d\n", device->id);
+		kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
 	}
 	/* clean up any to-be-freed entries that belong to this
 	 * process and this device
@@ -720,9 +713,7 @@
 			mutex_unlock(&device->mutex);
 			goto err_putprocess;
 		}
-		device->state = KGSL_STATE_ACTIVE;
-		KGSL_PWR_WARN(device,
-				"state -> ACTIVE, device %d\n", minor);
+		kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
 	}
 	device->open_count++;
 	mutex_unlock(&device->mutex);
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 3ef11ce..f82b038 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -175,6 +175,7 @@
 	struct kobject pwrscale_kobj;
 	struct work_struct ts_expired_ws;
 	struct list_head events;
+	s64 on_time;
 };
 
 struct kgsl_context {
@@ -317,4 +318,6 @@
 		irqreturn_t (*dev_isr) (int, void*));
 void kgsl_device_platform_remove(struct kgsl_device *device);
 
+const char *kgsl_pwrstate_to_str(unsigned int state);
+
 #endif  /* __KGSL_DEVICE_H */
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index dbbe4d5..f4abf99 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -18,6 +18,7 @@
 #include "kgsl.h"
 #include "kgsl_pwrscale.h"
 #include "kgsl_device.h"
+#include "kgsl_trace.h"
 
 #define KGSL_PWRFLAGS_POWER_ON 0
 #define KGSL_PWRFLAGS_CLK_ON   1
@@ -62,24 +63,20 @@
 	if (new_level < (pwr->num_pwrlevels - 1) &&
 		new_level >= pwr->thermal_pwrlevel &&
 		new_level != pwr->active_pwrlevel) {
+		struct kgsl_pwrlevel *pwrlevel = &pwr->pwrlevels[new_level];
 		pwr->active_pwrlevel = new_level;
 		if ((test_bit(KGSL_PWRFLAGS_CLK_ON, &pwr->power_flags)) ||
 			(device->state == KGSL_STATE_NAP))
-			clk_set_rate(pwr->grp_clks[0],
-					pwr->pwrlevels[pwr->active_pwrlevel].
-					gpu_freq);
+			clk_set_rate(pwr->grp_clks[0], pwrlevel->gpu_freq);
 		if (test_bit(KGSL_PWRFLAGS_AXI_ON, &pwr->power_flags)) {
 			if (pwr->pcl)
 				msm_bus_scale_client_update_request(pwr->pcl,
-					pwr->pwrlevels[pwr->active_pwrlevel].
-					bus_freq);
+					pwrlevel->bus_freq);
 			else if (pwr->ebi1_clk)
-				clk_set_rate(pwr->ebi1_clk,
-					pwr->pwrlevels[pwr->active_pwrlevel].
-					bus_freq);
+				clk_set_rate(pwr->ebi1_clk, pwrlevel->bus_freq);
 		}
-		KGSL_PWR_WARN(device, "kgsl pwr level changed to %d\n",
-					  pwr->active_pwrlevel);
+		trace_kgsl_pwrlevel(device, pwr->active_pwrlevel,
+				    pwrlevel->gpu_freq);
 	}
 }
 EXPORT_SYMBOL(kgsl_pwrctrl_pwrlevel_change);
@@ -335,8 +332,7 @@
 	if (state == KGSL_PWRFLAGS_OFF) {
 		if (test_and_clear_bit(KGSL_PWRFLAGS_CLK_ON,
 			&pwr->power_flags)) {
-			KGSL_PWR_INFO(device,
-				"clocks off, device %d\n", device->id);
+			trace_kgsl_clk(device, state);
 			for (i = KGSL_MAX_CLKS - 1; i > 0; i--)
 				if (pwr->grp_clks[i])
 					clk_disable(pwr->grp_clks[i]);
@@ -350,9 +346,7 @@
 	} else if (state == KGSL_PWRFLAGS_ON) {
 		if (!test_and_set_bit(KGSL_PWRFLAGS_CLK_ON,
 			&pwr->power_flags)) {
-			KGSL_PWR_INFO(device,
-				"clocks on, device %d\n", device->id);
-
+			trace_kgsl_clk(device, state);
 			if ((pwr->pwrlevels[0].gpu_freq > 0) &&
 				(device->state != KGSL_STATE_NAP))
 				clk_set_rate(pwr->grp_clks[0],
@@ -376,8 +370,7 @@
 	if (state == KGSL_PWRFLAGS_OFF) {
 		if (test_and_clear_bit(KGSL_PWRFLAGS_AXI_ON,
 			&pwr->power_flags)) {
-			KGSL_PWR_INFO(device,
-				"axi off, device %d\n", device->id);
+			trace_kgsl_bus(device, state);
 			if (pwr->ebi1_clk) {
 				clk_set_rate(pwr->ebi1_clk, 0);
 				clk_disable(pwr->ebi1_clk);
@@ -389,8 +382,7 @@
 	} else if (state == KGSL_PWRFLAGS_ON) {
 		if (!test_and_set_bit(KGSL_PWRFLAGS_AXI_ON,
 			&pwr->power_flags)) {
-			KGSL_PWR_INFO(device,
-				"axi on, device %d\n", device->id);
+			trace_kgsl_bus(device, state);
 			if (pwr->ebi1_clk) {
 				clk_enable(pwr->ebi1_clk);
 				clk_set_rate(pwr->ebi1_clk,
@@ -412,16 +404,14 @@
 	if (state == KGSL_PWRFLAGS_OFF) {
 		if (test_and_clear_bit(KGSL_PWRFLAGS_POWER_ON,
 			&pwr->power_flags)) {
-			KGSL_PWR_INFO(device,
-				"power off, device %d\n", device->id);
+			trace_kgsl_rail(device, state);
 			if (pwr->gpu_reg)
 				regulator_disable(pwr->gpu_reg);
 		}
 	} else if (state == KGSL_PWRFLAGS_ON) {
 		if (!test_and_set_bit(KGSL_PWRFLAGS_POWER_ON,
 			&pwr->power_flags)) {
-			KGSL_PWR_INFO(device,
-				"power on, device %d\n", device->id);
+			trace_kgsl_rail(device, state);
 			if (pwr->gpu_reg)
 				regulator_enable(pwr->gpu_reg);
 		}
@@ -435,16 +425,14 @@
 	if (state == KGSL_PWRFLAGS_ON) {
 		if (!test_and_set_bit(KGSL_PWRFLAGS_IRQ_ON,
 			&pwr->power_flags)) {
-			KGSL_PWR_INFO(device,
-				"irq on, device %d\n", device->id);
+			trace_kgsl_irq(device, state);
 			enable_irq(pwr->interrupt_num);
 			device->ftbl->irqctrl(device, 1);
 		}
 	} else if (state == KGSL_PWRFLAGS_OFF) {
 		if (test_and_clear_bit(KGSL_PWRFLAGS_IRQ_ON,
 			&pwr->power_flags)) {
-			KGSL_PWR_INFO(device,
-				"irq off, device %d\n", device->id);
+			trace_kgsl_irq(device, state);
 			device->ftbl->irqctrl(device, 0);
 			if (in_interrupt())
 				disable_irq_nosync(pwr->interrupt_num);
@@ -599,6 +587,9 @@
 {
 	struct kgsl_device *device = container_of(work, struct kgsl_device,
 							idle_check_ws);
+	WARN_ON(device == NULL);
+	if (device == NULL)
+		return;
 
 	mutex_lock(&device->mutex);
 	if (device->state & (KGSL_STATE_ACTIVE | KGSL_STATE_NAP)) {
@@ -620,7 +611,7 @@
 		}
 	} else if (device->state & (KGSL_STATE_HUNG |
 					KGSL_STATE_DUMP_AND_RECOVER)) {
-		device->requested_state = KGSL_STATE_NONE;
+		kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
 	}
 
 	mutex_unlock(&device->mutex);
@@ -632,7 +623,7 @@
 
 	KGSL_PWR_INFO(device, "idle timer expired device %d\n", device->id);
 	if (device->requested_state != KGSL_STATE_SUSPEND) {
-		device->requested_state = KGSL_STATE_SLEEP;
+		kgsl_pwrctrl_request_state(device, KGSL_STATE_SLEEP);
 		/* Have work run in a non-interrupt context. */
 		queue_work(device->work_queue, &device->idle_check_ws);
 	}
@@ -663,155 +654,182 @@
 }
 
 static int
-_slumber(struct kgsl_device *device)
+_nap(struct kgsl_device *device)
 {
-	int status = -EINVAL;
-	if (!device)
-		return -EINVAL;
-	KGSL_PWR_WARN(device, "Slumber start\n");
-
-	device->requested_state = KGSL_STATE_SLUMBER;
-	del_timer(&device->idle_timer);
 	switch (device->state) {
 	case KGSL_STATE_ACTIVE:
-		/* Wait for the device to become idle */
-		device->ftbl->idle(device, KGSL_TIMEOUT_DEFAULT);
+		if (!device->ftbl->isidle(device)) {
+			kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
+			return -EBUSY;
+		}
+		kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
+		kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF);
+		kgsl_pwrctrl_set_state(device, KGSL_STATE_NAP);
+		if (device->idle_wakelock.name)
+			wake_unlock(&device->idle_wakelock);
 	case KGSL_STATE_NAP:
 	case KGSL_STATE_SLEEP:
-		device->ftbl->suspend_context(device);
-		device->ftbl->stop(device);
-		device->state = KGSL_STATE_SLUMBER;
-		device->pwrctrl.restore_slumber = 1;
-		KGSL_PWR_WARN(device, "state -> SLUMBER, device %d\n",
-				device->id);
+	case KGSL_STATE_SLUMBER:
 		break;
 	default:
+		kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
 		break;
 	}
-	status = 0;
-	/* Don't set requested state to NONE
-	It's done in kgsl_pwrctrl_sleep*/
-	KGSL_PWR_WARN(device, "Done going to slumber\n");
-	return status;
+	return 0;
+}
+
+static void
+_sleep_accounting(struct kgsl_device *device)
+{
+	kgsl_pwrctrl_busy_time(device, false);
+	device->pwrctrl.busy.start.tv_sec = 0;
+	device->pwrctrl.time = 0;
+	kgsl_pwrscale_sleep(device);
+}
+
+static int
+_sleep(struct kgsl_device *device)
+{
+	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+	switch (device->state) {
+	case KGSL_STATE_ACTIVE:
+		if (!device->ftbl->isidle(device)) {
+			kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
+			return -EBUSY;
+		}
+		/* fall through */
+	case KGSL_STATE_NAP:
+		kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
+		kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF);
+		if (pwr->pwrlevels[0].gpu_freq > 0)
+			clk_set_rate(pwr->grp_clks[0],
+				pwr->pwrlevels[pwr->num_pwrlevels - 1].
+				gpu_freq);
+		_sleep_accounting(device);
+		kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF);
+		kgsl_pwrctrl_set_state(device, KGSL_STATE_SLEEP);
+		if (device->idle_wakelock.name)
+			wake_unlock(&device->idle_wakelock);
+		break;
+	case KGSL_STATE_SLEEP:
+	case KGSL_STATE_SLUMBER:
+		break;
+	default:
+		KGSL_PWR_WARN(device, "unhandled state %s\n",
+				kgsl_pwrstate_to_str(device->state));
+		break;
+	}
+	return 0;
+}
+
+static int
+_slumber(struct kgsl_device *device)
+{
+	switch (device->state) {
+	case KGSL_STATE_ACTIVE:
+		if (!device->ftbl->isidle(device)) {
+			kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
+			device->pwrctrl.restore_slumber = true;
+			return -EBUSY;
+		}
+		/* fall through */
+	case KGSL_STATE_NAP:
+	case KGSL_STATE_SLEEP:
+		del_timer_sync(&device->idle_timer);
+		kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_NOMINAL);
+		device->ftbl->suspend_context(device);
+		device->ftbl->stop(device);
+		device->pwrctrl.restore_slumber = true;
+		_sleep_accounting(device);
+		kgsl_pwrctrl_set_state(device, KGSL_STATE_SLUMBER);
+		if (device->idle_wakelock.name)
+			wake_unlock(&device->idle_wakelock);
+		break;
+	case KGSL_STATE_SLUMBER:
+		break;
+	default:
+		KGSL_PWR_WARN(device, "unhandled state %s\n",
+				kgsl_pwrstate_to_str(device->state));
+		break;
+	}
+	return 0;
 }
 
 /******************************************************************/
 /* Caller must hold the device mutex. */
 int kgsl_pwrctrl_sleep(struct kgsl_device *device)
 {
-	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+	int status = 0;
 	KGSL_PWR_INFO(device, "sleep device %d\n", device->id);
 
 	/* Work through the legal state transitions */
-	if ((device->requested_state == KGSL_STATE_NAP)) {
+	switch (device->requested_state) {
+	case KGSL_STATE_NAP:
 		if (device->pwrctrl.restore_slumber) {
-			device->requested_state = KGSL_STATE_NONE;
-			return 0;
-		} else if (device->ftbl->isidle(device))
-			goto nap;
-	} else if (device->requested_state == KGSL_STATE_SLEEP) {
-		if (device->state == KGSL_STATE_NAP ||
-			device->ftbl->isidle(device)) {
-			if (!device->pwrctrl.restore_slumber)
-				goto sleep;
-			else
-				goto slumber;
-			}
-	} else if (device->requested_state == KGSL_STATE_SLUMBER) {
-		if (device->state == KGSL_STATE_INIT)
-			return 0;
-		if (device->ftbl->isidle(device))
-			goto slumber;
+			kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
+			break;
+		}
+		status = _nap(device);
+		break;
+	case KGSL_STATE_SLEEP:
+		if (device->pwrctrl.restore_slumber)
+			status = _slumber(device);
 		else
-			device->pwrctrl.restore_slumber = true;
+			status = _sleep(device);
+		break;
+	case KGSL_STATE_SLUMBER:
+		status = _slumber(device);
+		break;
+	default:
+		KGSL_PWR_INFO(device, "bad state request 0x%x\n",
+				device->requested_state);
+		kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
+		status = -EINVAL;
+		break;
 	}
-
-	device->requested_state = KGSL_STATE_NONE;
-	return -EBUSY;
-
-
-slumber:
-	_slumber(device);
-
-sleep:
-	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
-	kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF);
-	if (pwr->pwrlevels[0].gpu_freq > 0)
-		clk_set_rate(pwr->grp_clks[0],
-				pwr->pwrlevels[pwr->num_pwrlevels - 1].
-				gpu_freq);
-	kgsl_pwrctrl_busy_time(device, false);
-	pwr->busy.start.tv_sec = 0;
-	device->pwrctrl.time = 0;
-
-	kgsl_pwrscale_sleep(device);
-	goto clk_off;
-
-nap:
-	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
-clk_off:
-	kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF);
-
-	device->state = device->requested_state;
-	device->requested_state = KGSL_STATE_NONE;
-	if (device->idle_wakelock.name)
-		wake_unlock(&device->idle_wakelock);
-	KGSL_PWR_WARN(device, "state -> NAP/SLEEP(%d), device %d\n",
-				  device->state, device->id);
-
-	return 0;
-}
-EXPORT_SYMBOL(kgsl_pwrctrl_sleep);
-
-static int
-_wake_from_slumber(struct kgsl_device *device)
-{
-	int status = -EINVAL;
-	if (!device)
-		return -EINVAL;
-
-	KGSL_PWR_WARN(device, "wake from slumber start\n");
-
-	device->requested_state = KGSL_STATE_ACTIVE;
-	kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_NOMINAL);
-	status = device->ftbl->start(device, 0);
-	device->requested_state = KGSL_STATE_NONE;
-
-	KGSL_PWR_WARN(device, "Done waking from slumber\n");
 	return status;
 }
+EXPORT_SYMBOL(kgsl_pwrctrl_sleep);
 
 /******************************************************************/
 /* Caller must hold the device mutex. */
 void kgsl_pwrctrl_wake(struct kgsl_device *device)
 {
-	if (device->state & (KGSL_STATE_SUSPEND | KGSL_STATE_INIT))
-		return;
-
-	if (device->state == KGSL_STATE_SLUMBER)
-		_wake_from_slumber(device);
-
-	if (device->state != KGSL_STATE_NAP) {
+	int status;
+	kgsl_pwrctrl_request_state(device, KGSL_STATE_ACTIVE);
+	switch (device->state) {
+	case KGSL_STATE_SLUMBER:
+		status = device->ftbl->start(device, 0);
+		if (status) {
+			kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
+			KGSL_DRV_ERR(device, "start failed %d\n", status);
+			break;
+		}
+		/* fall through */
+	case KGSL_STATE_SLEEP:
 		kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON);
 		kgsl_pwrscale_wake(device);
-	}
-
-	/* Turn on the core clocks */
-	kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON);
-
-	/* Enable state before turning on irq */
-	device->state = KGSL_STATE_ACTIVE;
-	KGSL_PWR_WARN(device, "state -> ACTIVE, device %d\n", device->id);
-	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
-
-	/* Re-enable HW access */
-	mod_timer(&device->idle_timer,
+		/* fall through */
+	case KGSL_STATE_NAP:
+		/* Turn on the core clocks */
+		kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON);
+		/* Enable state before turning on irq */
+		kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
+		kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
+		/* Re-enable HW access */
+		mod_timer(&device->idle_timer,
 				jiffies + device->pwrctrl.interval_timeout);
 
-	if (device->idle_wakelock.name)
-		wake_lock(&device->idle_wakelock);
-
-	KGSL_PWR_INFO(device, "wake return for device %d\n", device->id);
+		if (device->idle_wakelock.name)
+			wake_lock(&device->idle_wakelock);
+	case KGSL_STATE_ACTIVE:
+		break;
+	default:
+		KGSL_PWR_WARN(device, "unhandled state %s\n",
+				kgsl_pwrstate_to_str(device->state));
+		kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
+		break;
+	}
 }
 EXPORT_SYMBOL(kgsl_pwrctrl_wake);
 
@@ -832,3 +850,48 @@
 	kgsl_pwrctrl_pwrrail(device, KGSL_PWRFLAGS_OFF);
 }
 EXPORT_SYMBOL(kgsl_pwrctrl_disable);
+
+void kgsl_pwrctrl_set_state(struct kgsl_device *device, unsigned int state)
+{
+	trace_kgsl_pwr_set_state(device, state);
+	device->state = state;
+	device->requested_state = KGSL_STATE_NONE;
+}
+EXPORT_SYMBOL(kgsl_pwrctrl_set_state);
+
+void kgsl_pwrctrl_request_state(struct kgsl_device *device, unsigned int state)
+{
+	if (state != KGSL_STATE_NONE && state != device->requested_state)
+		trace_kgsl_pwr_request_state(device, state);
+	device->requested_state = state;
+}
+EXPORT_SYMBOL(kgsl_pwrctrl_request_state);
+
+const char *kgsl_pwrstate_to_str(unsigned int state)
+{
+	switch (state) {
+	case KGSL_STATE_NONE:
+		return "NONE";
+	case KGSL_STATE_INIT:
+		return "INIT";
+	case KGSL_STATE_ACTIVE:
+		return "ACTIVE";
+	case KGSL_STATE_NAP:
+		return "NAP";
+	case KGSL_STATE_SLEEP:
+		return "SLEEP";
+	case KGSL_STATE_SUSPEND:
+		return "SUSPEND";
+	case KGSL_STATE_HUNG:
+		return "HUNG";
+	case KGSL_STATE_DUMP_AND_RECOVER:
+		return "DNR";
+	case KGSL_STATE_SLUMBER:
+		return "SLUMBER";
+	default:
+		break;
+	}
+	return "UNKNOWN";
+}
+EXPORT_SYMBOL(kgsl_pwrstate_to_str);
+
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 8b33fcd..8ec41be 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -77,4 +77,6 @@
 	return (clk != NULL) ? clk_get_rate(clk) : 0;
 }
 
+void kgsl_pwrctrl_set_state(struct kgsl_device *device, unsigned int state);
+void kgsl_pwrctrl_request_state(struct kgsl_device *device, unsigned int state);
 #endif /* __KGSL_PWRCTRL_H */
diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
index f3e84e4..931ef48 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
@@ -14,6 +14,7 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/io.h>
+#include <linux/spinlock.h>
 #include <mach/socinfo.h>
 #include <mach/scm.h>
 
@@ -29,6 +30,7 @@
 	unsigned int no_switch_cnt;
 	unsigned int skip_cnt;
 };
+spinlock_t tz_lock;
 
 #define SWITCH_OFF		200
 #define SWITCH_OFF_RESET_TH	40
@@ -38,13 +40,17 @@
 
 #ifdef CONFIG_MSM_SCM
 /* Trap into the TrustZone, and call funcs there. */
-static int __secure_tz_entry(u32 cmd, u32 val)
+static int __secure_tz_entry(u32 cmd, u32 val, u32 id)
 {
+	int ret;
+	spin_lock(&tz_lock);
 	__iowmb();
-	return scm_call_atomic1(SCM_SVC_IO, cmd, val);
+	ret = scm_call_atomic2(SCM_SVC_IO, cmd, val, id);
+	spin_unlock(&tz_lock);
+	return ret;
 }
 #else
-static int __secure_tz_entry(u32 cmd, u32 val)
+static int __secure_tz_entry(u32 cmd, u32 val, u32 id)
 {
 	return 0;
 }
@@ -107,7 +113,8 @@
 {
 	struct tz_priv *priv = pwrscale->priv;
 	if (device->state != KGSL_STATE_NAP &&
-		priv->governor == TZ_GOVERNOR_ONDEMAND)
+		priv->governor == TZ_GOVERNOR_ONDEMAND &&
+		device->pwrctrl.restore_slumber == 0)
 		kgsl_pwrctrl_pwrlevel_change(device,
 					     device->pwrctrl.thermal_pwrlevel);
 }
@@ -117,7 +124,7 @@
 	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
 	struct tz_priv *priv = pwrscale->priv;
 	struct kgsl_power_stats stats;
-	int val;
+	int val, idle;
 
 	/* In "performance" mode the clock speed always stays
 	   the same */
@@ -145,19 +152,26 @@
 		priv->no_switch_cnt = 0;
 	}
 
-	val = __secure_tz_entry(TZ_UPDATE_ID,
-				stats.total_time - stats.busy_time);
+	idle = stats.total_time - stats.busy_time;
+	idle = (idle > 0) ? idle : 0;
+	val = __secure_tz_entry(TZ_UPDATE_ID, idle, device->id);
 	if (val)
 		kgsl_pwrctrl_pwrlevel_change(device,
 					     pwr->active_pwrlevel + val);
 }
 
+static void tz_busy(struct kgsl_device *device,
+	struct kgsl_pwrscale *pwrscale)
+{
+	device->on_time = ktime_to_us(ktime_get());
+}
+
 static void tz_sleep(struct kgsl_device *device,
 	struct kgsl_pwrscale *pwrscale)
 {
 	struct tz_priv *priv = pwrscale->priv;
 
-	__secure_tz_entry(TZ_RESET_ID, 0);
+	__secure_tz_entry(TZ_RESET_ID, 0, device->id);
 	priv->no_switch_cnt = 0;
 }
 
@@ -174,6 +188,7 @@
 		return -ENOMEM;
 
 	priv->governor = TZ_GOVERNOR_ONDEMAND;
+	spin_lock_init(&tz_lock);
 	kgsl_pwrscale_policy_add_files(device, pwrscale, &tz_attr_group);
 
 	return 0;
@@ -189,6 +204,7 @@
 struct kgsl_pwrscale_policy kgsl_pwrscale_policy_tz = {
 	.name = "trustzone",
 	.init = tz_init,
+	.busy = tz_busy,
 	.idle = tz_idle,
 	.sleep = tz_sleep,
 	.wake = tz_wake,
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 7c14ac1..86a9adc 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -155,6 +155,108 @@
 		__entry->result
 	)
 );
+
+DECLARE_EVENT_CLASS(kgsl_pwr_template,
+	TP_PROTO(struct kgsl_device *device, int on),
+
+	TP_ARGS(device, on),
+
+	TP_STRUCT__entry(
+		__string(device_name, device->name)
+		__field(int, on)
+	),
+
+	TP_fast_assign(
+		__assign_str(device_name, device->name);
+		__entry->on = on;
+	),
+
+	TP_printk(
+		"d_name=%s %s",
+		__get_str(device_name),
+		__entry->on ? "on" : "off"
+	)
+);
+
+DEFINE_EVENT(kgsl_pwr_template, kgsl_clk,
+	TP_PROTO(struct kgsl_device *device, int on),
+	TP_ARGS(device, on)
+);
+
+DEFINE_EVENT(kgsl_pwr_template, kgsl_irq,
+	TP_PROTO(struct kgsl_device *device, int on),
+	TP_ARGS(device, on)
+);
+
+DEFINE_EVENT(kgsl_pwr_template, kgsl_bus,
+	TP_PROTO(struct kgsl_device *device, int on),
+	TP_ARGS(device, on)
+);
+
+DEFINE_EVENT(kgsl_pwr_template, kgsl_rail,
+	TP_PROTO(struct kgsl_device *device, int on),
+	TP_ARGS(device, on)
+);
+
+TRACE_EVENT(kgsl_pwrlevel,
+
+	TP_PROTO(struct kgsl_device *device, unsigned int pwrlevel,
+		 unsigned int freq),
+
+	TP_ARGS(device, pwrlevel, freq),
+
+	TP_STRUCT__entry(
+		__string(device_name, device->name)
+		__field(unsigned int, pwrlevel)
+		__field(unsigned int, freq)
+	),
+
+	TP_fast_assign(
+		__assign_str(device_name, device->name);
+		__entry->pwrlevel = pwrlevel;
+		__entry->freq = freq;
+	),
+
+	TP_printk(
+		"d_name=%s pwrlevel=%d freq=%d",
+		__get_str(device_name),
+		__entry->pwrlevel,
+		__entry->freq
+	)
+);
+
+DECLARE_EVENT_CLASS(kgsl_pwrstate_template,
+	TP_PROTO(struct kgsl_device *device, unsigned int state),
+
+	TP_ARGS(device, state),
+
+	TP_STRUCT__entry(
+		__string(device_name, device->name)
+		__field(unsigned int, state)
+	),
+
+	TP_fast_assign(
+		__assign_str(device_name, device->name);
+		__entry->state = state;
+	),
+
+	TP_printk(
+		"d_name=%s %s",
+		__get_str(device_name),
+		kgsl_pwrstate_to_str(__entry->state)
+	)
+);
+
+DEFINE_EVENT(kgsl_pwrstate_template, kgsl_pwr_set_state,
+	TP_PROTO(struct kgsl_device *device, unsigned int state),
+	TP_ARGS(device, state)
+);
+
+DEFINE_EVENT(kgsl_pwrstate_template, kgsl_pwr_request_state,
+	TP_PROTO(struct kgsl_device *device, unsigned int state),
+	TP_ARGS(device, state)
+);
+
 #endif /* _KGSL_TRACE_H */
 
 /* This part must be outside protection */
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index cf74e64..de7d1be 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -248,7 +248,7 @@
 
 	if ((device->pwrctrl.nap_allowed == true) &&
 		(device->requested_state == KGSL_STATE_NONE)) {
-		device->requested_state = KGSL_STATE_NAP;
+		kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
 		queue_work(device->work_queue, &device->idle_check_ws);
 	}
 	mod_timer(&device->idle_timer,
@@ -460,6 +460,7 @@
 	z180_dev->ringbuffer.prevctx = context->id;
 
 	addcmd(&z180_dev->ringbuffer, index, cmd + ofs, cnt);
+	kgsl_pwrscale_busy(device);
 
 	/* Make sure the next ringbuffer entry has a marker */
 	addmarker(&z180_dev->ringbuffer, nextindex);
@@ -523,6 +524,7 @@
 		goto error_close_ringbuffer;
 
 	kgsl_pwrscale_init(device);
+	kgsl_pwrscale_attach_policy(device, Z180_DEFAULT_PWRSCALE_POLICY);
 
 	return status;
 
@@ -551,9 +553,7 @@
 {
 	int status = 0;
 
-	device->state = KGSL_STATE_INIT;
-	device->requested_state = KGSL_STATE_NONE;
-	KGSL_PWR_WARN(device, "state -> INIT, device %d\n", device->id);
+	kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
 
 	kgsl_pwrctrl_enable(device);
 
@@ -834,8 +834,7 @@
 		status = 0;
 	else if (timeout == 0) {
 		status = -ETIMEDOUT;
-		device->state = KGSL_STATE_HUNG;
-		KGSL_PWR_WARN(device, "state -> HUNG, device %d\n", device->id);
+		kgsl_pwrctrl_set_state(device, KGSL_STATE_HUNG);
 	} else
 		status = timeout;
 
@@ -861,17 +860,17 @@
 			    struct kgsl_power_stats *stats)
 {
 	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+	s64 tmp = ktime_to_us(ktime_get());
 
 	if (pwr->time == 0) {
-		pwr->time = ktime_to_us(ktime_get());
+		pwr->time = tmp;
 		stats->total_time = 0;
 		stats->busy_time = 0;
 	} else {
-		s64 tmp;
-		tmp = ktime_to_us(ktime_get());
 		stats->total_time = tmp - pwr->time;
-		stats->busy_time = tmp - pwr->time;
 		pwr->time = tmp;
+		stats->busy_time = tmp - device->on_time;
+		device->on_time = tmp;
 	}
 }
 
diff --git a/drivers/gpu/msm/z180.h b/drivers/gpu/msm/z180.h
index 28b1cc6..e5c5ef3 100644
--- a/drivers/gpu/msm/z180.h
+++ b/drivers/gpu/msm/z180.h
@@ -19,6 +19,8 @@
 #define DEVICE_2D0_NAME "kgsl-2d0"
 #define DEVICE_2D1_NAME "kgsl-2d1"
 
+#define Z180_DEFAULT_PWRSCALE_POLICY  NULL
+
 struct z180_ringbuffer {
 	unsigned int prevctx;
 	struct kgsl_memdesc      cmdbufdesc;
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 3dbbf15..2d69256 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -29,6 +29,7 @@
 #include <linux/timer.h>
 #include <linux/slab.h>
 #include <mach/board.h>
+#include <mach/gpiomux.h>
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
 #include <linux/gpio.h>
@@ -110,6 +111,7 @@
 enum {
 	I2C_STATUS_WR_BUFFER_FULL  = 1U << 0,
 	I2C_STATUS_BUS_ACTIVE      = 1U << 8,
+	I2C_STATUS_BUS_MASTER	   = 1U << 9,
 	I2C_STATUS_ERROR_MASK      = 0x38000FC,
 	QUP_I2C_NACK_FLAG          = 1U << 3,
 	QUP_IN_NOT_EMPTY           = 1U << 5,
@@ -126,6 +128,12 @@
 
 static char const * const i2c_rsrcs[] = {"i2c_clk", "i2c_sda"};
 
+static struct gpiomux_setting recovery_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
 struct qup_i2c_dev {
 	struct device                *dev;
 	void __iomem                 *base;		/* virtual */
@@ -639,6 +647,83 @@
 	return ret;
 }
 
+
+static void qup_i2c_recover_bus_busy(struct qup_i2c_dev *dev)
+{
+	int i;
+	int gpio_clk;
+	int gpio_dat;
+	bool gpio_clk_status = false;
+	uint32_t status = readl_relaxed(dev->base + QUP_I2C_STATUS);
+	struct gpiomux_setting old_gpio_setting;
+
+	if (dev->pdata->msm_i2c_config_gpio)
+		return;
+
+	if (!(status & (I2C_STATUS_BUS_ACTIVE)) ||
+		(status & (I2C_STATUS_BUS_MASTER)))
+		return;
+
+	gpio_clk = dev->i2c_gpios[0];
+	gpio_dat = dev->i2c_gpios[1];
+
+	if ((gpio_clk == -1) && (gpio_dat == -1)) {
+		dev_err(dev->dev, "Recovery failed due to undefined GPIO's\n");
+		return;
+	}
+
+	disable_irq(dev->err_irq);
+	for (i = 0; i < ARRAY_SIZE(i2c_rsrcs); ++i) {
+		if (msm_gpiomux_write(dev->i2c_gpios[i], GPIOMUX_ACTIVE,
+				&recovery_config, &old_gpio_setting)) {
+			dev_err(dev->dev, "GPIO pins have no active setting\n");
+			goto recovery_end;
+		}
+	}
+
+	dev_warn(dev->dev, "i2c_scl: %d, i2c_sda: %d\n",
+		 gpio_get_value(gpio_clk), gpio_get_value(gpio_dat));
+
+	for (i = 0; i < 9; i++) {
+		if (gpio_get_value(gpio_dat) && gpio_clk_status)
+			break;
+		gpio_direction_output(gpio_clk, 0);
+		udelay(5);
+		gpio_direction_output(gpio_dat, 0);
+		udelay(5);
+		gpio_direction_input(gpio_clk);
+		udelay(5);
+		if (!gpio_get_value(gpio_clk))
+			udelay(20);
+		if (!gpio_get_value(gpio_clk))
+			usleep_range(10000, 10000);
+		gpio_clk_status = gpio_get_value(gpio_clk);
+		gpio_direction_input(gpio_dat);
+		udelay(5);
+	}
+
+	/* Configure ALT funciton to QUP I2C*/
+	for (i = 0; i < ARRAY_SIZE(i2c_rsrcs); ++i) {
+		msm_gpiomux_write(dev->i2c_gpios[i], GPIOMUX_ACTIVE,
+				&old_gpio_setting, NULL);
+	}
+
+	udelay(10);
+
+	status = readl_relaxed(dev->base + QUP_I2C_STATUS);
+	if (!(status & I2C_STATUS_BUS_ACTIVE)) {
+		dev_info(dev->dev, "Bus busy cleared after %d clock cycles, "
+			 "status %x\n",
+			 i, status);
+		goto recovery_end;
+	}
+
+	dev_warn(dev->dev, "Bus still busy, status %x\n", status);
+
+recovery_end:
+	enable_irq(dev->err_irq);
+}
+
 static int
 qup_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 {
@@ -837,7 +922,8 @@
 				idx, rem, num, dev->mode);
 
 			qup_print_status(dev);
-			timeout = wait_for_completion_timeout(&complete, HZ);
+			timeout = wait_for_completion_timeout(&complete,
+					msecs_to_jiffies(dev->out_fifo_sz));
 			if (!timeout) {
 				uint32_t istatus = readl_relaxed(dev->base +
 							QUP_I2C_STATUS);
@@ -846,7 +932,24 @@
 				uint32_t op_flgs = readl_relaxed(dev->base +
 							QUP_OPERATIONAL);
 
-				dev_err(dev->dev, "Transaction timed out\n");
+				/*
+				 * Dont wait for 1 sec if i2c sees the bus
+				 * active and controller is not master.
+				 * A slave has pulled line low. Try to recover
+				 */
+				if (!(istatus & I2C_STATUS_BUS_ACTIVE) ||
+					(istatus & I2C_STATUS_BUS_MASTER)) {
+					timeout =
+					wait_for_completion_timeout(&complete,
+									HZ);
+					if (timeout)
+						goto timeout_err;
+				}
+				qup_i2c_recover_bus_busy(dev);
+				dev_err(dev->dev,
+					"Transaction timed out, SL-AD = 0x%x\n",
+					dev->msg->addr);
+
 				dev_err(dev->dev, "I2C Status: %x\n", istatus);
 				dev_err(dev->dev, "QUP Status: %x\n", qstatus);
 				dev_err(dev->dev, "OP Flags: %x\n", op_flgs);
@@ -858,17 +961,27 @@
 				ret = -ETIMEDOUT;
 				goto out_err;
 			}
+timeout_err:
 			if (dev->err) {
 				if (dev->err > 0 &&
-					dev->err & QUP_I2C_NACK_FLAG)
+					dev->err & QUP_I2C_NACK_FLAG) {
 					dev_err(dev->dev,
 					"I2C slave addr:0x%x not connected\n",
 					dev->msg->addr);
-				else if (dev->err < 0) {
+					dev->err = ENOTCONN;
+				} else if (dev->err < 0) {
 					dev_err(dev->dev,
 					"QUP data xfer error %d\n", dev->err);
 					ret = dev->err;
 					goto out_err;
+				} else if (dev->err > 0) {
+					/*
+					 * ISR returns +ve error if error code
+					 * is I2C related, e.g. unexpected start
+					 * So you may call recover-bus-busy when
+					 * this error happens
+					 */
+					qup_i2c_recover_bus_busy(dev);
 				}
 				ret = -dev->err;
 				goto out_err;
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 6db0da1..ec392c3 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -594,28 +594,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called w90p910_keypad.
 
-config KEYBOARD_PMIC8058
-	tristate "Qualcomm PMIC8058 keypad"
-	depends on PMIC8058
-	default y
-	help
-	  Say Y here if you want to enable the driver for the PMIC8058
-	  keypad provided as a reference design from Qualcomm. This is intended
-	  to support upto 18x8 matrix based keypad design.
-
-	  To compile this driver as a module, choose M here: the module will
-	  be called pmic8058-keypad.
 endif
-config KEYBOARD_PMIC8058
-        tristate "Qualcomm PMIC8058 keypad"
-        depends on PMIC8058
-        default y
-        help
-          Say Y here if you want to enable the driver for the PMIC8058
-          keypad provided as a reference design from Qualcomm. This is intended
-          to support upto 18x8 matrix based keypad design.
-
-          To compile this driver as a module, choose M here: the module will
-          be called pmic8058-keypad.
 
 
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index cf4c058..b22df06 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -34,7 +34,6 @@
 obj-$(CONFIG_KEYBOARD_OMAP)		+= omap-keypad.o
 obj-$(CONFIG_KEYBOARD_OMAP4)		+= omap4-keypad.o
 obj-$(CONFIG_KEYBOARD_OPENCORES)	+= opencores-kbd.o
-obj-$(CONFIG_KEYBOARD_PM8058)		+= pm8058-keypad.o
 obj-$(CONFIG_KEYBOARD_PMIC8XXX)		+= pmic8xxx-keypad.o
 obj-$(CONFIG_KEYBOARD_PXA27x)		+= pxa27x_keypad.o
 obj-$(CONFIG_KEYBOARD_PXA930_ROTARY)	+= pxa930_rotary.o
diff --git a/drivers/input/keyboard/pmic8058-keypad.c b/drivers/input/keyboard/pmic8058-keypad.c
deleted file mode 100644
index 9c7588e..0000000
--- a/drivers/input/keyboard/pmic8058-keypad.c
+++ /dev/null
@@ -1,948 +0,0 @@
-/* Copyright (c) 2009-2010, Code Aurora Forum. 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 version 2 and
- * only 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.
- *
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/input.h>
-#include <linux/bitops.h>
-#include <linux/mfd/pmic8058.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/pm.h>
-#include <linux/pm_runtime.h>
-
-#include <linux/input/pmic8058-keypad.h>
-
-#define PM8058_MAX_ROWS		18
-#define PM8058_MAX_COLS		8
-#define PM8058_ROW_SHIFT	3
-#define PM8058_MATRIX_MAX_SIZE	(PM8058_MAX_ROWS * PM8058_MAX_COLS)
-
-#define PM8058_MIN_ROWS		5
-#define PM8058_MIN_COLS		5
-
-#define MAX_SCAN_DELAY		128
-#define MIN_SCAN_DELAY		1
-
-/* in nanoseconds */
-#define MAX_ROW_HOLD_DELAY	122000
-#define MIN_ROW_HOLD_DELAY	30500
-
-#define MAX_DEBOUNCE_B0_TIME	20
-#define MIN_DEBOUNCE_B0_TIME	5
-
-#define MAX_DEBOUNCE_A0_TIME	8
-#define MIN_DEBOUNCE_A0_TIME	1
-
-#define KEYP_CTRL			0x148
-
-#define KEYP_CTRL_EVNTS			BIT(0)
-#define KEYP_CTRL_EVNTS_MASK		0x3
-
-#define KEYP_CTRL_SCAN_COLS_SHIFT	5
-#define KEYP_CTRL_SCAN_COLS_MIN		5
-#define KEYP_CTRL_SCAN_COLS_BITS	0x3
-
-#define KEYP_CTRL_SCAN_ROWS_SHIFT	2
-#define KEYP_CTRL_SCAN_ROWS_MIN		5
-#define KEYP_CTRL_SCAN_ROWS_BITS	0x7
-
-#define KEYP_CTRL_KEYP_EN		BIT(7)
-
-#define KEYP_SCAN			0x149
-
-#define KEYP_SCAN_READ_STATE		BIT(0)
-#define KEYP_SCAN_DBOUNCE_SHIFT		1
-#define KEYP_SCAN_PAUSE_SHIFT		3
-#define KEYP_SCAN_ROW_HOLD_SHIFT	6
-
-#define KEYP_TEST			0x14A
-
-#define KEYP_TEST_CLEAR_RECENT_SCAN	BIT(6)
-#define KEYP_TEST_CLEAR_OLD_SCAN	BIT(5)
-#define KEYP_TEST_READ_RESET		BIT(4)
-#define KEYP_TEST_DTEST_EN		BIT(3)
-#define KEYP_TEST_ABORT_READ		BIT(0)
-
-#define KEYP_TEST_DBG_SELECT_SHIFT	1
-
-/* bits of these register represent
- * '0' for key press
- * '1' for key release
- */
-#define KEYP_RECENT_DATA		0x14B
-#define KEYP_OLD_DATA			0x14C
-
-#define KEYP_CLOCK_FREQ			32768
-
-/* Internal flags */
-#define KEYF_FIX_LAST_ROW		0x01
-
-
-/* ---------------------------------------------------------------------*/
-struct pmic8058_kp {
-	const struct pmic8058_keypad_data *pdata;
-	struct input_dev *input;
-	int key_sense_irq;
-	int key_stuck_irq;
-
-	unsigned short *keycodes;
-
-	struct device *dev;
-	u16 keystate[PM8058_MAX_ROWS];
-	u16 stuckstate[PM8058_MAX_ROWS];
-
-	u32	flags;
-	struct pm8058_chip	*pm_chip;
-
-	/* protect read/write */
-	struct mutex		mutex;
-	bool			user_disabled;
-	u32			disable_depth;
-
-	u8			ctrl_reg;
-};
-
-static int pmic8058_kp_write_u8(struct pmic8058_kp *kp,
-				 u8 data, u16 reg)
-{
-	int rc;
-
-	rc = pm8058_write(kp->pm_chip, reg, &data, 1);
-	if (rc < 0)
-		dev_warn(kp->dev, "Error writing pmic8058: %X - ret %X\n",
-				reg, rc);
-	return rc;
-}
-
-static int pmic8058_kp_read(struct pmic8058_kp *kp,
-				 u8 *data, u16 reg, unsigned num_bytes)
-{
-	int rc;
-
-	rc = pm8058_read(kp->pm_chip, reg, data, num_bytes);
-	if (rc < 0)
-		dev_warn(kp->dev, "Error reading pmic8058: %X - ret %X\n",
-				reg, rc);
-
-	return rc;
-}
-
-static int pmic8058_kp_read_u8(struct pmic8058_kp *kp,
-				 u8 *data, u16 reg)
-{
-	int rc;
-
-	rc = pmic8058_kp_read(kp, data, reg, 1);
-	if (rc < 0)
-		dev_warn(kp->dev, "Error reading pmic8058: %X - ret %X\n",
-				reg, rc);
-	return rc;
-}
-
-static u8 pmic8058_col_state(struct pmic8058_kp *kp, u8 col)
-{
-	/* all keys pressed on that particular row? */
-	if (col == 0x00)
-		return 1 << kp->pdata->num_cols;
-	else
-		return col & ((1 << kp->pdata->num_cols) - 1);
-}
-/* REVISIT: just for debugging, will be removed in final working version */
-static void __dump_kp_regs(struct pmic8058_kp *kp, char *msg)
-{
-	u8 temp;
-
-	dev_dbg(kp->dev, "%s\n", msg);
-
-	pmic8058_kp_read_u8(kp, &temp, KEYP_CTRL);
-	dev_dbg(kp->dev, "KEYP_CTRL - %X\n", temp);
-	pmic8058_kp_read_u8(kp, &temp, KEYP_SCAN);
-	dev_dbg(kp->dev, "KEYP_SCAN - %X\n", temp);
-	pmic8058_kp_read_u8(kp, &temp, KEYP_TEST);
-	dev_dbg(kp->dev, "KEYP_TEST - %X\n", temp);
-}
-
-/* H/W constraint:
- * One should read recent/old data registers equal to the
- * number of columns programmed in the keyp_control register,
- * otherwise h/w state machine may get stuck. In order to avoid this
- * situation one should check readstate bit in keypad scan
- * register to be '0' at the end of data read, to make sure
- * the keypad state machine is not in READ state.
- */
-static int pmic8058_chk_read_state(struct pmic8058_kp *kp, u16 data_reg)
-{
-	u8 temp, scan_val;
-	int retries = 10, rc;
-
-	do {
-		rc = pmic8058_kp_read_u8(kp, &scan_val, KEYP_SCAN);
-		if (scan_val & 0x1)
-			rc = pmic8058_kp_read_u8(kp, &temp, data_reg);
-	} while ((scan_val & 0x1) && (--retries > 0));
-
-	if (retries == 0)
-		dev_dbg(kp->dev, "Unable to clear read state bit\n");
-
-	return 0;
-}
-/*
- * Synchronous read protocol for RevB0 onwards:
- *
- * 1. Write '1' to ReadState bit in KEYP_SCAN register
- * 2. Wait 2*32KHz clocks, so that HW can successfully enter read mode
- *    synchronously
- * 3. Read rows in old array first if events are more than one
- * 4. Read rows in recent array
- * 5. Wait 4*32KHz clocks
- * 6. Write '0' to ReadState bit of KEYP_SCAN register so that hw can
- *    synchronously exit read mode.
- */
-static int pmic8058_chk_sync_read(struct pmic8058_kp *kp)
-{
-	int rc;
-	u8 scan_val;
-
-	rc = pmic8058_kp_read_u8(kp, &scan_val, KEYP_SCAN);
-	scan_val |= 0x1;
-	rc = pmic8058_kp_write_u8(kp, scan_val, KEYP_SCAN);
-
-	/* 2 * 32KHz clocks */
-	udelay((2 * USEC_PER_SEC / KEYP_CLOCK_FREQ) + 1);
-
-	return rc;
-}
-
-static int pmic8058_kp_read_data(struct pmic8058_kp *kp, u16 *state,
-					u16 data_reg, int read_rows)
-{
-	int rc, row;
-	u8 new_data[PM8058_MAX_ROWS];
-
-	rc = pmic8058_kp_read(kp, new_data, data_reg, read_rows);
-
-	if (!rc) {
-		if (pm8058_rev(kp->pm_chip) == PM_8058_REV_1p0)
-			pmic8058_chk_read_state(kp, data_reg);
-		for (row = 0; row < kp->pdata->num_rows; row++) {
-			dev_dbg(kp->dev, "new_data[%d] = %d\n", row,
-						new_data[row]);
-			state[row] = pmic8058_col_state(kp, new_data[row]);
-		}
-	}
-
-	return rc;
-}
-
-static int pmic8058_kp_read_matrix(struct pmic8058_kp *kp, u16 *new_state,
-					 u16 *old_state)
-{
-	int rc, read_rows;
-	u8 scan_val;
-	static u8 rows[] = {
-		5, 6, 7, 8, 10, 10, 12, 12, 15, 15, 15, 18, 18, 18
-	};
-
-	if (kp->flags & KEYF_FIX_LAST_ROW &&
-			(kp->pdata->num_rows != PM8058_MAX_ROWS))
-		read_rows = rows[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN
-					 + 1];
-	else
-		read_rows = kp->pdata->num_rows;
-
-	if (pm8058_rev(kp->pm_chip) > PM_8058_REV_1p0)
-		pmic8058_chk_sync_read(kp);
-
-	if (old_state)
-		rc = pmic8058_kp_read_data(kp, old_state, KEYP_OLD_DATA,
-						read_rows);
-
-	rc = pmic8058_kp_read_data(kp, new_state, KEYP_RECENT_DATA,
-					 read_rows);
-
-	if (pm8058_rev(kp->pm_chip) > PM_8058_REV_1p0) {
-		/* 4 * 32KHz clocks */
-		udelay((4 * USEC_PER_SEC / KEYP_CLOCK_FREQ) + 1);
-
-		rc = pmic8058_kp_read(kp, &scan_val, KEYP_SCAN, 1);
-		scan_val &= 0xFE;
-		rc = pmic8058_kp_write_u8(kp, scan_val, KEYP_SCAN);
-	}
-
-	return rc;
-}
-
-static int __pmic8058_kp_scan_matrix(struct pmic8058_kp *kp, u16 *new_state,
-					 u16 *old_state)
-{
-	int row, col, code;
-
-	for (row = 0; row < kp->pdata->num_rows; row++) {
-		int bits_changed = new_state[row] ^ old_state[row];
-
-		if (!bits_changed)
-			continue;
-
-		for (col = 0; col < kp->pdata->num_cols; col++) {
-			if (!(bits_changed & (1 << col)))
-				continue;
-
-			dev_dbg(kp->dev, "key [%d:%d] %s\n", row, col,
-					!(new_state[row] & (1 << col)) ?
-					"pressed" : "released");
-
-			code = MATRIX_SCAN_CODE(row, col, PM8058_ROW_SHIFT);
-			input_event(kp->input, EV_MSC, MSC_SCAN, code);
-			input_report_key(kp->input,
-					kp->keycodes[code],
-					!(new_state[row] & (1 << col)));
-
-			input_sync(kp->input);
-		}
-	}
-
-	return 0;
-}
-
-static int pmic8058_detect_ghost_keys(struct pmic8058_kp *kp, u16 *new_state)
-{
-	int row, found_first = -1;
-	u16 check, row_state;
-
-	check = 0;
-	for (row = 0; row < kp->pdata->num_rows; row++) {
-		row_state = (~new_state[row]) &
-				 ((1 << kp->pdata->num_cols) - 1);
-
-		if (hweight16(row_state) > 1) {
-			if (found_first == -1)
-				found_first = row;
-			if (check & row_state) {
-				dev_dbg(kp->dev, "detected ghost key on row[%d]"
-						 "row[%d]\n", found_first, row);
-				return 1;
-			}
-		}
-		check |= row_state;
-	}
-	return 0;
-}
-
-static int pmic8058_kp_scan_matrix(struct pmic8058_kp *kp, unsigned int events)
-{
-	u16 new_state[PM8058_MAX_ROWS];
-	u16 old_state[PM8058_MAX_ROWS];
-	int rc;
-
-	switch (events) {
-	case 0x1:
-		rc = pmic8058_kp_read_matrix(kp, new_state, NULL);
-		if (pmic8058_detect_ghost_keys(kp, new_state))
-			return -EINVAL;
-		__pmic8058_kp_scan_matrix(kp, new_state, kp->keystate);
-		memcpy(kp->keystate, new_state, sizeof(new_state));
-	break;
-	case 0x3: /* two events - eventcounter is gray-coded */
-		rc = pmic8058_kp_read_matrix(kp, new_state, old_state);
-		__pmic8058_kp_scan_matrix(kp, old_state, kp->keystate);
-		__pmic8058_kp_scan_matrix(kp, new_state, old_state);
-		memcpy(kp->keystate, new_state, sizeof(new_state));
-	break;
-	case 0x2:
-		dev_dbg(kp->dev, "Some key events are missed\n");
-		rc = pmic8058_kp_read_matrix(kp, new_state, old_state);
-		__pmic8058_kp_scan_matrix(kp, old_state, kp->keystate);
-		__pmic8058_kp_scan_matrix(kp, new_state, old_state);
-		memcpy(kp->keystate, new_state, sizeof(new_state));
-	break;
-	default:
-		rc = -1;
-	}
-	return rc;
-}
-
-static inline int pmic8058_kp_disabled(struct pmic8058_kp *kp)
-{
-	return kp->disable_depth != 0;
-}
-
-static void pmic8058_kp_enable(struct pmic8058_kp *kp)
-{
-	if (!pmic8058_kp_disabled(kp))
-		return;
-
-	if (--kp->disable_depth == 0) {
-
-		kp->ctrl_reg |= KEYP_CTRL_KEYP_EN;
-		pmic8058_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL);
-
-		enable_irq(kp->key_sense_irq);
-		enable_irq(kp->key_stuck_irq);
-	}
-}
-
-static void pmic8058_kp_disable(struct pmic8058_kp *kp)
-{
-	if (kp->disable_depth++ == 0) {
-		disable_irq(kp->key_sense_irq);
-		disable_irq(kp->key_stuck_irq);
-
-		kp->ctrl_reg &= ~KEYP_CTRL_KEYP_EN;
-		pmic8058_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL);
-	}
-}
-
-static ssize_t pmic8058_kp_disable_show(struct device *dev,
-					struct device_attribute *attr,
-					char *buf)
-{
-	struct pmic8058_kp *kp = dev_get_drvdata(dev);
-
-	return sprintf(buf, "%u\n", pmic8058_kp_disabled(kp));
-}
-
-static ssize_t pmic8058_kp_disable_store(struct device *dev,
-					struct device_attribute *attr,
-					const char *buf, size_t count)
-{
-	struct pmic8058_kp *kp = dev_get_drvdata(dev);
-	long i = 0;
-	int rc;
-
-	rc = strict_strtoul(buf, 10, &i);
-	if (rc)
-		return -EINVAL;
-
-	i = !!i;
-
-	mutex_lock(&kp->mutex);
-	if (i == kp->user_disabled) {
-		mutex_unlock(&kp->mutex);
-		return count;
-	}
-
-	kp->user_disabled = i;
-
-	if (i)
-		pmic8058_kp_disable(kp);
-	else
-		pmic8058_kp_enable(kp);
-	mutex_unlock(&kp->mutex);
-
-	return count;
-}
-
-static DEVICE_ATTR(disable_kp, 0664, pmic8058_kp_disable_show,
-			pmic8058_kp_disable_store);
-
-
-/*
- * NOTE: We are reading recent and old data registers blindly
- * whenever key-stuck interrupt happens, because events counter doesn't
- * get updated when this interrupt happens due to key stuck doesn't get
- * considered as key state change.
- *
- * We are not using old data register contents after they are being read
- * because it might report the key which was pressed before the key being stuck
- * as stuck key because it's pressed status is stored in the old data
- * register.
- */
-static irqreturn_t pmic8058_kp_stuck_irq(int irq, void *data)
-{
-	u16 new_state[PM8058_MAX_ROWS];
-	u16 old_state[PM8058_MAX_ROWS];
-	int rc;
-	struct pmic8058_kp *kp = data;
-
-	rc = pmic8058_kp_read_matrix(kp, new_state, old_state);
-	__pmic8058_kp_scan_matrix(kp, new_state, kp->stuckstate);
-
-	return IRQ_HANDLED;
-}
-
-/*
- * NOTE: Any row multiple interrupt issue - PMIC4 Rev A0
- *
- * If the S/W responds to the key-event interrupt too early and reads the
- * recent data, the keypad FSM will mistakenly go to the IDLE state, instead
- * of the scan pause state as it is supposed too. Since the key is still
- * pressed, the keypad scanner will go through the debounce, scan, and generate
- * another key event interrupt. The workaround for this issue is to add delay
- * of 1ms between servicing the key event interrupt and reading the recent data.
- */
-static irqreturn_t pmic8058_kp_irq(int irq, void *data)
-{
-	struct pmic8058_kp *kp = data;
-	u8 ctrl_val, events;
-	int rc;
-
-	if (pm8058_rev(kp->pm_chip) == PM_8058_REV_1p0)
-		mdelay(1);
-
-	dev_dbg(kp->dev, "key sense irq\n");
-	__dump_kp_regs(kp, "pmic8058_kp_irq");
-
-	rc = pmic8058_kp_read(kp, &ctrl_val, KEYP_CTRL, 1);
-	events = ctrl_val & KEYP_CTRL_EVNTS_MASK;
-
-	rc = pmic8058_kp_scan_matrix(kp, events);
-
-	return IRQ_HANDLED;
-}
-/*
- * NOTE: Last row multi-interrupt issue
- *
- * In PMIC Rev A0, if any key in the last row of the keypad matrix
- * is pressed and held, the H/W keeps on generating interrupts.
- * Software work-arounds it by programming the keypad controller next level
- * up rows (for 8x12 matrix it is 15 rows) so the keypad controller
- * thinks of more-rows than the actual ones, so the actual last-row
- * in the matrix won't generate multiple interrupts.
- */
-static int pmic8058_kpd_init(struct pmic8058_kp *kp)
-{
-	int bits, rc, cycles;
-	u8 scan_val = 0, ctrl_val = 0;
-	static u8 row_bits[] = {
-		0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7,
-	};
-
-	/* Find column bits */
-	if (kp->pdata->num_cols < KEYP_CTRL_SCAN_COLS_MIN)
-		bits = 0;
-	else
-		bits = kp->pdata->num_cols - KEYP_CTRL_SCAN_COLS_MIN;
-	ctrl_val = (bits & KEYP_CTRL_SCAN_COLS_BITS) <<
-		KEYP_CTRL_SCAN_COLS_SHIFT;
-
-	/* Find row bits */
-	if (kp->pdata->num_rows < KEYP_CTRL_SCAN_ROWS_MIN)
-		bits = 0;
-	else if (kp->pdata->num_rows > PM8058_MAX_ROWS)
-		bits = KEYP_CTRL_SCAN_ROWS_BITS;
-	else
-		bits = row_bits[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN];
-
-	/* Use max rows to fix last row problem if actual rows are less */
-	if (kp->flags & KEYF_FIX_LAST_ROW &&
-			 (kp->pdata->num_rows != PM8058_MAX_ROWS))
-		bits = row_bits[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN
-					 + 1];
-
-	ctrl_val |= (bits << KEYP_CTRL_SCAN_ROWS_SHIFT);
-
-	rc = pmic8058_kp_write_u8(kp, ctrl_val, KEYP_CTRL);
-
-	if (pm8058_rev(kp->pm_chip) == PM_8058_REV_1p0)
-		bits = fls(kp->pdata->debounce_ms[0]) - 1;
-	else
-		bits = (kp->pdata->debounce_ms[1] / 5) - 1;
-
-	scan_val |= (bits << KEYP_SCAN_DBOUNCE_SHIFT);
-
-	bits = fls(kp->pdata->scan_delay_ms) - 1;
-	scan_val |= (bits << KEYP_SCAN_PAUSE_SHIFT);
-
-	/* Row hold time is a multiple of 32KHz cycles. */
-	cycles = (kp->pdata->row_hold_ns * KEYP_CLOCK_FREQ) / NSEC_PER_SEC;
-
-	scan_val |= (cycles << KEYP_SCAN_ROW_HOLD_SHIFT);
-
-	rc = pmic8058_kp_write_u8(kp, scan_val, KEYP_SCAN);
-
-	return rc;
-}
-
-static int pm8058_kp_config_drv(int gpio_start, int num_gpios)
-{
-	int	rc;
-	struct pm8058_gpio kypd_drv = {
-		.direction	= PM_GPIO_DIR_OUT,
-		.output_buffer	= PM_GPIO_OUT_BUF_OPEN_DRAIN,
-		.output_value	= 0,
-		.pull		= PM_GPIO_PULL_NO,
-		.vin_sel	= 2,
-		.out_strength	= PM_GPIO_STRENGTH_LOW,
-		.function	= PM_GPIO_FUNC_1,
-		.inv_int_pol	= 1,
-	};
-
-	if (gpio_start < 0 || num_gpios < 0 || num_gpios > PM8058_GPIOS)
-		return -EINVAL;
-
-	while (num_gpios--) {
-		rc = pm8058_gpio_config(gpio_start++, &kypd_drv);
-		if (rc) {
-			pr_err("%s: FAIL pm8058_gpio_config(): rc=%d.\n",
-				__func__, rc);
-			return rc;
-		}
-	}
-
-	return 0;
-}
-
-static int pm8058_kp_config_sns(int gpio_start, int num_gpios)
-{
-	int	rc;
-	struct pm8058_gpio kypd_sns = {
-		.direction	= PM_GPIO_DIR_IN,
-		.pull		= PM_GPIO_PULL_UP_31P5,
-		.vin_sel	= 2,
-		.out_strength	= PM_GPIO_STRENGTH_NO,
-		.function	= PM_GPIO_FUNC_NORMAL,
-		.inv_int_pol	= 1,
-	};
-
-	if (gpio_start < 0 || num_gpios < 0 || num_gpios > PM8058_GPIOS)
-		return -EINVAL;
-
-	while (num_gpios--) {
-		rc = pm8058_gpio_config(gpio_start++, &kypd_sns);
-		if (rc) {
-			pr_err("%s: FAIL pm8058_gpio_config(): rc=%d.\n",
-				__func__, rc);
-			return rc;
-		}
-	}
-
-	return 0;
-}
-
-/*
- * keypad controller should be initialized in the following sequence
- * only, otherwise it might get into FSM stuck state.
- *
- * - Initialize keypad control parameters, like no. of rows, columns,
- *   timing values etc.,
- * - configure rows and column gpios pull up/down.
- * - set irq edge type.
- * - enable the keypad controller.
- */
-static int __devinit pmic8058_kp_probe(struct platform_device *pdev)
-{
-	struct pmic8058_keypad_data *pdata = pdev->dev.platform_data;
-	const struct matrix_keymap_data *keymap_data;
-	struct pmic8058_kp *kp;
-	int rc;
-	unsigned short *keycodes;
-	u8 ctrl_val;
-	struct pm8058_chip	*pm_chip;
-
-	pm_chip = dev_get_drvdata(pdev->dev.parent);
-	if (pm_chip == NULL) {
-		dev_err(&pdev->dev, "no parent data passed in\n");
-		return -EFAULT;
-	}
-
-	if (!pdata || !pdata->num_cols || !pdata->num_rows ||
-		pdata->num_cols > PM8058_MAX_COLS ||
-		pdata->num_rows > PM8058_MAX_ROWS ||
-		pdata->num_cols < PM8058_MIN_COLS ||
-		pdata->num_rows < PM8058_MIN_ROWS) {
-		dev_err(&pdev->dev, "invalid platform data\n");
-		return -EINVAL;
-	}
-
-	if (pdata->rows_gpio_start < 0 || pdata->cols_gpio_start < 0) {
-		dev_err(&pdev->dev, "invalid gpio_start platform data\n");
-		return -EINVAL;
-	}
-
-	if (!pdata->scan_delay_ms || pdata->scan_delay_ms > MAX_SCAN_DELAY
-		|| pdata->scan_delay_ms < MIN_SCAN_DELAY ||
-		!is_power_of_2(pdata->scan_delay_ms)) {
-		dev_err(&pdev->dev, "invalid keypad scan time supplied\n");
-		return -EINVAL;
-	}
-
-	if (!pdata->row_hold_ns || pdata->row_hold_ns > MAX_ROW_HOLD_DELAY
-		|| pdata->row_hold_ns < MIN_ROW_HOLD_DELAY ||
-		((pdata->row_hold_ns % MIN_ROW_HOLD_DELAY) != 0)) {
-		dev_err(&pdev->dev, "invalid keypad row hold time supplied\n");
-		return -EINVAL;
-	}
-
-	if (pm8058_rev(pm_chip) == PM_8058_REV_1p0) {
-		if (!pdata->debounce_ms
-			|| !is_power_of_2(pdata->debounce_ms[0])
-			|| pdata->debounce_ms[0] > MAX_DEBOUNCE_A0_TIME
-			|| pdata->debounce_ms[0] < MIN_DEBOUNCE_A0_TIME) {
-			dev_err(&pdev->dev, "invalid debounce time supplied\n");
-			return -EINVAL;
-		}
-	} else {
-		if (!pdata->debounce_ms
-			|| ((pdata->debounce_ms[1] % 5) != 0)
-			|| pdata->debounce_ms[1] > MAX_DEBOUNCE_B0_TIME
-			|| pdata->debounce_ms[1] < MIN_DEBOUNCE_B0_TIME) {
-			dev_err(&pdev->dev, "invalid debounce time supplied\n");
-			return -EINVAL;
-		}
-	}
-
-	keymap_data = pdata->keymap_data;
-	if (!keymap_data) {
-		dev_err(&pdev->dev, "no keymap data supplied\n");
-		return -EINVAL;
-	}
-
-	kp = kzalloc(sizeof(*kp), GFP_KERNEL);
-	if (!kp)
-		return -ENOMEM;
-
-	keycodes = kzalloc(PM8058_MATRIX_MAX_SIZE * sizeof(*keycodes),
-				 GFP_KERNEL);
-	if (!keycodes) {
-		rc = -ENOMEM;
-		goto err_alloc_mem;
-	}
-
-	platform_set_drvdata(pdev, kp);
-	mutex_init(&kp->mutex);
-
-	kp->pdata	= pdata;
-	kp->dev		= &pdev->dev;
-	kp->keycodes	= keycodes;
-	kp->pm_chip	= pm_chip;
-
-	if (pm8058_rev(pm_chip) == PM_8058_REV_1p0)
-		kp->flags |= KEYF_FIX_LAST_ROW;
-
-	kp->input = input_allocate_device();
-	if (!kp->input) {
-		dev_err(&pdev->dev, "unable to allocate input device\n");
-		rc = -ENOMEM;
-		goto err_alloc_device;
-	}
-
-	/* Enable runtime PM ops, start in ACTIVE mode */
-	rc = pm_runtime_set_active(&pdev->dev);
-	if (rc < 0)
-		dev_dbg(&pdev->dev, "unable to set runtime pm state\n");
-	pm_runtime_enable(&pdev->dev);
-
-	kp->key_sense_irq = platform_get_irq(pdev, 0);
-	if (kp->key_sense_irq < 0) {
-		dev_err(&pdev->dev, "unable to get keypad sense irq\n");
-		rc = -ENXIO;
-		goto err_get_irq;
-	}
-
-	kp->key_stuck_irq = platform_get_irq(pdev, 1);
-	if (kp->key_stuck_irq < 0) {
-		dev_err(&pdev->dev, "unable to get keypad stuck irq\n");
-		rc = -ENXIO;
-		goto err_get_irq;
-	}
-
-	if (pdata->input_name)
-		kp->input->name = pdata->input_name;
-	else
-		kp->input->name = "PMIC8058 keypad";
-
-	if (pdata->input_phys_device)
-		kp->input->phys = pdata->input_phys_device;
-	else
-		kp->input->phys = "pmic8058_keypad/input0";
-
-	kp->input->dev.parent	= &pdev->dev;
-
-	kp->input->id.bustype	= BUS_HOST;
-	kp->input->id.version	= 0x0001;
-	kp->input->id.product	= 0x0001;
-	kp->input->id.vendor	= 0x0001;
-
-	kp->input->evbit[0]	= BIT_MASK(EV_KEY);
-
-	if (pdata->rep)
-		__set_bit(EV_REP, kp->input->evbit);
-
-	kp->input->keycode	= keycodes;
-	kp->input->keycodemax	= PM8058_MATRIX_MAX_SIZE;
-	kp->input->keycodesize	= sizeof(*keycodes);
-
-	matrix_keypad_build_keymap(keymap_data, PM8058_ROW_SHIFT,
-					kp->input->keycode, kp->input->keybit);
-
-	input_set_capability(kp->input, EV_MSC, MSC_SCAN);
-	input_set_drvdata(kp->input, kp);
-
-	rc = input_register_device(kp->input);
-	if (rc < 0) {
-		dev_err(&pdev->dev, "unable to register keypad input device\n");
-		goto err_get_irq;
-	}
-
-	/* initialize keypad state */
-	memset(kp->keystate, 0xff, sizeof(kp->keystate));
-	memset(kp->stuckstate, 0xff, sizeof(kp->stuckstate));
-
-	rc = pmic8058_kpd_init(kp);
-	if (rc < 0) {
-		dev_err(&pdev->dev, "unable to initialize keypad controller\n");
-		goto err_kpd_init;
-	}
-
-	rc = pm8058_kp_config_sns(pdata->cols_gpio_start,
-			pdata->num_cols);
-	if (rc < 0) {
-		dev_err(&pdev->dev, "unable to configure keypad sense lines\n");
-		goto err_gpio_config;
-	}
-
-	rc = pm8058_kp_config_drv(pdata->rows_gpio_start,
-			pdata->num_rows);
-	if (rc < 0) {
-		dev_err(&pdev->dev, "unable to configure keypad drive lines\n");
-		goto err_gpio_config;
-	}
-
-	rc = request_threaded_irq(kp->key_sense_irq, NULL, pmic8058_kp_irq,
-				 IRQF_TRIGGER_RISING, "pmic-keypad", kp);
-	if (rc < 0) {
-		dev_err(&pdev->dev, "failed to request keypad sense irq\n");
-		goto err_req_sense_irq;
-	}
-
-	rc = request_threaded_irq(kp->key_stuck_irq, NULL,
-				 pmic8058_kp_stuck_irq, IRQF_TRIGGER_RISING,
-				 "pmic-keypad-stuck", kp);
-	if (rc < 0) {
-		dev_err(&pdev->dev, "failed to request keypad stuck irq\n");
-		goto err_req_stuck_irq;
-	}
-
-	rc = pmic8058_kp_read_u8(kp, &ctrl_val, KEYP_CTRL);
-	ctrl_val |= KEYP_CTRL_KEYP_EN;
-	rc = pmic8058_kp_write_u8(kp, ctrl_val, KEYP_CTRL);
-
-	kp->ctrl_reg = ctrl_val;
-
-	__dump_kp_regs(kp, "probe");
-
-	rc = device_create_file(&pdev->dev, &dev_attr_disable_kp);
-	if (rc < 0)
-		goto err_create_file;
-
-	device_init_wakeup(&pdev->dev, pdata->wakeup);
-
-	return 0;
-
-err_create_file:
-	free_irq(kp->key_stuck_irq, NULL);
-err_req_stuck_irq:
-	free_irq(kp->key_sense_irq, NULL);
-err_req_sense_irq:
-err_gpio_config:
-err_kpd_init:
-	input_unregister_device(kp->input);
-	kp->input = NULL;
-err_get_irq:
-	pm_runtime_set_suspended(&pdev->dev);
-	pm_runtime_disable(&pdev->dev);
-	input_free_device(kp->input);
-err_alloc_device:
-	kfree(keycodes);
-err_alloc_mem:
-	kfree(kp);
-	return rc;
-}
-
-static int __devexit pmic8058_kp_remove(struct platform_device *pdev)
-{
-	struct pmic8058_kp *kp = platform_get_drvdata(pdev);
-
-	pm_runtime_set_suspended(&pdev->dev);
-	pm_runtime_disable(&pdev->dev);
-	device_remove_file(&pdev->dev, &dev_attr_disable_kp);
-	device_init_wakeup(&pdev->dev, 0);
-	free_irq(kp->key_stuck_irq, NULL);
-	free_irq(kp->key_sense_irq, NULL);
-	input_unregister_device(kp->input);
-	platform_set_drvdata(pdev, NULL);
-	kfree(kp->input->keycode);
-	kfree(kp);
-
-	return 0;
-}
-
-#ifdef CONFIG_PM
-static int pmic8058_kp_suspend(struct device *dev)
-{
-	struct pmic8058_kp *kp = dev_get_drvdata(dev);
-
-	if (device_may_wakeup(dev) && !pmic8058_kp_disabled(kp)) {
-		enable_irq_wake(kp->key_sense_irq);
-	} else {
-		mutex_lock(&kp->mutex);
-		pmic8058_kp_disable(kp);
-		mutex_unlock(&kp->mutex);
-	}
-
-	return 0;
-}
-
-static int pmic8058_kp_resume(struct device *dev)
-{
-	struct pmic8058_kp *kp = dev_get_drvdata(dev);
-
-	if (device_may_wakeup(dev) && !pmic8058_kp_disabled(kp)) {
-		disable_irq_wake(kp->key_sense_irq);
-	} else {
-		mutex_lock(&kp->mutex);
-		pmic8058_kp_enable(kp);
-		mutex_unlock(&kp->mutex);
-	}
-
-	return 0;
-}
-
-static struct dev_pm_ops pm8058_kp_pm_ops = {
-	.suspend	= pmic8058_kp_suspend,
-	.resume		= pmic8058_kp_resume,
-};
-#endif
-
-static struct platform_driver pmic8058_kp_driver = {
-	.probe		= pmic8058_kp_probe,
-	.remove		= __devexit_p(pmic8058_kp_remove),
-	.driver		= {
-		.name = "pm8058-keypad",
-		.owner = THIS_MODULE,
-#ifdef CONFIG_PM
-		.pm = &pm8058_kp_pm_ops,
-#endif
-	},
-};
-
-static int __init pmic8058_kp_init(void)
-{
-	return platform_driver_register(&pmic8058_kp_driver);
-}
-module_init(pmic8058_kp_init);
-
-static void __exit pmic8058_kp_exit(void)
-{
-	platform_driver_unregister(&pmic8058_kp_driver);
-}
-module_exit(pmic8058_kp_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("PMIC8058 keypad driver");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:pmic8058_keypad");
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 9acebc0..d279a63 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -517,16 +517,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called xen-kbdfront.
 
-config PMIC8058_PWRKEY
-        tristate "PMIC8058 power key support"
-        default n
-        depends on PMIC8058
-        help
-          Say Y here if you want support for the PMIC8058 power key.
-
-          To compile this driver as a module, choose M here: the
-          module will be called pmic8058-pwrkey.
-
 config PMIC8058_OTHC
         tristate "Qualcomm PMIC8058 OTHC support"
         default n
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 770eb96..c5c4639 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -36,7 +36,6 @@
 obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY)	+= pmic8xxx-pwrkey.o
 obj-$(CONFIG_INPUT_POWERMATE)		+= powermate.o
 obj-$(CONFIG_INPUT_PWM_BEEPER)		+= pwm-beeper.o
-obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY)	+= pmic8xxx-pwrkey.o
 obj-$(CONFIG_INPUT_RB532_BUTTON)	+= rb532_button.o
 obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER)	+= rotary_encoder.o
 obj-$(CONFIG_INPUT_SGI_BTNS)		+= sgi_btns.o
@@ -49,7 +48,6 @@
 obj-$(CONFIG_INPUT_WM831X_ON)		+= wm831x-on.o
 obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND)	+= xen-kbdfront.o
 obj-$(CONFIG_INPUT_YEALINK)		+= yealink.o
-obj-$(CONFIG_PMIC8058_PWRKEY)           += pmic8058-pwrkey.o
 obj-$(CONFIG_PMIC8058_OTHC)             += pmic8058-othc.o
 obj-$(CONFIG_INPUT_PMIC8058_VIBRA_MEMLESS) += pmic8058-vib-memless.o
 obj-$(CONFIG_BOSCH_BMA150)              += bma150.o
diff --git a/drivers/input/misc/pmic8058-pwrkey.c b/drivers/input/misc/pmic8058-pwrkey.c
deleted file mode 100644
index a981013..0000000
--- a/drivers/input/misc/pmic8058-pwrkey.c
+++ /dev/null
@@ -1,375 +0,0 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. 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 version 2 and
- * only 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.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/input.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/mfd/pmic8058.h>
-#include <linux/pmic8058-pwrkey.h>
-#include <linux/log2.h>
-#include <linux/spinlock.h>
-#include <linux/hrtimer.h>
-#include <linux/pm.h>
-#include <linux/slab.h>
-#include <linux/pm_runtime.h>
-
-#define PON_CNTL_1	0x1C
-#define PON_CNTL_PULL_UP BIT(7)
-#define PON_CNTL_TRIG_DELAY_MASK (0x7)
-
-struct pmic8058_pwrkey {
-	struct input_dev *pwr;
-	int key_press_irq;
-	int key_release_irq;
-	struct pm8058_chip	*pm_chip;
-	struct hrtimer timer;
-	bool key_pressed;
-	bool pressed_first;
-	struct pmic8058_pwrkey_pdata *pdata;
-	spinlock_t lock;
-};
-
-static enum hrtimer_restart pmic8058_pwrkey_timer(struct hrtimer *timer)
-{
-	unsigned long flags;
-	struct pmic8058_pwrkey *pwrkey = container_of(timer,
-						struct pmic8058_pwrkey,	timer);
-
-	spin_lock_irqsave(&pwrkey->lock, flags);
-	pwrkey->key_pressed = true;
-
-	input_report_key(pwrkey->pwr, KEY_POWER, 1);
-	input_sync(pwrkey->pwr);
-	spin_unlock_irqrestore(&pwrkey->lock, flags);
-
-	return HRTIMER_NORESTART;
-}
-
-static irqreturn_t pwrkey_press_irq(int irq, void *_pwrkey)
-{
-	struct pmic8058_pwrkey *pwrkey = _pwrkey;
-	struct pmic8058_pwrkey_pdata *pdata = pwrkey->pdata;
-	unsigned long flags;
-
-	spin_lock_irqsave(&pwrkey->lock, flags);
-	if (pwrkey->pressed_first) {
-		/*
-		 * If pressed_first flag is set already then release interrupt
-		 * has occured first. Events are handled in the release IRQ so
-		 * return.
-		 */
-		pwrkey->pressed_first = false;
-		spin_unlock_irqrestore(&pwrkey->lock, flags);
-		return IRQ_HANDLED;
-	} else {
-		pwrkey->pressed_first = true;
-		/*no pwrkey time duration, means no end key simulation*/
-		if (!pwrkey->pdata->pwrkey_time_ms) {
-			input_report_key(pwrkey->pwr, KEY_POWER, 1);
-			input_sync(pwrkey->pwr);
-			spin_unlock_irqrestore(&pwrkey->lock, flags);
-			return IRQ_HANDLED;
-		}
-
-		input_report_key(pwrkey->pwr, KEY_END, 1);
-		input_sync(pwrkey->pwr);
-
-		hrtimer_start(&pwrkey->timer,
-				ktime_set(pdata->pwrkey_time_ms / 1000,
-				(pdata->pwrkey_time_ms % 1000) * 1000000),
-				HRTIMER_MODE_REL);
-	}
-	spin_unlock_irqrestore(&pwrkey->lock, flags);
-
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t pwrkey_release_irq(int irq, void *_pwrkey)
-{
-	struct pmic8058_pwrkey *pwrkey = _pwrkey;
-	unsigned long flags;
-
-	spin_lock_irqsave(&pwrkey->lock, flags);
-	if (pwrkey->pressed_first) {
-		pwrkey->pressed_first = false;
-		/* no pwrkey time, means no delay in pwr key reporting */
-		if (!pwrkey->pdata->pwrkey_time_ms) {
-			input_report_key(pwrkey->pwr, KEY_POWER, 0);
-			input_sync(pwrkey->pwr);
-			spin_unlock_irqrestore(&pwrkey->lock, flags);
-			return IRQ_HANDLED;
-		}
-
-		hrtimer_cancel(&pwrkey->timer);
-
-		if (pwrkey->key_pressed) {
-			pwrkey->key_pressed = false;
-			input_report_key(pwrkey->pwr, KEY_POWER, 0);
-			input_sync(pwrkey->pwr);
-		}
-
-		input_report_key(pwrkey->pwr, KEY_END, 0);
-		input_sync(pwrkey->pwr);
-	} else {
-		/*
-		 * Set this flag true so that in the subsequent interrupt of
-		 * press we can know release interrupt came first
-		 */
-		pwrkey->pressed_first = true;
-		/* no pwrkey time, means no delay in pwr key reporting */
-		if (!pwrkey->pdata->pwrkey_time_ms) {
-			input_report_key(pwrkey->pwr, KEY_POWER, 1);
-			input_sync(pwrkey->pwr);
-			input_report_key(pwrkey->pwr, KEY_POWER, 0);
-			input_sync(pwrkey->pwr);
-			spin_unlock_irqrestore(&pwrkey->lock, flags);
-			return IRQ_HANDLED;
-		}
-		input_report_key(pwrkey->pwr, KEY_END, 1);
-		input_sync(pwrkey->pwr);
-		input_report_key(pwrkey->pwr, KEY_END, 0);
-		input_sync(pwrkey->pwr);
-	}
-	spin_unlock_irqrestore(&pwrkey->lock, flags);
-
-	return IRQ_HANDLED;
-}
-
-#ifdef CONFIG_PM
-static int pmic8058_pwrkey_suspend(struct device *dev)
-{
-	struct pmic8058_pwrkey *pwrkey = dev_get_drvdata(dev);
-
-	if (device_may_wakeup(dev)) {
-		enable_irq_wake(pwrkey->key_press_irq);
-		enable_irq_wake(pwrkey->key_release_irq);
-	}
-
-	return 0;
-}
-
-static int pmic8058_pwrkey_resume(struct device *dev)
-{
-	struct pmic8058_pwrkey *pwrkey = dev_get_drvdata(dev);
-
-	if (device_may_wakeup(dev)) {
-		disable_irq_wake(pwrkey->key_press_irq);
-		disable_irq_wake(pwrkey->key_release_irq);
-	}
-
-	return 0;
-}
-
-static struct dev_pm_ops pm8058_pwr_key_pm_ops = {
-	.suspend	= pmic8058_pwrkey_suspend,
-	.resume		= pmic8058_pwrkey_resume,
-};
-#endif
-
-static int __devinit pmic8058_pwrkey_probe(struct platform_device *pdev)
-{
-	struct input_dev *pwr;
-	int key_release_irq = platform_get_irq(pdev, 0);
-	int key_press_irq = platform_get_irq(pdev, 1);
-	int err;
-	unsigned int delay;
-	u8 pon_cntl;
-	struct pmic8058_pwrkey *pwrkey;
-	struct pmic8058_pwrkey_pdata *pdata = pdev->dev.platform_data;
-	struct pm8058_chip	*pm_chip;
-
-	pm_chip = dev_get_drvdata(pdev->dev.parent);
-	if (pm_chip == NULL) {
-		dev_err(&pdev->dev, "no parent data passed in\n");
-		return -EFAULT;
-	}
-
-	if (!pdata) {
-		dev_err(&pdev->dev, "power key platform data not supplied\n");
-		return -EINVAL;
-	}
-
-	if (pdata->kpd_trigger_delay_us > 62500) {
-		dev_err(&pdev->dev, "invalid pwr key trigger delay\n");
-		return -EINVAL;
-	}
-
-	if (pdata->pwrkey_time_ms &&
-	     (pdata->pwrkey_time_ms < 500 || pdata->pwrkey_time_ms > 1000)) {
-		dev_err(&pdev->dev, "invalid pwr key time supplied\n");
-		return -EINVAL;
-	}
-
-	pwrkey = kzalloc(sizeof(*pwrkey), GFP_KERNEL);
-	if (!pwrkey)
-		return -ENOMEM;
-
-	pwrkey->pm_chip = pm_chip;
-	pwrkey->pdata   = pdata;
-	pwrkey->pressed_first = false;
-	/* Enable runtime PM ops, start in ACTIVE mode */
-	err = pm_runtime_set_active(&pdev->dev);
-	if (err < 0)
-		dev_dbg(&pdev->dev, "unable to set runtime pm state\n");
-	pm_runtime_enable(&pdev->dev);
-
-	pwr = input_allocate_device();
-	if (!pwr) {
-		dev_dbg(&pdev->dev, "Can't allocate power button\n");
-		err = -ENOMEM;
-		goto free_pwrkey;
-	}
-
-	input_set_capability(pwr, EV_KEY, KEY_POWER);
-	input_set_capability(pwr, EV_KEY, KEY_END);
-
-	pwr->name = "pmic8058_pwrkey";
-	pwr->phys = "pmic8058_pwrkey/input0";
-	pwr->dev.parent = &pdev->dev;
-
-	delay = (pdata->kpd_trigger_delay_us << 10) / USEC_PER_SEC;
-	delay = 1 + ilog2(delay);
-
-	err = pm8058_read(pwrkey->pm_chip, PON_CNTL_1, &pon_cntl, 1);
-	if (err < 0) {
-		dev_err(&pdev->dev, "failed reading PON_CNTL_1 err=%d\n", err);
-		goto free_input_dev;
-	}
-
-
-	pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
-	pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
-	pon_cntl |= (pdata->pull_up ? PON_CNTL_PULL_UP : ~PON_CNTL_PULL_UP);
-	err = pm8058_write(pwrkey->pm_chip, PON_CNTL_1, &pon_cntl, 1);
-	if (err < 0) {
-		dev_err(&pdev->dev, "failed writing PON_CNTL_1 err=%d\n", err);
-		goto free_input_dev;
-	}
-
-	hrtimer_init(&pwrkey->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-	pwrkey->timer.function = pmic8058_pwrkey_timer;
-
-	spin_lock_init(&pwrkey->lock);
-
-	err = input_register_device(pwr);
-	if (err) {
-		dev_dbg(&pdev->dev, "Can't register power key: %d\n", err);
-		goto free_input_dev;
-	}
-
-	pwrkey->key_press_irq = key_press_irq;
-	pwrkey->key_release_irq = key_release_irq;
-	pwrkey->pwr = pwr;
-
-	platform_set_drvdata(pdev, pwrkey);
-
-	/* Check if power-key is pressed at boot up */
-	err = pm8058_irq_get_rt_status(pwrkey->pm_chip, key_press_irq);
-	if (err < 0) {
-		dev_err(&pdev->dev, "Key-press status at boot failed rc=%d\n",
-									err);
-		goto unreg_input_dev;
-	}
-	if (err) {
-		if (!pwrkey->pdata->pwrkey_time_ms)
-			input_report_key(pwrkey->pwr, KEY_POWER, 1);
-		else
-			input_report_key(pwrkey->pwr, KEY_END, 1);
-		input_sync(pwrkey->pwr);
-		pwrkey->pressed_first = true;
-	}
-
-	err = request_threaded_irq(key_press_irq, NULL, pwrkey_press_irq,
-			 IRQF_TRIGGER_RISING, "pmic8058_pwrkey_press", pwrkey);
-	if (err < 0) {
-		dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
-				 key_press_irq, err);
-		goto unreg_input_dev;
-	}
-
-	err = request_threaded_irq(key_release_irq, NULL, pwrkey_release_irq,
-			 IRQF_TRIGGER_RISING, "pmic8058_pwrkey_release",
-				 pwrkey);
-	if (err < 0) {
-		dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
-				 key_release_irq, err);
-
-		goto free_press_irq;
-	}
-
-	device_init_wakeup(&pdev->dev, pdata->wakeup);
-
-	return 0;
-
-free_press_irq:
-	free_irq(key_press_irq, NULL);
-unreg_input_dev:
-	input_unregister_device(pwr);
-	pwr = NULL;
-free_input_dev:
-	input_free_device(pwr);
-free_pwrkey:
-	pm_runtime_set_suspended(&pdev->dev);
-	pm_runtime_disable(&pdev->dev);
-	kfree(pwrkey);
-	return err;
-}
-
-static int __devexit pmic8058_pwrkey_remove(struct platform_device *pdev)
-{
-	struct pmic8058_pwrkey *pwrkey = platform_get_drvdata(pdev);
-	int key_release_irq = platform_get_irq(pdev, 0);
-	int key_press_irq = platform_get_irq(pdev, 1);
-
-	pm_runtime_set_suspended(&pdev->dev);
-	pm_runtime_disable(&pdev->dev);
-	device_init_wakeup(&pdev->dev, 0);
-
-	free_irq(key_press_irq, pwrkey);
-	free_irq(key_release_irq, pwrkey);
-	input_unregister_device(pwrkey->pwr);
-	kfree(pwrkey);
-
-	return 0;
-}
-
-static struct platform_driver pmic8058_pwrkey_driver = {
-	.probe		= pmic8058_pwrkey_probe,
-	.remove		= __devexit_p(pmic8058_pwrkey_remove),
-	.driver		= {
-		.name	= "pm8058-pwrkey",
-		.owner	= THIS_MODULE,
-#ifdef CONFIG_PM
-		.pm	= &pm8058_pwr_key_pm_ops,
-#endif
-	},
-};
-
-static int __init pmic8058_pwrkey_init(void)
-{
-	return platform_driver_register(&pmic8058_pwrkey_driver);
-}
-module_init(pmic8058_pwrkey_init);
-
-static void __exit pmic8058_pwrkey_exit(void)
-{
-	platform_driver_unregister(&pmic8058_pwrkey_driver);
-}
-module_exit(pmic8058_pwrkey_exit);
-
-MODULE_ALIAS("platform:pmic8058_pwrkey");
-MODULE_DESCRIPTION("PMIC8058 Power Key");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/atmel_maxtouch.c b/drivers/input/touchscreen/atmel_maxtouch.c
index e397774..cc18bc7 100644
--- a/drivers/input/touchscreen/atmel_maxtouch.c
+++ b/drivers/input/touchscreen/atmel_maxtouch.c
@@ -1832,16 +1832,14 @@
 	if (error < 0)
 		goto err_write_block;
 
-	enable_irq(mxt->irq);
+	/* Make sure we just didn't miss a interrupt. */
+	if (mxt->read_chg() == 0)
+		schedule_delayed_work(&mxt->dwork, 0);
+	else
+		enable_irq(mxt->irq);
 
 	mxt->is_suspended = false;
 
-	/* Make sure we just didn't miss a interrupt. */
-	if (mxt->read_chg() == 0) {
-		disable_irq(mxt->irq);
-		schedule_delayed_work(&mxt->dwork, 0);
-	}
-
 	return 0;
 
 err_write_block:
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 790a9e1..5b594bc 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -21,6 +21,7 @@
 #include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
+#include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
 
 #if defined(CONFIG_HAS_EARLYSUSPEND)
@@ -31,6 +32,7 @@
 
 /* Family ID */
 #define MXT224_ID	0x80
+#define MXT224E_ID	0x81
 #define MXT1386_ID	0xA0
 
 /* Version */
@@ -60,41 +62,47 @@
 #define MXT_OBJECT_SIZE		6
 
 /* Object types */
-#define MXT_DEBUG_DIAGNOSTIC	37
-#define MXT_GEN_MESSAGE		5
-#define MXT_GEN_COMMAND		6
-#define MXT_GEN_POWER		7
-#define MXT_GEN_ACQUIRE		8
-#define MXT_TOUCH_MULTI		9
-#define MXT_TOUCH_KEYARRAY	15
-#define MXT_TOUCH_PROXIMITY	23
-#define MXT_PROCI_GRIPFACE	20
-#define MXT_PROCG_NOISE		22
-#define MXT_PROCI_ONETOUCH	24
-#define MXT_PROCI_TWOTOUCH	27
-#define MXT_PROCI_GRIP		40
-#define MXT_PROCI_PALM		41
-#define MXT_SPT_COMMSCONFIG	18
-#define MXT_SPT_GPIOPWM		19
-#define MXT_SPT_SELFTEST	25
-#define MXT_SPT_CTECONFIG	28
-#define MXT_SPT_USERDATA	38
-#define MXT_SPT_DIGITIZER	43
-#define MXT_SPT_MESSAGECOUNT	44
+#define MXT_DEBUG_DIAGNOSTIC_T37	37
+#define MXT_GEN_MESSAGE_T5		5
+#define MXT_GEN_COMMAND_T6		6
+#define MXT_GEN_POWER_T7		7
+#define MXT_GEN_ACQUIRE_T8		8
+#define MXT_GEN_DATASOURCE_T53		53
+#define MXT_TOUCH_MULTI_T9		9
+#define MXT_TOUCH_KEYARRAY_T15		15
+#define MXT_TOUCH_PROXIMITY_T23		23
+#define MXT_TOUCH_PROXKEY_T52		52
+#define MXT_PROCI_GRIPFACE_T20		20
+#define MXT_PROCG_NOISE_T22		22
+#define MXT_PROCI_ONETOUCH_T24		24
+#define MXT_PROCI_TWOTOUCH_T27		27
+#define MXT_PROCI_GRIP_T40		40
+#define MXT_PROCI_PALM_T41		41
+#define MXT_PROCI_TOUCHSUPPRESSION_T42	42
+#define MXT_PROCI_STYLUS_T47		47
+#define MXT_PROCG_NOISESUPPRESSION_T48	48
+#define MXT_SPT_COMMSCONFIG_T18		18
+#define MXT_SPT_GPIOPWM_T19		19
+#define MXT_SPT_SELFTEST_T25		25
+#define MXT_SPT_CTECONFIG_T28		28
+#define MXT_SPT_USERDATA_T38		38
+#define MXT_SPT_DIGITIZER_T43		43
+#define MXT_SPT_MESSAGECOUNT_T44	44
+#define MXT_SPT_CTECONFIG_T46		46
 
-/* MXT_GEN_COMMAND field */
+/* MXT_GEN_COMMAND_T6 field */
 #define MXT_COMMAND_RESET	0
 #define MXT_COMMAND_BACKUPNV	1
 #define MXT_COMMAND_CALIBRATE	2
 #define MXT_COMMAND_REPORTALL	3
 #define MXT_COMMAND_DIAGNOSTIC	5
 
-/* MXT_GEN_POWER field */
+/* MXT_GEN_POWER_T7 field */
 #define MXT_POWER_IDLEACQINT	0
 #define MXT_POWER_ACTVACQINT	1
 #define MXT_POWER_ACTV2IDLETO	2
 
-/* MXT_GEN_ACQUIRE field */
+/* MXT_GEN_ACQUIRE_T8 field */
 #define MXT_ACQUIRE_CHRGTIME	0
 #define MXT_ACQUIRE_TCHDRIFT	2
 #define MXT_ACQUIRE_DRIFTST	3
@@ -103,7 +111,7 @@
 #define MXT_ACQUIRE_ATCHCALST	6
 #define MXT_ACQUIRE_ATCHCALSTHR	7
 
-/* MXT_TOUCH_MULTI field */
+/* MXT_TOUCH_MULT_T9 field */
 #define MXT_TOUCH_CTRL		0
 #define MXT_TOUCH_XORIGIN	1
 #define MXT_TOUCH_YORIGIN	2
@@ -133,7 +141,7 @@
 #define MXT_TOUCH_YEDGEDIST	29
 #define MXT_TOUCH_JUMPLIMIT	30
 
-/* MXT_PROCI_GRIPFACE field */
+/* MXT_PROCI_GRIPFACE_T20 field */
 #define MXT_GRIPFACE_CTRL	0
 #define MXT_GRIPFACE_XLOGRIP	1
 #define MXT_GRIPFACE_XHIGRIP	2
@@ -163,11 +171,11 @@
 #define MXT_NOISE_FREQ4		15
 #define MXT_NOISE_IDLEGCAFVALID	16
 
-/* MXT_SPT_COMMSCONFIG */
+/* MXT_SPT_COMMSCONFIG_T18 */
 #define MXT_COMMS_CTRL		0
 #define MXT_COMMS_CMD		1
 
-/* MXT_SPT_CTECONFIG field */
+/* MXT_SPT_CTECONFIG_T28 field */
 #define MXT_CTE_CTRL		0
 #define MXT_CTE_CMD		1
 #define MXT_CTE_MODE		2
@@ -178,21 +186,28 @@
 #define MXT_VOLTAGE_DEFAULT	2700000
 #define MXT_VOLTAGE_STEP	10000
 
+/* Analog voltage @2.7 V */
 #define MXT_VTG_MIN_UV		2700000
 #define MXT_VTG_MAX_UV		3300000
 #define MXT_ACTIVE_LOAD_UA	15000
 #define MXT_LPM_LOAD_UA		10
+/* Digital voltage @1.8 V */
+#define MXT_VTG_DIG_MIN_UV	1800000
+#define MXT_VTG_DIG_MAX_UV	1800000
+#define MXT_ACTIVE_LOAD_DIG_UA	10000
+#define MXT_LPM_LOAD_DIG_UA	10
 
 #define MXT_I2C_VTG_MIN_UV	1800000
 #define MXT_I2C_VTG_MAX_UV	1800000
 #define MXT_I2C_LOAD_UA		10000
 #define MXT_I2C_LPM_LOAD_UA	10
 
-/* Define for MXT_GEN_COMMAND */
+/* Define for MXT_GEN_COMMAND_T6 */
 #define MXT_BOOT_VALUE		0xa5
 #define MXT_BACKUP_VALUE	0x55
 #define MXT_BACKUP_TIME		25	/* msec */
 #define MXT224_RESET_TIME		65	/* msec */
+#define MXT224E_RESET_TIME		22	/* msec */
 #define MXT1386_RESET_TIME		250	/* msec */
 #define MXT_RESET_TIME		250	/* msec */
 #define MXT_RESET_NOCHGREAD		400	/* msec */
@@ -269,6 +284,7 @@
 	int x;
 	int y;
 	int area;
+	int pressure;
 };
 
 /* Each client has this additional data */
@@ -280,7 +296,8 @@
 	struct mxt_info info;
 	struct mxt_finger finger[MXT_MAX_FINGER];
 	unsigned int irq;
-	struct regulator *vcc;
+	struct regulator *vcc_ana;
+	struct regulator *vcc_dig;
 	struct regulator *vcc_i2c;
 #if defined(CONFIG_HAS_EARLYSUSPEND)
 	struct early_suspend early_suspend;
@@ -294,25 +311,31 @@
 static bool mxt_object_readable(unsigned int type)
 {
 	switch (type) {
-	case MXT_GEN_MESSAGE:
-	case MXT_GEN_COMMAND:
-	case MXT_GEN_POWER:
-	case MXT_GEN_ACQUIRE:
-	case MXT_TOUCH_MULTI:
-	case MXT_TOUCH_KEYARRAY:
-	case MXT_TOUCH_PROXIMITY:
-	case MXT_PROCI_GRIPFACE:
-	case MXT_PROCG_NOISE:
-	case MXT_PROCI_ONETOUCH:
-	case MXT_PROCI_TWOTOUCH:
-	case MXT_PROCI_GRIP:
-	case MXT_PROCI_PALM:
-	case MXT_SPT_COMMSCONFIG:
-	case MXT_SPT_GPIOPWM:
-	case MXT_SPT_SELFTEST:
-	case MXT_SPT_CTECONFIG:
-	case MXT_SPT_USERDATA:
-	case MXT_SPT_DIGITIZER:
+	case MXT_GEN_MESSAGE_T5:
+	case MXT_GEN_COMMAND_T6:
+	case MXT_GEN_POWER_T7:
+	case MXT_GEN_ACQUIRE_T8:
+	case MXT_GEN_DATASOURCE_T53:
+	case MXT_TOUCH_MULTI_T9:
+	case MXT_TOUCH_KEYARRAY_T15:
+	case MXT_TOUCH_PROXIMITY_T23:
+	case MXT_TOUCH_PROXKEY_T52:
+	case MXT_PROCI_GRIPFACE_T20:
+	case MXT_PROCG_NOISE_T22:
+	case MXT_PROCI_ONETOUCH_T24:
+	case MXT_PROCI_TWOTOUCH_T27:
+	case MXT_PROCI_GRIP_T40:
+	case MXT_PROCI_PALM_T41:
+	case MXT_PROCI_TOUCHSUPPRESSION_T42:
+	case MXT_PROCI_STYLUS_T47:
+	case MXT_PROCG_NOISESUPPRESSION_T48:
+	case MXT_SPT_COMMSCONFIG_T18:
+	case MXT_SPT_GPIOPWM_T19:
+	case MXT_SPT_SELFTEST_T25:
+	case MXT_SPT_CTECONFIG_T28:
+	case MXT_SPT_USERDATA_T38:
+	case MXT_SPT_DIGITIZER_T43:
+	case MXT_SPT_CTECONFIG_T46:
 		return true;
 	default:
 		return false;
@@ -322,23 +345,29 @@
 static bool mxt_object_writable(unsigned int type)
 {
 	switch (type) {
-	case MXT_GEN_COMMAND:
-	case MXT_GEN_POWER:
-	case MXT_GEN_ACQUIRE:
-	case MXT_TOUCH_MULTI:
-	case MXT_TOUCH_KEYARRAY:
-	case MXT_TOUCH_PROXIMITY:
-	case MXT_PROCI_GRIPFACE:
-	case MXT_PROCG_NOISE:
-	case MXT_PROCI_ONETOUCH:
-	case MXT_PROCI_TWOTOUCH:
-	case MXT_PROCI_GRIP:
-	case MXT_PROCI_PALM:
-	case MXT_SPT_GPIOPWM:
-	case MXT_SPT_SELFTEST:
-	case MXT_SPT_CTECONFIG:
-	case MXT_SPT_USERDATA:
-	case MXT_SPT_DIGITIZER:
+	case MXT_GEN_COMMAND_T6:
+	case MXT_GEN_POWER_T7:
+	case MXT_GEN_ACQUIRE_T8:
+	case MXT_TOUCH_MULTI_T9:
+	case MXT_TOUCH_KEYARRAY_T15:
+	case MXT_TOUCH_PROXIMITY_T23:
+	case MXT_TOUCH_PROXKEY_T52:
+	case MXT_PROCI_GRIPFACE_T20:
+	case MXT_PROCG_NOISE_T22:
+	case MXT_PROCI_ONETOUCH_T24:
+	case MXT_PROCI_TWOTOUCH_T27:
+	case MXT_PROCI_GRIP_T40:
+	case MXT_PROCI_PALM_T41:
+	case MXT_PROCI_TOUCHSUPPRESSION_T42:
+	case MXT_PROCI_STYLUS_T47:
+	case MXT_PROCG_NOISESUPPRESSION_T48:
+	case MXT_SPT_COMMSCONFIG_T18:
+	case MXT_SPT_GPIOPWM_T19:
+	case MXT_SPT_SELFTEST_T25:
+	case MXT_SPT_CTECONFIG_T28:
+	case MXT_SPT_USERDATA_T38:
+	case MXT_SPT_DIGITIZER_T43:
+	case MXT_SPT_CTECONFIG_T46:
 		return true;
 	default:
 		return false;
@@ -512,7 +541,7 @@
 	struct mxt_object *object;
 	u16 reg;
 
-	object = mxt_get_object(data, MXT_GEN_MESSAGE);
+	object = mxt_get_object(data, MXT_GEN_MESSAGE_T5);
 	if (!object)
 		return -EINVAL;
 
@@ -568,6 +597,8 @@
 				finger[id].x);
 		input_report_abs(input_dev, ABS_MT_POSITION_Y,
 				finger[id].y);
+		input_report_abs(input_dev, ABS_MT_PRESSURE,
+					finger[id].pressure);
 		input_mt_sync(input_dev);
 
 		if (finger[id].status == MXT_RELEASE)
@@ -581,6 +612,8 @@
 	if (status != MXT_RELEASE) {
 		input_report_abs(input_dev, ABS_X, finger[single_id].x);
 		input_report_abs(input_dev, ABS_Y, finger[single_id].y);
+		input_report_abs(input_dev,
+			ABS_PRESSURE, finger[single_id].pressure);
 	}
 
 	input_sync(input_dev);
@@ -595,6 +628,7 @@
 	int x;
 	int y;
 	int area;
+	int pressure;
 
 	/* Check the touch is present on the screen */
 	if (!(status & MXT_DETECT)) {
@@ -619,6 +653,7 @@
 		y = y >> 2;
 
 	area = message->message[4];
+	pressure = message->message[5];
 
 	dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id,
 		status & MXT_MOVE ? "moved" : "pressed",
@@ -629,6 +664,7 @@
 	finger[id].x = x;
 	finger[id].y = y;
 	finger[id].area = area;
+	finger[id].pressure = pressure;
 
 	mxt_input_report(data, id);
 }
@@ -649,14 +685,12 @@
 			dev_err(dev, "Failed to read message\n");
 			goto end;
 		}
-
 		reportid = message.reportid;
 
-		/* whether reportid is thing of MXT_TOUCH_MULTI */
-		object = mxt_get_object(data, MXT_TOUCH_MULTI);
+		/* whether reportid is thing of MXT_TOUCH_MULTI_T9 */
+		object = mxt_get_object(data, MXT_TOUCH_MULTI_T9);
 		if (!object)
 			goto end;
-
 		max_reportid = object->max_reportid;
 		min_reportid = max_reportid - object->num_report_ids + 1;
 		id = reportid - min_reportid;
@@ -802,6 +836,9 @@
 	case MXT224_ID:
 		msleep(MXT224_RESET_TIME);
 		break;
+	case MXT224E_ID:
+		msleep(MXT224E_RESET_TIME);
+		break;
 	case MXT1386_ID:
 		msleep(MXT1386_RESET_TIME);
 		break;
@@ -843,7 +880,7 @@
 		goto free_object_table;
 
 	/* Store T7 and T9 locally, used in suspend/resume operations */
-	t7_object = mxt_get_object(data, MXT_GEN_POWER);
+	t7_object = mxt_get_object(data, MXT_GEN_POWER_T7);
 	if (!t7_object) {
 		dev_err(&client->dev, "Failed to get T7 object\n");
 		error = -EINVAL;
@@ -858,7 +895,7 @@
 			"Failed to save current power state\n");
 		goto free_object_table;
 	}
-	error = mxt_read_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_CTRL,
+	error = mxt_read_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL,
 			&data->t9_ctrl);
 	if (error < 0) {
 		dev_err(&client->dev, "Failed to save current touch object\n");
@@ -866,12 +903,12 @@
 	}
 
 	/* Backup to memory */
-	mxt_write_object(data, MXT_GEN_COMMAND,
+	mxt_write_object(data, MXT_GEN_COMMAND_T6,
 			MXT_COMMAND_BACKUPNV,
 			MXT_BACKUP_VALUE);
 	msleep(MXT_BACKUP_TIME);
 	do {
-		error =  mxt_read_object(data, MXT_GEN_COMMAND,
+		error =  mxt_read_object(data, MXT_GEN_COMMAND_T6,
 					MXT_COMMAND_BACKUPNV,
 					&command_register);
 		if (error)
@@ -886,7 +923,7 @@
 
 
 	/* Soft reset */
-	mxt_write_object(data, MXT_GEN_COMMAND,
+	mxt_write_object(data, MXT_GEN_COMMAND_T6,
 			MXT_COMMAND_RESET, 1);
 
 	mxt_reset_delay(data);
@@ -982,7 +1019,7 @@
 	}
 
 	/* Change to the bootloader mode */
-	mxt_write_object(data, MXT_GEN_COMMAND,
+	mxt_write_object(data, MXT_GEN_COMMAND_T6,
 			MXT_COMMAND_RESET, MXT_BOOT_VALUE);
 
 	mxt_reset_delay(data);
@@ -1099,7 +1136,7 @@
 	}
 
 	error = mxt_write_object(data,
-			MXT_TOUCH_MULTI, MXT_TOUCH_CTRL, data->t9_ctrl);
+			MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, data->t9_ctrl);
 	if (error < 0) {
 		dev_err(&data->client->dev, "failed to restore touch\n");
 		return error;
@@ -1114,7 +1151,7 @@
 	u8 t7_data[T7_DATA_SIZE] = {0};
 
 	/* disable touch and configure deep sleep mode */
-	error = mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_CTRL, 0);
+	error = mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, 0);
 	if (error < 0) {
 		dev_err(&data->client->dev, "failed to disable touch\n");
 		return error;
@@ -1163,32 +1200,50 @@
 	if (on == false)
 		goto power_off;
 
-	rc = regulator_set_optimum_mode(data->vcc, MXT_ACTIVE_LOAD_UA);
+	rc = regulator_set_optimum_mode(data->vcc_ana, MXT_ACTIVE_LOAD_UA);
 	if (rc < 0) {
-		dev_err(&data->client->dev, "Regulator set_opt failed rc=%d\n",
-									rc);
+		dev_err(&data->client->dev,
+			"Regulator vcc_ana set_opt failed rc=%d\n", rc);
 		return rc;
 	}
 
-	rc = regulator_enable(data->vcc);
+	rc = regulator_enable(data->vcc_ana);
 	if (rc) {
-		dev_err(&data->client->dev, "Regulator enable failed rc=%d\n",
-									rc);
-		goto error_reg_en_vcc;
+		dev_err(&data->client->dev,
+			"Regulator vcc_ana enable failed rc=%d\n", rc);
+		goto error_reg_en_vcc_ana;
+	}
+
+	if (data->pdata->digital_pwr_regulator) {
+		rc = regulator_set_optimum_mode(data->vcc_dig,
+						MXT_ACTIVE_LOAD_DIG_UA);
+		if (rc < 0) {
+			dev_err(&data->client->dev,
+				"Regulator vcc_dig set_opt failed rc=%d\n",
+				rc);
+			goto error_reg_opt_vcc_dig;
+		}
+
+		rc = regulator_enable(data->vcc_dig);
+		if (rc) {
+			dev_err(&data->client->dev,
+				"Regulator vcc_dig enable failed rc=%d\n", rc);
+			goto error_reg_en_vcc_dig;
+		}
 	}
 
 	if (data->pdata->i2c_pull_up) {
 		rc = regulator_set_optimum_mode(data->vcc_i2c, MXT_I2C_LOAD_UA);
 		if (rc < 0) {
 			dev_err(&data->client->dev,
-				"Regulator set_opt failed rc=%d\n", rc);
+				"Regulator vcc_i2c set_opt failed rc=%d\n", rc);
 			goto error_reg_opt_i2c;
 		}
 
 		rc = regulator_enable(data->vcc_i2c);
 		if (rc) {
 			dev_err(&data->client->dev,
-				"Regulator enable failed rc=%d\n", rc);
+				"Regulator vcc_i2c enable failed rc=%d\n", rc);
 			goto error_reg_en_vcc_i2c;
 		}
 	}
@@ -1201,14 +1256,24 @@
 	if (data->pdata->i2c_pull_up)
 		regulator_set_optimum_mode(data->vcc_i2c, 0);
 error_reg_opt_i2c:
-	regulator_disable(data->vcc);
-error_reg_en_vcc:
-	regulator_set_optimum_mode(data->vcc, 0);
+	if (data->pdata->digital_pwr_regulator)
+		regulator_disable(data->vcc_dig);
+error_reg_en_vcc_dig:
+	if (data->pdata->digital_pwr_regulator)
+		regulator_set_optimum_mode(data->vcc_dig, 0);
+error_reg_opt_vcc_dig:
+	regulator_disable(data->vcc_ana);
+error_reg_en_vcc_ana:
+	regulator_set_optimum_mode(data->vcc_ana, 0);
 	return rc;
 
 power_off:
-	regulator_set_optimum_mode(data->vcc, 0);
-	regulator_disable(data->vcc);
+	regulator_set_optimum_mode(data->vcc_ana, 0);
+	regulator_disable(data->vcc_ana);
+	if (data->pdata->digital_pwr_regulator) {
+		regulator_set_optimum_mode(data->vcc_dig, 0);
+		regulator_disable(data->vcc_dig);
+	}
 	if (data->pdata->i2c_pull_up) {
 		regulator_set_optimum_mode(data->vcc_i2c, 0);
 		regulator_disable(data->vcc_i2c);
@@ -1224,24 +1289,42 @@
 	if (on == false)
 		goto hw_shutdown;
 
-	data->vcc = regulator_get(&data->client->dev, "vdd");
-	if (IS_ERR(data->vcc)) {
-		rc = PTR_ERR(data->vcc);
-		dev_err(&data->client->dev, "Regulator get failed rc=%d\n",
-									rc);
+	data->vcc_ana = regulator_get(&data->client->dev, "vdd_ana");
+	if (IS_ERR(data->vcc_ana)) {
+		rc = PTR_ERR(data->vcc_ana);
+		dev_err(&data->client->dev,
+			"Regulator get failed vcc_ana rc=%d\n", rc);
 		return rc;
 	}
 
-	if (regulator_count_voltages(data->vcc) > 0) {
-		rc = regulator_set_voltage(data->vcc, MXT_VTG_MIN_UV,
+	if (regulator_count_voltages(data->vcc_ana) > 0) {
+		rc = regulator_set_voltage(data->vcc_ana, MXT_VTG_MIN_UV,
 							MXT_VTG_MAX_UV);
 		if (rc) {
 			dev_err(&data->client->dev,
 				"regulator set_vtg failed rc=%d\n", rc);
-			goto error_set_vtg_vcc;
+			goto error_set_vtg_vcc_ana;
 		}
 	}
+	if (data->pdata->digital_pwr_regulator) {
+		data->vcc_dig = regulator_get(&data->client->dev, "vdd_dig");
+		if (IS_ERR(data->vcc_dig)) {
+			rc = PTR_ERR(data->vcc_dig);
+			dev_err(&data->client->dev,
+				"Regulator get dig failed rc=%d\n", rc);
+			goto error_get_vtg_vcc_dig;
+		}
 
+		if (regulator_count_voltages(data->vcc_dig) > 0) {
+			rc = regulator_set_voltage(data->vcc_dig,
+				MXT_VTG_DIG_MIN_UV, MXT_VTG_DIG_MAX_UV);
+			if (rc) {
+				dev_err(&data->client->dev,
+					"regulator set_vtg failed rc=%d\n", rc);
+				goto error_set_vtg_vcc_dig;
+			}
+		}
+	}
 	if (data->pdata->i2c_pull_up) {
 		data->vcc_i2c = regulator_get(&data->client->dev, "vcc_i2c");
 		if (IS_ERR(data->vcc_i2c)) {
@@ -1266,16 +1349,30 @@
 error_set_vtg_i2c:
 	regulator_put(data->vcc_i2c);
 error_get_vtg_i2c:
-	if (regulator_count_voltages(data->vcc) > 0)
-		regulator_set_voltage(data->vcc, 0, MXT_VTG_MAX_UV);
-error_set_vtg_vcc:
-	regulator_put(data->vcc);
+	if (data->pdata->digital_pwr_regulator)
+		if (regulator_count_voltages(data->vcc_dig) > 0)
+			regulator_set_voltage(data->vcc_dig, 0,
+				MXT_VTG_DIG_MAX_UV);
+error_set_vtg_vcc_dig:
+	if (data->pdata->digital_pwr_regulator)
+		regulator_put(data->vcc_dig);
+error_get_vtg_vcc_dig:
+	if (regulator_count_voltages(data->vcc_ana) > 0)
+		regulator_set_voltage(data->vcc_ana, 0, MXT_VTG_MAX_UV);
+error_set_vtg_vcc_ana:
+	regulator_put(data->vcc_ana);
 	return rc;
 
 hw_shutdown:
-	if (regulator_count_voltages(data->vcc) > 0)
-		regulator_set_voltage(data->vcc, 0, MXT_VTG_MAX_UV);
-	regulator_put(data->vcc);
+	if (regulator_count_voltages(data->vcc_ana) > 0)
+		regulator_set_voltage(data->vcc_ana, 0, MXT_VTG_MAX_UV);
+	regulator_put(data->vcc_ana);
+	if (data->pdata->digital_pwr_regulator) {
+		if (regulator_count_voltages(data->vcc_dig) > 0)
+			regulator_set_voltage(data->vcc_dig, 0,
+						MXT_VTG_DIG_MAX_UV);
+		regulator_put(data->vcc_dig);
+	}
 	if (data->pdata->i2c_pull_up) {
 		if (regulator_count_voltages(data->vcc_i2c) > 0)
 			regulator_set_voltage(data->vcc_i2c, 0,
@@ -1294,19 +1391,29 @@
 	if (on == false)
 		goto regulator_hpm;
 
-	rc = regulator_set_optimum_mode(data->vcc, MXT_LPM_LOAD_UA);
+	rc = regulator_set_optimum_mode(data->vcc_ana, MXT_LPM_LOAD_UA);
 	if (rc < 0) {
 		dev_err(&data->client->dev,
-			"Regulator set_opt failed rc=%d\n", rc);
+			"Regulator vcc_ana set_opt failed rc=%d\n", rc);
 		goto fail_regulator_lpm;
 	}
 
+	if (data->pdata->digital_pwr_regulator) {
+		rc = regulator_set_optimum_mode(data->vcc_dig,
+						MXT_LPM_LOAD_DIG_UA);
+		if (rc < 0) {
+			dev_err(&data->client->dev,
+				"Regulator vcc_dig set_opt failed rc=%d\n", rc);
+			goto fail_regulator_lpm;
+		}
+	}
+
 	if (data->pdata->i2c_pull_up) {
 		rc = regulator_set_optimum_mode(data->vcc_i2c,
 						MXT_I2C_LPM_LOAD_UA);
 		if (rc < 0) {
 			dev_err(&data->client->dev,
-				"Regulator set_opt failed rc=%d\n", rc);
+				"Regulator vcc_i2c set_opt failed rc=%d\n", rc);
 			goto fail_regulator_lpm;
 		}
 	}
@@ -1315,18 +1422,28 @@
 
 regulator_hpm:
 
-	rc = regulator_set_optimum_mode(data->vcc, MXT_ACTIVE_LOAD_UA);
+	rc = regulator_set_optimum_mode(data->vcc_ana, MXT_ACTIVE_LOAD_UA);
 	if (rc < 0) {
 		dev_err(&data->client->dev,
-			"Regulator set_opt failed rc=%d\n", rc);
+			"Regulator vcc_ana set_opt failed rc=%d\n", rc);
 		goto fail_regulator_hpm;
 	}
 
+	if (data->pdata->digital_pwr_regulator) {
+		rc = regulator_set_optimum_mode(data->vcc_dig,
+						 MXT_ACTIVE_LOAD_DIG_UA);
+		if (rc < 0) {
+			dev_err(&data->client->dev,
+				"Regulator vcc_dig set_opt failed rc=%d\n", rc);
+			goto fail_regulator_hpm;
+		}
+	}
+
 	if (data->pdata->i2c_pull_up) {
 		rc = regulator_set_optimum_mode(data->vcc_i2c, MXT_I2C_LOAD_UA);
 		if (rc < 0) {
 			dev_err(&data->client->dev,
-				"Regulator set_opt failed rc=%d\n", rc);
+				"Regulator vcc_i2c set_opt failed rc=%d\n", rc);
 			goto fail_regulator_hpm;
 		}
 	}
@@ -1334,14 +1451,19 @@
 	return 0;
 
 fail_regulator_lpm:
-	regulator_set_optimum_mode(data->vcc, MXT_ACTIVE_LOAD_UA);
+	regulator_set_optimum_mode(data->vcc_ana, MXT_ACTIVE_LOAD_UA);
+	if (data->pdata->digital_pwr_regulator)
+		regulator_set_optimum_mode(data->vcc_dig,
+						MXT_ACTIVE_LOAD_DIG_UA);
 	if (data->pdata->i2c_pull_up)
 		regulator_set_optimum_mode(data->vcc_i2c, MXT_I2C_LOAD_UA);
 
 	return rc;
 
 fail_regulator_hpm:
-	regulator_set_optimum_mode(data->vcc, MXT_LPM_LOAD_UA);
+	regulator_set_optimum_mode(data->vcc_ana, MXT_LPM_LOAD_UA);
+	if (data->pdata->digital_pwr_regulator)
+		regulator_set_optimum_mode(data->vcc_dig, MXT_LPM_LOAD_DIG_UA);
 	if (data->pdata->i2c_pull_up)
 		regulator_set_optimum_mode(data->vcc_i2c, MXT_I2C_LPM_LOAD_UA);
 
@@ -1472,6 +1594,8 @@
 			     0, data->pdata->x_size, 0, 0);
 	input_set_abs_params(input_dev, ABS_Y,
 			     0, data->pdata->y_size, 0, 0);
+	input_set_abs_params(input_dev, ABS_PRESSURE,
+			     0, 255, 0, 0);
 
 	/* For multi touch */
 	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
@@ -1480,6 +1604,8 @@
 			     0, data->pdata->x_size, 0, 0);
 	input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
 			     0, data->pdata->y_size, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_PRESSURE,
+			     0, 255, 0, 0);
 
 	input_set_drvdata(input_dev, data);
 	i2c_set_clientdata(client, data);
@@ -1502,9 +1628,47 @@
 		goto err_regulator_on;
 	}
 
+	if (gpio_is_valid(pdata->irq_gpio)) {
+		/* configure touchscreen irq gpio */
+		error = gpio_request(pdata->irq_gpio,
+							"mxt_irq_gpio");
+		if (error) {
+			pr_err("%s: unable to request gpio [%d]\n", __func__,
+						pdata->irq_gpio);
+			goto err_power_on;
+		}
+		error = gpio_direction_input(pdata->irq_gpio);
+		if (error) {
+			pr_err("%s: unable to set_direction for gpio [%d]\n",
+					__func__, pdata->irq_gpio);
+			goto err_irq_gpio_req;
+		}
+	}
+
+	if (gpio_is_valid(pdata->reset_gpio)) {
+		/* configure touchscreen reset out gpio */
+		error = gpio_request(pdata->reset_gpio,
+						"mxt_reset_gpio");
+		if (error) {
+			pr_err("%s: unable to request reset gpio %d\n",
+				__func__, pdata->reset_gpio);
+			goto err_irq_gpio_req;
+		}
+
+		error = gpio_direction_output(
+					pdata->reset_gpio, 1);
+		if (error) {
+			pr_err("%s: unable to set direction for gpio %d\n",
+				__func__, pdata->reset_gpio);
+			goto err_reset_gpio_req;
+		}
+	}
+
+	mxt_reset_delay(data);
+
 	error = mxt_initialize(data);
 	if (error)
-		goto err_power_on;
+		goto err_reset_gpio_req;
 
 	error = request_threaded_irq(client->irq, NULL, mxt_interrupt,
 			pdata->irqflags, client->dev.driver->name, data);
@@ -1542,6 +1706,12 @@
 	free_irq(client->irq, data);
 err_free_object:
 	kfree(data->object_table);
+err_reset_gpio_req:
+	if (gpio_is_valid(pdata->reset_gpio))
+		gpio_free(pdata->reset_gpio);
+err_irq_gpio_req:
+	if (gpio_is_valid(pdata->irq_gpio))
+		gpio_free(pdata->irq_gpio);
 err_power_on:
 	if (pdata->power_on)
 		pdata->power_on(false);
diff --git a/drivers/input/touchscreen/cyttsp-i2c.c b/drivers/input/touchscreen/cyttsp-i2c.c
index 9df1189..bb02be6 100644
--- a/drivers/input/touchscreen/cyttsp-i2c.c
+++ b/drivers/input/touchscreen/cyttsp-i2c.c
@@ -1006,7 +1006,7 @@
 		/* wait for TTSP Device to complete reset back to bootloader */
 		tries = 0;
 		do {
-			mdelay(1);
+			usleep_range(1000, 1000);
 			cyttsp_putbl(ts, 1, false, false, false);
 		} while (g_bl_data.bl_status != 0x10 &&
 			g_bl_data.bl_status != 0x11 &&
@@ -1024,7 +1024,7 @@
 			 * switch to Operational mode */
 			tries = 0;
 			do {
-				mdelay(100);
+				msleep(100);
 				cyttsp_putbl(ts, 2, false, false, false);
 			} while (GET_BOOTLOADERMODE(g_bl_data.bl_status) &&
 				tries++ < 100);
@@ -2001,7 +2001,7 @@
 	/* wait for TTSP Device to complete reset back to bootloader */
 	tries = 0;
 	do {
-		mdelay(1);
+		usleep_range(1000, 1000);
 		cyttsp_putbl(ts, 3, false, false, false);
 	} while (g_bl_data.bl_status != 0x10 &&
 		g_bl_data.bl_status != 0x11 &&
@@ -2026,7 +2026,7 @@
 			i++;
 			tries = 0;
 			do {
-				mdelay(100);
+				msleep(100);
 				cyttsp_putbl(ts, 4, false, false, false);
 			} while (g_bl_data.bl_status != 0x10 &&
 				g_bl_data.bl_status != 0x11 &&
@@ -2059,7 +2059,7 @@
 							!((g_bl_data.bl_status == 0x11) &&
 							(g_bl_data.bl_error == 0x20)) &&
 							(tries++ < 100)) {
-							mdelay(1);
+							usleep_range(1000, 1000);
 							cyttsp_putbl(ts, 5, false, false, false);
 						}
 					}
@@ -2073,7 +2073,7 @@
 						i++;
 						tries = 0;
 						do {
-							mdelay(100);
+							msleep(100);
 							cyttsp_putbl(ts, 6, true, false, false);
 						} while (g_bl_data.bl_status != 0x10 &&
 							g_bl_data.bl_status != 0x11 &&
@@ -2098,7 +2098,7 @@
 	/* wait for TTSP Device to complete reset back to bootloader */
 	tries = 0;
 	do {
-		mdelay(1);
+		usleep_range(1000, 1000);
 		cyttsp_putbl(ts, 3, false, false, false);
 	} while (g_bl_data.bl_status != 0x10 &&
 		g_bl_data.bl_status != 0x11 &&
@@ -2132,7 +2132,7 @@
 		sizeof(host_reg), &host_reg);
 	tries = 0;
 	do {
-		mdelay(1);
+		usleep_range(1000, 1000);
 
 		/* set arg2 to non-0 to activate */
 		retval = cyttsp_putbl(ts, 1, true, true, true);
@@ -2170,7 +2170,7 @@
 					sizeof(host_reg), &host_reg);
 				/* wait for TTSP Device to complete switch to
 				 * Operational mode */
-				mdelay(1000);
+				msleep(1000);
 				goto bypass;
 			}
 		}
@@ -2249,7 +2249,7 @@
 				 * switch to Operational mode */
 				tries = 0;
 				do {
-					mdelay(100);
+					msleep(100);
 					cyttsp_putbl(ts, 9, false, false, false);
 				} while (GET_BOOTLOADERMODE(g_bl_data.bl_status) &&
 					tries++ < 100);
@@ -2267,7 +2267,7 @@
 		retval = i2c_smbus_write_i2c_block_data(ts->client,
 			CY_REG_BASE, sizeof(host_reg), &host_reg);
 		/* wait for TTSP Device to complete switch to SysInfo mode */
-		mdelay(100);
+		msleep(100);
 		if (!(retval < CY_OK)) {
 			retval = i2c_smbus_read_i2c_block_data(ts->client,
 				CY_REG_BASE,
@@ -2326,7 +2326,7 @@
 						ts->client,
 						CY_REG_ACT_INTRVL,
 						sizeof(intrvl_ray), intrvl_ray);
-					mdelay(CY_DLY_SYSINFO);
+					msleep(CY_DLY_SYSINFO);
 				}
 			}
 		}
@@ -2339,7 +2339,7 @@
 				sizeof(host_reg), &host_reg);
 			/* wait for TTSP Device to complete
 			 * switch to Operational mode */
-			mdelay(100);
+			msleep(100);
 		}
 	}
 	/* init gesture setup;
@@ -2352,7 +2352,7 @@
 		retval = i2c_smbus_write_i2c_block_data(ts->client,
 			CY_REG_GEST_SET,
 			sizeof(gesture_setup), &gesture_setup);
-		mdelay(CY_DLY_DFLT);
+		msleep(CY_DLY_DFLT);
 	}
 
 	if (!(retval < CY_OK))
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index fd5fcd2..59f915e 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -2961,8 +2961,9 @@
 		retval = hci_set_notch_filter(&temp_val, radio->fm_hdev);
 		break;
 	case V4L2_CID_PRIVATE_IRIS_SRCH_ALGORITHM:
+	case V4L2_CID_PRIVATE_IRIS_SET_AUDIO_PATH:
 		/*
-		This private control is a place holder to keep the
+		These private controls are place holders to keep the
 		driver compatible with changes done in the frameworks
 		which are specific to TAVARUA.
 		*/
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index b73775c..393e30e 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. 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 version 2 and
@@ -1416,93 +1416,49 @@
 	adie_type_bahma = is_bahama();
 
 	/* Set freq band */
-	switch (region) {
-	case TAVARUA_REGION_US:
-	case TAVARUA_REGION_EU:
+	if (region == TAVARUA_REGION_JAPAN)
+		SET_REG_FIELD(radio->registers[RDCTRL], 1,
+			RDCTRL_BAND_OFFSET, RDCTRL_BAND_MASK);
+	else
 		SET_REG_FIELD(radio->registers[RDCTRL], 0,
 			RDCTRL_BAND_OFFSET, RDCTRL_BAND_MASK);
-		break;
-	case TAVARUA_REGION_JAPAN_WIDE:
-	case TAVARUA_REGION_JAPAN:
-	default:
-		retval = sync_read_xfr(radio, RADIO_CONFIG, xfr_buf);
-		if (retval < 0) {
-			FMDERR("failed to get RADIO_CONFIG\n");
-			return retval;
-		}
-		band_low = (radio->region_params.band_low -
-					low_band_limit) / spacing;
-		band_high = (radio->region_params.band_high -
-					low_band_limit) / spacing;
-		FMDBG("low_band: %x, high_band: %x\n", band_low, band_high);
-		xfr_buf[0] = band_low >> 8;
-		xfr_buf[1] = band_low & 0xFF;
-		xfr_buf[2] = band_high >> 8;
-		xfr_buf[3] = band_high & 0xFF;
-		retval = sync_write_xfr(radio, RADIO_CONFIG, xfr_buf);
-		if (retval < 0) {
-			FMDERR("Could not set regional settings\n");
-			return retval;
-		}
-		break;
-	}
 
 	/* Set De-emphasis and soft band range*/
-	switch (region) {
-	case TAVARUA_REGION_US:
-	case TAVARUA_REGION_JAPAN:
-	case TAVARUA_REGION_JAPAN_WIDE:
-		value = EMP_75;
-		break;
-	case TAVARUA_REGION_EU:
-		value = EMP_50;
-		break;
-	default:
-		value = radio->region_params.emphasis;
-	}
-
-	SET_REG_FIELD(radio->registers[RDCTRL], value,
+	SET_REG_FIELD(radio->registers[RDCTRL], radio->region_params.emphasis,
 		RDCTRL_DEEMPHASIS_OFFSET, RDCTRL_DEEMPHASIS_MASK);
 
 	/* set RDS standard */
-	switch (region) {
-	default:
-		value = radio->region_params.rds_std;
-		break;
-	case TAVARUA_REGION_US:
-		value = RBDS_STD;
-		break;
-	case TAVARUA_REGION_EU:
-		value = RDS_STD;
-		break;
-	}
-	SET_REG_FIELD(radio->registers[RDSCTRL], value,
+	SET_REG_FIELD(radio->registers[RDSCTRL], radio->region_params.rds_std,
 		RDSCTRL_STANDARD_OFFSET, RDSCTRL_STANDARD_MASK);
 
 	FMDBG("RDSCTRLL %x\n", radio->registers[RDSCTRL]);
 	retval = tavarua_write_register(radio, RDSCTRL,
 					radio->registers[RDSCTRL]);
-	if (retval < 0)
+	if (retval < 0) {
+		FMDERR("Failed to set RDS/RBDS standard\n");
 		return retval;
+	}
 
+	/* Set the lower and upper band limits*/
+	retval = sync_read_xfr(radio, RADIO_CONFIG, xfr_buf);
+	if (retval < 0) {
+		FMDERR("failed to get RADIO_CONFIG\n");
+		return retval;
+	}
 
-	/* setting soft band */
-	switch (region) {
-	case TAVARUA_REGION_US:
-	case TAVARUA_REGION_EU:
-		radio->region_params.band_low = 87.5 * FREQ_MUL;
-		radio->region_params.band_high = 108 * FREQ_MUL;
-		break;
-	case TAVARUA_REGION_JAPAN:
-		radio->region_params.band_low = 76 * FREQ_MUL;
-		radio->region_params.band_high = 90 * FREQ_MUL;
-		break;
-	case TAVARUA_REGION_JAPAN_WIDE:
-		radio->region_params.band_low = 90 * FREQ_MUL;
-		radio->region_params.band_high = 108 * FREQ_MUL;
-		break;
-	default:
-		break;
+	band_low = (radio->region_params.band_low -
+				low_band_limit) / spacing;
+	band_high = (radio->region_params.band_high -
+				low_band_limit) / spacing;
+
+	xfr_buf[0] = RSH_DATA(band_low, 8);
+	xfr_buf[1] = GET_ABS_VAL(band_low);
+	xfr_buf[2] = RSH_DATA(band_high, 8);
+	xfr_buf[3] = GET_ABS_VAL(band_high);
+	retval = sync_write_xfr(radio, RADIO_CONFIG, xfr_buf);
+	if (retval < 0) {
+		FMDERR("Could not set regional settings\n");
+		return retval;
 	}
 	radio->region_params.region = region;
 
@@ -1555,8 +1511,7 @@
 		}
 
 		/* Set channel spacing */
-		switch (region) {
-		case TAVARUA_REGION_US:
+		if (region == TAVARUA_REGION_US) {
 			if (adie_type_bahma) {
 				FMDBG("Adie type : Bahama\n");
 				/*
@@ -1569,23 +1524,13 @@
 				FMDBG("Adie type : Marimba\n");
 				value = FM_CH_SPACE_200KHZ;
 			}
-			break;
-		case TAVARUA_REGION_JAPAN:
-			value = FM_CH_SPACE_100KHZ;
-			break;
-		case TAVARUA_REGION_EU:
-		case TAVARUA_REGION_JAPAN_WIDE:
-			value = FM_CH_SPACE_50KHZ;
-			break;
-		default:
+		} else {
 			/*
 			Set the channel spacing as configured from
 			the upper layers.
 			*/
 			value = radio->region_params.spacing;
-			break;
 		}
-
 		SET_REG_FIELD(radio->registers[RDCTRL], value,
 			RDCTRL_CHSPACE_OFFSET, RDCTRL_CHSPACE_MASK);
 
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 6f39576..5454763 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -5,6 +5,8 @@
 
 ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
   EXTRA_CFLAGS += -Idrivers/media/video/msm/csi
+  EXTRA_CFLAGS += -Idrivers/media/video/msm/io
+  EXTRA_CFLAGS += -Idrivers/media/video/msm/sensors
   obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o msm_mctl_pp.o
   obj-$(CONFIG_MSM_CAMERA) += io/ sensors/ actuators/ csi/
 else
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 579c4d5..8df6243 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -19,7 +19,7 @@
 #include <linux/spinlock.h>
 #include <linux/proc_fs.h>
 #include "msm.h"
-
+#include "msm_sensor.h"
 
 #define MSM_MAX_CAMERA_SENSORS 5
 
@@ -2294,10 +2294,11 @@
 {
 	int rc = -ENOMEM;
 	struct video_device *pvdev = NULL;
+	struct i2c_client *client = v4l2_get_subdevdata(pcam->mctl.sensor_sdev);
 	D("%s\n", __func__);
 
 	/* first register the v4l2 device */
-	pcam->v4l2_dev.dev = &pcam->pdev->dev;
+	pcam->v4l2_dev.dev = &client->dev;
 	rc = v4l2_device_register(pcam->v4l2_dev.dev, &pcam->v4l2_dev);
 	if (rc < 0)
 		return -EINVAL;
@@ -2314,11 +2315,11 @@
 
 	/* init video device's driver interface */
 	D("sensor name = %s, sizeof(pvdev->name)=%d\n",
-		pcam->pdev->name, sizeof(pvdev->name));
+		pcam->mctl.sensor_sdev->name, sizeof(pvdev->name));
 
 	/* device info - strlcpy is safer than strncpy but
 	   only if architecture supports*/
-	strlcpy(pvdev->name, pcam->pdev->name, sizeof(pvdev->name));
+	strlcpy(pvdev->name, pcam->mctl.sensor_sdev->name, sizeof(pvdev->name));
 
 	pvdev->release   = video_device_release;
 	pvdev->fops	  = &g_msm_fops;
@@ -2418,36 +2419,25 @@
 	struct platform_device *pdev)
 {
 	int rc = 0;
-
-	sync->sdata = pdev->dev.platform_data;
-
 	wake_lock_init(&sync->wake_lock, WAKE_LOCK_IDLE, "msm_camera");
-
-	sync->pdev = pdev;
 	sync->opencnt = 0;
-
 	mutex_init(&sync->lock);
-	D("%s: initialized %s\n", __func__, sync->sdata->sensor_name);
 	return rc;
 }
 
 /* register a msm sensor into the msm device, which will probe the
  * sensor HW. if the HW exist then create a video device (/dev/videoX/)
  * to represent this sensor */
-int msm_sensor_register(struct platform_device *pdev,
-		int (*sensor_probe)(const struct msm_camera_sensor_info *,
-			struct v4l2_subdev *, struct msm_sensor_ctrl *))
+int msm_sensor_register(struct v4l2_subdev *sensor_sd)
 {
-
 	int rc = -EINVAL;
-	struct msm_camera_sensor_info *sdata = pdev->dev.platform_data;
+	struct msm_camera_sensor_info *sdata;
 	struct msm_cam_v4l2_device *pcam;
-	struct v4l2_subdev *sdev = NULL;
-	struct msm_sensor_ctrl *sctrl = NULL;
+	struct msm_sensor_ctrl_t *s_ctrl;
 	struct v4l2_subdev *act_sdev = NULL;
 	struct msm_actuator_ctrl *actctrl = NULL;
 
-	D("%s for %s\n", __func__, pdev->name);
+	D("%s for %s\n", __func__, sensor_sd->name);
 
 	/* allocate the memory for the camera device first */
 	pcam = kzalloc(sizeof(*pcam), GFP_KERNEL);
@@ -2457,44 +2447,15 @@
 		return -ENOMEM;
 	}
 
-	pcam->mctl.sensor_sdev = kzalloc(sizeof(struct v4l2_subdev),
-					 GFP_KERNEL);
-	if (!pcam->mctl.sensor_sdev) {
-		pr_err("%s: could not allocate mem for sensor v4l2_subdev\n",
-			__func__);
-		kfree(pcam);
-		return -ENOMEM;
-	}
-
-	sdev = pcam->mctl.sensor_sdev;
-	snprintf(sdev->name, sizeof(sdev->name), "%s", pdev->name);
-	sctrl = &pcam->mctl.sync.sctrl;
-
-	/* come sensor probe logic */
-	rc = msm_camio_probe_on(pdev);
-	if (rc < 0) {
-		kzfree(pcam);
-		return rc;
-	}
-
-	rc = sensor_probe(sdata, sdev, sctrl);
-	if (rc < 0) {
-		pr_err("%s: failed to detect %s\n",
-			__func__,
-			sdata->sensor_name);
-		msm_camio_probe_off(pdev);
-		kzfree(sdev);
-		kzfree(pcam);
-		return rc;
-	}
+	pcam->mctl.sensor_sdev = sensor_sd;
+	s_ctrl = get_sctrl(sensor_sd);
+	sdata = (struct msm_camera_sensor_info *) s_ctrl->sensordata;
 
 	pcam->mctl.act_sdev = kzalloc(sizeof(struct v4l2_subdev),
-					 GFP_KERNEL);
+								  GFP_KERNEL);
 	if (!pcam->mctl.act_sdev) {
 		pr_err("%s: could not allocate mem for actuator v4l2_subdev\n",
-			__func__);
-		msm_camio_probe_off(pdev);
-		kzfree(sdev);
+			   __func__);
 		kfree(pcam);
 		return -ENOMEM;
 	}
@@ -2503,20 +2464,17 @@
 	actctrl = &pcam->mctl.sync.actctrl;
 
 	msm_actuator_probe(sdata->actuator_info,
-			act_sdev, actctrl);
-
-	msm_camio_probe_off(pdev);
+					   act_sdev, actctrl);
 
 	/* setup a manager object*/
-	rc = msm_sync_init(&pcam->mctl.sync, pdev);
+	rc = msm_sync_init(&pcam->mctl.sync, NULL);
 	if (rc < 0)
 		goto failure;
 	D("%s: pcam =0x%p\n", __func__, pcam);
 	D("%s: &pcam->mctl.sync =0x%p\n", __func__, &pcam->mctl.sync);
 
+	pcam->mctl.sync.sdata = sdata;
 	pcam->mctl.sync.pcam_sync = pcam;
-	/* bind the driver device to the sensor device */
-	pcam->pdev = pdev;
 
 	/* init the user count and lock*/
 	pcam->use_count = 0;
@@ -2527,7 +2485,6 @@
 	if (rc < 0)
 		goto failure;
 
-	/* now initialize the camera device object */
 	rc  = msm_cam_dev_init(pcam);
 	if (rc < 0)
 		goto failure;
@@ -2541,39 +2498,35 @@
 
 	g_server_dev.camera_info.s_mount_angle
 	[g_server_dev.camera_info.num_cameras]
-	= sctrl->s_mount_angle;
+	= sdata->sensor_platform_info->mount_angle;
 
 	g_server_dev.camera_info.is_internal_cam
 	[g_server_dev.camera_info.num_cameras]
-	= sctrl->s_camera_type;
+	= sdata->camera_type;
 
 	g_server_dev.camera_info.num_cameras++;
 
 	D("%s done, rc = %d\n", __func__, rc);
 	D("%s number of sensors connected is %d\n", __func__,
 			g_server_dev.camera_info.num_cameras);
-/*
-	if (g_server_dev.camera_info.num_cameras == 1) {
-		rc = add_axi_qos();
-		if (rc < 0)
-			goto failure;
-	}
-*/
+
 	/* register the subdevice, must be done for callbacks */
-	rc = v4l2_device_register_subdev(&pcam->v4l2_dev, sdev);
+	rc = v4l2_device_register_subdev(&pcam->v4l2_dev, sensor_sd);
 	if (rc < 0) {
 		D("%s sensor sub device register failed\n",
 			__func__);
 		goto failure;
 	}
+
 	if (sdata->actuator_info) {
 		rc = v4l2_device_register_subdev(&pcam->v4l2_dev, act_sdev);
 		if (rc < 0) {
 			D("%s actuator sub device register failed\n",
-				__func__);
+			  __func__);
 			goto failure;
 		}
 	}
+
 	pcam->vnode_id = vnode_count++;
 	return rc;
 
@@ -2581,9 +2534,7 @@
 	/* mutex_destroy not needed at this moment as the associated
 	implemenation of mutex_init is not consuming resources */
 	msm_sync_destroy(&pcam->mctl.sync);
-	pcam->pdev = NULL;
 	kfree(act_sdev);
-	kfree(sdev);
 	kzfree(pcam);
 	return rc;
 }
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 3e3b9c8..5fc3e6ae 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -396,9 +396,7 @@
 */
 int msm_isp_register(struct msm_cam_server_dev *psvr);
 void msm_isp_unregister(struct msm_cam_server_dev *psvr);
-int msm_sensor_register(struct platform_device *pdev,
-	int (*sensor_probe)(const struct msm_camera_sensor_info *,
-	struct v4l2_subdev *, struct msm_sensor_ctrl *));
+int msm_sensor_register(struct v4l2_subdev *);
 int msm_isp_init_module(int g_num_config_nodes);
 
 int msm_mctl_init_module(struct msm_cam_v4l2_device *pcam);
diff --git a/drivers/media/video/msm/msm_io_8960.c b/drivers/media/video/msm/msm_io_8960.c
index ec18a93..3168bb6 100644
--- a/drivers/media/video/msm/msm_io_8960.c
+++ b/drivers/media/video/msm/msm_io_8960.c
@@ -136,10 +136,10 @@
 	msm_io_dump(dest_addr, len);
 }
 
-static int msm_camera_vreg_enable(struct platform_device *pdev)
+static int msm_camera_vreg_enable(struct device *dev)
 {
 	if (mipi_csi_vdd == NULL) {
-		mipi_csi_vdd = regulator_get(&pdev->dev, "mipi_csi_vdd");
+		mipi_csi_vdd = regulator_get(dev, "mipi_csi_vdd");
 		if (IS_ERR(mipi_csi_vdd)) {
 			CDBG("%s: VREG MIPI CSI VDD get failed\n", __func__);
 			mipi_csi_vdd = NULL;
@@ -164,7 +164,7 @@
 		}
 	}
 	if (cam_vana == NULL) {
-		cam_vana = regulator_get(&pdev->dev, "cam_vana");
+		cam_vana = regulator_get(dev, "cam_vana");
 		if (IS_ERR(cam_vana)) {
 			CDBG("%s: VREG CAM VANA get failed\n", __func__);
 			cam_vana = NULL;
@@ -188,7 +188,7 @@
 		}
 	}
 	if (cam_vio == NULL) {
-		cam_vio = regulator_get(&pdev->dev, "cam_vio");
+		cam_vio = regulator_get(dev, "cam_vio");
 		if (IS_ERR(cam_vio)) {
 			CDBG("%s: VREG VIO get failed\n", __func__);
 			cam_vio = NULL;
@@ -200,7 +200,7 @@
 		}
 	}
 	if (cam_vdig == NULL) {
-		cam_vdig = regulator_get(&pdev->dev, "cam_vdig");
+		cam_vdig = regulator_get(dev, "cam_vdig");
 		if (IS_ERR(cam_vdig)) {
 			CDBG("%s: VREG CAM VDIG get failed\n", __func__);
 			cam_vdig = NULL;
@@ -224,7 +224,7 @@
 		}
 	}
 	if (cam_vaf == NULL) {
-		cam_vaf = regulator_get(&pdev->dev, "cam_vaf");
+		cam_vaf = regulator_get(dev, "cam_vaf");
 		if (IS_ERR(cam_vaf)) {
 			CDBG("%s: VREG CAM VAF get failed\n", __func__);
 			cam_vaf = NULL;
@@ -456,9 +456,8 @@
 	return rc;
 }
 
-static int config_gpio_table(int gpio_en)
+static int config_gpio_table(struct msm_camera_sensor_info *sinfo, int gpio_en)
 {
-	struct msm_camera_sensor_info *sinfo = camio_dev->dev.platform_data;
 	struct msm_camera_gpio_conf *gpio_conf = sinfo->gpio_conf;
 	int rc = 0, i = 0;
 
@@ -567,73 +566,47 @@
 	.control	= PM8XXX_MPP_CS_CTRL_DISABLE,
 };
 
-int msm_camio_sensor_clk_on(struct platform_device *pdev)
+static struct msm_cam_clk_info cam_clk_info[] = {
+	{"cam_clk", 24000000},
+};
+
+int msm_sensor_probe_on(struct device *dev)
 {
 	int rc = 0;
-	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_sensor_info *sinfo = dev->platform_data;
 	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
-	camio_dev = pdev;
 	camio_clk = camdev->ioclk;
 
-	msm_camera_vreg_enable(pdev);
+	rc = config_gpio_table(sinfo, 1);
+	if (rc < 0)
+		return rc;
+	msm_camera_vreg_enable(dev);
 	if (sinfo->sensor_platform_info->privacy_light) {
 		struct msm8960_privacy_light_cfg *privacy_light_config =
 			sinfo->sensor_platform_info->privacy_light_info;
 		pm8xxx_mpp_config(privacy_light_config->mpp,
 						  &privacy_light_on_config);
 	}
-	msleep(20);
-	rc = config_gpio_table(1);
-	if (rc < 0)
-		return rc;
-	return msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK);
+	return msm_cam_clk_enable(dev, cam_clk_info,
+		&camio_cam_clk, ARRAY_SIZE(cam_clk_info), 1);
 }
 
-int msm_camio_sensor_clk_off(struct platform_device *pdev)
+int msm_sensor_probe_off(struct device *dev)
 {
 	int rc = 0;
-	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
-	msm_camera_vreg_disable();
+	struct msm_camera_sensor_info *sinfo = dev->platform_data;
 	if (sinfo->sensor_platform_info->privacy_light) {
 		struct msm8960_privacy_light_cfg *privacy_light_config =
 			sinfo->sensor_platform_info->privacy_light_info;
 		pm8xxx_mpp_config(privacy_light_config->mpp,
 						  &privacy_light_off_config);
 	}
-	rc = config_gpio_table(0);
-	if (rc < 0)
-		return rc;
-	return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
-}
-
-void msm_camio_vfe_blk_reset(void)
-{
-	return;
-}
-
-int msm_camio_probe_on(struct platform_device *pdev)
-{
-	int rc = 0;
-	struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
-	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
-	camio_dev = pdev;
-	camio_clk = camdev->ioclk;
-
-	rc = config_gpio_table(1);
-	if (rc < 0)
-		return rc;
-	msm_camera_vreg_enable(pdev);
-	return msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK);
-}
-
-int msm_camio_probe_off(struct platform_device *pdev)
-{
-	int rc = 0;
 	msm_camera_vreg_disable();
-	rc = config_gpio_table(0);
+	rc = config_gpio_table(sinfo, 0);
 	if (rc < 0)
 		return rc;
-	return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
+	return msm_cam_clk_enable(dev, cam_clk_info,
+		&camio_cam_clk, ARRAY_SIZE(cam_clk_info), 0);
 }
 
 void msm_camio_mode_config(enum msm_cam_mode mode)
@@ -653,16 +626,13 @@
 	}
 }
 
-void msm_camio_set_perf_lvl(enum msm_bus_perf_setting perf_setting)
+void msm_camio_bus_scale_cfg(struct msm_bus_scale_pdata *cam_bus_scale_table,
+		enum msm_bus_perf_setting perf_setting)
 {
 	static uint32_t bus_perf_client;
-	struct msm_camera_sensor_info *sinfo = camio_dev->dev.platform_data;
-	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
-
 	int rc = 0;
 	switch (perf_setting) {
 	case S_INIT:
-		cam_bus_scale_table = camdev->cam_bus_scale_table;
 		bus_perf_client =
 			msm_bus_scale_register_client(cam_bus_scale_table);
 		if (!bus_perf_client) {
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 689a614..759ac47 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -31,6 +31,7 @@
 #include "msm_csid.h"
 #include "msm_csiphy.h"
 #include "msm_ispif.h"
+#include "msm_sensor.h"
 
 #ifdef CONFIG_MSM_CAMERA_DEBUG
 #define D(fmt, args...) pr_debug("msm_mctl: " fmt, ##args)
@@ -151,7 +152,7 @@
 		return -EFAULT;
 	}
 
-	sdata = sync->pdev->dev.platform_data;
+	sdata = sync->sdata;
 	D("%s: sensor_name %s\n", __func__, sdata->sensor_name);
 
 	memcpy(&info.name[0], sdata->sensor_name, MAX_SENSOR_NAME);
@@ -175,8 +176,9 @@
 	unsigned int notification, void *arg)
 {
 	int rc = -EINVAL;
+	struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(p_mctl->sensor_sdev);
 	struct msm_camera_sensor_info *sinfo =
-			p_mctl->plat_dev->dev.platform_data;
+		(struct msm_camera_sensor_info *) s_ctrl->sensordata;
 	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
 	uint8_t csid_core = camdev->csid_core;
 	switch (notification) {
@@ -258,7 +260,8 @@
 			break;
 
 	case MSM_CAM_IOCTL_SENSOR_IO_CFG:
-			rc = p_mctl->sync.sctrl.s_config(argp);
+		rc = v4l2_subdev_call(p_mctl->sensor_sdev,
+			core, ioctl, VIDIOC_MSM_SENSOR_CFG, argp);
 			break;
 
 	case MSM_CAM_IOCTL_SENSOR_V4l2_S_CTRL: {
@@ -325,6 +328,19 @@
 		break;
 	}
 
+	case MSM_CAM_IOCTL_GET_KERNEL_SYSTEM_TIME: {
+		struct timeval timestamp;
+		if (copy_from_user(&timestamp, argp, sizeof(timestamp))) {
+			ERR_COPY_FROM_USER();
+			rc = -EFAULT;
+		} else {
+			msm_mctl_gettimeofday(&timestamp);
+			rc = copy_to_user((void *)argp,
+				 &timestamp, sizeof(timestamp));
+		}
+		break;
+	}
+
 	case MSM_CAM_IOCTL_FLASH_CTRL: {
 		struct flash_ctrl_data flash_info;
 		if (copy_from_user(&flash_info, argp, sizeof(flash_info))) {
@@ -462,8 +478,10 @@
 {
 	int rc = 0;
 	struct msm_sync *sync = NULL;
-	struct msm_camera_sensor_info *sinfo;
-	struct msm_camera_device_platform_data *camdev;
+	struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(p_mctl->sensor_sdev);
+	struct msm_camera_sensor_info *sinfo =
+		(struct msm_camera_sensor_info *) s_ctrl->sensordata;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
 	uint8_t csid_core;
 	D("%s\n", __func__);
 	if (!p_mctl) {
@@ -480,10 +498,6 @@
 		uint32_t csid_version;
 		wake_lock(&sync->wake_lock);
 
-		sinfo = sync->pdev->dev.platform_data;
-		sync->pdev->resource = sinfo->resource;
-		sync->pdev->num_resources = sinfo->num_resources;
-		camdev = sinfo->pdata;
 		csid_core = camdev->csid_core;
 		rc = msm_mctl_register_subdevs(p_mctl, csid_core);
 		if (rc < 0) {
@@ -492,14 +506,6 @@
 			goto msm_open_done;
 		}
 
-		/* turn on clock */
-		rc = msm_camio_sensor_clk_on(sync->pdev);
-		if (rc < 0) {
-			pr_err("%s: msm_camio_sensor_clk_on failed:%d\n",
-			 __func__, rc);
-			goto msm_open_done;
-		}
-
 		rc = v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
 			VIDIOC_MSM_CSIPHY_INIT, NULL);
 		if (rc < 0) {
@@ -535,8 +541,7 @@
 		}
 
 		/* then sensor - move sub dev later*/
-		if (sync->sctrl.s_init)
-			rc = sync->sctrl.s_init(sync->sdata);
+		rc = v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 1);
 
 		if (rc < 0) {
 			pr_err("%s: isp init failed: %d\n", __func__, rc);
@@ -570,8 +575,6 @@
 static int msm_mctl_release(struct msm_cam_media_controller *p_mctl)
 {
 	int rc = 0;
-	struct msm_sync *sync = &(p_mctl->sync);
-
 	v4l2_subdev_call(p_mctl->ispif_sdev, core, ioctl,
 		VIDIOC_MSM_ISPIF_RELEASE, NULL);
 
@@ -585,20 +588,16 @@
 		VIDIOC_MSM_CSIPHY_RELEASE, NULL);
 
 	if (p_mctl->sync.actctrl.a_power_down)
-		p_mctl->sync.actctrl.a_power_down(sync->sdata->actuator_info);
+		p_mctl->sync.actctrl.a_power_down(
+			p_mctl->sync.sdata->actuator_info);
 
-	if (p_mctl->sync.sctrl.s_release)
-		p_mctl->sync.sctrl.s_release();
-
-	rc = msm_camio_sensor_clk_off(sync->pdev);
-	if (rc < 0)
-		pr_err("%s: msm_camio_sensor_clk_off failed:%d\n",
-			 __func__, rc);
+	v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 0);
 
 	pm_qos_update_request(&p_mctl->pm_qos_req_list,
 				PM_QOS_DEFAULT_VALUE);
 	pm_qos_remove_request(&p_mctl->pm_qos_req_list);
 
+	wake_unlock(&p_mctl->sync.wake_lock);
 	return rc;
 }
 
@@ -679,7 +678,6 @@
 	pmctl->mctl_cmd = msm_mctl_cmd;
 	pmctl->mctl_notify = msm_mctl_notify;
 	pmctl->mctl_release = msm_mctl_release;
-	pmctl->plat_dev = pcam->pdev;
 	/* init mctl buf */
 	msm_mctl_buf_init(pcam);
 	memset(&pmctl->pp_info, 0, sizeof(pmctl->pp_info));
diff --git a/drivers/media/video/msm/msm_mctl_pp.c b/drivers/media/video/msm/msm_mctl_pp.c
index 77f963c..6a2c8aa 100644
--- a/drivers/media/video/msm/msm_mctl_pp.c
+++ b/drivers/media/video/msm/msm_mctl_pp.c
@@ -149,6 +149,8 @@
 	msm_mctl_gettimeofday(&div.frame.timestamp);
 	vb->vidbuf.v4l2_buf.timestamp = div.frame.timestamp;
 	div.do_pp = pp_type;
+	D("%s Diverting frame %x id %d to userspace ", __func__,
+		(int)div.frame.handle, div.frame.frame_id);
 	/* Get the cookie for 1st plane and store the path.
 	 * Also use this to check the number of planes in
 	 * this buffer.*/
@@ -187,7 +189,8 @@
 		}
 		if (!pp_type)
 			p_mctl->pp_info.div_frame[pcam_inst->image_mode].
-			ch_paddr[0] = div.frame.mp[0].phy_addr;
+			ch_paddr[0] = div.frame.mp[0].phy_addr +
+					div.frame.mp[0].data_offset;
 	}
 	rc = msm_mctl_pp_buf_divert(p_mctl, pcam_inst, &div);
 	return rc;
@@ -823,6 +826,8 @@
 		rc = -EFAULT;
 		goto err;
 	}
+	D("%s Returning frame %x id %d to kernel ", __func__,
+		(int)frame.handle, frame.frame_id);
 	if (p_mctl->pp_info.div_frame[image_mode].ch_paddr[0]) {
 		memcpy(&buf,
 			&p_mctl->pp_info.div_frame[image_mode],
@@ -836,9 +841,10 @@
 		}
 	} else {
 		if (frame.num_planes > 1)
-			buf.ch_paddr[0] = frame.mp[0].phy_addr;
+			buf.ch_paddr[0] = frame.mp[0].phy_addr +
+						frame.mp[0].data_offset;
 		else
-			buf.ch_paddr[0] = frame.sp.phy_addr;
+			buf.ch_paddr[0] = frame.sp.phy_addr + frame.sp.y_off;
 	}
 	spin_unlock_irqrestore(&p_mctl->pp_info.lock, flags);
 	/* here buf.addr is phy_addr */
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index d34d5b1..b04f07c 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -444,10 +444,11 @@
 
 static int vfe32_config_axi(int mode, uint32_t *ao)
 {
-	int32_t *ch_info;
+	uint32_t *ch_info;
+	uint32_t *axi_cfg = ao+V32_AXI_BUS_FMT_OFF;
 
 	/* Update the corresponding write masters for each output*/
-	ch_info = ao + V32_AXI_CFG_LEN;
+	ch_info = axi_cfg + V32_AXI_CFG_LEN;
 	vfe32_ctrl->outpath.out0.ch0 = 0x0000FFFF & *ch_info;
 	vfe32_ctrl->outpath.out0.ch1 = 0x0000FFFF & (*ch_info++ >> 16);
 	vfe32_ctrl->outpath.out0.ch2 = 0x0000FFFF & *ch_info++;
@@ -517,9 +518,12 @@
 	default:
 		break;
 	}
+	msm_io_w(*ao, vfe32_ctrl->vfebase +
+		VFE_BUS_IO_FORMAT_CFG);
 	msm_io_memcpy(vfe32_ctrl->vfebase +
-		vfe32_cmd[VFE_CMD_AXI_OUT_CFG].offset, ao,
-		vfe32_cmd[VFE_CMD_AXI_OUT_CFG].length - V32_AXI_CH_INF_LEN);
+		vfe32_cmd[VFE_CMD_AXI_OUT_CFG].offset, axi_cfg,
+		vfe32_cmd[VFE_CMD_AXI_OUT_CFG].length - V32_AXI_CH_INF_LEN
+		- V32_AXI_BUS_FMT_LEN);
 	return 0;
 }
 
@@ -727,7 +731,9 @@
 
 static int vfe32_start_recording(void)
 {
-	msm_camio_set_perf_lvl(S_VIDEO);
+	struct msm_sync *sync = vfe_syncdata;
+	msm_camio_bus_scale_cfg(
+		sync->sdata->pdata->cam_bus_scale_table, S_VIDEO);
 	vfe32_ctrl->recording_state = VFE_REC_STATE_START_REQUESTED;
 	msm_io_w_mb(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD);
 	return 0;
@@ -735,9 +741,11 @@
 
 static int vfe32_stop_recording(void)
 {
+	struct msm_sync *sync = vfe_syncdata;
 	vfe32_ctrl->recording_state = VFE_REC_STATE_STOP_REQUESTED;
 	msm_io_w_mb(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD);
-	msm_camio_set_perf_lvl(S_PREVIEW);
+	msm_camio_bus_scale_cfg(
+		sync->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
 	return 0;
 }
 
@@ -749,6 +757,7 @@
 
 static int vfe32_zsl(void)
 {
+	struct msm_sync *sync = vfe_syncdata;
 	uint32_t irq_comp_mask = 0;
 	/* capture command is valid for both idle and active state. */
 	irq_comp_mask	=
@@ -807,7 +816,8 @@
 	}
 	msm_io_w(irq_comp_mask, vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
 	vfe32_start_common();
-	msm_camio_set_perf_lvl(S_ZSL);
+	msm_camio_bus_scale_cfg(
+		sync->sdata->pdata->cam_bus_scale_table, S_ZSL);
 
 	msm_io_w(1, vfe32_ctrl->vfebase + 0x18C);
 	msm_io_w(1, vfe32_ctrl->vfebase + 0x188);
@@ -861,13 +871,12 @@
 			(0x1 << (vfe32_ctrl->outpath.out1.ch0 + 8));
 			msm_io_w(1, vfe32_ctrl->vfebase +
 				vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch0]);
-			msm_io_w(0x1000, vfe32_ctrl->vfebase +
-					VFE_BUS_IO_FORMAT_CFG);
 		}
 	}
 	msm_io_w(irq_comp_mask, vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
 	msm_io_r(vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
-	msm_camio_set_perf_lvl(S_CAPTURE);
+	msm_camio_bus_scale_cfg(
+		p_sync->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
 	vfe32_start_common();
 	msm_io_r(vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
 	/* for debug */
@@ -879,6 +888,7 @@
 static int vfe32_start(void)
 {
 	uint32_t irq_comp_mask = 0;
+	struct msm_sync *sync = vfe_syncdata;
 	/* start command now is only good for continuous mode. */
 	if ((vfe32_ctrl->operation_mode != VFE_MODE_OF_OPERATION_CONTINUOUS) &&
 		(vfe32_ctrl->operation_mode != VFE_MODE_OF_OPERATION_VIDEO))
@@ -918,7 +928,8 @@
 		msm_io_w(1, vfe32_ctrl->vfebase +
 			vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch2]);
 	}
-	msm_camio_set_perf_lvl(S_PREVIEW);
+	msm_camio_bus_scale_cfg(
+		sync->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
 	vfe32_start_common();
 	return 0;
 }
@@ -3681,6 +3692,7 @@
 	struct platform_device *pdev)
 {
 	int rc = 0;
+	struct msm_sync *sync = data;
 	v4l2_set_subdev_hostdata(sd, data);
 	vfe_syncdata = data;
 
@@ -3733,8 +3745,10 @@
 	if (rc < 0)
 		goto vfe_clk_enable_failed;
 
-	msm_camio_set_perf_lvl(S_INIT);
-	msm_camio_set_perf_lvl(S_PREVIEW);
+	msm_camio_bus_scale_cfg(
+		sync->sdata->pdata->cam_bus_scale_table, S_INIT);
+	msm_camio_bus_scale_cfg(
+		sync->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
 
 	if (msm_io_r(vfe32_ctrl->vfebase + V32_GET_HW_VERSION_OFF) ==
 		VFE32_HW_NUMBER)
@@ -3757,6 +3771,7 @@
 
 void msm_vfe_subdev_release(struct platform_device *pdev)
 {
+	struct msm_sync *sync = vfe_syncdata;
 	msm_cam_clk_enable(&vfe32_ctrl->pdev->dev, vfe32_clk_info,
 			vfe32_ctrl->vfe_clk, ARRAY_SIZE(vfe32_clk_info), 0);
 	if (vfe32_ctrl->fs_vfe) {
@@ -3772,7 +3787,8 @@
 	if (atomic_read(&irq_cnt))
 		pr_warning("%s, Warning IRQ Count not ZERO\n", __func__);
 
-	msm_camio_set_perf_lvl(S_EXIT);
+	msm_camio_bus_scale_cfg(
+		sync->sdata->pdata->cam_bus_scale_table, S_EXIT);
 	vfe_syncdata = NULL;
 }
 
diff --git a/drivers/media/video/msm/msm_vfe32.h b/drivers/media/video/msm/msm_vfe32.h
index ecb8608..ff42c28 100644
--- a/drivers/media/video/msm/msm_vfe32.h
+++ b/drivers/media/video/msm/msm_vfe32.h
@@ -226,9 +226,11 @@
 #define V32_OPERATION_CFG_LEN     32
 
 #define V32_AXI_OUT_OFF           0x00000038
-#define V32_AXI_OUT_LEN           212
+#define V32_AXI_OUT_LEN           216
 #define V32_AXI_CH_INF_LEN        24
 #define V32_AXI_CFG_LEN           47
+#define V32_AXI_BUS_FMT_OFF    1
+#define V32_AXI_BUS_FMT_LEN    4
 
 #define V32_FRAME_SKIP_OFF        0x00000504
 #define V32_FRAME_SKIP_LEN        32
diff --git a/drivers/media/video/msm/sensors/imx074_v4l2.c b/drivers/media/video/msm/sensors/imx074_v4l2.c
index f721441..c77cfc3 100644
--- a/drivers/media/video/msm/sensors/imx074_v4l2.c
+++ b/drivers/media/video/msm/sensors/imx074_v4l2.c
@@ -211,23 +211,8 @@
 	.vert_offset = 3,
 };
 
-static int imx074_sensor_config(void __user *argp)
-{
-	return msm_sensor_config(&imx074_s_ctrl, argp);
-}
-
 static struct sensor_calib_data imx074_calib_data;
 
-static int imx074_sensor_open_init(const struct msm_camera_sensor_info *data)
-{
-	return msm_sensor_open_init(&imx074_s_ctrl, data);
-}
-
-static int imx074_sensor_release(void)
-{
-	return msm_sensor_release(&imx074_s_ctrl);
-}
-
 static const struct i2c_device_id imx074_i2c_id[] = {
 	{SENSOR_NAME, (kernel_ulong_t)&imx074_s_ctrl},
 	{ }
@@ -276,31 +261,16 @@
 	.data_tbl_size = ARRAY_SIZE(imx074_eeprom_data_tbl),
 };
 
-static int imx074_sensor_v4l2_probe(const struct msm_camera_sensor_info *info,
-	struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s)
-{
-	return msm_sensor_v4l2_probe(&imx074_s_ctrl, info, sdev, s);
-}
-
-static int imx074_probe(struct platform_device *pdev)
-{
-	return msm_sensor_register(pdev, imx074_sensor_v4l2_probe);
-}
-
-struct platform_driver imx074_driver = {
-	.probe = imx074_probe,
-	.driver = {
-		.name = PLATFORM_DRIVER_NAME,
-		.owner = THIS_MODULE,
-	},
-};
-
 static int __init msm_sensor_init_module(void)
 {
-	return platform_driver_register(&imx074_driver);
+	return i2c_add_driver(&imx074_i2c_driver);
 }
 
-static struct v4l2_subdev_core_ops imx074_subdev_core_ops;
+static struct v4l2_subdev_core_ops imx074_subdev_core_ops = {
+	.ioctl = msm_sensor_subdev_ioctl,
+	.s_power = msm_sensor_power,
+};
+
 static struct v4l2_subdev_video_ops imx074_subdev_video_ops = {
 	.enum_mbus_fmt = msm_sensor_v4l2_enum_fmt,
 };
@@ -322,12 +292,9 @@
 	.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
 	.sensor_mode_init = msm_sensor_mode_init,
 	.sensor_get_output_info = msm_sensor_get_output_info,
-	.sensor_config = imx074_sensor_config,
-	.sensor_open_init = imx074_sensor_open_init,
-	.sensor_release = imx074_sensor_release,
+	.sensor_config = msm_sensor_config,
 	.sensor_power_up = msm_sensor_power_up,
 	.sensor_power_down = msm_sensor_power_down,
-	.sensor_probe = msm_sensor_probe,
 };
 
 static struct msm_sensor_reg_t imx074_regs = {
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index e67f9cd..d31de14 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -177,7 +177,7 @@
 {
 	int32_t rc = 0;
 
-	v4l2_subdev_notify(s_ctrl->sensor_v4l2_subdev,
+	v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
 		NOTIFY_ISPIF_STREAM, (void *)ISPIF_STREAM(
 		PIX0, ISPIF_OFF_IMMEDIATELY));
 	s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
@@ -190,23 +190,23 @@
 		msm_sensor_write_res_settings(s_ctrl, res);
 		if (s_ctrl->curr_csi_params != s_ctrl->csi_params[res]) {
 			s_ctrl->curr_csi_params = s_ctrl->csi_params[res];
-			v4l2_subdev_notify(s_ctrl->sensor_v4l2_subdev,
+			v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
 				NOTIFY_CSID_CFG,
 				&s_ctrl->curr_csi_params->csid_params);
-			v4l2_subdev_notify(s_ctrl->sensor_v4l2_subdev,
+			v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
 						NOTIFY_CID_CHANGE, NULL);
 			mb();
-			v4l2_subdev_notify(s_ctrl->sensor_v4l2_subdev,
+			v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
 				NOTIFY_CSIPHY_CFG,
 				&s_ctrl->curr_csi_params->csiphy_params);
 			mb();
 			msleep(20);
 		}
 
-		v4l2_subdev_notify(s_ctrl->sensor_v4l2_subdev,
+		v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
 			NOTIFY_PCLK_CHANGE, &s_ctrl->msm_sensor_reg->
 			output_settings[res].op_pixel_clk);
-		v4l2_subdev_notify(s_ctrl->sensor_v4l2_subdev,
+		v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
 			NOTIFY_ISPIF_STREAM, (void *)ISPIF_STREAM(
 			PIX0, ISPIF_ON_FRAME_BOUNDARY));
 		s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
@@ -269,6 +269,19 @@
 	return rc;
 }
 
+long msm_sensor_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int cmd, void *arg)
+{
+	struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
+	void __user *argp = (void __user *)arg;
+	switch (cmd) {
+	case VIDIOC_MSM_SENSOR_CFG:
+		return s_ctrl->func_tbl->sensor_config(s_ctrl, argp);
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+
 int32_t msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void __user *argp)
 {
 	struct sensor_cfg_data cdata;
@@ -396,10 +409,12 @@
 	return rc;
 }
 
-int32_t msm_sensor_power_up(const struct msm_camera_sensor_info *data)
+int32_t msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl)
 {
 	int32_t rc = 0;
+	struct msm_camera_sensor_info *data = s_ctrl->sensordata;
 	CDBG("%s: %d\n", __func__, __LINE__);
+	msm_sensor_probe_on(&s_ctrl->sensor_i2c_client->client->dev);
 	msm_camio_clk_rate_set(MSM_SENSOR_MCLK_24HZ);
 	rc = gpio_request(data->sensor_platform_info->sensor_reset,
 		"SENSOR_NAME");
@@ -417,9 +432,11 @@
 	return rc;
 }
 
-int32_t msm_sensor_power_down(const struct msm_camera_sensor_info *data)
+int32_t msm_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl)
 {
+	struct msm_camera_sensor_info *data = s_ctrl->sensordata;
 	CDBG("%s\n", __func__);
+	msm_sensor_probe_off(&s_ctrl->sensor_i2c_client->client->dev);
 	gpio_set_value_cansleep(data->sensor_platform_info->sensor_reset, 0);
 	usleep_range(1000, 2000);
 	gpio_free(data->sensor_platform_info->sensor_reset);
@@ -448,64 +465,37 @@
 	return rc;
 }
 
+struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct msm_sensor_ctrl_t, sensor_v4l2_subdev);
+}
+
 int32_t msm_sensor_i2c_probe(struct i2c_client *client,
 	const struct i2c_device_id *id)
 {
 	int rc = 0;
-	struct msm_sensor_ctrl_t *this_ctrl;
+	struct msm_sensor_ctrl_t *s_ctrl;
 	CDBG("%s_i2c_probe called\n", client->name);
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
 		CDBG("i2c_check_functionality failed\n");
 		rc = -EFAULT;
-		goto probe_failure;
+		return rc;
 	}
 
-	this_ctrl = (struct msm_sensor_ctrl_t *)(id->driver_data);
-	if (this_ctrl->sensor_i2c_client != NULL) {
-		this_ctrl->sensor_i2c_client->client = client;
-		if (this_ctrl->sensor_i2c_addr != 0)
-			this_ctrl->sensor_i2c_client->client->addr =
-				this_ctrl->sensor_i2c_addr;
+	s_ctrl = (struct msm_sensor_ctrl_t *)(id->driver_data);
+	if (s_ctrl->sensor_i2c_client != NULL) {
+		s_ctrl->sensor_i2c_client->client = client;
+		if (s_ctrl->sensor_i2c_addr != 0)
+			s_ctrl->sensor_i2c_client->client->addr =
+				s_ctrl->sensor_i2c_addr;
 	} else {
 		rc = -EFAULT;
+		return rc;
 	}
 
-probe_failure:
-	CDBG("%s_i2c_probe failed\n", client->name);
-	return rc;
-}
+	s_ctrl->sensordata = client->dev.platform_data;
 
-int32_t msm_sensor_release(struct msm_sensor_ctrl_t *s_ctrl)
-{
-	mutex_lock(s_ctrl->msm_sensor_mutex);
-	s_ctrl->func_tbl->sensor_power_down(s_ctrl->sensordata);
-	mutex_unlock(s_ctrl->msm_sensor_mutex);
-	CDBG("%s completed\n", __func__);
-	return 0;
-}
-
-int32_t msm_sensor_open_init(struct msm_sensor_ctrl_t *s_ctrl,
-				const struct msm_camera_sensor_info *data)
-{
-	if (data)
-		s_ctrl->sensordata = data;
-
-	return s_ctrl->func_tbl->sensor_power_up(data);
-}
-
-int32_t msm_sensor_probe(struct msm_sensor_ctrl_t *s_ctrl,
-		const struct msm_camera_sensor_info *info,
-		struct msm_sensor_ctrl *s)
-{
-	int rc = 0;
-	rc = i2c_add_driver(s_ctrl->sensor_i2c_driver);
-	if (rc < 0 || s_ctrl->sensor_i2c_client->client == NULL) {
-		rc = -ENOTSUPP;
-		CDBG("I2C add driver failed");
-		goto probe_fail;
-	}
-
-	rc = s_ctrl->func_tbl->sensor_power_up(info);
+	rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
 	if (rc < 0)
 		goto probe_fail;
 
@@ -532,45 +522,38 @@
 		}
 	}
 
-	s->s_init = s_ctrl->func_tbl->sensor_open_init;
-	s->s_release = s_ctrl->func_tbl->sensor_release;
-	s->s_config  = s_ctrl->func_tbl->sensor_config;
-	s->s_camera_type = info->camera_type;
-	if (info->sensor_platform_info != NULL)
-		s->s_mount_angle = info->sensor_platform_info->mount_angle;
-	else
-		s->s_mount_angle = 0;
+	snprintf(s_ctrl->sensor_v4l2_subdev.name,
+		sizeof(s_ctrl->sensor_v4l2_subdev.name), "%s", id->name);
+	v4l2_i2c_subdev_init(&s_ctrl->sensor_v4l2_subdev, client,
+		s_ctrl->sensor_v4l2_subdev_ops);
 
+	msm_sensor_register(&s_ctrl->sensor_v4l2_subdev);
 	goto power_down;
 probe_fail:
-	i2c_del_driver(s_ctrl->sensor_i2c_driver);
+	CDBG("%s_i2c_probe failed\n", client->name);
 power_down:
-	s_ctrl->func_tbl->sensor_power_down(info);
+	s_ctrl->func_tbl->sensor_power_down(s_ctrl);
 	return rc;
 }
 
-int32_t msm_sensor_v4l2_probe(struct msm_sensor_ctrl_t *s_ctrl,
-	const struct msm_camera_sensor_info *info,
-	struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s)
+int32_t msm_sensor_power(struct v4l2_subdev *sd, int on)
 {
-	int32_t rc = 0;
-	rc = s_ctrl->func_tbl->sensor_probe(s_ctrl, info, s);
-	if (rc < 0)
-		return rc;
-
-	s_ctrl->sensor_v4l2_subdev = sdev;
-	v4l2_i2c_subdev_init(s_ctrl->sensor_v4l2_subdev,
-		s_ctrl->sensor_i2c_client->client,
-		s_ctrl->sensor_v4l2_subdev_ops);
-	s_ctrl->sensor_v4l2_subdev->dev_priv = (void *) s_ctrl;
+	int rc = 0;
+	struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
+	mutex_lock(s_ctrl->msm_sensor_mutex);
+	if (on)
+		rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
+	else
+		rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+	mutex_unlock(s_ctrl->msm_sensor_mutex);
 	return rc;
 }
 
 int32_t msm_sensor_v4l2_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
 			   enum v4l2_mbus_pixelcode *code)
 {
-	struct msm_sensor_ctrl_t *s_ctrl =
-		(struct msm_sensor_ctrl_t *) sd->dev_priv;
+	struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
+
 	if ((unsigned int)index >= s_ctrl->sensor_v4l2_subdev_info_size)
 		return -EINVAL;
 
diff --git a/drivers/media/video/msm/sensors/msm_sensor.h b/drivers/media/video/msm/sensors/msm_sensor.h
index f1a15b2..e06f628 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.h
+++ b/drivers/media/video/msm/sensors/msm_sensor.h
@@ -10,6 +10,9 @@
  * GNU General Public License for more details.
  */
 
+#ifndef MSM_SENSOR_H
+#define MSM_SENSOR_H
+
 #include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
@@ -22,7 +25,6 @@
 #include <mach/gpio.h>
 #include <media/msm_camera.h>
 #include <media/v4l2-subdev.h>
-#include "msm.h"
 #include "msm_camera_i2c.h"
 #include "msm_camera_eeprom.h"
 #define Q8  0x00000100
@@ -124,19 +126,14 @@
 		int, struct sensor_init_cfg *);
 	int32_t (*sensor_get_output_info) (struct msm_sensor_ctrl_t *,
 		struct sensor_output_info_t *);
-	int (*sensor_config) (void __user *);
-	int (*sensor_open_init) (const struct msm_camera_sensor_info *);
-	int (*sensor_release) (void);
+	int (*sensor_config) (struct msm_sensor_ctrl_t *, void __user *);
 	int (*sensor_power_down)
-		(const struct msm_camera_sensor_info *);
-	int (*sensor_power_up) (const struct msm_camera_sensor_info *);
-	int (*sensor_probe) (struct msm_sensor_ctrl_t *s_ctrl,
-			const struct msm_camera_sensor_info *info,
-			struct msm_sensor_ctrl *s);
+		(struct msm_sensor_ctrl_t *);
+	int (*sensor_power_up) (struct msm_sensor_ctrl_t *);
 };
 
 struct msm_sensor_ctrl_t {
-	const struct  msm_camera_sensor_info *sensordata;
+	struct  msm_camera_sensor_info *sensordata;
 	struct i2c_client *msm_sensor_client;
 	struct i2c_driver *sensor_i2c_driver;
 	struct msm_camera_i2c_client *sensor_i2c_client;
@@ -162,7 +159,7 @@
 	struct msm_camera_csi2_params *curr_csi_params;
 	struct msm_camera_csi2_params **csi_params;
 
-	struct v4l2_subdev *sensor_v4l2_subdev;
+	struct v4l2_subdev sensor_v4l2_subdev;
 	struct v4l2_subdev_info *sensor_v4l2_subdev_info;
 	uint8_t sensor_v4l2_subdev_info_size;
 	struct v4l2_subdev_ops *sensor_v4l2_subdev_ops;
@@ -188,22 +185,13 @@
 		struct sensor_output_info_t *);
 int32_t msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl,
 			void __user *argp);
-int32_t msm_sensor_power_up(const struct msm_camera_sensor_info *data);
-int32_t msm_sensor_power_down(const struct msm_camera_sensor_info *data);
+int32_t msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl);
+int32_t msm_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl);
 
 int32_t msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl);
 int msm_sensor_i2c_probe(struct i2c_client *client,
 	const struct i2c_device_id *id);
-int32_t msm_sensor_release(struct msm_sensor_ctrl_t *s_ctrl);
-int32_t msm_sensor_open_init(struct msm_sensor_ctrl_t *s_ctrl,
-				const struct msm_camera_sensor_info *data);
-int msm_sensor_probe(struct msm_sensor_ctrl_t *s_ctrl,
-		const struct msm_camera_sensor_info *info,
-		struct msm_sensor_ctrl *s);
-
-int msm_sensor_v4l2_probe(struct msm_sensor_ctrl_t *s_ctrl,
-	const struct msm_camera_sensor_info *info,
-	struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s);
+int32_t msm_sensor_power(struct v4l2_subdev *sd, int on);
 
 int32_t msm_sensor_v4l2_s_ctrl(struct v4l2_subdev *sd,
 	struct v4l2_control *ctrl);
@@ -231,3 +219,13 @@
 			int update_type, int res);
 
 int msm_sensor_enable_debugfs(struct msm_sensor_ctrl_t *s_ctrl);
+
+long msm_sensor_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int cmd, void *arg);
+
+struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd);
+
+#define VIDIOC_MSM_SENSOR_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 10, void __user *)
+
+#endif
diff --git a/drivers/media/video/msm/sensors/mt9m114_v4l2.c b/drivers/media/video/msm/sensors/mt9m114_v4l2.c
index fc45705..a1e56f7 100644
--- a/drivers/media/video/msm/sensors/mt9m114_v4l2.c
+++ b/drivers/media/video/msm/sensors/mt9m114_v4l2.c
@@ -1221,21 +1221,6 @@
 	.sensor_id = 0x2481,
 };
 
-static int mt9m114_sensor_config(void __user *argp)
-{
-	return msm_sensor_config(&mt9m114_s_ctrl, argp);
-}
-
-static int mt9m114_sensor_open_init(const struct msm_camera_sensor_info *data)
-{
-	return msm_sensor_open_init(&mt9m114_s_ctrl, data);
-}
-
-static int mt9m114_sensor_release(void)
-{
-	return msm_sensor_release(&mt9m114_s_ctrl);
-}
-
 static const struct i2c_device_id mt9m114_i2c_id[] = {
 	{SENSOR_NAME, (kernel_ulong_t)&mt9m114_s_ctrl},
 	{ }
@@ -1253,33 +1238,16 @@
 	.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
 };
 
-static int mt9m114_sensor_v4l2_probe(const struct msm_camera_sensor_info *info,
-	struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s)
-{
-	return msm_sensor_v4l2_probe(&mt9m114_s_ctrl, info, sdev, s);
-}
-
-static int mt9m114_probe(struct platform_device *pdev)
-{
-	return msm_sensor_register(pdev, mt9m114_sensor_v4l2_probe);
-}
-
-struct platform_driver mt9m114_driver = {
-	.probe = mt9m114_probe,
-	.driver = {
-		.name = PLATFORM_DRIVER_NAME,
-		.owner = THIS_MODULE,
-	},
-};
-
 static int __init msm_sensor_init_module(void)
 {
-	return platform_driver_register(&mt9m114_driver);
+	return i2c_add_driver(&mt9m114_i2c_driver);
 }
 
 static struct v4l2_subdev_core_ops mt9m114_subdev_core_ops = {
 	.s_ctrl = msm_sensor_v4l2_s_ctrl,
 	.queryctrl = msm_sensor_v4l2_query_ctrl,
+	.ioctl = msm_sensor_subdev_ioctl,
+	.s_power = msm_sensor_power,
 };
 
 static struct v4l2_subdev_video_ops mt9m114_subdev_video_ops = {
@@ -1298,12 +1266,9 @@
 	.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
 	.sensor_mode_init = msm_sensor_mode_init,
 	.sensor_get_output_info = msm_sensor_get_output_info,
-	.sensor_config = mt9m114_sensor_config,
-	.sensor_open_init = mt9m114_sensor_open_init,
-	.sensor_release = mt9m114_sensor_release,
+	.sensor_config = msm_sensor_config,
 	.sensor_power_up = msm_sensor_power_up,
 	.sensor_power_down = msm_sensor_power_down,
-	.sensor_probe = msm_sensor_probe,
 };
 
 static struct msm_sensor_reg_t mt9m114_regs = {
diff --git a/drivers/media/video/msm/sensors/ov2720.c b/drivers/media/video/msm/sensors/ov2720.c
index 5938406..6389498 100644
--- a/drivers/media/video/msm/sensors/ov2720.c
+++ b/drivers/media/video/msm/sensors/ov2720.c
@@ -406,21 +406,6 @@
 	return 0;
 }
 
-static int ov2720_sensor_config(void __user *argp)
-{
-	return msm_sensor_config(&ov2720_s_ctrl, argp);
-}
-
-static int ov2720_sensor_open_init(const struct msm_camera_sensor_info *data)
-{
-	return msm_sensor_open_init(&ov2720_s_ctrl, data);
-}
-
-static int ov2720_sensor_release(void)
-{
-	return msm_sensor_release(&ov2720_s_ctrl);
-}
-
 static const struct i2c_device_id ov2720_i2c_id[] = {
 	{SENSOR_NAME, (kernel_ulong_t)&ov2720_s_ctrl},
 	{ }
@@ -438,31 +423,16 @@
 	.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
 };
 
-static int ov2720_sensor_v4l2_probe(const struct msm_camera_sensor_info *info,
-	struct v4l2_subdev *sdev, struct msm_sensor_ctrl *s)
-{
-	return msm_sensor_v4l2_probe(&ov2720_s_ctrl, info, sdev, s);
-}
-
-static int ov2720_probe(struct platform_device *pdev)
-{
-	return msm_sensor_register(pdev, ov2720_sensor_v4l2_probe);
-}
-
-struct platform_driver ov2720_driver = {
-	.probe = ov2720_probe,
-	.driver = {
-		.name = PLATFORM_DRIVER_NAME,
-		.owner = THIS_MODULE,
-	},
-};
-
 static int __init msm_sensor_init_module(void)
 {
-	return platform_driver_register(&ov2720_driver);
+	return i2c_add_driver(&ov2720_i2c_driver);
 }
 
-static struct v4l2_subdev_core_ops ov2720_subdev_core_ops;
+static struct v4l2_subdev_core_ops ov2720_subdev_core_ops = {
+	.ioctl = msm_sensor_subdev_ioctl,
+	.s_power = msm_sensor_power,
+};
+
 static struct v4l2_subdev_video_ops ov2720_subdev_video_ops = {
 	.enum_mbus_fmt = msm_sensor_v4l2_enum_fmt,
 };
@@ -484,12 +454,9 @@
 	.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
 	.sensor_mode_init = msm_sensor_mode_init,
 	.sensor_get_output_info = msm_sensor_get_output_info,
-	.sensor_config = ov2720_sensor_config,
-	.sensor_open_init = ov2720_sensor_open_init,
-	.sensor_release = ov2720_sensor_release,
+	.sensor_config = msm_sensor_config,
 	.sensor_power_up = msm_sensor_power_up,
 	.sensor_power_down = msm_sensor_power_down,
-	.sensor_probe = msm_sensor_probe,
 };
 
 static struct msm_sensor_reg_t ov2720_regs = {
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 9e9bb23..77ac845 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -158,7 +158,6 @@
 	depends on MSM_SSBI
 	select MFD_CORE
 	select MFD_PM8XXX
-	select MSM_SHOW_RESUME_IRQ
 	help
 	  Say yes here for Qualcomm PM8058 chip.
 
diff --git a/drivers/mfd/pm8018-core.c b/drivers/mfd/pm8018-core.c
index 8d89568..fc85a42 100644
--- a/drivers/mfd/pm8018-core.c
+++ b/drivers/mfd/pm8018-core.c
@@ -16,11 +16,13 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <linux/string.h>
 #include <linux/err.h>
 #include <linux/msm_ssbi.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/pm8xxx/pm8018.h>
 #include <linux/mfd/pm8xxx/core.h>
+#include <linux/mfd/pm8xxx/regulator.h>
 #include <linux/leds-pm8xxx.h>
 
 
@@ -53,10 +55,11 @@
 }
 
 struct pm8018 {
-	struct device			*dev;
-	struct pm_irq_chip		*irq_chip;
-	struct mfd_cell			*mfd_regulators;
-	u32				rev_registers;
+	struct device					*dev;
+	struct pm_irq_chip				*irq_chip;
+	struct mfd_cell					*mfd_regulators;
+	struct pm8xxx_regulator_core_platform_data	*regulator_cdata;
+	u32						rev_registers;
 };
 
 static int pm8018_readb(const struct device *dev, u16 addr, u8 *val)
@@ -227,14 +230,136 @@
 	.id		= -1,
 };
 
+static struct pm8xxx_vreg regulator_data[] = {
+	/*   name	     pc_name	    ctrl   test   hpm_min */
+	PLDO("8018_l2",      "8018_l2_pc",  0x0B0, 0x0B1, LDO_50),
+	PLDO("8018_l3",      "8018_l3_pc",  0x0B2, 0x0B3, LDO_50),
+	PLDO("8018_l4",      "8018_l4_pc",  0x0B4, 0x0B5, LDO_300),
+	PLDO("8018_l5",      "8018_l5_pc",  0x0B6, 0x0B7, LDO_150),
+	PLDO("8018_l6",      "8018_l6_pc",  0x0B8, 0x0B9, LDO_150),
+	PLDO("8018_l7",      "8018_l7_pc",  0x0BA, 0x0BB, LDO_300),
+	NLDO("8018_l8",      "8018_l8_pc",  0x0BC, 0x0BD, LDO_150),
+	NLDO1200("8018_l9",		    0x0BE, 0x0BF, LDO_1200),
+	NLDO1200("8018_l10",		    0x0C0, 0x0C1, LDO_1200),
+	NLDO1200("8018_l11",		    0x0C2, 0x0C3, LDO_1200),
+	NLDO1200("8018_l12",		    0x0C4, 0x0C5, LDO_1200),
+	PLDO("8018_l13",     "8018_l13_pc", 0x0C8, 0x0C9, LDO_50),
+	PLDO("8018_l14",     "8018_l14_pc", 0x0CA, 0x0CB, LDO_50),
+
+	/*   name	pc_name       ctrl   test2  clk    sleep  hpm_min */
+	SMPS("8018_s1", "8018_s1_pc", 0x1D0, 0x1D5, 0x009, 0x1D2, SMPS_1500),
+	SMPS("8018_s2", "8018_s2_pc", 0x1D8, 0x1DD, 0x00A, 0x1DA, SMPS_1500),
+	SMPS("8018_s3", "8018_s3_pc", 0x1E0, 0x1E5, 0x00B, 0x1E2, SMPS_1500),
+	SMPS("8018_s4", "8018_s4_pc", 0x1E8, 0x1ED, 0x00C, 0x1EA, SMPS_1500),
+	SMPS("8018_s5", "8018_s5_pc", 0x1F0, 0x1F5, 0x00D, 0x1F2, SMPS_1500),
+
+	/* name		     pc_name	     ctrl */
+	VS("8018_lvs1",      "8018_lvs1_pc", 0x060),
+};
+
+#define MAX_NAME_COMPARISON_LEN 32
+
+static int __devinit match_regulator(
+	struct pm8xxx_regulator_core_platform_data *core_data, char *name)
+{
+	int found = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(regulator_data); i++) {
+		if (regulator_data[i].rdesc.name
+		    && strncmp(regulator_data[i].rdesc.name, name,
+				MAX_NAME_COMPARISON_LEN) == 0) {
+			core_data->is_pin_controlled = false;
+			core_data->vreg = &regulator_data[i];
+			found = 1;
+			break;
+		} else if (regulator_data[i].rdesc_pc.name
+			   && strncmp(regulator_data[i].rdesc_pc.name, name,
+				MAX_NAME_COMPARISON_LEN) == 0) {
+			core_data->is_pin_controlled = true;
+			core_data->vreg = &regulator_data[i];
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found)
+		pr_err("could not find a match for regulator: %s\n", name);
+
+	return found;
+}
+
+static int __devinit
+pm8018_add_regulators(const struct pm8018_platform_data *pdata,
+		      struct pm8018 *pmic, int irq_base)
+{
+	int ret = 0;
+	struct mfd_cell *mfd_regulators;
+	struct pm8xxx_regulator_core_platform_data *cdata;
+	int i;
+
+	/* Add one device for each regulator used by the board. */
+	mfd_regulators = kzalloc(sizeof(struct mfd_cell)
+				 * (pdata->num_regulators), GFP_KERNEL);
+	if (!mfd_regulators) {
+		pr_err("Cannot allocate %d bytes for pm8018 regulator "
+			"mfd cells\n", sizeof(struct mfd_cell)
+					* (pdata->num_regulators));
+		return -ENOMEM;
+	}
+	cdata = kzalloc(sizeof(struct pm8xxx_regulator_core_platform_data)
+			* pdata->num_regulators, GFP_KERNEL);
+	if (!cdata) {
+		pr_err("Cannot allocate %d bytes for pm8018 regulator "
+			"core data\n", pdata->num_regulators
+			  * sizeof(struct pm8xxx_regulator_core_platform_data));
+		kfree(mfd_regulators);
+		return -ENOMEM;
+	}
+	for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
+		mutex_init(&regulator_data[i].pc_lock);
+
+	for (i = 0; i < pdata->num_regulators; i++) {
+		if (!pdata->regulator_pdatas[i].init_data.constraints.name) {
+			pr_err("name missing for regulator %d\n", i);
+			ret = -EINVAL;
+			goto bail;
+		}
+		if (!match_regulator(&cdata[i],
+		      pdata->regulator_pdatas[i].init_data.constraints.name)) {
+			ret = -ENODEV;
+			goto bail;
+		}
+		cdata[i].pdata = &(pdata->regulator_pdatas[i]);
+		mfd_regulators[i].name = PM8XXX_REGULATOR_DEV_NAME;
+		mfd_regulators[i].id = cdata[i].pdata->id;
+		mfd_regulators[i].platform_data = &cdata[i];
+		mfd_regulators[i].pdata_size =
+			sizeof(struct pm8xxx_regulator_core_platform_data);
+	}
+	ret = mfd_add_devices(pmic->dev, 0, mfd_regulators,
+			pdata->num_regulators, NULL, irq_base);
+	if (ret)
+		goto bail;
+
+	pmic->mfd_regulators = mfd_regulators;
+	pmic->regulator_cdata = cdata;
+	return ret;
+
+bail:
+	for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
+		mutex_destroy(&regulator_data[i].pc_lock);
+	kfree(mfd_regulators);
+	kfree(cdata);
+	return ret;
+}
+
 static int __devinit
 pm8018_add_subdevices(const struct pm8018_platform_data *pdata,
 		      struct pm8018 *pmic)
 {
 	int ret = 0, irq_base = 0;
 	struct pm_irq_chip *irq_chip;
-	static struct mfd_cell *mfd_regulators;
-	int i;
 
 	if (pdata->irq_pdata) {
 		pdata->irq_pdata->irq_cdata.nirqs = PM8018_NR_IRQS;
@@ -341,36 +466,16 @@
 		goto bail;
 	}
 
-	/* Add one device for each regulator used by the board. */
 	if (pdata->num_regulators > 0 && pdata->regulator_pdatas) {
-		mfd_regulators = kzalloc(sizeof(struct mfd_cell)
-					 * (pdata->num_regulators), GFP_KERNEL);
-		if (!mfd_regulators) {
-			pr_err("Cannot allocate %d bytes for pm8018 regulator "
-				"mfd cells\n", sizeof(struct mfd_cell)
-						* (pdata->num_regulators));
-			ret = -ENOMEM;
-			goto bail;
-		}
-		for (i = 0; i < pdata->num_regulators; i++) {
-			mfd_regulators[i].name = PM8018_REGULATOR_DEV_NAME;
-			mfd_regulators[i].id = pdata->regulator_pdatas[i].id;
-			mfd_regulators[i].platform_data =
-				&(pdata->regulator_pdatas[i]);
-			mfd_regulators[i].pdata_size =
-				sizeof(struct pm8018_regulator_platform_data);
-		}
-		ret = mfd_add_devices(pmic->dev, 0, mfd_regulators,
-				pdata->num_regulators, NULL, irq_base);
+		ret = pm8018_add_regulators(pdata, pmic, irq_base);
 		if (ret) {
 			pr_err("Failed to add regulator subdevices ret=%d\n",
 				ret);
-			kfree(mfd_regulators);
 			goto bail;
 		}
-		pmic->mfd_regulators = mfd_regulators;
 	}
 
+
 	return 0;
 bail:
 	if (pmic->irq_chip) {
@@ -475,6 +580,8 @@
 err:
 	mfd_remove_devices(pmic->dev);
 	platform_set_drvdata(pdev, NULL);
+	kfree(pmic->mfd_regulators);
+	kfree(pmic->regulator_cdata);
 err_read_rev:
 	kfree(pmic);
 	return rc;
@@ -484,19 +591,27 @@
 {
 	struct pm8xxx_drvdata *drvdata;
 	struct pm8018 *pmic = NULL;
+	int i;
 
 	drvdata = platform_get_drvdata(pdev);
 	if (drvdata)
 		pmic = drvdata->pm_chip_data;
-	if (pmic)
-		mfd_remove_devices(pmic->dev);
-	if (pmic->irq_chip) {
-		pm8xxx_irq_exit(pmic->irq_chip);
-		pmic->irq_chip = NULL;
+	if (pmic) {
+		if (pmic->dev)
+			mfd_remove_devices(pmic->dev);
+		if (pmic->irq_chip) {
+			pm8xxx_irq_exit(pmic->irq_chip);
+			pmic->irq_chip = NULL;
+		}
+		if (pmic->mfd_regulators) {
+			for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
+				mutex_destroy(&regulator_data[i].pc_lock);
+		}
+		kfree(pmic->mfd_regulators);
+		kfree(pmic->regulator_cdata);
+		kfree(pmic);
 	}
 	platform_set_drvdata(pdev, NULL);
-	kfree(pmic->mfd_regulators);
-	kfree(pmic);
 
 	return 0;
 }
diff --git a/drivers/mfd/pm8038-core.c b/drivers/mfd/pm8038-core.c
index 9123067..f433456 100644
--- a/drivers/mfd/pm8038-core.c
+++ b/drivers/mfd/pm8038-core.c
@@ -17,10 +17,12 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/err.h>
+#include <linux/string.h>
 #include <linux/msm_ssbi.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/pm8xxx/pm8038.h>
 #include <linux/mfd/pm8xxx/core.h>
+#include <linux/mfd/pm8xxx/regulator.h>
 
 #define REG_HWREV		0x002  /* PMIC4 revision */
 #define REG_HWREV_2		0x0E8  /* PMIC4 revision 2 */
@@ -45,9 +47,11 @@
 }
 
 struct pm8038 {
-	struct device			*dev;
-	struct pm_irq_chip		*irq_chip;
-	u32				rev_registers;
+	struct device					*dev;
+	struct pm_irq_chip				*irq_chip;
+	struct mfd_cell					*mfd_regulators;
+	struct pm8xxx_regulator_core_platform_data	*regulator_cdata;
+	u32						rev_registers;
 };
 
 static int pm8038_readb(const struct device *dev, u16 addr, u8 *val)
@@ -200,6 +204,145 @@
 	.pdata_size	= sizeof("pm8038-dbg"),
 };
 
+static struct pm8xxx_vreg regulator_data[] = {
+	/*   name	     pc_name	    ctrl   test   hpm_min */
+	NLDO1200("8038_l1",		    0x0AE, 0x0AF, LDO_1200),
+	NLDO("8038_l2",      "8038_l2_pc",  0x0B0, 0x0B1, LDO_150),
+	PLDO("8038_l3",      "8038_l3_pc",  0x0B2, 0x0B3, LDO_50),
+	PLDO("8038_l4",      "8038_l4_pc",  0x0B4, 0x0B5, LDO_50),
+	PLDO("8038_l5",      "8038_l5_pc",  0x0B6, 0x0B7, LDO_600),
+	PLDO("8038_l6",      "8038_l6_pc",  0x0B8, 0x0B9, LDO_600),
+	PLDO("8038_l7",      "8038_l7_pc",  0x0BA, 0x0BB, LDO_600),
+	PLDO("8038_l8",      "8038_l8_pc",  0x0BC, 0x0BD, LDO_300),
+	PLDO("8038_l9",      "8038_l9_pc",  0x0BE, 0x0BF, LDO_300),
+	PLDO("8038_l10",     "8038_l10_pc", 0x0C0, 0x0C1, LDO_600),
+	PLDO("8038_l11",     "8038_l11_pc", 0x0C2, 0x0C3, LDO_600),
+	NLDO("8038_l12",     "8038_l12_pc", 0x0C4, 0x0C5, LDO_300),
+	PLDO("8038_l14",     "8038_l14_pc", 0x0C8, 0x0C9, LDO_50),
+	PLDO("8038_l15",     "8038_l15_pc", 0x0CA, 0x0CB, LDO_150),
+	NLDO1200("8038_l16",		    0x0CC, 0x0CD, LDO_1200),
+	PLDO("8038_l17",     "8038_l17_pc", 0x0CE, 0x0CF, LDO_150),
+	PLDO("8038_l18",     "8038_l18_pc", 0x0D0, 0x0D1, LDO_50),
+	NLDO1200("8038_l19",		    0x0D2, 0x0D3, LDO_1200),
+	NLDO1200("8038_l20",		    0x0D4, 0x0D5, LDO_1200),
+	PLDO("8038_l21",     "8038_l21_pc", 0x0D6, 0x0D7, LDO_150),
+	PLDO("8038_l22",     "8038_l22_pc", 0x0D8, 0x0D9, LDO_50),
+	PLDO("8038_l23",     "8038_l23_pc", 0x0DA, 0x0DB, LDO_50),
+	NLDO1200("8038_l24",		    0x0DC, 0x0DD, LDO_1200),
+	NLDO("8038_l26",     "8038_l26_pc", 0x0E0, 0x0E1, LDO_150),
+	NLDO1200("8038_l27",		    0x0E2, 0x0E3, LDO_1200),
+
+	/*   name	pc_name       ctrl   test2  clk    sleep  hpm_min */
+	SMPS("8038_s1", "8038_s1_pc", 0x1E0, 0x1E5, 0x009, 0x1E2, SMPS_1500),
+	SMPS("8038_s2", "8038_s2_pc", 0x1D8, 0x1DD, 0x00A, 0x1DA, SMPS_1500),
+	SMPS("8038_s3", "8038_s3_pc", 0x1D0, 0x1D5, 0x00B, 0x1D2, SMPS_1500),
+	SMPS("8038_s4", "8038_s4_pc", 0x1E8, 0x1ED, 0x00C, 0x1EA, SMPS_1500),
+
+	/*     name	  ctrl fts_cnfg1 pfm  pwr_cnfg  hpm_min */
+	FTSMPS("8038_s5", 0x025, 0x02E, 0x026, 0x032, SMPS_2000),
+	FTSMPS("8038_s6", 0x036, 0x03F, 0x037, 0x043, SMPS_2000),
+
+	/* name		       pc_name	       ctrl */
+	VS("8038_lvs1",        "8038_lvs1_pc", 0x060),
+	VS("8038_lvs2",        "8038_lvs2_pc", 0x062),
+};
+
+#define MAX_NAME_COMPARISON_LEN 32
+
+static int __devinit match_regulator(
+	struct pm8xxx_regulator_core_platform_data *core_data, char *name)
+{
+	int found = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(regulator_data); i++) {
+		if (regulator_data[i].rdesc.name
+		    && strncmp(regulator_data[i].rdesc.name, name,
+				MAX_NAME_COMPARISON_LEN) == 0) {
+			core_data->is_pin_controlled = false;
+			core_data->vreg = &regulator_data[i];
+			found = 1;
+			break;
+		} else if (regulator_data[i].rdesc_pc.name
+			   && strncmp(regulator_data[i].rdesc_pc.name, name,
+				MAX_NAME_COMPARISON_LEN) == 0) {
+			core_data->is_pin_controlled = true;
+			core_data->vreg = &regulator_data[i];
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found)
+		pr_err("could not find a match for regulator: %s\n", name);
+
+	return found;
+}
+
+static int __devinit
+pm8038_add_regulators(const struct pm8038_platform_data *pdata,
+		      struct pm8038 *pmic, int irq_base)
+{
+	int ret = 0;
+	struct mfd_cell *mfd_regulators;
+	struct pm8xxx_regulator_core_platform_data *cdata;
+	int i;
+
+	/* Add one device for each regulator used by the board. */
+	mfd_regulators = kzalloc(sizeof(struct mfd_cell)
+				 * (pdata->num_regulators), GFP_KERNEL);
+	if (!mfd_regulators) {
+		pr_err("Cannot allocate %d bytes for pm8038 regulator "
+			"mfd cells\n", sizeof(struct mfd_cell)
+					* (pdata->num_regulators));
+		return -ENOMEM;
+	}
+	cdata = kzalloc(sizeof(struct pm8xxx_regulator_core_platform_data)
+			* pdata->num_regulators, GFP_KERNEL);
+	if (!cdata) {
+		pr_err("Cannot allocate %d bytes for pm8038 regulator "
+			"core data\n", pdata->num_regulators
+			  * sizeof(struct pm8xxx_regulator_core_platform_data));
+		kfree(mfd_regulators);
+		return -ENOMEM;
+	}
+	for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
+		mutex_init(&regulator_data[i].pc_lock);
+
+	for (i = 0; i < pdata->num_regulators; i++) {
+		if (!pdata->regulator_pdatas[i].init_data.constraints.name) {
+			pr_err("name missing for regulator %d\n", i);
+			ret = -EINVAL;
+			goto bail;
+		}
+		if (!match_regulator(&cdata[i],
+		      pdata->regulator_pdatas[i].init_data.constraints.name)) {
+			ret = -ENODEV;
+			goto bail;
+		}
+		cdata[i].pdata = &(pdata->regulator_pdatas[i]);
+		mfd_regulators[i].name = PM8XXX_REGULATOR_DEV_NAME;
+		mfd_regulators[i].id = cdata[i].pdata->id;
+		mfd_regulators[i].platform_data = &cdata[i];
+		mfd_regulators[i].pdata_size =
+			sizeof(struct pm8xxx_regulator_core_platform_data);
+	}
+	ret = mfd_add_devices(pmic->dev, 0, mfd_regulators,
+			pdata->num_regulators, NULL, irq_base);
+	if (ret)
+		goto bail;
+
+	pmic->mfd_regulators = mfd_regulators;
+	pmic->regulator_cdata = cdata;
+	return ret;
+
+bail:
+	for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
+		mutex_destroy(&regulator_data[i].pc_lock);
+	kfree(mfd_regulators);
+	kfree(cdata);
+	return ret;
+}
 
 static int __devinit
 pm8038_add_subdevices(const struct pm8038_platform_data *pdata,
@@ -287,6 +430,15 @@
 		}
 	}
 
+	if (pdata->num_regulators > 0 && pdata->regulator_pdatas) {
+		ret = pm8038_add_regulators(pdata, pmic, irq_base);
+		if (ret) {
+			pr_err("Failed to add regulator subdevices ret=%d\n",
+				ret);
+			goto bail;
+		}
+	}
+
 	ret = mfd_add_devices(pmic->dev, 0, &debugfs_cell, 1, NULL, irq_base);
 	if (ret) {
 		pr_err("Failed to add debugfs subdevice ret=%d\n", ret);
@@ -395,6 +547,8 @@
 err:
 	mfd_remove_devices(pmic->dev);
 	platform_set_drvdata(pdev, NULL);
+	kfree(pmic->mfd_regulators);
+	kfree(pmic->regulator_cdata);
 err_read_rev:
 	kfree(pmic);
 	return rc;
@@ -404,6 +558,7 @@
 {
 	struct pm8xxx_drvdata *drvdata;
 	struct pm8038 *pmic = NULL;
+	int i;
 
 	drvdata = platform_get_drvdata(pdev);
 
@@ -418,7 +573,12 @@
 			pm8xxx_irq_exit(pmic->irq_chip);
 			pmic->irq_chip = NULL;
 		}
-
+		if (pmic->mfd_regulators) {
+			for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
+				mutex_destroy(&regulator_data[i].pc_lock);
+		}
+		kfree(pmic->mfd_regulators);
+		kfree(pmic->regulator_cdata);
 		kfree(pmic);
 	}
 
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c
index 373aaf7..3c4686f 100644
--- a/drivers/mfd/pm8921-core.c
+++ b/drivers/mfd/pm8921-core.c
@@ -16,11 +16,13 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <linux/string.h>
 #include <linux/err.h>
 #include <linux/msm_ssbi.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/pm8xxx/pm8921.h>
 #include <linux/mfd/pm8xxx/core.h>
+#include <linux/mfd/pm8xxx/regulator.h>
 #include <linux/leds-pm8xxx.h>
 
 #define REG_HWREV		0x002  /* PMIC4 revision */
@@ -55,10 +57,11 @@
 }
 
 struct pm8921 {
-	struct device			*dev;
-	struct pm_irq_chip		*irq_chip;
-	struct mfd_cell                 *mfd_regulators;
-	u32				rev_registers;
+	struct device					*dev;
+	struct pm_irq_chip				*irq_chip;
+	struct mfd_cell					*mfd_regulators;
+	struct pm8xxx_regulator_core_platform_data	*regulator_cdata;
+	u32						rev_registers;
 };
 
 static int pm8921_readb(const struct device *dev, u16 addr, u8 *val)
@@ -363,15 +366,168 @@
 	.id             = -1,
 };
 
+static struct pm8xxx_vreg regulator_data[] = {
+	/*   name	     pc_name	    ctrl   test   hpm_min */
+	NLDO("8921_l1",      "8921_l1_pc",  0x0AE, 0x0AF, LDO_150),
+	NLDO("8921_l2",      "8921_l2_pc",  0x0B0, 0x0B1, LDO_150),
+	PLDO("8921_l3",      "8921_l3_pc",  0x0B2, 0x0B3, LDO_150),
+	PLDO("8921_l4",      "8921_l4_pc",  0x0B4, 0x0B5, LDO_50),
+	PLDO("8921_l5",      "8921_l5_pc",  0x0B6, 0x0B7, LDO_300),
+	PLDO("8921_l6",      "8921_l6_pc",  0x0B8, 0x0B9, LDO_600),
+	PLDO("8921_l7",      "8921_l7_pc",  0x0BA, 0x0BB, LDO_150),
+	PLDO("8921_l8",      "8921_l8_pc",  0x0BC, 0x0BD, LDO_300),
+	PLDO("8921_l9",      "8921_l9_pc",  0x0BE, 0x0BF, LDO_300),
+	PLDO("8921_l10",     "8921_l10_pc", 0x0C0, 0x0C1, LDO_600),
+	PLDO("8921_l11",     "8921_l11_pc", 0x0C2, 0x0C3, LDO_150),
+	NLDO("8921_l12",     "8921_l12_pc", 0x0C4, 0x0C5, LDO_150),
+	PLDO("8921_l14",     "8921_l14_pc", 0x0C8, 0x0C9, LDO_50),
+	PLDO("8921_l15",     "8921_l15_pc", 0x0CA, 0x0CB, LDO_150),
+	PLDO("8921_l16",     "8921_l16_pc", 0x0CC, 0x0CD, LDO_300),
+	PLDO("8921_l17",     "8921_l17_pc", 0x0CE, 0x0CF, LDO_150),
+	NLDO("8921_l18",     "8921_l18_pc", 0x0D0, 0x0D1, LDO_150),
+	PLDO("8921_l21",     "8921_l21_pc", 0x0D6, 0x0D7, LDO_150),
+	PLDO("8921_l22",     "8921_l22_pc", 0x0D8, 0x0D9, LDO_150),
+	PLDO("8921_l23",     "8921_l23_pc", 0x0DA, 0x0DB, LDO_150),
+	NLDO1200("8921_l24",		    0x0DC, 0x0DD, LDO_1200),
+	NLDO1200("8921_l25",		    0x0DE, 0x0DF, LDO_1200),
+	NLDO1200("8921_l26",		    0x0E0, 0x0E1, LDO_1200),
+	NLDO1200("8921_l27",		    0x0E2, 0x0E3, LDO_1200),
+	NLDO1200("8921_l28",		    0x0E4, 0x0E5, LDO_1200),
+	PLDO("8921_l29",     "8921_l29_pc", 0x0E6, 0x0E7, LDO_150),
+
+	/*   name	pc_name       ctrl   test2  clk    sleep  hpm_min */
+	SMPS("8921_s1", "8921_s1_pc", 0x1D0, 0x1D5, 0x009, 0x1D2, SMPS_1500),
+	SMPS("8921_s2", "8921_s2_pc", 0x1D8, 0x1DD, 0x00A, 0x1DA, SMPS_1500),
+	SMPS("8921_s3", "8921_s3_pc", 0x1E0, 0x1E5, 0x00B, 0x1E2, SMPS_1500),
+	SMPS("8921_s4", "8921_s4_pc", 0x1E8, 0x1ED, 0x011, 0x1EA, SMPS_1500),
+
+	/*     name	  ctrl fts_cnfg1 pfm  pwr_cnfg  hpm_min */
+	FTSMPS("8921_s5", 0x025, 0x02E, 0x026, 0x032, SMPS_2000),
+	FTSMPS("8921_s6", 0x036, 0x03F, 0x037, 0x043, SMPS_2000),
+
+	/*   name	pc_name       ctrl   test2  clk    sleep  hpm_min */
+	SMPS("8921_s7", "8921_s7_pc", 0x1F0, 0x1F5, 0x012, 0x1F2, SMPS_1500),
+	SMPS("8921_s8", "8921_s8_pc", 0x1F8, 0x1FD, 0x013, 0x1FA, SMPS_1500),
+
+	/* name		       pc_name	       ctrl */
+	VS("8921_lvs1",        "8921_lvs1_pc", 0x060),
+	VS300("8921_lvs2",		       0x062),
+	VS("8921_lvs3",        "8921_lvs3_pc", 0x064),
+	VS("8921_lvs4",        "8921_lvs4_pc", 0x066),
+	VS("8921_lvs5",        "8921_lvs5_pc", 0x068),
+	VS("8921_lvs6",        "8921_lvs6_pc", 0x06A),
+	VS("8921_lvs7",        "8921_lvs7_pc", 0x06C),
+	VS300("8921_usb_otg",		       0x06E),
+	VS300("8921_hdmi_mvs",		       0x070),
+
+	/*  name	ctrl */
+	NCP("8921_ncp", 0x090),
+};
+
+#define MAX_NAME_COMPARISON_LEN 32
+
+static int __devinit match_regulator(
+	struct pm8xxx_regulator_core_platform_data *core_data, char *name)
+{
+	int found = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(regulator_data); i++) {
+		if (regulator_data[i].rdesc.name
+		    && strncmp(regulator_data[i].rdesc.name, name,
+				MAX_NAME_COMPARISON_LEN) == 0) {
+			core_data->is_pin_controlled = false;
+			core_data->vreg = &regulator_data[i];
+			found = 1;
+			break;
+		} else if (regulator_data[i].rdesc_pc.name
+			   && strncmp(regulator_data[i].rdesc_pc.name, name,
+				MAX_NAME_COMPARISON_LEN) == 0) {
+			core_data->is_pin_controlled = true;
+			core_data->vreg = &regulator_data[i];
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found)
+		pr_err("could not find a match for regulator: %s\n", name);
+
+	return found;
+}
+
+static int __devinit
+pm8921_add_regulators(const struct pm8921_platform_data *pdata,
+		      struct pm8921 *pmic, int irq_base)
+{
+	int ret = 0;
+	struct mfd_cell *mfd_regulators;
+	struct pm8xxx_regulator_core_platform_data *cdata;
+	int i;
+
+	/* Add one device for each regulator used by the board. */
+	mfd_regulators = kzalloc(sizeof(struct mfd_cell)
+				 * (pdata->num_regulators), GFP_KERNEL);
+	if (!mfd_regulators) {
+		pr_err("Cannot allocate %d bytes for pm8921 regulator "
+			"mfd cells\n", sizeof(struct mfd_cell)
+					* (pdata->num_regulators));
+		return -ENOMEM;
+	}
+	cdata = kzalloc(sizeof(struct pm8xxx_regulator_core_platform_data)
+			* pdata->num_regulators, GFP_KERNEL);
+	if (!cdata) {
+		pr_err("Cannot allocate %d bytes for pm8921 regulator "
+			"core data\n", pdata->num_regulators
+			  * sizeof(struct pm8xxx_regulator_core_platform_data));
+		kfree(mfd_regulators);
+		return -ENOMEM;
+	}
+	for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
+		mutex_init(&regulator_data[i].pc_lock);
+
+	for (i = 0; i < pdata->num_regulators; i++) {
+		if (!pdata->regulator_pdatas[i].init_data.constraints.name) {
+			pr_err("name missing for regulator %d\n", i);
+			ret = -EINVAL;
+			goto bail;
+		}
+		if (!match_regulator(&cdata[i],
+		      pdata->regulator_pdatas[i].init_data.constraints.name)) {
+			ret = -ENODEV;
+			goto bail;
+		}
+		cdata[i].pdata = &(pdata->regulator_pdatas[i]);
+		mfd_regulators[i].name = PM8XXX_REGULATOR_DEV_NAME;
+		mfd_regulators[i].id = cdata[i].pdata->id;
+		mfd_regulators[i].platform_data = &cdata[i];
+		mfd_regulators[i].pdata_size =
+			sizeof(struct pm8xxx_regulator_core_platform_data);
+	}
+	ret = mfd_add_devices(pmic->dev, 0, mfd_regulators,
+			pdata->num_regulators, NULL, irq_base);
+	if (ret)
+		goto bail;
+
+	pmic->mfd_regulators = mfd_regulators;
+	pmic->regulator_cdata = cdata;
+	return ret;
+
+bail:
+	for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
+		mutex_destroy(&regulator_data[i].pc_lock);
+	kfree(mfd_regulators);
+	kfree(cdata);
+	return ret;
+}
+
 static int __devinit
 pm8921_add_subdevices(const struct pm8921_platform_data *pdata,
 		      struct pm8921 *pmic)
 {
 	int ret = 0, irq_base = 0;
 	struct pm_irq_chip *irq_chip;
-	static struct mfd_cell *mfd_regulators;
 	enum pm8xxx_version version;
-	int i;
 
 	version = pm8xxx_get_version(pmic->dev);
 
@@ -495,34 +651,13 @@
 		}
 	}
 
-	/* Add one device for each regulator used by the board. */
 	if (pdata->num_regulators > 0 && pdata->regulator_pdatas) {
-		mfd_regulators = kzalloc(sizeof(struct mfd_cell)
-					 * (pdata->num_regulators), GFP_KERNEL);
-		if (!mfd_regulators) {
-			pr_err("Cannot allocate %d bytes for pm8921 regulator "
-				"mfd cells\n", sizeof(struct mfd_cell)
-						* (pdata->num_regulators));
-			ret = -ENOMEM;
-			goto bail;
-		}
-		for (i = 0; i < pdata->num_regulators; i++) {
-			mfd_regulators[i].name = PM8921_REGULATOR_DEV_NAME;
-			mfd_regulators[i].id = pdata->regulator_pdatas[i].id;
-			mfd_regulators[i].platform_data =
-				&(pdata->regulator_pdatas[i]);
-			mfd_regulators[i].pdata_size =
-				sizeof(struct pm8921_regulator_platform_data);
-		}
-		ret = mfd_add_devices(pmic->dev, 0, mfd_regulators,
-				pdata->num_regulators, NULL, irq_base);
+		ret = pm8921_add_regulators(pdata, pmic, irq_base);
 		if (ret) {
 			pr_err("Failed to add regulator subdevices ret=%d\n",
 				ret);
-			kfree(mfd_regulators);
 			goto bail;
 		}
-		pmic->mfd_regulators = mfd_regulators;
 	}
 
 	ret = mfd_add_devices(pmic->dev, 0, &debugfs_cell, 1, NULL, irq_base);
@@ -725,6 +860,8 @@
 err:
 	mfd_remove_devices(pmic->dev);
 	platform_set_drvdata(pdev, NULL);
+	kfree(pmic->mfd_regulators);
+	kfree(pmic->regulator_cdata);
 err_read_rev:
 	kfree(pmic);
 	return rc;
@@ -734,6 +871,7 @@
 {
 	struct pm8xxx_drvdata *drvdata;
 	struct pm8921 *pmic = NULL;
+	int i;
 
 	drvdata = platform_get_drvdata(pdev);
 	if (drvdata)
@@ -743,7 +881,12 @@
 			mfd_remove_devices(pmic->dev);
 		if (pmic->irq_chip)
 			pm8xxx_irq_exit(pmic->irq_chip);
+		if (pmic->mfd_regulators) {
+			for (i = 0; i < ARRAY_SIZE(regulator_data); i++)
+				mutex_destroy(&regulator_data[i].pc_lock);
+		}
 		kfree(pmic->mfd_regulators);
+		kfree(pmic->regulator_cdata);
 		kfree(pmic);
 	}
 	platform_set_drvdata(pdev, NULL);
diff --git a/drivers/mfd/pmic8058.c b/drivers/mfd/pmic8058.c
index 7c56dd6..814b59c 100644
--- a/drivers/mfd/pmic8058.c
+++ b/drivers/mfd/pmic8058.c
@@ -73,119 +73,8 @@
 	struct mfd_cell         *mfd_regulators, *mfd_xo_buffers;
 
 	u8		revision;
-
-	struct mutex	pm_lock;
 };
 
-static struct pm8058_chip *pmic_chip;
-
-static inline int
-ssbi_read(struct device *dev, u16 addr, u8 *buf, size_t len)
-{
-	return msm_ssbi_read(dev->parent, addr, buf, len);
-}
-
-static inline int
-ssbi_write(struct device *dev, u16 addr, u8 *buf, size_t len)
-{
-	return msm_ssbi_write(dev->parent, addr, buf, len);
-}
-
-/**
- * pm8058_stay_on - enables stay_on feature
- *
- * PMIC stay-on feature allows PMIC to ignore MSM PS_HOLD=low
- * signal so that some special functions like debugging could be
- * performed.
- *
- * This feature should not be used in any product release.
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_stay_on(void)
-{
-	u8	ctrl = 0x92;
-	int	rc;
-
-	rc = ssbi_write(pmic_chip->dev, SSBI_REG_ADDR_GP_TEST_1, &ctrl, 1);
-	pr_info("%s: set stay-on: rc = %d\n", __func__, rc);
-	return rc;
-}
-EXPORT_SYMBOL(pm8058_stay_on);
-
-/*
-   power on hard reset configuration
-   config = DISABLE_HARD_RESET to disable hard reset
-	  = SHUTDOWN_ON_HARD_RESET to turn off the system on hard reset
-	  = RESTART_ON_HARD_RESET to restart the system on hard reset
- */
-int pm8058_hard_reset_config(enum pon_config config)
-{
-	int rc, ret;
-	u8 pon, pon_5;
-
-	if (config >= MAX_PON_CONFIG)
-		return -EINVAL;
-
-	if (pmic_chip == NULL)
-		return -ENODEV;
-
-	mutex_lock(&pmic_chip->pm_lock);
-
-	rc = ssbi_read(pmic_chip->dev, SSBI_REG_ADDR_PON_CNTL_5, &pon, 1);
-	if (rc) {
-		pr_err("%s: FAIL ssbi_read(0x%x): rc=%d\n",
-		       __func__, SSBI_REG_ADDR_PON_CNTL_5, rc);
-		mutex_unlock(&pmic_chip->pm_lock);
-		return rc;
-	}
-
-	pon_5 = pon;
-	(config != DISABLE_HARD_RESET) ? (pon |= PM8058_HARD_RESET_EN_MASK) :
-					(pon &= ~PM8058_HARD_RESET_EN_MASK);
-
-	rc = ssbi_write(pmic_chip->dev, SSBI_REG_ADDR_PON_CNTL_5, &pon, 1);
-	if (rc) {
-		pr_err("%s: FAIL ssbi_write(0x%x)=0x%x: rc=%d\n",
-		       __func__, SSBI_REG_ADDR_PON_CNTL_5, pon, rc);
-		mutex_unlock(&pmic_chip->pm_lock);
-		return rc;
-	}
-
-	if (config == DISABLE_HARD_RESET) {
-		mutex_unlock(&pmic_chip->pm_lock);
-		return 0;
-	}
-
-	rc = ssbi_read(pmic_chip->dev, SSBI_REG_ADDR_PON_CNTL_4, &pon, 1);
-	if (rc) {
-		pr_err("%s: FAIL ssbi_read(0x%x): rc=%d\n",
-		       __func__, SSBI_REG_ADDR_PON_CNTL_4, rc);
-		goto err_restore_pon_5;
-	}
-
-	(config == RESTART_ON_HARD_RESET) ? (pon |= PM8058_PON_RESET_EN_MASK) :
-					(pon &= ~PM8058_PON_RESET_EN_MASK);
-
-	rc = ssbi_write(pmic_chip->dev, SSBI_REG_ADDR_PON_CNTL_4, &pon, 1);
-	if (rc) {
-		pr_err("%s: FAIL ssbi_write(0x%x)=0x%x: rc=%d\n",
-		       __func__, SSBI_REG_ADDR_PON_CNTL_4, pon, rc);
-		goto err_restore_pon_5;
-	}
-	mutex_unlock(&pmic_chip->pm_lock);
-	return 0;
-
-err_restore_pon_5:
-	ret = ssbi_write(pmic_chip->dev, SSBI_REG_ADDR_PON_CNTL_5, &pon_5, 1);
-	if (ret)
-		pr_err("%s: FAIL ssbi_write(0x%x)=0x%x: rc=%d\n",
-		       __func__, SSBI_REG_ADDR_PON_CNTL_5, pon, ret);
-	mutex_unlock(&pmic_chip->pm_lock);
-	return rc;
-}
-EXPORT_SYMBOL(pm8058_hard_reset_config);
-
 static int pm8058_readb(const struct device *dev, u16 addr, u8 *val)
 {
 	const struct pm8xxx_drvdata *pm8058_drvdata = dev_get_drvdata(dev);
@@ -823,9 +712,6 @@
 	pm8058_drvdata.pm_chip_data = pmic;
 	platform_set_drvdata(pdev, &pm8058_drvdata);
 
-	mutex_init(&pmic->pm_lock);
-	pmic_chip = pmic;
-
 	/* Read PMIC chip revision */
 	rc = pm8058_readb(pmic->dev, PM8058_REG_REV, &pmic->revision);
 	if (rc)
@@ -843,7 +729,7 @@
 		goto err;
 	}
 
-	rc = pm8058_hard_reset_config(SHUTDOWN_ON_HARD_RESET);
+	rc = pm8xxx_hard_reset_config(PM8XXX_SHUTDOWN_ON_HARD_RESET);
 	if (rc < 0)
 		pr_err("%s: failed to config shutdown on hard reset: %d\n",
 								__func__, rc);
@@ -870,7 +756,6 @@
 			mfd_remove_devices(pmic->dev);
 		if (pmic->irq_chip)
 			pm8xxx_irq_exit(pmic->irq_chip);
-		mutex_destroy(&pmic->pm_lock);
 		kfree(pmic->mfd_regulators);
 		kfree(pmic);
 	}
diff --git a/drivers/mfd/wcd9310-core.c b/drivers/mfd/wcd9310-core.c
index aabc2cc..4b81e99 100644
--- a/drivers/mfd/wcd9310-core.c
+++ b/drivers/mfd/wcd9310-core.c
@@ -27,6 +27,7 @@
 
 #define TABLA_SLIM_GLA_MAX_RETRIES 5
 #define TABLA_REGISTER_START_OFFSET 0x800
+#define TABLA_SLIM_RW_MAX_TRIES 3
 
 #define MAX_TABLA_DEVICE	4
 #define TABLA_I2C_MODE	0x03
@@ -183,21 +184,25 @@
 {
 	int ret;
 	struct slim_ele_access msg;
+	int slim_read_tries = TABLA_SLIM_RW_MAX_TRIES;
 	msg.start_offset = TABLA_REGISTER_START_OFFSET + reg;
 	msg.num_bytes = bytes;
 	msg.comp = NULL;
 
-	mutex_lock(&tabla->xfer_lock);
-	if (interface)
-		ret = slim_request_val_element(tabla->slim_slave, &msg, dest,
-			bytes);
-	else
-		ret = slim_request_val_element(tabla->slim, &msg, dest, bytes);
+	while (1) {
+		mutex_lock(&tabla->xfer_lock);
+		ret = slim_request_val_element(interface ?
+					       tabla->slim_slave : tabla->slim,
+					       &msg, dest, bytes);
+		mutex_unlock(&tabla->xfer_lock);
+		if (likely(ret == 0) || (--slim_read_tries == 0))
+			break;
+		usleep_range(5000, 5000);
+	}
 
 	if (ret)
-		pr_err("%s: Error, Tabla read failed\n", __func__);
+		pr_err("%s: Error, Tabla read failed (%d)\n", __func__, ret);
 
-	mutex_unlock(&tabla->xfer_lock);
 	return ret;
 }
 /* Interface specifies whether the write is to the interface or general
@@ -208,20 +213,25 @@
 {
 	int ret;
 	struct slim_ele_access msg;
+	int slim_write_tries = TABLA_SLIM_RW_MAX_TRIES;
 	msg.start_offset = TABLA_REGISTER_START_OFFSET + reg;
 	msg.num_bytes = bytes;
 	msg.comp = NULL;
 
-	mutex_lock(&tabla->xfer_lock);
-	if (interface)
-		ret = slim_change_val_element(tabla->slim_slave, &msg, src,
-			bytes);
-	else
-		ret = slim_change_val_element(tabla->slim, &msg, src, bytes);
-	if (ret)
-		pr_err("%s: Error, Tabla write failed\n", __func__);
+	while (1) {
+		mutex_lock(&tabla->xfer_lock);
+		ret = slim_change_val_element(interface ?
+					      tabla->slim_slave : tabla->slim,
+					      &msg, src, bytes);
+		mutex_unlock(&tabla->xfer_lock);
+		if (likely(ret == 0) || (--slim_write_tries == 0))
+			break;
+		usleep_range(5000, 5000);
+	}
 
-	mutex_unlock(&tabla->xfer_lock);
+	if (ret)
+		pr_err("%s: Error, Tabla write failed (%d)\n", __func__, ret);
+
 	return ret;
 }
 
diff --git a/drivers/mfd/wcd9310-irq.c b/drivers/mfd/wcd9310-irq.c
index 9cc4761..fef1323 100644
--- a/drivers/mfd/wcd9310-irq.c
+++ b/drivers/mfd/wcd9310-irq.c
@@ -189,17 +189,37 @@
 	ret = request_threaded_irq(tabla->irq, NULL, tabla_irq_thread,
 				   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
 				   "tabla", tabla);
-
-	if (ret != 0) {
+	if (ret != 0)
 		dev_err(tabla->dev, "Failed to request IRQ %d: %d\n",
 			tabla->irq, ret);
-		return ret;
+	else {
+		ret = enable_irq_wake(tabla->irq);
+		if (ret == 0) {
+			ret = device_init_wakeup(tabla->dev, 1);
+			if (ret) {
+				dev_err(tabla->dev, "Failed to init device"
+					"wakeup : %d\n", ret);
+				disable_irq_wake(tabla->irq);
+			}
+		} else
+			dev_err(tabla->dev, "Failed to set wake interrupt on"
+				" IRQ %d: %d\n", tabla->irq, ret);
+		if (ret)
+			free_irq(tabla->irq, tabla);
 	}
-	return 0;
+
+	if (ret)
+		mutex_destroy(&tabla->irq_lock);
+
+	return ret;
 }
+
 void tabla_irq_exit(struct tabla *tabla)
 {
-	if (tabla->irq)
+	if (tabla->irq) {
+		disable_irq_wake(tabla->irq);
 		free_irq(tabla->irq, tabla);
+		device_init_wakeup(tabla->dev, 0);
+	}
 	mutex_destroy(&tabla->irq_lock);
 }
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 0c579e2..43eb169 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -561,6 +561,14 @@
 	---help---
 	  This turns on debugging information for the tsif driver
 
+config TSPP
+	depends on ARCH_MSM
+	tristate "TSPP (Transport Stream Packet Processor) Support"
+	---help---
+	Transport Stream Packet Processor is used to offload the
+	processing of MPEG transport streams from the main processor.
+	This can also be compiled as a loadable module.
+
 config HAPTIC_ISA1200
 	tristate "ISA1200 haptic support"
 	depends on I2C
@@ -578,14 +586,6 @@
 	  purposes including software controlled brightness of backlight,
 	  motor control, and waveform generation.
 
-config PMIC8058_VIBRATOR
-	tristate "Qualcomm PM8058 vibrator support"
-	depends on PMIC8058 && ANDROID_TIMED_OUTPUT
-	default n
-	help
-	  This option enables device driver support for the vibrator
-	  on Qualcomm PM8058 chip.
-
 config PMIC8XXX_VIBRATOR
 	tristate "Qualcomm Vibrator support for PMIC8XXX"
 	depends on MFD_PM8XXX && ANDROID_TIMED_OUTPUT
@@ -619,23 +619,6 @@
 	  PMIC8058. Driver interface to program registers of the ADC over
 	  AMUX channels, devices on programmable MPP's and xotherm.
 
-config PMIC8058_MISC
-	tristate "Qualcomm PM8058 Misc Device driver"
-	depends on PMIC8058
-	default n
-	help
-	  Provides functionality for various small drivers utilizing the
-	  Qualcomm PM8058 chip.  Examples include: signalling when the 32kHz
-	  oscillator malfunctions.
-
-config PMIC8058_BATTALARM
-	tristate "Qualcomm PM8058 Battery Alarm Device driver"
-	depends on PMIC8058
-	help
-	  This option enables support for the battery alarm module on the
-	  Qualcomm PM8058 PMIC chip.  This support allows for configuration of
-	  the alarm module as well as interrupt handling.
-
 config TZCOM
 	tristate "Trustzone Communicator driver"
 	default n
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 385f8ff..6b5fdcc 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -54,16 +54,14 @@
 obj-$(CONFIG_TSIF) += msm_tsif.o
 msm_tsif-objs := tsif.o
 obj-$(CONFIG_TSIF_CHRDEV) += tsif_chrdev.o
+obj-$(CONFIG_TSPP) += tspp.o
 obj-$(CONFIG_HAPTIC_ISA1200)		+= isa1200.o
 obj-$(CONFIG_PMIC8058_PWM) += pmic8058-pwm.o
-obj-$(CONFIG_PMIC8058_VIBRATOR) += pmic8058-vibrator.o
 obj-$(CONFIG_PMIC8XXX_VIBRATOR) += pm8xxx-vibrator.o
 obj-$(CONFIG_PMIC8XXX_NFC) += pm8xxx-nfc.o
 obj-$(CONFIG_PMIC8XXX_UPL) += pm8xxx-upl.o
 obj-$(CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_DEEP_POWER_DOWN) \
 	+= msm_migrate_pages.o
 obj-$(CONFIG_PMIC8058_XOADC) += pmic8058-xoadc.o
-obj-$(CONFIG_PMIC8058_MISC) += pmic8058-misc.o
-obj-$(CONFIG_PMIC8058_BATTALARM) += pmic8058-batt-alarm.o
 obj-$(CONFIG_TZCOM) += tzcom.o
 obj-$(CONFIG_QFP_FUSE) += qfp_fuse.o
diff --git a/drivers/misc/pmem.c b/drivers/misc/pmem.c
index 692849a..7ee7c11 100644
--- a/drivers/misc/pmem.c
+++ b/drivers/misc/pmem.c
@@ -18,6 +18,7 @@
 #include <linux/platform_device.h>
 #include <linux/fs.h>
 #include <linux/file.h>
+#include <linux/fmem.h>
 #include <linux/mm.h>
 #include <linux/list.h>
 #include <linux/debugfs.h>
@@ -229,12 +230,12 @@
 	 * request function for a region when the allocation count goes
 	 * from 0 -> 1
 	 */
-	void (*mem_request)(void *);
+	int (*mem_request)(void *);
 	/*
 	 * release function for a region when the allocation count goes
 	 * from 1 -> 0
 	 */
-	void (*mem_release)(void *);
+	int (*mem_release)(void *);
 	/*
 	 * private data for the request/release callback
 	 */
@@ -243,6 +244,10 @@
 	 * map and unmap as needed
 	 */
 	int map_on_demand;
+	/*
+	 * memory will be reused through fmem
+	 */
+	int reusable;
 };
 #define to_pmem_info_id(a) (container_of(a, struct pmem_info, kobj)->id)
 
@@ -582,8 +587,13 @@
 	atomic_inc(&pmem[id].allocation_cnt);
 	if (!pmem[id].vbase) {
 		DLOG("PMEMDEBUG: mapping for %s", pmem[id].name);
-		if (pmem[id].mem_request)
-				pmem[id].mem_request(pmem[id].region_data);
+		if (pmem[id].mem_request) {
+			int ret = pmem[id].mem_request(pmem[id].region_data);
+			if (ret) {
+				atomic_dec(&pmem[id].allocation_cnt);
+				return 1;
+			}
+		}
 		ioremap_pmem(id);
 	}
 
@@ -610,8 +620,11 @@
 			unmap_kernel_range((unsigned long)pmem[id].vbase,
 				 pmem[id].size);
 			pmem[id].vbase = NULL;
-			if (pmem[id].mem_release)
-				pmem[id].mem_release(pmem[id].region_data);
+			if (pmem[id].mem_release) {
+				int ret = pmem[id].mem_release(
+						pmem[id].region_data);
+				WARN(ret, "mem_release failed");
+			}
 
 		}
 	}
@@ -2785,19 +2798,26 @@
 	pr_info("allocating %lu bytes at %p (%lx physical) for %s\n",
 		pmem[id].size, pmem[id].vbase, pmem[id].base, pmem[id].name);
 
-	pmem[id].map_on_demand = pdata->map_on_demand;
+	pmem[id].reusable = pdata->reusable;
+	/* reusable pmem requires map on demand */
+	pmem[id].map_on_demand = pdata->map_on_demand || pdata->reusable;
 	if (pmem[id].map_on_demand) {
-		pmem_vma = get_vm_area(pmem[id].size, VM_IOREMAP);
-		if (!pmem_vma) {
-			pr_err("pmem: Failed to allocate virtual space for "
+		if (pmem[id].reusable) {
+			const struct fmem_data *fmem_info = fmem_get_info();
+			pmem[id].area = fmem_info->area;
+		} else {
+			pmem_vma = get_vm_area(pmem[id].size, VM_IOREMAP);
+			if (!pmem_vma) {
+				pr_err("pmem: Failed to allocate virtual space for "
 					"%s\n", pdata->name);
-			goto out_put_kobj;
-		}
-		pr_err("pmem: Reserving virtual address range %lx - %lx for"
+				goto out_put_kobj;
+			}
+			pr_err("pmem: Reserving virtual address range %lx - %lx for"
 				" %s\n", (unsigned long) pmem_vma->addr,
 				(unsigned long) pmem_vma->addr + pmem[id].size,
 				pdata->name);
-		pmem[id].area = pmem_vma;
+			pmem[id].area = pmem_vma;
+		}
 	} else
 		pmem[id].area = NULL;
 
diff --git a/drivers/misc/pmic8058-batt-alarm.c b/drivers/misc/pmic8058-batt-alarm.c
deleted file mode 100644
index bff0720..0000000
--- a/drivers/misc/pmic8058-batt-alarm.c
+++ /dev/null
@@ -1,753 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. 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 version 2 and
- * only 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.
- */
-/*
- * Qualcomm PMIC 8058 Battery Alarm Device driver
- *
- */
-
-#define pr_fmt(fmt)	"%s: " fmt, __func__
-
-#include <linux/err.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/notifier.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/pmic8058-batt-alarm.h>
-#include <linux/mfd/pmic8058.h>
-
-/* PMIC 8058 Battery Alarm SSBI registers */
-#define	REG_THRESHOLD			0x023
-#define	REG_CTRL1			0x024
-#define	REG_CTRL2			0x0AA
-#define	REG_PWM_CTRL			0x0A3
-
-/* Available voltage threshold values */
-#define THRESHOLD_MIN_MV		2500
-#define THRESHOLD_MAX_MV		5675
-#define THRESHOLD_STEP_MV		25
-
-/* Register bit definitions */
-
-/* Threshold register */
-#define THRESHOLD_UPPER_MASK		0xF0
-#define THRESHOLD_LOWER_MASK		0x0F
-#define THRESHOLD_UPPER_SHIFT		4
-#define THRESHOLD_LOWER_SHIFT		0
-
-/* CTRL 1 register */
-#define CTRL1_BATT_ALARM_EN_MASK	0x80
-#define CTRL1_HOLD_TIME_MASK		0x70
-#define CTRL1_STATUS_UPPER_MASK		0x02
-#define CTRL1_STATUS_LOWER_MASK		0x01
-#define CTRL1_HOLD_TIME_SHIFT		4
-#define CTRL1_HOLD_TIME_MIN		0
-#define CTRL1_HOLD_TIME_MAX		7
-
-/* CTRL 2 register */
-#define CTRL2_COMP_UPPER_DISABLE_MASK	0x80
-#define CTRL2_COMP_LOWER_DISABLE_MASK	0x40
-#define CTRL2_FINE_STEP_UPPER_MASK	0x30
-#define CTRL2_RANGE_EXT_UPPER_MASK	0x08
-#define CTRL2_FINE_STEP_LOWER_MASK	0x06
-#define CTRL2_RANGE_EXT_LOWER_MASK	0x01
-#define CTRL2_FINE_STEP_UPPER_SHIFT	4
-#define CTRL2_FINE_STEP_LOWER_SHIFT	1
-
-/* PWM control register */
-#define PWM_CTRL_ALARM_EN_MASK		0xC0
-#define PWM_CTRL_ALARM_EN_NEVER		0x00
-#define PWM_CTRL_ALARM_EN_TCXO		0x40
-#define PWM_CTRL_ALARM_EN_PWM		0x80
-#define PWM_CTRL_ALARM_EN_ALWAYS	0xC0
-#define PWM_CTRL_PRE_MASK		0x38
-#define PWM_CTRL_DIV_MASK		0x07
-#define PWM_CTRL_PRE_SHIFT		3
-#define PWM_CTRL_DIV_SHIFT		0
-#define PWM_CTRL_PRE_MIN		0
-#define PWM_CTRL_PRE_MAX		7
-#define PWM_CTRL_DIV_MIN		1
-#define PWM_CTRL_DIV_MAX		7
-
-/* PWM control input range */
-#define PWM_CTRL_PRE_INPUT_MIN		2
-#define PWM_CTRL_PRE_INPUT_MAX		9
-#define PWM_CTRL_DIV_INPUT_MIN		2
-#define PWM_CTRL_DIV_INPUT_MAX		8
-
-/* Available voltage threshold values */
-#define THRESHOLD_BASIC_MIN_MV		2800
-#define THRESHOLD_EXT_MIN_MV		4400
-
-/*
- * Default values used during initialization:
- * Slowest PWM rate to ensure minimal status jittering when crossing thresholds.
- * Largest hold time also helps reduce status value jittering.  Comparators
- * are disabled by default and must be turned on by calling
- * pm8058_batt_alarm_state_set.
- */
-#define DEFAULT_THRESHOLD_LOWER		3200
-#define DEFAULT_THRESHOLD_UPPER		4300
-#define DEFAULT_HOLD_TIME		PM8058_BATT_ALARM_HOLD_TIME_16_MS
-#define DEFAULT_USE_PWM			1
-#define DEFAULT_PWM_SCALER		9
-#define DEFAULT_PWM_DIVIDER		8
-#define DEFAULT_LOWER_ENABLE		0
-#define DEFAULT_UPPER_ENABLE		0
-
-struct pm8058_batt_alarm_device {
-	struct srcu_notifier_head		irq_notifier_list;
-	struct pm8058_chip			*pm_chip;
-	struct mutex				batt_mutex;
-	unsigned int				irq;
-	int					notifier_count;
-	u8					reg_threshold;
-	u8					reg_ctrl1;
-	u8					reg_ctrl2;
-	u8					reg_pwm_ctrl;
-};
-static struct pm8058_batt_alarm_device *the_battalarm;
-
-static int pm8058_reg_write(struct pm8058_chip *chip, u16 addr, u8 val, u8 mask,
-			    u8 *reg_save)
-{
-	int rc = 0;
-	u8 reg;
-
-	reg = (*reg_save & ~mask) | (val & mask);
-	if (reg != *reg_save)
-		rc = pm8058_write(chip, addr, &reg, 1);
-	if (rc)
-		pr_err("pm8058_write failed; addr=%03X, rc=%d\n", addr, rc);
-	else
-		*reg_save = reg;
-	return rc;
-}
-
-/**
- * pm8058_batt_alarm_state_set - enable or disable the threshold comparators
- * @enable_lower_comparator: 1 = enable comparator, 0 = disable comparator
- * @enable_upper_comparator: 1 = enable comparator, 0 = disable comparator
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_batt_alarm_state_set(int enable_lower_comparator,
-				int enable_upper_comparator)
-{
-	struct pm8058_batt_alarm_device *battdev = the_battalarm;
-	int rc;
-	u8 reg_ctrl1 = 0, reg_ctrl2 = 0;
-
-	if (!battdev) {
-		pr_err("no battery alarm device found.\n");
-		return -ENXIO;
-	}
-
-	if (!enable_lower_comparator)
-		reg_ctrl2 |= CTRL2_COMP_LOWER_DISABLE_MASK;
-	if (!enable_upper_comparator)
-		reg_ctrl2 |= CTRL2_COMP_UPPER_DISABLE_MASK;
-
-	if (enable_lower_comparator || enable_upper_comparator)
-		reg_ctrl1 = CTRL1_BATT_ALARM_EN_MASK;
-
-	mutex_lock(&battdev->batt_mutex);
-	rc = pm8058_reg_write(battdev->pm_chip, REG_CTRL1, reg_ctrl1,
-				CTRL1_BATT_ALARM_EN_MASK, &battdev->reg_ctrl1);
-	if (rc)
-		goto bail;
-
-	rc = pm8058_reg_write(battdev->pm_chip, REG_CTRL2, reg_ctrl2,
-		CTRL2_COMP_LOWER_DISABLE_MASK | CTRL2_COMP_UPPER_DISABLE_MASK,
-		&battdev->reg_ctrl2);
-
-bail:
-	mutex_unlock(&battdev->batt_mutex);
-	return rc;
-}
-EXPORT_SYMBOL_GPL(pm8058_batt_alarm_state_set);
-
-/**
- * pm8058_batt_alarm_threshold_set - set the lower and upper alarm thresholds
- * @lower_threshold_mV: battery undervoltage threshold in millivolts
- * @upper_threshold_mV: battery overvoltage threshold in millivolts
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_batt_alarm_threshold_set(int lower_threshold_mV,
-				    int upper_threshold_mV)
-{
-	struct pm8058_batt_alarm_device *battdev = the_battalarm;
-	int step, fine_step, rc;
-	u8 reg_threshold = 0, reg_ctrl2 = 0;
-
-	if (!battdev) {
-		pr_err("no battery alarm device found.\n");
-		return -ENXIO;
-	}
-
-	if (lower_threshold_mV < THRESHOLD_MIN_MV
-	    || lower_threshold_mV > THRESHOLD_MAX_MV) {
-		pr_err("lower threshold value, %d mV, is outside of allowable "
-			"range: [%d, %d] mV\n", lower_threshold_mV,
-			THRESHOLD_MIN_MV, THRESHOLD_MAX_MV);
-		return -EINVAL;
-	}
-
-	if (upper_threshold_mV < THRESHOLD_MIN_MV
-	    || upper_threshold_mV > THRESHOLD_MAX_MV) {
-		pr_err("upper threshold value, %d mV, is outside of allowable "
-			"range: [%d, %d] mV\n", upper_threshold_mV,
-			THRESHOLD_MIN_MV, THRESHOLD_MAX_MV);
-		return -EINVAL;
-	}
-
-	if (upper_threshold_mV < lower_threshold_mV) {
-		pr_err("lower threshold value, %d mV, must be <= upper "
-			"threshold value, %d mV\n", lower_threshold_mV,
-			upper_threshold_mV);
-		return -EINVAL;
-	}
-
-	/* Determine register settings for lower threshold. */
-	if (lower_threshold_mV < THRESHOLD_BASIC_MIN_MV) {
-		/* Extended low range */
-		reg_ctrl2 |= CTRL2_RANGE_EXT_LOWER_MASK;
-
-		step = (lower_threshold_mV - THRESHOLD_MIN_MV)
-			/ THRESHOLD_STEP_MV;
-
-		fine_step = step & 0x3;
-		/* Extended low range is for steps 0 to 2 */
-		step >>= 2;
-
-		reg_threshold |= (step << THRESHOLD_LOWER_SHIFT)
-				 & THRESHOLD_LOWER_MASK;
-		reg_ctrl2 |= (fine_step << CTRL2_FINE_STEP_LOWER_SHIFT)
-			     & CTRL2_FINE_STEP_LOWER_MASK;
-	} else if (lower_threshold_mV >= THRESHOLD_EXT_MIN_MV) {
-		/* Extended high range */
-		reg_ctrl2 |= CTRL2_RANGE_EXT_LOWER_MASK;
-
-		step = (lower_threshold_mV - THRESHOLD_EXT_MIN_MV)
-			/ THRESHOLD_STEP_MV;
-
-		fine_step = step & 0x3;
-		/* Extended high range is for steps 3 to 15 */
-		step = (step >> 2) + 3;
-
-		reg_threshold |= (step << THRESHOLD_LOWER_SHIFT)
-				 & THRESHOLD_LOWER_MASK;
-		reg_ctrl2 |= (fine_step << CTRL2_FINE_STEP_LOWER_SHIFT)
-			     & CTRL2_FINE_STEP_LOWER_MASK;
-	} else {
-		/* Basic range */
-		step = (lower_threshold_mV - THRESHOLD_BASIC_MIN_MV)
-			/ THRESHOLD_STEP_MV;
-
-		fine_step = step & 0x3;
-		step >>= 2;
-
-		reg_threshold |= (step << THRESHOLD_LOWER_SHIFT)
-				 & THRESHOLD_LOWER_MASK;
-		reg_ctrl2 |= (fine_step << CTRL2_FINE_STEP_LOWER_SHIFT)
-			     & CTRL2_FINE_STEP_LOWER_MASK;
-	}
-
-	/* Determine register settings for upper threshold. */
-	if (upper_threshold_mV < THRESHOLD_BASIC_MIN_MV) {
-		/* Extended low range */
-		reg_ctrl2 |= CTRL2_RANGE_EXT_UPPER_MASK;
-
-		step = (upper_threshold_mV - THRESHOLD_MIN_MV)
-			/ THRESHOLD_STEP_MV;
-
-		fine_step = step & 0x3;
-		/* Extended low range is for steps 0 to 2 */
-		step >>= 2;
-
-		reg_threshold |= (step << THRESHOLD_UPPER_SHIFT)
-				 & THRESHOLD_UPPER_MASK;
-		reg_ctrl2 |= (fine_step << CTRL2_FINE_STEP_UPPER_SHIFT)
-			     & CTRL2_FINE_STEP_UPPER_MASK;
-	} else if (upper_threshold_mV >= THRESHOLD_EXT_MIN_MV) {
-		/* Extended high range */
-		reg_ctrl2 |= CTRL2_RANGE_EXT_UPPER_MASK;
-
-		step = (upper_threshold_mV - THRESHOLD_EXT_MIN_MV)
-			/ THRESHOLD_STEP_MV;
-
-		fine_step = step & 0x3;
-		/* Extended high range is for steps 3 to 15 */
-		step = (step >> 2) + 3;
-
-		reg_threshold |= (step << THRESHOLD_UPPER_SHIFT)
-				 & THRESHOLD_UPPER_MASK;
-		reg_ctrl2 |= (fine_step << CTRL2_FINE_STEP_UPPER_SHIFT)
-			     & CTRL2_FINE_STEP_UPPER_MASK;
-	} else {
-		/* Basic range */
-		step = (upper_threshold_mV - THRESHOLD_BASIC_MIN_MV)
-			/ THRESHOLD_STEP_MV;
-
-		fine_step = step & 0x3;
-		step >>= 2;
-
-		reg_threshold |= (step << THRESHOLD_UPPER_SHIFT)
-				 & THRESHOLD_UPPER_MASK;
-		reg_ctrl2 |= (fine_step << CTRL2_FINE_STEP_UPPER_SHIFT)
-			     & CTRL2_FINE_STEP_UPPER_MASK;
-	}
-
-	mutex_lock(&battdev->batt_mutex);
-	rc = pm8058_reg_write(battdev->pm_chip, REG_THRESHOLD, reg_threshold,
-				THRESHOLD_LOWER_MASK | THRESHOLD_UPPER_MASK,
-				&battdev->reg_threshold);
-	if (rc)
-		goto bail;
-
-	rc = pm8058_reg_write(battdev->pm_chip, REG_CTRL2, reg_ctrl2,
-		CTRL2_FINE_STEP_LOWER_MASK | CTRL2_FINE_STEP_UPPER_MASK
-		  | CTRL2_RANGE_EXT_LOWER_MASK | CTRL2_RANGE_EXT_UPPER_MASK,
-		&battdev->reg_ctrl2);
-
-bail:
-	mutex_unlock(&battdev->batt_mutex);
-	return rc;
-}
-EXPORT_SYMBOL_GPL(pm8058_batt_alarm_threshold_set);
-
-/**
- * pm8058_batt_alarm_status_read - get status of both threshold comparators
- *
- * RETURNS:	< 0	   = error
- *		  0	   = battery voltage ok
- *		BIT(0) set = battery voltage below lower threshold
- *		BIT(1) set = battery voltage above upper threshold
- */
-int pm8058_batt_alarm_status_read(void)
-{
-	struct pm8058_batt_alarm_device *battdev = the_battalarm;
-	int status, rc;
-
-	if (!battdev) {
-		pr_err("no battery alarm device found.\n");
-		return -ENXIO;
-	}
-
-	mutex_lock(&battdev->batt_mutex);
-	rc = pm8058_read(battdev->pm_chip, REG_CTRL1, &battdev->reg_ctrl1, 1);
-
-	status = ((battdev->reg_ctrl1 & CTRL1_STATUS_LOWER_MASK)
-			? PM8058_BATT_ALARM_STATUS_BELOW_LOWER : 0)
-		| ((battdev->reg_ctrl1 & CTRL1_STATUS_UPPER_MASK)
-			? PM8058_BATT_ALARM_STATUS_ABOVE_UPPER : 0);
-	mutex_unlock(&battdev->batt_mutex);
-
-	if (rc) {
-		pr_err("pm8058_read failed, rc=%d\n", rc);
-		return rc;
-	}
-
-	return status;
-}
-EXPORT_SYMBOL_GPL(pm8058_batt_alarm_status_read);
-
-/**
- * pm8058_batt_alarm_hold_time_set - set hold time of interrupt output *
- * @hold_time:	amount of time that battery voltage must remain outside of the
- *		threshold range before the battery alarm interrupt triggers
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_batt_alarm_hold_time_set(enum pm8058_batt_alarm_hold_time hold_time)
-{
-	struct pm8058_batt_alarm_device *battdev = the_battalarm;
-	int rc;
-	u8 reg_ctrl1 = 0;
-
-	if (!battdev) {
-		pr_err("no battery alarm device found.\n");
-		return -ENXIO;
-	}
-
-	if (hold_time < CTRL1_HOLD_TIME_MIN
-	    || hold_time > CTRL1_HOLD_TIME_MAX) {
-
-		pr_err("hold time, %d, is outside of allowable range: "
-			"[%d, %d]\n", hold_time, CTRL1_HOLD_TIME_MIN,
-			CTRL1_HOLD_TIME_MAX);
-		return -EINVAL;
-	}
-
-	reg_ctrl1 = hold_time << CTRL1_HOLD_TIME_SHIFT;
-
-	mutex_lock(&battdev->batt_mutex);
-	rc = pm8058_reg_write(battdev->pm_chip, REG_CTRL1, reg_ctrl1,
-			      CTRL1_HOLD_TIME_MASK, &battdev->reg_ctrl1);
-	mutex_unlock(&battdev->batt_mutex);
-
-	return rc;
-}
-EXPORT_SYMBOL_GPL(pm8058_batt_alarm_hold_time_set);
-
-/**
- * pm8058_batt_alarm_pwm_rate_set - set battery alarm update rate *
- * @use_pwm:		1 = use PWM update rate, 0 = comparators always active
- * @clock_scaler:	PWM clock scaler = 2 to 9
- * @clock_divider:	PWM clock divider = 2 to 8
- *
- * This function sets the rate at which the battery alarm module enables
- * the threshold comparators.  The rate is determined by the following equation:
- *
- * f_update = (1024 Hz) / (clock_divider * (2 ^ clock_scaler))
- *
- * Thus, the update rate can range from 0.25 Hz to 128 Hz.
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_batt_alarm_pwm_rate_set(int use_pwm, int clock_scaler,
-				   int clock_divider)
-{
-	struct pm8058_batt_alarm_device *battdev = the_battalarm;
-	int rc;
-	u8 reg_pwm_ctrl = 0, mask = 0;
-
-	if (!battdev) {
-		pr_err("no battery alarm device found.\n");
-		return -ENXIO;
-	}
-
-	if (use_pwm && (clock_scaler < PWM_CTRL_PRE_INPUT_MIN
-	    || clock_scaler > PWM_CTRL_PRE_INPUT_MAX)) {
-		pr_err("PWM clock scaler, %d, is outside of allowable range: "
-			"[%d, %d]\n", clock_scaler, PWM_CTRL_PRE_INPUT_MIN,
-			PWM_CTRL_PRE_INPUT_MAX);
-		return -EINVAL;
-	}
-
-	if (use_pwm && (clock_divider < PWM_CTRL_DIV_INPUT_MIN
-	    || clock_divider > PWM_CTRL_DIV_INPUT_MAX)) {
-		pr_err("PWM clock divider, %d, is outside of allowable range: "
-			"[%d, %d]\n", clock_divider, PWM_CTRL_DIV_INPUT_MIN,
-			PWM_CTRL_DIV_INPUT_MAX);
-		return -EINVAL;
-	}
-
-	if (!use_pwm) {
-		/* Turn off PWM control and always enable. */
-		reg_pwm_ctrl = PWM_CTRL_ALARM_EN_ALWAYS;
-		mask = PWM_CTRL_ALARM_EN_MASK;
-	} else {
-		/* Use PWM control. */
-		reg_pwm_ctrl = PWM_CTRL_ALARM_EN_PWM;
-		mask = PWM_CTRL_ALARM_EN_MASK | PWM_CTRL_PRE_MASK
-			| PWM_CTRL_DIV_MASK;
-
-		clock_scaler -= PWM_CTRL_PRE_INPUT_MIN - PWM_CTRL_PRE_MIN;
-		clock_divider -= PWM_CTRL_DIV_INPUT_MIN - PWM_CTRL_DIV_MIN;
-
-		reg_pwm_ctrl |= (clock_scaler << PWM_CTRL_PRE_SHIFT)
-				& PWM_CTRL_PRE_MASK;
-		reg_pwm_ctrl |= (clock_divider << PWM_CTRL_DIV_SHIFT)
-				& PWM_CTRL_DIV_MASK;
-	}
-
-	mutex_lock(&battdev->batt_mutex);
-	rc = pm8058_reg_write(battdev->pm_chip, REG_PWM_CTRL, reg_pwm_ctrl,
-			      mask, &battdev->reg_pwm_ctrl);
-	mutex_unlock(&battdev->batt_mutex);
-
-	return rc;
-}
-EXPORT_SYMBOL_GPL(pm8058_batt_alarm_pwm_rate_set);
-
-/*
- * Handle the BATT_ALARM interrupt:
- * Battery voltage is above or below threshold range.
- */
-static irqreturn_t pm8058_batt_alarm_isr(int irq, void *data)
-{
-	struct pm8058_batt_alarm_device *battdev = data;
-	int status;
-
-	if (battdev) {
-		status = pm8058_batt_alarm_status_read();
-
-		if (status < 0)
-			pr_err("failed to read status, rc=%d\n", status);
-		else
-			srcu_notifier_call_chain(&battdev->irq_notifier_list,
-						 status, NULL);
-	}
-
-	return IRQ_HANDLED;
-}
-
-/**
- * pm8058_batt_alarm_register_notifier - register a notifier to run when a
- *	battery voltage change interrupt fires
- * @nb:	notifier block containing callback function to register
- *
- * nb->notifier_call must point to a function of this form -
- * int (*notifier_call)(struct notifier_block *nb, unsigned long status,
- *			void *unused);
- * "status" will receive the battery alarm status; "unused" will be NULL.
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_batt_alarm_register_notifier(struct notifier_block *nb)
-{
-	int rc;
-
-	if (!the_battalarm) {
-		pr_err("no battery alarm device found.\n");
-		return -ENXIO;
-	}
-
-	rc = srcu_notifier_chain_register(&the_battalarm->irq_notifier_list,
-					  nb);
-	mutex_lock(&the_battalarm->batt_mutex);
-	if (rc == 0) {
-		if (the_battalarm->notifier_count == 0) {
-			/* request the irq */
-			rc = request_threaded_irq(the_battalarm->irq, NULL,
-				pm8058_batt_alarm_isr,
-				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-				"pm8058-batt_alarm-irq", the_battalarm);
-			if (rc < 0) {
-				pr_err("request_irq(%d) failed, rc=%d\n",
-					the_battalarm->irq, rc);
-				goto done;
-			}
-
-			rc = irq_set_irq_wake(the_battalarm->irq, 1);
-			if (rc < 0) {
-				pr_err("irq_set_irq_wake(%d,1) failed, rc=%d\n",
-					the_battalarm->irq, rc);
-				goto done;
-			}
-		}
-
-		the_battalarm->notifier_count++;
-	}
-done:
-	mutex_unlock(&the_battalarm->batt_mutex);
-	return rc;
-}
-EXPORT_SYMBOL_GPL(pm8058_batt_alarm_register_notifier);
-
-/**
- * pm8058_batt_alarm_unregister_notifier - unregister a notifier that is run
- *	when a battery voltage change interrupt fires
- * @nb:	notifier block containing callback function to unregister
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_batt_alarm_unregister_notifier(struct notifier_block *nb)
-{
-	int rc;
-
-	if (!the_battalarm) {
-		pr_err("no battery alarm device found.\n");
-		return -ENXIO;
-	}
-
-	rc = srcu_notifier_chain_unregister(&the_battalarm->irq_notifier_list,
-					    nb);
-	if (rc == 0) {
-		mutex_lock(&the_battalarm->batt_mutex);
-
-		the_battalarm->notifier_count--;
-
-		if (the_battalarm->notifier_count == 0)
-			free_irq(the_battalarm->irq, the_battalarm);
-
-		WARN_ON(the_battalarm->notifier_count < 0);
-
-		mutex_unlock(&the_battalarm->batt_mutex);
-	}
-
-
-
-	return rc;
-}
-EXPORT_SYMBOL_GPL(pm8058_batt_alarm_unregister_notifier);
-
-static int pm8058_batt_alarm_reg_init(struct pm8058_batt_alarm_device *battdev)
-{
-	int rc = 0;
-
-	/* save the current register states */
-	rc = pm8058_read(battdev->pm_chip, REG_THRESHOLD,
-			 &battdev->reg_threshold, 1);
-	if (rc)
-		goto bail;
-
-	rc = pm8058_read(battdev->pm_chip, REG_CTRL1,
-			 &battdev->reg_ctrl1, 1);
-	if (rc)
-		goto bail;
-
-	rc = pm8058_read(battdev->pm_chip, REG_CTRL2,
-			 &battdev->reg_ctrl2, 1);
-	if (rc)
-		goto bail;
-
-	rc = pm8058_read(battdev->pm_chip, REG_PWM_CTRL,
-			 &battdev->reg_pwm_ctrl, 1);
-	if (rc)
-		goto bail;
-
-bail:
-	if (rc)
-		pr_err("pm8058_read failed; initial register states "
-			"unknown, rc=%d\n", rc);
-	return rc;
-}
-
-static int pm8058_batt_alarm_config(void)
-{
-	int rc = 0;
-
-	/* Use default values when no platform data is provided. */
-	rc = pm8058_batt_alarm_threshold_set(DEFAULT_THRESHOLD_LOWER,
-		DEFAULT_THRESHOLD_UPPER);
-	if (rc) {
-		pr_err("threshold_set failed, rc=%d\n", rc);
-		goto done;
-	}
-
-	rc = pm8058_batt_alarm_hold_time_set(DEFAULT_HOLD_TIME);
-	if (rc) {
-		pr_err("hold_time_set failed, rc=%d\n", rc);
-		goto done;
-	}
-
-	rc = pm8058_batt_alarm_pwm_rate_set(DEFAULT_USE_PWM,
-			DEFAULT_PWM_SCALER, DEFAULT_PWM_DIVIDER);
-	if (rc) {
-		pr_err("pwm_rate_set failed, rc=%d\n", rc);
-		goto done;
-	}
-
-	rc = pm8058_batt_alarm_state_set(DEFAULT_LOWER_ENABLE,
-			DEFAULT_UPPER_ENABLE);
-	if (rc) {
-		pr_err("state_set failed, rc=%d\n", rc);
-		goto done;
-	}
-
-done:
-	return rc;
-}
-
-static int __devinit pm8058_batt_alarm_probe(struct platform_device *pdev)
-{
-	struct pm8058_batt_alarm_device *battdev;
-	struct pm8058_chip *pm_chip;
-	unsigned int irq;
-	int rc;
-
-	pm_chip = dev_get_drvdata(pdev->dev.parent);
-	if (pm_chip == NULL) {
-		pr_err("no driver data passed in.\n");
-		rc = -EFAULT;
-		goto exit_input;
-	}
-
-	irq = platform_get_irq(pdev, 0);
-	if (!irq) {
-		pr_err("no IRQ passed in.\n");
-		rc = -EFAULT;
-		goto exit_input;
-	}
-
-	battdev = kzalloc(sizeof *battdev, GFP_KERNEL);
-	if (battdev == NULL) {
-		pr_err("kzalloc() failed.\n");
-		rc = -ENOMEM;
-		goto exit_input;
-	}
-
-	battdev->pm_chip = pm_chip;
-	platform_set_drvdata(pdev, battdev);
-
-	srcu_init_notifier_head(&battdev->irq_notifier_list);
-
-	battdev->irq = irq;
-	battdev->notifier_count = 0;
-	mutex_init(&battdev->batt_mutex);
-
-	rc = pm8058_batt_alarm_reg_init(battdev);
-	if (rc)
-		goto exit_free_dev;
-
-	the_battalarm = battdev;
-
-	rc = pm8058_batt_alarm_config();
-	if (rc)
-		goto exit_free_dev;
-
-	pr_notice("OK\n");
-	return 0;
-
-exit_free_dev:
-	mutex_destroy(&battdev->batt_mutex);
-	srcu_cleanup_notifier_head(&battdev->irq_notifier_list);
-	platform_set_drvdata(pdev, battdev->pm_chip);
-	kfree(battdev);
-exit_input:
-	return rc;
-}
-
-static int __devexit pm8058_batt_alarm_remove(struct platform_device *pdev)
-{
-	struct pm8058_batt_alarm_device *battdev = platform_get_drvdata(pdev);
-
-	mutex_destroy(&battdev->batt_mutex);
-	srcu_cleanup_notifier_head(&battdev->irq_notifier_list);
-	platform_set_drvdata(pdev, battdev->pm_chip);
-	free_irq(battdev->irq, battdev);
-	kfree(battdev);
-
-	the_battalarm = NULL;
-
-	return 0;
-}
-
-static struct platform_driver pm8058_batt_alarm_driver = {
-	.probe	= pm8058_batt_alarm_probe,
-	.remove	= __devexit_p(pm8058_batt_alarm_remove),
-	.driver	= {
-		.name = "pm8058-batt-alarm",
-		.owner = THIS_MODULE,
-	},
-};
-
-static int __init pm8058_batt_alarm_init(void)
-{
-	return platform_driver_register(&pm8058_batt_alarm_driver);
-}
-
-static void __exit pm8058_batt_alarm_exit(void)
-{
-	platform_driver_unregister(&pm8058_batt_alarm_driver);
-}
-
-module_init(pm8058_batt_alarm_init);
-module_exit(pm8058_batt_alarm_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("PMIC8058 Battery Alarm Device driver");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:pm8058-batt-alarm");
diff --git a/drivers/misc/pmic8058-misc.c b/drivers/misc/pmic8058-misc.c
deleted file mode 100644
index 77a2f47..0000000
--- a/drivers/misc/pmic8058-misc.c
+++ /dev/null
@@ -1,335 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. 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 version 2 and
- * only 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.
- *
- */
-/*
- * Qualcomm PMIC8058 Misc Device driver
- *
- */
-
-#include <linux/debugfs.h>
-#include <linux/err.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/mfd/pmic8058.h>
-#include <linux/pmic8058-misc.h>
-
-/* VIB_DRV register */
-#define SSBI_REG_ADDR_DRV_VIB		0x4A
-
-#define PM8058_VIB_DRIVE_SHIFT		3
-#define PM8058_VIB_LOGIC_SHIFT		2
-#define PM8058_VIB_MIN_LEVEL_mV		1200
-#define PM8058_VIB_MAX_LEVEL_mV		3100
-
-/* COINCELL_CHG register */
-#define SSBI_REG_ADDR_COINCELL_CHG	(0x2F)
-#define PM8058_COINCELL_RESISTOR_SHIFT	(2)
-
-/* Resource offsets. */
-enum PM8058_MISC_IRQ {
-	PM8058_MISC_IRQ_OSC_HALT = 0
-};
-
-struct pm8058_misc_device {
-	struct pm8058_chip	*pm_chip;
-	struct dentry		*dgb_dir;
-	unsigned int		osc_halt_irq;
-	u64			osc_halt_count;
-};
-
-static struct pm8058_misc_device *misc_dev;
-
-int pm8058_vibrator_config(struct pm8058_vib_config *vib_config)
-{
-	u8 reg = 0;
-	int rc;
-
-	if (misc_dev == NULL) {
-		pr_info("misc_device is NULL\n");
-		return -EINVAL;
-	}
-
-	if (vib_config->drive_mV) {
-		if (vib_config->drive_mV < PM8058_VIB_MIN_LEVEL_mV ||
-			vib_config->drive_mV > PM8058_VIB_MAX_LEVEL_mV) {
-			pr_err("Invalid vibrator drive strength\n");
-			return -EINVAL;
-		}
-	}
-
-	reg = (vib_config->drive_mV / 100) << PM8058_VIB_DRIVE_SHIFT;
-
-	reg |= (!!vib_config->active_low) << PM8058_VIB_LOGIC_SHIFT;
-
-	reg |= vib_config->enable_mode;
-
-	rc = pm8058_write(misc_dev->pm_chip, SSBI_REG_ADDR_DRV_VIB, &reg, 1);
-	if (rc)
-		pr_err("%s: pm8058 write failed: rc=%d\n", __func__, rc);
-
-	return rc;
-}
-EXPORT_SYMBOL(pm8058_vibrator_config);
-
-/**
- * pm8058_coincell_chg_config - Disables or enables the coincell charger, and
- *				configures its voltage and resistor settings.
- * @chg_config:			Holds both voltage and resistor values, and a
- *				switch to change the state of charger.
- *				If state is to disable the charger then
- *				both voltage and resistor are disregarded.
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_coincell_chg_config(struct pm8058_coincell_chg_config *chg_config)
-{
-	u8 reg, voltage, resistor;
-	int rc;
-
-	reg = 0;
-	voltage = 0;
-	resistor = 0;
-	rc = 0;
-
-	if (misc_dev == NULL) {
-		pr_err("misc_device is NULL\n");
-		return -EINVAL;
-	}
-
-	if (chg_config == NULL) {
-		pr_err("chg_config is NULL\n");
-		return -EINVAL;
-	}
-
-	if (chg_config->state == PM8058_COINCELL_CHG_DISABLE) {
-		rc = pm8058_write(misc_dev->pm_chip,
-				SSBI_REG_ADDR_COINCELL_CHG, &reg, 1);
-		if (rc)
-			pr_err("%s: pm8058 write failed: rc=%d\n",
-							__func__, rc);
-		return rc;
-	}
-
-	voltage = chg_config->voltage;
-	resistor = chg_config->resistor;
-
-	if (voltage < PM8058_COINCELL_VOLTAGE_3p2V ||
-			(voltage > PM8058_COINCELL_VOLTAGE_3p0V &&
-				voltage != PM8058_COINCELL_VOLTAGE_2p5V)) {
-		pr_err("Invalid voltage value provided\n");
-		return -EINVAL;
-	}
-
-	if (resistor < PM8058_COINCELL_RESISTOR_2100_OHMS ||
-			resistor > PM8058_COINCELL_RESISTOR_800_OHMS) {
-		pr_err("Invalid resistor value provided\n");
-		return -EINVAL;
-	}
-
-	reg |= voltage;
-
-	reg |= (resistor << PM8058_COINCELL_RESISTOR_SHIFT);
-
-	rc = pm8058_write(misc_dev->pm_chip,
-			SSBI_REG_ADDR_COINCELL_CHG, &reg, 1);
-
-	if (rc)
-		pr_err("%s: pm8058 write failed: rc=%d\n", __func__, rc);
-
-	return rc;
-}
-EXPORT_SYMBOL(pm8058_coincell_chg_config);
-
-/* Handle the OSC_HALT interrupt: 32 kHz XTAL oscillator has stopped. */
-static irqreturn_t pm8058_osc_halt_isr(int irq, void *data)
-{
-	struct pm8058_misc_device *miscdev = data;
-	u64 count = 0;
-
-	if (miscdev) {
-		miscdev->osc_halt_count++;
-		count = miscdev->osc_halt_count;
-	}
-
-	pr_crit("%s: OSC_HALT interrupt has triggered, 32 kHz XTAL oscillator"
-		" has halted (%llu)!\n", __func__, count);
-
-	return IRQ_HANDLED;
-}
-
-#if defined(CONFIG_DEBUG_FS)
-
-static int osc_halt_count_get(void *data, u64 *val)
-{
-	struct pm8058_misc_device *miscdev = data;
-
-	if (miscdev == NULL) {
-		pr_err("%s: null pointer input.\n", __func__);
-		return -EINVAL;
-	}
-
-	*val = miscdev->osc_halt_count;
-
-	return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(dbg_osc_halt_fops, osc_halt_count_get, NULL, "%llu\n");
-
-static int __devinit pmic8058_misc_dbg_probe(struct pm8058_misc_device *miscdev)
-{
-	struct dentry *dent;
-	struct dentry *temp;
-
-	if (miscdev == NULL) {
-		pr_err("%s: no parent data passed in.\n", __func__);
-		return -EINVAL;
-	}
-
-	dent = debugfs_create_dir("pm8058-misc", NULL);
-	if (dent == NULL || IS_ERR(dent)) {
-		pr_err("%s: ERR debugfs_create_dir: dent=0x%X\n",
-					__func__, (unsigned)dent);
-		return -ENOMEM;
-	}
-
-	temp = debugfs_create_file("osc_halt_count", S_IRUSR, dent,
-					miscdev, &dbg_osc_halt_fops);
-	if (temp == NULL || IS_ERR(temp)) {
-		pr_err("%s: ERR debugfs_create_file: dent=0x%X\n",
-					__func__, (unsigned)temp);
-		goto debug_error;
-	}
-
-	miscdev->dgb_dir = dent;
-	return 0;
-
-debug_error:
-	debugfs_remove_recursive(dent);
-	return -ENOMEM;
-}
-
-static int __devexit pmic8058_misc_dbg_remove(
-		struct pm8058_misc_device *miscdev)
-{
-	if (miscdev->dgb_dir)
-		debugfs_remove_recursive(miscdev->dgb_dir);
-
-	return 0;
-}
-
-#else
-
-static int __devinit pmic8058_misc_dbg_probe(struct pm8058_misc_device *miscdev)
-{
-	return 0;
-}
-
-static int __devexit pmic8058_misc_dbg_remove(
-		struct pm8058_misc_device *miscdev)
-{
-	return 0;
-}
-
-#endif
-
-
-static int __devinit pmic8058_misc_probe(struct platform_device *pdev)
-{
-	struct pm8058_misc_device *miscdev;
-	struct pm8058_chip *pm_chip;
-	unsigned int irq;
-	int rc;
-
-	pm_chip = dev_get_drvdata(pdev->dev.parent);
-	if (pm_chip == NULL) {
-		pr_err("%s: no driver data passed in.\n", __func__);
-		return -EFAULT;
-	}
-
-	irq = platform_get_irq(pdev, PM8058_MISC_IRQ_OSC_HALT);
-	if (!irq) {
-		pr_err("%s: no IRQ passed in.\n", __func__);
-		return -EFAULT;
-	}
-
-	miscdev = kzalloc(sizeof *miscdev, GFP_KERNEL);
-	if (miscdev == NULL) {
-		pr_err("%s: kzalloc() failed.\n", __func__);
-		return -ENOMEM;
-	}
-
-	miscdev->pm_chip = pm_chip;
-	platform_set_drvdata(pdev, miscdev);
-
-	rc = request_threaded_irq(irq, NULL, pm8058_osc_halt_isr,
-			 IRQF_TRIGGER_RISING | IRQF_DISABLED,
-			 "pm8058-osc_halt-irq", miscdev);
-	if (rc < 0) {
-		pr_err("%s: request_irq(%d) FAIL: %d\n", __func__, irq, rc);
-		platform_set_drvdata(pdev, miscdev->pm_chip);
-		kfree(miscdev);
-		return rc;
-	}
-	miscdev->osc_halt_irq = irq;
-	miscdev->osc_halt_count = 0;
-
-	rc = pmic8058_misc_dbg_probe(miscdev);
-	if (rc)
-		return rc;
-
-	misc_dev = miscdev;
-
-	pr_notice("%s: OK\n", __func__);
-	return 0;
-}
-
-static int __devexit pmic8058_misc_remove(struct platform_device *pdev)
-{
-	struct pm8058_misc_device *miscdev = platform_get_drvdata(pdev);
-
-	pmic8058_misc_dbg_remove(miscdev);
-
-	platform_set_drvdata(pdev, miscdev->pm_chip);
-	free_irq(miscdev->osc_halt_irq, miscdev);
-	kfree(miscdev);
-
-	return 0;
-}
-
-static struct platform_driver pmic8058_misc_driver = {
-	.probe	= pmic8058_misc_probe,
-	.remove	= __devexit_p(pmic8058_misc_remove),
-	.driver	= {
-		.name = "pm8058-misc",
-		.owner = THIS_MODULE,
-	},
-};
-
-static int __init pm8058_misc_init(void)
-{
-	return platform_driver_register(&pmic8058_misc_driver);
-}
-
-static void __exit pm8058_misc_exit(void)
-{
-	platform_driver_unregister(&pmic8058_misc_driver);
-}
-
-module_init(pm8058_misc_init);
-module_exit(pm8058_misc_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("PMIC8058 Misc Device driver");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:pmic8058-misc");
diff --git a/drivers/misc/pmic8058-vibrator.c b/drivers/misc/pmic8058-vibrator.c
deleted file mode 100644
index f6284ee..0000000
--- a/drivers/misc/pmic8058-vibrator.c
+++ /dev/null
@@ -1,312 +0,0 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. 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 version 2 and
- * only 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.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/pmic8058-vibrator.h>
-#include <linux/mfd/pmic8058.h>
-#include <linux/pm.h>
-#include <linux/pm_runtime.h>
-#include <linux/slab.h>
-
-#include "../staging/android/timed_output.h"
-
-#define VIB_DRV			0x4A
-
-#define VIB_DRV_SEL_MASK	0xf8
-#define VIB_DRV_SEL_SHIFT	0x03
-#define VIB_DRV_EN_MANUAL_MASK	0xfc
-
-#define VIB_MAX_LEVEL_mV	3100
-#define VIB_MIN_LEVEL_mV	1200
-
-struct pmic8058_vib {
-	struct hrtimer vib_timer;
-	struct timed_output_dev timed_dev;
-	spinlock_t lock;
-	struct work_struct work;
-
-	struct device *dev;
-	struct pmic8058_vibrator_pdata *pdata;
-	int state;
-	int level;
-	u8  reg_vib_drv;
-
-	struct pm8058_chip	*pm_chip;
-};
-
-/* REVISIT: just for debugging, will be removed in final working version */
-static void __dump_vib_regs(struct pmic8058_vib *vib, char *msg)
-{
-	u8 temp;
-
-	dev_dbg(vib->dev, "%s\n", msg);
-
-	pm8058_read(vib->pm_chip, VIB_DRV, &temp, 1);
-	dev_dbg(vib->dev, "VIB_DRV - %X\n", temp);
-}
-
-static int pmic8058_vib_read_u8(struct pmic8058_vib *vib,
-				 u8 *data, u16 reg)
-{
-	int rc;
-
-	rc = pm8058_read(vib->pm_chip, reg, data, 1);
-	if (rc < 0)
-		dev_warn(vib->dev, "Error reading pmic8058: %X - ret %X\n",
-				reg, rc);
-
-	return rc;
-}
-
-static int pmic8058_vib_write_u8(struct pmic8058_vib *vib,
-				 u8 data, u16 reg)
-{
-	int rc;
-
-	rc = pm8058_write(vib->pm_chip, reg, &data, 1);
-	if (rc < 0)
-		dev_warn(vib->dev, "Error writing pmic8058: %X - ret %X\n",
-				reg, rc);
-	return rc;
-}
-
-static int pmic8058_vib_set(struct pmic8058_vib *vib, int on)
-{
-	int rc;
-	u8 val;
-
-	if (on) {
-		rc = pm_runtime_resume(vib->dev);
-		if (rc < 0)
-			dev_dbg(vib->dev, "pm_runtime_resume failed\n");
-
-		val = vib->reg_vib_drv;
-		val |= ((vib->level << VIB_DRV_SEL_SHIFT) & VIB_DRV_SEL_MASK);
-		rc = pmic8058_vib_write_u8(vib, val, VIB_DRV);
-		if (rc < 0)
-			return rc;
-		vib->reg_vib_drv = val;
-	} else {
-		val = vib->reg_vib_drv;
-		val &= ~VIB_DRV_SEL_MASK;
-		rc = pmic8058_vib_write_u8(vib, val, VIB_DRV);
-		if (rc < 0)
-			return rc;
-		vib->reg_vib_drv = val;
-
-		rc = pm_runtime_suspend(vib->dev);
-		if (rc < 0)
-			dev_dbg(vib->dev, "pm_runtime_suspend failed\n");
-	}
-	__dump_vib_regs(vib, "vib_set_end");
-
-	return rc;
-}
-
-static void pmic8058_vib_enable(struct timed_output_dev *dev, int value)
-{
-	struct pmic8058_vib *vib = container_of(dev, struct pmic8058_vib,
-					 timed_dev);
-	unsigned long flags;
-
-retry:
-	spin_lock_irqsave(&vib->lock, flags);
-	if (hrtimer_try_to_cancel(&vib->vib_timer) < 0) {
-		spin_unlock_irqrestore(&vib->lock, flags);
-		cpu_relax();
-		goto retry;
-	}
-
-	if (value == 0)
-		vib->state = 0;
-	else {
-		value = (value > vib->pdata->max_timeout_ms ?
-				 vib->pdata->max_timeout_ms : value);
-		vib->state = 1;
-		hrtimer_start(&vib->vib_timer,
-			      ktime_set(value / 1000, (value % 1000) * 1000000),
-			      HRTIMER_MODE_REL);
-	}
-	spin_unlock_irqrestore(&vib->lock, flags);
-	schedule_work(&vib->work);
-}
-
-static void pmic8058_vib_update(struct work_struct *work)
-{
-	struct pmic8058_vib *vib = container_of(work, struct pmic8058_vib,
-					 work);
-
-	pmic8058_vib_set(vib, vib->state);
-}
-
-static int pmic8058_vib_get_time(struct timed_output_dev *dev)
-{
-	struct pmic8058_vib *vib = container_of(dev, struct pmic8058_vib,
-					 timed_dev);
-
-	if (hrtimer_active(&vib->vib_timer)) {
-		ktime_t r = hrtimer_get_remaining(&vib->vib_timer);
-		return (int) ktime_to_us(r);
-	} else
-		return 0;
-}
-
-static enum hrtimer_restart pmic8058_vib_timer_func(struct hrtimer *timer)
-{
-	struct pmic8058_vib *vib = container_of(timer, struct pmic8058_vib,
-					 vib_timer);
-	vib->state = 0;
-	schedule_work(&vib->work);
-	return HRTIMER_NORESTART;
-}
-
-#ifdef CONFIG_PM
-static int pmic8058_vib_suspend(struct device *dev)
-{
-	struct pmic8058_vib *vib = dev_get_drvdata(dev);
-
-	hrtimer_cancel(&vib->vib_timer);
-	cancel_work_sync(&vib->work);
-	/* turn-off vibrator */
-	pmic8058_vib_set(vib, 0);
-	return 0;
-}
-
-static struct dev_pm_ops pmic8058_vib_pm_ops = {
-	.suspend = pmic8058_vib_suspend,
-};
-#endif
-
-static int __devinit pmic8058_vib_probe(struct platform_device *pdev)
-
-{
-	struct pmic8058_vibrator_pdata *pdata = pdev->dev.platform_data;
-	struct pmic8058_vib *vib;
-	u8 val;
-	int rc;
-
-	struct pm8058_chip	*pm_chip;
-
-	pm_chip = dev_get_drvdata(pdev->dev.parent);
-	if (pm_chip == NULL) {
-		dev_err(&pdev->dev, "no parent data passed in\n");
-		return -EFAULT;
-	}
-
-	if (!pdata)
-		return -EINVAL;
-
-	if (pdata->level_mV < VIB_MIN_LEVEL_mV ||
-			 pdata->level_mV > VIB_MAX_LEVEL_mV)
-		return -EINVAL;
-
-	vib = kzalloc(sizeof(*vib), GFP_KERNEL);
-	if (!vib)
-		return -ENOMEM;
-
-	/* Enable runtime PM ops, start in ACTIVE mode */
-	rc = pm_runtime_set_active(&pdev->dev);
-	if (rc < 0)
-		dev_dbg(&pdev->dev, "unable to set runtime pm state\n");
-	pm_runtime_enable(&pdev->dev);
-
-	vib->pm_chip	= pm_chip;
-	vib->pdata	= pdata;
-	vib->level	= pdata->level_mV / 100;
-	vib->dev	= &pdev->dev;
-
-	spin_lock_init(&vib->lock);
-	INIT_WORK(&vib->work, pmic8058_vib_update);
-
-	hrtimer_init(&vib->vib_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-	vib->vib_timer.function = pmic8058_vib_timer_func;
-
-	vib->timed_dev.name = "vibrator";
-	vib->timed_dev.get_time = pmic8058_vib_get_time;
-	vib->timed_dev.enable = pmic8058_vib_enable;
-
-	__dump_vib_regs(vib, "boot_vib_default");
-
-	/* operate in manual mode */
-	rc = pmic8058_vib_read_u8(vib, &val, VIB_DRV);
-	if (rc < 0)
-		goto err_read_vib;
-	val &= ~VIB_DRV_EN_MANUAL_MASK;
-	rc = pmic8058_vib_write_u8(vib, val, VIB_DRV);
-	if (rc < 0)
-		goto err_read_vib;
-
-	vib->reg_vib_drv = val;
-
-	rc = timed_output_dev_register(&vib->timed_dev);
-	if (rc < 0)
-		goto err_read_vib;
-
-	pmic8058_vib_enable(&vib->timed_dev, pdata->initial_vibrate_ms);
-
-	platform_set_drvdata(pdev, vib);
-
-	pm_runtime_set_suspended(&pdev->dev);
-	return 0;
-
-err_read_vib:
-	pm_runtime_set_suspended(&pdev->dev);
-	pm_runtime_disable(&pdev->dev);
-	kfree(vib);
-	return rc;
-}
-
-static int __devexit pmic8058_vib_remove(struct platform_device *pdev)
-{
-	struct pmic8058_vib *vib = platform_get_drvdata(pdev);
-
-	pm_runtime_disable(&pdev->dev);
-	cancel_work_sync(&vib->work);
-	hrtimer_cancel(&vib->vib_timer);
-	timed_output_dev_unregister(&vib->timed_dev);
-	kfree(vib);
-
-	return 0;
-}
-
-static struct platform_driver pmic8058_vib_driver = {
-	.probe		= pmic8058_vib_probe,
-	.remove		= __devexit_p(pmic8058_vib_remove),
-	.driver		= {
-		.name	= "pm8058-vib",
-		.owner	= THIS_MODULE,
-#ifdef CONFIG_PM
-		.pm	= &pmic8058_vib_pm_ops,
-#endif
-	},
-};
-
-static int __init pmic8058_vib_init(void)
-{
-	return platform_driver_register(&pmic8058_vib_driver);
-}
-module_init(pmic8058_vib_init);
-
-static void __exit pmic8058_vib_exit(void)
-{
-	platform_driver_unregister(&pmic8058_vib_driver);
-}
-module_exit(pmic8058_vib_exit);
-
-MODULE_ALIAS("platform:pmic8058_vib");
-MODULE_DESCRIPTION("PMIC8058 vibrator driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 1ee8538..48f3f2d 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -549,6 +549,7 @@
 	return err;
 }
 
+#define ERR_NOMEDIUM	3
 #define ERR_RETRY	2
 #define ERR_ABORT	1
 #define ERR_CONTINUE	0
@@ -620,6 +621,9 @@
 	u32 status, stop_status = 0;
 	int err, retry;
 
+	if (mmc_card_removed(card))
+		return ERR_NOMEDIUM;
+
 	/*
 	 * Try to get card status which indicates both the card state
 	 * and why there was no response.  If the first attempt fails,
@@ -636,8 +640,12 @@
 	}
 
 	/* We couldn't get a response from the card.  Give up. */
-	if (err)
+	if (err) {
+		/* Check if the card is removed */
+		if (mmc_detect_card_removed(card->host))
+			return ERR_NOMEDIUM;
 		return ERR_ABORT;
+	}
 
 	/*
 	 * Check the current card state.  If it is in some data transfer
@@ -969,6 +977,7 @@
 				if (retry++ < 5)
 					continue;
 			case ERR_ABORT:
+			case ERR_NOMEDIUM:
 				goto cmd_abort;
 			case ERR_CONTINUE:
 				break;
@@ -1075,6 +1084,8 @@
 
  cmd_abort:
 	spin_lock_irq(&md->lock);
+	if (mmc_card_removed(card))
+		req->cmd_flags |= REQ_QUIET;
 	while (ret)
 		ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
 	spin_unlock_irq(&md->lock);
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 9b64847..b2fb161 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -29,6 +29,8 @@
  */
 static int mmc_prep_request(struct request_queue *q, struct request *req)
 {
+	struct mmc_queue *mq = q->queuedata;
+
 	/*
 	 * We only like normal block requests and discards.
 	 */
@@ -37,6 +39,9 @@
 		return BLKPREP_KILL;
 	}
 
+	if (mq && mmc_card_removed(mq->card))
+		return BLKPREP_KILL;
+
 	req->cmd_flags |= REQ_DONTPREP;
 
 	return BLKPREP_OK;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 2c7c0a5..51434b6 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -105,7 +105,7 @@
 			cmd->retries = 0;
 	}
 
-	if (err && cmd->retries) {
+	if (err && cmd->retries && !mmc_card_removed(host->card)) {
 		pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
 			mmc_hostname(host), cmd->opcode, err);
 
@@ -238,6 +238,10 @@
 
 	mrq->done_data = &complete;
 	mrq->done = mmc_wait_done;
+	if (mmc_card_removed(host->card)) {
+		mrq->cmd->error = -ENOMEDIUM;
+		return;
+	}
 
 	mmc_start_request(host, mrq);
 
@@ -502,13 +506,6 @@
 	might_sleep();
 
 	add_wait_queue(&host->wq, &wait);
-#ifdef CONFIG_PM_RUNTIME
-	while (mmc_dev(host)->power.runtime_status == RPM_SUSPENDING) {
-		if (host->suspend_task == current)
-			break;
-		msleep(15);
-	}
-#endif
 
 	spin_lock_irqsave(&host->lock, flags);
 	while (1) {
@@ -1257,6 +1254,7 @@
 #endif
 
 	wake_lock(&host->detect_wake_lock);
+	host->detect_change = 1;
 	mmc_schedule_delayed_work(&host->detect, delay);
 }
 
@@ -1665,6 +1663,43 @@
 	return -EIO;
 }
 
+int _mmc_detect_card_removed(struct mmc_host *host)
+{
+	int ret;
+
+	if ((host->caps & MMC_CAP_NONREMOVABLE) || !host->bus_ops->alive)
+		return 0;
+
+	if (!host->card || mmc_card_removed(host->card))
+		return 1;
+
+	ret = host->bus_ops->alive(host);
+	if (ret) {
+		mmc_card_set_removed(host->card);
+		pr_debug("%s: card remove detected\n", mmc_hostname(host));
+	}
+
+	return ret;
+}
+
+int mmc_detect_card_removed(struct mmc_host *host)
+{
+	struct mmc_card *card = host->card;
+
+	WARN_ON(!host->claimed);
+	/*
+	 * The card will be considered unchanged unless we have been asked to
+	 * detect a change or host requires polling to provide card detection.
+	 */
+	if (card && !host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL))
+		return mmc_card_removed(card);
+
+	host->detect_change = 0;
+
+	return _mmc_detect_card_removed(host);
+}
+EXPORT_SYMBOL(mmc_detect_card_removed);
+
 void mmc_rescan(struct work_struct *work)
 {
 	struct mmc_host *host =
@@ -1690,6 +1725,8 @@
 	if (host->bus_dead)
 		extend_wakelock = 1;
 
+	host->detect_change = 0;
+
 	/*
 	 * Let mmc_bus_put() free the bus/bus_ops if we've found that
 	 * the card is no longer present.
@@ -1873,20 +1910,43 @@
 
 	mmc_bus_get(host);
 	if (host->bus_ops && !host->bus_dead) {
-		if (host->bus_ops->suspend)
-			err = host->bus_ops->suspend(host);
-		if (err == -ENOSYS || !host->bus_ops->resume) {
-			/*
-			 * We simply "remove" the card in this case.
-			 * It will be redetected on resume.
-			 */
-			if (host->bus_ops->remove)
-				host->bus_ops->remove(host);
-			mmc_claim_host(host);
-			mmc_detach_bus(host);
-			mmc_release_host(host);
-			host->pm_flags = 0;
-			err = 0;
+
+		/*
+		 * A long response time is not acceptable for device drivers
+		 * when doing suspend. Prevent mmc_claim_host in the suspend
+		 * sequence, to potentially wait "forever" by trying to
+		 * pre-claim the host.
+		 *
+		 * Skip try claim host for SDIO cards, doing so fixes deadlock
+		 * conditions. The function driver suspend may again call into
+		 * SDIO driver within a different context for enabling power
+		 * save mode in the card and hence wait in mmc_claim_host
+		 * causing deadlock.
+		 */
+		if (!(host->card && mmc_card_sdio(host->card)))
+			if (!mmc_try_claim_host(host))
+				err = -EBUSY;
+
+		if (!err) {
+			if (host->bus_ops->suspend)
+				err = host->bus_ops->suspend(host);
+			if (!(host->card && mmc_card_sdio(host->card)))
+				mmc_do_release_host(host);
+
+			if (err == -ENOSYS || !host->bus_ops->resume) {
+				/*
+				 * We simply "remove" the card in this case.
+				 * It will be redetected on resume.
+				 */
+				if (host->bus_ops->remove)
+					host->bus_ops->remove(host);
+				mmc_claim_host(host);
+				mmc_detach_bus(host);
+				mmc_power_off(host);
+				mmc_release_host(host);
+				host->pm_flags = 0;
+				err = 0;
+			}
 		}
 	}
 	mmc_bus_put(host);
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index a4edb24..49684f6 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -24,6 +24,7 @@
 	int (*resume)(struct mmc_host *);
 	int (*power_save)(struct mmc_host *);
 	int (*power_restore)(struct mmc_host *);
+	int (*alive)(struct mmc_host *);
 };
 
 void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
@@ -60,6 +61,8 @@
 void mmc_start_host(struct mmc_host *host);
 void mmc_stop_host(struct mmc_host *host);
 
+int _mmc_detect_card_removed(struct mmc_host *host);
+
 int mmc_attach_mmc(struct mmc_host *host);
 int mmc_attach_sd(struct mmc_host *host);
 int mmc_attach_sdio(struct mmc_host *host);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 918fc9e..79d6e97 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -874,6 +874,14 @@
 }
 
 /*
+ * Card detection - card is alive.
+ */
+static int mmc_alive(struct mmc_host *host)
+{
+	return mmc_send_status(host->card, NULL);
+}
+
+/*
  * Card detection callback from host.
  */
 static void mmc_detect(struct mmc_host *host)
@@ -888,7 +896,7 @@
 	/*
 	 * Just check if our card has been removed.
 	 */
-	err = mmc_send_status(host->card, NULL);
+	err = _mmc_detect_card_removed(host);
 
 	mmc_release_host(host);
 
@@ -992,6 +1000,7 @@
 	.suspend = NULL,
 	.resume = NULL,
 	.power_restore = mmc_power_restore,
+	.alive = mmc_alive,
 };
 
 static const struct mmc_bus_ops mmc_ops_unsafe = {
@@ -1002,6 +1011,7 @@
 	.suspend = mmc_suspend,
 	.resume = mmc_resume,
 	.power_restore = mmc_power_restore,
+	.alive = mmc_alive,
 };
 
 static void mmc_attach_bus_ops(struct mmc_host *host)
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 71518f6..6522efb 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1044,6 +1044,14 @@
 }
 
 /*
+ * Card detection - card is alive.
+ */
+static int mmc_sd_alive(struct mmc_host *host)
+{
+	return mmc_send_status(host->card, NULL);
+}
+
+/*
  * Card detection callback from host.
  */
 static void mmc_sd_detect(struct mmc_host *host)
@@ -1063,7 +1071,7 @@
 	 */
 #ifdef CONFIG_MMC_PARANOID_SD_INIT
 	while(retries) {
-		err = mmc_send_status(host->card, NULL);
+		err = _mmc_detect_card_removed(host);
 		if (err) {
 			retries--;
 			udelay(5);
@@ -1076,7 +1084,7 @@
 		       __func__, mmc_hostname(host), err);
 	}
 #else
-	err = mmc_send_status(host->card, NULL);
+	err = _mmc_detect_card_removed(host);
 #endif
 	mmc_release_host(host);
 
@@ -1163,6 +1171,7 @@
 	.suspend = NULL,
 	.resume = NULL,
 	.power_restore = mmc_sd_power_restore,
+	.alive = mmc_sd_alive,
 };
 
 static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
@@ -1171,6 +1180,7 @@
 	.suspend = mmc_sd_suspend,
 	.resume = mmc_sd_resume,
 	.power_restore = mmc_sd_power_restore,
+	.alive = mmc_sd_alive,
 };
 
 static void mmc_sd_attach_bus_ops(struct mmc_host *host)
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 3237742..8ac2e59 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -582,6 +582,14 @@
 }
 
 /*
+ * Card detection - card is alive.
+ */
+static int mmc_sdio_alive(struct mmc_host *host)
+{
+	return mmc_select_card(host->card);
+}
+
+/*
  * Card detection callback from host.
  */
 static void mmc_sdio_detect(struct mmc_host *host)
@@ -603,7 +611,7 @@
 	/*
 	 * Just check if our card has been removed.
 	 */
-	err = mmc_select_card(host->card);
+	err = _mmc_detect_card_removed(host);
 
 	mmc_release_host(host);
 
@@ -783,6 +791,7 @@
 	.suspend = mmc_sdio_suspend,
 	.resume = mmc_sdio_resume,
 	.power_restore = mmc_sdio_power_restore,
+	.alive = mmc_sdio_alive,
 };
 
 
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 0410473..e853699 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -132,6 +132,7 @@
 msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
 		      u32 c);
 static inline void msmsdcc_delay(struct msmsdcc_host *host);
+static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
 
 static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
 {
@@ -476,7 +477,11 @@
 			goto out;
 		}
 		msmsdcc_stop_data(host);
-		if (!mrq->data->stop || mrq->cmd->error ||
+
+		if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
+				|| !mrq->sbc)) {
+			msmsdcc_start_command(host, mrq->data->stop, 0);
+		} else if (!mrq->data->stop || mrq->cmd->error ||
 			(mrq->sbc && !mrq->data->error)) {
 			host->curr.mrq = NULL;
 			host->curr.cmd = NULL;
@@ -486,9 +491,6 @@
 
 			mmc_request_done(host->mmc, mrq);
 			return;
-		} else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
-				|| !mrq->sbc)) {
-			msmsdcc_start_command(host, mrq->data->stop, 0);
 		}
 	}
 
@@ -633,7 +635,10 @@
 			return;
 		}
 		msmsdcc_stop_data(host);
-		if (!mrq->data->stop || mrq->cmd->error ||
+		if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
+				|| !mrq->sbc)) {
+			msmsdcc_start_command(host, mrq->data->stop, 0);
+		} else if (!mrq->data->stop || mrq->cmd->error ||
 			(mrq->sbc && !mrq->data->error)) {
 			host->curr.mrq = NULL;
 			host->curr.cmd = NULL;
@@ -643,9 +648,6 @@
 
 			mmc_request_done(host->mmc, mrq);
 			return;
-		} else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
-				|| !mrq->sbc)) {
-			msmsdcc_start_command(host, mrq->data->stop, 0);
 		}
 	}
 	spin_unlock_irqrestore(&host->lock, flags);
@@ -696,7 +698,7 @@
 static inline void msmsdcc_sps_exit_curr_xfer(struct msmsdcc_host *host) { }
 #endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
 
-static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
+static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host);
 
 static void
 msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
@@ -942,7 +944,7 @@
 msmsdcc_start_command_deferred(struct msmsdcc_host *host,
 				struct mmc_command *cmd, u32 *c)
 {
-	DBG(host, "op %02x arg %08x flags %08x\n",
+	DBG(host, "op %d arg %08x flags %08x\n",
 	    cmd->opcode, cmd->arg, cmd->flags);
 
 	*c |= (cmd->opcode | MCI_CPSM_ENABLE);
@@ -1149,9 +1151,11 @@
 		 */
 		if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
 			|| data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
-			pr_err("%s: Data timeout\n",
-				 mmc_hostname(host->mmc));
+			pr_err("%s: CMD%d: Data timeout\n",
+				 mmc_hostname(host->mmc),
+				 data->mrq->cmd->opcode);
 			data->error = -ETIMEDOUT;
+			msmsdcc_dump_sdcc_state(host);
 		}
 	} else if (status & MCI_RXOVERRUN) {
 		pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
@@ -1262,6 +1266,9 @@
 			len = msmsdcc_pio_read(host, buffer, remain);
 		if (status & MCI_TXACTIVE)
 			len = msmsdcc_pio_write(host, buffer, remain);
+		/* len might have aligned to 32bits above */
+		if (len > remain)
+			len = remain;
 
 		/* Unmap the buffer */
 		kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
@@ -1362,11 +1369,14 @@
 	cmd->resp[3] = readl_relaxed(host->base + MMCIRESPONSE3);
 
 	if (status & (MCI_CMDTIMEOUT | MCI_AUTOCMD19TIMEOUT)) {
-		pr_debug("%s: Command timeout\n", mmc_hostname(host->mmc));
+		pr_debug("%s: CMD%d: Command timeout\n",
+				mmc_hostname(host->mmc), cmd->opcode);
 		cmd->error = -ETIMEDOUT;
 	} else if ((status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) &&
 			!host->cmd19_tuning_in_progress) {
-		pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc));
+		pr_err("%s: CMD%d: Command CRC error\n",
+			mmc_hostname(host->mmc), cmd->opcode);
+		msmsdcc_dump_sdcc_state(host);
 		cmd->error = -EILSEQ;
 	}
 
@@ -1383,9 +1393,16 @@
 		else if (host->curr.data) { /* Non DMA */
 			msmsdcc_reset_and_restore(host);
 			msmsdcc_stop_data(host);
-			msmsdcc_request_end(host, cmd->mrq);
+			if (cmd->data && cmd->data->stop)
+				msmsdcc_start_command(host,
+						cmd->data->stop, 0);
+			else
+				msmsdcc_request_end(host, cmd->mrq);
 		} else { /* host->data == NULL */
-			if (!cmd->error && host->prog_enable) {
+			if (cmd->data && cmd->data->stop) {
+				msmsdcc_start_command(host,
+						cmd->data->stop, 0);
+			} else if (!cmd->error && host->prog_enable) {
 				if (status & MCI_PROGDONE) {
 					host->prog_enable = 0;
 					msmsdcc_request_end(host, cmd->mrq);
@@ -2221,7 +2238,7 @@
 		if (clock != host->clk_rate) {
 			rc = clk_set_rate(host->clk, clock);
 			if (rc < 0)
-				pr_debug("%s: failed to set clk rate %u\n",
+				pr_err("%s: failed to set clk rate %u\n",
 						mmc_hostname(mmc), clock);
 			host->clk_rate = clock;
 			host->reg_write_delay =
@@ -2254,8 +2271,7 @@
 	 * Select the controller timing mode according
 	 * to current bus speed mode
 	 */
-	if ((ios->timing == MMC_TIMING_UHS_SDR104) ||
-		(ios->timing == MMC_TIMING_UHS_SDR50)) {
+	if (ios->timing == MMC_TIMING_UHS_SDR104) {
 		clk |= (4 << 14);
 		host->tuning_needed = 1;
 	} else if (ios->timing == MMC_TIMING_UHS_DDR50) {
@@ -2357,6 +2373,11 @@
 		msmsdcc_setup_clocks(host, false);
 		host->clks_on = 0;
 	}
+
+	if (host->cmd19_tuning_in_progress)
+		WARN(!host->clks_on,
+			"cmd19_tuning_in_progress but SDCC clocks are OFF\n");
+
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
@@ -2603,97 +2624,9 @@
 	return rc;
 }
 
-static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
-						u8 phase);
-/* Initialize the DLL (Programmable Delay Line ) */
-static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
+static inline void msmsdcc_cm_sdc4_dll_set_freq(struct msmsdcc_host *host)
 {
-	int rc = 0;
-	u32 wait_timeout;
-
-	/* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
-	writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
-			& ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
-
-	/* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
-	writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
-			| MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
-
-	msmsdcc_delay(host);
-
-	/* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
-	writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
-			& ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
-
-	/* Initialize the phase to 0 */
-	rc = msmsdcc_config_cm_sdc4_dll_phase(host, 0);
-	if (rc)
-		goto out;
-
-	wait_timeout = 1000;
-	/* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
-	while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
-		/* max. wait for 1 sec for LOCK bit to be set */
-		if (--wait_timeout == 0) {
-			pr_err("%s: %s: DLL failed to lock at phase: %d",
-				mmc_hostname(host->mmc), __func__, 0);
-			rc = -1;
-			goto out;
-		}
-		/* wait for 1ms */
-		usleep_range(1000, 1500);
-	}
-out:
-	return rc;
-}
-
-/*
- * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
- * calibration sequence. This function should be called before
- * enabling AUTO_CMD19 bit in MCI_CMD register for block read
- * commands (CMD17/CMD18).
- */
-static void msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
-{
-	/* Set CDR_EN bit to 1. */
-	writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG) |
-			MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
-
-	/* Set CDR_EXT_EN bit to 0. */
-	writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
-			& ~MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
-
-	/* Set CK_OUT_EN bit to 0. */
-	writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
-			& ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
-
-	/* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
-	while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)
-		;
-
-	/* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
-	writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
-			| MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
-
-	/* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register is 1. */
-	while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN))
-		;
-}
-
-static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
-						u8 phase)
-{
-	int rc = 0;
 	u32 mclk_freq = 0;
-	u32 wait_timeout;
-
-	/* Set CDR_EN bit to 0. */
-	writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
-			& ~MCI_CDR_EN), host->base + MCI_DLL_CONFIG);
-
-	/* Set CDR_EXT_EN bit to 1. */
-	writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
-			| MCI_CDR_EXT_EN), host->base + MCI_DLL_CONFIG);
 
 	/* Program the MCLK value to MCLK_FREQ bit field */
 	if (host->clk_rate <= 112000000)
@@ -2716,73 +2649,16 @@
 	writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
 			& ~(7 << 24)) | (mclk_freq << 24)),
 			host->base + MCI_DLL_CONFIG);
-
-	/* Set CK_OUT_EN bit to 0. */
-	writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
-		& ~MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
-
-	/* Set DLL_EN bit to 1. */
-	writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
-			| MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
-
-	wait_timeout = 1000;
-	/* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
-	while (readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN) {
-		/* max. wait for 1 sec for LOCK bit for be set */
-		if (--wait_timeout == 0) {
-			pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 0",
-				mmc_hostname(host->mmc), __func__, phase);
-			rc = -1;
-			goto out;
-		}
-		/* wait for 1ms */
-		usleep_range(1000, 1500);
-	}
-
-	/*
-	 * Write the selected DLL clock output phase (0 ... 15)
-	 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
-	 */
-	writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
-			& ~(0xF << 20)) | (phase << 20)),
-			host->base + MCI_DLL_CONFIG);
-
-	/* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
-	writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
-			| MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
-
-	wait_timeout = 1000;
-	/* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
-	while (!(readl_relaxed(host->base + MCI_DLL_CONFIG) & MCI_CK_OUT_EN)) {
-		/* max. wait for 1 sec for LOCK bit for be set */
-		if (--wait_timeout == 0) {
-			pr_err("%s: %s: Failed to set DLL phase: %d, CK_OUT_EN bit is not 1",
-				mmc_hostname(host->mmc), __func__, phase);
-			rc = -1;
-			goto out;
-		}
-		/* wait for 1ms */
-		usleep_range(1000, 1500);
-	}
-out:
-	return rc;
 }
 
-static int msmsdcc_execute_tuning(struct mmc_host *mmc)
+/* Initialize the DLL (Programmable Delay Line ) */
+static int msmsdcc_init_cm_sdc4_dll(struct msmsdcc_host *host)
 {
-	struct msmsdcc_host *host = mmc_priv(mmc);
-	u8 phase;
-	u8 *data_buf;
-	u8 tuned_phases[16], tuned_phase_cnt = 0;
 	int rc = 0;
+	unsigned long flags;
+	u32 wait_cnt;
 
-	/* Tuning is only required for SDR50 & SDR104 modes */
-	if (!host->tuning_needed) {
-		rc = 0;
-		goto out;
-	}
-
-	host->cmd19_tuning_in_progress = 1;
+	spin_lock_irqsave(&host->lock, flags);
 	/*
 	 * Make sure that clock is always enabled when DLL
 	 * tuning is in progress. Keeping PWRSAVE ON may
@@ -2791,7 +2667,248 @@
 	 */
 	writel_relaxed((readl_relaxed(host->base + MMCICLOCK)
 			& ~MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
+
+	/* Write 1 to DLL_RST bit of MCI_DLL_CONFIG register */
+	writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
+			| MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
+
+	/* Write 1 to DLL_PDN bit of MCI_DLL_CONFIG register */
+	writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
+			| MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
+
+	msmsdcc_cm_sdc4_dll_set_freq(host);
+
+	/* Write 0 to DLL_RST bit of MCI_DLL_CONFIG register */
+	writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
+			& ~MCI_DLL_RST), host->base + MCI_DLL_CONFIG);
+
+	/* Write 0 to DLL_PDN bit of MCI_DLL_CONFIG register */
+	writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
+			& ~MCI_DLL_PDN), host->base + MCI_DLL_CONFIG);
+
+	/* Set DLL_EN bit to 1. */
+	writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
+			| MCI_DLL_EN), host->base + MCI_DLL_CONFIG);
+
+	/* Set CK_OUT_EN bit to 1. */
+	writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
+			| MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
+
+	wait_cnt = 50;
+	/* Wait until DLL_LOCK bit of MCI_DLL_STATUS register becomes '1' */
+	while (!(readl_relaxed(host->base + MCI_DLL_STATUS) & MCI_DLL_LOCK)) {
+		/* max. wait for 50us sec for LOCK bit to be set */
+		if (--wait_cnt == 0) {
+			pr_err("%s: %s: DLL failed to LOCK\n",
+				mmc_hostname(host->mmc), __func__);
+			rc = -ETIMEDOUT;
+			goto out;
+		}
+		/* wait for 1us before polling again */
+		udelay(1);
+	}
+
+out:
+	/* re-enable PWRSAVE */
+	writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
+			MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	return rc;
+}
+
+static inline int msmsdcc_dll_poll_ck_out_en(struct msmsdcc_host *host,
+						u8 poll)
+{
+	int rc = 0;
+	u32 wait_cnt = 50;
+	u8 ck_out_en = 0;
+
+	/* poll for MCI_CK_OUT_EN bit.  max. poll time = 50us */
+	ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
+			MCI_CK_OUT_EN);
+
+	while (ck_out_en != poll) {
+		if (--wait_cnt == 0) {
+			pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
+				mmc_hostname(host->mmc), __func__, poll);
+			rc = -ETIMEDOUT;
+			goto out;
+		}
+		udelay(1);
+
+		ck_out_en = !!(readl_relaxed(host->base + MCI_DLL_CONFIG) &
+			MCI_CK_OUT_EN);
+	}
+out:
+	return rc;
+}
+
+/*
+ * Enable a CDR circuit in CM_SDC4_DLL block to enable automatic
+ * calibration sequence. This function should be called before
+ * enabling AUTO_CMD19 bit in MCI_CMD register for block read
+ * commands (CMD17/CMD18).
+ *
+ * This function gets called when host spinlock acquired.
+ */
+static int msmsdcc_enable_cdr_cm_sdc4_dll(struct msmsdcc_host *host)
+{
+	int rc = 0;
+	u32 config;
+
+	config = readl_relaxed(host->base + MCI_DLL_CONFIG);
+	config |= MCI_CDR_EN;
+	config &= ~(MCI_CDR_EXT_EN | MCI_CK_OUT_EN);
+	writel_relaxed(config, host->base + MCI_DLL_CONFIG);
+
+	/* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
+	rc = msmsdcc_dll_poll_ck_out_en(host, 0);
+	if (rc)
+		goto err_out;
+
+	/* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
+	writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
+			| MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
+
+	/* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
+	rc = msmsdcc_dll_poll_ck_out_en(host, 1);
+	if (rc)
+		goto err_out;
+
+	goto out;
+
+err_out:
+	pr_err("%s: %s: Failed\n", mmc_hostname(host->mmc), __func__);
+out:
+	return rc;
+}
+
+static int msmsdcc_config_cm_sdc4_dll_phase(struct msmsdcc_host *host,
+						u8 phase)
+{
+	int rc = 0;
+	u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6,
+					0x7, 0x5, 0x4, 0x8, 0x9,
+					0xB, 0xA, 0xE, 0xF, 0xD,
+					0xC};
+	unsigned long flags;
+	u32 config;
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	config = readl_relaxed(host->base + MCI_DLL_CONFIG);
+	config &= ~(MCI_CDR_EN | MCI_CK_OUT_EN);
+	config |= (MCI_CDR_EXT_EN | MCI_DLL_EN);
+	writel_relaxed(config, host->base + MCI_DLL_CONFIG);
+
+	/* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '0' */
+	rc = msmsdcc_dll_poll_ck_out_en(host, 0);
+	if (rc)
+		goto err_out;
+
+	/*
+	 * Write the selected DLL clock output phase (0 ... 15)
+	 * to CDR_SELEXT bit field of MCI_DLL_CONFIG register.
+	 */
+	writel_relaxed(((readl_relaxed(host->base + MCI_DLL_CONFIG)
+			& ~(0xF << 20))
+			| (grey_coded_phase_table[phase] << 20)),
+			host->base + MCI_DLL_CONFIG);
+
+	/* Set CK_OUT_EN bit of MCI_DLL_CONFIG register to 1. */
+	writel_relaxed((readl_relaxed(host->base + MCI_DLL_CONFIG)
+			| MCI_CK_OUT_EN), host->base + MCI_DLL_CONFIG);
+
+	/* Wait until CK_OUT_EN bit of MCI_DLL_CONFIG register becomes '1' */
+	rc = msmsdcc_dll_poll_ck_out_en(host, 1);
+	if (rc)
+		goto err_out;
+
+	config = readl_relaxed(host->base + MCI_DLL_CONFIG);
+	config |= MCI_CDR_EN;
+	config &= ~MCI_CDR_EXT_EN;
+	writel_relaxed(config, host->base + MCI_DLL_CONFIG);
+	goto out;
+
+err_out:
+	pr_err("%s: %s: Failed to set DLL phase: %d\n",
+		mmc_hostname(host->mmc), __func__, phase);
+out:
+	spin_unlock_irqrestore(&host->lock, flags);
+	return rc;
+}
+
+/*
+ * Find out the greatest range of consecuitive selected
+ * DLL clock output phases that can be used as sampling
+ * setting for SD3.0 UHS-I card read operation (in SDR104
+ * timing mode) or for eMMC4.5 card read operation (in HS200
+ * timing mode).
+ * Select the 3/4 of the range and configure the DLL with the
+ * selected DLL clock output phase.
+*/
+
+static u8 find_most_appropriate_phase(struct msmsdcc_host *host,
+				u8 *phase_table, u8 total_phases)
+{
+	u8 ret, temp;
+	u8 ranges[16][16] = { {0}, {0} };
+	u8 phases_per_row[16] = {0};
+	int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
+	int cnt;
+
+	for (cnt = 0; cnt <= total_phases; cnt++) {
+		ranges[row_index][col_index] = phase_table[cnt];
+		phases_per_row[row_index] += 1;
+		col_index++;
+
+		if ((cnt + 1) > total_phases) {
+			continue;
+		/* check if next phase in phase_table is consecutive or not */
+		} else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
+			row_index++;
+			col_index = 0;
+		}
+	}
+
+	for (cnt = 0; cnt <= total_phases; cnt++) {
+		if (phases_per_row[cnt] > curr_max) {
+			curr_max = phases_per_row[cnt];
+			selected_row_index = cnt;
+		}
+	}
+
+	temp = ((curr_max * 3) / 4);
+	ret = ranges[selected_row_index][temp];
+
+	return ret;
+}
+
+static int msmsdcc_execute_tuning(struct mmc_host *mmc)
+{
+	int rc = 0;
+	struct msmsdcc_host *host = mmc_priv(mmc);
+	unsigned long	flags;
+	u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
+
+	pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
+
+	/* Tuning is only required for SDR104 modes */
+	if (!host->tuning_needed) {
+		rc = 0;
+		goto exit;
+	}
+
+	spin_lock_irqsave(&host->lock, flags);
+	WARN(!host->pwr, "SDCC power is turned off\n");
+	WARN(!host->clks_on, "SDCC clocks are turned off\n");
+	WARN(host->sdcc_irq_disabled, "SDCC IRQ is disabled\n");
+
+	host->cmd19_tuning_in_progress = 1;
 	msmsdcc_delay(host);
+	spin_unlock_irqrestore(&host->lock, flags);
+
 	/* first of all reset the tuning block */
 	rc = msmsdcc_init_cm_sdc4_dll(host);
 	if (rc)
@@ -2839,35 +2956,36 @@
 		}
 	} while (++phase < 16);
 
-	kfree(data_buf);
-
 	if (tuned_phase_cnt) {
 		tuned_phase_cnt--;
-		tuned_phase_cnt = (tuned_phase_cnt * 3) / 4;
-		phase = tuned_phases[tuned_phase_cnt];
+		phase = find_most_appropriate_phase(host, tuned_phases,
+							tuned_phase_cnt);
 		/*
 		 * Finally set the selected phase in delay
 		 * line hw block.
 		 */
 		rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
 		if (rc)
-			goto out;
+			goto kfree;
+		pr_debug("%s: %s: finally setting the tuning phase to %d\n",
+				mmc_hostname(mmc), __func__, phase);
 	} else {
 		/* tuning failed */
-		rc = -EAGAIN;
-		pr_err("%s: %s: no tuning point found",
+		pr_err("%s: %s: no tuning point found\n",
 			mmc_hostname(mmc), __func__);
+		msmsdcc_dump_sdcc_state(host);
+		rc = -EAGAIN;
 	}
-	goto out;
 
 kfree:
 	kfree(data_buf);
 out:
-	/* re-enable PWESAVE */
-	writel_relaxed((readl_relaxed(host->base + MMCICLOCK) |
-			MCI_CLK_PWRSAVE), host->base + MMCICLOCK);
+	spin_lock_irqsave(&host->lock, flags);
 	msmsdcc_delay(host);
 	host->cmd19_tuning_in_progress = 0;
+	spin_unlock_irqrestore(&host->lock, flags);
+exit:
+	pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
 	return rc;
 }
 
@@ -2897,7 +3015,7 @@
 	} else {
 		status = gpio_direction_input(gpio_no);
 		if (!status)
-			status = !gpio_get_value_cansleep(gpio_no);
+			status = gpio_get_value_cansleep(gpio_no);
 		gpio_free(gpio_no);
 	}
 	return status;
@@ -2910,15 +3028,36 @@
 	unsigned int status;
 
 	if (host->plat->status || host->plat->status_gpio) {
-		if (host->plat->status)
+		if (host->plat->status) {
 			status = host->plat->status(mmc_dev(host->mmc));
-		else
+			host->eject = !status;
+		} else {
 			status = msmsdcc_slot_status(host);
 
-		host->eject = !status;
+			if (host->plat->is_status_gpio_active_low)
+				host->eject = status;
+			else
+				host->eject = !status;
+		}
+
 		if (status ^ host->oldstat) {
-			pr_info("%s: Slot status change detected (%d -> %d)\n",
-			       mmc_hostname(host->mmc), host->oldstat, status);
+			if (host->plat->status)
+				pr_info("%s: Slot status change detected "
+					"(%d -> %d)\n",
+					mmc_hostname(host->mmc),
+					host->oldstat, status);
+			else if (host->plat->is_status_gpio_active_low)
+				pr_info("%s: Slot status change detected "
+					"(%d -> %d) and the card detect GPIO"
+					" is ACTIVE_LOW\n",
+					mmc_hostname(host->mmc),
+					host->oldstat, status);
+			else
+				pr_info("%s: Slot status change detected "
+					"(%d -> %d) and the card detect GPIO"
+					" is ACTIVE_HIGH\n",
+					mmc_hostname(host->mmc),
+					host->oldstat, status);
 			mmc_detect_change(host->mmc, 0);
 		}
 		host->oldstat = status;
@@ -4049,11 +4188,17 @@
 	 */
 
 	if (plat->status || plat->status_gpio) {
-		if (plat->status)
+		if (plat->status) {
 			host->oldstat = plat->status(mmc_dev(host->mmc));
-		else
+			host->eject = !host->oldstat;
+		} else {
 			host->oldstat = msmsdcc_slot_status(host);
-		host->eject = !host->oldstat;
+
+			if (host->plat->is_status_gpio_active_low)
+				host->eject = host->oldstat;
+			else
+				host->eject = !host->oldstat;
+		}
 	}
 
 	if (plat->status_irq) {
@@ -4376,7 +4521,6 @@
 
 	if (host->plat->is_sdio_al_client)
 		return 0;
-
 	pr_debug("%s: %s: start\n", mmc_hostname(mmc), __func__);
 	if (mmc) {
 		host->sdcc_suspending = 1;
@@ -4411,7 +4555,11 @@
 		 * simple become pm usage counter increment operations.
 		 */
 		pm_runtime_get_noresume(dev);
-		rc = mmc_suspend_host(mmc);
+		/* If there is pending detect work abort runtime suspend */
+		if (unlikely(work_busy(&mmc->detect.work)))
+			rc = -EAGAIN;
+		else
+			rc = mmc_suspend_host(mmc);
 		pm_runtime_put_noidle(dev);
 
 		if (!rc) {
@@ -4442,7 +4590,7 @@
 		if (rc && wake_lock_active(&host->sdio_suspend_wlock))
 			wake_unlock(&host->sdio_suspend_wlock);
 	}
-	pr_debug("%s: %s: end\n", mmc_hostname(mmc), __func__);
+	pr_debug("%s: %s: ends with err=%d\n", mmc_hostname(mmc), __func__, rc);
 	return rc;
 }
 
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 84d4608..4e40468 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -458,4 +458,14 @@
 
 	  http://ubuntuforums.org/showpost.php?p=10589647&postcount=17
 
+config MSM_RMNET_USB
+	tristate "RMNET USB Driver"
+	depends on USB_USBNET
+	help
+	Select this if you have a Qualcomm modem device connected via USB
+	supporting RMNET network interface.
+
+	To compile this driver as a module, choose M here: the module
+	will be called rmnet_usb. If unsure, choose N.
+
 endmenu
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index c203fa2..84228c1 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -29,4 +29,5 @@
 obj-$(CONFIG_USB_NET_CX82310_ETH)	+= cx82310_eth.o
 obj-$(CONFIG_USB_NET_CDC_NCM)	+= cdc_ncm.o
 obj-$(CONFIG_USB_VL600)		+= lg-vl600.o
-
+rmnet_usb-y			:= rmnet_usb_ctrl.o rmnet_usb_data.o
+obj-$(CONFIG_MSM_RMNET_USB)	+= rmnet_usb.o
diff --git a/drivers/net/usb/rmnet_usb_ctrl.c b/drivers/net/usb/rmnet_usb_ctrl.c
new file mode 100644
index 0000000..b693b18
--- /dev/null
+++ b/drivers/net/usb/rmnet_usb_ctrl.c
@@ -0,0 +1,1071 @@
+/* Copyright (c) 2011, Code Aurora Forum. 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 version 2 and
+ * only 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.
+ */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+#include <linux/termios.h>
+#include <linux/ratelimit.h>
+#include <linux/debugfs.h>
+#include "rmnet_usb_ctrl.h"
+
+#define DEVICE_NAME			"hsicctl"
+#define NUM_CTRL_CHANNELS		4
+#define DEFAULT_READ_URB_LENGTH		0x1000
+
+/*Output control lines.*/
+#define ACM_CTRL_DTR		BIT(0)
+#define ACM_CTRL_RTS		BIT(1)
+
+
+/*Input control lines.*/
+#define ACM_CTRL_DSR		BIT(0)
+#define ACM_CTRL_CTS		BIT(1)
+#define ACM_CTRL_RI		BIT(2)
+#define ACM_CTRL_CD		BIT(3)
+
+/* polling interval for Interrupt ep */
+#define HS_INTERVAL		7
+#define FS_LS_INTERVAL		3
+
+/*echo modem_wait > /sys/class/hsicctl/hsicctlx/modem_wait*/
+static ssize_t modem_wait_store(struct device *d, struct device_attribute *attr,
+		const char *buf, size_t n)
+{
+	unsigned int		mdm_wait;
+	struct rmnet_ctrl_dev	*dev = dev_get_drvdata(d);
+
+	if (!dev)
+		return -ENODEV;
+
+	sscanf(buf, "%u", &mdm_wait);
+
+	dev->mdm_wait_timeout = mdm_wait;
+
+	return n;
+}
+
+static ssize_t modem_wait_show(struct device *d, struct device_attribute *attr,
+		char *buf)
+{
+	struct rmnet_ctrl_dev	*dev = dev_get_drvdata(d);
+
+	if (!dev)
+		return -ENODEV;
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", dev->mdm_wait_timeout);
+}
+
+static DEVICE_ATTR(modem_wait, 0666, modem_wait_show, modem_wait_store);
+
+static int	ctl_msg_dbg_mask;
+module_param_named(dump_ctrl_msg, ctl_msg_dbg_mask, int,
+		S_IRUGO | S_IWUSR | S_IWGRP);
+
+enum {
+	MSM_USB_CTL_DEBUG = 1U << 0,
+	MSM_USB_CTL_DUMP_BUFFER = 1U << 1,
+};
+
+#define DUMP_BUFFER(prestr, cnt, buf) \
+do { \
+	if (ctl_msg_dbg_mask & MSM_USB_CTL_DUMP_BUFFER) \
+			print_hex_dump(KERN_INFO, prestr, DUMP_PREFIX_NONE, \
+					16, 1, buf, cnt, false); \
+} while (0)
+
+#define DBG(x...) \
+		do { \
+			if (ctl_msg_dbg_mask & MSM_USB_CTL_DEBUG) \
+				pr_info(x); \
+		} while (0)
+
+struct rmnet_ctrl_dev		*ctrl_dev[NUM_CTRL_CHANNELS];
+struct class			*ctrldev_classp;
+static dev_t			ctrldev_num;
+
+struct ctrl_pkt {
+	size_t	data_size;
+	void	*data;
+};
+
+struct ctrl_pkt_list_elem {
+	struct list_head	list;
+	struct ctrl_pkt		cpkt;
+};
+
+static void resp_avail_cb(struct urb *);
+
+static int is_dev_connected(struct rmnet_ctrl_dev *dev)
+{
+	if (dev) {
+		mutex_lock(&dev->dev_lock);
+		if (!dev->intf) {
+			mutex_unlock(&dev->dev_lock);
+			return 0;
+		}
+		mutex_unlock(&dev->dev_lock);
+		return 1;
+	}
+	return 0;
+}
+
+static void notification_available_cb(struct urb *urb)
+{
+	int				status;
+	struct usb_cdc_notification	*ctrl;
+	struct usb_device		*udev;
+	struct rmnet_ctrl_dev		*dev = urb->context;
+
+	udev = interface_to_usbdev(dev->intf);
+
+	switch (urb->status) {
+	case 0:
+		/*success*/
+		break;
+
+	/*do not resubmit*/
+	case -ESHUTDOWN:
+	case -ENOENT:
+	case -ECONNRESET:
+	case -EPROTO:
+		return;
+	case -EPIPE:
+		pr_err_ratelimited("%s: Stall on int endpoint\n", __func__);
+		/* TBD : halt to be cleared in work */
+		return;
+
+	/*resubmit*/
+	case -EOVERFLOW:
+		pr_err_ratelimited("%s: Babble error happened\n", __func__);
+	default:
+		 pr_debug_ratelimited("%s: Non zero urb status = %d\n",
+			__func__, urb->status);
+		goto resubmit_int_urb;
+	}
+
+	ctrl = urb->transfer_buffer;
+
+	switch (ctrl->bNotificationType) {
+	case USB_CDC_NOTIFY_RESPONSE_AVAILABLE:
+		dev->resp_avail_cnt++;
+		usb_fill_control_urb(dev->rcvurb, udev,
+					usb_rcvctrlpipe(udev, 0),
+					(unsigned char *)dev->in_ctlreq,
+					dev->rcvbuf,
+					DEFAULT_READ_URB_LENGTH,
+					resp_avail_cb, dev);
+
+		status = usb_submit_urb(dev->rcvurb, GFP_ATOMIC);
+		if (status) {
+			dev_err(dev->devicep,
+			"%s: Error submitting Read URB %d\n", __func__, status);
+			goto resubmit_int_urb;
+		}
+
+		if (!dev->resp_available) {
+			dev->resp_available = true;
+			wake_up(&dev->open_wait_queue);
+		}
+
+		return;
+	default:
+		 dev_err(dev->devicep,
+			"%s:Command not implemented\n", __func__);
+	}
+
+resubmit_int_urb:
+	status = usb_submit_urb(urb, GFP_ATOMIC);
+	if (status)
+		dev_err(dev->devicep, "%s: Error re-submitting Int URB %d\n",
+		__func__, status);
+
+	return;
+}
+
+static void resp_avail_cb(struct urb *urb)
+{
+	struct usb_device		*udev;
+	struct ctrl_pkt_list_elem	*list_elem = NULL;
+	struct rmnet_ctrl_dev		*dev = urb->context;
+	void				*cpkt;
+	int				status = 0;
+	size_t				cpkt_size = 0;
+
+	udev = interface_to_usbdev(dev->intf);
+
+	switch (urb->status) {
+	case 0:
+		/*success*/
+		dev->get_encap_resp_cnt++;
+		break;
+
+	/*do not resubmit*/
+	case -ESHUTDOWN:
+	case -ENOENT:
+	case -ECONNRESET:
+	case -EPROTO:
+		return;
+
+	/*resubmit*/
+	case -EOVERFLOW:
+		pr_err_ratelimited("%s: Babble error happened\n", __func__);
+	default:
+		pr_debug_ratelimited("%s: Non zero urb status = %d\n",
+				__func__, urb->status);
+		goto resubmit_int_urb;
+	}
+
+	dev_dbg(dev->devicep, "Read %d bytes for %s\n",
+		urb->actual_length, dev->name);
+
+	cpkt = urb->transfer_buffer;
+	cpkt_size = urb->actual_length;
+
+	list_elem = kmalloc(sizeof(struct ctrl_pkt_list_elem), GFP_ATOMIC);
+	if (!list_elem) {
+		dev_err(dev->devicep, "%s: list_elem alloc failed\n", __func__);
+		return;
+	}
+	list_elem->cpkt.data = kmalloc(cpkt_size, GFP_ATOMIC);
+	if (!list_elem->cpkt.data) {
+		dev_err(dev->devicep, "%s: list_elem->data alloc failed\n",
+			__func__);
+		kfree(list_elem);
+		return;
+	}
+	memcpy(list_elem->cpkt.data, cpkt, cpkt_size);
+	list_elem->cpkt.data_size = cpkt_size;
+	spin_lock(&dev->rx_lock);
+	list_add_tail(&list_elem->list, &dev->rx_list);
+	spin_unlock(&dev->rx_lock);
+
+	wake_up(&dev->read_wait_queue);
+
+resubmit_int_urb:
+	/*re-submit int urb to check response available*/
+	status = usb_submit_urb(dev->inturb, GFP_ATOMIC);
+	if (status)
+		dev_err(dev->devicep, "%s: Error re-submitting Int URB %d\n",
+			__func__, status);
+}
+
+static int rmnet_usb_ctrl_start_rx(struct rmnet_ctrl_dev *dev)
+{
+	int	retval = 0;
+
+	retval = usb_autopm_get_interface(dev->intf);
+	if (retval < 0) {
+		dev_err(dev->devicep, "%s Resumption fail\n", __func__);
+		goto done_nopm;
+	}
+
+	retval = usb_submit_urb(dev->inturb, GFP_KERNEL);
+	if (retval < 0)
+		dev_err(dev->devicep, "%s Intr submit %d\n", __func__, retval);
+
+	usb_autopm_put_interface(dev->intf);
+
+done_nopm:
+	return retval;
+}
+
+int rmnet_usb_ctrl_stop_rx(struct rmnet_ctrl_dev *dev)
+{
+	if (!is_dev_connected(dev)) {
+		dev_dbg(dev->devicep, "%s: Ctrl device disconnected\n",
+			__func__);
+		return -ENODEV;
+	}
+
+	dev_dbg(dev->devicep, "%s\n", __func__);
+
+	usb_kill_urb(dev->rcvurb);
+	usb_kill_urb(dev->inturb);
+
+	return 0;
+}
+
+int rmnet_usb_ctrl_start(struct rmnet_ctrl_dev *dev)
+{
+	int	status = 0;
+
+	mutex_lock(&dev->dev_lock);
+	if (dev->is_opened)
+		status = rmnet_usb_ctrl_start_rx(dev);
+	mutex_unlock(&dev->dev_lock);
+
+	return status;
+}
+
+static int rmnet_usb_ctrl_alloc_rx(struct rmnet_ctrl_dev *dev)
+{
+	int	retval = -ENOMEM;
+
+	dev->rcvurb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!dev->rcvurb) {
+		pr_err("%s: Error allocating read urb\n", __func__);
+		goto nomem;
+	}
+
+	dev->rcvbuf = kmalloc(DEFAULT_READ_URB_LENGTH, GFP_KERNEL);
+	if (!dev->rcvbuf) {
+		pr_err("%s: Error allocating read buffer\n", __func__);
+		goto nomem;
+	}
+
+	dev->in_ctlreq = kmalloc(sizeof(*dev->in_ctlreq), GFP_KERNEL);
+	if (!dev->in_ctlreq) {
+		pr_err("%s: Error allocating setup packet buffer\n", __func__);
+		goto nomem;
+	}
+
+	return 0;
+
+nomem:
+	usb_free_urb(dev->rcvurb);
+	kfree(dev->rcvbuf);
+	kfree(dev->in_ctlreq);
+
+	return retval;
+
+}
+static int rmnet_usb_ctrl_write_cmd(struct rmnet_ctrl_dev *dev)
+{
+	int			retval = 0;
+	struct usb_device	*udev;
+
+	if (!is_dev_connected(dev))
+		return -ENODEV;
+
+	udev = interface_to_usbdev(dev->intf);
+	retval = usb_autopm_get_interface(dev->intf);
+	if (retval < 0) {
+		dev_err(dev->devicep, "%s: Unable to resume interface: %d\n",
+			__func__, retval);
+
+		/*
+		* Revisit if (retval == -EPERM)
+		*		rmnet_usb_suspend(dev->intf, PMSG_SUSPEND);
+		*/
+
+		return retval;
+	}
+	dev->set_ctrl_line_state_cnt++;
+	retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+		USB_CDC_REQ_SET_CONTROL_LINE_STATE,
+		(USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE),
+		dev->cbits_tomdm,
+		dev->intf->cur_altsetting->desc.bInterfaceNumber,
+		NULL, 0, USB_CTRL_SET_TIMEOUT);
+	usb_autopm_put_interface(dev->intf);
+
+	return retval;
+}
+
+static void ctrl_write_callback(struct urb *urb)
+{
+	struct rmnet_ctrl_dev	*dev = urb->context;
+
+	if (urb->status) {
+		dev->tx_ctrl_err_cnt++;
+		pr_debug_ratelimited("Write status/size %d/%d\n",
+				urb->status, urb->actual_length);
+	}
+
+	kfree(urb->setup_packet);
+	kfree(urb->transfer_buffer);
+	usb_free_urb(urb);
+	usb_autopm_put_interface_async(dev->intf);
+}
+
+static int rmnet_usb_ctrl_write(struct rmnet_ctrl_dev *dev, char *buf,
+		size_t size)
+{
+	int			result;
+	struct urb		*sndurb;
+	struct usb_ctrlrequest	*out_ctlreq;
+	struct usb_device	*udev;
+
+	if (!is_dev_connected(dev))
+		return -ENETRESET;
+
+	udev = interface_to_usbdev(dev->intf);
+
+	sndurb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!sndurb) {
+		dev_err(dev->devicep, "Error allocating read urb\n");
+		return -ENOMEM;
+	}
+
+	out_ctlreq = kmalloc(sizeof(*out_ctlreq), GFP_KERNEL);
+	if (!out_ctlreq) {
+		usb_free_urb(sndurb);
+		dev_err(dev->devicep, "Error allocating setup packet buffer\n");
+		return -ENOMEM;
+	}
+
+	/* CDC Send Encapsulated Request packet */
+	out_ctlreq->bRequestType = (USB_DIR_OUT | USB_TYPE_CLASS |
+			     USB_RECIP_INTERFACE);
+	out_ctlreq->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND;
+	out_ctlreq->wValue = 0;
+	out_ctlreq->wIndex = dev->intf->cur_altsetting->desc.bInterfaceNumber;
+	out_ctlreq->wLength = cpu_to_le16(size);
+
+	usb_fill_control_urb(sndurb, udev,
+			     usb_sndctrlpipe(udev, 0),
+			     (unsigned char *)out_ctlreq, (void *)buf, size,
+			     ctrl_write_callback, dev);
+
+	result = usb_autopm_get_interface_async(dev->intf);
+	if (result < 0) {
+		dev_err(dev->devicep, "%s: Unable to resume interface: %d\n",
+			__func__, result);
+
+		/*
+		* Revisit:  if (result == -EPERM)
+		*		rmnet_usb_suspend(dev->intf, PMSG_SUSPEND);
+		*/
+
+		usb_free_urb(sndurb);
+		kfree(out_ctlreq);
+		return result;
+	}
+
+	usb_anchor_urb(sndurb, &dev->tx_submitted);
+	dev->snd_encap_cmd_cnt++;
+	result = usb_submit_urb(sndurb, GFP_KERNEL);
+	if (result < 0) {
+		dev_err(dev->devicep, "%s: Submit URB error %d\n",
+			__func__, result);
+		dev->snd_encap_cmd_cnt--;
+		usb_autopm_put_interface_async(dev->intf);
+		usb_unanchor_urb(sndurb);
+		usb_free_urb(sndurb);
+		kfree(out_ctlreq);
+		return result;
+	}
+
+	return size;
+}
+
+static int rmnet_ctl_open(struct inode *inode, struct file *file)
+{
+	int			retval = 0;
+	struct rmnet_ctrl_dev	*dev =
+		container_of(inode->i_cdev, struct rmnet_ctrl_dev, cdev);
+
+	if (!dev)
+		return -ENODEV;
+
+	if (dev->is_opened)
+		goto already_opened;
+
+ctrl_open:
+	if (!is_dev_connected(dev)) {
+		dev_dbg(dev->devicep, "%s: Device not connected\n",
+			__func__);
+		return -ENODEV;
+	}
+
+	/*block open to get first response available from mdm*/
+	if (dev->mdm_wait_timeout && !dev->resp_available) {
+		retval = wait_event_interruptible_timeout(
+					dev->open_wait_queue,
+					dev->resp_available ||
+					!is_dev_connected(dev),
+					msecs_to_jiffies(dev->mdm_wait_timeout *
+									1000));
+		if (retval == 0) {
+			dev_err(dev->devicep, "%s: Timeout opening %s\n",
+						__func__, dev->name);
+			return -ETIMEDOUT;
+		} else if (retval < 0) {
+			dev_err(dev->devicep, "%s: Error waiting for %s\n",
+						__func__, dev->name);
+			return retval;
+		}
+
+		goto ctrl_open;
+	}
+
+	if (!dev->resp_available) {
+		dev_dbg(dev->devicep, "%s: Connection timedout opening %s\n",
+					__func__, dev->name);
+		return -ETIMEDOUT;
+	}
+
+	mutex_lock(&dev->dev_lock);
+	dev->is_opened = 1;
+	mutex_unlock(&dev->dev_lock);
+
+	file->private_data = dev;
+
+already_opened:
+	DBG("%s: Open called for %s\n", __func__, dev->name);
+
+	return 0;
+}
+
+static int rmnet_ctl_release(struct inode *inode, struct file *file)
+{
+	struct ctrl_pkt_list_elem	*list_elem = NULL;
+	struct rmnet_ctrl_dev		*dev;
+	unsigned long			flag;
+
+	dev = file->private_data;
+	if (!dev)
+		return -ENODEV;
+
+	DBG("%s Called on %s device\n", __func__, dev->name);
+
+	spin_lock_irqsave(&dev->rx_lock, flag);
+	while (!list_empty(&dev->rx_list)) {
+		list_elem = list_first_entry(
+				&dev->rx_list,
+				struct ctrl_pkt_list_elem,
+				list);
+		list_del(&list_elem->list);
+		kfree(list_elem->cpkt.data);
+		kfree(list_elem);
+	}
+	spin_unlock_irqrestore(&dev->rx_lock, flag);
+
+	mutex_lock(&dev->dev_lock);
+	dev->is_opened = 0;
+	mutex_unlock(&dev->dev_lock);
+
+	rmnet_usb_ctrl_stop_rx(dev);
+
+	if (is_dev_connected(dev))
+		usb_kill_anchored_urbs(&dev->tx_submitted);
+
+	file->private_data = NULL;
+
+	return 0;
+}
+
+static ssize_t rmnet_ctl_read(struct file *file, char __user *buf, size_t count,
+		loff_t *ppos)
+{
+	int				retval = 0;
+	int				bytes_to_read;
+	struct rmnet_ctrl_dev		*dev;
+	struct ctrl_pkt_list_elem	*list_elem = NULL;
+	unsigned long			flags;
+
+	dev = file->private_data;
+	if (!dev)
+		return -ENODEV;
+
+	DBG("%s: Read from %s\n", __func__, dev->name);
+
+ctrl_read:
+	if (!is_dev_connected(dev)) {
+		dev_err(dev->devicep, "%s: Device not connected\n",
+			__func__);
+		return -ENETRESET;
+	}
+	spin_lock_irqsave(&dev->rx_lock, flags);
+	if (list_empty(&dev->rx_list)) {
+		spin_unlock_irqrestore(&dev->rx_lock, flags);
+
+		retval = wait_event_interruptible(dev->read_wait_queue,
+					!list_empty(&dev->rx_list) ||
+					!is_dev_connected(dev));
+		if (retval < 0)
+			return retval;
+
+		goto ctrl_read;
+	}
+
+	list_elem = list_first_entry(&dev->rx_list,
+				     struct ctrl_pkt_list_elem, list);
+	bytes_to_read = (uint32_t)(list_elem->cpkt.data_size);
+	if (bytes_to_read > count) {
+		spin_unlock_irqrestore(&dev->rx_lock, flags);
+		dev_err(dev->devicep, "%s: Packet size %d > buf size %d\n",
+			__func__, bytes_to_read, count);
+		return -ENOMEM;
+	}
+	spin_unlock_irqrestore(&dev->rx_lock, flags);
+
+	if (copy_to_user(buf, list_elem->cpkt.data, bytes_to_read)) {
+			dev_err(dev->devicep,
+				"%s: copy_to_user failed for %s\n",
+				__func__, dev->name);
+		return -EFAULT;
+	}
+	spin_lock_irqsave(&dev->rx_lock, flags);
+	list_del(&list_elem->list);
+	spin_unlock_irqrestore(&dev->rx_lock, flags);
+
+	kfree(list_elem->cpkt.data);
+	kfree(list_elem);
+	DBG("%s: Returning %d bytes to %s\n", __func__, bytes_to_read,
+			dev->name);
+	DUMP_BUFFER("Read: ", bytes_to_read, buf);
+
+	return bytes_to_read;
+}
+
+static ssize_t rmnet_ctl_write(struct file *file, const char __user * buf,
+		size_t size, loff_t *pos)
+{
+	int			status;
+	void			*wbuf;
+	struct rmnet_ctrl_dev	*dev = file->private_data;
+
+	if (!dev)
+		return -ENODEV;
+
+	if (size <= 0)
+		return -EINVAL;
+
+	if (!is_dev_connected(dev))
+		return -ENETRESET;
+
+	DBG("%s: Writing %i bytes on %s\n", __func__, size, dev->name);
+
+	wbuf = kmalloc(size , GFP_KERNEL);
+	if (!wbuf)
+		return -ENOMEM;
+
+	status = copy_from_user(wbuf , buf, size);
+	if (status) {
+		dev_err(dev->devicep,
+		"%s: Unable to copy data from userspace %d\n",
+		__func__, status);
+		kfree(wbuf);
+		return status;
+	}
+	DUMP_BUFFER("Write: ", size, buf);
+
+	status = rmnet_usb_ctrl_write(dev, wbuf, size);
+	if (status == size)
+		return size;
+
+	return status;
+}
+
+static int rmnet_ctrl_tiocmset(struct rmnet_ctrl_dev *dev, unsigned int set,
+		unsigned int clear)
+{
+	mutex_lock(&dev->dev_lock);
+	if (set & TIOCM_DTR)
+		dev->cbits_tomdm |= ACM_CTRL_DTR;
+
+	/*
+	 * TBD if (set & TIOCM_RTS)
+	 *	dev->cbits_tomdm |= ACM_CTRL_RTS;
+	 */
+
+	if (clear & TIOCM_DTR)
+		dev->cbits_tomdm &= ~ACM_CTRL_DTR;
+
+	/*
+	 * (clear & TIOCM_RTS)
+	 *	dev->cbits_tomdm &= ~ACM_CTRL_RTS;
+	 */
+
+	mutex_unlock(&dev->dev_lock);
+
+	return rmnet_usb_ctrl_write_cmd(dev);
+}
+
+static int rmnet_ctrl_tiocmget(struct rmnet_ctrl_dev *dev)
+{
+	int	ret;
+
+	mutex_lock(&dev->dev_lock);
+	ret =
+	/*
+	 * TBD(dev->cbits_tolocal & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
+	 * (dev->cbits_tolocal & ACM_CTRL_CTS ? TIOCM_CTS : 0) |
+	 */
+	(dev->cbits_tolocal & ACM_CTRL_CD ? TIOCM_CD : 0) |
+	/*
+	 * TBD (dev->cbits_tolocal & ACM_CTRL_RI ? TIOCM_RI : 0) |
+	 *(dev->cbits_tomdm & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
+	*/
+	(dev->cbits_tomdm & ACM_CTRL_DTR ? TIOCM_DTR : 0);
+	mutex_unlock(&dev->dev_lock);
+
+	return ret;
+}
+
+static long rmnet_ctrl_ioctl(struct file *file, unsigned int cmd,
+		unsigned long arg)
+{
+	int			ret;
+	struct rmnet_ctrl_dev	*dev;
+
+	dev = file->private_data;
+	if (!dev)
+		return -ENODEV;
+
+	switch (cmd) {
+	case TIOCMGET:
+
+		ret = rmnet_ctrl_tiocmget(dev);
+		break;
+	case TIOCMSET:
+		ret = rmnet_ctrl_tiocmset(dev, arg, ~arg);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static const struct file_operations ctrldev_fops = {
+	.owner = THIS_MODULE,
+	.read  = rmnet_ctl_read,
+	.write = rmnet_ctl_write,
+	.unlocked_ioctl = rmnet_ctrl_ioctl,
+	.open  = rmnet_ctl_open,
+	.release = rmnet_ctl_release,
+};
+
+int rmnet_usb_ctrl_probe(struct usb_interface *intf,
+		struct usb_host_endpoint *int_in, struct rmnet_ctrl_dev *dev)
+{
+	u16				wMaxPacketSize;
+	struct usb_endpoint_descriptor	*ep;
+	struct usb_device		*udev;
+	int				interval;
+	int				ret = 0;
+
+	udev = interface_to_usbdev(intf);
+
+	if (!dev) {
+		pr_err("%s: Ctrl device not found\n", __func__);
+		return -ENODEV;
+	}
+	dev->int_pipe = usb_rcvintpipe(udev,
+		int_in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+
+	mutex_lock(&dev->dev_lock);
+	dev->intf = intf;
+
+	/*TBD: for now just update CD status*/
+	dev->cbits_tolocal = ACM_CTRL_CD;
+
+	/*send DTR high to modem*/
+	dev->cbits_tomdm = ACM_CTRL_DTR;
+	mutex_unlock(&dev->dev_lock);
+
+	dev->resp_available = false;
+	dev->snd_encap_cmd_cnt = 0;
+	dev->get_encap_resp_cnt = 0;
+	dev->resp_avail_cnt = 0;
+	dev->tx_ctrl_err_cnt = 0;
+	dev->set_ctrl_line_state_cnt = 0;
+
+	dev->inturb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!dev->inturb) {
+		dev_err(dev->devicep, "Error allocating int urb\n");
+		return -ENOMEM;
+	}
+
+	/*use max pkt size from ep desc*/
+	ep = &dev->intf->cur_altsetting->endpoint[0].desc;
+	wMaxPacketSize = le16_to_cpu(ep->wMaxPacketSize);
+
+	dev->intbuf = kmalloc(wMaxPacketSize, GFP_KERNEL);
+	if (!dev->intbuf) {
+		usb_free_urb(dev->inturb);
+		dev_err(dev->devicep, "Error allocating int buffer\n");
+		return -ENOMEM;
+	}
+
+	dev->in_ctlreq->bRequestType =
+		(USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
+	dev->in_ctlreq->bRequest  = USB_CDC_GET_ENCAPSULATED_RESPONSE;
+	dev->in_ctlreq->wValue = 0;
+	dev->in_ctlreq->wIndex =
+		dev->intf->cur_altsetting->desc.bInterfaceNumber;
+	dev->in_ctlreq->wLength = cpu_to_le16(DEFAULT_READ_URB_LENGTH);
+
+	interval =
+		max((int)int_in->desc.bInterval,
+		(udev->speed == USB_SPEED_HIGH) ? HS_INTERVAL : FS_LS_INTERVAL);
+
+	usb_fill_int_urb(dev->inturb, udev,
+			 dev->int_pipe,
+			 dev->intbuf, wMaxPacketSize,
+			 notification_available_cb, dev, interval);
+
+	ret = rmnet_usb_ctrl_write_cmd(dev);
+	if (ret < 0)
+		return ret;
+
+	return rmnet_usb_ctrl_start_rx(dev);
+}
+
+void rmnet_usb_ctrl_disconnect(struct rmnet_ctrl_dev *dev)
+{
+	rmnet_usb_ctrl_stop_rx(dev);
+
+	mutex_lock(&dev->dev_lock);
+
+	/*TBD: for now just update CD status*/
+	dev->cbits_tolocal = ~ACM_CTRL_CD;
+
+	dev->cbits_tomdm = ~ACM_CTRL_DTR;
+	dev->intf = NULL;
+	mutex_unlock(&dev->dev_lock);
+
+	usb_free_urb(dev->inturb);
+	dev->inturb = NULL;
+
+	kfree(dev->intbuf);
+	dev->intbuf = NULL;
+
+	usb_kill_anchored_urbs(&dev->tx_submitted);
+}
+
+#if defined(CONFIG_DEBUG_FS)
+#define DEBUG_BUF_SIZE	1024
+static ssize_t rmnet_usb_ctrl_read_stats(struct file *file, char __user *ubuf,
+		size_t count, loff_t *ppos)
+{
+	struct rmnet_ctrl_dev	*dev;
+	char			*buf;
+	int			ret;
+	int			i;
+	int			temp = 0;
+
+	buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	for (i = 0; i < NUM_CTRL_CHANNELS; i++) {
+		dev = ctrl_dev[i];
+		if (!dev)
+			continue;
+
+		temp += scnprintf(buf + temp, DEBUG_BUF_SIZE - temp,
+				"\n#ctrl_dev: %p     Name: %s#\n"
+				"snd encap cmd cnt         %u\n"
+				"resp avail cnt:           %u\n"
+				"get encap resp cnt:       %u\n"
+				"set ctrl line state cnt:  %u\n"
+				"tx_err_cnt:               %u\n"
+				"cbits_tolocal:            %d\n"
+				"cbits_tomdm:              %d\n"
+				"mdm_wait_timeout:         %u\n"
+				"dev opened:               %s\n",
+				dev, dev->name,
+				dev->snd_encap_cmd_cnt,
+				dev->resp_avail_cnt,
+				dev->get_encap_resp_cnt,
+				dev->set_ctrl_line_state_cnt,
+				dev->tx_ctrl_err_cnt,
+				dev->cbits_tolocal,
+				dev->cbits_tomdm,
+				dev->mdm_wait_timeout,
+				dev->is_opened ? "OPEN" : "CLOSE");
+
+	}
+
+	ret = simple_read_from_buffer(ubuf, count, ppos, buf, temp);
+
+	kfree(buf);
+
+	return ret;
+}
+
+static ssize_t rmnet_usb_ctrl_reset_stats(struct file *file, const char __user *
+		buf, size_t count, loff_t *ppos)
+{
+	struct rmnet_ctrl_dev	*dev;
+	int			i;
+
+	for (i = 0; i < NUM_CTRL_CHANNELS; i++) {
+		dev = ctrl_dev[i];
+		if (!dev)
+			continue;
+
+		dev->snd_encap_cmd_cnt = 0;
+		dev->resp_avail_cnt = 0;
+		dev->get_encap_resp_cnt = 0;
+		dev->set_ctrl_line_state_cnt = 0;
+		dev->tx_ctrl_err_cnt = 0;
+	}
+	return count;
+}
+
+const struct file_operations rmnet_usb_ctrl_stats_ops = {
+	.read = rmnet_usb_ctrl_read_stats,
+	.write = rmnet_usb_ctrl_reset_stats,
+};
+
+struct dentry	*usb_ctrl_dent;
+struct dentry	*usb_ctrl_dfile;
+static void rmnet_usb_ctrl_debugfs_init(void)
+{
+	usb_ctrl_dent = debugfs_create_dir("rmnet_usb_ctrl", 0);
+	if (IS_ERR(usb_ctrl_dent))
+		return;
+
+	usb_ctrl_dfile = debugfs_create_file("status", 0644, usb_ctrl_dent, 0,
+			&rmnet_usb_ctrl_stats_ops);
+	if (!usb_ctrl_dfile || IS_ERR(usb_ctrl_dfile))
+		debugfs_remove(usb_ctrl_dent);
+}
+
+static void rmnet_usb_ctrl_debugfs_exit(void)
+{
+	debugfs_remove(usb_ctrl_dfile);
+	debugfs_remove(usb_ctrl_dent);
+}
+
+#else
+static void rmnet_usb_ctrl_debugfs_init(void) { }
+static void rmnet_usb_ctrl_debugfs_exit(void) { }
+#endif
+
+int rmnet_usb_ctrl_init(void)
+{
+	struct rmnet_ctrl_dev	*dev;
+	int			n;
+	int			status;
+
+	for (n = 0; n < NUM_CTRL_CHANNELS; ++n) {
+
+		dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+		if (!dev) {
+			status = -ENOMEM;
+			goto error0;
+		}
+		/*for debug purpose*/
+		snprintf(dev->name, CTRL_DEV_MAX_LEN, "hsicctl%d", n);
+
+		mutex_init(&dev->dev_lock);
+		spin_lock_init(&dev->rx_lock);
+		init_waitqueue_head(&dev->read_wait_queue);
+		init_waitqueue_head(&dev->open_wait_queue);
+		INIT_LIST_HEAD(&dev->rx_list);
+		init_usb_anchor(&dev->tx_submitted);
+
+		status = rmnet_usb_ctrl_alloc_rx(dev);
+		if (status < 0) {
+			kfree(dev);
+			goto error0;
+		}
+
+		ctrl_dev[n] = dev;
+	}
+
+	status = alloc_chrdev_region(&ctrldev_num, 0, NUM_CTRL_CHANNELS,
+			DEVICE_NAME);
+	if (IS_ERR_VALUE(status)) {
+		pr_err("ERROR:%s: alloc_chrdev_region() ret %i.\n",
+		       __func__, status);
+		goto error0;
+	}
+
+	ctrldev_classp = class_create(THIS_MODULE, DEVICE_NAME);
+	if (IS_ERR(ctrldev_classp)) {
+		pr_err("ERROR:%s: class_create() ENOMEM\n", __func__);
+		status = -ENOMEM;
+		goto error1;
+	}
+	for (n = 0; n < NUM_CTRL_CHANNELS; ++n) {
+		cdev_init(&ctrl_dev[n]->cdev, &ctrldev_fops);
+		ctrl_dev[n]->cdev.owner = THIS_MODULE;
+
+		status = cdev_add(&ctrl_dev[n]->cdev, (ctrldev_num + n), 1);
+
+		if (IS_ERR_VALUE(status)) {
+			pr_err("%s: cdev_add() ret %i\n", __func__, status);
+			kfree(ctrl_dev[n]);
+			goto error2;
+		}
+
+		ctrl_dev[n]->devicep =
+				device_create(ctrldev_classp, NULL,
+				(ctrldev_num + n), NULL,
+				DEVICE_NAME "%d", n);
+
+		if (IS_ERR(ctrl_dev[n]->devicep)) {
+			pr_err("%s: device_create() ENOMEM\n", __func__);
+			status = -ENOMEM;
+			cdev_del(&ctrl_dev[n]->cdev);
+			kfree(ctrl_dev[n]);
+			goto error2;
+		}
+		/*create /sys/class/hsicctl/hsicctlx/modem_wait*/
+		status = device_create_file(ctrl_dev[n]->devicep,
+					&dev_attr_modem_wait);
+		if (status) {
+			device_destroy(ctrldev_classp,
+				MKDEV(MAJOR(ctrldev_num), n));
+			cdev_del(&ctrl_dev[n]->cdev);
+			kfree(ctrl_dev[n]);
+			goto error2;
+		}
+		dev_set_drvdata(ctrl_dev[n]->devicep, ctrl_dev[n]);
+	}
+
+	rmnet_usb_ctrl_debugfs_init();
+	pr_info("rmnet usb ctrl Initialized.\n");
+	return 0;
+
+error2:
+		while (--n >= 0) {
+			cdev_del(&ctrl_dev[n]->cdev);
+			device_destroy(ctrldev_classp,
+				MKDEV(MAJOR(ctrldev_num), n));
+		}
+
+		class_destroy(ctrldev_classp);
+		n = NUM_CTRL_CHANNELS;
+error1:
+	unregister_chrdev_region(MAJOR(ctrldev_num), NUM_CTRL_CHANNELS);
+error0:
+	while (--n >= 0)
+		kfree(ctrl_dev[n]);
+
+	return status;
+}
+
+void rmnet_usb_ctrl_exit(void)
+{
+	int	i;
+
+	for (i = 0; i < NUM_CTRL_CHANNELS; ++i) {
+		if (!ctrl_dev[i])
+			return;
+
+		kfree(ctrl_dev[i]->in_ctlreq);
+		kfree(ctrl_dev[i]->rcvbuf);
+		kfree(ctrl_dev[i]->intbuf);
+		usb_free_urb(ctrl_dev[i]->rcvurb);
+		usb_free_urb(ctrl_dev[i]->inturb);
+#if defined(DEBUG)
+		device_remove_file(ctrl_dev[i]->devicep, &dev_attr_modem_wait);
+#endif
+		cdev_del(&ctrl_dev[i]->cdev);
+		kfree(ctrl_dev[i]);
+		ctrl_dev[i] = NULL;
+		device_destroy(ctrldev_classp, MKDEV(MAJOR(ctrldev_num), i));
+	}
+
+	class_destroy(ctrldev_classp);
+	unregister_chrdev_region(MAJOR(ctrldev_num), NUM_CTRL_CHANNELS);
+	rmnet_usb_ctrl_debugfs_exit();
+}
diff --git a/drivers/net/usb/rmnet_usb_ctrl.h b/drivers/net/usb/rmnet_usb_ctrl.h
new file mode 100644
index 0000000..f6e5876
--- /dev/null
+++ b/drivers/net/usb/rmnet_usb_ctrl.h
@@ -0,0 +1,82 @@
+/* Copyright (c) 2011, Code Aurora Forum. 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 version 2 and
+ * only 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.
+ */
+
+#ifndef __RMNET_USB_CTRL_H
+#define __RMNET_USB_CTRL_H
+
+#include <linux/mutex.h>
+#include <linux/usb.h>
+#include <linux/cdev.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/cdc.h>
+
+#define CTRL_DEV_MAX_LEN 10
+
+struct rmnet_ctrl_dev {
+
+	/*for debugging purpose*/
+	char			name[CTRL_DEV_MAX_LEN];
+
+	struct cdev		cdev;
+	struct device		*devicep;
+
+	struct usb_interface	*intf;
+	unsigned int		int_pipe;
+	struct urb		*rcvurb;
+	struct urb		*inturb;
+	struct usb_anchor	tx_submitted;
+	void			*rcvbuf;
+	void			*intbuf;
+	struct usb_ctrlrequest	*in_ctlreq;
+
+	spinlock_t		rx_lock;
+	struct mutex		dev_lock;
+	struct list_head	rx_list;
+	wait_queue_head_t	read_wait_queue;
+	wait_queue_head_t	open_wait_queue;
+
+	unsigned		is_opened;
+
+	/*input control lines (DSR, CTS, CD, RI)*/
+	unsigned int		cbits_tolocal;
+
+	/*output control lines (DTR, RTS)*/
+	unsigned int		cbits_tomdm;
+
+	/*
+	 * track first resp available from mdm when it boots up
+	 * to avoid bigger  timeout value used by qmuxd
+	 */
+	bool			resp_available;
+
+	unsigned int		mdm_wait_timeout;
+
+	/*counters*/
+	unsigned int		snd_encap_cmd_cnt;
+	unsigned int		get_encap_resp_cnt;
+	unsigned int		resp_avail_cnt;
+	unsigned int		set_ctrl_line_state_cnt;
+	unsigned int		tx_ctrl_err_cnt;
+};
+
+extern struct rmnet_ctrl_dev *ctrl_dev[];
+
+extern int rmnet_usb_ctrl_start(struct rmnet_ctrl_dev *);
+extern int rmnet_usb_ctrl_stop_rx(struct rmnet_ctrl_dev *);
+extern int rmnet_usb_ctrl_init(void);
+extern void rmnet_usb_ctrl_exit(void);
+extern int rmnet_usb_ctrl_probe(struct usb_interface *intf,
+		struct usb_host_endpoint *status,
+		struct rmnet_ctrl_dev *dev);
+extern void rmnet_usb_ctrl_disconnect(struct rmnet_ctrl_dev *);
+
+#endif /* __RMNET_USB_H*/
diff --git a/drivers/net/usb/rmnet_usb_data.c b/drivers/net/usb/rmnet_usb_data.c
new file mode 100644
index 0000000..fa0cd82
--- /dev/null
+++ b/drivers/net/usb/rmnet_usb_data.c
@@ -0,0 +1,564 @@
+/* Copyright (c) 2011, Code Aurora Forum. 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 version 2 and
+ * only 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.
+ */
+
+#include <linux/mii.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/usb.h>
+#include <linux/usb/usbnet.h>
+#include <linux/msm_rmnet.h>
+
+#include "rmnet_usb_ctrl.h"
+
+#define RMNET_DATA_LEN			2000
+#define HEADROOM_FOR_QOS		8
+
+#define FIRST_RMNET_USB_INTERFACE	5
+#define NUM_EMBEDDED_RMNET_IFACE	4
+
+static int	data_msg_dbg_mask;
+
+enum {
+	DEBUG_MASK_LVL0 = 1U << 0,
+	DEBUG_MASK_LVL1 = 1U << 1,
+	DEBUG_MASK_LVL2 = 1U << 2,
+};
+
+#define DBG(m, x...) do { \
+		if (data_msg_dbg_mask & m) \
+			pr_info(x); \
+} while (0)
+
+/*echo dbg_mask > /sys/class/net/rmnet_usbx/dbg_mask*/
+static ssize_t dbg_mask_store(struct device *d,
+		struct device_attribute *attr,
+		const char *buf, size_t n)
+{
+	unsigned int		dbg_mask;
+	struct net_device	*dev = to_net_dev(d);
+	struct usbnet		*unet = netdev_priv(dev);
+
+	if (!dev)
+		return -ENODEV;
+
+	sscanf(buf, "%u", &dbg_mask);
+	/*enable dbg msgs for data driver*/
+	data_msg_dbg_mask = dbg_mask;
+
+	/*set default msg level*/
+	unet->msg_enable = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK;
+
+	/*enable netif_xxx msgs*/
+	if (dbg_mask & DEBUG_MASK_LVL0)
+		unet->msg_enable |= NETIF_MSG_IFUP | NETIF_MSG_IFDOWN;
+	if (dbg_mask & DEBUG_MASK_LVL1)
+		unet->msg_enable |= NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR
+			| NETIF_MSG_TX_QUEUED | NETIF_MSG_TX_DONE
+			| NETIF_MSG_RX_STATUS;
+
+	return n;
+}
+
+static ssize_t dbg_mask_show(struct device *d,
+		struct device_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", data_msg_dbg_mask);
+}
+
+static DEVICE_ATTR(dbg_mask, 0644, dbg_mask_show, dbg_mask_store);
+
+#define DBG0(x...) DBG(DEBUG_MASK_LVL0, x)
+#define DBG1(x...) DBG(DEBUG_MASK_LVL1, x)
+#define DBG2(x...) DBG(DEBUG_MASK_LVL2, x)
+
+static void rmnet_usb_setup(struct net_device *);
+static int rmnet_ioctl(struct net_device *, struct ifreq *, int);
+
+static int rmnet_usb_suspend(struct usb_interface *iface, pm_message_t message)
+{
+	struct usbnet		*unet;
+	struct rmnet_ctrl_dev	*dev;
+	int			time = 0;
+	int			retval = 0;
+
+	unet = usb_get_intfdata(iface);
+	if (!unet) {
+		pr_err("%s:data device not found\n", __func__);
+		retval = -ENODEV;
+		goto fail;
+	}
+
+	dev = (struct rmnet_ctrl_dev *)unet->data[1];
+	if (!dev) {
+		dev_err(&unet->udev->dev, "%s: ctrl device not found\n",
+				__func__);
+		retval = -ENODEV;
+		goto fail;
+	}
+
+	retval = usbnet_suspend(iface, message);
+	if (!retval) {
+		if (message.event & PM_EVENT_SUSPEND) {
+			time = usb_wait_anchor_empty_timeout(&dev->tx_submitted,
+								1000);
+			if (!time)
+				usb_kill_anchored_urbs(&dev->tx_submitted);
+
+			retval = rmnet_usb_ctrl_stop_rx(dev);
+			iface->dev.power.power_state.event = message.event;
+		}
+		/*  TBD : do we need to set/clear usbnet->udev->reset_resume*/
+		} else
+		dev_dbg(&unet->udev->dev,
+			"%s: device is busy can not suspend\n", __func__);
+
+fail:
+	return retval;
+}
+
+static int rmnet_usb_resume(struct usb_interface *iface)
+{
+	int			retval = 0;
+	int			oldstate;
+	struct usbnet		*unet;
+	struct rmnet_ctrl_dev	*dev;
+
+	unet = usb_get_intfdata(iface);
+	if (!unet) {
+		pr_err("%s:data device not found\n", __func__);
+		retval = -ENODEV;
+		goto fail;
+	}
+
+	dev = (struct rmnet_ctrl_dev *)unet->data[1];
+	if (!dev) {
+		dev_err(&unet->udev->dev, "%s: ctrl device not found\n",
+				__func__);
+		retval = -ENODEV;
+		goto fail;
+	}
+	oldstate = iface->dev.power.power_state.event;
+	iface->dev.power.power_state.event = PM_EVENT_ON;
+
+	retval = usbnet_resume(iface);
+	if (!retval) {
+
+		if (oldstate & PM_EVENT_SUSPEND)
+			retval = rmnet_usb_ctrl_start(dev);
+	}
+fail:
+	return retval;
+}
+
+static int rmnet_usb_bind(struct usbnet *usbnet, struct usb_interface *iface)
+{
+	struct usb_host_endpoint	*endpoint = NULL;
+	struct usb_host_endpoint	*bulk_in = NULL;
+	struct usb_host_endpoint	*bulk_out = NULL;
+	struct usb_host_endpoint	*int_in = NULL;
+	struct usb_device		*udev;
+	int				status = 0;
+	int				i;
+	int				numends;
+
+	udev = interface_to_usbdev(iface);
+	numends = iface->cur_altsetting->desc.bNumEndpoints;
+	for (i = 0; i < numends; i++) {
+		endpoint = iface->cur_altsetting->endpoint + i;
+		if (!endpoint) {
+			dev_err(&udev->dev, "%s: invalid endpoint %u\n",
+				__func__, i);
+			status = -EINVAL;
+			goto out;
+		}
+		if (usb_endpoint_is_bulk_in(&endpoint->desc))
+			bulk_in = endpoint;
+		else if (usb_endpoint_is_bulk_out(&endpoint->desc))
+			bulk_out = endpoint;
+		else if (usb_endpoint_is_int_in(&endpoint->desc))
+			int_in = endpoint;
+	}
+
+	if (!bulk_in || !bulk_out || !int_in) {
+		dev_err(&udev->dev, "%s: invalid endpoints\n", __func__);
+		status = -EINVAL;
+		goto out;
+	}
+	usbnet->in = usb_rcvbulkpipe(usbnet->udev,
+		bulk_in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+	usbnet->out = usb_sndbulkpipe(usbnet->udev,
+		bulk_out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+	usbnet->status = int_in;
+
+	/*change name of net device to rmnet_usbx here*/
+	strlcpy(usbnet->net->name, "rmnet_usb%d", IFNAMSIZ);
+
+	/*TBD: update rx_urb_size, curently set to eth frame len by usbnet*/
+out:
+	return status;
+}
+
+static struct sk_buff *rmnet_usb_tx_fixup(struct usbnet *dev,
+		struct sk_buff *skb, gfp_t flags)
+{
+	struct QMI_QOS_HDR_S	*qmih;
+
+	if (test_bit(RMNET_MODE_QOS, &dev->data[0])) {
+		qmih = (struct QMI_QOS_HDR_S *)
+		skb_push(skb, sizeof(struct QMI_QOS_HDR_S));
+		qmih->version = 1;
+		qmih->flags = 0;
+		qmih->flow_id = skb->mark;
+	 }
+
+	DBG1("[%s] Tx packet #%lu len=%d mark=0x%x\n",
+	    dev->net->name, dev->net->stats.tx_packets, skb->len, skb->mark);
+
+	return skb;
+}
+
+static __be16 rmnet_ip_type_trans(struct sk_buff *skb,
+	struct net_device *dev)
+{
+	__be16	protocol = 0;
+
+	skb->dev = dev;
+
+	switch (skb->data[0] & 0xf0) {
+	case 0x40:
+		protocol = htons(ETH_P_IP);
+		break;
+	case 0x60:
+		protocol = htons(ETH_P_IPV6);
+		break;
+	default:
+		pr_err("[%s] rmnet_recv() L3 protocol decode error: 0x%02x",
+		       dev->name, skb->data[0] & 0xf0);
+	}
+
+	return protocol;
+}
+
+static int rmnet_usb_rx_fixup(struct usbnet *dev,
+	struct sk_buff *skb)
+{
+
+	if (test_bit(RMNET_MODE_LLP_IP, &dev->data[0]))
+		skb->protocol = rmnet_ip_type_trans(skb, dev->net);
+	else /*set zero for eth mode*/
+		skb->protocol = 0;
+
+	DBG1("[%s] Rx packet #%lu len=%d\n",
+		dev->net->name, dev->net->stats.rx_packets, skb->len);
+
+	return 1;
+}
+
+static int rmnet_change_mtu(struct net_device *dev, int new_mtu)
+{
+	if (0 > new_mtu || RMNET_DATA_LEN < new_mtu)
+		return -EINVAL;
+
+	DBG0("[%s] MTU change: old=%d new=%d\n", dev->name, dev->mtu, new_mtu);
+
+	dev->mtu = new_mtu;
+
+	return 0;
+}
+
+static struct net_device_stats *rmnet_get_stats(struct net_device *dev)
+{
+		return &dev->stats;
+}
+
+static const struct net_device_ops rmnet_usb_ops_ether = {
+	.ndo_open = usbnet_open,
+	.ndo_stop = usbnet_stop,
+	.ndo_start_xmit = usbnet_start_xmit,
+	.ndo_get_stats = rmnet_get_stats,
+	/*.ndo_set_multicast_list = rmnet_set_multicast_list,*/
+	.ndo_tx_timeout = usbnet_tx_timeout,
+	.ndo_do_ioctl = rmnet_ioctl,
+	.ndo_change_mtu = usbnet_change_mtu,
+	.ndo_set_mac_address = eth_mac_addr,
+	.ndo_validate_addr = eth_validate_addr,
+};
+
+static const struct net_device_ops rmnet_usb_ops_ip = {
+	.ndo_open = usbnet_open,
+	.ndo_stop = usbnet_stop,
+	.ndo_start_xmit = usbnet_start_xmit,
+	.ndo_get_stats = rmnet_get_stats,
+	/*.ndo_set_multicast_list = rmnet_set_multicast_list,*/
+	.ndo_tx_timeout = usbnet_tx_timeout,
+	.ndo_do_ioctl = rmnet_ioctl,
+	.ndo_change_mtu = rmnet_change_mtu,
+	.ndo_set_mac_address = 0,
+	.ndo_validate_addr = 0,
+};
+
+
+static int rmnet_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct usbnet	*unet = netdev_priv(dev);
+	u32		old_opmode;
+	int		prev_mtu = dev->mtu;
+	int		rc = 0;
+
+	old_opmode = unet->data[0]; /*data[0] saves operation mode*/
+	/* Process IOCTL command */
+	switch (cmd) {
+	case RMNET_IOCTL_SET_LLP_ETHERNET:	/*Set Ethernet protocol*/
+		/* Perform Ethernet config only if in IP mode currently*/
+		if (test_bit(RMNET_MODE_LLP_IP, &unet->data[0])) {
+			ether_setup(dev);
+			random_ether_addr(dev->dev_addr);
+			dev->mtu = prev_mtu;
+			dev->netdev_ops = &rmnet_usb_ops_ether;
+			clear_bit(RMNET_MODE_LLP_IP, &unet->data[0]);
+			set_bit(RMNET_MODE_LLP_ETH, &unet->data[0]);
+			DBG0("[%s] rmnet_ioctl(): set Ethernet protocol mode\n",
+					dev->name);
+		}
+		break;
+
+	case RMNET_IOCTL_SET_LLP_IP:		/* Set RAWIP protocol*/
+		/* Perform IP config only if in Ethernet mode currently*/
+		if (test_bit(RMNET_MODE_LLP_ETH, &unet->data[0])) {
+
+			/* Undo config done in ether_setup() */
+			dev->header_ops = 0;  /* No header */
+			dev->type = ARPHRD_RAWIP;
+			dev->hard_header_len = 0;
+			dev->mtu = prev_mtu;
+			dev->addr_len = 0;
+			dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST);
+			dev->needed_headroom = HEADROOM_FOR_QOS;
+			dev->netdev_ops = &rmnet_usb_ops_ip;
+			clear_bit(RMNET_MODE_LLP_ETH, &unet->data[0]);
+			set_bit(RMNET_MODE_LLP_IP, &unet->data[0]);
+			DBG0("[%s] rmnet_ioctl(): set IP protocol mode\n",
+					dev->name);
+		}
+		break;
+
+	case RMNET_IOCTL_GET_LLP:	/* Get link protocol state */
+		ifr->ifr_ifru.ifru_data = (void *)(unet->data[0]
+						& (RMNET_MODE_LLP_ETH
+						| RMNET_MODE_LLP_IP));
+		break;
+
+	case RMNET_IOCTL_SET_QOS_ENABLE:	/* Set QoS header enabled*/
+		set_bit(RMNET_MODE_QOS, &unet->data[0]);
+		DBG0("[%s] rmnet_ioctl(): set QMI QOS header enable\n",
+				dev->name);
+		break;
+
+	case RMNET_IOCTL_SET_QOS_DISABLE:	/* Set QoS header disabled */
+		clear_bit(RMNET_MODE_QOS, &unet->data[0]);
+		DBG0("[%s] rmnet_ioctl(): set QMI QOS header disable\n",
+				dev->name);
+		break;
+
+	case RMNET_IOCTL_GET_QOS:		/* Get QoS header state */
+		ifr->ifr_ifru.ifru_data = (void *)(unet->data[0]
+						& RMNET_MODE_QOS);
+		break;
+
+	case RMNET_IOCTL_GET_OPMODE:		/* Get operation mode*/
+		ifr->ifr_ifru.ifru_data = (void *)unet->data[0];
+		break;
+
+	case RMNET_IOCTL_OPEN:			/* Open transport port */
+		rc = usbnet_open(dev);
+		DBG0("[%s] rmnet_ioctl(): open transport port\n", dev->name);
+		break;
+
+	case RMNET_IOCTL_CLOSE:			/* Close transport port*/
+		rc = usbnet_stop(dev);
+		DBG0("[%s] rmnet_ioctl(): close transport port\n", dev->name);
+		break;
+
+	default:
+		dev_err(&unet->udev->dev, "[%s] error: "
+			"rmnet_ioct called for unsupported cmd[%d]",
+			dev->name, cmd);
+		return -EINVAL;
+	}
+
+	DBG2("[%s] %s: cmd=0x%x opmode old=0x%08x new=0x%08lx\n",
+		dev->name, __func__, cmd, old_opmode, unet->data[0]);
+
+	return rc;
+}
+
+static void rmnet_usb_setup(struct net_device *dev)
+{
+	/* Using Ethernet mode by default */
+	dev->netdev_ops = &rmnet_usb_ops_ether;
+
+	/* set this after calling ether_setup */
+	dev->mtu = RMNET_DATA_LEN;
+
+	dev->needed_headroom = HEADROOM_FOR_QOS;
+	random_ether_addr(dev->dev_addr);
+	dev->watchdog_timeo = 1000; /* 10 seconds? */
+}
+
+static int rmnet_usb_probe(struct usb_interface *iface,
+		const struct usb_device_id *prod)
+{
+	struct usbnet		*unet;
+	struct usb_device	*udev;
+	int			iface_num;
+	int			last_rmnet_iface_num;
+	int			status = -ENODEV;
+
+	udev = interface_to_usbdev(iface);
+	iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
+	if (iface->num_altsetting != 1) {
+		dev_err(&udev->dev, "%s invalid num_altsetting %u\n",
+			__func__, iface->num_altsetting);
+		status = -EINVAL;
+		goto out;
+	}
+
+	last_rmnet_iface_num = (FIRST_RMNET_USB_INTERFACE +
+		 NUM_EMBEDDED_RMNET_IFACE - 1);
+
+	if (iface_num >= FIRST_RMNET_USB_INTERFACE &&
+		iface_num <= last_rmnet_iface_num) {
+		status = usbnet_probe(iface, prod);
+		if (status < 0) {
+			dev_err(&udev->dev, "usbnet_probe failed %d\n",
+				status);
+			goto out;
+		}
+		unet = usb_get_intfdata(iface);
+
+		/*set rmnet operation mode to eth by default*/
+		set_bit(RMNET_MODE_LLP_ETH, &unet->data[0]);
+
+		/*update net device*/
+		rmnet_usb_setup(unet->net);
+
+		/*create /sys/class/net/rmnet_usbx/dbg_mask*/
+		status = device_create_file(&unet->net->dev,
+				&dev_attr_dbg_mask);
+		if (status)
+			goto out;
+
+		/*save control device intstance */
+		unet->data[1] = (unsigned long)ctrl_dev	\
+		[iface_num - FIRST_RMNET_USB_INTERFACE];
+
+		status = rmnet_usb_ctrl_probe(iface, unet->status,
+			(struct rmnet_ctrl_dev *)unet->data[1]);
+	}
+out:
+	return status;
+}
+
+static void rmnet_usb_disconnect(struct usb_interface *intf)
+{
+	struct usbnet		*unet;
+	struct usb_device	*udev;
+	struct rmnet_ctrl_dev	*dev;
+	int			iface_num;
+	int			last_rmnet_iface_num;
+
+	udev = interface_to_usbdev(intf);
+	iface_num = intf->cur_altsetting->desc.bInterfaceNumber;
+
+	last_rmnet_iface_num = (FIRST_RMNET_USB_INTERFACE +
+			 NUM_EMBEDDED_RMNET_IFACE - 1);
+
+	if (iface_num >= FIRST_RMNET_USB_INTERFACE &&
+		iface_num <= last_rmnet_iface_num) {
+		unet = usb_get_intfdata(intf);
+		if (!unet) {
+			dev_err(&udev->dev, "%s:data device not found\n",
+					__func__);
+			return;
+		}
+		dev = (struct rmnet_ctrl_dev *)unet->data[1];
+		if (!dev) {
+			dev_err(&udev->dev, "%s:ctrl device not found\n",
+					__func__);
+			return;
+		}
+		unet->data[0] = 0;
+		unet->data[1] = 0;
+		rmnet_usb_ctrl_disconnect(dev);
+		device_remove_file(&unet->net->dev, &dev_attr_dbg_mask);
+		usbnet_disconnect(intf);
+	}
+}
+
+static const struct driver_info rmnet_info = {
+	.description   = "RmNET net device",
+	.bind          = rmnet_usb_bind,
+	.tx_fixup      = rmnet_usb_tx_fixup,
+	.rx_fixup      = rmnet_usb_rx_fixup,
+	.data          = 0,
+};
+
+static const struct usb_device_id vidpids[] = {
+	{
+		USB_DEVICE(0x05c6, 0x9048),	/* MDM9x15*/
+		.driver_info = (unsigned long)&rmnet_info,
+	},
+	{ },
+};
+
+MODULE_DEVICE_TABLE(usb, vidpids);
+
+static struct usb_driver rmnet_usb = {
+	.name       = "rmnet_usb",
+	.id_table   = vidpids,
+	.probe      = rmnet_usb_probe,
+	.disconnect = rmnet_usb_disconnect,
+	.suspend    = rmnet_usb_suspend,
+	.resume     = rmnet_usb_resume,
+	.supports_autosuspend = true,
+};
+
+static int __init rmnet_usb_init(void)
+{
+	int	retval;
+
+	retval = usb_register(&rmnet_usb);
+	if (retval) {
+		err("usb_register failed: %d", retval);
+		return retval;
+	}
+	/* initialize rmnet ctrl device here*/
+	retval = rmnet_usb_ctrl_init();
+	if (retval) {
+		usb_deregister(&rmnet_usb);
+		err("rmnet_usb_cmux_init failed: %d", retval);
+		return retval;
+	}
+
+	return 0;
+}
+module_init(rmnet_usb_init);
+
+static void __exit rmnet_usb_exit(void)
+{
+	rmnet_usb_ctrl_exit();
+	usb_deregister(&rmnet_usb);
+}
+module_exit(rmnet_usb_exit);
+
+MODULE_DESCRIPTION("msm rmnet usb device");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index ce395fe..dce8d6d 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -231,6 +231,9 @@
 		return;
 	}
 
+	if (!skb->protocol)
+		skb->protocol = eth_type_trans(skb, dev->net);
+
 	skb->protocol = eth_type_trans (skb, dev->net);
 	dev->net->stats.rx_packets++;
 	dev->net->stats.rx_bytes += skb->len;
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index df2d556..0af181b 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -1063,12 +1063,6 @@
 		soc = 100;
 	pr_debug("SOC = %u%%\n", soc);
 
-	if (bms_fake_battery) {
-		soc = BATTERY_POWER_SUPPLY_SOC;
-		pr_debug("setting SOC = %u%% bms_fake_battery = %d\n", soc,
-							bms_fake_battery);
-	}
-
 	if (soc < 0) {
 		pr_err("bad rem_usb_chg = %d rem_chg %d,"
 				"cc_mah %d, unusb_chg %d\n",
@@ -1085,7 +1079,7 @@
 
 	if (last_soc == -EINVAL || soc <= last_soc) {
 		last_soc = update_userspace ? soc : last_soc;
-		return soc;
+		return bms_fake_battery ? BATTERY_POWER_SUPPLY_SOC : soc;
 	}
 
 	/*
@@ -1093,27 +1087,14 @@
 	 * the device must be charging for reporting a higher soc, if not ignore
 	 * this soc and continue reporting the last_soc
 	 */
-	if (the_chip->start_percent != 0) {
+	if (the_chip->start_percent != -EINVAL) {
 		last_soc = soc;
 	} else {
 		pr_debug("soc = %d reporting last_soc = %d\n", soc, last_soc);
 		soc = last_soc;
 	}
 
-	return soc;
-}
-
-#define XOADC_MAX_1P25V		1312500
-#define XOADC_MIN_1P25V		1187500
-#define XOADC_MAX_0P625V		656250
-#define XOADC_MIN_0P625V		593750
-
-#define HKADC_V_PER_BIT_MUL_FACTOR	977
-#define HKADC_V_PER_BIT_DIV_FACTOR	10
-static int calib_hkadc_convert_microvolt(unsigned int phy)
-{
-	return (phy - 0x6000) *
-			HKADC_V_PER_BIT_MUL_FACTOR / HKADC_V_PER_BIT_DIV_FACTOR;
+	return bms_fake_battery ? BATTERY_POWER_SUPPLY_SOC : soc;
 }
 
 static void calib_hkadc(struct pm8921_bms_chip *chip)
@@ -1126,16 +1107,11 @@
 		pr_err("ADC failed for 1.25volts rc = %d\n", rc);
 		return;
 	}
-	voltage = calib_hkadc_convert_microvolt(result.adc_code);
+	voltage = xoadc_reading_to_microvolt(result.adc_code);
 
 	pr_debug("result 1.25v = 0x%x, voltage = %duV adc_meas = %lld\n",
 				result.adc_code, voltage, result.measurement);
 
-	/* check for valid range */
-	if (voltage > XOADC_MAX_1P25V)
-		voltage = XOADC_MAX_1P25V;
-	else if (voltage < XOADC_MIN_1P25V)
-		voltage = XOADC_MIN_1P25V;
 	chip->xoadc_v125 = voltage;
 
 	rc = pm8xxx_adc_read(the_chip->ref625mv_channel, &result);
@@ -1143,14 +1119,9 @@
 		pr_err("ADC failed for 1.25volts rc = %d\n", rc);
 		return;
 	}
-	voltage = calib_hkadc_convert_microvolt(result.adc_code);
+	voltage = xoadc_reading_to_microvolt(result.adc_code);
 	pr_debug("result 0.625V = 0x%x, voltage = %duV adc_meas = %lld\n",
 				result.adc_code, voltage, result.measurement);
-	/* check for valid range */
-	if (voltage > XOADC_MAX_0P625V)
-		voltage = XOADC_MAX_0P625V;
-	else if (voltage < XOADC_MIN_0P625V)
-		voltage = XOADC_MIN_0P625V;
 
 	chip->xoadc_v0625 = voltage;
 }
@@ -1369,8 +1340,8 @@
 			the_chip->end_percent,
 			last_charge_increase,
 			last_chargecycles);
-	the_chip->start_percent = 0;
-	the_chip->end_percent = 0;
+	the_chip->start_percent = -EINVAL;
+	the_chip->end_percent = -EINVAL;
 }
 EXPORT_SYMBOL_GPL(pm8921_bms_charging_end);
 
@@ -1854,6 +1825,8 @@
 	chip->v_failure = pdata->v_failure;
 	chip->calib_delay_ms = pdata->calib_delay_ms;
 	chip->max_voltage_uv = pdata->max_voltage_uv;
+	chip->start_percent = -EINVAL;
+	chip->end_percent = -EINVAL;
 	rc = set_battery_data(chip);
 	if (rc) {
 		pr_err("%s bad battery data %d\n", __func__, rc);
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index ef97389..ea50ae9 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -1334,6 +1334,69 @@
 	return pm_chg_vinmin_set(the_chip, voltage);
 }
 
+#define USB_OV_THRESHOLD_MASK  0x60
+#define USB_OV_THRESHOLD_SHIFT  5
+int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
+{
+	u8 temp;
+
+	if (!the_chip) {
+		pr_err("called before init\n");
+		return -EINVAL;
+	}
+
+	if (ov > PM_USB_OV_7V) {
+		pr_err("limiting to over voltage threshold to 7volts\n");
+		ov = PM_USB_OV_7V;
+	}
+
+	temp = USB_OV_THRESHOLD_MASK & (ov << USB_OV_THRESHOLD_SHIFT);
+
+	return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
+				USB_OV_THRESHOLD_MASK, temp);
+}
+EXPORT_SYMBOL(pm8921_usb_ovp_set_threshold);
+
+#define USB_DEBOUNCE_TIME_MASK	0x06
+#define USB_DEBOUNCE_TIME_SHIFT 1
+int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
+{
+	u8 temp;
+
+	if (!the_chip) {
+		pr_err("called before init\n");
+		return -EINVAL;
+	}
+
+	if (ms > PM_USB_DEBOUNCE_80P5MS) {
+		pr_err("limiting debounce to 80.5ms\n");
+		ms = PM_USB_DEBOUNCE_80P5MS;
+	}
+
+	temp = USB_DEBOUNCE_TIME_MASK & (ms << USB_DEBOUNCE_TIME_SHIFT);
+
+	return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
+				USB_DEBOUNCE_TIME_MASK, temp);
+}
+EXPORT_SYMBOL(pm8921_usb_ovp_set_hystersis);
+
+#define USB_OVP_DISABLE_MASK	0x80
+int pm8921_usb_ovp_disable(int disable)
+{
+	u8 temp = 0;
+
+	if (!the_chip) {
+		pr_err("called before init\n");
+		return -EINVAL;
+	}
+
+	if (disable)
+		temp = USB_OVP_DISABLE_MASK;
+
+	return pm_chg_masked_write(the_chip, USB_OVP_CONTROL,
+				USB_OVP_DISABLE_MASK, temp);
+}
+
 bool pm8921_is_battery_charging(int *source)
 {
 	int fsm_state, is_charging, dc_present, usb_present;
@@ -1975,7 +2038,7 @@
 	if (chip->is_bat_warm)
 		chg_current = min(chg_current, chip->warm_bat_chg_current);
 
-	if (thermal_mitigation != 0 && !chip->thermal_mitigation)
+	if (thermal_mitigation != 0 && chip->thermal_mitigation)
 		chg_current = min(chg_current,
 				chip->thermal_mitigation[thermal_mitigation]);
 
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 8eb443f..49e0d0e9 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -317,15 +317,14 @@
         help
          Say Y here to support the voltage regulators on PMIC8901
 
-config REGULATOR_PM8921
-	tristate "Qualcomm PM8921 PMIC Power regulators"
-	depends on MFD_PM8921_CORE
-	default y if MFD_PM8921_CORE
+config REGULATOR_PM8XXX
+	tristate "Qualcomm PM8XXX PMIC Voltage regulators"
+	depends on MFD_PM8XXX
 	help
-	  This driver supports voltage regulators in the Qualcomm PM8921 PMIC
-	  chip.  The PM8921 provides several different varieties of LDO and
-	  switching regulators.  It also provides a negative charge pump and
-	  voltage switches.
+	  This driver supports voltage regulators in Qualcomm PM8XXX PMIC chips.
+	  PM8XXX chips provide several different varieties of LDO and switching
+	  regulators.  They also provide negative charge pumps and voltage
+	  switches.
 
 config REGULATOR_GPIO
 	tristate "GPIO regulator"
@@ -345,14 +344,5 @@
 	  chip. It is only supposed to be used when Linux on application
 	  processor is the master in control of XO buffers.
 
-config REGULATOR_PM8018
-	tristate "Qualcomm PM8018 PMIC Power regulators"
-	depends on MFD_PM8018_CORE
-	default y if MFD_PM8018_CORE
-	help
-	  This driver supports voltage regulators in the Qualcomm PM8018 PMIC
-	  chip.  The PM8018 provides several different varieties of LDO and
-	  switching regulators.  It also provides a voltage switch.
-
 endif
 
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 4e5fd66..5318cff 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -45,9 +45,8 @@
 obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
 obj-$(CONFIG_REGULATOR_PMIC8058) += pmic8058-regulator.o
 obj-$(CONFIG_REGULATOR_PMIC8901) += pmic8901-regulator.o
-obj-$(CONFIG_REGULATOR_PM8921) += pm8921-regulator.o
 obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o
 obj-$(CONFIG_REGULATOR_PM8058_XO) += pm8058-xo.o
-obj-$(CONFIG_REGULATOR_PM8018) += pm8018-regulator.o
+obj-$(CONFIG_REGULATOR_PM8XXX) += pm8xxx-regulator.o
 
 ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/pm8018-regulator.c b/drivers/regulator/pm8018-regulator.c
deleted file mode 100644
index 2f31cbb..0000000
--- a/drivers/regulator/pm8018-regulator.c
+++ /dev/null
@@ -1,2590 +0,0 @@
-/*
- * Copyright (c) 2011, Code Aurora Forum. 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 version 2 and
- * only 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.
- */
-
-#define pr_fmt(fmt) "%s: " fmt, __func__
-
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/mutex.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <linux/platform_device.h>
-#include <linux/regulator/driver.h>
-#include <linux/regulator/machine.h>
-#include <linux/regulator/pm8018-regulator.h>
-#include <linux/mfd/pm8xxx/core.h>
-
-/* Debug Flag Definitions */
-enum {
-	PM8018_VREG_DEBUG_REQUEST	= BIT(0),
-	PM8018_VREG_DEBUG_DUPLICATE	= BIT(1),
-	PM8018_VREG_DEBUG_INIT		= BIT(2),
-	PM8018_VREG_DEBUG_WRITES	= BIT(3), /* SSBI writes */
-};
-
-static int pm8018_vreg_debug_mask;
-module_param_named(
-	debug_mask, pm8018_vreg_debug_mask, int, S_IRUSR | S_IWUSR
-);
-
-#define REGULATOR_TYPE_PLDO		0
-#define REGULATOR_TYPE_NLDO		1
-#define REGULATOR_TYPE_NLDO1200		2
-#define REGULATOR_TYPE_SMPS		3
-#define REGULATOR_TYPE_VS		4
-
-/* Common Masks */
-#define REGULATOR_ENABLE_MASK		0x80
-#define REGULATOR_ENABLE		0x80
-#define REGULATOR_DISABLE		0x00
-
-#define REGULATOR_BANK_MASK		0xF0
-#define REGULATOR_BANK_SEL(n)		((n) << 4)
-#define REGULATOR_BANK_WRITE		0x80
-
-#define LDO_TEST_BANKS			7
-#define NLDO1200_TEST_BANKS		5
-#define SMPS_TEST_BANKS			8
-#define REGULATOR_TEST_BANKS_MAX	SMPS_TEST_BANKS
-
-/*
- * This voltage in uV is returned by get_voltage functions when there is no way
- * to determine the current voltage level.  It is needed because the regulator
- * framework treats a 0 uV voltage as an error.
- */
-#define VOLTAGE_UNKNOWN			1
-
-/* LDO masks and values */
-
-/* CTRL register */
-#define LDO_ENABLE_MASK			0x80
-#define LDO_DISABLE			0x00
-#define LDO_ENABLE			0x80
-#define LDO_PULL_DOWN_ENABLE_MASK	0x40
-#define LDO_PULL_DOWN_ENABLE		0x40
-
-#define LDO_CTRL_PM_MASK		0x20
-#define LDO_CTRL_PM_HPM			0x00
-#define LDO_CTRL_PM_LPM			0x20
-
-#define LDO_CTRL_VPROG_MASK		0x1F
-
-/* TEST register bank 0 */
-#define LDO_TEST_LPM_MASK		0x40
-#define LDO_TEST_LPM_SEL_CTRL		0x00
-#define LDO_TEST_LPM_SEL_TCXO		0x40
-
-/* TEST register bank 2 */
-#define LDO_TEST_VPROG_UPDATE_MASK	0x08
-#define LDO_TEST_RANGE_SEL_MASK		0x04
-#define LDO_TEST_FINE_STEP_MASK		0x02
-#define LDO_TEST_FINE_STEP_SHIFT	1
-
-/* TEST register bank 4 */
-#define LDO_TEST_RANGE_EXT_MASK		0x01
-
-/* TEST register bank 5 */
-#define LDO_TEST_PIN_CTRL_MASK		0x0F
-#define LDO_TEST_PIN_CTRL_EN3		0x08
-#define LDO_TEST_PIN_CTRL_EN2		0x04
-#define LDO_TEST_PIN_CTRL_EN1		0x02
-#define LDO_TEST_PIN_CTRL_EN0		0x01
-
-/* TEST register bank 6 */
-#define LDO_TEST_PIN_CTRL_LPM_MASK	0x0F
-
-/*
- * If a given voltage could be output by two ranges, then the preferred one must
- * be determined by the range limits.  Specified voltage ranges should must
- * not overlap.
- *
- * Allowable voltage ranges:
- */
-#define PLDO_LOW_UV_MIN			750000
-#define PLDO_LOW_UV_MAX			1487500
-#define PLDO_LOW_UV_FINE_STEP		12500
-
-#define PLDO_NORM_UV_MIN		1500000
-#define PLDO_NORM_UV_MAX		3075000
-#define PLDO_NORM_UV_FINE_STEP		25000
-
-#define PLDO_HIGH_UV_MIN		1750000
-#define PLDO_HIGH_UV_SET_POINT_MIN	3100000
-#define PLDO_HIGH_UV_MAX		4900000
-#define PLDO_HIGH_UV_FINE_STEP		50000
-
-#define PLDO_LOW_SET_POINTS		((PLDO_LOW_UV_MAX - PLDO_LOW_UV_MIN) \
-						/ PLDO_LOW_UV_FINE_STEP + 1)
-#define PLDO_NORM_SET_POINTS		((PLDO_NORM_UV_MAX - PLDO_NORM_UV_MIN) \
-						/ PLDO_NORM_UV_FINE_STEP + 1)
-#define PLDO_HIGH_SET_POINTS		((PLDO_HIGH_UV_MAX \
-						- PLDO_HIGH_UV_SET_POINT_MIN) \
-					/ PLDO_HIGH_UV_FINE_STEP + 1)
-#define PLDO_SET_POINTS			(PLDO_LOW_SET_POINTS \
-						+ PLDO_NORM_SET_POINTS \
-						+ PLDO_HIGH_SET_POINTS)
-
-#define NLDO_UV_MIN			750000
-#define NLDO_UV_MAX			1537500
-#define NLDO_UV_FINE_STEP		12500
-
-#define NLDO_SET_POINTS			((NLDO_UV_MAX - NLDO_UV_MIN) \
-						/ NLDO_UV_FINE_STEP + 1)
-
-/* NLDO1200 masks and values */
-
-/* CTRL register */
-#define NLDO1200_ENABLE_MASK		0x80
-#define NLDO1200_DISABLE		0x00
-#define NLDO1200_ENABLE			0x80
-
-/* Legacy mode */
-#define NLDO1200_LEGACY_PM_MASK		0x20
-#define NLDO1200_LEGACY_PM_HPM		0x00
-#define NLDO1200_LEGACY_PM_LPM		0x20
-
-/* Advanced mode */
-#define NLDO1200_CTRL_RANGE_MASK	0x40
-#define NLDO1200_CTRL_RANGE_HIGH	0x00
-#define NLDO1200_CTRL_RANGE_LOW		0x40
-#define NLDO1200_CTRL_VPROG_MASK	0x3F
-
-#define NLDO1200_LOW_UV_MIN		375000
-#define NLDO1200_LOW_UV_MAX		743750
-#define NLDO1200_LOW_UV_STEP		6250
-
-#define NLDO1200_HIGH_UV_MIN		750000
-#define NLDO1200_HIGH_UV_MAX		1537500
-#define NLDO1200_HIGH_UV_STEP		12500
-
-#define NLDO1200_LOW_SET_POINTS		((NLDO1200_LOW_UV_MAX \
-						- NLDO1200_LOW_UV_MIN) \
-					/ NLDO1200_LOW_UV_STEP + 1)
-#define NLDO1200_HIGH_SET_POINTS	((NLDO1200_HIGH_UV_MAX \
-						- NLDO1200_HIGH_UV_MIN) \
-					/ NLDO1200_HIGH_UV_STEP + 1)
-#define NLDO1200_SET_POINTS		(NLDO1200_LOW_SET_POINTS \
-						+ NLDO1200_HIGH_SET_POINTS)
-
-/* TEST register bank 0 */
-#define NLDO1200_TEST_LPM_MASK		0x04
-#define NLDO1200_TEST_LPM_SEL_CTRL	0x00
-#define NLDO1200_TEST_LPM_SEL_TCXO	0x04
-
-/* TEST register bank 1 */
-#define NLDO1200_PULL_DOWN_ENABLE_MASK	0x02
-#define NLDO1200_PULL_DOWN_ENABLE	0x02
-
-/* TEST register bank 2 */
-#define NLDO1200_ADVANCED_MODE_MASK	0x08
-#define NLDO1200_ADVANCED_MODE		0x00
-#define NLDO1200_LEGACY_MODE		0x08
-
-/* Advanced mode power mode control */
-#define NLDO1200_ADVANCED_PM_MASK	0x02
-#define NLDO1200_ADVANCED_PM_HPM	0x00
-#define NLDO1200_ADVANCED_PM_LPM	0x02
-
-#define NLDO1200_IN_ADVANCED_MODE(vreg) \
-	((vreg->test_reg[2] & NLDO1200_ADVANCED_MODE_MASK) \
-	 == NLDO1200_ADVANCED_MODE)
-
-/* SMPS masks and values */
-
-/* CTRL register */
-
-/* Legacy mode */
-#define SMPS_LEGACY_ENABLE_MASK		0x80
-#define SMPS_LEGACY_DISABLE		0x00
-#define SMPS_LEGACY_ENABLE		0x80
-#define SMPS_LEGACY_PULL_DOWN_ENABLE	0x40
-#define SMPS_LEGACY_VREF_SEL_MASK	0x20
-#define SMPS_LEGACY_VPROG_MASK		0x1F
-
-/* Advanced mode */
-#define SMPS_ADVANCED_BAND_MASK		0xC0
-#define SMPS_ADVANCED_BAND_OFF		0x00
-#define SMPS_ADVANCED_BAND_1		0x40
-#define SMPS_ADVANCED_BAND_2		0x80
-#define SMPS_ADVANCED_BAND_3		0xC0
-#define SMPS_ADVANCED_VPROG_MASK	0x3F
-
-/* Legacy mode voltage ranges */
-#define SMPS_MODE3_UV_MIN		375000
-#define SMPS_MODE3_UV_MAX		725000
-#define SMPS_MODE3_UV_STEP		25000
-
-#define SMPS_MODE2_UV_MIN		750000
-#define SMPS_MODE2_UV_MAX		1475000
-#define SMPS_MODE2_UV_STEP		25000
-
-#define SMPS_MODE1_UV_MIN		1500000
-#define SMPS_MODE1_UV_MAX		3050000
-#define SMPS_MODE1_UV_STEP		50000
-
-#define SMPS_MODE3_SET_POINTS		((SMPS_MODE3_UV_MAX \
-						- SMPS_MODE3_UV_MIN) \
-					/ SMPS_MODE3_UV_STEP + 1)
-#define SMPS_MODE2_SET_POINTS		((SMPS_MODE2_UV_MAX \
-						- SMPS_MODE2_UV_MIN) \
-					/ SMPS_MODE2_UV_STEP + 1)
-#define SMPS_MODE1_SET_POINTS		((SMPS_MODE1_UV_MAX \
-						- SMPS_MODE1_UV_MIN) \
-					/ SMPS_MODE1_UV_STEP + 1)
-#define SMPS_LEGACY_SET_POINTS		(SMPS_MODE3_SET_POINTS \
-						+ SMPS_MODE2_SET_POINTS \
-						+ SMPS_MODE1_SET_POINTS)
-
-/* Advanced mode voltage ranges */
-#define SMPS_BAND1_UV_MIN		375000
-#define SMPS_BAND1_UV_MAX		737500
-#define SMPS_BAND1_UV_STEP		12500
-
-#define SMPS_BAND2_UV_MIN		750000
-#define SMPS_BAND2_UV_MAX		1487500
-#define SMPS_BAND2_UV_STEP		12500
-
-#define SMPS_BAND3_UV_MIN		1500000
-#define SMPS_BAND3_UV_MAX		3075000
-#define SMPS_BAND3_UV_STEP		25000
-
-#define SMPS_BAND1_SET_POINTS		((SMPS_BAND1_UV_MAX \
-						- SMPS_BAND1_UV_MIN) \
-					/ SMPS_BAND1_UV_STEP + 1)
-#define SMPS_BAND2_SET_POINTS		((SMPS_BAND2_UV_MAX \
-						- SMPS_BAND2_UV_MIN) \
-					/ SMPS_BAND2_UV_STEP + 1)
-#define SMPS_BAND3_SET_POINTS		((SMPS_BAND3_UV_MAX \
-						- SMPS_BAND3_UV_MIN) \
-					/ SMPS_BAND3_UV_STEP + 1)
-#define SMPS_ADVANCED_SET_POINTS	(SMPS_BAND1_SET_POINTS \
-						+ SMPS_BAND2_SET_POINTS \
-						+ SMPS_BAND3_SET_POINTS)
-
-/* Test2 register bank 1 */
-#define SMPS_LEGACY_VLOW_SEL_MASK	0x01
-
-/* Test2 register bank 6 */
-#define SMPS_ADVANCED_PULL_DOWN_ENABLE	0x08
-
-/* Test2 register bank 7 */
-#define SMPS_ADVANCED_MODE_MASK		0x02
-#define SMPS_ADVANCED_MODE		0x02
-#define SMPS_LEGACY_MODE		0x00
-
-#define SMPS_IN_ADVANCED_MODE(vreg) \
-	((vreg->test_reg[7] & SMPS_ADVANCED_MODE_MASK) == SMPS_ADVANCED_MODE)
-
-/* BUCK_SLEEP_CNTRL register */
-#define SMPS_PIN_CTRL_MASK		0xF0
-#define SMPS_PIN_CTRL_EN3		0x80
-#define SMPS_PIN_CTRL_EN2		0x40
-#define SMPS_PIN_CTRL_EN1		0x20
-#define SMPS_PIN_CTRL_EN0		0x10
-
-#define SMPS_PIN_CTRL_LPM_MASK		0x0F
-#define SMPS_PIN_CTRL_LPM_EN3		0x08
-#define SMPS_PIN_CTRL_LPM_EN2		0x04
-#define SMPS_PIN_CTRL_LPM_EN1		0x02
-#define SMPS_PIN_CTRL_LPM_EN0		0x01
-
-/* BUCK_CLOCK_CNTRL register */
-#define SMPS_CLK_DIVIDE2		0x40
-
-#define SMPS_CLK_CTRL_MASK		0x30
-#define SMPS_CLK_CTRL_FOLLOW_TCXO	0x00
-#define SMPS_CLK_CTRL_PWM		0x10
-#define SMPS_CLK_CTRL_PFM		0x20
-
-/* VS masks and values */
-
-/* CTRL register */
-#define VS_ENABLE_MASK			0x80
-#define VS_DISABLE			0x00
-#define VS_ENABLE			0x80
-#define VS_PULL_DOWN_ENABLE_MASK	0x40
-#define VS_PULL_DOWN_ENABLE		0x40
-
-#define VS_PIN_CTRL_MASK		0x0F
-#define VS_PIN_CTRL_EN0			0x08
-#define VS_PIN_CTRL_EN1			0x04
-#define VS_PIN_CTRL_EN2			0x02
-#define VS_PIN_CTRL_EN3			0x01
-
-#define IS_REAL_REGULATOR(id)		((id) >= 0 && \
-					 (id) < PM8018_VREG_ID_L2_PC)
-
-struct pm8018_vreg {
-	/* Configuration data */
-	struct regulator_dev			*rdev;
-	struct regulator_dev			*rdev_pc;
-	struct device				*dev;
-	struct device				*dev_pc;
-	const char				*name;
-	struct pm8018_regulator_platform_data	pdata;
-	const int				hpm_min_load;
-	const u16				ctrl_addr;
-	const u16				test_addr;
-	const u16				clk_ctrl_addr;
-	const u16				sleep_ctrl_addr;
-	const u8				type;
-	/* State data */
-	struct mutex				pc_lock;
-	int					save_uV;
-	int					mode;
-	u32					write_count;
-	u32					prev_write_count;
-	bool					is_enabled;
-	bool					is_enabled_pc;
-	u8				test_reg[REGULATOR_TEST_BANKS_MAX];
-	u8					ctrl_reg;
-	u8					clk_ctrl_reg;
-	u8					sleep_ctrl_reg;
-};
-
-#define vreg_err(vreg, fmt, ...) \
-	pr_err("%s: " fmt, vreg->name, ##__VA_ARGS__)
-
-#define PLDO(_id, _ctrl_addr, _test_addr, _hpm_min_load) \
-	[PM8018_VREG_ID_##_id] = { \
-		.type		= REGULATOR_TYPE_PLDO, \
-		.ctrl_addr	= _ctrl_addr, \
-		.test_addr	= _test_addr, \
-		.hpm_min_load	= PM8018_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
-	}
-
-#define NLDO(_id, _ctrl_addr, _test_addr, _hpm_min_load) \
-	[PM8018_VREG_ID_##_id] = { \
-		.type		= REGULATOR_TYPE_NLDO, \
-		.ctrl_addr	= _ctrl_addr, \
-		.test_addr	= _test_addr, \
-		.hpm_min_load	= PM8018_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
-	}
-
-#define NLDO1200(_id, _ctrl_addr, _test_addr, _hpm_min_load) \
-	[PM8018_VREG_ID_##_id] = { \
-		.type		= REGULATOR_TYPE_NLDO1200, \
-		.ctrl_addr	= _ctrl_addr, \
-		.test_addr	= _test_addr, \
-		.hpm_min_load	= PM8018_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
-	}
-
-#define SMPS(_id, _ctrl_addr, _test_addr, _clk_ctrl_addr, _sleep_ctrl_addr, \
-	     _hpm_min_load) \
-	[PM8018_VREG_ID_##_id] = { \
-		.type		= REGULATOR_TYPE_SMPS, \
-		.ctrl_addr	= _ctrl_addr, \
-		.test_addr	= _test_addr, \
-		.clk_ctrl_addr	= _clk_ctrl_addr, \
-		.sleep_ctrl_addr = _sleep_ctrl_addr, \
-		.hpm_min_load	= PM8018_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
-	}
-
-#define VS(_id, _ctrl_addr) \
-	[PM8018_VREG_ID_##_id] = { \
-		.type		= REGULATOR_TYPE_VS, \
-		.ctrl_addr	= _ctrl_addr, \
-	}
-
-static struct pm8018_vreg pm8018_vreg[] = {
-	/*   id       ctrl   test   hpm_min */
-	PLDO(L2,      0x0B0, 0x0B1, LDO_50),
-	PLDO(L3,      0x0B2, 0x0B3, LDO_50),
-	PLDO(L4,      0x0B4, 0x0B5, LDO_300),
-	PLDO(L5,      0x0B6, 0x0B7, LDO_150),
-	PLDO(L6,      0x0B8, 0x0B9, LDO_150),
-	PLDO(L7,      0x0BA, 0x0BB, LDO_300),
-	NLDO(L8,      0x0BC, 0x0BD, LDO_150),
-	NLDO1200(L9,  0x0BE, 0x0BF, LDO_1200),
-	NLDO1200(L10, 0x0C0, 0x0C1, LDO_1200),
-	NLDO1200(L11, 0x0C2, 0x0C3, LDO_1200),
-	NLDO1200(L12, 0x0C4, 0x0C5, LDO_1200),
-	PLDO(L13,     0x0C8, 0x0C9, LDO_50),
-	PLDO(L14,     0x0CA, 0x0CB, LDO_50),
-
-	/*   id  ctrl   test2  clk    sleep  hpm_min */
-	SMPS(S1, 0x1D0, 0x1D5, 0x009, 0x1D2, SMPS_1500),
-	SMPS(S2, 0x1D8, 0x1DD, 0x00A, 0x1DA, SMPS_1500),
-	SMPS(S3, 0x1E0, 0x1E5, 0x00B, 0x1E2, SMPS_1500),
-	SMPS(S4, 0x1E8, 0x1ED, 0x00C, 0x1EA, SMPS_1500),
-	SMPS(S5, 0x1F0, 0x1F5, 0x00D, 0x1F2, SMPS_1500),
-
-	/* id    ctrl */
-	VS(LVS1, 0x060),
-};
-
-/* Determines which label to add to the print. */
-enum pm8018_regulator_action {
-	PM8018_REGULATOR_ACTION_INIT,
-	PM8018_REGULATOR_ACTION_ENABLE,
-	PM8018_REGULATOR_ACTION_DISABLE,
-	PM8018_REGULATOR_ACTION_VOLTAGE,
-	PM8018_REGULATOR_ACTION_MODE,
-	PM8018_REGULATOR_ACTION_PIN_CTRL,
-};
-
-/* Debug state printing */
-static void pm8018_vreg_show_state(struct regulator_dev *rdev,
-				   enum pm8018_regulator_action action);
-
-/*
- * Perform a masked write to a PMIC register only if the new value differs
- * from the last value written to the register.  This removes redundant
- * register writing.
- *
- * No locking is required because registers are not shared between regulators.
- */
-static int pm8018_vreg_masked_write(struct pm8018_vreg *vreg, u16 addr, u8 val,
-		u8 mask, u8 *reg_save)
-{
-	int rc = 0;
-	u8 reg;
-
-	reg = (*reg_save & ~mask) | (val & mask);
-	if (reg != *reg_save) {
-		rc = pm8xxx_writeb(vreg->dev->parent, addr, reg);
-
-		if (rc) {
-			pr_err("%s: pm8xxx_writeb failed; addr=0x%03X, rc=%d\n",
-				vreg->name, addr, rc);
-		} else {
-			*reg_save = reg;
-			vreg->write_count++;
-			if (pm8018_vreg_debug_mask & PM8018_VREG_DEBUG_WRITES)
-				pr_info("%s: write(0x%03X)=0x%02X", vreg->name,
-					addr, reg);
-		}
-	}
-
-	return rc;
-}
-
-/*
- * Perform a masked write to a PMIC register without checking the previously
- * written value.  This is needed for registers that must be rewritten even if
- * the value hasn't changed in order for changes in other registers to take
- * effect.
- */
-static int pm8018_vreg_masked_write_forced(struct pm8018_vreg *vreg, u16 addr,
-		u8 val, u8 mask, u8 *reg_save)
-{
-	int rc = 0;
-	u8 reg;
-
-	reg = (*reg_save & ~mask) | (val & mask);
-	rc = pm8xxx_writeb(vreg->dev->parent, addr, reg);
-
-	if (rc) {
-		pr_err("%s: pm8xxx_writeb failed; addr=0x%03X, rc=%d\n",
-			vreg->name, addr, rc);
-	} else {
-		*reg_save = reg;
-		vreg->write_count++;
-		if (pm8018_vreg_debug_mask & PM8018_VREG_DEBUG_WRITES)
-			pr_info("%s: write(0x%03X)=0x%02X", vreg->name,
-				addr, reg);
-	}
-
-	return rc;
-}
-
-static int pm8018_vreg_is_pin_controlled(struct pm8018_vreg *vreg)
-{
-	int ret = 0;
-
-	switch (vreg->type) {
-	case REGULATOR_TYPE_PLDO:
-	case REGULATOR_TYPE_NLDO:
-		ret = ((vreg->test_reg[5] & LDO_TEST_PIN_CTRL_MASK) << 4)
-			| (vreg->test_reg[6] & LDO_TEST_PIN_CTRL_LPM_MASK);
-		break;
-	case REGULATOR_TYPE_SMPS:
-		ret = vreg->sleep_ctrl_reg
-			& (SMPS_PIN_CTRL_MASK | SMPS_PIN_CTRL_LPM_MASK);
-		break;
-	case REGULATOR_TYPE_VS:
-		ret = vreg->ctrl_reg & VS_PIN_CTRL_MASK;
-		break;
-	}
-
-	return ret;
-}
-
-/*
- * Returns the logical pin control enable state because the pin control options
- * present in the hardware out of restart could be different from those desired
- * by the consumer.
- */
-static int pm8018_vreg_pin_control_is_enabled(struct regulator_dev *rdev)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	int enabled;
-
-	mutex_lock(&vreg->pc_lock);
-	enabled = vreg->is_enabled_pc;
-	mutex_unlock(&vreg->pc_lock);
-
-	return enabled;
-}
-
-/* Returns the physical enable state of the regulator. */
-static int _pm8018_vreg_is_enabled(struct pm8018_vreg *vreg)
-{
-	int rc = 0;
-
-	/*
-	 * All regulator types except advanced mode SMPS have enable bit in
-	 * bit 7 of the control register.
-	 */
-
-	if (vreg->type == REGULATOR_TYPE_SMPS && SMPS_IN_ADVANCED_MODE(vreg)) {
-		if ((vreg->ctrl_reg & SMPS_ADVANCED_BAND_MASK)
-		    != SMPS_ADVANCED_BAND_OFF)
-			rc = 1;
-	} else {
-		if ((vreg->ctrl_reg & REGULATOR_ENABLE_MASK)
-		    == REGULATOR_ENABLE)
-			rc = 1;
-	}
-
-	return rc;
-}
-
-/*
- * Returns the logical enable state of the regulator which may be different from
- * the physical enable state thanks to HPM/LPM pin control.
- */
-static int pm8018_vreg_is_enabled(struct regulator_dev *rdev)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	int enabled;
-
-	if (vreg->type == REGULATOR_TYPE_PLDO
-	    || vreg->type == REGULATOR_TYPE_NLDO
-	    || vreg->type == REGULATOR_TYPE_SMPS
-	    || vreg->type == REGULATOR_TYPE_VS) {
-		/* Pin controllable */
-		mutex_lock(&vreg->pc_lock);
-		enabled = vreg->is_enabled;
-		mutex_unlock(&vreg->pc_lock);
-	} else {
-		/* Not pin controlable */
-		enabled = _pm8018_vreg_is_enabled(vreg);
-	}
-
-	return enabled;
-}
-
-static int pm8018_pldo_get_voltage(struct regulator_dev *rdev)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	int vmin, fine_step;
-	u8 range_ext, range_sel, vprog, fine_step_reg;
-
-	mutex_lock(&vreg->pc_lock);
-
-	fine_step_reg = vreg->test_reg[2] & LDO_TEST_FINE_STEP_MASK;
-	range_sel = vreg->test_reg[2] & LDO_TEST_RANGE_SEL_MASK;
-	range_ext = vreg->test_reg[4] & LDO_TEST_RANGE_EXT_MASK;
-	vprog = vreg->ctrl_reg & LDO_CTRL_VPROG_MASK;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	vprog = (vprog << 1) | (fine_step_reg >> LDO_TEST_FINE_STEP_SHIFT);
-
-	if (range_sel) {
-		/* low range mode */
-		fine_step = PLDO_LOW_UV_FINE_STEP;
-		vmin = PLDO_LOW_UV_MIN;
-	} else if (!range_ext) {
-		/* normal mode */
-		fine_step = PLDO_NORM_UV_FINE_STEP;
-		vmin = PLDO_NORM_UV_MIN;
-	} else {
-		/* high range mode */
-		fine_step = PLDO_HIGH_UV_FINE_STEP;
-		vmin = PLDO_HIGH_UV_MIN;
-	}
-
-	return fine_step * vprog + vmin;
-}
-
-static int pm8018_pldo_list_voltage(struct regulator_dev *rdev,
-				    unsigned selector)
-{
-	int uV;
-
-	if (selector >= PLDO_SET_POINTS)
-		return 0;
-
-	if (selector < PLDO_LOW_SET_POINTS)
-		uV = selector * PLDO_LOW_UV_FINE_STEP + PLDO_LOW_UV_MIN;
-	else if (selector < (PLDO_LOW_SET_POINTS + PLDO_NORM_SET_POINTS))
-		uV = (selector - PLDO_LOW_SET_POINTS) * PLDO_NORM_UV_FINE_STEP
-			+ PLDO_NORM_UV_MIN;
-	else
-		uV = (selector - PLDO_LOW_SET_POINTS - PLDO_NORM_SET_POINTS)
-				* PLDO_HIGH_UV_FINE_STEP
-			+ PLDO_HIGH_UV_SET_POINT_MIN;
-
-	return uV;
-}
-
-static int pm8018_pldo_set_voltage(struct regulator_dev *rdev, int min_uV,
-				   int max_uV, unsigned *selector)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc = 0, uV = min_uV;
-	int vmin;
-	unsigned vprog, fine_step;
-	u8 range_ext, range_sel, fine_step_reg, prev_reg;
-	bool reg_changed = false;
-
-	if (uV < PLDO_LOW_UV_MIN && max_uV >= PLDO_LOW_UV_MIN)
-		uV = PLDO_LOW_UV_MIN;
-
-	if (uV < PLDO_LOW_UV_MIN || uV > PLDO_HIGH_UV_MAX) {
-		vreg_err(vreg,
-			"request v=[%d, %d] is outside possible v=[%d, %d]\n",
-			 min_uV, max_uV, PLDO_LOW_UV_MIN, PLDO_HIGH_UV_MAX);
-		return -EINVAL;
-	}
-
-	if (uV > PLDO_NORM_UV_MAX) {
-		vmin = PLDO_HIGH_UV_MIN;
-		fine_step = PLDO_HIGH_UV_FINE_STEP;
-		range_ext = LDO_TEST_RANGE_EXT_MASK;
-		range_sel = 0;
-	} else if (uV > PLDO_LOW_UV_MAX) {
-		vmin = PLDO_NORM_UV_MIN;
-		fine_step = PLDO_NORM_UV_FINE_STEP;
-		range_ext = 0;
-		range_sel = 0;
-	} else {
-		vmin = PLDO_LOW_UV_MIN;
-		fine_step = PLDO_LOW_UV_FINE_STEP;
-		range_ext = 0;
-		range_sel = LDO_TEST_RANGE_SEL_MASK;
-	}
-
-	vprog = (uV - vmin + fine_step - 1) / fine_step;
-	uV = vprog * fine_step + vmin;
-	fine_step_reg = (vprog & 1) << LDO_TEST_FINE_STEP_SHIFT;
-	vprog >>= 1;
-
-	if (uV > max_uV) {
-		vreg_err(vreg,
-			"request v=[%d, %d] cannot be met by any set point\n",
-			min_uV, max_uV);
-		return -EINVAL;
-	}
-
-	mutex_lock(&vreg->pc_lock);
-
-	/* Write fine step, range select and program voltage update. */
-	prev_reg = vreg->test_reg[2];
-	rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
-			fine_step_reg | range_sel | REGULATOR_BANK_SEL(2)
-			 | REGULATOR_BANK_WRITE | LDO_TEST_VPROG_UPDATE_MASK,
-			LDO_TEST_FINE_STEP_MASK | LDO_TEST_RANGE_SEL_MASK
-			 | REGULATOR_BANK_MASK | LDO_TEST_VPROG_UPDATE_MASK,
-			&vreg->test_reg[2]);
-	if (rc)
-		goto bail;
-	if (prev_reg != vreg->test_reg[2])
-		reg_changed = true;
-
-	/* Write range extension. */
-	prev_reg = vreg->test_reg[4];
-	rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
-			range_ext | REGULATOR_BANK_SEL(4)
-			 | REGULATOR_BANK_WRITE,
-			LDO_TEST_RANGE_EXT_MASK | REGULATOR_BANK_MASK,
-			&vreg->test_reg[4]);
-	if (rc)
-		goto bail;
-	if (prev_reg != vreg->test_reg[4])
-		reg_changed = true;
-
-	/* Write new voltage. */
-	if (reg_changed) {
-		/*
-		 * Force a CTRL register write even if the value hasn't changed.
-		 * This is neccessary because range select, range extension, and
-		 * fine step will not update until a value is written into the
-		 * control register.
-		 */
-		rc = pm8018_vreg_masked_write_forced(vreg, vreg->ctrl_addr,
-			vprog, LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
-	} else {
-		/* Only write to control register if new value is different. */
-		rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr, vprog,
-			LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
-	}
-bail:
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_VOLTAGE);
-
-	return rc;
-}
-
-static int pm8018_nldo_get_voltage(struct regulator_dev *rdev)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	u8 vprog, fine_step_reg;
-
-	mutex_lock(&vreg->pc_lock);
-
-	fine_step_reg = vreg->test_reg[2] & LDO_TEST_FINE_STEP_MASK;
-	vprog = vreg->ctrl_reg & LDO_CTRL_VPROG_MASK;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	vprog = (vprog << 1) | (fine_step_reg >> LDO_TEST_FINE_STEP_SHIFT);
-
-	return NLDO_UV_FINE_STEP * vprog + NLDO_UV_MIN;
-}
-
-static int pm8018_nldo_list_voltage(struct regulator_dev *rdev,
-				    unsigned selector)
-{
-	if (selector >= NLDO_SET_POINTS)
-		return 0;
-
-	return selector * NLDO_UV_FINE_STEP + NLDO_UV_MIN;
-}
-
-static int pm8018_nldo_set_voltage(struct regulator_dev *rdev, int min_uV,
-				   int max_uV, unsigned *selector)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	unsigned vprog, fine_step_reg, prev_reg;
-	int rc;
-	int uV = min_uV;
-
-	if (uV < NLDO_UV_MIN && max_uV >= NLDO_UV_MIN)
-		uV = NLDO_UV_MIN;
-
-	if (uV < NLDO_UV_MIN || uV > NLDO_UV_MAX) {
-		vreg_err(vreg,
-			"request v=[%d, %d] is outside possible v=[%d, %d]\n",
-			 min_uV, max_uV, NLDO_UV_MIN, NLDO_UV_MAX);
-		return -EINVAL;
-	}
-
-	vprog = (uV - NLDO_UV_MIN + NLDO_UV_FINE_STEP - 1) / NLDO_UV_FINE_STEP;
-	uV = vprog * NLDO_UV_FINE_STEP + NLDO_UV_MIN;
-	fine_step_reg = (vprog & 1) << LDO_TEST_FINE_STEP_SHIFT;
-	vprog >>= 1;
-
-	if (uV > max_uV) {
-		vreg_err(vreg,
-			"request v=[%d, %d] cannot be met by any set point\n",
-			min_uV, max_uV);
-		return -EINVAL;
-	}
-
-	mutex_lock(&vreg->pc_lock);
-
-	/* Write fine step. */
-	prev_reg = vreg->test_reg[2];
-	rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
-			fine_step_reg | REGULATOR_BANK_SEL(2)
-			 | REGULATOR_BANK_WRITE | LDO_TEST_VPROG_UPDATE_MASK,
-			LDO_TEST_FINE_STEP_MASK | REGULATOR_BANK_MASK
-			 | LDO_TEST_VPROG_UPDATE_MASK,
-		       &vreg->test_reg[2]);
-	if (rc)
-		goto bail;
-
-	/* Write new voltage. */
-	if (prev_reg != vreg->test_reg[2]) {
-		/*
-		 * Force a CTRL register write even if the value hasn't changed.
-		 * This is neccessary because fine step will not update until a
-		 * value is written into the control register.
-		 */
-		rc = pm8018_vreg_masked_write_forced(vreg, vreg->ctrl_addr,
-			vprog, LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
-	} else {
-		/* Only write to control register if new value is different. */
-		rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr, vprog,
-			LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
-	}
-bail:
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_VOLTAGE);
-
-	return rc;
-}
-
-static int _pm8018_nldo1200_get_voltage(struct pm8018_vreg *vreg)
-{
-	int uV = 0;
-	int vprog;
-
-	if (!NLDO1200_IN_ADVANCED_MODE(vreg)) {
-		pr_warn("%s: currently in legacy mode; voltage unknown.\n",
-			vreg->name);
-		return vreg->save_uV;
-	}
-
-	vprog = vreg->ctrl_reg & NLDO1200_CTRL_VPROG_MASK;
-
-	if ((vreg->ctrl_reg & NLDO1200_CTRL_RANGE_MASK)
-	    == NLDO1200_CTRL_RANGE_LOW)
-		uV = vprog * NLDO1200_LOW_UV_STEP + NLDO1200_LOW_UV_MIN;
-	else
-		uV = vprog * NLDO1200_HIGH_UV_STEP + NLDO1200_HIGH_UV_MIN;
-
-	return uV;
-}
-
-static int pm8018_nldo1200_get_voltage(struct regulator_dev *rdev)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-
-	return _pm8018_nldo1200_get_voltage(vreg);
-}
-
-static int pm8018_nldo1200_list_voltage(struct regulator_dev *rdev,
-					unsigned selector)
-{
-	int uV;
-
-	if (selector >= NLDO1200_SET_POINTS)
-		return 0;
-
-	if (selector < NLDO1200_LOW_SET_POINTS)
-		uV = selector * NLDO1200_LOW_UV_STEP + NLDO1200_LOW_UV_MIN;
-	else
-		uV = (selector - NLDO1200_LOW_SET_POINTS)
-				* NLDO1200_HIGH_UV_STEP
-			+ NLDO1200_HIGH_UV_MIN;
-
-	return uV;
-}
-
-static int _pm8018_nldo1200_set_voltage(struct pm8018_vreg *vreg, int min_uV,
-		int max_uV)
-{
-	u8 vprog, range;
-	int rc;
-	int uV = min_uV;
-
-	if (uV < NLDO1200_LOW_UV_MIN && max_uV >= NLDO1200_LOW_UV_MIN)
-		uV = NLDO1200_LOW_UV_MIN;
-
-	if (uV < NLDO1200_LOW_UV_MIN || uV > NLDO1200_HIGH_UV_MAX) {
-		vreg_err(vreg,
-			"request v=[%d, %d] is outside possible v=[%d, %d]\n",
-			 min_uV, max_uV, NLDO_UV_MIN, NLDO_UV_MAX);
-		return -EINVAL;
-	}
-
-	if (uV > NLDO1200_LOW_UV_MAX) {
-		vprog = (uV - NLDO1200_HIGH_UV_MIN + NLDO1200_HIGH_UV_STEP - 1)
-			/ NLDO1200_HIGH_UV_STEP;
-		uV = vprog * NLDO1200_HIGH_UV_STEP + NLDO1200_HIGH_UV_MIN;
-		vprog &= NLDO1200_CTRL_VPROG_MASK;
-		range = NLDO1200_CTRL_RANGE_HIGH;
-	} else {
-		vprog = (uV - NLDO1200_LOW_UV_MIN + NLDO1200_LOW_UV_STEP - 1)
-			/ NLDO1200_LOW_UV_STEP;
-		uV = vprog * NLDO1200_LOW_UV_STEP + NLDO1200_LOW_UV_MIN;
-		vprog &= NLDO1200_CTRL_VPROG_MASK;
-		range = NLDO1200_CTRL_RANGE_LOW;
-	}
-
-	if (uV > max_uV) {
-		vreg_err(vreg,
-			"request v=[%d, %d] cannot be met by any set point\n",
-			min_uV, max_uV);
-		return -EINVAL;
-	}
-
-	/* Set to advanced mode */
-	rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
-		NLDO1200_ADVANCED_MODE | REGULATOR_BANK_SEL(2)
-		| REGULATOR_BANK_WRITE, NLDO1200_ADVANCED_MODE_MASK
-		| REGULATOR_BANK_MASK, &vreg->test_reg[2]);
-	if (rc)
-		goto bail;
-
-	/* Set voltage and range selection. */
-	rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr, vprog | range,
-			NLDO1200_CTRL_VPROG_MASK | NLDO1200_CTRL_RANGE_MASK,
-			&vreg->ctrl_reg);
-	if (rc)
-		goto bail;
-
-	vreg->save_uV = uV;
-
-bail:
-	if (rc)
-		vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
-
-	return rc;
-}
-
-static int pm8018_nldo1200_set_voltage(struct regulator_dev *rdev, int min_uV,
-				   int max_uV, unsigned *selector)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	rc = _pm8018_nldo1200_set_voltage(vreg, min_uV, max_uV);
-
-	if (!rc)
-		pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_VOLTAGE);
-
-	return rc;
-}
-
-static int pm8018_smps_get_voltage_advanced(struct pm8018_vreg *vreg)
-{
-	u8 vprog, band;
-	int uV = 0;
-
-	vprog = vreg->ctrl_reg & SMPS_ADVANCED_VPROG_MASK;
-	band = vreg->ctrl_reg & SMPS_ADVANCED_BAND_MASK;
-
-	if (band == SMPS_ADVANCED_BAND_1)
-		uV = vprog * SMPS_BAND1_UV_STEP + SMPS_BAND1_UV_MIN;
-	else if (band == SMPS_ADVANCED_BAND_2)
-		uV = vprog * SMPS_BAND2_UV_STEP + SMPS_BAND2_UV_MIN;
-	else if (band == SMPS_ADVANCED_BAND_3)
-		uV = vprog * SMPS_BAND3_UV_STEP + SMPS_BAND3_UV_MIN;
-	else if (vreg->save_uV > 0)
-		uV = vreg->save_uV;
-	else
-		uV = VOLTAGE_UNKNOWN;
-
-	return uV;
-}
-
-static int pm8018_smps_get_voltage_legacy(struct pm8018_vreg *vreg)
-{
-	u8 vlow, vref, vprog;
-	int uV;
-
-	vlow = vreg->test_reg[1] & SMPS_LEGACY_VLOW_SEL_MASK;
-	vref = vreg->ctrl_reg & SMPS_LEGACY_VREF_SEL_MASK;
-	vprog = vreg->ctrl_reg & SMPS_LEGACY_VPROG_MASK;
-
-	if (vlow && vref) {
-		/* mode 3 */
-		uV = vprog * SMPS_MODE3_UV_STEP + SMPS_MODE3_UV_MIN;
-	} else if (vref) {
-		/* mode 2 */
-		uV = vprog * SMPS_MODE2_UV_STEP + SMPS_MODE2_UV_MIN;
-	} else {
-		/* mode 1 */
-		uV = vprog * SMPS_MODE1_UV_STEP + SMPS_MODE1_UV_MIN;
-	}
-
-	return uV;
-}
-
-static int _pm8018_smps_get_voltage(struct pm8018_vreg *vreg)
-{
-	if (SMPS_IN_ADVANCED_MODE(vreg))
-		return pm8018_smps_get_voltage_advanced(vreg);
-
-	return pm8018_smps_get_voltage_legacy(vreg);
-}
-
-static int pm8018_smps_list_voltage(struct regulator_dev *rdev,
-				    unsigned selector)
-{
-	int uV;
-
-	if (selector >= SMPS_ADVANCED_SET_POINTS)
-		return 0;
-
-	if (selector < SMPS_BAND1_SET_POINTS)
-		uV = selector * SMPS_BAND1_UV_STEP + SMPS_BAND1_UV_MIN;
-	else if (selector < (SMPS_BAND1_SET_POINTS + SMPS_BAND2_SET_POINTS))
-		uV = (selector - SMPS_BAND1_SET_POINTS) * SMPS_BAND2_UV_STEP
-			+ SMPS_BAND2_UV_MIN;
-	else
-		uV = (selector - SMPS_BAND1_SET_POINTS - SMPS_BAND2_SET_POINTS)
-				* SMPS_BAND3_UV_STEP
-			+ SMPS_BAND3_UV_MIN;
-
-	return uV;
-}
-
-static int pm8018_smps_get_voltage(struct regulator_dev *rdev)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	int uV;
-
-	mutex_lock(&vreg->pc_lock);
-	uV = _pm8018_smps_get_voltage(vreg);
-	mutex_unlock(&vreg->pc_lock);
-
-	return uV;
-}
-
-static int pm8018_smps_set_voltage_advanced(struct pm8018_vreg *vreg,
-					   int min_uV, int max_uV, int force_on)
-{
-	u8 vprog, band;
-	int rc;
-	int uV = min_uV;
-
-	if (uV < SMPS_BAND1_UV_MIN && max_uV >= SMPS_BAND1_UV_MIN)
-		uV = SMPS_BAND1_UV_MIN;
-
-	if (uV < SMPS_BAND1_UV_MIN || uV > SMPS_BAND3_UV_MAX) {
-		vreg_err(vreg,
-			"request v=[%d, %d] is outside possible v=[%d, %d]\n",
-			 min_uV, max_uV, SMPS_BAND1_UV_MIN, SMPS_BAND3_UV_MAX);
-		return -EINVAL;
-	}
-
-	if (uV > SMPS_BAND2_UV_MAX) {
-		vprog = (uV - SMPS_BAND3_UV_MIN + SMPS_BAND3_UV_STEP - 1)
-			/ SMPS_BAND3_UV_STEP;
-		band = SMPS_ADVANCED_BAND_3;
-		uV = SMPS_BAND3_UV_MIN + vprog * SMPS_BAND3_UV_STEP;
-	} else if (uV > SMPS_BAND1_UV_MAX) {
-		vprog = (uV - SMPS_BAND2_UV_MIN + SMPS_BAND2_UV_STEP - 1)
-			/ SMPS_BAND2_UV_STEP;
-		band = SMPS_ADVANCED_BAND_2;
-		uV = SMPS_BAND2_UV_MIN + vprog * SMPS_BAND2_UV_STEP;
-	} else {
-		vprog = (uV - SMPS_BAND1_UV_MIN + SMPS_BAND1_UV_STEP - 1)
-			/ SMPS_BAND1_UV_STEP;
-		band = SMPS_ADVANCED_BAND_1;
-		uV = SMPS_BAND1_UV_MIN + vprog * SMPS_BAND1_UV_STEP;
-	}
-
-	if (uV > max_uV) {
-		vreg_err(vreg,
-			"request v=[%d, %d] cannot be met by any set point\n",
-			min_uV, max_uV);
-		return -EINVAL;
-	}
-
-	/* Do not set band if regulator currently disabled. */
-	if (!_pm8018_vreg_is_enabled(vreg) && !force_on)
-		band = SMPS_ADVANCED_BAND_OFF;
-
-	/* Set advanced mode bit to 1. */
-	rc = pm8018_vreg_masked_write(vreg, vreg->test_addr, SMPS_ADVANCED_MODE
-		| REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(7),
-		SMPS_ADVANCED_MODE_MASK | REGULATOR_BANK_MASK,
-		&vreg->test_reg[7]);
-	if (rc)
-		goto bail;
-
-	/* Set voltage and voltage band. */
-	rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr, band | vprog,
-			SMPS_ADVANCED_BAND_MASK | SMPS_ADVANCED_VPROG_MASK,
-			&vreg->ctrl_reg);
-	if (rc)
-		goto bail;
-
-	vreg->save_uV = uV;
-
-bail:
-	if (rc)
-		vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
-
-	return rc;
-}
-
-static int pm8018_smps_set_voltage_legacy(struct pm8018_vreg *vreg, int min_uV,
-					  int max_uV)
-{
-	u8 vlow, vref, vprog, pd, en;
-	int rc;
-	int uV = min_uV;
-
-
-	if (uV < SMPS_MODE3_UV_MIN && max_uV >= SMPS_MODE3_UV_MIN)
-		uV = SMPS_MODE3_UV_MIN;
-
-	if (uV < SMPS_MODE3_UV_MIN || uV > SMPS_MODE1_UV_MAX) {
-		vreg_err(vreg,
-			"request v=[%d, %d] is outside possible v=[%d, %d]\n",
-			 min_uV, max_uV, SMPS_MODE3_UV_MIN, SMPS_MODE1_UV_MAX);
-		return -EINVAL;
-	}
-
-	if (uV > SMPS_MODE2_UV_MAX) {
-		vprog = (uV - SMPS_MODE1_UV_MIN + SMPS_MODE1_UV_STEP - 1)
-			/ SMPS_MODE1_UV_STEP;
-		vref = 0;
-		vlow = 0;
-		uV = SMPS_MODE1_UV_MIN + vprog * SMPS_MODE1_UV_STEP;
-	} else if (uV > SMPS_MODE3_UV_MAX) {
-		vprog = (uV - SMPS_MODE2_UV_MIN + SMPS_MODE2_UV_STEP - 1)
-			/ SMPS_MODE2_UV_STEP;
-		vref = SMPS_LEGACY_VREF_SEL_MASK;
-		vlow = 0;
-		uV = SMPS_MODE2_UV_MIN + vprog * SMPS_MODE2_UV_STEP;
-	} else {
-		vprog = (uV - SMPS_MODE3_UV_MIN + SMPS_MODE3_UV_STEP - 1)
-			/ SMPS_MODE3_UV_STEP;
-		vref = SMPS_LEGACY_VREF_SEL_MASK;
-		vlow = SMPS_LEGACY_VLOW_SEL_MASK;
-		uV = SMPS_MODE3_UV_MIN + vprog * SMPS_MODE3_UV_STEP;
-	}
-
-	if (uV > max_uV) {
-		vreg_err(vreg,
-			"request v=[%d, %d] cannot be met by any set point\n",
-			min_uV, max_uV);
-		return -EINVAL;
-	}
-
-	/* set vlow bit for ultra low voltage mode */
-	rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
-		vlow | REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(1),
-		REGULATOR_BANK_MASK | SMPS_LEGACY_VLOW_SEL_MASK,
-		&vreg->test_reg[1]);
-	if (rc)
-		goto bail;
-
-	/* Set advanced mode bit to 0. */
-	rc = pm8018_vreg_masked_write(vreg, vreg->test_addr, SMPS_LEGACY_MODE
-		| REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(7),
-		SMPS_ADVANCED_MODE_MASK | REGULATOR_BANK_MASK,
-		&vreg->test_reg[7]);
-	if (rc)
-		goto bail;
-
-	en = (_pm8018_vreg_is_enabled(vreg) ? SMPS_LEGACY_ENABLE : 0);
-	pd = (vreg->pdata.pull_down_enable ? SMPS_LEGACY_PULL_DOWN_ENABLE : 0);
-
-	/* Set voltage (and the rest of the control register). */
-	rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
-		en | pd | vref | vprog,
-		SMPS_LEGACY_ENABLE_MASK | SMPS_LEGACY_PULL_DOWN_ENABLE
-		  | SMPS_LEGACY_VREF_SEL_MASK | SMPS_LEGACY_VPROG_MASK,
-		&vreg->ctrl_reg);
-
-	vreg->save_uV = uV;
-
-bail:
-	if (rc)
-		vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
-
-	return rc;
-}
-
-static int pm8018_smps_set_voltage(struct regulator_dev *rdev, int min_uV,
-				   int max_uV, unsigned *selector)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc = 0;
-
-	mutex_lock(&vreg->pc_lock);
-
-	if (SMPS_IN_ADVANCED_MODE(vreg) || !pm8018_vreg_is_pin_controlled(vreg))
-		rc = pm8018_smps_set_voltage_advanced(vreg, min_uV, max_uV, 0);
-	else
-		rc = pm8018_smps_set_voltage_legacy(vreg, min_uV, max_uV);
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (!rc)
-		pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_VOLTAGE);
-
-	return rc;
-}
-
-static unsigned int pm8018_ldo_get_mode(struct regulator_dev *rdev)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	unsigned int mode = 0;
-
-	mutex_lock(&vreg->pc_lock);
-	mode = vreg->mode;
-	mutex_unlock(&vreg->pc_lock);
-
-	return mode;
-}
-
-static int pm8018_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc = 0;
-
-	if (mode != REGULATOR_MODE_NORMAL && mode != REGULATOR_MODE_IDLE) {
-		vreg_err(vreg, "invalid mode: %u\n", mode);
-		return -EINVAL;
-	}
-
-	mutex_lock(&vreg->pc_lock);
-
-	if (mode == REGULATOR_MODE_NORMAL
-	    || (vreg->is_enabled_pc
-		&& vreg->pdata.pin_fn == PM8018_VREG_PIN_FN_ENABLE)) {
-		/* HPM */
-		rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
-			LDO_CTRL_PM_HPM, LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
-	} else {
-		/* LPM */
-		rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
-			LDO_CTRL_PM_LPM, LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
-		if (rc)
-			goto bail;
-
-		rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
-			LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
-			  | REGULATOR_BANK_SEL(0),
-			LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK,
-			&vreg->test_reg[0]);
-	}
-
-bail:
-	if (!rc)
-		vreg->mode = mode;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_MODE);
-
-	return rc;
-}
-
-static unsigned int pm8018_nldo1200_get_mode(struct regulator_dev *rdev)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	unsigned int mode = 0;
-
-	if (NLDO1200_IN_ADVANCED_MODE(vreg)) {
-		/* Advanced mode */
-		if ((vreg->test_reg[2] & NLDO1200_ADVANCED_PM_MASK)
-		    == NLDO1200_ADVANCED_PM_LPM)
-			mode = REGULATOR_MODE_IDLE;
-		else
-			mode = REGULATOR_MODE_NORMAL;
-	} else {
-		/* Legacy mode */
-		if ((vreg->ctrl_reg & NLDO1200_LEGACY_PM_MASK)
-		    == NLDO1200_LEGACY_PM_LPM)
-			mode = REGULATOR_MODE_IDLE;
-		else
-			mode = REGULATOR_MODE_NORMAL;
-	}
-
-	return mode;
-}
-
-static int pm8018_nldo1200_set_mode(struct regulator_dev *rdev,
-				    unsigned int mode)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc = 0;
-
-	if (mode != REGULATOR_MODE_NORMAL && mode != REGULATOR_MODE_IDLE) {
-		vreg_err(vreg, "invalid mode: %u\n", mode);
-		return -EINVAL;
-	}
-
-	/*
-	 * Make sure that advanced mode is in use.  If it isn't, then set it
-	 * and update the voltage accordingly.
-	 */
-	if (!NLDO1200_IN_ADVANCED_MODE(vreg)) {
-		rc = _pm8018_nldo1200_set_voltage(vreg, vreg->save_uV,
-			vreg->save_uV);
-		if (rc)
-			goto bail;
-	}
-
-	if (mode == REGULATOR_MODE_NORMAL) {
-		/* HPM */
-		rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
-			NLDO1200_ADVANCED_PM_HPM | REGULATOR_BANK_WRITE
-			| REGULATOR_BANK_SEL(2), NLDO1200_ADVANCED_PM_MASK
-			| REGULATOR_BANK_MASK, &vreg->test_reg[2]);
-	} else {
-		/* LPM */
-		rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
-			NLDO1200_ADVANCED_PM_LPM | REGULATOR_BANK_WRITE
-			| REGULATOR_BANK_SEL(2), NLDO1200_ADVANCED_PM_MASK
-			| REGULATOR_BANK_MASK, &vreg->test_reg[2]);
-	}
-
-bail:
-	if (rc)
-		vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_MODE);
-
-	return rc;
-}
-
-static unsigned int pm8018_smps_get_mode(struct regulator_dev *rdev)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	unsigned int mode = 0;
-
-	mutex_lock(&vreg->pc_lock);
-	mode = vreg->mode;
-	mutex_unlock(&vreg->pc_lock);
-
-	return mode;
-}
-
-static int pm8018_smps_set_mode(struct regulator_dev *rdev, unsigned int mode)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc = 0;
-
-	if (mode != REGULATOR_MODE_NORMAL && mode != REGULATOR_MODE_IDLE) {
-		vreg_err(vreg, "invalid mode: %u\n", mode);
-		return -EINVAL;
-	}
-
-	mutex_lock(&vreg->pc_lock);
-
-	if (mode == REGULATOR_MODE_NORMAL
-	    || (vreg->is_enabled_pc
-		&& vreg->pdata.pin_fn == PM8018_VREG_PIN_FN_ENABLE)) {
-		/* HPM */
-		rc = pm8018_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
-				       SMPS_CLK_CTRL_PWM, SMPS_CLK_CTRL_MASK,
-				       &vreg->clk_ctrl_reg);
-	} else {
-		/* LPM */
-		rc = pm8018_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
-				       SMPS_CLK_CTRL_PFM, SMPS_CLK_CTRL_MASK,
-				       &vreg->clk_ctrl_reg);
-	}
-
-	if (!rc)
-		vreg->mode = mode;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_MODE);
-
-	return rc;
-}
-
-static unsigned int pm8018_vreg_get_optimum_mode(struct regulator_dev *rdev,
-		int input_uV, int output_uV, int load_uA)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	unsigned int mode;
-
-	if (load_uA + vreg->pdata.system_uA >= vreg->hpm_min_load)
-		mode = REGULATOR_MODE_NORMAL;
-	else
-		mode = REGULATOR_MODE_IDLE;
-
-	return mode;
-}
-
-static int pm8018_ldo_enable(struct regulator_dev *rdev)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc, val;
-
-	mutex_lock(&vreg->pc_lock);
-
-	/*
-	 * Choose HPM if previously set to HPM or if pin control is enabled in
-	 * on/off mode.
-	 */
-	val = LDO_CTRL_PM_LPM;
-	if (vreg->mode == REGULATOR_MODE_NORMAL
-		|| (vreg->is_enabled_pc
-			&& vreg->pdata.pin_fn == PM8018_VREG_PIN_FN_ENABLE))
-		val = LDO_CTRL_PM_HPM;
-
-	rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr, val | LDO_ENABLE,
-		LDO_ENABLE_MASK | LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
-
-	if (!rc)
-		vreg->is_enabled = true;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_ENABLE);
-
-	return rc;
-}
-
-static int pm8018_ldo_disable(struct regulator_dev *rdev)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	mutex_lock(&vreg->pc_lock);
-
-	/*
-	 * Only disable the regulator if it isn't still required for HPM/LPM
-	 * pin control.
-	 */
-	if (!vreg->is_enabled_pc
-	    || vreg->pdata.pin_fn != PM8018_VREG_PIN_FN_MODE) {
-		rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
-			LDO_DISABLE, LDO_ENABLE_MASK, &vreg->ctrl_reg);
-		if (rc)
-			goto bail;
-	}
-
-	/* Change to LPM if HPM/LPM pin control is enabled. */
-	if (vreg->is_enabled_pc
-	    && vreg->pdata.pin_fn == PM8018_VREG_PIN_FN_MODE) {
-		rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
-			LDO_CTRL_PM_LPM, LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
-		if (rc)
-			goto bail;
-
-		rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
-			LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
-			  | REGULATOR_BANK_SEL(0),
-			LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK,
-			&vreg->test_reg[0]);
-	}
-
-	if (!rc)
-		vreg->is_enabled = false;
-bail:
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_DISABLE);
-
-	return rc;
-}
-
-static int pm8018_nldo1200_enable(struct regulator_dev *rdev)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr, NLDO1200_ENABLE,
-		NLDO1200_ENABLE_MASK, &vreg->ctrl_reg);
-
-	if (rc)
-		vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_ENABLE);
-
-	return rc;
-}
-
-static int pm8018_nldo1200_disable(struct regulator_dev *rdev)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr, NLDO1200_DISABLE,
-		NLDO1200_ENABLE_MASK, &vreg->ctrl_reg);
-
-	if (rc)
-		vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_DISABLE);
-
-	return rc;
-}
-
-static int pm8018_smps_enable(struct regulator_dev *rdev)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc = 0;
-	int val;
-
-	mutex_lock(&vreg->pc_lock);
-
-	if (SMPS_IN_ADVANCED_MODE(vreg)
-	     || !pm8018_vreg_is_pin_controlled(vreg)) {
-		/* Enable in advanced mode if not using pin control. */
-		rc = pm8018_smps_set_voltage_advanced(vreg, vreg->save_uV,
-			vreg->save_uV, 1);
-	} else {
-		rc = pm8018_smps_set_voltage_legacy(vreg, vreg->save_uV,
-			vreg->save_uV);
-		if (rc)
-			goto bail;
-
-		rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
-			SMPS_LEGACY_ENABLE, SMPS_LEGACY_ENABLE_MASK,
-			&vreg->ctrl_reg);
-	}
-
-	/*
-	 * Choose HPM if previously set to HPM or if pin control is enabled in
-	 * on/off mode.
-	 */
-	val = SMPS_CLK_CTRL_PFM;
-	if (vreg->mode == REGULATOR_MODE_NORMAL
-		|| (vreg->is_enabled_pc
-			&& vreg->pdata.pin_fn == PM8018_VREG_PIN_FN_ENABLE))
-		val = SMPS_CLK_CTRL_PWM;
-
-	rc = pm8018_vreg_masked_write(vreg, vreg->clk_ctrl_addr, val,
-			SMPS_CLK_CTRL_MASK, &vreg->clk_ctrl_reg);
-
-	if (!rc)
-		vreg->is_enabled = true;
-bail:
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_ENABLE);
-
-	return rc;
-}
-
-static int pm8018_smps_disable(struct regulator_dev *rdev)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	mutex_lock(&vreg->pc_lock);
-
-	if (SMPS_IN_ADVANCED_MODE(vreg)) {
-		/* Change SMPS to legacy mode before disabling. */
-		rc = pm8018_smps_set_voltage_legacy(vreg, vreg->save_uV,
-				vreg->save_uV);
-		if (rc)
-			goto bail;
-	}
-
-	/*
-	 * Only disable the regulator if it isn't still required for HPM/LPM
-	 * pin control.
-	 */
-	if (!vreg->is_enabled_pc
-	    || vreg->pdata.pin_fn != PM8018_VREG_PIN_FN_MODE) {
-		rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
-			SMPS_LEGACY_DISABLE, SMPS_LEGACY_ENABLE_MASK,
-			&vreg->ctrl_reg);
-		if (rc)
-			goto bail;
-	}
-
-	/* Change to LPM if HPM/LPM pin control is enabled. */
-	if (vreg->is_enabled_pc
-	    && vreg->pdata.pin_fn == PM8018_VREG_PIN_FN_MODE)
-		rc = pm8018_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
-		       SMPS_CLK_CTRL_PFM, SMPS_CLK_CTRL_MASK,
-		       &vreg->clk_ctrl_reg);
-
-	if (!rc)
-		vreg->is_enabled = false;
-
-bail:
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_DISABLE);
-
-	return rc;
-}
-
-static int pm8018_vs_enable(struct regulator_dev *rdev)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	mutex_lock(&vreg->pc_lock);
-
-	rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr, VS_ENABLE,
-		VS_ENABLE_MASK, &vreg->ctrl_reg);
-
-	if (!rc)
-		vreg->is_enabled = true;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_ENABLE);
-
-	return rc;
-}
-
-static int pm8018_vs_disable(struct regulator_dev *rdev)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	mutex_lock(&vreg->pc_lock);
-
-	rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr, VS_DISABLE,
-		VS_ENABLE_MASK, &vreg->ctrl_reg);
-
-	if (!rc)
-		vreg->is_enabled = false;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_DISABLE);
-
-	return rc;
-}
-
-static int pm8018_ldo_pin_control_enable(struct regulator_dev *rdev)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc = 0;
-	int bank;
-	u8 val = 0;
-	u8 mask;
-
-	mutex_lock(&vreg->pc_lock);
-
-	if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_D1)
-		val |= LDO_TEST_PIN_CTRL_EN0;
-	if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_A0)
-		val |= LDO_TEST_PIN_CTRL_EN1;
-	if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_A1)
-		val |= LDO_TEST_PIN_CTRL_EN2;
-	if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_A2)
-		val |= LDO_TEST_PIN_CTRL_EN3;
-
-	bank = (vreg->pdata.pin_fn == PM8018_VREG_PIN_FN_ENABLE ? 5 : 6);
-	rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
-		val | REGULATOR_BANK_SEL(bank) | REGULATOR_BANK_WRITE,
-		LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
-		&vreg->test_reg[bank]);
-	if (rc)
-		goto bail;
-
-	/* Unset pin control bits in unused bank. */
-	bank = (bank == 5 ? 6 : 5);
-	rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
-		REGULATOR_BANK_SEL(bank) | REGULATOR_BANK_WRITE,
-		LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
-		&vreg->test_reg[bank]);
-	if (rc)
-		goto bail;
-
-	val = LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
-		| REGULATOR_BANK_SEL(0);
-	mask = LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK;
-	rc = pm8018_vreg_masked_write(vreg, vreg->test_addr, val, mask,
-		&vreg->test_reg[0]);
-	if (rc)
-		goto bail;
-
-	if (vreg->pdata.pin_fn == PM8018_VREG_PIN_FN_ENABLE) {
-		/* Pin control ON/OFF */
-		val = LDO_CTRL_PM_HPM;
-		/* Leave physically enabled if already enabled. */
-		val |= (vreg->is_enabled ? LDO_ENABLE : LDO_DISABLE);
-		rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr, val,
-			LDO_ENABLE_MASK | LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
-		if (rc)
-			goto bail;
-	} else {
-		/* Pin control LPM/HPM */
-		val = LDO_ENABLE;
-		/* Leave in HPM if already enabled in HPM. */
-		val |= (vreg->is_enabled && vreg->mode == REGULATOR_MODE_NORMAL
-			?  LDO_CTRL_PM_HPM : LDO_CTRL_PM_LPM);
-		rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr, val,
-			LDO_ENABLE_MASK | LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
-		if (rc)
-			goto bail;
-	}
-
-bail:
-	if (!rc)
-		vreg->is_enabled_pc = true;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_PIN_CTRL);
-
-	return rc;
-}
-
-static int pm8018_ldo_pin_control_disable(struct regulator_dev *rdev)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	mutex_lock(&vreg->pc_lock);
-
-	rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
-			REGULATOR_BANK_SEL(5) | REGULATOR_BANK_WRITE,
-			LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
-			&vreg->test_reg[5]);
-	if (rc)
-		goto bail;
-
-	rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
-			REGULATOR_BANK_SEL(6) | REGULATOR_BANK_WRITE,
-			LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
-			&vreg->test_reg[6]);
-
-	/*
-	 * Physically disable the regulator if it was enabled in HPM/LPM pin
-	 * control mode previously and it logically should not be enabled.
-	 */
-	if ((vreg->ctrl_reg & LDO_ENABLE_MASK) == LDO_ENABLE
-	    && !vreg->is_enabled) {
-		rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
-			LDO_DISABLE, LDO_ENABLE_MASK, &vreg->ctrl_reg);
-		if (rc)
-			goto bail;
-	}
-
-	/* Change to LPM if LPM was enabled. */
-	if (vreg->is_enabled && vreg->mode == REGULATOR_MODE_IDLE) {
-		rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
-			LDO_CTRL_PM_LPM, LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
-		if (rc)
-			goto bail;
-
-		rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
-			LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
-			  | REGULATOR_BANK_SEL(0),
-			LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK,
-			&vreg->test_reg[0]);
-		if (rc)
-			goto bail;
-	}
-
-bail:
-	if (!rc)
-		vreg->is_enabled_pc = false;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_PIN_CTRL);
-
-	return rc;
-}
-
-static int pm8018_smps_pin_control_enable(struct regulator_dev *rdev)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc = 0;
-	u8 val = 0;
-
-	mutex_lock(&vreg->pc_lock);
-
-	if (vreg->pdata.pin_fn == PM8018_VREG_PIN_FN_ENABLE) {
-		/* Pin control ON/OFF */
-		if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_D1)
-			val |= SMPS_PIN_CTRL_EN0;
-		if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_A0)
-			val |= SMPS_PIN_CTRL_EN1;
-		if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_A1)
-			val |= SMPS_PIN_CTRL_EN2;
-		if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_A2)
-			val |= SMPS_PIN_CTRL_EN3;
-	} else {
-		/* Pin control LPM/HPM */
-		if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_D1)
-			val |= SMPS_PIN_CTRL_LPM_EN0;
-		if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_A0)
-			val |= SMPS_PIN_CTRL_LPM_EN1;
-		if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_A1)
-			val |= SMPS_PIN_CTRL_LPM_EN2;
-		if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_A2)
-			val |= SMPS_PIN_CTRL_LPM_EN3;
-	}
-
-	rc = pm8018_smps_set_voltage_legacy(vreg, vreg->save_uV, vreg->save_uV);
-	if (rc)
-		goto bail;
-
-	rc = pm8018_vreg_masked_write(vreg, vreg->sleep_ctrl_addr, val,
-			SMPS_PIN_CTRL_MASK | SMPS_PIN_CTRL_LPM_MASK,
-			&vreg->sleep_ctrl_reg);
-	if (rc)
-		goto bail;
-
-	/*
-	 * Physically enable the regulator if using HPM/LPM pin control mode or
-	 * if the regulator should be logically left on.
-	 */
-	rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
-		((vreg->pdata.pin_fn == PM8018_VREG_PIN_FN_MODE
-		  || vreg->is_enabled) ?
-			SMPS_LEGACY_ENABLE : SMPS_LEGACY_DISABLE),
-		SMPS_LEGACY_ENABLE_MASK, &vreg->ctrl_reg);
-	if (rc)
-		goto bail;
-
-	/*
-	 * Set regulator to HPM if using on/off pin control or if the regulator
-	 * is already enabled in HPM.  Otherwise, set it to LPM.
-	 */
-	rc = pm8018_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
-			(vreg->pdata.pin_fn == PM8018_VREG_PIN_FN_ENABLE
-			 || (vreg->is_enabled
-			     && vreg->mode == REGULATOR_MODE_NORMAL)
-				? SMPS_CLK_CTRL_PWM : SMPS_CLK_CTRL_PFM),
-			SMPS_CLK_CTRL_MASK, &vreg->clk_ctrl_reg);
-
-bail:
-	if (!rc)
-		vreg->is_enabled_pc = true;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_PIN_CTRL);
-
-	return rc;
-}
-
-static int pm8018_smps_pin_control_disable(struct regulator_dev *rdev)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	mutex_lock(&vreg->pc_lock);
-
-	rc = pm8018_vreg_masked_write(vreg, vreg->sleep_ctrl_addr, 0,
-			SMPS_PIN_CTRL_MASK | SMPS_PIN_CTRL_LPM_MASK,
-			&vreg->sleep_ctrl_reg);
-	if (rc)
-		goto bail;
-
-	/*
-	 * Physically disable the regulator if it was enabled in HPM/LPM pin
-	 * control mode previously and it logically should not be enabled.
-	 */
-	if ((vreg->ctrl_reg & SMPS_LEGACY_ENABLE_MASK) == SMPS_LEGACY_ENABLE
-	    && vreg->is_enabled == false) {
-		rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
-			SMPS_LEGACY_DISABLE, SMPS_LEGACY_ENABLE_MASK,
-			&vreg->ctrl_reg);
-		if (rc)
-			goto bail;
-	}
-
-	/* Change to LPM if LPM was enabled. */
-	if (vreg->is_enabled && vreg->mode == REGULATOR_MODE_IDLE) {
-		rc = pm8018_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
-		       SMPS_CLK_CTRL_PFM, SMPS_CLK_CTRL_MASK,
-		       &vreg->clk_ctrl_reg);
-		if (rc)
-			goto bail;
-	}
-
-	rc = pm8018_smps_set_voltage_advanced(vreg, vreg->save_uV,
-			vreg->save_uV, 0);
-
-bail:
-	if (!rc)
-		vreg->is_enabled_pc = false;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_PIN_CTRL);
-
-	return rc;
-}
-
-static int pm8018_vs_pin_control_enable(struct regulator_dev *rdev)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-	u8 val = 0;
-
-	mutex_lock(&vreg->pc_lock);
-
-	if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_D1)
-		val |= VS_PIN_CTRL_EN0;
-	if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_A0)
-		val |= VS_PIN_CTRL_EN1;
-	if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_A1)
-		val |= VS_PIN_CTRL_EN2;
-	if (vreg->pdata.pin_ctrl & PM8018_VREG_PIN_CTRL_A2)
-		val |= VS_PIN_CTRL_EN3;
-
-	rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr, val,
-			VS_PIN_CTRL_MASK | VS_ENABLE_MASK, &vreg->ctrl_reg);
-
-	if (!rc)
-		vreg->is_enabled_pc = true;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_PIN_CTRL);
-
-	return rc;
-}
-
-static int pm8018_vs_pin_control_disable(struct regulator_dev *rdev)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	mutex_lock(&vreg->pc_lock);
-
-	rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr, 0,
-				      VS_PIN_CTRL_MASK, &vreg->ctrl_reg);
-
-	if (!rc)
-		vreg->is_enabled_pc = false;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8018_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8018_vreg_show_state(rdev, PM8018_REGULATOR_ACTION_PIN_CTRL);
-
-	return rc;
-}
-
-static int pm8018_enable_time(struct regulator_dev *rdev)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-
-	return vreg->pdata.enable_time;
-}
-
-static const char const *pm8018_print_actions[] = {
-	[PM8018_REGULATOR_ACTION_INIT]		= "initial    ",
-	[PM8018_REGULATOR_ACTION_ENABLE]	= "enable     ",
-	[PM8018_REGULATOR_ACTION_DISABLE]	= "disable    ",
-	[PM8018_REGULATOR_ACTION_VOLTAGE]	= "set voltage",
-	[PM8018_REGULATOR_ACTION_MODE]		= "set mode   ",
-	[PM8018_REGULATOR_ACTION_PIN_CTRL]	= "pin control",
-};
-
-static void pm8018_vreg_show_state(struct regulator_dev *rdev,
-				   enum pm8018_regulator_action action)
-{
-	struct pm8018_vreg *vreg = rdev_get_drvdata(rdev);
-	int uV, pc;
-	unsigned int mode;
-	const char *pc_en0 = "", *pc_en1 = "", *pc_en2 = "", *pc_en3 = "";
-	const char *pc_total = "";
-	const char *action_label = pm8018_print_actions[action];
-	const char *enable_label;
-
-	mutex_lock(&vreg->pc_lock);
-
-	/*
-	 * Do not print unless REQUEST is specified and SSBI writes have taken
-	 * place, or DUPLICATE is specified.
-	 */
-	if (!((pm8018_vreg_debug_mask & PM8018_VREG_DEBUG_DUPLICATE)
-	      || ((pm8018_vreg_debug_mask & PM8018_VREG_DEBUG_REQUEST)
-		  && (vreg->write_count != vreg->prev_write_count)))) {
-		mutex_unlock(&vreg->pc_lock);
-		return;
-	}
-
-	vreg->prev_write_count = vreg->write_count;
-
-	pc = vreg->pdata.pin_ctrl;
-	if (vreg->is_enabled_pc) {
-		if (pc & PM8018_VREG_PIN_CTRL_D1)
-			pc_en0 = " D1";
-		if (pc & PM8018_VREG_PIN_CTRL_A0)
-			pc_en1 = " A0";
-		if (pc & PM8018_VREG_PIN_CTRL_A1)
-			pc_en2 = " A1";
-		if (pc & PM8018_VREG_PIN_CTRL_A2)
-			pc_en3 = " A2";
-		if (pc == PM8018_VREG_PIN_CTRL_NONE)
-			pc_total = " none";
-	} else {
-		pc_total = " none";
-	}
-
-	mutex_unlock(&vreg->pc_lock);
-
-	enable_label = pm8018_vreg_is_enabled(rdev) ? "on " : "off";
-
-	switch (vreg->type) {
-	case REGULATOR_TYPE_PLDO:
-		uV = pm8018_pldo_get_voltage(rdev);
-		mode = pm8018_ldo_get_mode(rdev);
-		pr_info("%s %-9s: %s, v=%7d uV, mode=%s, pc=%s%s%s%s%s\n",
-			action_label, vreg->name, enable_label, uV,
-			(mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"),
-			pc_en0, pc_en1, pc_en2, pc_en3, pc_total);
-		break;
-	case REGULATOR_TYPE_NLDO:
-		uV = pm8018_nldo_get_voltage(rdev);
-		mode = pm8018_ldo_get_mode(rdev);
-		pr_info("%s %-9s: %s, v=%7d uV, mode=%s, pc=%s%s%s%s%s\n",
-			action_label, vreg->name, enable_label, uV,
-			(mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"),
-			pc_en0, pc_en1, pc_en2, pc_en3, pc_total);
-		break;
-	case REGULATOR_TYPE_NLDO1200:
-		uV = pm8018_nldo1200_get_voltage(rdev);
-		mode = pm8018_nldo1200_get_mode(rdev);
-		pr_info("%s %-9s: %s, v=%7d uV, mode=%s\n",
-			action_label, vreg->name, enable_label, uV,
-			(mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"));
-		break;
-	case REGULATOR_TYPE_SMPS:
-		uV = pm8018_smps_get_voltage(rdev);
-		mode = pm8018_smps_get_mode(rdev);
-		pr_info("%s %-9s: %s, v=%7d uV, mode=%s, pc=%s%s%s%s%s\n",
-			action_label, vreg->name, enable_label, uV,
-			(mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"),
-			pc_en0, pc_en1, pc_en2, pc_en3, pc_total);
-		break;
-	case REGULATOR_TYPE_VS:
-		pr_info("%s %-9s: %s, pc=%s%s%s%s%s\n",
-			action_label, vreg->name, enable_label,
-			pc_en0, pc_en1, pc_en2, pc_en3, pc_total);
-		break;
-	default:
-		break;
-	}
-}
-
-/* Real regulator operations. */
-static struct regulator_ops pm8018_pldo_ops = {
-	.enable			= pm8018_ldo_enable,
-	.disable		= pm8018_ldo_disable,
-	.is_enabled		= pm8018_vreg_is_enabled,
-	.set_voltage		= pm8018_pldo_set_voltage,
-	.get_voltage		= pm8018_pldo_get_voltage,
-	.list_voltage		= pm8018_pldo_list_voltage,
-	.set_mode		= pm8018_ldo_set_mode,
-	.get_mode		= pm8018_ldo_get_mode,
-	.get_optimum_mode	= pm8018_vreg_get_optimum_mode,
-	.enable_time		= pm8018_enable_time,
-};
-
-static struct regulator_ops pm8018_nldo_ops = {
-	.enable			= pm8018_ldo_enable,
-	.disable		= pm8018_ldo_disable,
-	.is_enabled		= pm8018_vreg_is_enabled,
-	.set_voltage		= pm8018_nldo_set_voltage,
-	.get_voltage		= pm8018_nldo_get_voltage,
-	.list_voltage		= pm8018_nldo_list_voltage,
-	.set_mode		= pm8018_ldo_set_mode,
-	.get_mode		= pm8018_ldo_get_mode,
-	.get_optimum_mode	= pm8018_vreg_get_optimum_mode,
-	.enable_time		= pm8018_enable_time,
-};
-
-static struct regulator_ops pm8018_nldo1200_ops = {
-	.enable			= pm8018_nldo1200_enable,
-	.disable		= pm8018_nldo1200_disable,
-	.is_enabled		= pm8018_vreg_is_enabled,
-	.set_voltage		= pm8018_nldo1200_set_voltage,
-	.get_voltage		= pm8018_nldo1200_get_voltage,
-	.list_voltage		= pm8018_nldo1200_list_voltage,
-	.set_mode		= pm8018_nldo1200_set_mode,
-	.get_mode		= pm8018_nldo1200_get_mode,
-	.get_optimum_mode	= pm8018_vreg_get_optimum_mode,
-	.enable_time		= pm8018_enable_time,
-};
-
-static struct regulator_ops pm8018_smps_ops = {
-	.enable			= pm8018_smps_enable,
-	.disable		= pm8018_smps_disable,
-	.is_enabled		= pm8018_vreg_is_enabled,
-	.set_voltage		= pm8018_smps_set_voltage,
-	.get_voltage		= pm8018_smps_get_voltage,
-	.list_voltage		= pm8018_smps_list_voltage,
-	.set_mode		= pm8018_smps_set_mode,
-	.get_mode		= pm8018_smps_get_mode,
-	.get_optimum_mode	= pm8018_vreg_get_optimum_mode,
-	.enable_time		= pm8018_enable_time,
-};
-
-static struct regulator_ops pm8018_vs_ops = {
-	.enable			= pm8018_vs_enable,
-	.disable		= pm8018_vs_disable,
-	.is_enabled		= pm8018_vreg_is_enabled,
-	.enable_time		= pm8018_enable_time,
-};
-
-/* Pin control regulator operations. */
-static struct regulator_ops pm8018_ldo_pc_ops = {
-	.enable			= pm8018_ldo_pin_control_enable,
-	.disable		= pm8018_ldo_pin_control_disable,
-	.is_enabled		= pm8018_vreg_pin_control_is_enabled,
-};
-
-static struct regulator_ops pm8018_smps_pc_ops = {
-	.enable			= pm8018_smps_pin_control_enable,
-	.disable		= pm8018_smps_pin_control_disable,
-	.is_enabled		= pm8018_vreg_pin_control_is_enabled,
-};
-
-static struct regulator_ops pm8018_vs_pc_ops = {
-	.enable			= pm8018_vs_pin_control_enable,
-	.disable		= pm8018_vs_pin_control_disable,
-	.is_enabled		= pm8018_vreg_pin_control_is_enabled,
-};
-
-#define VREG_DESC(_id, _name, _ops, _n_voltages) \
-	[PM8018_VREG_ID_##_id] = { \
-		.id	= PM8018_VREG_ID_##_id, \
-		.name	= _name, \
-		.n_voltages = _n_voltages, \
-		.ops	= _ops, \
-		.type	= REGULATOR_VOLTAGE, \
-		.owner	= THIS_MODULE, \
-	}
-
-static struct regulator_desc pm8018_vreg_description[] = {
-	VREG_DESC(L2,  "8018_l2",  &pm8018_pldo_ops, PLDO_SET_POINTS),
-	VREG_DESC(L3,  "8018_l3",  &pm8018_pldo_ops, PLDO_SET_POINTS),
-	VREG_DESC(L4,  "8018_l4",  &pm8018_pldo_ops, PLDO_SET_POINTS),
-	VREG_DESC(L5,  "8018_l5",  &pm8018_pldo_ops, PLDO_SET_POINTS),
-	VREG_DESC(L6,  "8018_l6",  &pm8018_pldo_ops, PLDO_SET_POINTS),
-	VREG_DESC(L7,  "8018_l7",  &pm8018_pldo_ops, PLDO_SET_POINTS),
-	VREG_DESC(L8,  "8018_l8",  &pm8018_nldo_ops, NLDO_SET_POINTS),
-	VREG_DESC(L9,  "8018_l9",  &pm8018_nldo1200_ops, NLDO1200_SET_POINTS),
-	VREG_DESC(L10, "8018_l10", &pm8018_nldo1200_ops, NLDO1200_SET_POINTS),
-	VREG_DESC(L11, "8018_l11", &pm8018_nldo1200_ops, NLDO1200_SET_POINTS),
-	VREG_DESC(L12, "8018_l12", &pm8018_nldo1200_ops, NLDO1200_SET_POINTS),
-	VREG_DESC(L13, "8018_l13", &pm8018_pldo_ops, PLDO_SET_POINTS),
-	VREG_DESC(L14, "8018_l14", &pm8018_pldo_ops, PLDO_SET_POINTS),
-
-	VREG_DESC(S1, "8018_s1", &pm8018_smps_ops, SMPS_ADVANCED_SET_POINTS),
-	VREG_DESC(S2, "8018_s2", &pm8018_smps_ops, SMPS_ADVANCED_SET_POINTS),
-	VREG_DESC(S3, "8018_s3", &pm8018_smps_ops, SMPS_ADVANCED_SET_POINTS),
-	VREG_DESC(S4, "8018_s4", &pm8018_smps_ops, SMPS_ADVANCED_SET_POINTS),
-	VREG_DESC(S5, "8018_s5", &pm8018_smps_ops, SMPS_ADVANCED_SET_POINTS),
-
-	VREG_DESC(LVS1, "8018_lvs1", &pm8018_vs_ops, 0),
-
-	VREG_DESC(L2_PC,  "8018_l2_pc",  &pm8018_ldo_pc_ops, 0),
-	VREG_DESC(L3_PC,  "8018_l3_pc",  &pm8018_ldo_pc_ops, 0),
-	VREG_DESC(L4_PC,  "8018_l4_pc",  &pm8018_ldo_pc_ops, 0),
-	VREG_DESC(L5_PC,  "8018_l5_pc",  &pm8018_ldo_pc_ops, 0),
-	VREG_DESC(L6_PC,  "8018_l6_pc",  &pm8018_ldo_pc_ops, 0),
-	VREG_DESC(L7_PC,  "8018_l7_pc",  &pm8018_ldo_pc_ops, 0),
-	VREG_DESC(L8_PC,  "8018_l8_pc",  &pm8018_ldo_pc_ops, 0),
-
-	VREG_DESC(L13_PC, "8018_l13_pc", &pm8018_ldo_pc_ops, 0),
-	VREG_DESC(L14_PC, "8018_l14_pc", &pm8018_ldo_pc_ops, 0),
-
-	VREG_DESC(S1_PC, "8018_s1_pc", &pm8018_smps_pc_ops, 0),
-	VREG_DESC(S2_PC, "8018_s2_pc", &pm8018_smps_pc_ops, 0),
-	VREG_DESC(S3_PC, "8018_s3_pc", &pm8018_smps_pc_ops, 0),
-	VREG_DESC(S4_PC, "8018_s4_pc", &pm8018_smps_pc_ops, 0),
-	VREG_DESC(S5_PC, "8018_s5_pc", &pm8018_smps_pc_ops, 0),
-
-	VREG_DESC(LVS1_PC, "8018_lvs1_pc", &pm8018_vs_pc_ops, 0),
-};
-
-static int pm8018_init_ldo(struct pm8018_vreg *vreg, bool is_real)
-{
-	int rc = 0;
-	int i;
-	u8 bank;
-
-	/* Save the current control register state. */
-	rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
-	if (rc)
-		goto bail;
-
-	/* Save the current test register state. */
-	for (i = 0; i < LDO_TEST_BANKS; i++) {
-		bank = REGULATOR_BANK_SEL(i);
-		rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
-		if (rc)
-			goto bail;
-
-		rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
-				  &vreg->test_reg[i]);
-		if (rc)
-			goto bail;
-		vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
-	}
-
-	if (is_real) {
-		/* Set pull down enable based on platform data. */
-		rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
-		      (vreg->pdata.pull_down_enable ? LDO_PULL_DOWN_ENABLE : 0),
-		      LDO_PULL_DOWN_ENABLE_MASK, &vreg->ctrl_reg);
-
-		vreg->is_enabled = !!_pm8018_vreg_is_enabled(vreg);
-
-		vreg->mode = ((vreg->ctrl_reg & LDO_CTRL_PM_MASK)
-					== LDO_CTRL_PM_LPM ?
-				REGULATOR_MODE_IDLE : REGULATOR_MODE_NORMAL);
-	}
-bail:
-	if (rc)
-		vreg_err(vreg, "pm8xxx_readb/writeb failed, rc=%d\n", rc);
-
-	return rc;
-}
-
-static int pm8018_init_nldo1200(struct pm8018_vreg *vreg)
-{
-	int rc = 0;
-	int i;
-	u8 bank;
-
-	/* Save the current control register state. */
-	rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
-	if (rc)
-		goto bail;
-
-	/* Save the current test register state. */
-	for (i = 0; i < LDO_TEST_BANKS; i++) {
-		bank = REGULATOR_BANK_SEL(i);
-		rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
-		if (rc)
-			goto bail;
-
-		rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
-				  &vreg->test_reg[i]);
-		if (rc)
-			goto bail;
-		vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
-	}
-
-	vreg->save_uV = _pm8018_nldo1200_get_voltage(vreg);
-
-	/* Set pull down enable based on platform data. */
-	rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
-		 (vreg->pdata.pull_down_enable ? NLDO1200_PULL_DOWN_ENABLE : 0)
-		 | REGULATOR_BANK_SEL(1) | REGULATOR_BANK_WRITE,
-		 NLDO1200_PULL_DOWN_ENABLE_MASK | REGULATOR_BANK_MASK,
-		 &vreg->test_reg[1]);
-
-bail:
-	if (rc)
-		vreg_err(vreg, "pm8xxx_readb/writeb failed, rc=%d\n", rc);
-
-	return rc;
-}
-
-static int pm8018_init_smps(struct pm8018_vreg *vreg, bool is_real)
-{
-	int rc = 0;
-	int i;
-	u8 bank;
-
-	/* Save the current control register state. */
-	rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
-	if (rc)
-		goto bail;
-
-	/* Save the current test2 register state. */
-	for (i = 0; i < SMPS_TEST_BANKS; i++) {
-		bank = REGULATOR_BANK_SEL(i);
-		rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
-		if (rc)
-			goto bail;
-
-		rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
-				  &vreg->test_reg[i]);
-		if (rc)
-			goto bail;
-		vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
-	}
-
-	/* Save the current clock control register state. */
-	rc = pm8xxx_readb(vreg->dev->parent, vreg->clk_ctrl_addr,
-			  &vreg->clk_ctrl_reg);
-	if (rc)
-		goto bail;
-
-	/* Save the current sleep control register state. */
-	rc = pm8xxx_readb(vreg->dev->parent, vreg->sleep_ctrl_addr,
-			  &vreg->sleep_ctrl_reg);
-	if (rc)
-		goto bail;
-
-	vreg->save_uV = _pm8018_smps_get_voltage(vreg);
-
-	if (is_real) {
-		/* Set advanced mode pull down enable based on platform data. */
-		rc = pm8018_vreg_masked_write(vreg, vreg->test_addr,
-			(vreg->pdata.pull_down_enable
-				? SMPS_ADVANCED_PULL_DOWN_ENABLE : 0)
-			| REGULATOR_BANK_SEL(6) | REGULATOR_BANK_WRITE,
-			REGULATOR_BANK_MASK | SMPS_ADVANCED_PULL_DOWN_ENABLE,
-			&vreg->test_reg[6]);
-		if (rc)
-			goto bail;
-
-		vreg->is_enabled = !!_pm8018_vreg_is_enabled(vreg);
-
-		vreg->mode = ((vreg->clk_ctrl_reg & SMPS_CLK_CTRL_MASK)
-					== SMPS_CLK_CTRL_PFM ?
-				REGULATOR_MODE_IDLE : REGULATOR_MODE_NORMAL);
-	}
-
-	if (!SMPS_IN_ADVANCED_MODE(vreg) && is_real) {
-		/* Set legacy mode pull down enable based on platform data. */
-		rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
-			(vreg->pdata.pull_down_enable
-				? SMPS_LEGACY_PULL_DOWN_ENABLE : 0),
-			SMPS_LEGACY_PULL_DOWN_ENABLE, &vreg->ctrl_reg);
-		if (rc)
-			goto bail;
-	}
-
-bail:
-	if (rc)
-		vreg_err(vreg, "pm8xxx_readb/writeb failed, rc=%d\n", rc);
-
-	return rc;
-}
-
-static int pm8018_init_vs(struct pm8018_vreg *vreg, bool is_real)
-{
-	int rc = 0;
-
-	/* Save the current control register state. */
-	rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
-	if (rc) {
-		vreg_err(vreg, "pm8xxx_readb failed, rc=%d\n", rc);
-		return rc;
-	}
-
-	if (is_real) {
-		/* Set pull down enable based on platform data. */
-		rc = pm8018_vreg_masked_write(vreg, vreg->ctrl_addr,
-		       (vreg->pdata.pull_down_enable ? VS_PULL_DOWN_ENABLE : 0),
-		       VS_PULL_DOWN_ENABLE_MASK, &vreg->ctrl_reg);
-
-		if (rc)
-			vreg_err(vreg,
-				"pm8018_vreg_masked_write failed, rc=%d\n", rc);
-
-		vreg->is_enabled = !!_pm8018_vreg_is_enabled(vreg);
-	}
-
-	return rc;
-}
-
-int pc_id_to_real_id(int id)
-{
-	int real_id;
-
-	if (id >= PM8018_VREG_ID_L2_PC && id <= PM8018_VREG_ID_L8_PC)
-		real_id = id - PM8018_VREG_ID_L2_PC + PM8018_VREG_ID_L2;
-	else
-		real_id = id - PM8018_VREG_ID_L13_PC + PM8018_VREG_ID_L13;
-
-	return real_id;
-}
-
-static int __devinit pm8018_vreg_probe(struct platform_device *pdev)
-{
-	const struct pm8018_regulator_platform_data *pdata;
-	enum pm8018_vreg_pin_function pin_fn;
-	struct regulator_desc *rdesc;
-	struct pm8018_vreg *vreg;
-	const char *reg_name = "";
-	unsigned pin_ctrl;
-	int rc = 0, id = pdev->id;
-
-	if (pdev == NULL)
-		return -EINVAL;
-
-	if (pdev->id >= 0 && pdev->id < PM8018_VREG_ID_MAX) {
-		pdata = pdev->dev.platform_data;
-		rdesc = &pm8018_vreg_description[pdev->id];
-		if (!IS_REAL_REGULATOR(pdev->id))
-			id = pc_id_to_real_id(pdev->id);
-		vreg = &pm8018_vreg[id];
-		reg_name = pm8018_vreg_description[pdev->id].name;
-		if (!pdata) {
-			pr_err("%s requires platform data\n", reg_name);
-			return -EINVAL;
-		}
-
-		mutex_lock(&vreg->pc_lock);
-
-		if (IS_REAL_REGULATOR(pdev->id)) {
-			/* Do not modify pin control and pin function values. */
-			pin_ctrl = vreg->pdata.pin_ctrl;
-			pin_fn = vreg->pdata.pin_fn;
-			memcpy(&(vreg->pdata), pdata,
-				sizeof(struct pm8018_regulator_platform_data));
-			vreg->pdata.pin_ctrl = pin_ctrl;
-			vreg->pdata.pin_fn = pin_fn;
-			vreg->dev = &pdev->dev;
-			vreg->name = reg_name;
-		} else {
-			/* Pin control regulator */
-			if ((pdata->pin_ctrl &
-			   (PM8018_VREG_PIN_CTRL_D1 | PM8018_VREG_PIN_CTRL_A0
-			   | PM8018_VREG_PIN_CTRL_A1 | PM8018_VREG_PIN_CTRL_A2))
-			      == PM8018_VREG_PIN_CTRL_NONE) {
-				pr_err("%s: no pin control input specified\n",
-					reg_name);
-				mutex_unlock(&vreg->pc_lock);
-				return -EINVAL;
-			}
-			vreg->pdata.pin_ctrl = pdata->pin_ctrl;
-			vreg->pdata.pin_fn = pdata->pin_fn;
-			vreg->dev_pc = &pdev->dev;
-			if (!vreg->dev)
-				vreg->dev = &pdev->dev;
-			if (!vreg->name)
-				vreg->name = reg_name;
-		}
-
-		/* Initialize register values. */
-		switch (vreg->type) {
-		case REGULATOR_TYPE_PLDO:
-		case REGULATOR_TYPE_NLDO:
-			rc = pm8018_init_ldo(vreg, IS_REAL_REGULATOR(pdev->id));
-			break;
-		case REGULATOR_TYPE_NLDO1200:
-			rc = pm8018_init_nldo1200(vreg);
-			break;
-		case REGULATOR_TYPE_SMPS:
-			rc = pm8018_init_smps(vreg,
-					      IS_REAL_REGULATOR(pdev->id));
-			break;
-		case REGULATOR_TYPE_VS:
-			rc = pm8018_init_vs(vreg, IS_REAL_REGULATOR(pdev->id));
-			break;
-		}
-
-		mutex_unlock(&vreg->pc_lock);
-
-		if (rc)
-			goto bail;
-
-		if (IS_REAL_REGULATOR(pdev->id)) {
-			vreg->rdev = regulator_register(rdesc, &pdev->dev,
-					&(pdata->init_data), vreg);
-			if (IS_ERR(vreg->rdev)) {
-				rc = PTR_ERR(vreg->rdev);
-				vreg->rdev = NULL;
-				pr_err("regulator_register failed: %s, rc=%d\n",
-					reg_name, rc);
-			}
-		} else {
-			vreg->rdev_pc = regulator_register(rdesc, &pdev->dev,
-					&(pdata->init_data), vreg);
-			if (IS_ERR(vreg->rdev_pc)) {
-				rc = PTR_ERR(vreg->rdev_pc);
-				vreg->rdev_pc = NULL;
-				pr_err("regulator_register failed: %s, rc=%d\n",
-					reg_name, rc);
-			}
-		}
-		if ((pm8018_vreg_debug_mask & PM8018_VREG_DEBUG_INIT) && !rc
-		    && vreg->rdev)
-			pm8018_vreg_show_state(vreg->rdev,
-						PM8018_REGULATOR_ACTION_INIT);
-	} else {
-		rc = -ENODEV;
-	}
-
-bail:
-	if (rc)
-		pr_err("error for %s, rc=%d\n", reg_name, rc);
-
-	return rc;
-}
-
-static int __devexit pm8018_vreg_remove(struct platform_device *pdev)
-{
-	if (IS_REAL_REGULATOR(pdev->id))
-		regulator_unregister(pm8018_vreg[pdev->id].rdev);
-	else
-		regulator_unregister(
-			pm8018_vreg[pc_id_to_real_id(pdev->id)].rdev_pc);
-
-	return 0;
-}
-
-static struct platform_driver pm8018_vreg_driver = {
-	.probe	= pm8018_vreg_probe,
-	.remove	= __devexit_p(pm8018_vreg_remove),
-	.driver	= {
-		.name	= PM8018_REGULATOR_DEV_NAME,
-		.owner	= THIS_MODULE,
-	},
-};
-
-static int __init pm8018_vreg_init(void)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(pm8018_vreg); i++) {
-		mutex_init(&pm8018_vreg[i].pc_lock);
-		pm8018_vreg[i].write_count = 0;
-		pm8018_vreg[i].prev_write_count = -1;
-	}
-
-	return platform_driver_register(&pm8018_vreg_driver);
-}
-postcore_initcall(pm8018_vreg_init);
-
-static void __exit pm8018_vreg_exit(void)
-{
-	int i;
-
-	platform_driver_unregister(&pm8018_vreg_driver);
-
-	for (i = 0; i < ARRAY_SIZE(pm8018_vreg); i++)
-		mutex_destroy(&pm8018_vreg[i].pc_lock);
-}
-module_exit(pm8018_vreg_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("PMIC8018 regulator driver");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:" PM8018_REGULATOR_DEV_NAME);
diff --git a/drivers/regulator/pm8921-regulator.c b/drivers/regulator/pm8921-regulator.c
deleted file mode 100644
index 69a1318..0000000
--- a/drivers/regulator/pm8921-regulator.c
+++ /dev/null
@@ -1,3303 +0,0 @@
-/*
- * Copyright (c) 2011, Code Aurora Forum. 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 version 2 and
- * only 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.
- */
-
-#define pr_fmt(fmt) "%s: " fmt, __func__
-
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/mutex.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <linux/platform_device.h>
-#include <linux/regulator/driver.h>
-#include <linux/regulator/machine.h>
-#include <linux/regulator/pm8921-regulator.h>
-#include <linux/mfd/pm8xxx/core.h>
-
-/* Debug Flag Definitions */
-enum {
-	PM8921_VREG_DEBUG_REQUEST	= BIT(0),
-	PM8921_VREG_DEBUG_DUPLICATE	= BIT(1),
-	PM8921_VREG_DEBUG_INIT		= BIT(2),
-	PM8921_VREG_DEBUG_WRITES	= BIT(3), /* SSBI writes */
-};
-
-static int pm8921_vreg_debug_mask;
-module_param_named(
-	debug_mask, pm8921_vreg_debug_mask, int, S_IRUSR | S_IWUSR
-);
-
-#define REGULATOR_TYPE_PLDO		0
-#define REGULATOR_TYPE_NLDO		1
-#define REGULATOR_TYPE_NLDO1200		2
-#define REGULATOR_TYPE_SMPS		3
-#define REGULATOR_TYPE_FTSMPS		4
-#define REGULATOR_TYPE_VS		5
-#define REGULATOR_TYPE_VS300		6
-#define REGULATOR_TYPE_NCP		7
-
-/* Common Masks */
-#define REGULATOR_ENABLE_MASK		0x80
-#define REGULATOR_ENABLE		0x80
-#define REGULATOR_DISABLE		0x00
-
-#define REGULATOR_BANK_MASK		0xF0
-#define REGULATOR_BANK_SEL(n)		((n) << 4)
-#define REGULATOR_BANK_WRITE		0x80
-
-#define LDO_TEST_BANKS			7
-#define NLDO1200_TEST_BANKS		5
-#define SMPS_TEST_BANKS			8
-#define REGULATOR_TEST_BANKS_MAX	SMPS_TEST_BANKS
-
-/*
- * This voltage in uV is returned by get_voltage functions when there is no way
- * to determine the current voltage level.  It is needed because the regulator
- * framework treats a 0 uV voltage as an error.
- */
-#define VOLTAGE_UNKNOWN			1
-
-/* LDO masks and values */
-
-/* CTRL register */
-#define LDO_ENABLE_MASK			0x80
-#define LDO_DISABLE			0x00
-#define LDO_ENABLE			0x80
-#define LDO_PULL_DOWN_ENABLE_MASK	0x40
-#define LDO_PULL_DOWN_ENABLE		0x40
-
-#define LDO_CTRL_PM_MASK		0x20
-#define LDO_CTRL_PM_HPM			0x00
-#define LDO_CTRL_PM_LPM			0x20
-
-#define LDO_CTRL_VPROG_MASK		0x1F
-
-/* TEST register bank 0 */
-#define LDO_TEST_LPM_MASK		0x04
-#define LDO_TEST_LPM_SEL_CTRL		0x00
-#define LDO_TEST_LPM_SEL_TCXO		0x04
-
-/* TEST register bank 2 */
-#define LDO_TEST_VPROG_UPDATE_MASK	0x08
-#define LDO_TEST_RANGE_SEL_MASK		0x04
-#define LDO_TEST_FINE_STEP_MASK		0x02
-#define LDO_TEST_FINE_STEP_SHIFT	1
-
-/* TEST register bank 4 */
-#define LDO_TEST_RANGE_EXT_MASK		0x01
-
-/* TEST register bank 5 */
-#define LDO_TEST_PIN_CTRL_MASK		0x0F
-#define LDO_TEST_PIN_CTRL_EN3		0x08
-#define LDO_TEST_PIN_CTRL_EN2		0x04
-#define LDO_TEST_PIN_CTRL_EN1		0x02
-#define LDO_TEST_PIN_CTRL_EN0		0x01
-
-/* TEST register bank 6 */
-#define LDO_TEST_PIN_CTRL_LPM_MASK	0x0F
-
-
-/*
- * If a given voltage could be output by two ranges, then the preferred one must
- * be determined by the range limits.  Specified voltage ranges should must
- * not overlap.
- *
- * Allowable voltage ranges:
- */
-#define PLDO_LOW_UV_MIN			750000
-#define PLDO_LOW_UV_MAX			1487500
-#define PLDO_LOW_UV_FINE_STEP		12500
-
-#define PLDO_NORM_UV_MIN		1500000
-#define PLDO_NORM_UV_MAX		3075000
-#define PLDO_NORM_UV_FINE_STEP		25000
-
-#define PLDO_HIGH_UV_MIN		1750000
-#define PLDO_HIGH_UV_SET_POINT_MIN	3100000
-#define PLDO_HIGH_UV_MAX		4900000
-#define PLDO_HIGH_UV_FINE_STEP		50000
-
-#define PLDO_LOW_SET_POINTS		((PLDO_LOW_UV_MAX - PLDO_LOW_UV_MIN) \
-						/ PLDO_LOW_UV_FINE_STEP + 1)
-#define PLDO_NORM_SET_POINTS		((PLDO_NORM_UV_MAX - PLDO_NORM_UV_MIN) \
-						/ PLDO_NORM_UV_FINE_STEP + 1)
-#define PLDO_HIGH_SET_POINTS		((PLDO_HIGH_UV_MAX \
-						- PLDO_HIGH_UV_SET_POINT_MIN) \
-					/ PLDO_HIGH_UV_FINE_STEP + 1)
-#define PLDO_SET_POINTS			(PLDO_LOW_SET_POINTS \
-						+ PLDO_NORM_SET_POINTS \
-						+ PLDO_HIGH_SET_POINTS)
-
-#define NLDO_UV_MIN			750000
-#define NLDO_UV_MAX			1537500
-#define NLDO_UV_FINE_STEP		12500
-
-#define NLDO_SET_POINTS			((NLDO_UV_MAX - NLDO_UV_MIN) \
-						/ NLDO_UV_FINE_STEP + 1)
-
-/* NLDO1200 masks and values */
-
-/* CTRL register */
-#define NLDO1200_ENABLE_MASK		0x80
-#define NLDO1200_DISABLE		0x00
-#define NLDO1200_ENABLE			0x80
-
-/* Legacy mode */
-#define NLDO1200_LEGACY_PM_MASK		0x20
-#define NLDO1200_LEGACY_PM_HPM		0x00
-#define NLDO1200_LEGACY_PM_LPM		0x20
-
-/* Advanced mode */
-#define NLDO1200_CTRL_RANGE_MASK	0x40
-#define NLDO1200_CTRL_RANGE_HIGH	0x00
-#define NLDO1200_CTRL_RANGE_LOW		0x40
-#define NLDO1200_CTRL_VPROG_MASK	0x3F
-
-#define NLDO1200_LOW_UV_MIN		375000
-#define NLDO1200_LOW_UV_MAX		743750
-#define NLDO1200_LOW_UV_STEP		6250
-
-#define NLDO1200_HIGH_UV_MIN		750000
-#define NLDO1200_HIGH_UV_MAX		1537500
-#define NLDO1200_HIGH_UV_STEP		12500
-
-#define NLDO1200_LOW_SET_POINTS		((NLDO1200_LOW_UV_MAX \
-						- NLDO1200_LOW_UV_MIN) \
-					/ NLDO1200_LOW_UV_STEP + 1)
-#define NLDO1200_HIGH_SET_POINTS	((NLDO1200_HIGH_UV_MAX \
-						- NLDO1200_HIGH_UV_MIN) \
-					/ NLDO1200_HIGH_UV_STEP + 1)
-#define NLDO1200_SET_POINTS		(NLDO1200_LOW_SET_POINTS \
-						+ NLDO1200_HIGH_SET_POINTS)
-
-/* TEST register bank 0 */
-#define NLDO1200_TEST_LPM_MASK		0x04
-#define NLDO1200_TEST_LPM_SEL_CTRL	0x00
-#define NLDO1200_TEST_LPM_SEL_TCXO	0x04
-
-/* TEST register bank 1 */
-#define NLDO1200_PULL_DOWN_ENABLE_MASK	0x02
-#define NLDO1200_PULL_DOWN_ENABLE	0x02
-
-/* TEST register bank 2 */
-#define NLDO1200_ADVANCED_MODE_MASK	0x08
-#define NLDO1200_ADVANCED_MODE		0x00
-#define NLDO1200_LEGACY_MODE		0x08
-
-/* Advanced mode power mode control */
-#define NLDO1200_ADVANCED_PM_MASK	0x02
-#define NLDO1200_ADVANCED_PM_HPM	0x00
-#define NLDO1200_ADVANCED_PM_LPM	0x02
-
-#define NLDO1200_IN_ADVANCED_MODE(vreg) \
-	((vreg->test_reg[2] & NLDO1200_ADVANCED_MODE_MASK) \
-	 == NLDO1200_ADVANCED_MODE)
-
-/* SMPS masks and values */
-
-/* CTRL register */
-
-/* Legacy mode */
-#define SMPS_LEGACY_ENABLE_MASK		0x80
-#define SMPS_LEGACY_DISABLE		0x00
-#define SMPS_LEGACY_ENABLE		0x80
-#define SMPS_LEGACY_PULL_DOWN_ENABLE	0x40
-#define SMPS_LEGACY_VREF_SEL_MASK	0x20
-#define SMPS_LEGACY_VPROG_MASK		0x1F
-
-/* Advanced mode */
-#define SMPS_ADVANCED_BAND_MASK		0xC0
-#define SMPS_ADVANCED_BAND_OFF		0x00
-#define SMPS_ADVANCED_BAND_1		0x40
-#define SMPS_ADVANCED_BAND_2		0x80
-#define SMPS_ADVANCED_BAND_3		0xC0
-#define SMPS_ADVANCED_VPROG_MASK	0x3F
-
-/* Legacy mode voltage ranges */
-#define SMPS_MODE3_UV_MIN		375000
-#define SMPS_MODE3_UV_MAX		725000
-#define SMPS_MODE3_UV_STEP		25000
-
-#define SMPS_MODE2_UV_MIN		750000
-#define SMPS_MODE2_UV_MAX		1475000
-#define SMPS_MODE2_UV_STEP		25000
-
-#define SMPS_MODE1_UV_MIN		1500000
-#define SMPS_MODE1_UV_MAX		3050000
-#define SMPS_MODE1_UV_STEP		50000
-
-#define SMPS_MODE3_SET_POINTS		((SMPS_MODE3_UV_MAX \
-						- SMPS_MODE3_UV_MIN) \
-					/ SMPS_MODE3_UV_STEP + 1)
-#define SMPS_MODE2_SET_POINTS		((SMPS_MODE2_UV_MAX \
-						- SMPS_MODE2_UV_MIN) \
-					/ SMPS_MODE2_UV_STEP + 1)
-#define SMPS_MODE1_SET_POINTS		((SMPS_MODE1_UV_MAX \
-						- SMPS_MODE1_UV_MIN) \
-					/ SMPS_MODE1_UV_STEP + 1)
-#define SMPS_LEGACY_SET_POINTS		(SMPS_MODE3_SET_POINTS \
-						+ SMPS_MODE2_SET_POINTS \
-						+ SMPS_MODE1_SET_POINTS)
-
-/* Advanced mode voltage ranges */
-#define SMPS_BAND1_UV_MIN		375000
-#define SMPS_BAND1_UV_MAX		737500
-#define SMPS_BAND1_UV_STEP		12500
-
-#define SMPS_BAND2_UV_MIN		750000
-#define SMPS_BAND2_UV_MAX		1487500
-#define SMPS_BAND2_UV_STEP		12500
-
-#define SMPS_BAND3_UV_MIN		1500000
-#define SMPS_BAND3_UV_MAX		3075000
-#define SMPS_BAND3_UV_STEP		25000
-
-#define SMPS_BAND1_SET_POINTS		((SMPS_BAND1_UV_MAX \
-						- SMPS_BAND1_UV_MIN) \
-					/ SMPS_BAND1_UV_STEP + 1)
-#define SMPS_BAND2_SET_POINTS		((SMPS_BAND2_UV_MAX \
-						- SMPS_BAND2_UV_MIN) \
-					/ SMPS_BAND2_UV_STEP + 1)
-#define SMPS_BAND3_SET_POINTS		((SMPS_BAND3_UV_MAX \
-						- SMPS_BAND3_UV_MIN) \
-					/ SMPS_BAND3_UV_STEP + 1)
-#define SMPS_ADVANCED_SET_POINTS	(SMPS_BAND1_SET_POINTS \
-						+ SMPS_BAND2_SET_POINTS \
-						+ SMPS_BAND3_SET_POINTS)
-
-/* Test2 register bank 1 */
-#define SMPS_LEGACY_VLOW_SEL_MASK	0x01
-
-/* Test2 register bank 6 */
-#define SMPS_ADVANCED_PULL_DOWN_ENABLE	0x08
-
-/* Test2 register bank 7 */
-#define SMPS_ADVANCED_MODE_MASK		0x02
-#define SMPS_ADVANCED_MODE		0x02
-#define SMPS_LEGACY_MODE		0x00
-
-#define SMPS_IN_ADVANCED_MODE(vreg) \
-	((vreg->test_reg[7] & SMPS_ADVANCED_MODE_MASK) == SMPS_ADVANCED_MODE)
-
-/* BUCK_SLEEP_CNTRL register */
-#define SMPS_PIN_CTRL_MASK		0xF0
-#define SMPS_PIN_CTRL_EN3		0x80
-#define SMPS_PIN_CTRL_EN2		0x40
-#define SMPS_PIN_CTRL_EN1		0x20
-#define SMPS_PIN_CTRL_EN0		0x10
-
-#define SMPS_PIN_CTRL_LPM_MASK		0x0F
-#define SMPS_PIN_CTRL_LPM_EN3		0x08
-#define SMPS_PIN_CTRL_LPM_EN2		0x04
-#define SMPS_PIN_CTRL_LPM_EN1		0x02
-#define SMPS_PIN_CTRL_LPM_EN0		0x01
-
-/* BUCK_CLOCK_CNTRL register */
-#define SMPS_CLK_DIVIDE2		0x40
-
-#define SMPS_CLK_CTRL_MASK		0x30
-#define SMPS_CLK_CTRL_FOLLOW_TCXO	0x00
-#define SMPS_CLK_CTRL_PWM		0x10
-#define SMPS_CLK_CTRL_PFM		0x20
-
-/* FTSMPS masks and values */
-
-/* CTRL register */
-#define FTSMPS_VCTRL_BAND_MASK		0xC0
-#define FTSMPS_VCTRL_BAND_OFF		0x00
-#define FTSMPS_VCTRL_BAND_1		0x40
-#define FTSMPS_VCTRL_BAND_2		0x80
-#define FTSMPS_VCTRL_BAND_3		0xC0
-#define FTSMPS_VCTRL_VPROG_MASK		0x3F
-
-#define FTSMPS_BAND1_UV_MIN		350000
-#define FTSMPS_BAND1_UV_MAX		650000
-/* 3 LSB's of program voltage must be 0 in band 1. */
-/* Logical step size */
-#define FTSMPS_BAND1_UV_LOG_STEP	50000
-/* Physical step size */
-#define FTSMPS_BAND1_UV_PHYS_STEP	6250
-
-#define FTSMPS_BAND2_UV_MIN		700000
-#define FTSMPS_BAND2_UV_MAX		1400000
-#define FTSMPS_BAND2_UV_STEP		12500
-
-#define FTSMPS_BAND3_UV_MIN		1400000
-#define FTSMPS_BAND3_UV_SET_POINT_MIN	1500000
-#define FTSMPS_BAND3_UV_MAX		3300000
-#define FTSMPS_BAND3_UV_STEP		50000
-
-#define FTSMPS_BAND1_SET_POINTS		((FTSMPS_BAND1_UV_MAX \
-						- FTSMPS_BAND1_UV_MIN) \
-					/ FTSMPS_BAND1_UV_LOG_STEP + 1)
-#define FTSMPS_BAND2_SET_POINTS		((FTSMPS_BAND2_UV_MAX \
-						- FTSMPS_BAND2_UV_MIN) \
-					/ FTSMPS_BAND2_UV_STEP + 1)
-#define FTSMPS_BAND3_SET_POINTS		((FTSMPS_BAND3_UV_MAX \
-					  - FTSMPS_BAND3_UV_SET_POINT_MIN) \
-					/ FTSMPS_BAND3_UV_STEP + 1)
-#define FTSMPS_SET_POINTS		(FTSMPS_BAND1_SET_POINTS \
-						+ FTSMPS_BAND2_SET_POINTS \
-						+ FTSMPS_BAND3_SET_POINTS)
-
-/* FTS_CNFG1 register bank 0 */
-#define FTSMPS_CNFG1_PM_MASK		0x0C
-#define FTSMPS_CNFG1_PM_PWM		0x00
-#define FTSMPS_CNFG1_PM_PFM		0x08
-
-/* PWR_CNFG register */
-#define FTSMPS_PULL_DOWN_ENABLE_MASK	0x40
-#define FTSMPS_PULL_DOWN_ENABLE		0x40
-
-/* VS masks and values */
-
-/* CTRL register */
-#define VS_ENABLE_MASK			0x80
-#define VS_DISABLE			0x00
-#define VS_ENABLE			0x80
-#define VS_PULL_DOWN_ENABLE_MASK	0x40
-#define VS_PULL_DOWN_DISABLE		0x40
-#define VS_PULL_DOWN_ENABLE		0x00
-
-#define VS_PIN_CTRL_MASK		0x0F
-#define VS_PIN_CTRL_EN0			0x08
-#define VS_PIN_CTRL_EN1			0x04
-#define VS_PIN_CTRL_EN2			0x02
-#define VS_PIN_CTRL_EN3			0x01
-
-/* VS300 masks and values */
-
-/* CTRL register */
-#define VS300_CTRL_ENABLE_MASK		0xC0
-#define VS300_CTRL_DISABLE		0x00
-#define VS300_CTRL_ENABLE		0x40
-
-#define VS300_PULL_DOWN_ENABLE_MASK	0x20
-#define VS300_PULL_DOWN_ENABLE		0x20
-
-/* NCP masks and values */
-
-/* CTRL register */
-#define NCP_ENABLE_MASK			0x80
-#define NCP_DISABLE			0x00
-#define NCP_ENABLE			0x80
-#define NCP_VPROG_MASK			0x1F
-
-#define NCP_UV_MIN			1500000
-#define NCP_UV_MAX			3050000
-#define NCP_UV_STEP			50000
-
-#define NCP_SET_POINTS			((NCP_UV_MAX - NCP_UV_MIN) \
-						/ NCP_UV_STEP + 1)
-
-#define IS_REAL_REGULATOR(id)		((id) >= 0 && \
-					 (id) < PM8921_VREG_ID_L1_PC)
-
-struct pm8921_vreg {
-	/* Configuration data */
-	struct regulator_dev			*rdev;
-	struct regulator_dev			*rdev_pc;
-	struct device				*dev;
-	struct device				*dev_pc;
-	const char				*name;
-	struct pm8921_regulator_platform_data	pdata;
-	const int				hpm_min_load;
-	const u16				ctrl_addr;
-	const u16				test_addr;
-	const u16				clk_ctrl_addr;
-	const u16				sleep_ctrl_addr;
-	const u16				pfm_ctrl_addr;
-	const u16				pwr_cnfg_addr;
-	const u8				type;
-	/* State data */
-	struct mutex				pc_lock;
-	int					save_uV;
-	int					mode;
-	u32					write_count;
-	u32					prev_write_count;
-	bool					is_enabled;
-	bool					is_enabled_pc;
-	u8				test_reg[REGULATOR_TEST_BANKS_MAX];
-	u8					ctrl_reg;
-	u8					clk_ctrl_reg;
-	u8					sleep_ctrl_reg;
-	u8					pfm_ctrl_reg;
-	u8					pwr_cnfg_reg;
-};
-
-#define vreg_err(vreg, fmt, ...) \
-	pr_err("%s: " fmt, vreg->name, ##__VA_ARGS__)
-
-#define PLDO(_id, _ctrl_addr, _test_addr, _hpm_min_load) \
-	[PM8921_VREG_ID_##_id] = { \
-		.type		= REGULATOR_TYPE_PLDO, \
-		.ctrl_addr	= _ctrl_addr, \
-		.test_addr	= _test_addr, \
-		.hpm_min_load	= PM8921_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
-	}
-
-#define NLDO(_id, _ctrl_addr, _test_addr, _hpm_min_load) \
-	[PM8921_VREG_ID_##_id] = { \
-		.type		= REGULATOR_TYPE_NLDO, \
-		.ctrl_addr	= _ctrl_addr, \
-		.test_addr	= _test_addr, \
-		.hpm_min_load	= PM8921_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
-	}
-
-#define NLDO1200(_id, _ctrl_addr, _test_addr, _hpm_min_load) \
-	[PM8921_VREG_ID_##_id] = { \
-		.type		= REGULATOR_TYPE_NLDO1200, \
-		.ctrl_addr	= _ctrl_addr, \
-		.test_addr	= _test_addr, \
-		.hpm_min_load	= PM8921_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
-	}
-
-#define SMPS(_id, _ctrl_addr, _test_addr, _clk_ctrl_addr, _sleep_ctrl_addr, \
-	     _hpm_min_load) \
-	[PM8921_VREG_ID_##_id] = { \
-		.type		= REGULATOR_TYPE_SMPS, \
-		.ctrl_addr	= _ctrl_addr, \
-		.test_addr	= _test_addr, \
-		.clk_ctrl_addr	= _clk_ctrl_addr, \
-		.sleep_ctrl_addr = _sleep_ctrl_addr, \
-		.hpm_min_load	= PM8921_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
-	}
-
-#define FTSMPS(_id, _pwm_ctrl_addr, _fts_cnfg1_addr, _pfm_ctrl_addr, \
-	       _pwr_cnfg_addr, _hpm_min_load) \
-	[PM8921_VREG_ID_##_id] = { \
-		.type		= REGULATOR_TYPE_FTSMPS, \
-		.ctrl_addr	= _pwm_ctrl_addr, \
-		.test_addr	= _fts_cnfg1_addr, \
-		.pfm_ctrl_addr = _pfm_ctrl_addr, \
-		.pwr_cnfg_addr = _pwr_cnfg_addr, \
-		.hpm_min_load	= PM8921_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
-	}
-
-#define VS(_id, _ctrl_addr) \
-	[PM8921_VREG_ID_##_id] = { \
-		.type		= REGULATOR_TYPE_VS, \
-		.ctrl_addr	= _ctrl_addr, \
-	}
-
-#define VS300(_id, _ctrl_addr) \
-	[PM8921_VREG_ID_##_id] = { \
-		.type		= REGULATOR_TYPE_VS300, \
-		.ctrl_addr	= _ctrl_addr, \
-	}
-
-#define NCP(_id, _ctrl_addr) \
-	[PM8921_VREG_ID_##_id] = { \
-		.type		= REGULATOR_TYPE_NCP, \
-		.ctrl_addr	= _ctrl_addr, \
-	}
-
-static struct pm8921_vreg pm8921_vreg[] = {
-	/*  id   ctrl   test   hpm_min */
-	NLDO(L1,  0x0AE, 0x0AF, LDO_150),
-	NLDO(L2,  0x0B0, 0x0B1, LDO_150),
-	PLDO(L3,  0x0B2, 0x0B3, LDO_150),
-	PLDO(L4,  0x0B4, 0x0B5, LDO_50),
-	PLDO(L5,  0x0B6, 0x0B7, LDO_300),
-	PLDO(L6,  0x0B8, 0x0B9, LDO_600),
-	PLDO(L7,  0x0BA, 0x0BB, LDO_150),
-	PLDO(L8,  0x0BC, 0x0BD, LDO_300),
-	PLDO(L9,  0x0BE, 0x0BF, LDO_300),
-	PLDO(L10, 0x0C0, 0x0C1, LDO_600),
-	PLDO(L11, 0x0C2, 0x0C3, LDO_150),
-	NLDO(L12, 0x0C4, 0x0C5, LDO_150),
-	PLDO(L14, 0x0C8, 0x0C9, LDO_50),
-	PLDO(L15, 0x0CA, 0x0CB, LDO_150),
-	PLDO(L16, 0x0CC, 0x0CD, LDO_300),
-	PLDO(L17, 0x0CE, 0x0CF, LDO_150),
-	NLDO(L18, 0x0D0, 0x0D1, LDO_150),
-	PLDO(L21, 0x0D6, 0x0D7, LDO_150),
-	PLDO(L22, 0x0D8, 0x0D9, LDO_150),
-	PLDO(L23, 0x0DA, 0x0DB, LDO_150),
-
-	/*       id   ctrl   test   hpm_min */
-	NLDO1200(L24, 0x0DC, 0x0DD, LDO_1200),
-	NLDO1200(L25, 0x0DE, 0x0DF, LDO_1200),
-	NLDO1200(L26, 0x0E0, 0x0E1, LDO_1200),
-	NLDO1200(L27, 0x0E2, 0x0E3, LDO_1200),
-	NLDO1200(L28, 0x0E4, 0x0E5, LDO_1200),
-
-	/*  id   ctrl   test   hpm_min */
-	PLDO(L29, 0x0E6, 0x0E7, LDO_150),
-
-	/*   id  ctrl   test2  clk    sleep  hpm_min */
-	SMPS(S1, 0x1D0, 0x1D5, 0x009, 0x1D2, SMPS_1500),
-	SMPS(S2, 0x1D8, 0x1DD, 0x00A, 0x1DA, SMPS_1500),
-	SMPS(S3, 0x1E0, 0x1E5, 0x00B, 0x1E2, SMPS_1500),
-	SMPS(S4, 0x1E8, 0x1ED, 0x011, 0x1EA, SMPS_1500),
-
-	/*     id  ctrl fts_cnfg1 pfm  pwr_cnfg  hpm_min */
-	FTSMPS(S5, 0x025, 0x02E, 0x026, 0x032, SMPS_2000),
-	FTSMPS(S6, 0x036, 0x03F, 0x037, 0x043, SMPS_2000),
-
-	/*   id  ctrl   test2  clk    sleep  hpm_min */
-	SMPS(S7, 0x1F0, 0x1F5, 0x012, 0x1F2, SMPS_1500),
-	SMPS(S8, 0x1F8, 0x1FD, 0x013, 0x1FA, SMPS_1500),
-
-	/* id		ctrl */
-	VS(LVS1,	0x060),
-	VS300(LVS2,     0x062),
-	VS(LVS3,	0x064),
-	VS(LVS4,	0x066),
-	VS(LVS5,	0x068),
-	VS(LVS6,	0x06A),
-	VS(LVS7,	0x06C),
-	VS300(USB_OTG,  0x06E),
-	VS300(HDMI_MVS, 0x070),
-
-	/*  id   ctrl */
-	NCP(NCP, 0x090),
-};
-
-/* Determines which label to add to the print. */
-enum pm8921_regulator_action {
-	PM8921_REGULATOR_ACTION_INIT,
-	PM8921_REGULATOR_ACTION_ENABLE,
-	PM8921_REGULATOR_ACTION_DISABLE,
-	PM8921_REGULATOR_ACTION_VOLTAGE,
-	PM8921_REGULATOR_ACTION_MODE,
-	PM8921_REGULATOR_ACTION_PIN_CTRL,
-};
-
-/* Debug state printing */
-static void pm8921_vreg_show_state(struct regulator_dev *rdev,
-				   enum pm8921_regulator_action action);
-
-/*
- * Perform a masked write to a PMIC register only if the new value differs
- * from the last value written to the register.  This removes redundant
- * register writing.
- *
- * No locking is required because registers are not shared between regulators.
- */
-static int pm8921_vreg_masked_write(struct pm8921_vreg *vreg, u16 addr, u8 val,
-		u8 mask, u8 *reg_save)
-{
-	int rc = 0;
-	u8 reg;
-
-	reg = (*reg_save & ~mask) | (val & mask);
-	if (reg != *reg_save) {
-		rc = pm8xxx_writeb(vreg->dev->parent, addr, reg);
-
-		if (rc) {
-			pr_err("%s: pm8xxx_writeb failed; addr=0x%03X, rc=%d\n",
-				vreg->name, addr, rc);
-		} else {
-			*reg_save = reg;
-			vreg->write_count++;
-			if (pm8921_vreg_debug_mask & PM8921_VREG_DEBUG_WRITES)
-				pr_info("%s: write(0x%03X)=0x%02X", vreg->name,
-					addr, reg);
-		}
-	}
-
-	return rc;
-}
-
-/*
- * Perform a masked write to a PMIC register without checking the previously
- * written value.  This is needed for registers that must be rewritten even if
- * the value hasn't changed in order for changes in other registers to take
- * effect.
- */
-static int pm8921_vreg_masked_write_forced(struct pm8921_vreg *vreg, u16 addr,
-		u8 val, u8 mask, u8 *reg_save)
-{
-	int rc = 0;
-	u8 reg;
-
-	reg = (*reg_save & ~mask) | (val & mask);
-	rc = pm8xxx_writeb(vreg->dev->parent, addr, reg);
-
-	if (rc) {
-		pr_err("%s: pm8xxx_writeb failed; addr=0x%03X, rc=%d\n",
-			vreg->name, addr, rc);
-	} else {
-		*reg_save = reg;
-		vreg->write_count++;
-		if (pm8921_vreg_debug_mask & PM8921_VREG_DEBUG_WRITES)
-			pr_info("%s: write(0x%03X)=0x%02X", vreg->name,
-				addr, reg);
-	}
-
-	return rc;
-}
-
-static int pm8921_vreg_is_pin_controlled(struct pm8921_vreg *vreg)
-{
-	int ret = 0;
-
-	switch (vreg->type) {
-	case REGULATOR_TYPE_PLDO:
-	case REGULATOR_TYPE_NLDO:
-		ret = ((vreg->test_reg[5] & LDO_TEST_PIN_CTRL_MASK) << 4)
-			| (vreg->test_reg[6] & LDO_TEST_PIN_CTRL_LPM_MASK);
-		break;
-	case REGULATOR_TYPE_SMPS:
-		ret = vreg->sleep_ctrl_reg
-			& (SMPS_PIN_CTRL_MASK | SMPS_PIN_CTRL_LPM_MASK);
-		break;
-	case REGULATOR_TYPE_VS:
-		ret = vreg->ctrl_reg & VS_PIN_CTRL_MASK;
-		break;
-	}
-
-	return ret;
-}
-
-/*
- * Returns the logical pin control enable state because the pin control options
- * present in the hardware out of restart could be different from those desired
- * by the consumer.
- */
-static int pm8921_vreg_pin_control_is_enabled(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int enabled;
-
-	mutex_lock(&vreg->pc_lock);
-	enabled = vreg->is_enabled_pc;
-	mutex_unlock(&vreg->pc_lock);
-
-	return enabled;
-}
-
-/* Returns the physical enable state of the regulator. */
-static int _pm8921_vreg_is_enabled(struct pm8921_vreg *vreg)
-{
-	int rc = 0;
-
-	/*
-	 * All regulator types except advanced mode SMPS, FTSMPS, and VS300 have
-	 * enable bit in bit 7 of the control register.
-	 */
-	switch (vreg->type) {
-	case REGULATOR_TYPE_FTSMPS:
-		if ((vreg->ctrl_reg & FTSMPS_VCTRL_BAND_MASK)
-		    != FTSMPS_VCTRL_BAND_OFF)
-			rc = 1;
-		break;
-	case REGULATOR_TYPE_VS300:
-		if ((vreg->ctrl_reg & VS300_CTRL_ENABLE_MASK)
-		    != VS300_CTRL_DISABLE)
-			rc = 1;
-		break;
-	case REGULATOR_TYPE_SMPS:
-		if (SMPS_IN_ADVANCED_MODE(vreg)) {
-			if ((vreg->ctrl_reg & SMPS_ADVANCED_BAND_MASK)
-			    != SMPS_ADVANCED_BAND_OFF)
-				rc = 1;
-			break;
-		}
-		/* Fall through for legacy mode SMPS. */
-	default:
-		if ((vreg->ctrl_reg & REGULATOR_ENABLE_MASK)
-		    == REGULATOR_ENABLE)
-			rc = 1;
-	}
-
-	return rc;
-}
-
-/*
- * Returns the logical enable state of the regulator which may be different from
- * the physical enable state thanks to HPM/LPM pin control.
- */
-static int pm8921_vreg_is_enabled(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int enabled;
-
-	if (vreg->type == REGULATOR_TYPE_PLDO
-	    || vreg->type == REGULATOR_TYPE_NLDO
-	    || vreg->type == REGULATOR_TYPE_SMPS
-	    || vreg->type == REGULATOR_TYPE_VS) {
-		/* Pin controllable */
-		mutex_lock(&vreg->pc_lock);
-		enabled = vreg->is_enabled;
-		mutex_unlock(&vreg->pc_lock);
-	} else {
-		/* Not pin controlable */
-		enabled = _pm8921_vreg_is_enabled(vreg);
-	}
-
-	return enabled;
-}
-
-static int pm8921_pldo_get_voltage(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int vmin, fine_step;
-	u8 range_ext, range_sel, vprog, fine_step_reg;
-
-	mutex_lock(&vreg->pc_lock);
-
-	fine_step_reg = vreg->test_reg[2] & LDO_TEST_FINE_STEP_MASK;
-	range_sel = vreg->test_reg[2] & LDO_TEST_RANGE_SEL_MASK;
-	range_ext = vreg->test_reg[4] & LDO_TEST_RANGE_EXT_MASK;
-	vprog = vreg->ctrl_reg & LDO_CTRL_VPROG_MASK;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	vprog = (vprog << 1) | (fine_step_reg >> LDO_TEST_FINE_STEP_SHIFT);
-
-	if (range_sel) {
-		/* low range mode */
-		fine_step = PLDO_LOW_UV_FINE_STEP;
-		vmin = PLDO_LOW_UV_MIN;
-	} else if (!range_ext) {
-		/* normal mode */
-		fine_step = PLDO_NORM_UV_FINE_STEP;
-		vmin = PLDO_NORM_UV_MIN;
-	} else {
-		/* high range mode */
-		fine_step = PLDO_HIGH_UV_FINE_STEP;
-		vmin = PLDO_HIGH_UV_MIN;
-	}
-
-	return fine_step * vprog + vmin;
-}
-
-static int pm8921_pldo_list_voltage(struct regulator_dev *rdev,
-				    unsigned selector)
-{
-	int uV;
-
-	if (selector >= PLDO_SET_POINTS)
-		return 0;
-
-	if (selector < PLDO_LOW_SET_POINTS)
-		uV = selector * PLDO_LOW_UV_FINE_STEP + PLDO_LOW_UV_MIN;
-	else if (selector < (PLDO_LOW_SET_POINTS + PLDO_NORM_SET_POINTS))
-		uV = (selector - PLDO_LOW_SET_POINTS) * PLDO_NORM_UV_FINE_STEP
-			+ PLDO_NORM_UV_MIN;
-	else
-		uV = (selector - PLDO_LOW_SET_POINTS - PLDO_NORM_SET_POINTS)
-				* PLDO_HIGH_UV_FINE_STEP
-			+ PLDO_HIGH_UV_SET_POINT_MIN;
-
-	return uV;
-}
-
-static int pm8921_pldo_set_voltage(struct regulator_dev *rdev, int min_uV,
-				   int max_uV, unsigned *selector)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc = 0, uV = min_uV;
-	int vmin;
-	unsigned vprog, fine_step;
-	u8 range_ext, range_sel, fine_step_reg, prev_reg;
-	bool reg_changed = false;
-
-	if (uV < PLDO_LOW_UV_MIN && max_uV >= PLDO_LOW_UV_MIN)
-		uV = PLDO_LOW_UV_MIN;
-
-	if (uV < PLDO_LOW_UV_MIN || uV > PLDO_HIGH_UV_MAX) {
-		vreg_err(vreg,
-			"request v=[%d, %d] is outside possible v=[%d, %d]\n",
-			 min_uV, max_uV, PLDO_LOW_UV_MIN, PLDO_HIGH_UV_MAX);
-		return -EINVAL;
-	}
-
-	/*
-	 * This is a temporary hack to boost LDO 4 voltage from 1.8 V to 2.0 V
-	 * for old PMIC revisions which have register read back issues when
-	 * LDO 4 is set to 1.8 V.
-	 */
-	if (vreg->pdata.id == PM8921_VREG_ID_L4
-		&& pm8xxx_get_revision(vreg->dev->parent)
-			<= PM8XXX_REVISION_8921_1p1) {
-		uV = 2000000;
-		max_uV = 2000000;
-	}
-
-	if (uV > PLDO_NORM_UV_MAX) {
-		vmin = PLDO_HIGH_UV_MIN;
-		fine_step = PLDO_HIGH_UV_FINE_STEP;
-		range_ext = LDO_TEST_RANGE_EXT_MASK;
-		range_sel = 0;
-	} else if (uV > PLDO_LOW_UV_MAX) {
-		vmin = PLDO_NORM_UV_MIN;
-		fine_step = PLDO_NORM_UV_FINE_STEP;
-		range_ext = 0;
-		range_sel = 0;
-	} else {
-		vmin = PLDO_LOW_UV_MIN;
-		fine_step = PLDO_LOW_UV_FINE_STEP;
-		range_ext = 0;
-		range_sel = LDO_TEST_RANGE_SEL_MASK;
-	}
-
-	vprog = (uV - vmin + fine_step - 1) / fine_step;
-	uV = vprog * fine_step + vmin;
-	fine_step_reg = (vprog & 1) << LDO_TEST_FINE_STEP_SHIFT;
-	vprog >>= 1;
-
-	if (uV > max_uV) {
-		vreg_err(vreg,
-			"request v=[%d, %d] cannot be met by any set point\n",
-			min_uV, max_uV);
-		return -EINVAL;
-	}
-
-	mutex_lock(&vreg->pc_lock);
-
-	/* Write fine step, range select and program voltage update. */
-	prev_reg = vreg->test_reg[2];
-	rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
-			fine_step_reg | range_sel | REGULATOR_BANK_SEL(2)
-			 | REGULATOR_BANK_WRITE | LDO_TEST_VPROG_UPDATE_MASK,
-			LDO_TEST_FINE_STEP_MASK | LDO_TEST_RANGE_SEL_MASK
-			 | REGULATOR_BANK_MASK | LDO_TEST_VPROG_UPDATE_MASK,
-			&vreg->test_reg[2]);
-	if (rc)
-		goto bail;
-	if (prev_reg != vreg->test_reg[2])
-		reg_changed = true;
-
-	/* Write range extension. */
-	prev_reg = vreg->test_reg[4];
-	rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
-			range_ext | REGULATOR_BANK_SEL(4)
-			 | REGULATOR_BANK_WRITE,
-			LDO_TEST_RANGE_EXT_MASK | REGULATOR_BANK_MASK,
-			&vreg->test_reg[4]);
-	if (rc)
-		goto bail;
-	if (prev_reg != vreg->test_reg[4])
-		reg_changed = true;
-
-	/* Write new voltage. */
-	if (reg_changed) {
-		/*
-		 * Force a CTRL register write even if the value hasn't changed.
-		 * This is neccessary because range select, range extension, and
-		 * fine step will not update until a value is written into the
-		 * control register.
-		 */
-		rc = pm8921_vreg_masked_write_forced(vreg, vreg->ctrl_addr,
-			vprog, LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
-	} else {
-		/* Only write to control register if new value is different. */
-		rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, vprog,
-			LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
-	}
-bail:
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_VOLTAGE);
-
-	return rc;
-}
-
-static int pm8921_nldo_get_voltage(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	u8 vprog, fine_step_reg;
-
-	mutex_lock(&vreg->pc_lock);
-
-	fine_step_reg = vreg->test_reg[2] & LDO_TEST_FINE_STEP_MASK;
-	vprog = vreg->ctrl_reg & LDO_CTRL_VPROG_MASK;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	vprog = (vprog << 1) | (fine_step_reg >> LDO_TEST_FINE_STEP_SHIFT);
-
-	return NLDO_UV_FINE_STEP * vprog + NLDO_UV_MIN;
-}
-
-static int pm8921_nldo_list_voltage(struct regulator_dev *rdev,
-				    unsigned selector)
-{
-	if (selector >= NLDO_SET_POINTS)
-		return 0;
-
-	return selector * NLDO_UV_FINE_STEP + NLDO_UV_MIN;
-}
-
-static int pm8921_nldo_set_voltage(struct regulator_dev *rdev, int min_uV,
-				   int max_uV, unsigned *selector)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	unsigned vprog, fine_step_reg, prev_reg;
-	int rc;
-	int uV = min_uV;
-
-	if (uV < NLDO_UV_MIN && max_uV >= NLDO_UV_MIN)
-		uV = NLDO_UV_MIN;
-
-	if (uV < NLDO_UV_MIN || uV > NLDO_UV_MAX) {
-		vreg_err(vreg,
-			"request v=[%d, %d] is outside possible v=[%d, %d]\n",
-			 min_uV, max_uV, NLDO_UV_MIN, NLDO_UV_MAX);
-		return -EINVAL;
-	}
-
-	vprog = (uV - NLDO_UV_MIN + NLDO_UV_FINE_STEP - 1) / NLDO_UV_FINE_STEP;
-	uV = vprog * NLDO_UV_FINE_STEP + NLDO_UV_MIN;
-	fine_step_reg = (vprog & 1) << LDO_TEST_FINE_STEP_SHIFT;
-	vprog >>= 1;
-
-	if (uV > max_uV) {
-		vreg_err(vreg,
-			"request v=[%d, %d] cannot be met by any set point\n",
-			min_uV, max_uV);
-		return -EINVAL;
-	}
-
-	mutex_lock(&vreg->pc_lock);
-
-	/* Write fine step. */
-	prev_reg = vreg->test_reg[2];
-	rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
-			fine_step_reg | REGULATOR_BANK_SEL(2)
-			 | REGULATOR_BANK_WRITE | LDO_TEST_VPROG_UPDATE_MASK,
-			LDO_TEST_FINE_STEP_MASK | REGULATOR_BANK_MASK
-			 | LDO_TEST_VPROG_UPDATE_MASK,
-		       &vreg->test_reg[2]);
-	if (rc)
-		goto bail;
-
-	/* Write new voltage. */
-	if (prev_reg != vreg->test_reg[2]) {
-		/*
-		 * Force a CTRL register write even if the value hasn't changed.
-		 * This is neccessary because fine step will not update until a
-		 * value is written into the control register.
-		 */
-		rc = pm8921_vreg_masked_write_forced(vreg, vreg->ctrl_addr,
-			vprog, LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
-	} else {
-		/* Only write to control register if new value is different. */
-		rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, vprog,
-			LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
-	}
-bail:
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_VOLTAGE);
-
-	return rc;
-}
-
-static int _pm8921_nldo1200_get_voltage(struct pm8921_vreg *vreg)
-{
-	int uV = 0;
-	int vprog;
-
-	if (!NLDO1200_IN_ADVANCED_MODE(vreg)) {
-		pr_warn("%s: currently in legacy mode; voltage unknown.\n",
-			vreg->name);
-		return vreg->save_uV;
-	}
-
-	vprog = vreg->ctrl_reg & NLDO1200_CTRL_VPROG_MASK;
-
-	if ((vreg->ctrl_reg & NLDO1200_CTRL_RANGE_MASK)
-	    == NLDO1200_CTRL_RANGE_LOW)
-		uV = vprog * NLDO1200_LOW_UV_STEP + NLDO1200_LOW_UV_MIN;
-	else
-		uV = vprog * NLDO1200_HIGH_UV_STEP + NLDO1200_HIGH_UV_MIN;
-
-	return uV;
-}
-
-static int pm8921_nldo1200_get_voltage(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-
-	return _pm8921_nldo1200_get_voltage(vreg);
-}
-
-static int pm8921_nldo1200_list_voltage(struct regulator_dev *rdev,
-					unsigned selector)
-{
-	int uV;
-
-	if (selector >= NLDO1200_SET_POINTS)
-		return 0;
-
-	if (selector < NLDO1200_LOW_SET_POINTS)
-		uV = selector * NLDO1200_LOW_UV_STEP + NLDO1200_LOW_UV_MIN;
-	else
-		uV = (selector - NLDO1200_LOW_SET_POINTS)
-				* NLDO1200_HIGH_UV_STEP
-			+ NLDO1200_HIGH_UV_MIN;
-
-	return uV;
-}
-
-static int _pm8921_nldo1200_set_voltage(struct pm8921_vreg *vreg, int min_uV,
-		int max_uV)
-{
-	u8 vprog, range;
-	int rc;
-	int uV = min_uV;
-
-	if (uV < NLDO1200_LOW_UV_MIN && max_uV >= NLDO1200_LOW_UV_MIN)
-		uV = NLDO1200_LOW_UV_MIN;
-
-	if (uV < NLDO1200_LOW_UV_MIN || uV > NLDO1200_HIGH_UV_MAX) {
-		vreg_err(vreg,
-			"request v=[%d, %d] is outside possible v=[%d, %d]\n",
-			 min_uV, max_uV, NLDO_UV_MIN, NLDO_UV_MAX);
-		return -EINVAL;
-	}
-
-	if (uV > NLDO1200_LOW_UV_MAX) {
-		vprog = (uV - NLDO1200_HIGH_UV_MIN + NLDO1200_HIGH_UV_STEP - 1)
-			/ NLDO1200_HIGH_UV_STEP;
-		uV = vprog * NLDO1200_HIGH_UV_STEP + NLDO1200_HIGH_UV_MIN;
-		vprog &= NLDO1200_CTRL_VPROG_MASK;
-		range = NLDO1200_CTRL_RANGE_HIGH;
-	} else {
-		vprog = (uV - NLDO1200_LOW_UV_MIN + NLDO1200_LOW_UV_STEP - 1)
-			/ NLDO1200_LOW_UV_STEP;
-		uV = vprog * NLDO1200_LOW_UV_STEP + NLDO1200_LOW_UV_MIN;
-		vprog &= NLDO1200_CTRL_VPROG_MASK;
-		range = NLDO1200_CTRL_RANGE_LOW;
-	}
-
-	if (uV > max_uV) {
-		vreg_err(vreg,
-			"request v=[%d, %d] cannot be met by any set point\n",
-			min_uV, max_uV);
-		return -EINVAL;
-	}
-
-	/* Set to advanced mode */
-	rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
-		NLDO1200_ADVANCED_MODE | REGULATOR_BANK_SEL(2)
-		| REGULATOR_BANK_WRITE, NLDO1200_ADVANCED_MODE_MASK
-		| REGULATOR_BANK_MASK, &vreg->test_reg[2]);
-	if (rc)
-		goto bail;
-
-	/* Set voltage and range selection. */
-	rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, vprog | range,
-			NLDO1200_CTRL_VPROG_MASK | NLDO1200_CTRL_RANGE_MASK,
-			&vreg->ctrl_reg);
-	if (rc)
-		goto bail;
-
-	vreg->save_uV = uV;
-
-bail:
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-
-	return rc;
-}
-
-static int pm8921_nldo1200_set_voltage(struct regulator_dev *rdev, int min_uV,
-				   int max_uV, unsigned *selector)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	rc = _pm8921_nldo1200_set_voltage(vreg, min_uV, max_uV);
-
-	if (!rc)
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_VOLTAGE);
-
-	return rc;
-}
-
-static int pm8921_smps_get_voltage_advanced(struct pm8921_vreg *vreg)
-{
-	u8 vprog, band;
-	int uV = 0;
-
-	vprog = vreg->ctrl_reg & SMPS_ADVANCED_VPROG_MASK;
-	band = vreg->ctrl_reg & SMPS_ADVANCED_BAND_MASK;
-
-	if (band == SMPS_ADVANCED_BAND_1)
-		uV = vprog * SMPS_BAND1_UV_STEP + SMPS_BAND1_UV_MIN;
-	else if (band == SMPS_ADVANCED_BAND_2)
-		uV = vprog * SMPS_BAND2_UV_STEP + SMPS_BAND2_UV_MIN;
-	else if (band == SMPS_ADVANCED_BAND_3)
-		uV = vprog * SMPS_BAND3_UV_STEP + SMPS_BAND3_UV_MIN;
-	else if (vreg->save_uV > 0)
-		uV = vreg->save_uV;
-	else
-		uV = VOLTAGE_UNKNOWN;
-
-	return uV;
-}
-
-static int pm8921_smps_get_voltage_legacy(struct pm8921_vreg *vreg)
-{
-	u8 vlow, vref, vprog;
-	int uV;
-
-	vlow = vreg->test_reg[1] & SMPS_LEGACY_VLOW_SEL_MASK;
-	vref = vreg->ctrl_reg & SMPS_LEGACY_VREF_SEL_MASK;
-	vprog = vreg->ctrl_reg & SMPS_LEGACY_VPROG_MASK;
-
-	if (vlow && vref) {
-		/* mode 3 */
-		uV = vprog * SMPS_MODE3_UV_STEP + SMPS_MODE3_UV_MIN;
-	} else if (vref) {
-		/* mode 2 */
-		uV = vprog * SMPS_MODE2_UV_STEP + SMPS_MODE2_UV_MIN;
-	} else {
-		/* mode 1 */
-		uV = vprog * SMPS_MODE1_UV_STEP + SMPS_MODE1_UV_MIN;
-	}
-
-	return uV;
-}
-
-static int _pm8921_smps_get_voltage(struct pm8921_vreg *vreg)
-{
-	if (SMPS_IN_ADVANCED_MODE(vreg))
-		return pm8921_smps_get_voltage_advanced(vreg);
-
-	return pm8921_smps_get_voltage_legacy(vreg);
-}
-
-static int pm8921_smps_list_voltage(struct regulator_dev *rdev,
-				    unsigned selector)
-{
-	int uV;
-
-	if (selector >= SMPS_ADVANCED_SET_POINTS)
-		return 0;
-
-	if (selector < SMPS_BAND1_SET_POINTS)
-		uV = selector * SMPS_BAND1_UV_STEP + SMPS_BAND1_UV_MIN;
-	else if (selector < (SMPS_BAND1_SET_POINTS + SMPS_BAND2_SET_POINTS))
-		uV = (selector - SMPS_BAND1_SET_POINTS) * SMPS_BAND2_UV_STEP
-			+ SMPS_BAND2_UV_MIN;
-	else
-		uV = (selector - SMPS_BAND1_SET_POINTS - SMPS_BAND2_SET_POINTS)
-				* SMPS_BAND3_UV_STEP
-			+ SMPS_BAND3_UV_MIN;
-
-	return uV;
-}
-
-static int pm8921_smps_get_voltage(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int uV;
-
-	mutex_lock(&vreg->pc_lock);
-	uV = _pm8921_smps_get_voltage(vreg);
-	mutex_unlock(&vreg->pc_lock);
-
-	return uV;
-}
-
-static int pm8921_smps_set_voltage_advanced(struct pm8921_vreg *vreg,
-					   int min_uV, int max_uV, int force_on)
-{
-	u8 vprog, band;
-	int rc;
-	int uV = min_uV;
-
-	if (uV < SMPS_BAND1_UV_MIN && max_uV >= SMPS_BAND1_UV_MIN)
-		uV = SMPS_BAND1_UV_MIN;
-
-	if (uV < SMPS_BAND1_UV_MIN || uV > SMPS_BAND3_UV_MAX) {
-		vreg_err(vreg,
-			"request v=[%d, %d] is outside possible v=[%d, %d]\n",
-			 min_uV, max_uV, SMPS_BAND1_UV_MIN, SMPS_BAND3_UV_MAX);
-		return -EINVAL;
-	}
-
-	if (uV > SMPS_BAND2_UV_MAX) {
-		vprog = (uV - SMPS_BAND3_UV_MIN + SMPS_BAND3_UV_STEP - 1)
-			/ SMPS_BAND3_UV_STEP;
-		band = SMPS_ADVANCED_BAND_3;
-		uV = SMPS_BAND3_UV_MIN + vprog * SMPS_BAND3_UV_STEP;
-	} else if (uV > SMPS_BAND1_UV_MAX) {
-		vprog = (uV - SMPS_BAND2_UV_MIN + SMPS_BAND2_UV_STEP - 1)
-			/ SMPS_BAND2_UV_STEP;
-		band = SMPS_ADVANCED_BAND_2;
-		uV = SMPS_BAND2_UV_MIN + vprog * SMPS_BAND2_UV_STEP;
-	} else {
-		vprog = (uV - SMPS_BAND1_UV_MIN + SMPS_BAND1_UV_STEP - 1)
-			/ SMPS_BAND1_UV_STEP;
-		band = SMPS_ADVANCED_BAND_1;
-		uV = SMPS_BAND1_UV_MIN + vprog * SMPS_BAND1_UV_STEP;
-	}
-
-	if (uV > max_uV) {
-		vreg_err(vreg,
-			"request v=[%d, %d] cannot be met by any set point\n",
-			min_uV, max_uV);
-		return -EINVAL;
-	}
-
-	/* Do not set band if regulator currently disabled. */
-	if (!_pm8921_vreg_is_enabled(vreg) && !force_on)
-		band = SMPS_ADVANCED_BAND_OFF;
-
-	/* Set advanced mode bit to 1. */
-	rc = pm8921_vreg_masked_write(vreg, vreg->test_addr, SMPS_ADVANCED_MODE
-		| REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(7),
-		SMPS_ADVANCED_MODE_MASK | REGULATOR_BANK_MASK,
-		&vreg->test_reg[7]);
-	if (rc)
-		goto bail;
-
-	/* Set voltage and voltage band. */
-	rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, band | vprog,
-			SMPS_ADVANCED_BAND_MASK | SMPS_ADVANCED_VPROG_MASK,
-			&vreg->ctrl_reg);
-	if (rc)
-		goto bail;
-
-	vreg->save_uV = uV;
-
-bail:
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-
-	return rc;
-}
-
-static int pm8921_smps_set_voltage_legacy(struct pm8921_vreg *vreg, int min_uV,
-					  int max_uV)
-{
-	u8 vlow, vref, vprog, pd, en;
-	int rc;
-	int uV = min_uV;
-
-
-	if (uV < SMPS_MODE3_UV_MIN && max_uV >= SMPS_MODE3_UV_MIN)
-		uV = SMPS_MODE3_UV_MIN;
-
-	if (uV < SMPS_MODE3_UV_MIN || uV > SMPS_MODE1_UV_MAX) {
-		vreg_err(vreg,
-			"request v=[%d, %d] is outside possible v=[%d, %d]\n",
-			 min_uV, max_uV, SMPS_MODE3_UV_MIN, SMPS_MODE1_UV_MAX);
-		return -EINVAL;
-	}
-
-	if (uV > SMPS_MODE2_UV_MAX) {
-		vprog = (uV - SMPS_MODE1_UV_MIN + SMPS_MODE1_UV_STEP - 1)
-			/ SMPS_MODE1_UV_STEP;
-		vref = 0;
-		vlow = 0;
-		uV = SMPS_MODE1_UV_MIN + vprog * SMPS_MODE1_UV_STEP;
-	} else if (uV > SMPS_MODE3_UV_MAX) {
-		vprog = (uV - SMPS_MODE2_UV_MIN + SMPS_MODE2_UV_STEP - 1)
-			/ SMPS_MODE2_UV_STEP;
-		vref = SMPS_LEGACY_VREF_SEL_MASK;
-		vlow = 0;
-		uV = SMPS_MODE2_UV_MIN + vprog * SMPS_MODE2_UV_STEP;
-	} else {
-		vprog = (uV - SMPS_MODE3_UV_MIN + SMPS_MODE3_UV_STEP - 1)
-			/ SMPS_MODE3_UV_STEP;
-		vref = SMPS_LEGACY_VREF_SEL_MASK;
-		vlow = SMPS_LEGACY_VLOW_SEL_MASK;
-		uV = SMPS_MODE3_UV_MIN + vprog * SMPS_MODE3_UV_STEP;
-	}
-
-	if (uV > max_uV) {
-		vreg_err(vreg,
-			"request v=[%d, %d] cannot be met by any set point\n",
-			min_uV, max_uV);
-		return -EINVAL;
-	}
-
-	/* set vlow bit for ultra low voltage mode */
-	rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
-		vlow | REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(1),
-		REGULATOR_BANK_MASK | SMPS_LEGACY_VLOW_SEL_MASK,
-		&vreg->test_reg[1]);
-	if (rc)
-		goto bail;
-
-	/* Set advanced mode bit to 0. */
-	rc = pm8921_vreg_masked_write(vreg, vreg->test_addr, SMPS_LEGACY_MODE
-		| REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(7),
-		SMPS_ADVANCED_MODE_MASK | REGULATOR_BANK_MASK,
-		&vreg->test_reg[7]);
-	if (rc)
-		goto bail;
-
-	en = (_pm8921_vreg_is_enabled(vreg) ? SMPS_LEGACY_ENABLE : 0);
-	pd = (vreg->pdata.pull_down_enable ? SMPS_LEGACY_PULL_DOWN_ENABLE : 0);
-
-	/* Set voltage (and the rest of the control register). */
-	rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
-		en | pd | vref | vprog,
-		SMPS_LEGACY_ENABLE_MASK | SMPS_LEGACY_PULL_DOWN_ENABLE
-		  | SMPS_LEGACY_VREF_SEL_MASK | SMPS_LEGACY_VPROG_MASK,
-		&vreg->ctrl_reg);
-
-	vreg->save_uV = uV;
-
-bail:
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-
-	return rc;
-}
-
-static int pm8921_smps_set_voltage(struct regulator_dev *rdev, int min_uV,
-				   int max_uV, unsigned *selector)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc = 0;
-
-	mutex_lock(&vreg->pc_lock);
-
-	if (SMPS_IN_ADVANCED_MODE(vreg) || !pm8921_vreg_is_pin_controlled(vreg))
-		rc = pm8921_smps_set_voltage_advanced(vreg, min_uV, max_uV, 0);
-	else
-		rc = pm8921_smps_set_voltage_legacy(vreg, min_uV, max_uV);
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (!rc)
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_VOLTAGE);
-
-	return rc;
-}
-
-static int _pm8921_ftsmps_get_voltage(struct pm8921_vreg *vreg)
-{
-	u8 vprog, band;
-	int uV = 0;
-
-	if ((vreg->test_reg[0] & FTSMPS_CNFG1_PM_MASK) == FTSMPS_CNFG1_PM_PFM) {
-		vprog = vreg->pfm_ctrl_reg & FTSMPS_VCTRL_VPROG_MASK;
-		band = vreg->pfm_ctrl_reg & FTSMPS_VCTRL_BAND_MASK;
-		if (band == FTSMPS_VCTRL_BAND_OFF && vprog == 0) {
-			/* PWM_VCTRL overrides PFM_VCTRL */
-			vprog = vreg->ctrl_reg & FTSMPS_VCTRL_VPROG_MASK;
-			band = vreg->ctrl_reg & FTSMPS_VCTRL_BAND_MASK;
-		}
-	} else {
-		vprog = vreg->ctrl_reg & FTSMPS_VCTRL_VPROG_MASK;
-		band = vreg->ctrl_reg & FTSMPS_VCTRL_BAND_MASK;
-	}
-
-	if (band == FTSMPS_VCTRL_BAND_1)
-		uV = vprog * FTSMPS_BAND1_UV_PHYS_STEP + FTSMPS_BAND1_UV_MIN;
-	else if (band == FTSMPS_VCTRL_BAND_2)
-		uV = vprog * FTSMPS_BAND2_UV_STEP + FTSMPS_BAND2_UV_MIN;
-	else if (band == FTSMPS_VCTRL_BAND_3)
-		uV = vprog * FTSMPS_BAND3_UV_STEP + FTSMPS_BAND3_UV_MIN;
-	else if (vreg->save_uV > 0)
-		uV = vreg->save_uV;
-	else
-		uV = VOLTAGE_UNKNOWN;
-
-	return uV;
-}
-
-static int pm8921_ftsmps_get_voltage(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-
-	return _pm8921_ftsmps_get_voltage(vreg);
-}
-
-static int pm8921_ftsmps_list_voltage(struct regulator_dev *rdev,
-				      unsigned selector)
-{
-	int uV;
-
-	if (selector >= FTSMPS_SET_POINTS)
-		return 0;
-
-	if (selector < FTSMPS_BAND1_SET_POINTS)
-		uV = selector * FTSMPS_BAND1_UV_LOG_STEP + FTSMPS_BAND1_UV_MIN;
-	else if (selector < (FTSMPS_BAND1_SET_POINTS + FTSMPS_BAND2_SET_POINTS))
-		uV = (selector - FTSMPS_BAND1_SET_POINTS) * FTSMPS_BAND2_UV_STEP
-			+ FTSMPS_BAND2_UV_MIN;
-	else
-		uV = (selector - FTSMPS_BAND1_SET_POINTS
-			- FTSMPS_BAND2_SET_POINTS)
-				* FTSMPS_BAND3_UV_STEP
-			+ FTSMPS_BAND3_UV_SET_POINT_MIN;
-
-	return uV;
-}
-
-static int _pm8921_ftsmps_set_voltage(struct pm8921_vreg *vreg, int min_uV,
-				      int max_uV, int force_on)
-{
-	int rc = 0;
-	u8 vprog, band;
-	int uV = min_uV;
-
-	if (uV < FTSMPS_BAND1_UV_MIN && max_uV >= FTSMPS_BAND1_UV_MIN)
-		uV = FTSMPS_BAND1_UV_MIN;
-
-	if (uV < FTSMPS_BAND1_UV_MIN || uV > FTSMPS_BAND3_UV_MAX) {
-		vreg_err(vreg,
-			"request v=[%d, %d] is outside possible v=[%d, %d]\n",
-			 min_uV, max_uV, FTSMPS_BAND1_UV_MIN,
-			 FTSMPS_BAND3_UV_MAX);
-		return -EINVAL;
-	}
-
-	/* Round up for set points in the gaps between bands. */
-	if (uV > FTSMPS_BAND1_UV_MAX && uV < FTSMPS_BAND2_UV_MIN)
-		uV = FTSMPS_BAND2_UV_MIN;
-	else if (uV > FTSMPS_BAND2_UV_MAX
-			&& uV < FTSMPS_BAND3_UV_SET_POINT_MIN)
-		uV = FTSMPS_BAND3_UV_SET_POINT_MIN;
-
-	if (uV > FTSMPS_BAND2_UV_MAX) {
-		vprog = (uV - FTSMPS_BAND3_UV_MIN + FTSMPS_BAND3_UV_STEP - 1)
-			/ FTSMPS_BAND3_UV_STEP;
-		band = FTSMPS_VCTRL_BAND_3;
-		uV = FTSMPS_BAND3_UV_MIN + vprog * FTSMPS_BAND3_UV_STEP;
-	} else if (uV > FTSMPS_BAND1_UV_MAX) {
-		vprog = (uV - FTSMPS_BAND2_UV_MIN + FTSMPS_BAND2_UV_STEP - 1)
-			/ FTSMPS_BAND2_UV_STEP;
-		band = FTSMPS_VCTRL_BAND_2;
-		uV = FTSMPS_BAND2_UV_MIN + vprog * FTSMPS_BAND2_UV_STEP;
-	} else {
-		vprog = (uV - FTSMPS_BAND1_UV_MIN
-				+ FTSMPS_BAND1_UV_LOG_STEP - 1)
-			/ FTSMPS_BAND1_UV_LOG_STEP;
-		uV = FTSMPS_BAND1_UV_MIN + vprog * FTSMPS_BAND1_UV_LOG_STEP;
-		vprog *= FTSMPS_BAND1_UV_LOG_STEP / FTSMPS_BAND1_UV_PHYS_STEP;
-		band = FTSMPS_VCTRL_BAND_1;
-	}
-
-	if (uV > max_uV) {
-		vreg_err(vreg,
-			"request v=[%d, %d] cannot be met by any set point\n",
-			min_uV, max_uV);
-		return -EINVAL;
-	}
-
-	/*
-	 * Do not set voltage if regulator is currently disabled because doing
-	 * so will enable it.
-	 */
-	if (_pm8921_vreg_is_enabled(vreg) || force_on) {
-		rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
-			band | vprog,
-			FTSMPS_VCTRL_BAND_MASK | FTSMPS_VCTRL_VPROG_MASK,
-			&vreg->ctrl_reg);
-		if (rc)
-			goto bail;
-
-		/* Program PFM_VCTRL as 0x00 so that PWM_VCTRL overrides it. */
-		rc = pm8921_vreg_masked_write(vreg, vreg->pfm_ctrl_addr, 0x00,
-			FTSMPS_VCTRL_BAND_MASK | FTSMPS_VCTRL_VPROG_MASK,
-			&vreg->pfm_ctrl_reg);
-		if (rc)
-			goto bail;
-	}
-
-	vreg->save_uV = uV;
-
-bail:
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-
-	return rc;
-}
-
-static int pm8921_ftsmps_set_voltage(struct regulator_dev *rdev, int min_uV,
-				     int max_uV, unsigned *selector)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	rc = _pm8921_ftsmps_set_voltage(vreg, min_uV, max_uV, 0);
-
-	if (!rc)
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_VOLTAGE);
-
-	return rc;
-}
-
-static int pm8921_ncp_get_voltage(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	u8 vprog;
-
-	vprog = vreg->ctrl_reg & NCP_VPROG_MASK;
-
-	return NCP_UV_MIN + vprog * NCP_UV_STEP;
-}
-
-static int pm8921_ncp_list_voltage(struct regulator_dev *rdev,
-				   unsigned selector)
-{
-	if (selector >= NCP_SET_POINTS)
-		return 0;
-
-	return selector * NCP_UV_STEP + NCP_UV_MIN;
-}
-
-static int pm8921_ncp_set_voltage(struct regulator_dev *rdev, int min_uV,
-				  int max_uV, unsigned *selector)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-	int uV = min_uV;
-	u8 val;
-
-	if (uV < NCP_UV_MIN && max_uV >= NCP_UV_MIN)
-		uV = NCP_UV_MIN;
-
-	if (uV < NCP_UV_MIN || uV > NCP_UV_MAX) {
-		vreg_err(vreg,
-			"request v=[%d, %d] is outside possible v=[%d, %d]\n",
-			 min_uV, max_uV, NCP_UV_MIN, NCP_UV_MAX);
-		return -EINVAL;
-	}
-
-	val = (uV - NCP_UV_MIN + NCP_UV_STEP - 1) / NCP_UV_STEP;
-	uV = val * NCP_UV_STEP + NCP_UV_MIN;
-
-	if (uV > max_uV) {
-		vreg_err(vreg,
-			"request v=[%d, %d] cannot be met by any set point\n",
-			min_uV, max_uV);
-		return -EINVAL;
-	}
-
-	/* voltage setting */
-	rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, val,
-			NCP_VPROG_MASK, &vreg->ctrl_reg);
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_VOLTAGE);
-
-	return rc;
-}
-
-static unsigned int pm8921_ldo_get_mode(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	unsigned int mode = 0;
-
-	mutex_lock(&vreg->pc_lock);
-	mode = vreg->mode;
-	mutex_unlock(&vreg->pc_lock);
-
-	return mode;
-}
-
-static int pm8921_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc = 0;
-
-	if (mode != REGULATOR_MODE_NORMAL && mode != REGULATOR_MODE_IDLE) {
-		vreg_err(vreg, "invalid mode: %u\n", mode);
-		return -EINVAL;
-	}
-
-	mutex_lock(&vreg->pc_lock);
-
-	if (mode == REGULATOR_MODE_NORMAL
-	    || (vreg->is_enabled_pc
-		&& vreg->pdata.pin_fn == PM8921_VREG_PIN_FN_ENABLE)) {
-		/* HPM */
-		rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
-			LDO_CTRL_PM_HPM, LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
-	} else {
-		/* LPM */
-		rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
-			LDO_CTRL_PM_LPM, LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
-		if (rc)
-			goto bail;
-
-		rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
-			LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
-			  | REGULATOR_BANK_SEL(0),
-			LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK,
-			&vreg->test_reg[0]);
-	}
-
-bail:
-	if (!rc)
-		vreg->mode = mode;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_MODE);
-
-	return rc;
-}
-
-static unsigned int pm8921_nldo1200_get_mode(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	unsigned int mode = 0;
-
-	if (NLDO1200_IN_ADVANCED_MODE(vreg)) {
-		/* Advanced mode */
-		if ((vreg->test_reg[2] & NLDO1200_ADVANCED_PM_MASK)
-		    == NLDO1200_ADVANCED_PM_LPM)
-			mode = REGULATOR_MODE_IDLE;
-		else
-			mode = REGULATOR_MODE_NORMAL;
-	} else {
-		/* Legacy mode */
-		if ((vreg->ctrl_reg & NLDO1200_LEGACY_PM_MASK)
-		    == NLDO1200_LEGACY_PM_LPM)
-			mode = REGULATOR_MODE_IDLE;
-		else
-			mode = REGULATOR_MODE_NORMAL;
-	}
-
-	return mode;
-}
-
-static int pm8921_nldo1200_set_mode(struct regulator_dev *rdev,
-				    unsigned int mode)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc = 0;
-
-	if (mode != REGULATOR_MODE_NORMAL && mode != REGULATOR_MODE_IDLE) {
-		vreg_err(vreg, "invalid mode: %u\n", mode);
-		return -EINVAL;
-	}
-
-	/*
-	 * Make sure that advanced mode is in use.  If it isn't, then set it
-	 * and update the voltage accordingly.
-	 */
-	if (!NLDO1200_IN_ADVANCED_MODE(vreg)) {
-		rc = _pm8921_nldo1200_set_voltage(vreg, vreg->save_uV,
-			vreg->save_uV);
-		if (rc)
-			goto bail;
-	}
-
-	if (mode == REGULATOR_MODE_NORMAL) {
-		/* HPM */
-		rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
-			NLDO1200_ADVANCED_PM_HPM | REGULATOR_BANK_WRITE
-			| REGULATOR_BANK_SEL(2), NLDO1200_ADVANCED_PM_MASK
-			| REGULATOR_BANK_MASK, &vreg->test_reg[2]);
-	} else {
-		/* LPM */
-		rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
-			NLDO1200_ADVANCED_PM_LPM | REGULATOR_BANK_WRITE
-			| REGULATOR_BANK_SEL(2), NLDO1200_ADVANCED_PM_MASK
-			| REGULATOR_BANK_MASK, &vreg->test_reg[2]);
-	}
-
-bail:
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_MODE);
-
-	return rc;
-}
-
-static unsigned int pm8921_smps_get_mode(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	unsigned int mode = 0;
-
-	mutex_lock(&vreg->pc_lock);
-	mode = vreg->mode;
-	mutex_unlock(&vreg->pc_lock);
-
-	return mode;
-}
-
-static int pm8921_smps_set_mode(struct regulator_dev *rdev, unsigned int mode)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc = 0;
-
-	if (mode != REGULATOR_MODE_NORMAL && mode != REGULATOR_MODE_IDLE) {
-		vreg_err(vreg, "invalid mode: %u\n", mode);
-		return -EINVAL;
-	}
-
-	mutex_lock(&vreg->pc_lock);
-
-	if (mode == REGULATOR_MODE_NORMAL
-	    || (vreg->is_enabled_pc
-		&& vreg->pdata.pin_fn == PM8921_VREG_PIN_FN_ENABLE)) {
-		/* HPM */
-		rc = pm8921_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
-				       SMPS_CLK_CTRL_PWM, SMPS_CLK_CTRL_MASK,
-				       &vreg->clk_ctrl_reg);
-	} else {
-		/* LPM */
-		rc = pm8921_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
-				       SMPS_CLK_CTRL_PFM, SMPS_CLK_CTRL_MASK,
-				       &vreg->clk_ctrl_reg);
-	}
-
-	if (!rc)
-		vreg->mode = mode;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_MODE);
-
-	return rc;
-}
-
-static unsigned int pm8921_ftsmps_get_mode(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	unsigned int mode = 0;
-
-	if ((vreg->test_reg[0] & FTSMPS_CNFG1_PM_MASK) == FTSMPS_CNFG1_PM_PFM)
-		mode = REGULATOR_MODE_IDLE;
-	else
-		mode = REGULATOR_MODE_NORMAL;
-
-	return mode;
-}
-
-static int pm8921_ftsmps_set_mode(struct regulator_dev *rdev, unsigned int mode)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc = 0;
-
-	if (mode == REGULATOR_MODE_NORMAL) {
-		/* HPM */
-		rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
-				FTSMPS_CNFG1_PM_PWM | REGULATOR_BANK_WRITE
-				| REGULATOR_BANK_SEL(0), FTSMPS_CNFG1_PM_MASK
-				| REGULATOR_BANK_MASK, &vreg->test_reg[0]);
-	} else if (mode == REGULATOR_MODE_IDLE) {
-		/* LPM */
-		rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
-				FTSMPS_CNFG1_PM_PFM | REGULATOR_BANK_WRITE
-				| REGULATOR_BANK_SEL(0), FTSMPS_CNFG1_PM_MASK
-				| REGULATOR_BANK_MASK, &vreg->test_reg[0]);
-	} else {
-		vreg_err(vreg, "invalid mode: %u\n", mode);
-		return -EINVAL;
-	}
-
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_MODE);
-
-	return rc;
-}
-
-static unsigned int pm8921_vreg_get_optimum_mode(struct regulator_dev *rdev,
-		int input_uV, int output_uV, int load_uA)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	unsigned int mode;
-
-	if (load_uA + vreg->pdata.system_uA >= vreg->hpm_min_load)
-		mode = REGULATOR_MODE_NORMAL;
-	else
-		mode = REGULATOR_MODE_IDLE;
-
-	return mode;
-}
-
-static int pm8921_ldo_enable(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc, val;
-
-	mutex_lock(&vreg->pc_lock);
-
-	/*
-	 * Choose HPM if previously set to HPM or if pin control is enabled in
-	 * on/off mode.
-	 */
-	val = LDO_CTRL_PM_LPM;
-	if (vreg->mode == REGULATOR_MODE_NORMAL
-		|| (vreg->is_enabled_pc
-			&& vreg->pdata.pin_fn == PM8921_VREG_PIN_FN_ENABLE))
-		val = LDO_CTRL_PM_HPM;
-
-	rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, val | LDO_ENABLE,
-		LDO_ENABLE_MASK | LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
-
-	if (!rc)
-		vreg->is_enabled = true;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_ENABLE);
-
-	return rc;
-}
-
-static int pm8921_ldo_disable(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	mutex_lock(&vreg->pc_lock);
-
-	/*
-	 * Only disable the regulator if it isn't still required for HPM/LPM
-	 * pin control.
-	 */
-	if (!vreg->is_enabled_pc
-	    || vreg->pdata.pin_fn != PM8921_VREG_PIN_FN_MODE) {
-		rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
-			LDO_DISABLE, LDO_ENABLE_MASK, &vreg->ctrl_reg);
-		if (rc)
-			goto bail;
-	}
-
-	/* Change to LPM if HPM/LPM pin control is enabled. */
-	if (vreg->is_enabled_pc
-	    && vreg->pdata.pin_fn == PM8921_VREG_PIN_FN_MODE) {
-		rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
-			LDO_CTRL_PM_LPM, LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
-		if (rc)
-			goto bail;
-
-		rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
-			LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
-			  | REGULATOR_BANK_SEL(0),
-			LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK,
-			&vreg->test_reg[0]);
-	}
-
-	if (!rc)
-		vreg->is_enabled = false;
-bail:
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_DISABLE);
-
-	return rc;
-}
-
-static int pm8921_nldo1200_enable(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, NLDO1200_ENABLE,
-		NLDO1200_ENABLE_MASK, &vreg->ctrl_reg);
-
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_ENABLE);
-
-	return rc;
-}
-
-static int pm8921_nldo1200_disable(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, NLDO1200_DISABLE,
-		NLDO1200_ENABLE_MASK, &vreg->ctrl_reg);
-
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_DISABLE);
-
-	return rc;
-}
-
-static int pm8921_smps_enable(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc = 0;
-	int val;
-
-	mutex_lock(&vreg->pc_lock);
-
-	if (SMPS_IN_ADVANCED_MODE(vreg)
-	     || !pm8921_vreg_is_pin_controlled(vreg)) {
-		/* Enable in advanced mode if not using pin control. */
-		rc = pm8921_smps_set_voltage_advanced(vreg, vreg->save_uV,
-			vreg->save_uV, 1);
-	} else {
-		rc = pm8921_smps_set_voltage_legacy(vreg, vreg->save_uV,
-			vreg->save_uV);
-		if (rc)
-			goto bail;
-
-		rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
-			SMPS_LEGACY_ENABLE, SMPS_LEGACY_ENABLE_MASK,
-			&vreg->ctrl_reg);
-	}
-
-	/*
-	 * Choose HPM if previously set to HPM or if pin control is enabled in
-	 * on/off mode.
-	 */
-	val = SMPS_CLK_CTRL_PFM;
-	if (vreg->mode == REGULATOR_MODE_NORMAL
-		|| (vreg->is_enabled_pc
-			&& vreg->pdata.pin_fn == PM8921_VREG_PIN_FN_ENABLE))
-		val = SMPS_CLK_CTRL_PWM;
-
-	rc = pm8921_vreg_masked_write(vreg, vreg->clk_ctrl_addr, val,
-			SMPS_CLK_CTRL_MASK, &vreg->clk_ctrl_reg);
-
-	if (!rc)
-		vreg->is_enabled = true;
-bail:
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_ENABLE);
-
-	return rc;
-}
-
-static int pm8921_smps_disable(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	mutex_lock(&vreg->pc_lock);
-
-	if (SMPS_IN_ADVANCED_MODE(vreg)) {
-		/* Change SMPS to legacy mode before disabling. */
-		rc = pm8921_smps_set_voltage_legacy(vreg, vreg->save_uV,
-				vreg->save_uV);
-		if (rc)
-			goto bail;
-	}
-
-	/*
-	 * Only disable the regulator if it isn't still required for HPM/LPM
-	 * pin control.
-	 */
-	if (!vreg->is_enabled_pc
-	    || vreg->pdata.pin_fn != PM8921_VREG_PIN_FN_MODE) {
-		rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
-			SMPS_LEGACY_DISABLE, SMPS_LEGACY_ENABLE_MASK,
-			&vreg->ctrl_reg);
-		if (rc)
-			goto bail;
-	}
-
-	/* Change to LPM if HPM/LPM pin control is enabled. */
-	if (vreg->is_enabled_pc
-	    && vreg->pdata.pin_fn == PM8921_VREG_PIN_FN_MODE)
-		rc = pm8921_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
-		       SMPS_CLK_CTRL_PFM, SMPS_CLK_CTRL_MASK,
-		       &vreg->clk_ctrl_reg);
-
-	if (!rc)
-		vreg->is_enabled = false;
-
-bail:
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_DISABLE);
-
-	return rc;
-}
-
-static int pm8921_ftsmps_enable(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	rc = _pm8921_ftsmps_set_voltage(vreg, vreg->save_uV, vreg->save_uV, 1);
-
-	if (rc)
-		vreg_err(vreg, "set voltage failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_ENABLE);
-
-	return rc;
-}
-
-static int pm8921_ftsmps_disable(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
-		FTSMPS_VCTRL_BAND_OFF, FTSMPS_VCTRL_BAND_MASK, &vreg->ctrl_reg);
-	if (rc)
-		goto bail;
-
-	rc = pm8921_vreg_masked_write(vreg, vreg->pfm_ctrl_addr,
-		FTSMPS_VCTRL_BAND_OFF, FTSMPS_VCTRL_BAND_MASK,
-		&vreg->pfm_ctrl_reg);
-bail:
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_DISABLE);
-
-	return rc;
-}
-
-static int pm8921_vs_enable(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	mutex_lock(&vreg->pc_lock);
-
-	rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, VS_ENABLE,
-		VS_ENABLE_MASK, &vreg->ctrl_reg);
-
-	if (!rc)
-		vreg->is_enabled = true;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_ENABLE);
-
-	return rc;
-}
-
-static int pm8921_vs_disable(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	mutex_lock(&vreg->pc_lock);
-
-	rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, VS_DISABLE,
-		VS_ENABLE_MASK, &vreg->ctrl_reg);
-
-	if (!rc)
-		vreg->is_enabled = false;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_DISABLE);
-
-	return rc;
-}
-
-static int pm8921_vs300_enable(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, VS300_CTRL_ENABLE,
-		VS300_CTRL_ENABLE_MASK, &vreg->ctrl_reg);
-
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_ENABLE);
-
-	return rc;
-}
-
-static int pm8921_vs300_disable(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, VS300_CTRL_DISABLE,
-		VS300_CTRL_ENABLE_MASK, &vreg->ctrl_reg);
-
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_DISABLE);
-
-	return rc;
-}
-
-static int pm8921_ncp_enable(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, NCP_ENABLE,
-		NCP_ENABLE_MASK, &vreg->ctrl_reg);
-
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_ENABLE);
-
-	return rc;
-}
-
-static int pm8921_ncp_disable(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, NCP_DISABLE,
-		NCP_ENABLE_MASK, &vreg->ctrl_reg);
-
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_DISABLE);
-
-	return rc;
-}
-
-static int pm8921_ldo_pin_control_enable(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc = 0;
-	int bank;
-	u8 val = 0;
-	u8 mask;
-
-	mutex_lock(&vreg->pc_lock);
-
-	if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_D1)
-		val |= LDO_TEST_PIN_CTRL_EN0;
-	if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_A0)
-		val |= LDO_TEST_PIN_CTRL_EN1;
-	if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_A1)
-		val |= LDO_TEST_PIN_CTRL_EN2;
-	if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_A2)
-		val |= LDO_TEST_PIN_CTRL_EN3;
-
-	bank = (vreg->pdata.pin_fn == PM8921_VREG_PIN_FN_ENABLE ? 5 : 6);
-	rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
-		val | REGULATOR_BANK_SEL(bank) | REGULATOR_BANK_WRITE,
-		LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
-		&vreg->test_reg[bank]);
-	if (rc)
-		goto bail;
-
-	/* Unset pin control bits in unused bank. */
-	bank = (bank == 5 ? 6 : 5);
-	rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
-		REGULATOR_BANK_SEL(bank) | REGULATOR_BANK_WRITE,
-		LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
-		&vreg->test_reg[bank]);
-	if (rc)
-		goto bail;
-
-	val = LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
-		| REGULATOR_BANK_SEL(0);
-	mask = LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK;
-	rc = pm8921_vreg_masked_write(vreg, vreg->test_addr, val, mask,
-		&vreg->test_reg[0]);
-	if (rc)
-		goto bail;
-
-	if (vreg->pdata.pin_fn == PM8921_VREG_PIN_FN_ENABLE) {
-		/* Pin control ON/OFF */
-		val = LDO_CTRL_PM_HPM;
-		/* Leave physically enabled if already enabled. */
-		val |= (vreg->is_enabled ? LDO_ENABLE : LDO_DISABLE);
-		rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, val,
-			LDO_ENABLE_MASK | LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
-		if (rc)
-			goto bail;
-	} else {
-		/* Pin control LPM/HPM */
-		val = LDO_ENABLE;
-		/* Leave in HPM if already enabled in HPM. */
-		val |= (vreg->is_enabled && vreg->mode == REGULATOR_MODE_NORMAL
-			?  LDO_CTRL_PM_HPM : LDO_CTRL_PM_LPM);
-		rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, val,
-			LDO_ENABLE_MASK | LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
-		if (rc)
-			goto bail;
-	}
-
-bail:
-	if (!rc)
-		vreg->is_enabled_pc = true;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_PIN_CTRL);
-
-	return rc;
-}
-
-static int pm8921_ldo_pin_control_disable(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	mutex_lock(&vreg->pc_lock);
-
-	rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
-			REGULATOR_BANK_SEL(5) | REGULATOR_BANK_WRITE,
-			LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
-			&vreg->test_reg[5]);
-	if (rc)
-		goto bail;
-
-	rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
-			REGULATOR_BANK_SEL(6) | REGULATOR_BANK_WRITE,
-			LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
-			&vreg->test_reg[6]);
-
-	/*
-	 * Physically disable the regulator if it was enabled in HPM/LPM pin
-	 * control mode previously and it logically should not be enabled.
-	 */
-	if ((vreg->ctrl_reg & LDO_ENABLE_MASK) == LDO_ENABLE
-	    && !vreg->is_enabled) {
-		rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
-			LDO_DISABLE, LDO_ENABLE_MASK, &vreg->ctrl_reg);
-		if (rc)
-			goto bail;
-	}
-
-	/* Change to LPM if LPM was enabled. */
-	if (vreg->is_enabled && vreg->mode == REGULATOR_MODE_IDLE) {
-		rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
-			LDO_CTRL_PM_LPM, LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
-		if (rc)
-			goto bail;
-
-		rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
-			LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
-			  | REGULATOR_BANK_SEL(0),
-			LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK,
-			&vreg->test_reg[0]);
-		if (rc)
-			goto bail;
-	}
-
-bail:
-	if (!rc)
-		vreg->is_enabled_pc = false;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_PIN_CTRL);
-
-	return rc;
-}
-
-static int pm8921_smps_pin_control_enable(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc = 0;
-	u8 val = 0;
-
-	mutex_lock(&vreg->pc_lock);
-
-	if (vreg->pdata.pin_fn == PM8921_VREG_PIN_FN_ENABLE) {
-		/* Pin control ON/OFF */
-		if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_D1)
-			val |= SMPS_PIN_CTRL_EN0;
-		if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_A0)
-			val |= SMPS_PIN_CTRL_EN1;
-		if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_A1)
-			val |= SMPS_PIN_CTRL_EN2;
-		if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_A2)
-			val |= SMPS_PIN_CTRL_EN3;
-	} else {
-		/* Pin control LPM/HPM */
-		if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_D1)
-			val |= SMPS_PIN_CTRL_LPM_EN0;
-		if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_A0)
-			val |= SMPS_PIN_CTRL_LPM_EN1;
-		if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_A1)
-			val |= SMPS_PIN_CTRL_LPM_EN2;
-		if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_A2)
-			val |= SMPS_PIN_CTRL_LPM_EN3;
-	}
-
-	rc = pm8921_smps_set_voltage_legacy(vreg, vreg->save_uV, vreg->save_uV);
-	if (rc)
-		goto bail;
-
-	rc = pm8921_vreg_masked_write(vreg, vreg->sleep_ctrl_addr, val,
-			SMPS_PIN_CTRL_MASK | SMPS_PIN_CTRL_LPM_MASK,
-			&vreg->sleep_ctrl_reg);
-	if (rc)
-		goto bail;
-
-	/*
-	 * Physically enable the regulator if using HPM/LPM pin control mode or
-	 * if the regulator should be logically left on.
-	 */
-	rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
-		((vreg->pdata.pin_fn == PM8921_VREG_PIN_FN_MODE
-		  || vreg->is_enabled) ?
-			SMPS_LEGACY_ENABLE : SMPS_LEGACY_DISABLE),
-		SMPS_LEGACY_ENABLE_MASK, &vreg->ctrl_reg);
-	if (rc)
-		goto bail;
-
-	/*
-	 * Set regulator to HPM if using on/off pin control or if the regulator
-	 * is already enabled in HPM.  Otherwise, set it to LPM.
-	 */
-	rc = pm8921_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
-			(vreg->pdata.pin_fn == PM8921_VREG_PIN_FN_ENABLE
-			 || (vreg->is_enabled
-			     && vreg->mode == REGULATOR_MODE_NORMAL)
-				? SMPS_CLK_CTRL_PWM : SMPS_CLK_CTRL_PFM),
-			SMPS_CLK_CTRL_MASK, &vreg->clk_ctrl_reg);
-
-bail:
-	if (!rc)
-		vreg->is_enabled_pc = true;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_PIN_CTRL);
-
-	return rc;
-}
-
-static int pm8921_smps_pin_control_disable(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	mutex_lock(&vreg->pc_lock);
-
-	rc = pm8921_vreg_masked_write(vreg, vreg->sleep_ctrl_addr, 0,
-			SMPS_PIN_CTRL_MASK | SMPS_PIN_CTRL_LPM_MASK,
-			&vreg->sleep_ctrl_reg);
-	if (rc)
-		goto bail;
-
-	/*
-	 * Physically disable the regulator if it was enabled in HPM/LPM pin
-	 * control mode previously and it logically should not be enabled.
-	 */
-	if ((vreg->ctrl_reg & SMPS_LEGACY_ENABLE_MASK) == SMPS_LEGACY_ENABLE
-	    && vreg->is_enabled == false) {
-		rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
-			SMPS_LEGACY_DISABLE, SMPS_LEGACY_ENABLE_MASK,
-			&vreg->ctrl_reg);
-		if (rc)
-			goto bail;
-	}
-
-	/* Change to LPM if LPM was enabled. */
-	if (vreg->is_enabled && vreg->mode == REGULATOR_MODE_IDLE) {
-		rc = pm8921_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
-		       SMPS_CLK_CTRL_PFM, SMPS_CLK_CTRL_MASK,
-		       &vreg->clk_ctrl_reg);
-		if (rc)
-			goto bail;
-	}
-
-	rc = pm8921_smps_set_voltage_advanced(vreg, vreg->save_uV,
-			vreg->save_uV, 0);
-
-bail:
-	if (!rc)
-		vreg->is_enabled_pc = false;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_PIN_CTRL);
-
-	return rc;
-}
-
-static int pm8921_vs_pin_control_enable(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-	u8 val = 0;
-
-	mutex_lock(&vreg->pc_lock);
-
-	if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_D1)
-		val |= VS_PIN_CTRL_EN0;
-	if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_A0)
-		val |= VS_PIN_CTRL_EN1;
-	if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_A1)
-		val |= VS_PIN_CTRL_EN2;
-	if (vreg->pdata.pin_ctrl & PM8921_VREG_PIN_CTRL_A2)
-		val |= VS_PIN_CTRL_EN3;
-
-	rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, val,
-			VS_PIN_CTRL_MASK | VS_ENABLE_MASK, &vreg->ctrl_reg);
-
-	if (!rc)
-		vreg->is_enabled_pc = true;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_PIN_CTRL);
-
-	return rc;
-}
-
-static int pm8921_vs_pin_control_disable(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int rc;
-
-	mutex_lock(&vreg->pc_lock);
-
-	rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr, 0,
-				      VS_PIN_CTRL_MASK, &vreg->ctrl_reg);
-
-	if (!rc)
-		vreg->is_enabled_pc = false;
-
-	mutex_unlock(&vreg->pc_lock);
-
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-	else
-		pm8921_vreg_show_state(rdev, PM8921_REGULATOR_ACTION_PIN_CTRL);
-
-	return rc;
-}
-
-static int pm8921_enable_time(struct regulator_dev *rdev)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-
-	return vreg->pdata.enable_time;
-}
-
-static const char const *pm8921_print_actions[] = {
-	[PM8921_REGULATOR_ACTION_INIT]		= "initial    ",
-	[PM8921_REGULATOR_ACTION_ENABLE]	= "enable     ",
-	[PM8921_REGULATOR_ACTION_DISABLE]	= "disable    ",
-	[PM8921_REGULATOR_ACTION_VOLTAGE]	= "set voltage",
-	[PM8921_REGULATOR_ACTION_MODE]		= "set mode   ",
-	[PM8921_REGULATOR_ACTION_PIN_CTRL]	= "pin control",
-};
-
-static void pm8921_vreg_show_state(struct regulator_dev *rdev,
-				   enum pm8921_regulator_action action)
-{
-	struct pm8921_vreg *vreg = rdev_get_drvdata(rdev);
-	int uV, pc;
-	unsigned int mode;
-	const char *pc_en0 = "", *pc_en1 = "", *pc_en2 = "", *pc_en3 = "";
-	const char *pc_total = "";
-	const char *action_label = pm8921_print_actions[action];
-	const char *enable_label;
-
-	mutex_lock(&vreg->pc_lock);
-
-	/*
-	 * Do not print unless REQUEST is specified and SSBI writes have taken
-	 * place, or DUPLICATE is specified.
-	 */
-	if (!((pm8921_vreg_debug_mask & PM8921_VREG_DEBUG_DUPLICATE)
-	      || ((pm8921_vreg_debug_mask & PM8921_VREG_DEBUG_REQUEST)
-		  && (vreg->write_count != vreg->prev_write_count)))) {
-		mutex_unlock(&vreg->pc_lock);
-		return;
-	}
-
-	vreg->prev_write_count = vreg->write_count;
-
-	pc = vreg->pdata.pin_ctrl;
-	if (vreg->is_enabled_pc) {
-		if (pc & PM8921_VREG_PIN_CTRL_D1)
-			pc_en0 = " D1";
-		if (pc & PM8921_VREG_PIN_CTRL_A0)
-			pc_en1 = " A0";
-		if (pc & PM8921_VREG_PIN_CTRL_A1)
-			pc_en2 = " A1";
-		if (pc & PM8921_VREG_PIN_CTRL_A2)
-			pc_en3 = " A2";
-		if (pc == PM8921_VREG_PIN_CTRL_NONE)
-			pc_total = " none";
-	} else {
-		pc_total = " none";
-	}
-
-	mutex_unlock(&vreg->pc_lock);
-
-	enable_label = pm8921_vreg_is_enabled(rdev) ? "on " : "off";
-
-	switch (vreg->type) {
-	case REGULATOR_TYPE_PLDO:
-		uV = pm8921_pldo_get_voltage(rdev);
-		mode = pm8921_ldo_get_mode(rdev);
-		pr_info("%s %-9s: %s, v=%7d uV, mode=%s, pc=%s%s%s%s%s\n",
-			action_label, vreg->name, enable_label, uV,
-			(mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"),
-			pc_en0, pc_en1, pc_en2, pc_en3, pc_total);
-		break;
-	case REGULATOR_TYPE_NLDO:
-		uV = pm8921_nldo_get_voltage(rdev);
-		mode = pm8921_ldo_get_mode(rdev);
-		pr_info("%s %-9s: %s, v=%7d uV, mode=%s, pc=%s%s%s%s%s\n",
-			action_label, vreg->name, enable_label, uV,
-			(mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"),
-			pc_en0, pc_en1, pc_en2, pc_en3, pc_total);
-		break;
-	case REGULATOR_TYPE_NLDO1200:
-		uV = pm8921_nldo1200_get_voltage(rdev);
-		mode = pm8921_nldo1200_get_mode(rdev);
-		pr_info("%s %-9s: %s, v=%7d uV, mode=%s\n",
-			action_label, vreg->name, enable_label, uV,
-			(mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"));
-		break;
-	case REGULATOR_TYPE_SMPS:
-		uV = pm8921_smps_get_voltage(rdev);
-		mode = pm8921_smps_get_mode(rdev);
-		pr_info("%s %-9s: %s, v=%7d uV, mode=%s, pc=%s%s%s%s%s\n",
-			action_label, vreg->name, enable_label, uV,
-			(mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"),
-			pc_en0, pc_en1, pc_en2, pc_en3, pc_total);
-		break;
-	case REGULATOR_TYPE_FTSMPS:
-		uV = pm8921_ftsmps_get_voltage(rdev);
-		mode = pm8921_ftsmps_get_mode(rdev);
-		pr_info("%s %-9s: %s, v=%7d uV, mode=%s\n",
-			action_label, vreg->name, enable_label, uV,
-			(mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"));
-		break;
-	case REGULATOR_TYPE_VS:
-		pr_info("%s %-9s: %s, pc=%s%s%s%s%s\n",
-			action_label, vreg->name, enable_label,
-			pc_en0, pc_en1, pc_en2, pc_en3, pc_total);
-		break;
-	case REGULATOR_TYPE_VS300:
-		pr_info("%s %-9s: %s\n",
-			action_label, vreg->name, enable_label);
-		break;
-	case REGULATOR_TYPE_NCP:
-		uV = pm8921_ncp_get_voltage(rdev);
-		pr_info("%s %-9s: %s, v=%7d uV\n",
-			action_label, vreg->name, enable_label, uV);
-		break;
-	default:
-		break;
-	}
-}
-
-
-/* Real regulator operations. */
-static struct regulator_ops pm8921_pldo_ops = {
-	.enable			= pm8921_ldo_enable,
-	.disable		= pm8921_ldo_disable,
-	.is_enabled		= pm8921_vreg_is_enabled,
-	.set_voltage		= pm8921_pldo_set_voltage,
-	.get_voltage		= pm8921_pldo_get_voltage,
-	.list_voltage		= pm8921_pldo_list_voltage,
-	.set_mode		= pm8921_ldo_set_mode,
-	.get_mode		= pm8921_ldo_get_mode,
-	.get_optimum_mode	= pm8921_vreg_get_optimum_mode,
-	.enable_time		= pm8921_enable_time,
-};
-
-static struct regulator_ops pm8921_nldo_ops = {
-	.enable			= pm8921_ldo_enable,
-	.disable		= pm8921_ldo_disable,
-	.is_enabled		= pm8921_vreg_is_enabled,
-	.set_voltage		= pm8921_nldo_set_voltage,
-	.get_voltage		= pm8921_nldo_get_voltage,
-	.list_voltage		= pm8921_nldo_list_voltage,
-	.set_mode		= pm8921_ldo_set_mode,
-	.get_mode		= pm8921_ldo_get_mode,
-	.get_optimum_mode	= pm8921_vreg_get_optimum_mode,
-	.enable_time		= pm8921_enable_time,
-};
-
-static struct regulator_ops pm8921_nldo1200_ops = {
-	.enable			= pm8921_nldo1200_enable,
-	.disable		= pm8921_nldo1200_disable,
-	.is_enabled		= pm8921_vreg_is_enabled,
-	.set_voltage		= pm8921_nldo1200_set_voltage,
-	.get_voltage		= pm8921_nldo1200_get_voltage,
-	.list_voltage		= pm8921_nldo1200_list_voltage,
-	.set_mode		= pm8921_nldo1200_set_mode,
-	.get_mode		= pm8921_nldo1200_get_mode,
-	.get_optimum_mode	= pm8921_vreg_get_optimum_mode,
-	.enable_time		= pm8921_enable_time,
-};
-
-static struct regulator_ops pm8921_smps_ops = {
-	.enable			= pm8921_smps_enable,
-	.disable		= pm8921_smps_disable,
-	.is_enabled		= pm8921_vreg_is_enabled,
-	.set_voltage		= pm8921_smps_set_voltage,
-	.get_voltage		= pm8921_smps_get_voltage,
-	.list_voltage		= pm8921_smps_list_voltage,
-	.set_mode		= pm8921_smps_set_mode,
-	.get_mode		= pm8921_smps_get_mode,
-	.get_optimum_mode	= pm8921_vreg_get_optimum_mode,
-	.enable_time		= pm8921_enable_time,
-};
-
-static struct regulator_ops pm8921_ftsmps_ops = {
-	.enable			= pm8921_ftsmps_enable,
-	.disable		= pm8921_ftsmps_disable,
-	.is_enabled		= pm8921_vreg_is_enabled,
-	.set_voltage		= pm8921_ftsmps_set_voltage,
-	.get_voltage		= pm8921_ftsmps_get_voltage,
-	.list_voltage		= pm8921_ftsmps_list_voltage,
-	.set_mode		= pm8921_ftsmps_set_mode,
-	.get_mode		= pm8921_ftsmps_get_mode,
-	.get_optimum_mode	= pm8921_vreg_get_optimum_mode,
-	.enable_time		= pm8921_enable_time,
-};
-
-static struct regulator_ops pm8921_vs_ops = {
-	.enable			= pm8921_vs_enable,
-	.disable		= pm8921_vs_disable,
-	.is_enabled		= pm8921_vreg_is_enabled,
-	.enable_time		= pm8921_enable_time,
-};
-
-static struct regulator_ops pm8921_vs300_ops = {
-	.enable			= pm8921_vs300_enable,
-	.disable		= pm8921_vs300_disable,
-	.is_enabled		= pm8921_vreg_is_enabled,
-	.enable_time		= pm8921_enable_time,
-};
-
-static struct regulator_ops pm8921_ncp_ops = {
-	.enable			= pm8921_ncp_enable,
-	.disable		= pm8921_ncp_disable,
-	.is_enabled		= pm8921_vreg_is_enabled,
-	.set_voltage		= pm8921_ncp_set_voltage,
-	.get_voltage		= pm8921_ncp_get_voltage,
-	.list_voltage		= pm8921_ncp_list_voltage,
-	.enable_time		= pm8921_enable_time,
-};
-
-/* Pin control regulator operations. */
-static struct regulator_ops pm8921_ldo_pc_ops = {
-	.enable			= pm8921_ldo_pin_control_enable,
-	.disable		= pm8921_ldo_pin_control_disable,
-	.is_enabled		= pm8921_vreg_pin_control_is_enabled,
-};
-
-static struct regulator_ops pm8921_smps_pc_ops = {
-	.enable			= pm8921_smps_pin_control_enable,
-	.disable		= pm8921_smps_pin_control_disable,
-	.is_enabled		= pm8921_vreg_pin_control_is_enabled,
-};
-
-static struct regulator_ops pm8921_vs_pc_ops = {
-	.enable			= pm8921_vs_pin_control_enable,
-	.disable		= pm8921_vs_pin_control_disable,
-	.is_enabled		= pm8921_vreg_pin_control_is_enabled,
-};
-
-#define VREG_DESC(_id, _name, _ops, _n_voltages) \
-	[PM8921_VREG_ID_##_id] = { \
-		.id	= PM8921_VREG_ID_##_id, \
-		.name	= _name, \
-		.n_voltages = _n_voltages, \
-		.ops	= _ops, \
-		.type	= REGULATOR_VOLTAGE, \
-		.owner	= THIS_MODULE, \
-	}
-
-static struct regulator_desc pm8921_vreg_description[] = {
-	VREG_DESC(L1,  "8921_l1",  &pm8921_nldo_ops, NLDO_SET_POINTS),
-	VREG_DESC(L2,  "8921_l2",  &pm8921_nldo_ops, NLDO_SET_POINTS),
-	VREG_DESC(L3,  "8921_l3",  &pm8921_pldo_ops, PLDO_SET_POINTS),
-	VREG_DESC(L4,  "8921_l4",  &pm8921_pldo_ops, PLDO_SET_POINTS),
-	VREG_DESC(L5,  "8921_l5",  &pm8921_pldo_ops, PLDO_SET_POINTS),
-	VREG_DESC(L6,  "8921_l6",  &pm8921_pldo_ops, PLDO_SET_POINTS),
-	VREG_DESC(L7,  "8921_l7",  &pm8921_pldo_ops, PLDO_SET_POINTS),
-	VREG_DESC(L8,  "8921_l8",  &pm8921_pldo_ops, PLDO_SET_POINTS),
-	VREG_DESC(L9,  "8921_l9",  &pm8921_pldo_ops, PLDO_SET_POINTS),
-	VREG_DESC(L10, "8921_l10", &pm8921_pldo_ops, PLDO_SET_POINTS),
-	VREG_DESC(L11, "8921_l11", &pm8921_pldo_ops, PLDO_SET_POINTS),
-	VREG_DESC(L12, "8921_l12", &pm8921_nldo_ops, NLDO_SET_POINTS),
-	VREG_DESC(L14, "8921_l14", &pm8921_pldo_ops, PLDO_SET_POINTS),
-	VREG_DESC(L15, "8921_l15", &pm8921_pldo_ops, PLDO_SET_POINTS),
-	VREG_DESC(L16, "8921_l16", &pm8921_pldo_ops, PLDO_SET_POINTS),
-	VREG_DESC(L17, "8921_l17", &pm8921_pldo_ops, PLDO_SET_POINTS),
-	VREG_DESC(L18, "8921_l18", &pm8921_nldo_ops, NLDO_SET_POINTS),
-	VREG_DESC(L21, "8921_l21", &pm8921_pldo_ops, PLDO_SET_POINTS),
-	VREG_DESC(L22, "8921_l22", &pm8921_pldo_ops, PLDO_SET_POINTS),
-	VREG_DESC(L23, "8921_l23", &pm8921_pldo_ops, PLDO_SET_POINTS),
-	VREG_DESC(L24, "8921_l24", &pm8921_nldo1200_ops, NLDO1200_SET_POINTS),
-	VREG_DESC(L25, "8921_l25", &pm8921_nldo1200_ops, NLDO1200_SET_POINTS),
-	VREG_DESC(L26, "8921_l26", &pm8921_nldo1200_ops, NLDO1200_SET_POINTS),
-	VREG_DESC(L27, "8921_l27", &pm8921_nldo1200_ops, NLDO1200_SET_POINTS),
-	VREG_DESC(L28, "8921_l28", &pm8921_nldo1200_ops, NLDO1200_SET_POINTS),
-	VREG_DESC(L29, "8921_l29", &pm8921_pldo_ops, PLDO_SET_POINTS),
-
-	VREG_DESC(S1, "8921_s1", &pm8921_smps_ops, SMPS_ADVANCED_SET_POINTS),
-	VREG_DESC(S2, "8921_s2", &pm8921_smps_ops, SMPS_ADVANCED_SET_POINTS),
-	VREG_DESC(S3, "8921_s3", &pm8921_smps_ops, SMPS_ADVANCED_SET_POINTS),
-	VREG_DESC(S4, "8921_s4", &pm8921_smps_ops, SMPS_ADVANCED_SET_POINTS),
-	VREG_DESC(S5, "8921_s5", &pm8921_ftsmps_ops, FTSMPS_SET_POINTS),
-	VREG_DESC(S6, "8921_s6", &pm8921_ftsmps_ops, FTSMPS_SET_POINTS),
-	VREG_DESC(S7, "8921_s7", &pm8921_smps_ops, SMPS_ADVANCED_SET_POINTS),
-	VREG_DESC(S8, "8921_s8", &pm8921_smps_ops, SMPS_ADVANCED_SET_POINTS),
-
-	VREG_DESC(LVS1, "8921_lvs1", &pm8921_vs_ops, 0),
-	VREG_DESC(LVS2, "8921_lvs2", &pm8921_vs300_ops, 0),
-	VREG_DESC(LVS3, "8921_lvs3", &pm8921_vs_ops, 0),
-	VREG_DESC(LVS4, "8921_lvs4", &pm8921_vs_ops, 0),
-	VREG_DESC(LVS5, "8921_lvs5", &pm8921_vs_ops, 0),
-	VREG_DESC(LVS6, "8921_lvs6", &pm8921_vs_ops, 0),
-	VREG_DESC(LVS7, "8921_lvs7", &pm8921_vs_ops, 0),
-
-	VREG_DESC(USB_OTG, "8921_usb_otg", &pm8921_vs300_ops, 0),
-	VREG_DESC(HDMI_MVS, "8921_hdmi_mvs", &pm8921_vs300_ops, 0),
-	VREG_DESC(NCP, "8921_ncp", &pm8921_ncp_ops, NCP_SET_POINTS),
-
-	VREG_DESC(L1_PC,  "8921_l1_pc",  &pm8921_ldo_pc_ops, 0),
-	VREG_DESC(L2_PC,  "8921_l2_pc",  &pm8921_ldo_pc_ops, 0),
-	VREG_DESC(L3_PC,  "8921_l3_pc",  &pm8921_ldo_pc_ops, 0),
-	VREG_DESC(L4_PC,  "8921_l4_pc",  &pm8921_ldo_pc_ops, 0),
-	VREG_DESC(L5_PC,  "8921_l5_pc",  &pm8921_ldo_pc_ops, 0),
-	VREG_DESC(L6_PC,  "8921_l6_pc",  &pm8921_ldo_pc_ops, 0),
-	VREG_DESC(L7_PC,  "8921_l7_pc",  &pm8921_ldo_pc_ops, 0),
-	VREG_DESC(L8_PC,  "8921_l8_pc",  &pm8921_ldo_pc_ops, 0),
-	VREG_DESC(L9_PC,  "8921_l9_pc",  &pm8921_ldo_pc_ops, 0),
-	VREG_DESC(L10_PC, "8921_l10_pc", &pm8921_ldo_pc_ops, 0),
-	VREG_DESC(L11_PC, "8921_l11_pc", &pm8921_ldo_pc_ops, 0),
-	VREG_DESC(L12_PC, "8921_l12_pc", &pm8921_ldo_pc_ops, 0),
-	VREG_DESC(L14_PC, "8921_l14_pc", &pm8921_ldo_pc_ops, 0),
-	VREG_DESC(L15_PC, "8921_l15_pc", &pm8921_ldo_pc_ops, 0),
-	VREG_DESC(L16_PC, "8921_l16_pc", &pm8921_ldo_pc_ops, 0),
-	VREG_DESC(L17_PC, "8921_l17_pc", &pm8921_ldo_pc_ops, 0),
-	VREG_DESC(L18_PC, "8921_l18_pc", &pm8921_ldo_pc_ops, 0),
-	VREG_DESC(L21_PC, "8921_l21_pc", &pm8921_ldo_pc_ops, 0),
-	VREG_DESC(L22_PC, "8921_l22_pc", &pm8921_ldo_pc_ops, 0),
-	VREG_DESC(L23_PC, "8921_l23_pc", &pm8921_ldo_pc_ops, 0),
-	VREG_DESC(L29_PC, "8921_l29_pc", &pm8921_ldo_pc_ops, 0),
-
-	VREG_DESC(S1_PC, "8921_s1_pc", &pm8921_smps_pc_ops, 0),
-	VREG_DESC(S2_PC, "8921_s2_pc", &pm8921_smps_pc_ops, 0),
-	VREG_DESC(S3_PC, "8921_s3_pc", &pm8921_smps_pc_ops, 0),
-	VREG_DESC(S4_PC, "8921_s4_pc", &pm8921_smps_pc_ops, 0),
-	VREG_DESC(S7_PC, "8921_s7_pc", &pm8921_smps_pc_ops, 0),
-	VREG_DESC(S8_PC, "8921_s8_pc", &pm8921_smps_pc_ops, 0),
-
-	VREG_DESC(LVS1_PC, "8921_lvs1_pc", &pm8921_vs_pc_ops, 0),
-	VREG_DESC(LVS3_PC, "8921_lvs3_pc", &pm8921_vs_pc_ops, 0),
-	VREG_DESC(LVS4_PC, "8921_lvs4_pc", &pm8921_vs_pc_ops, 0),
-	VREG_DESC(LVS5_PC, "8921_lvs5_pc", &pm8921_vs_pc_ops, 0),
-	VREG_DESC(LVS6_PC, "8921_lvs6_pc", &pm8921_vs_pc_ops, 0),
-	VREG_DESC(LVS7_PC, "8921_lvs7_pc", &pm8921_vs_pc_ops, 0),
-};
-
-static int pm8921_init_ldo(struct pm8921_vreg *vreg, bool is_real)
-{
-	int rc = 0;
-	int i;
-	u8 bank;
-
-	/* Save the current control register state. */
-	rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
-	if (rc)
-		goto bail;
-
-	/* Save the current test register state. */
-	for (i = 0; i < LDO_TEST_BANKS; i++) {
-		bank = REGULATOR_BANK_SEL(i);
-		rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
-		if (rc)
-			goto bail;
-
-		rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
-				  &vreg->test_reg[i]);
-		if (rc)
-			goto bail;
-		vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
-	}
-
-	if (is_real) {
-		/* Set pull down enable based on platform data. */
-		rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
-		      (vreg->pdata.pull_down_enable ? LDO_PULL_DOWN_ENABLE : 0),
-		      LDO_PULL_DOWN_ENABLE_MASK, &vreg->ctrl_reg);
-
-		vreg->is_enabled = !!_pm8921_vreg_is_enabled(vreg);
-
-		vreg->mode = ((vreg->ctrl_reg & LDO_CTRL_PM_MASK)
-					== LDO_CTRL_PM_LPM ?
-				REGULATOR_MODE_IDLE : REGULATOR_MODE_NORMAL);
-	}
-bail:
-	if (rc)
-		vreg_err(vreg, "pm8xxx_readb/writeb failed, rc=%d\n", rc);
-
-	return rc;
-}
-
-static int pm8921_init_nldo1200(struct pm8921_vreg *vreg)
-{
-	int rc = 0;
-	int i;
-	u8 bank;
-
-	/* Save the current control register state. */
-	rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
-	if (rc)
-		goto bail;
-
-	/* Save the current test register state. */
-	for (i = 0; i < LDO_TEST_BANKS; i++) {
-		bank = REGULATOR_BANK_SEL(i);
-		rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
-		if (rc)
-			goto bail;
-
-		rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
-				  &vreg->test_reg[i]);
-		if (rc)
-			goto bail;
-		vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
-	}
-
-	vreg->save_uV = _pm8921_nldo1200_get_voltage(vreg);
-
-	/* Set pull down enable based on platform data. */
-	rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
-		 (vreg->pdata.pull_down_enable ? NLDO1200_PULL_DOWN_ENABLE : 0)
-		 | REGULATOR_BANK_SEL(1) | REGULATOR_BANK_WRITE,
-		 NLDO1200_PULL_DOWN_ENABLE_MASK | REGULATOR_BANK_MASK,
-		 &vreg->test_reg[1]);
-
-bail:
-	if (rc)
-		vreg_err(vreg, "pm8xxx_readb/writeb failed, rc=%d\n", rc);
-
-	return rc;
-}
-
-static int pm8921_init_smps(struct pm8921_vreg *vreg, bool is_real)
-{
-	int rc = 0;
-	int i;
-	u8 bank;
-
-	/* Save the current control register state. */
-	rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
-	if (rc)
-		goto bail;
-
-	/* Save the current test2 register state. */
-	for (i = 0; i < SMPS_TEST_BANKS; i++) {
-		bank = REGULATOR_BANK_SEL(i);
-		rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
-		if (rc)
-			goto bail;
-
-		rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
-				  &vreg->test_reg[i]);
-		if (rc)
-			goto bail;
-		vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
-	}
-
-	/* Save the current clock control register state. */
-	rc = pm8xxx_readb(vreg->dev->parent, vreg->clk_ctrl_addr,
-			  &vreg->clk_ctrl_reg);
-	if (rc)
-		goto bail;
-
-	/* Save the current sleep control register state. */
-	rc = pm8xxx_readb(vreg->dev->parent, vreg->sleep_ctrl_addr,
-			  &vreg->sleep_ctrl_reg);
-	if (rc)
-		goto bail;
-
-	vreg->save_uV = _pm8921_smps_get_voltage(vreg);
-
-	if (is_real) {
-		/* Set advanced mode pull down enable based on platform data. */
-		rc = pm8921_vreg_masked_write(vreg, vreg->test_addr,
-			(vreg->pdata.pull_down_enable
-				? SMPS_ADVANCED_PULL_DOWN_ENABLE : 0)
-			| REGULATOR_BANK_SEL(6) | REGULATOR_BANK_WRITE,
-			REGULATOR_BANK_MASK | SMPS_ADVANCED_PULL_DOWN_ENABLE,
-			&vreg->test_reg[6]);
-		if (rc)
-			goto bail;
-
-		vreg->is_enabled = !!_pm8921_vreg_is_enabled(vreg);
-
-		vreg->mode = ((vreg->clk_ctrl_reg & SMPS_CLK_CTRL_MASK)
-					== SMPS_CLK_CTRL_PFM ?
-				REGULATOR_MODE_IDLE : REGULATOR_MODE_NORMAL);
-	}
-
-	if (!SMPS_IN_ADVANCED_MODE(vreg) && is_real) {
-		/* Set legacy mode pull down enable based on platform data. */
-		rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
-			(vreg->pdata.pull_down_enable
-				? SMPS_LEGACY_PULL_DOWN_ENABLE : 0),
-			SMPS_LEGACY_PULL_DOWN_ENABLE, &vreg->ctrl_reg);
-		if (rc)
-			goto bail;
-	}
-
-bail:
-	if (rc)
-		vreg_err(vreg, "pm8xxx_readb/writeb failed, rc=%d\n", rc);
-
-	return rc;
-}
-
-static int pm8921_init_ftsmps(struct pm8921_vreg *vreg)
-{
-	int rc, i;
-	u8 bank;
-
-	/* Save the current control register state. */
-	rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
-	if (rc)
-		goto bail;
-
-	/* Store current regulator register values. */
-	rc = pm8xxx_readb(vreg->dev->parent, vreg->pfm_ctrl_addr,
-			  &vreg->pfm_ctrl_reg);
-	if (rc)
-		goto bail;
-
-	rc = pm8xxx_readb(vreg->dev->parent, vreg->pwr_cnfg_addr,
-			  &vreg->pwr_cnfg_reg);
-	if (rc)
-		goto bail;
-
-	/* Save the current fts_cnfg1 register state (uses 'test' member). */
-	for (i = 0; i < SMPS_TEST_BANKS; i++) {
-		bank = REGULATOR_BANK_SEL(i);
-		rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
-		if (rc)
-			goto bail;
-
-		rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
-				  &vreg->test_reg[i]);
-		if (rc)
-			goto bail;
-		vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
-	}
-
-	vreg->save_uV = _pm8921_ftsmps_get_voltage(vreg);
-
-	/* Set pull down enable based on platform data. */
-	rc = pm8921_vreg_masked_write(vreg, vreg->pwr_cnfg_addr,
-		(vreg->pdata.pull_down_enable ? FTSMPS_PULL_DOWN_ENABLE : 0),
-		FTSMPS_PULL_DOWN_ENABLE_MASK, &vreg->pwr_cnfg_reg);
-
-bail:
-	if (rc)
-		vreg_err(vreg, "pm8xxx_readb/writeb failed, rc=%d\n", rc);
-
-	return rc;
-}
-
-static int pm8921_init_vs(struct pm8921_vreg *vreg, bool is_real)
-{
-	int rc = 0;
-
-	/* Save the current control register state. */
-	rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
-	if (rc) {
-		vreg_err(vreg, "pm8xxx_readb failed, rc=%d\n", rc);
-		return rc;
-	}
-
-	if (is_real) {
-		/* Set pull down enable based on platform data. */
-		rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
-		       (vreg->pdata.pull_down_enable ? VS_PULL_DOWN_ENABLE
-						     : VS_PULL_DOWN_DISABLE),
-		       VS_PULL_DOWN_ENABLE_MASK, &vreg->ctrl_reg);
-
-		if (rc)
-			vreg_err(vreg,
-				"pm8921_vreg_masked_write failed, rc=%d\n", rc);
-
-		vreg->is_enabled = !!_pm8921_vreg_is_enabled(vreg);
-	}
-
-	return rc;
-}
-
-static int pm8921_init_vs300(struct pm8921_vreg *vreg)
-{
-	int rc;
-
-	/* Save the current control register state. */
-	rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
-	if (rc) {
-		vreg_err(vreg, "pm8xxx_readb failed, rc=%d\n", rc);
-		return rc;
-	}
-
-	/* Set pull down enable based on platform data. */
-	rc = pm8921_vreg_masked_write(vreg, vreg->ctrl_addr,
-		    (vreg->pdata.pull_down_enable ? VS300_PULL_DOWN_ENABLE : 0),
-		    VS300_PULL_DOWN_ENABLE_MASK, &vreg->ctrl_reg);
-
-	if (rc)
-		vreg_err(vreg, "pm8921_vreg_masked_write failed, rc=%d\n", rc);
-
-	return rc;
-}
-
-static int pm8921_init_ncp(struct pm8921_vreg *vreg)
-{
-	int rc;
-
-	/* Save the current control register state. */
-	rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
-	if (rc) {
-		vreg_err(vreg, "pm8xxx_readb failed, rc=%d\n", rc);
-		return rc;
-	}
-
-	return rc;
-}
-
-int pc_id_to_real_id(int id)
-{
-	int real_id;
-
-	if (id >= PM8921_VREG_ID_L1_PC && id <= PM8921_VREG_ID_L23_PC)
-		real_id = id - PM8921_VREG_ID_L1_PC;
-	else if (id >= PM8921_VREG_ID_L29_PC && id <= PM8921_VREG_ID_S4_PC)
-		real_id = id - PM8921_VREG_ID_L29_PC + PM8921_VREG_ID_L29;
-	else if (id >= PM8921_VREG_ID_S7_PC && id <= PM8921_VREG_ID_LVS1_PC)
-		real_id = id - PM8921_VREG_ID_S7_PC + PM8921_VREG_ID_S7;
-	else
-		real_id = id - PM8921_VREG_ID_LVS3_PC + PM8921_VREG_ID_LVS3;
-
-	return real_id;
-}
-
-static int __devinit pm8921_vreg_probe(struct platform_device *pdev)
-{
-	const struct pm8921_regulator_platform_data *pdata;
-	enum pm8921_vreg_pin_function pin_fn;
-	struct regulator_desc *rdesc;
-	struct pm8921_vreg *vreg;
-	const char *reg_name = "";
-	unsigned pin_ctrl;
-	int rc = 0, id = pdev->id;
-
-	if (pdev == NULL)
-		return -EINVAL;
-
-	if (pdev->id >= 0 && pdev->id < PM8921_VREG_ID_MAX) {
-		pdata = pdev->dev.platform_data;
-		rdesc = &pm8921_vreg_description[pdev->id];
-		if (!IS_REAL_REGULATOR(pdev->id))
-			id = pc_id_to_real_id(pdev->id);
-		vreg = &pm8921_vreg[id];
-		reg_name = pm8921_vreg_description[pdev->id].name;
-		if (!pdata) {
-			pr_err("%s requires platform data\n", reg_name);
-			return -EINVAL;
-		}
-
-		mutex_lock(&vreg->pc_lock);
-
-		if (IS_REAL_REGULATOR(pdev->id)) {
-			/* Do not modify pin control and pin function values. */
-			pin_ctrl = vreg->pdata.pin_ctrl;
-			pin_fn = vreg->pdata.pin_fn;
-			memcpy(&(vreg->pdata), pdata,
-				sizeof(struct pm8921_regulator_platform_data));
-			vreg->pdata.pin_ctrl = pin_ctrl;
-			vreg->pdata.pin_fn = pin_fn;
-			vreg->dev = &pdev->dev;
-			vreg->name = reg_name;
-		} else {
-			/* Pin control regulator */
-			if ((pdata->pin_ctrl &
-			   (PM8921_VREG_PIN_CTRL_D1 | PM8921_VREG_PIN_CTRL_A0
-			   | PM8921_VREG_PIN_CTRL_A1 | PM8921_VREG_PIN_CTRL_A2))
-			      == PM8921_VREG_PIN_CTRL_NONE) {
-				pr_err("%s: no pin control input specified\n",
-					reg_name);
-				mutex_unlock(&vreg->pc_lock);
-				return -EINVAL;
-			}
-			vreg->pdata.pin_ctrl = pdata->pin_ctrl;
-			vreg->pdata.pin_fn = pdata->pin_fn;
-			vreg->dev_pc = &pdev->dev;
-			if (!vreg->dev)
-				vreg->dev = &pdev->dev;
-			if (!vreg->name)
-				vreg->name = reg_name;
-		}
-
-		/* Initialize register values. */
-		switch (vreg->type) {
-		case REGULATOR_TYPE_PLDO:
-		case REGULATOR_TYPE_NLDO:
-			rc = pm8921_init_ldo(vreg, IS_REAL_REGULATOR(pdev->id));
-			break;
-		case REGULATOR_TYPE_NLDO1200:
-			rc = pm8921_init_nldo1200(vreg);
-			break;
-		case REGULATOR_TYPE_SMPS:
-			rc = pm8921_init_smps(vreg,
-						IS_REAL_REGULATOR(pdev->id));
-			break;
-		case REGULATOR_TYPE_FTSMPS:
-			rc = pm8921_init_ftsmps(vreg);
-			break;
-		case REGULATOR_TYPE_VS:
-			rc = pm8921_init_vs(vreg, IS_REAL_REGULATOR(pdev->id));
-			break;
-		case REGULATOR_TYPE_VS300:
-			rc = pm8921_init_vs300(vreg);
-			break;
-		case REGULATOR_TYPE_NCP:
-			rc = pm8921_init_ncp(vreg);
-			break;
-		}
-
-		mutex_unlock(&vreg->pc_lock);
-
-		if (rc)
-			goto bail;
-
-		if (IS_REAL_REGULATOR(pdev->id)) {
-			vreg->rdev = regulator_register(rdesc, &pdev->dev,
-					&(pdata->init_data), vreg);
-			if (IS_ERR(vreg->rdev)) {
-				rc = PTR_ERR(vreg->rdev);
-				vreg->rdev = NULL;
-				pr_err("regulator_register failed: %s, rc=%d\n",
-					reg_name, rc);
-			}
-		} else {
-			vreg->rdev_pc = regulator_register(rdesc, &pdev->dev,
-					&(pdata->init_data), vreg);
-			if (IS_ERR(vreg->rdev_pc)) {
-				rc = PTR_ERR(vreg->rdev_pc);
-				vreg->rdev_pc = NULL;
-				pr_err("regulator_register failed: %s, rc=%d\n",
-					reg_name, rc);
-			}
-		}
-		if ((pm8921_vreg_debug_mask & PM8921_VREG_DEBUG_INIT) && !rc
-		    && vreg->rdev)
-			pm8921_vreg_show_state(vreg->rdev,
-						PM8921_REGULATOR_ACTION_INIT);
-	} else {
-		rc = -ENODEV;
-	}
-
-bail:
-	if (rc)
-		pr_err("error for %s, rc=%d\n", reg_name, rc);
-
-	return rc;
-}
-
-static int __devexit pm8921_vreg_remove(struct platform_device *pdev)
-{
-	if (IS_REAL_REGULATOR(pdev->id))
-		regulator_unregister(pm8921_vreg[pdev->id].rdev);
-	else
-		regulator_unregister(
-			pm8921_vreg[pc_id_to_real_id(pdev->id)].rdev_pc);
-
-	return 0;
-}
-
-static struct platform_driver pm8921_vreg_driver = {
-	.probe	= pm8921_vreg_probe,
-	.remove	= __devexit_p(pm8921_vreg_remove),
-	.driver	= {
-		.name	= PM8921_REGULATOR_DEV_NAME,
-		.owner	= THIS_MODULE,
-	},
-};
-
-static int __init pm8921_vreg_init(void)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(pm8921_vreg); i++) {
-		mutex_init(&pm8921_vreg[i].pc_lock);
-		pm8921_vreg[i].write_count = 0;
-		pm8921_vreg[i].prev_write_count = -1;
-	}
-
-	return platform_driver_register(&pm8921_vreg_driver);
-}
-postcore_initcall(pm8921_vreg_init);
-
-static void __exit pm8921_vreg_exit(void)
-{
-	int i;
-
-	platform_driver_unregister(&pm8921_vreg_driver);
-
-	for (i = 0; i < ARRAY_SIZE(pm8921_vreg); i++)
-		mutex_destroy(&pm8921_vreg[i].pc_lock);
-}
-module_exit(pm8921_vreg_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("PMIC8921 regulator driver");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:" PM8921_REGULATOR_DEV_NAME);
diff --git a/drivers/regulator/pm8xxx-regulator.c b/drivers/regulator/pm8xxx-regulator.c
new file mode 100644
index 0000000..15a9cb1
--- /dev/null
+++ b/drivers/regulator/pm8xxx-regulator.c
@@ -0,0 +1,3065 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. 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 version 2 and
+ * only 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/mfd/pm8xxx/core.h>
+#include <linux/mfd/pm8xxx/regulator.h>
+
+/* Debug Flag Definitions */
+enum {
+	PM8XXX_VREG_DEBUG_REQUEST	= BIT(0),
+	PM8XXX_VREG_DEBUG_DUPLICATE	= BIT(1),
+	PM8XXX_VREG_DEBUG_INIT		= BIT(2),
+	PM8XXX_VREG_DEBUG_WRITES	= BIT(3), /* SSBI writes */
+};
+
+static int pm8xxx_vreg_debug_mask;
+module_param_named(
+	debug_mask, pm8xxx_vreg_debug_mask, int, S_IRUSR | S_IWUSR
+);
+
+/* Common Masks */
+#define REGULATOR_ENABLE_MASK		0x80
+#define REGULATOR_ENABLE		0x80
+#define REGULATOR_DISABLE		0x00
+
+#define REGULATOR_BANK_MASK		0xF0
+#define REGULATOR_BANK_SEL(n)		((n) << 4)
+#define REGULATOR_BANK_WRITE		0x80
+
+#define LDO_TEST_BANKS			7
+#define NLDO1200_TEST_BANKS		5
+#define SMPS_TEST_BANKS			8
+
+/*
+ * This voltage in uV is returned by get_voltage functions when there is no way
+ * to determine the current voltage level.  It is needed because the regulator
+ * framework treats a 0 uV voltage as an error.
+ */
+#define VOLTAGE_UNKNOWN			1
+
+/* LDO masks and values */
+
+/* CTRL register */
+#define LDO_ENABLE_MASK			0x80
+#define LDO_DISABLE			0x00
+#define LDO_ENABLE			0x80
+#define LDO_PULL_DOWN_ENABLE_MASK	0x40
+#define LDO_PULL_DOWN_ENABLE		0x40
+
+#define LDO_CTRL_PM_MASK		0x20
+#define LDO_CTRL_PM_HPM			0x00
+#define LDO_CTRL_PM_LPM			0x20
+
+#define LDO_CTRL_VPROG_MASK		0x1F
+
+/* TEST register bank 0 */
+#define LDO_TEST_LPM_MASK		0x04
+#define LDO_TEST_LPM_SEL_CTRL		0x00
+#define LDO_TEST_LPM_SEL_TCXO		0x04
+
+/* TEST register bank 2 */
+#define LDO_TEST_VPROG_UPDATE_MASK	0x08
+#define LDO_TEST_RANGE_SEL_MASK		0x04
+#define LDO_TEST_FINE_STEP_MASK		0x02
+#define LDO_TEST_FINE_STEP_SHIFT	1
+
+/* TEST register bank 4 */
+#define LDO_TEST_RANGE_EXT_MASK		0x01
+
+/* TEST register bank 5 */
+#define LDO_TEST_PIN_CTRL_MASK		0x0F
+#define LDO_TEST_PIN_CTRL_EN3		0x08
+#define LDO_TEST_PIN_CTRL_EN2		0x04
+#define LDO_TEST_PIN_CTRL_EN1		0x02
+#define LDO_TEST_PIN_CTRL_EN0		0x01
+
+/* TEST register bank 6 */
+#define LDO_TEST_PIN_CTRL_LPM_MASK	0x0F
+
+/*
+ * If a given voltage could be output by two ranges, then the preferred one must
+ * be determined by the range limits.  Specified voltage ranges should must
+ * not overlap.
+ *
+ * Allowable voltage ranges:
+ */
+#define PLDO_LOW_UV_MIN			750000
+#define PLDO_LOW_UV_MAX			1487500
+#define PLDO_LOW_UV_FINE_STEP		12500
+
+#define PLDO_NORM_UV_MIN		1500000
+#define PLDO_NORM_UV_MAX		3075000
+#define PLDO_NORM_UV_FINE_STEP		25000
+
+#define PLDO_HIGH_UV_MIN		1750000
+#define PLDO_HIGH_UV_SET_POINT_MIN	3100000
+#define PLDO_HIGH_UV_MAX		4900000
+#define PLDO_HIGH_UV_FINE_STEP		50000
+
+#define PLDO_LOW_SET_POINTS		((PLDO_LOW_UV_MAX - PLDO_LOW_UV_MIN) \
+						/ PLDO_LOW_UV_FINE_STEP + 1)
+#define PLDO_NORM_SET_POINTS		((PLDO_NORM_UV_MAX - PLDO_NORM_UV_MIN) \
+						/ PLDO_NORM_UV_FINE_STEP + 1)
+#define PLDO_HIGH_SET_POINTS		((PLDO_HIGH_UV_MAX \
+						- PLDO_HIGH_UV_SET_POINT_MIN) \
+					/ PLDO_HIGH_UV_FINE_STEP + 1)
+#define PLDO_SET_POINTS			(PLDO_LOW_SET_POINTS \
+						+ PLDO_NORM_SET_POINTS \
+						+ PLDO_HIGH_SET_POINTS)
+
+#define NLDO_UV_MIN			750000
+#define NLDO_UV_MAX			1537500
+#define NLDO_UV_FINE_STEP		12500
+
+#define NLDO_SET_POINTS			((NLDO_UV_MAX - NLDO_UV_MIN) \
+						/ NLDO_UV_FINE_STEP + 1)
+
+/* NLDO1200 masks and values */
+
+/* CTRL register */
+#define NLDO1200_ENABLE_MASK		0x80
+#define NLDO1200_DISABLE		0x00
+#define NLDO1200_ENABLE			0x80
+
+/* Legacy mode */
+#define NLDO1200_LEGACY_PM_MASK		0x20
+#define NLDO1200_LEGACY_PM_HPM		0x00
+#define NLDO1200_LEGACY_PM_LPM		0x20
+
+/* Advanced mode */
+#define NLDO1200_CTRL_RANGE_MASK	0x40
+#define NLDO1200_CTRL_RANGE_HIGH	0x00
+#define NLDO1200_CTRL_RANGE_LOW		0x40
+#define NLDO1200_CTRL_VPROG_MASK	0x3F
+
+#define NLDO1200_LOW_UV_MIN		375000
+#define NLDO1200_LOW_UV_MAX		743750
+#define NLDO1200_LOW_UV_STEP		6250
+
+#define NLDO1200_HIGH_UV_MIN		750000
+#define NLDO1200_HIGH_UV_MAX		1537500
+#define NLDO1200_HIGH_UV_STEP		12500
+
+#define NLDO1200_LOW_SET_POINTS		((NLDO1200_LOW_UV_MAX \
+						- NLDO1200_LOW_UV_MIN) \
+					/ NLDO1200_LOW_UV_STEP + 1)
+#define NLDO1200_HIGH_SET_POINTS	((NLDO1200_HIGH_UV_MAX \
+						- NLDO1200_HIGH_UV_MIN) \
+					/ NLDO1200_HIGH_UV_STEP + 1)
+#define NLDO1200_SET_POINTS		(NLDO1200_LOW_SET_POINTS \
+						+ NLDO1200_HIGH_SET_POINTS)
+
+/* TEST register bank 0 */
+#define NLDO1200_TEST_LPM_MASK		0x04
+#define NLDO1200_TEST_LPM_SEL_CTRL	0x00
+#define NLDO1200_TEST_LPM_SEL_TCXO	0x04
+
+/* TEST register bank 1 */
+#define NLDO1200_PULL_DOWN_ENABLE_MASK	0x02
+#define NLDO1200_PULL_DOWN_ENABLE	0x02
+
+/* TEST register bank 2 */
+#define NLDO1200_ADVANCED_MODE_MASK	0x08
+#define NLDO1200_ADVANCED_MODE		0x00
+#define NLDO1200_LEGACY_MODE		0x08
+
+/* Advanced mode power mode control */
+#define NLDO1200_ADVANCED_PM_MASK	0x02
+#define NLDO1200_ADVANCED_PM_HPM	0x00
+#define NLDO1200_ADVANCED_PM_LPM	0x02
+
+#define NLDO1200_IN_ADVANCED_MODE(vreg) \
+	((vreg->test_reg[2] & NLDO1200_ADVANCED_MODE_MASK) \
+	 == NLDO1200_ADVANCED_MODE)
+
+/* SMPS masks and values */
+
+/* CTRL register */
+
+/* Legacy mode */
+#define SMPS_LEGACY_ENABLE_MASK		0x80
+#define SMPS_LEGACY_DISABLE		0x00
+#define SMPS_LEGACY_ENABLE		0x80
+#define SMPS_LEGACY_PULL_DOWN_ENABLE	0x40
+#define SMPS_LEGACY_VREF_SEL_MASK	0x20
+#define SMPS_LEGACY_VPROG_MASK		0x1F
+
+/* Advanced mode */
+#define SMPS_ADVANCED_BAND_MASK		0xC0
+#define SMPS_ADVANCED_BAND_OFF		0x00
+#define SMPS_ADVANCED_BAND_1		0x40
+#define SMPS_ADVANCED_BAND_2		0x80
+#define SMPS_ADVANCED_BAND_3		0xC0
+#define SMPS_ADVANCED_VPROG_MASK	0x3F
+
+/* Legacy mode voltage ranges */
+#define SMPS_MODE3_UV_MIN		375000
+#define SMPS_MODE3_UV_MAX		725000
+#define SMPS_MODE3_UV_STEP		25000
+
+#define SMPS_MODE2_UV_MIN		750000
+#define SMPS_MODE2_UV_MAX		1475000
+#define SMPS_MODE2_UV_STEP		25000
+
+#define SMPS_MODE1_UV_MIN		1500000
+#define SMPS_MODE1_UV_MAX		3050000
+#define SMPS_MODE1_UV_STEP		50000
+
+#define SMPS_MODE3_SET_POINTS		((SMPS_MODE3_UV_MAX \
+						- SMPS_MODE3_UV_MIN) \
+					/ SMPS_MODE3_UV_STEP + 1)
+#define SMPS_MODE2_SET_POINTS		((SMPS_MODE2_UV_MAX \
+						- SMPS_MODE2_UV_MIN) \
+					/ SMPS_MODE2_UV_STEP + 1)
+#define SMPS_MODE1_SET_POINTS		((SMPS_MODE1_UV_MAX \
+						- SMPS_MODE1_UV_MIN) \
+					/ SMPS_MODE1_UV_STEP + 1)
+#define SMPS_LEGACY_SET_POINTS		(SMPS_MODE3_SET_POINTS \
+						+ SMPS_MODE2_SET_POINTS \
+						+ SMPS_MODE1_SET_POINTS)
+
+/* Advanced mode voltage ranges */
+#define SMPS_BAND1_UV_MIN		375000
+#define SMPS_BAND1_UV_MAX		737500
+#define SMPS_BAND1_UV_STEP		12500
+
+#define SMPS_BAND2_UV_MIN		750000
+#define SMPS_BAND2_UV_MAX		1487500
+#define SMPS_BAND2_UV_STEP		12500
+
+#define SMPS_BAND3_UV_MIN		1500000
+#define SMPS_BAND3_UV_MAX		3075000
+#define SMPS_BAND3_UV_STEP		25000
+
+#define SMPS_BAND1_SET_POINTS		((SMPS_BAND1_UV_MAX \
+						- SMPS_BAND1_UV_MIN) \
+					/ SMPS_BAND1_UV_STEP + 1)
+#define SMPS_BAND2_SET_POINTS		((SMPS_BAND2_UV_MAX \
+						- SMPS_BAND2_UV_MIN) \
+					/ SMPS_BAND2_UV_STEP + 1)
+#define SMPS_BAND3_SET_POINTS		((SMPS_BAND3_UV_MAX \
+						- SMPS_BAND3_UV_MIN) \
+					/ SMPS_BAND3_UV_STEP + 1)
+#define SMPS_ADVANCED_SET_POINTS	(SMPS_BAND1_SET_POINTS \
+						+ SMPS_BAND2_SET_POINTS \
+						+ SMPS_BAND3_SET_POINTS)
+
+/* Test2 register bank 1 */
+#define SMPS_LEGACY_VLOW_SEL_MASK	0x01
+
+/* Test2 register bank 6 */
+#define SMPS_ADVANCED_PULL_DOWN_ENABLE	0x08
+
+/* Test2 register bank 7 */
+#define SMPS_ADVANCED_MODE_MASK		0x02
+#define SMPS_ADVANCED_MODE		0x02
+#define SMPS_LEGACY_MODE		0x00
+
+#define SMPS_IN_ADVANCED_MODE(vreg) \
+	((vreg->test_reg[7] & SMPS_ADVANCED_MODE_MASK) == SMPS_ADVANCED_MODE)
+
+/* BUCK_SLEEP_CNTRL register */
+#define SMPS_PIN_CTRL_MASK		0xF0
+#define SMPS_PIN_CTRL_EN3		0x80
+#define SMPS_PIN_CTRL_EN2		0x40
+#define SMPS_PIN_CTRL_EN1		0x20
+#define SMPS_PIN_CTRL_EN0		0x10
+
+#define SMPS_PIN_CTRL_LPM_MASK		0x0F
+#define SMPS_PIN_CTRL_LPM_EN3		0x08
+#define SMPS_PIN_CTRL_LPM_EN2		0x04
+#define SMPS_PIN_CTRL_LPM_EN1		0x02
+#define SMPS_PIN_CTRL_LPM_EN0		0x01
+
+/* BUCK_CLOCK_CNTRL register */
+#define SMPS_CLK_DIVIDE2		0x40
+
+#define SMPS_CLK_CTRL_MASK		0x30
+#define SMPS_CLK_CTRL_FOLLOW_TCXO	0x00
+#define SMPS_CLK_CTRL_PWM		0x10
+#define SMPS_CLK_CTRL_PFM		0x20
+
+/* FTSMPS masks and values */
+
+/* CTRL register */
+#define FTSMPS_VCTRL_BAND_MASK		0xC0
+#define FTSMPS_VCTRL_BAND_OFF		0x00
+#define FTSMPS_VCTRL_BAND_1		0x40
+#define FTSMPS_VCTRL_BAND_2		0x80
+#define FTSMPS_VCTRL_BAND_3		0xC0
+#define FTSMPS_VCTRL_VPROG_MASK		0x3F
+
+#define FTSMPS_BAND1_UV_MIN		350000
+#define FTSMPS_BAND1_UV_MAX		650000
+/* 3 LSB's of program voltage must be 0 in band 1. */
+/* Logical step size */
+#define FTSMPS_BAND1_UV_LOG_STEP	50000
+/* Physical step size */
+#define FTSMPS_BAND1_UV_PHYS_STEP	6250
+
+#define FTSMPS_BAND2_UV_MIN		700000
+#define FTSMPS_BAND2_UV_MAX		1400000
+#define FTSMPS_BAND2_UV_STEP		12500
+
+#define FTSMPS_BAND3_UV_MIN		1400000
+#define FTSMPS_BAND3_UV_SET_POINT_MIN	1500000
+#define FTSMPS_BAND3_UV_MAX		3300000
+#define FTSMPS_BAND3_UV_STEP		50000
+
+#define FTSMPS_BAND1_SET_POINTS		((FTSMPS_BAND1_UV_MAX \
+						- FTSMPS_BAND1_UV_MIN) \
+					/ FTSMPS_BAND1_UV_LOG_STEP + 1)
+#define FTSMPS_BAND2_SET_POINTS		((FTSMPS_BAND2_UV_MAX \
+						- FTSMPS_BAND2_UV_MIN) \
+					/ FTSMPS_BAND2_UV_STEP + 1)
+#define FTSMPS_BAND3_SET_POINTS		((FTSMPS_BAND3_UV_MAX \
+					  - FTSMPS_BAND3_UV_SET_POINT_MIN) \
+					/ FTSMPS_BAND3_UV_STEP + 1)
+#define FTSMPS_SET_POINTS		(FTSMPS_BAND1_SET_POINTS \
+						+ FTSMPS_BAND2_SET_POINTS \
+						+ FTSMPS_BAND3_SET_POINTS)
+
+/* FTS_CNFG1 register bank 0 */
+#define FTSMPS_CNFG1_PM_MASK		0x0C
+#define FTSMPS_CNFG1_PM_PWM		0x00
+#define FTSMPS_CNFG1_PM_PFM		0x08
+
+/* PWR_CNFG register */
+#define FTSMPS_PULL_DOWN_ENABLE_MASK	0x40
+#define FTSMPS_PULL_DOWN_ENABLE		0x40
+
+/* VS masks and values */
+
+/* CTRL register */
+#define VS_ENABLE_MASK			0x80
+#define VS_DISABLE			0x00
+#define VS_ENABLE			0x80
+#define VS_PULL_DOWN_ENABLE_MASK	0x40
+#define VS_PULL_DOWN_DISABLE		0x40
+#define VS_PULL_DOWN_ENABLE		0x00
+
+#define VS_PIN_CTRL_MASK		0x0F
+#define VS_PIN_CTRL_EN0			0x08
+#define VS_PIN_CTRL_EN1			0x04
+#define VS_PIN_CTRL_EN2			0x02
+#define VS_PIN_CTRL_EN3			0x01
+
+/* VS300 masks and values */
+
+/* CTRL register */
+#define VS300_CTRL_ENABLE_MASK		0xC0
+#define VS300_CTRL_DISABLE		0x00
+#define VS300_CTRL_ENABLE		0x40
+
+#define VS300_PULL_DOWN_ENABLE_MASK	0x20
+#define VS300_PULL_DOWN_ENABLE		0x20
+
+/* NCP masks and values */
+
+/* CTRL register */
+#define NCP_ENABLE_MASK			0x80
+#define NCP_DISABLE			0x00
+#define NCP_ENABLE			0x80
+#define NCP_VPROG_MASK			0x1F
+
+#define NCP_UV_MIN			1500000
+#define NCP_UV_MAX			3050000
+#define NCP_UV_STEP			50000
+
+#define NCP_SET_POINTS			((NCP_UV_MAX - NCP_UV_MIN) \
+						/ NCP_UV_STEP + 1)
+
+#define vreg_err(vreg, fmt, ...) \
+	pr_err("%s: " fmt, vreg->rdesc.name, ##__VA_ARGS__)
+
+/* Determines which label to add to the print. */
+enum pm8xxx_regulator_action {
+	PM8XXX_REGULATOR_ACTION_INIT,
+	PM8XXX_REGULATOR_ACTION_ENABLE,
+	PM8XXX_REGULATOR_ACTION_DISABLE,
+	PM8XXX_REGULATOR_ACTION_VOLTAGE,
+	PM8XXX_REGULATOR_ACTION_MODE,
+	PM8XXX_REGULATOR_ACTION_PIN_CTRL,
+};
+
+/* Debug state printing */
+static void pm8xxx_vreg_show_state(struct regulator_dev *rdev,
+				   enum pm8xxx_regulator_action action);
+
+/*
+ * Perform a masked write to a PMIC register only if the new value differs
+ * from the last value written to the register.  This removes redundant
+ * register writing.
+ *
+ * No locking is required because registers are not shared between regulators.
+ */
+static int pm8xxx_vreg_masked_write(struct pm8xxx_vreg *vreg, u16 addr, u8 val,
+		u8 mask, u8 *reg_save)
+{
+	int rc = 0;
+	u8 reg;
+
+	reg = (*reg_save & ~mask) | (val & mask);
+	if (reg != *reg_save) {
+		rc = pm8xxx_writeb(vreg->dev->parent, addr, reg);
+
+		if (rc) {
+			pr_err("%s: pm8xxx_writeb failed; addr=0x%03X, rc=%d\n",
+				vreg->rdesc.name, addr, rc);
+		} else {
+			*reg_save = reg;
+			vreg->write_count++;
+			if (pm8xxx_vreg_debug_mask & PM8XXX_VREG_DEBUG_WRITES)
+				pr_info("%s: write(0x%03X)=0x%02X\n",
+					vreg->rdesc.name, addr, reg);
+		}
+	}
+
+	return rc;
+}
+
+/*
+ * Perform a masked write to a PMIC register without checking the previously
+ * written value.  This is needed for registers that must be rewritten even if
+ * the value hasn't changed in order for changes in other registers to take
+ * effect.
+ */
+static int pm8xxx_vreg_masked_write_forced(struct pm8xxx_vreg *vreg, u16 addr,
+		u8 val, u8 mask, u8 *reg_save)
+{
+	int rc = 0;
+	u8 reg;
+
+	reg = (*reg_save & ~mask) | (val & mask);
+	rc = pm8xxx_writeb(vreg->dev->parent, addr, reg);
+
+	if (rc) {
+		pr_err("%s: pm8xxx_writeb failed; addr=0x%03X, rc=%d\n",
+			vreg->rdesc.name, addr, rc);
+	} else {
+		*reg_save = reg;
+		vreg->write_count++;
+		if (pm8xxx_vreg_debug_mask & PM8XXX_VREG_DEBUG_WRITES)
+			pr_info("%s: write(0x%03X)=0x%02X\n", vreg->rdesc.name,
+				addr, reg);
+	}
+
+	return rc;
+}
+
+static int pm8xxx_vreg_is_pin_controlled(struct pm8xxx_vreg *vreg)
+{
+	int ret = 0;
+
+	switch (vreg->type) {
+	case PM8XXX_REGULATOR_TYPE_PLDO:
+	case PM8XXX_REGULATOR_TYPE_NLDO:
+		ret = ((vreg->test_reg[5] & LDO_TEST_PIN_CTRL_MASK) << 4)
+			| (vreg->test_reg[6] & LDO_TEST_PIN_CTRL_LPM_MASK);
+		break;
+	case PM8XXX_REGULATOR_TYPE_SMPS:
+		ret = vreg->sleep_ctrl_reg
+			& (SMPS_PIN_CTRL_MASK | SMPS_PIN_CTRL_LPM_MASK);
+		break;
+	case PM8XXX_REGULATOR_TYPE_VS:
+		ret = vreg->ctrl_reg & VS_PIN_CTRL_MASK;
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ * Returns the logical pin control enable state because the pin control options
+ * present in the hardware out of restart could be different from those desired
+ * by the consumer.
+ */
+static int pm8xxx_vreg_pin_control_is_enabled(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int enabled;
+
+	mutex_lock(&vreg->pc_lock);
+	enabled = vreg->is_enabled_pc;
+	mutex_unlock(&vreg->pc_lock);
+
+	return enabled;
+}
+
+/* Returns the physical enable state of the regulator. */
+static int _pm8xxx_vreg_is_enabled(struct pm8xxx_vreg *vreg)
+{
+	int rc = 0;
+
+	/*
+	 * All regulator types except advanced mode SMPS, FTSMPS, and VS300 have
+	 * enable bit in bit 7 of the control register.
+	 */
+	switch (vreg->type) {
+	case PM8XXX_REGULATOR_TYPE_FTSMPS:
+		if ((vreg->ctrl_reg & FTSMPS_VCTRL_BAND_MASK)
+		    != FTSMPS_VCTRL_BAND_OFF)
+			rc = 1;
+		break;
+	case PM8XXX_REGULATOR_TYPE_VS300:
+		if ((vreg->ctrl_reg & VS300_CTRL_ENABLE_MASK)
+		    != VS300_CTRL_DISABLE)
+			rc = 1;
+		break;
+	case PM8XXX_REGULATOR_TYPE_SMPS:
+		if (SMPS_IN_ADVANCED_MODE(vreg)) {
+			if ((vreg->ctrl_reg & SMPS_ADVANCED_BAND_MASK)
+			    != SMPS_ADVANCED_BAND_OFF)
+				rc = 1;
+			break;
+		}
+		/* Fall through for legacy mode SMPS. */
+	default:
+		if ((vreg->ctrl_reg & REGULATOR_ENABLE_MASK)
+		    == REGULATOR_ENABLE)
+			rc = 1;
+	}
+
+	return rc;
+}
+
+/*
+ * Returns the logical enable state of the regulator which may be different from
+ * the physical enable state thanks to HPM/LPM pin control.
+ */
+static int pm8xxx_vreg_is_enabled(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int enabled;
+
+	if (vreg->type == PM8XXX_REGULATOR_TYPE_PLDO
+	    || vreg->type == PM8XXX_REGULATOR_TYPE_NLDO
+	    || vreg->type == PM8XXX_REGULATOR_TYPE_SMPS
+	    || vreg->type == PM8XXX_REGULATOR_TYPE_VS) {
+		/* Pin controllable */
+		mutex_lock(&vreg->pc_lock);
+		enabled = vreg->is_enabled;
+		mutex_unlock(&vreg->pc_lock);
+	} else {
+		/* Not pin controlable */
+		enabled = _pm8xxx_vreg_is_enabled(vreg);
+	}
+
+	return enabled;
+}
+
+static int pm8xxx_pldo_get_voltage(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int vmin, fine_step;
+	u8 range_ext, range_sel, vprog, fine_step_reg;
+
+	mutex_lock(&vreg->pc_lock);
+
+	fine_step_reg = vreg->test_reg[2] & LDO_TEST_FINE_STEP_MASK;
+	range_sel = vreg->test_reg[2] & LDO_TEST_RANGE_SEL_MASK;
+	range_ext = vreg->test_reg[4] & LDO_TEST_RANGE_EXT_MASK;
+	vprog = vreg->ctrl_reg & LDO_CTRL_VPROG_MASK;
+
+	mutex_unlock(&vreg->pc_lock);
+
+	vprog = (vprog << 1) | (fine_step_reg >> LDO_TEST_FINE_STEP_SHIFT);
+
+	if (range_sel) {
+		/* low range mode */
+		fine_step = PLDO_LOW_UV_FINE_STEP;
+		vmin = PLDO_LOW_UV_MIN;
+	} else if (!range_ext) {
+		/* normal mode */
+		fine_step = PLDO_NORM_UV_FINE_STEP;
+		vmin = PLDO_NORM_UV_MIN;
+	} else {
+		/* high range mode */
+		fine_step = PLDO_HIGH_UV_FINE_STEP;
+		vmin = PLDO_HIGH_UV_MIN;
+	}
+
+	return fine_step * vprog + vmin;
+}
+
+static int pm8xxx_pldo_list_voltage(struct regulator_dev *rdev,
+				    unsigned selector)
+{
+	int uV;
+
+	if (selector >= PLDO_SET_POINTS)
+		return 0;
+
+	if (selector < PLDO_LOW_SET_POINTS)
+		uV = selector * PLDO_LOW_UV_FINE_STEP + PLDO_LOW_UV_MIN;
+	else if (selector < (PLDO_LOW_SET_POINTS + PLDO_NORM_SET_POINTS))
+		uV = (selector - PLDO_LOW_SET_POINTS) * PLDO_NORM_UV_FINE_STEP
+			+ PLDO_NORM_UV_MIN;
+	else
+		uV = (selector - PLDO_LOW_SET_POINTS - PLDO_NORM_SET_POINTS)
+				* PLDO_HIGH_UV_FINE_STEP
+			+ PLDO_HIGH_UV_SET_POINT_MIN;
+
+	return uV;
+}
+
+static int pm8xxx_pldo_set_voltage(struct regulator_dev *rdev, int min_uV,
+				   int max_uV, unsigned *selector)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc = 0, uV = min_uV;
+	int vmin;
+	unsigned vprog, fine_step;
+	u8 range_ext, range_sel, fine_step_reg, prev_reg;
+	bool reg_changed = false;
+
+	if (uV < PLDO_LOW_UV_MIN && max_uV >= PLDO_LOW_UV_MIN)
+		uV = PLDO_LOW_UV_MIN;
+
+	if (uV < PLDO_LOW_UV_MIN || uV > PLDO_HIGH_UV_MAX) {
+		vreg_err(vreg,
+			"request v=[%d, %d] is outside possible v=[%d, %d]\n",
+			 min_uV, max_uV, PLDO_LOW_UV_MIN, PLDO_HIGH_UV_MAX);
+		return -EINVAL;
+	}
+
+	if (uV > PLDO_NORM_UV_MAX) {
+		vmin = PLDO_HIGH_UV_MIN;
+		fine_step = PLDO_HIGH_UV_FINE_STEP;
+		range_ext = LDO_TEST_RANGE_EXT_MASK;
+		range_sel = 0;
+	} else if (uV > PLDO_LOW_UV_MAX) {
+		vmin = PLDO_NORM_UV_MIN;
+		fine_step = PLDO_NORM_UV_FINE_STEP;
+		range_ext = 0;
+		range_sel = 0;
+	} else {
+		vmin = PLDO_LOW_UV_MIN;
+		fine_step = PLDO_LOW_UV_FINE_STEP;
+		range_ext = 0;
+		range_sel = LDO_TEST_RANGE_SEL_MASK;
+	}
+
+	vprog = (uV - vmin + fine_step - 1) / fine_step;
+	uV = vprog * fine_step + vmin;
+	fine_step_reg = (vprog & 1) << LDO_TEST_FINE_STEP_SHIFT;
+	vprog >>= 1;
+
+	if (uV > max_uV) {
+		vreg_err(vreg,
+			"request v=[%d, %d] cannot be met by any set point\n",
+			min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	mutex_lock(&vreg->pc_lock);
+
+	/* Write fine step, range select and program voltage update. */
+	prev_reg = vreg->test_reg[2];
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+			fine_step_reg | range_sel | REGULATOR_BANK_SEL(2)
+			 | REGULATOR_BANK_WRITE | LDO_TEST_VPROG_UPDATE_MASK,
+			LDO_TEST_FINE_STEP_MASK | LDO_TEST_RANGE_SEL_MASK
+			 | REGULATOR_BANK_MASK | LDO_TEST_VPROG_UPDATE_MASK,
+			&vreg->test_reg[2]);
+	if (rc)
+		goto bail;
+	if (prev_reg != vreg->test_reg[2])
+		reg_changed = true;
+
+	/* Write range extension. */
+	prev_reg = vreg->test_reg[4];
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+			range_ext | REGULATOR_BANK_SEL(4)
+			 | REGULATOR_BANK_WRITE,
+			LDO_TEST_RANGE_EXT_MASK | REGULATOR_BANK_MASK,
+			&vreg->test_reg[4]);
+	if (rc)
+		goto bail;
+	if (prev_reg != vreg->test_reg[4])
+		reg_changed = true;
+
+	/* Write new voltage. */
+	if (reg_changed) {
+		/*
+		 * Force a CTRL register write even if the value hasn't changed.
+		 * This is neccessary because range select, range extension, and
+		 * fine step will not update until a value is written into the
+		 * control register.
+		 */
+		rc = pm8xxx_vreg_masked_write_forced(vreg, vreg->ctrl_addr,
+			vprog, LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
+	} else {
+		/* Only write to control register if new value is different. */
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, vprog,
+			LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
+	}
+bail:
+	mutex_unlock(&vreg->pc_lock);
+
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_VOLTAGE);
+
+	return rc;
+}
+
+static int pm8xxx_nldo_get_voltage(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	u8 vprog, fine_step_reg;
+
+	mutex_lock(&vreg->pc_lock);
+
+	fine_step_reg = vreg->test_reg[2] & LDO_TEST_FINE_STEP_MASK;
+	vprog = vreg->ctrl_reg & LDO_CTRL_VPROG_MASK;
+
+	mutex_unlock(&vreg->pc_lock);
+
+	vprog = (vprog << 1) | (fine_step_reg >> LDO_TEST_FINE_STEP_SHIFT);
+
+	return NLDO_UV_FINE_STEP * vprog + NLDO_UV_MIN;
+}
+
+static int pm8xxx_nldo_list_voltage(struct regulator_dev *rdev,
+				    unsigned selector)
+{
+	if (selector >= NLDO_SET_POINTS)
+		return 0;
+
+	return selector * NLDO_UV_FINE_STEP + NLDO_UV_MIN;
+}
+
+static int pm8xxx_nldo_set_voltage(struct regulator_dev *rdev, int min_uV,
+				   int max_uV, unsigned *selector)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	unsigned vprog, fine_step_reg, prev_reg;
+	int rc;
+	int uV = min_uV;
+
+	if (uV < NLDO_UV_MIN && max_uV >= NLDO_UV_MIN)
+		uV = NLDO_UV_MIN;
+
+	if (uV < NLDO_UV_MIN || uV > NLDO_UV_MAX) {
+		vreg_err(vreg,
+			"request v=[%d, %d] is outside possible v=[%d, %d]\n",
+			 min_uV, max_uV, NLDO_UV_MIN, NLDO_UV_MAX);
+		return -EINVAL;
+	}
+
+	vprog = (uV - NLDO_UV_MIN + NLDO_UV_FINE_STEP - 1) / NLDO_UV_FINE_STEP;
+	uV = vprog * NLDO_UV_FINE_STEP + NLDO_UV_MIN;
+	fine_step_reg = (vprog & 1) << LDO_TEST_FINE_STEP_SHIFT;
+	vprog >>= 1;
+
+	if (uV > max_uV) {
+		vreg_err(vreg,
+			"request v=[%d, %d] cannot be met by any set point\n",
+			min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	mutex_lock(&vreg->pc_lock);
+
+	/* Write fine step. */
+	prev_reg = vreg->test_reg[2];
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+			fine_step_reg | REGULATOR_BANK_SEL(2)
+			 | REGULATOR_BANK_WRITE | LDO_TEST_VPROG_UPDATE_MASK,
+			LDO_TEST_FINE_STEP_MASK | REGULATOR_BANK_MASK
+			 | LDO_TEST_VPROG_UPDATE_MASK,
+		       &vreg->test_reg[2]);
+	if (rc)
+		goto bail;
+
+	/* Write new voltage. */
+	if (prev_reg != vreg->test_reg[2]) {
+		/*
+		 * Force a CTRL register write even if the value hasn't changed.
+		 * This is neccessary because fine step will not update until a
+		 * value is written into the control register.
+		 */
+		rc = pm8xxx_vreg_masked_write_forced(vreg, vreg->ctrl_addr,
+			vprog, LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
+	} else {
+		/* Only write to control register if new value is different. */
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, vprog,
+			LDO_CTRL_VPROG_MASK, &vreg->ctrl_reg);
+	}
+bail:
+	mutex_unlock(&vreg->pc_lock);
+
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_VOLTAGE);
+
+	return rc;
+}
+
+static int _pm8xxx_nldo1200_get_voltage(struct pm8xxx_vreg *vreg)
+{
+	int uV = 0;
+	int vprog;
+
+	if (!NLDO1200_IN_ADVANCED_MODE(vreg)) {
+		pr_warn("%s: currently in legacy mode; voltage unknown.\n",
+			vreg->rdesc.name);
+		return vreg->save_uV;
+	}
+
+	vprog = vreg->ctrl_reg & NLDO1200_CTRL_VPROG_MASK;
+
+	if ((vreg->ctrl_reg & NLDO1200_CTRL_RANGE_MASK)
+	    == NLDO1200_CTRL_RANGE_LOW)
+		uV = vprog * NLDO1200_LOW_UV_STEP + NLDO1200_LOW_UV_MIN;
+	else
+		uV = vprog * NLDO1200_HIGH_UV_STEP + NLDO1200_HIGH_UV_MIN;
+
+	return uV;
+}
+
+static int pm8xxx_nldo1200_get_voltage(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+
+	return _pm8xxx_nldo1200_get_voltage(vreg);
+}
+
+static int pm8xxx_nldo1200_list_voltage(struct regulator_dev *rdev,
+					unsigned selector)
+{
+	int uV;
+
+	if (selector >= NLDO1200_SET_POINTS)
+		return 0;
+
+	if (selector < NLDO1200_LOW_SET_POINTS)
+		uV = selector * NLDO1200_LOW_UV_STEP + NLDO1200_LOW_UV_MIN;
+	else
+		uV = (selector - NLDO1200_LOW_SET_POINTS)
+				* NLDO1200_HIGH_UV_STEP
+			+ NLDO1200_HIGH_UV_MIN;
+
+	return uV;
+}
+
+static int _pm8xxx_nldo1200_set_voltage(struct pm8xxx_vreg *vreg, int min_uV,
+		int max_uV)
+{
+	u8 vprog, range;
+	int rc;
+	int uV = min_uV;
+
+	if (uV < NLDO1200_LOW_UV_MIN && max_uV >= NLDO1200_LOW_UV_MIN)
+		uV = NLDO1200_LOW_UV_MIN;
+
+	if (uV < NLDO1200_LOW_UV_MIN || uV > NLDO1200_HIGH_UV_MAX) {
+		vreg_err(vreg,
+			"request v=[%d, %d] is outside possible v=[%d, %d]\n",
+			 min_uV, max_uV, NLDO_UV_MIN, NLDO_UV_MAX);
+		return -EINVAL;
+	}
+
+	if (uV > NLDO1200_LOW_UV_MAX) {
+		vprog = (uV - NLDO1200_HIGH_UV_MIN + NLDO1200_HIGH_UV_STEP - 1)
+			/ NLDO1200_HIGH_UV_STEP;
+		uV = vprog * NLDO1200_HIGH_UV_STEP + NLDO1200_HIGH_UV_MIN;
+		vprog &= NLDO1200_CTRL_VPROG_MASK;
+		range = NLDO1200_CTRL_RANGE_HIGH;
+	} else {
+		vprog = (uV - NLDO1200_LOW_UV_MIN + NLDO1200_LOW_UV_STEP - 1)
+			/ NLDO1200_LOW_UV_STEP;
+		uV = vprog * NLDO1200_LOW_UV_STEP + NLDO1200_LOW_UV_MIN;
+		vprog &= NLDO1200_CTRL_VPROG_MASK;
+		range = NLDO1200_CTRL_RANGE_LOW;
+	}
+
+	if (uV > max_uV) {
+		vreg_err(vreg,
+			"request v=[%d, %d] cannot be met by any set point\n",
+			min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	/* Set to advanced mode */
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+		NLDO1200_ADVANCED_MODE | REGULATOR_BANK_SEL(2)
+		| REGULATOR_BANK_WRITE, NLDO1200_ADVANCED_MODE_MASK
+		| REGULATOR_BANK_MASK, &vreg->test_reg[2]);
+	if (rc)
+		goto bail;
+
+	/* Set voltage and range selection. */
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, vprog | range,
+			NLDO1200_CTRL_VPROG_MASK | NLDO1200_CTRL_RANGE_MASK,
+			&vreg->ctrl_reg);
+	if (rc)
+		goto bail;
+
+	vreg->save_uV = uV;
+
+bail:
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+
+	return rc;
+}
+
+static int pm8xxx_nldo1200_set_voltage(struct regulator_dev *rdev, int min_uV,
+				   int max_uV, unsigned *selector)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc;
+
+	rc = _pm8xxx_nldo1200_set_voltage(vreg, min_uV, max_uV);
+
+	if (!rc)
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_VOLTAGE);
+
+	return rc;
+}
+
+static int pm8xxx_smps_get_voltage_advanced(struct pm8xxx_vreg *vreg)
+{
+	u8 vprog, band;
+	int uV = 0;
+
+	vprog = vreg->ctrl_reg & SMPS_ADVANCED_VPROG_MASK;
+	band = vreg->ctrl_reg & SMPS_ADVANCED_BAND_MASK;
+
+	if (band == SMPS_ADVANCED_BAND_1)
+		uV = vprog * SMPS_BAND1_UV_STEP + SMPS_BAND1_UV_MIN;
+	else if (band == SMPS_ADVANCED_BAND_2)
+		uV = vprog * SMPS_BAND2_UV_STEP + SMPS_BAND2_UV_MIN;
+	else if (band == SMPS_ADVANCED_BAND_3)
+		uV = vprog * SMPS_BAND3_UV_STEP + SMPS_BAND3_UV_MIN;
+	else if (vreg->save_uV > 0)
+		uV = vreg->save_uV;
+	else
+		uV = VOLTAGE_UNKNOWN;
+
+	return uV;
+}
+
+static int pm8xxx_smps_get_voltage_legacy(struct pm8xxx_vreg *vreg)
+{
+	u8 vlow, vref, vprog;
+	int uV;
+
+	vlow = vreg->test_reg[1] & SMPS_LEGACY_VLOW_SEL_MASK;
+	vref = vreg->ctrl_reg & SMPS_LEGACY_VREF_SEL_MASK;
+	vprog = vreg->ctrl_reg & SMPS_LEGACY_VPROG_MASK;
+
+	if (vlow && vref) {
+		/* mode 3 */
+		uV = vprog * SMPS_MODE3_UV_STEP + SMPS_MODE3_UV_MIN;
+	} else if (vref) {
+		/* mode 2 */
+		uV = vprog * SMPS_MODE2_UV_STEP + SMPS_MODE2_UV_MIN;
+	} else {
+		/* mode 1 */
+		uV = vprog * SMPS_MODE1_UV_STEP + SMPS_MODE1_UV_MIN;
+	}
+
+	return uV;
+}
+
+static int _pm8xxx_smps_get_voltage(struct pm8xxx_vreg *vreg)
+{
+	if (SMPS_IN_ADVANCED_MODE(vreg))
+		return pm8xxx_smps_get_voltage_advanced(vreg);
+
+	return pm8xxx_smps_get_voltage_legacy(vreg);
+}
+
+static int pm8xxx_smps_list_voltage(struct regulator_dev *rdev,
+				    unsigned selector)
+{
+	int uV;
+
+	if (selector >= SMPS_ADVANCED_SET_POINTS)
+		return 0;
+
+	if (selector < SMPS_BAND1_SET_POINTS)
+		uV = selector * SMPS_BAND1_UV_STEP + SMPS_BAND1_UV_MIN;
+	else if (selector < (SMPS_BAND1_SET_POINTS + SMPS_BAND2_SET_POINTS))
+		uV = (selector - SMPS_BAND1_SET_POINTS) * SMPS_BAND2_UV_STEP
+			+ SMPS_BAND2_UV_MIN;
+	else
+		uV = (selector - SMPS_BAND1_SET_POINTS - SMPS_BAND2_SET_POINTS)
+				* SMPS_BAND3_UV_STEP
+			+ SMPS_BAND3_UV_MIN;
+
+	return uV;
+}
+
+static int pm8xxx_smps_get_voltage(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int uV;
+
+	mutex_lock(&vreg->pc_lock);
+	uV = _pm8xxx_smps_get_voltage(vreg);
+	mutex_unlock(&vreg->pc_lock);
+
+	return uV;
+}
+
+static int pm8xxx_smps_set_voltage_advanced(struct pm8xxx_vreg *vreg,
+					   int min_uV, int max_uV, int force_on)
+{
+	u8 vprog, band;
+	int rc;
+	int uV = min_uV;
+
+	if (uV < SMPS_BAND1_UV_MIN && max_uV >= SMPS_BAND1_UV_MIN)
+		uV = SMPS_BAND1_UV_MIN;
+
+	if (uV < SMPS_BAND1_UV_MIN || uV > SMPS_BAND3_UV_MAX) {
+		vreg_err(vreg,
+			"request v=[%d, %d] is outside possible v=[%d, %d]\n",
+			 min_uV, max_uV, SMPS_BAND1_UV_MIN, SMPS_BAND3_UV_MAX);
+		return -EINVAL;
+	}
+
+	if (uV > SMPS_BAND2_UV_MAX) {
+		vprog = (uV - SMPS_BAND3_UV_MIN + SMPS_BAND3_UV_STEP - 1)
+			/ SMPS_BAND3_UV_STEP;
+		band = SMPS_ADVANCED_BAND_3;
+		uV = SMPS_BAND3_UV_MIN + vprog * SMPS_BAND3_UV_STEP;
+	} else if (uV > SMPS_BAND1_UV_MAX) {
+		vprog = (uV - SMPS_BAND2_UV_MIN + SMPS_BAND2_UV_STEP - 1)
+			/ SMPS_BAND2_UV_STEP;
+		band = SMPS_ADVANCED_BAND_2;
+		uV = SMPS_BAND2_UV_MIN + vprog * SMPS_BAND2_UV_STEP;
+	} else {
+		vprog = (uV - SMPS_BAND1_UV_MIN + SMPS_BAND1_UV_STEP - 1)
+			/ SMPS_BAND1_UV_STEP;
+		band = SMPS_ADVANCED_BAND_1;
+		uV = SMPS_BAND1_UV_MIN + vprog * SMPS_BAND1_UV_STEP;
+	}
+
+	if (uV > max_uV) {
+		vreg_err(vreg,
+			"request v=[%d, %d] cannot be met by any set point\n",
+			min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	/* Do not set band if regulator currently disabled. */
+	if (!_pm8xxx_vreg_is_enabled(vreg) && !force_on)
+		band = SMPS_ADVANCED_BAND_OFF;
+
+	/* Set advanced mode bit to 1. */
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr, SMPS_ADVANCED_MODE
+		| REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(7),
+		SMPS_ADVANCED_MODE_MASK | REGULATOR_BANK_MASK,
+		&vreg->test_reg[7]);
+	if (rc)
+		goto bail;
+
+	/* Set voltage and voltage band. */
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, band | vprog,
+			SMPS_ADVANCED_BAND_MASK | SMPS_ADVANCED_VPROG_MASK,
+			&vreg->ctrl_reg);
+	if (rc)
+		goto bail;
+
+	vreg->save_uV = uV;
+
+bail:
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+
+	return rc;
+}
+
+static int pm8xxx_smps_set_voltage_legacy(struct pm8xxx_vreg *vreg, int min_uV,
+					  int max_uV)
+{
+	u8 vlow, vref, vprog, pd, en;
+	int rc;
+	int uV = min_uV;
+
+	if (uV < SMPS_MODE3_UV_MIN && max_uV >= SMPS_MODE3_UV_MIN)
+		uV = SMPS_MODE3_UV_MIN;
+
+	if (uV < SMPS_MODE3_UV_MIN || uV > SMPS_MODE1_UV_MAX) {
+		vreg_err(vreg,
+			"request v=[%d, %d] is outside possible v=[%d, %d]\n",
+			 min_uV, max_uV, SMPS_MODE3_UV_MIN, SMPS_MODE1_UV_MAX);
+		return -EINVAL;
+	}
+
+	if (uV > SMPS_MODE2_UV_MAX) {
+		vprog = (uV - SMPS_MODE1_UV_MIN + SMPS_MODE1_UV_STEP - 1)
+			/ SMPS_MODE1_UV_STEP;
+		vref = 0;
+		vlow = 0;
+		uV = SMPS_MODE1_UV_MIN + vprog * SMPS_MODE1_UV_STEP;
+	} else if (uV > SMPS_MODE3_UV_MAX) {
+		vprog = (uV - SMPS_MODE2_UV_MIN + SMPS_MODE2_UV_STEP - 1)
+			/ SMPS_MODE2_UV_STEP;
+		vref = SMPS_LEGACY_VREF_SEL_MASK;
+		vlow = 0;
+		uV = SMPS_MODE2_UV_MIN + vprog * SMPS_MODE2_UV_STEP;
+	} else {
+		vprog = (uV - SMPS_MODE3_UV_MIN + SMPS_MODE3_UV_STEP - 1)
+			/ SMPS_MODE3_UV_STEP;
+		vref = SMPS_LEGACY_VREF_SEL_MASK;
+		vlow = SMPS_LEGACY_VLOW_SEL_MASK;
+		uV = SMPS_MODE3_UV_MIN + vprog * SMPS_MODE3_UV_STEP;
+	}
+
+	if (uV > max_uV) {
+		vreg_err(vreg,
+			"request v=[%d, %d] cannot be met by any set point\n",
+			min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	/* set vlow bit for ultra low voltage mode */
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+		vlow | REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(1),
+		REGULATOR_BANK_MASK | SMPS_LEGACY_VLOW_SEL_MASK,
+		&vreg->test_reg[1]);
+	if (rc)
+		goto bail;
+
+	/* Set advanced mode bit to 0. */
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr, SMPS_LEGACY_MODE
+		| REGULATOR_BANK_WRITE | REGULATOR_BANK_SEL(7),
+		SMPS_ADVANCED_MODE_MASK | REGULATOR_BANK_MASK,
+		&vreg->test_reg[7]);
+	if (rc)
+		goto bail;
+
+	en = (_pm8xxx_vreg_is_enabled(vreg) ? SMPS_LEGACY_ENABLE : 0);
+	pd = (vreg->pdata.pull_down_enable ? SMPS_LEGACY_PULL_DOWN_ENABLE : 0);
+
+	/* Set voltage (and the rest of the control register). */
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+		en | pd | vref | vprog,
+		SMPS_LEGACY_ENABLE_MASK | SMPS_LEGACY_PULL_DOWN_ENABLE
+		  | SMPS_LEGACY_VREF_SEL_MASK | SMPS_LEGACY_VPROG_MASK,
+		&vreg->ctrl_reg);
+
+	vreg->save_uV = uV;
+
+bail:
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+
+	return rc;
+}
+
+static int pm8xxx_smps_set_voltage(struct regulator_dev *rdev, int min_uV,
+				   int max_uV, unsigned *selector)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc = 0;
+
+	mutex_lock(&vreg->pc_lock);
+
+	if (SMPS_IN_ADVANCED_MODE(vreg) || !pm8xxx_vreg_is_pin_controlled(vreg))
+		rc = pm8xxx_smps_set_voltage_advanced(vreg, min_uV, max_uV, 0);
+	else
+		rc = pm8xxx_smps_set_voltage_legacy(vreg, min_uV, max_uV);
+
+	mutex_unlock(&vreg->pc_lock);
+
+	if (!rc)
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_VOLTAGE);
+
+	return rc;
+}
+
+static int _pm8xxx_ftsmps_get_voltage(struct pm8xxx_vreg *vreg)
+{
+	u8 vprog, band;
+	int uV = 0;
+
+	if ((vreg->test_reg[0] & FTSMPS_CNFG1_PM_MASK) == FTSMPS_CNFG1_PM_PFM) {
+		vprog = vreg->pfm_ctrl_reg & FTSMPS_VCTRL_VPROG_MASK;
+		band = vreg->pfm_ctrl_reg & FTSMPS_VCTRL_BAND_MASK;
+		if (band == FTSMPS_VCTRL_BAND_OFF && vprog == 0) {
+			/* PWM_VCTRL overrides PFM_VCTRL */
+			vprog = vreg->ctrl_reg & FTSMPS_VCTRL_VPROG_MASK;
+			band = vreg->ctrl_reg & FTSMPS_VCTRL_BAND_MASK;
+		}
+	} else {
+		vprog = vreg->ctrl_reg & FTSMPS_VCTRL_VPROG_MASK;
+		band = vreg->ctrl_reg & FTSMPS_VCTRL_BAND_MASK;
+	}
+
+	if (band == FTSMPS_VCTRL_BAND_1)
+		uV = vprog * FTSMPS_BAND1_UV_PHYS_STEP + FTSMPS_BAND1_UV_MIN;
+	else if (band == FTSMPS_VCTRL_BAND_2)
+		uV = vprog * FTSMPS_BAND2_UV_STEP + FTSMPS_BAND2_UV_MIN;
+	else if (band == FTSMPS_VCTRL_BAND_3)
+		uV = vprog * FTSMPS_BAND3_UV_STEP + FTSMPS_BAND3_UV_MIN;
+	else if (vreg->save_uV > 0)
+		uV = vreg->save_uV;
+	else
+		uV = VOLTAGE_UNKNOWN;
+
+	return uV;
+}
+
+static int pm8xxx_ftsmps_get_voltage(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+
+	return _pm8xxx_ftsmps_get_voltage(vreg);
+}
+
+static int pm8xxx_ftsmps_list_voltage(struct regulator_dev *rdev,
+				      unsigned selector)
+{
+	int uV;
+
+	if (selector >= FTSMPS_SET_POINTS)
+		return 0;
+
+	if (selector < FTSMPS_BAND1_SET_POINTS)
+		uV = selector * FTSMPS_BAND1_UV_LOG_STEP + FTSMPS_BAND1_UV_MIN;
+	else if (selector < (FTSMPS_BAND1_SET_POINTS + FTSMPS_BAND2_SET_POINTS))
+		uV = (selector - FTSMPS_BAND1_SET_POINTS) * FTSMPS_BAND2_UV_STEP
+			+ FTSMPS_BAND2_UV_MIN;
+	else
+		uV = (selector - FTSMPS_BAND1_SET_POINTS
+			- FTSMPS_BAND2_SET_POINTS)
+				* FTSMPS_BAND3_UV_STEP
+			+ FTSMPS_BAND3_UV_SET_POINT_MIN;
+
+	return uV;
+}
+
+static int _pm8xxx_ftsmps_set_voltage(struct pm8xxx_vreg *vreg, int min_uV,
+				      int max_uV, int force_on)
+{
+	int rc = 0;
+	u8 vprog, band;
+	int uV = min_uV;
+
+	if (uV < FTSMPS_BAND1_UV_MIN && max_uV >= FTSMPS_BAND1_UV_MIN)
+		uV = FTSMPS_BAND1_UV_MIN;
+
+	if (uV < FTSMPS_BAND1_UV_MIN || uV > FTSMPS_BAND3_UV_MAX) {
+		vreg_err(vreg,
+			"request v=[%d, %d] is outside possible v=[%d, %d]\n",
+			 min_uV, max_uV, FTSMPS_BAND1_UV_MIN,
+			 FTSMPS_BAND3_UV_MAX);
+		return -EINVAL;
+	}
+
+	/* Round up for set points in the gaps between bands. */
+	if (uV > FTSMPS_BAND1_UV_MAX && uV < FTSMPS_BAND2_UV_MIN)
+		uV = FTSMPS_BAND2_UV_MIN;
+	else if (uV > FTSMPS_BAND2_UV_MAX
+			&& uV < FTSMPS_BAND3_UV_SET_POINT_MIN)
+		uV = FTSMPS_BAND3_UV_SET_POINT_MIN;
+
+	if (uV > FTSMPS_BAND2_UV_MAX) {
+		vprog = (uV - FTSMPS_BAND3_UV_MIN + FTSMPS_BAND3_UV_STEP - 1)
+			/ FTSMPS_BAND3_UV_STEP;
+		band = FTSMPS_VCTRL_BAND_3;
+		uV = FTSMPS_BAND3_UV_MIN + vprog * FTSMPS_BAND3_UV_STEP;
+	} else if (uV > FTSMPS_BAND1_UV_MAX) {
+		vprog = (uV - FTSMPS_BAND2_UV_MIN + FTSMPS_BAND2_UV_STEP - 1)
+			/ FTSMPS_BAND2_UV_STEP;
+		band = FTSMPS_VCTRL_BAND_2;
+		uV = FTSMPS_BAND2_UV_MIN + vprog * FTSMPS_BAND2_UV_STEP;
+	} else {
+		vprog = (uV - FTSMPS_BAND1_UV_MIN
+				+ FTSMPS_BAND1_UV_LOG_STEP - 1)
+			/ FTSMPS_BAND1_UV_LOG_STEP;
+		uV = FTSMPS_BAND1_UV_MIN + vprog * FTSMPS_BAND1_UV_LOG_STEP;
+		vprog *= FTSMPS_BAND1_UV_LOG_STEP / FTSMPS_BAND1_UV_PHYS_STEP;
+		band = FTSMPS_VCTRL_BAND_1;
+	}
+
+	if (uV > max_uV) {
+		vreg_err(vreg,
+			"request v=[%d, %d] cannot be met by any set point\n",
+			min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	/*
+	 * Do not set voltage if regulator is currently disabled because doing
+	 * so will enable it.
+	 */
+	if (_pm8xxx_vreg_is_enabled(vreg) || force_on) {
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+			band | vprog,
+			FTSMPS_VCTRL_BAND_MASK | FTSMPS_VCTRL_VPROG_MASK,
+			&vreg->ctrl_reg);
+		if (rc)
+			goto bail;
+
+		/* Program PFM_VCTRL as 0x00 so that PWM_VCTRL overrides it. */
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->pfm_ctrl_addr, 0x00,
+			FTSMPS_VCTRL_BAND_MASK | FTSMPS_VCTRL_VPROG_MASK,
+			&vreg->pfm_ctrl_reg);
+		if (rc)
+			goto bail;
+	}
+
+	vreg->save_uV = uV;
+
+bail:
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+
+	return rc;
+}
+
+static int pm8xxx_ftsmps_set_voltage(struct regulator_dev *rdev, int min_uV,
+				     int max_uV, unsigned *selector)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc;
+
+	rc = _pm8xxx_ftsmps_set_voltage(vreg, min_uV, max_uV, 0);
+
+	if (!rc)
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_VOLTAGE);
+
+	return rc;
+}
+
+static int pm8xxx_ncp_get_voltage(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	u8 vprog;
+
+	vprog = vreg->ctrl_reg & NCP_VPROG_MASK;
+
+	return NCP_UV_MIN + vprog * NCP_UV_STEP;
+}
+
+static int pm8xxx_ncp_list_voltage(struct regulator_dev *rdev,
+				   unsigned selector)
+{
+	if (selector >= NCP_SET_POINTS)
+		return 0;
+
+	return selector * NCP_UV_STEP + NCP_UV_MIN;
+}
+
+static int pm8xxx_ncp_set_voltage(struct regulator_dev *rdev, int min_uV,
+				  int max_uV, unsigned *selector)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc;
+	int uV = min_uV;
+	u8 val;
+
+	if (uV < NCP_UV_MIN && max_uV >= NCP_UV_MIN)
+		uV = NCP_UV_MIN;
+
+	if (uV < NCP_UV_MIN || uV > NCP_UV_MAX) {
+		vreg_err(vreg,
+			"request v=[%d, %d] is outside possible v=[%d, %d]\n",
+			 min_uV, max_uV, NCP_UV_MIN, NCP_UV_MAX);
+		return -EINVAL;
+	}
+
+	val = (uV - NCP_UV_MIN + NCP_UV_STEP - 1) / NCP_UV_STEP;
+	uV = val * NCP_UV_STEP + NCP_UV_MIN;
+
+	if (uV > max_uV) {
+		vreg_err(vreg,
+			"request v=[%d, %d] cannot be met by any set point\n",
+			min_uV, max_uV);
+		return -EINVAL;
+	}
+
+	/* voltage setting */
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, val,
+			NCP_VPROG_MASK, &vreg->ctrl_reg);
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_VOLTAGE);
+
+	return rc;
+}
+
+static unsigned int pm8xxx_ldo_get_mode(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	unsigned int mode = 0;
+
+	mutex_lock(&vreg->pc_lock);
+	mode = vreg->mode;
+	mutex_unlock(&vreg->pc_lock);
+
+	return mode;
+}
+
+static int pm8xxx_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc = 0;
+
+	if (mode != REGULATOR_MODE_NORMAL && mode != REGULATOR_MODE_IDLE) {
+		vreg_err(vreg, "invalid mode: %u\n", mode);
+		return -EINVAL;
+	}
+
+	mutex_lock(&vreg->pc_lock);
+
+	if (mode == REGULATOR_MODE_NORMAL
+	    || (vreg->is_enabled_pc
+		&& vreg->pdata.pin_fn == PM8XXX_VREG_PIN_FN_ENABLE)) {
+		/* HPM */
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+			LDO_CTRL_PM_HPM, LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
+	} else {
+		/* LPM */
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+			LDO_CTRL_PM_LPM, LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
+		if (rc)
+			goto bail;
+
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+			LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
+			  | REGULATOR_BANK_SEL(0),
+			LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK,
+			&vreg->test_reg[0]);
+	}
+
+bail:
+	if (!rc)
+		vreg->mode = mode;
+
+	mutex_unlock(&vreg->pc_lock);
+
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_MODE);
+
+	return rc;
+}
+
+static unsigned int pm8xxx_nldo1200_get_mode(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	unsigned int mode = 0;
+
+	if (NLDO1200_IN_ADVANCED_MODE(vreg)) {
+		/* Advanced mode */
+		if ((vreg->test_reg[2] & NLDO1200_ADVANCED_PM_MASK)
+		    == NLDO1200_ADVANCED_PM_LPM)
+			mode = REGULATOR_MODE_IDLE;
+		else
+			mode = REGULATOR_MODE_NORMAL;
+	} else {
+		/* Legacy mode */
+		if ((vreg->ctrl_reg & NLDO1200_LEGACY_PM_MASK)
+		    == NLDO1200_LEGACY_PM_LPM)
+			mode = REGULATOR_MODE_IDLE;
+		else
+			mode = REGULATOR_MODE_NORMAL;
+	}
+
+	return mode;
+}
+
+static int pm8xxx_nldo1200_set_mode(struct regulator_dev *rdev,
+				    unsigned int mode)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc = 0;
+
+	if (mode != REGULATOR_MODE_NORMAL && mode != REGULATOR_MODE_IDLE) {
+		vreg_err(vreg, "invalid mode: %u\n", mode);
+		return -EINVAL;
+	}
+
+	/*
+	 * Make sure that advanced mode is in use.  If it isn't, then set it
+	 * and update the voltage accordingly.
+	 */
+	if (!NLDO1200_IN_ADVANCED_MODE(vreg)) {
+		rc = _pm8xxx_nldo1200_set_voltage(vreg, vreg->save_uV,
+			vreg->save_uV);
+		if (rc)
+			goto bail;
+	}
+
+	if (mode == REGULATOR_MODE_NORMAL) {
+		/* HPM */
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+			NLDO1200_ADVANCED_PM_HPM | REGULATOR_BANK_WRITE
+			| REGULATOR_BANK_SEL(2), NLDO1200_ADVANCED_PM_MASK
+			| REGULATOR_BANK_MASK, &vreg->test_reg[2]);
+	} else {
+		/* LPM */
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+			NLDO1200_ADVANCED_PM_LPM | REGULATOR_BANK_WRITE
+			| REGULATOR_BANK_SEL(2), NLDO1200_ADVANCED_PM_MASK
+			| REGULATOR_BANK_MASK, &vreg->test_reg[2]);
+	}
+
+bail:
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_MODE);
+
+	return rc;
+}
+
+static unsigned int pm8xxx_smps_get_mode(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	unsigned int mode = 0;
+
+	mutex_lock(&vreg->pc_lock);
+	mode = vreg->mode;
+	mutex_unlock(&vreg->pc_lock);
+
+	return mode;
+}
+
+static int pm8xxx_smps_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc = 0;
+
+	if (mode != REGULATOR_MODE_NORMAL && mode != REGULATOR_MODE_IDLE) {
+		vreg_err(vreg, "invalid mode: %u\n", mode);
+		return -EINVAL;
+	}
+
+	mutex_lock(&vreg->pc_lock);
+
+	if (mode == REGULATOR_MODE_NORMAL
+	    || (vreg->is_enabled_pc
+		&& vreg->pdata.pin_fn == PM8XXX_VREG_PIN_FN_ENABLE)) {
+		/* HPM */
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
+				       SMPS_CLK_CTRL_PWM, SMPS_CLK_CTRL_MASK,
+				       &vreg->clk_ctrl_reg);
+	} else {
+		/* LPM */
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
+				       SMPS_CLK_CTRL_PFM, SMPS_CLK_CTRL_MASK,
+				       &vreg->clk_ctrl_reg);
+	}
+
+	if (!rc)
+		vreg->mode = mode;
+
+	mutex_unlock(&vreg->pc_lock);
+
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_MODE);
+
+	return rc;
+}
+
+static unsigned int pm8xxx_ftsmps_get_mode(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	unsigned int mode = 0;
+
+	if ((vreg->test_reg[0] & FTSMPS_CNFG1_PM_MASK) == FTSMPS_CNFG1_PM_PFM)
+		mode = REGULATOR_MODE_IDLE;
+	else
+		mode = REGULATOR_MODE_NORMAL;
+
+	return mode;
+}
+
+static int pm8xxx_ftsmps_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc = 0;
+
+	if (mode == REGULATOR_MODE_NORMAL) {
+		/* HPM */
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+				FTSMPS_CNFG1_PM_PWM | REGULATOR_BANK_WRITE
+				| REGULATOR_BANK_SEL(0), FTSMPS_CNFG1_PM_MASK
+				| REGULATOR_BANK_MASK, &vreg->test_reg[0]);
+	} else if (mode == REGULATOR_MODE_IDLE) {
+		/* LPM */
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+				FTSMPS_CNFG1_PM_PFM | REGULATOR_BANK_WRITE
+				| REGULATOR_BANK_SEL(0), FTSMPS_CNFG1_PM_MASK
+				| REGULATOR_BANK_MASK, &vreg->test_reg[0]);
+	} else {
+		vreg_err(vreg, "invalid mode: %u\n", mode);
+		return -EINVAL;
+	}
+
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_MODE);
+
+	return rc;
+}
+
+static unsigned int pm8xxx_vreg_get_optimum_mode(struct regulator_dev *rdev,
+		int input_uV, int output_uV, int load_uA)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	unsigned int mode;
+
+	if (load_uA + vreg->pdata.system_uA >= vreg->hpm_min_load)
+		mode = REGULATOR_MODE_NORMAL;
+	else
+		mode = REGULATOR_MODE_IDLE;
+
+	return mode;
+}
+
+static int pm8xxx_ldo_enable(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc, val;
+
+	mutex_lock(&vreg->pc_lock);
+
+	/*
+	 * Choose HPM if previously set to HPM or if pin control is enabled in
+	 * on/off mode.
+	 */
+	val = LDO_CTRL_PM_LPM;
+	if (vreg->mode == REGULATOR_MODE_NORMAL
+		|| (vreg->is_enabled_pc
+			&& vreg->pdata.pin_fn == PM8XXX_VREG_PIN_FN_ENABLE))
+		val = LDO_CTRL_PM_HPM;
+
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, val | LDO_ENABLE,
+		LDO_ENABLE_MASK | LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
+
+	if (!rc)
+		vreg->is_enabled = true;
+
+	mutex_unlock(&vreg->pc_lock);
+
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_ENABLE);
+
+	return rc;
+}
+
+static int pm8xxx_ldo_disable(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc;
+
+	mutex_lock(&vreg->pc_lock);
+
+	/*
+	 * Only disable the regulator if it isn't still required for HPM/LPM
+	 * pin control.
+	 */
+	if (!vreg->is_enabled_pc
+	    || vreg->pdata.pin_fn != PM8XXX_VREG_PIN_FN_MODE) {
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+			LDO_DISABLE, LDO_ENABLE_MASK, &vreg->ctrl_reg);
+		if (rc)
+			goto bail;
+	}
+
+	/* Change to LPM if HPM/LPM pin control is enabled. */
+	if (vreg->is_enabled_pc
+	    && vreg->pdata.pin_fn == PM8XXX_VREG_PIN_FN_MODE) {
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+			LDO_CTRL_PM_LPM, LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
+		if (rc)
+			goto bail;
+
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+			LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
+			  | REGULATOR_BANK_SEL(0),
+			LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK,
+			&vreg->test_reg[0]);
+	}
+
+	if (!rc)
+		vreg->is_enabled = false;
+bail:
+	mutex_unlock(&vreg->pc_lock);
+
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_DISABLE);
+
+	return rc;
+}
+
+static int pm8xxx_nldo1200_enable(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc;
+
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, NLDO1200_ENABLE,
+		NLDO1200_ENABLE_MASK, &vreg->ctrl_reg);
+
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_ENABLE);
+
+	return rc;
+}
+
+static int pm8xxx_nldo1200_disable(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc;
+
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, NLDO1200_DISABLE,
+		NLDO1200_ENABLE_MASK, &vreg->ctrl_reg);
+
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_DISABLE);
+
+	return rc;
+}
+
+static int pm8xxx_smps_enable(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc = 0;
+	int val;
+
+	mutex_lock(&vreg->pc_lock);
+
+	if (SMPS_IN_ADVANCED_MODE(vreg)
+	     || !pm8xxx_vreg_is_pin_controlled(vreg)) {
+		/* Enable in advanced mode if not using pin control. */
+		rc = pm8xxx_smps_set_voltage_advanced(vreg, vreg->save_uV,
+			vreg->save_uV, 1);
+	} else {
+		rc = pm8xxx_smps_set_voltage_legacy(vreg, vreg->save_uV,
+			vreg->save_uV);
+		if (rc)
+			goto bail;
+
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+			SMPS_LEGACY_ENABLE, SMPS_LEGACY_ENABLE_MASK,
+			&vreg->ctrl_reg);
+	}
+
+	/*
+	 * Choose HPM if previously set to HPM or if pin control is enabled in
+	 * on/off mode.
+	 */
+	val = SMPS_CLK_CTRL_PFM;
+	if (vreg->mode == REGULATOR_MODE_NORMAL
+		|| (vreg->is_enabled_pc
+			&& vreg->pdata.pin_fn == PM8XXX_VREG_PIN_FN_ENABLE))
+		val = SMPS_CLK_CTRL_PWM;
+
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->clk_ctrl_addr, val,
+			SMPS_CLK_CTRL_MASK, &vreg->clk_ctrl_reg);
+
+	if (!rc)
+		vreg->is_enabled = true;
+bail:
+	mutex_unlock(&vreg->pc_lock);
+
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_ENABLE);
+
+	return rc;
+}
+
+static int pm8xxx_smps_disable(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc;
+
+	mutex_lock(&vreg->pc_lock);
+
+	if (SMPS_IN_ADVANCED_MODE(vreg)) {
+		/* Change SMPS to legacy mode before disabling. */
+		rc = pm8xxx_smps_set_voltage_legacy(vreg, vreg->save_uV,
+				vreg->save_uV);
+		if (rc)
+			goto bail;
+	}
+
+	/*
+	 * Only disable the regulator if it isn't still required for HPM/LPM
+	 * pin control.
+	 */
+	if (!vreg->is_enabled_pc
+	    || vreg->pdata.pin_fn != PM8XXX_VREG_PIN_FN_MODE) {
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+			SMPS_LEGACY_DISABLE, SMPS_LEGACY_ENABLE_MASK,
+			&vreg->ctrl_reg);
+		if (rc)
+			goto bail;
+	}
+
+	/* Change to LPM if HPM/LPM pin control is enabled. */
+	if (vreg->is_enabled_pc
+	    && vreg->pdata.pin_fn == PM8XXX_VREG_PIN_FN_MODE)
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
+		       SMPS_CLK_CTRL_PFM, SMPS_CLK_CTRL_MASK,
+		       &vreg->clk_ctrl_reg);
+
+	if (!rc)
+		vreg->is_enabled = false;
+
+bail:
+	mutex_unlock(&vreg->pc_lock);
+
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_DISABLE);
+
+	return rc;
+}
+
+static int pm8xxx_ftsmps_enable(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc;
+
+	rc = _pm8xxx_ftsmps_set_voltage(vreg, vreg->save_uV, vreg->save_uV, 1);
+
+	if (rc)
+		vreg_err(vreg, "set voltage failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_ENABLE);
+
+	return rc;
+}
+
+static int pm8xxx_ftsmps_disable(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc;
+
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+		FTSMPS_VCTRL_BAND_OFF, FTSMPS_VCTRL_BAND_MASK, &vreg->ctrl_reg);
+	if (rc)
+		goto bail;
+
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->pfm_ctrl_addr,
+		FTSMPS_VCTRL_BAND_OFF, FTSMPS_VCTRL_BAND_MASK,
+		&vreg->pfm_ctrl_reg);
+bail:
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_DISABLE);
+
+	return rc;
+}
+
+static int pm8xxx_vs_enable(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc;
+
+	mutex_lock(&vreg->pc_lock);
+
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, VS_ENABLE,
+		VS_ENABLE_MASK, &vreg->ctrl_reg);
+
+	if (!rc)
+		vreg->is_enabled = true;
+
+	mutex_unlock(&vreg->pc_lock);
+
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_ENABLE);
+
+	return rc;
+}
+
+static int pm8xxx_vs_disable(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc;
+
+	mutex_lock(&vreg->pc_lock);
+
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, VS_DISABLE,
+		VS_ENABLE_MASK, &vreg->ctrl_reg);
+
+	if (!rc)
+		vreg->is_enabled = false;
+
+	mutex_unlock(&vreg->pc_lock);
+
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_DISABLE);
+
+	return rc;
+}
+
+static int pm8xxx_vs300_enable(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc;
+
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, VS300_CTRL_ENABLE,
+		VS300_CTRL_ENABLE_MASK, &vreg->ctrl_reg);
+
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_ENABLE);
+
+	return rc;
+}
+
+static int pm8xxx_vs300_disable(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc;
+
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, VS300_CTRL_DISABLE,
+		VS300_CTRL_ENABLE_MASK, &vreg->ctrl_reg);
+
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_DISABLE);
+
+	return rc;
+}
+
+static int pm8xxx_ncp_enable(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc;
+
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, NCP_ENABLE,
+		NCP_ENABLE_MASK, &vreg->ctrl_reg);
+
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_ENABLE);
+
+	return rc;
+}
+
+static int pm8xxx_ncp_disable(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc;
+
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, NCP_DISABLE,
+		NCP_ENABLE_MASK, &vreg->ctrl_reg);
+
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_DISABLE);
+
+	return rc;
+}
+
+static int pm8xxx_ldo_pin_control_enable(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc = 0;
+	int bank;
+	u8 val = 0;
+	u8 mask;
+
+	mutex_lock(&vreg->pc_lock);
+
+	if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN0)
+		val |= LDO_TEST_PIN_CTRL_EN0;
+	if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN1)
+		val |= LDO_TEST_PIN_CTRL_EN1;
+	if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN2)
+		val |= LDO_TEST_PIN_CTRL_EN2;
+	if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN3)
+		val |= LDO_TEST_PIN_CTRL_EN3;
+
+	bank = (vreg->pdata.pin_fn == PM8XXX_VREG_PIN_FN_ENABLE ? 5 : 6);
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+		val | REGULATOR_BANK_SEL(bank) | REGULATOR_BANK_WRITE,
+		LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
+		&vreg->test_reg[bank]);
+	if (rc)
+		goto bail;
+
+	/* Unset pin control bits in unused bank. */
+	bank = (bank == 5 ? 6 : 5);
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+		REGULATOR_BANK_SEL(bank) | REGULATOR_BANK_WRITE,
+		LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
+		&vreg->test_reg[bank]);
+	if (rc)
+		goto bail;
+
+	val = LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
+		| REGULATOR_BANK_SEL(0);
+	mask = LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK;
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr, val, mask,
+		&vreg->test_reg[0]);
+	if (rc)
+		goto bail;
+
+	if (vreg->pdata.pin_fn == PM8XXX_VREG_PIN_FN_ENABLE) {
+		/* Pin control ON/OFF */
+		val = LDO_CTRL_PM_HPM;
+		/* Leave physically enabled if already enabled. */
+		val |= (vreg->is_enabled ? LDO_ENABLE : LDO_DISABLE);
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, val,
+			LDO_ENABLE_MASK | LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
+		if (rc)
+			goto bail;
+	} else {
+		/* Pin control LPM/HPM */
+		val = LDO_ENABLE;
+		/* Leave in HPM if already enabled in HPM. */
+		val |= (vreg->is_enabled && vreg->mode == REGULATOR_MODE_NORMAL
+			?  LDO_CTRL_PM_HPM : LDO_CTRL_PM_LPM);
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, val,
+			LDO_ENABLE_MASK | LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
+		if (rc)
+			goto bail;
+	}
+
+bail:
+	if (!rc)
+		vreg->is_enabled_pc = true;
+
+	mutex_unlock(&vreg->pc_lock);
+
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_PIN_CTRL);
+
+	return rc;
+}
+
+static int pm8xxx_ldo_pin_control_disable(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc;
+
+	mutex_lock(&vreg->pc_lock);
+
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+			REGULATOR_BANK_SEL(5) | REGULATOR_BANK_WRITE,
+			LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
+			&vreg->test_reg[5]);
+	if (rc)
+		goto bail;
+
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+			REGULATOR_BANK_SEL(6) | REGULATOR_BANK_WRITE,
+			LDO_TEST_PIN_CTRL_MASK | REGULATOR_BANK_MASK,
+			&vreg->test_reg[6]);
+
+	/*
+	 * Physically disable the regulator if it was enabled in HPM/LPM pin
+	 * control mode previously and it logically should not be enabled.
+	 */
+	if ((vreg->ctrl_reg & LDO_ENABLE_MASK) == LDO_ENABLE
+	    && !vreg->is_enabled) {
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+			LDO_DISABLE, LDO_ENABLE_MASK, &vreg->ctrl_reg);
+		if (rc)
+			goto bail;
+	}
+
+	/* Change to LPM if LPM was enabled. */
+	if (vreg->is_enabled && vreg->mode == REGULATOR_MODE_IDLE) {
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+			LDO_CTRL_PM_LPM, LDO_CTRL_PM_MASK, &vreg->ctrl_reg);
+		if (rc)
+			goto bail;
+
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+			LDO_TEST_LPM_SEL_CTRL | REGULATOR_BANK_WRITE
+			  | REGULATOR_BANK_SEL(0),
+			LDO_TEST_LPM_MASK | REGULATOR_BANK_MASK,
+			&vreg->test_reg[0]);
+		if (rc)
+			goto bail;
+	}
+
+bail:
+	if (!rc)
+		vreg->is_enabled_pc = false;
+
+	mutex_unlock(&vreg->pc_lock);
+
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_PIN_CTRL);
+
+	return rc;
+}
+
+static int pm8xxx_smps_pin_control_enable(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc = 0;
+	u8 val = 0;
+
+	mutex_lock(&vreg->pc_lock);
+
+	if (vreg->pdata.pin_fn == PM8XXX_VREG_PIN_FN_ENABLE) {
+		/* Pin control ON/OFF */
+		if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN0)
+			val |= SMPS_PIN_CTRL_EN0;
+		if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN1)
+			val |= SMPS_PIN_CTRL_EN1;
+		if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN2)
+			val |= SMPS_PIN_CTRL_EN2;
+		if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN3)
+			val |= SMPS_PIN_CTRL_EN3;
+	} else {
+		/* Pin control LPM/HPM */
+		if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN0)
+			val |= SMPS_PIN_CTRL_LPM_EN0;
+		if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN1)
+			val |= SMPS_PIN_CTRL_LPM_EN1;
+		if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN2)
+			val |= SMPS_PIN_CTRL_LPM_EN2;
+		if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN3)
+			val |= SMPS_PIN_CTRL_LPM_EN3;
+	}
+
+	rc = pm8xxx_smps_set_voltage_legacy(vreg, vreg->save_uV, vreg->save_uV);
+	if (rc)
+		goto bail;
+
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->sleep_ctrl_addr, val,
+			SMPS_PIN_CTRL_MASK | SMPS_PIN_CTRL_LPM_MASK,
+			&vreg->sleep_ctrl_reg);
+	if (rc)
+		goto bail;
+
+	/*
+	 * Physically enable the regulator if using HPM/LPM pin control mode or
+	 * if the regulator should be logically left on.
+	 */
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+		((vreg->pdata.pin_fn == PM8XXX_VREG_PIN_FN_MODE
+		  || vreg->is_enabled) ?
+			SMPS_LEGACY_ENABLE : SMPS_LEGACY_DISABLE),
+		SMPS_LEGACY_ENABLE_MASK, &vreg->ctrl_reg);
+	if (rc)
+		goto bail;
+
+	/*
+	 * Set regulator to HPM if using on/off pin control or if the regulator
+	 * is already enabled in HPM.  Otherwise, set it to LPM.
+	 */
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
+			(vreg->pdata.pin_fn == PM8XXX_VREG_PIN_FN_ENABLE
+			 || (vreg->is_enabled
+			     && vreg->mode == REGULATOR_MODE_NORMAL)
+				? SMPS_CLK_CTRL_PWM : SMPS_CLK_CTRL_PFM),
+			SMPS_CLK_CTRL_MASK, &vreg->clk_ctrl_reg);
+
+bail:
+	if (!rc)
+		vreg->is_enabled_pc = true;
+
+	mutex_unlock(&vreg->pc_lock);
+
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_PIN_CTRL);
+
+	return rc;
+}
+
+static int pm8xxx_smps_pin_control_disable(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc;
+
+	mutex_lock(&vreg->pc_lock);
+
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->sleep_ctrl_addr, 0,
+			SMPS_PIN_CTRL_MASK | SMPS_PIN_CTRL_LPM_MASK,
+			&vreg->sleep_ctrl_reg);
+	if (rc)
+		goto bail;
+
+	/*
+	 * Physically disable the regulator if it was enabled in HPM/LPM pin
+	 * control mode previously and it logically should not be enabled.
+	 */
+	if ((vreg->ctrl_reg & SMPS_LEGACY_ENABLE_MASK) == SMPS_LEGACY_ENABLE
+	    && vreg->is_enabled == false) {
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+			SMPS_LEGACY_DISABLE, SMPS_LEGACY_ENABLE_MASK,
+			&vreg->ctrl_reg);
+		if (rc)
+			goto bail;
+	}
+
+	/* Change to LPM if LPM was enabled. */
+	if (vreg->is_enabled && vreg->mode == REGULATOR_MODE_IDLE) {
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->clk_ctrl_addr,
+		       SMPS_CLK_CTRL_PFM, SMPS_CLK_CTRL_MASK,
+		       &vreg->clk_ctrl_reg);
+		if (rc)
+			goto bail;
+	}
+
+	rc = pm8xxx_smps_set_voltage_advanced(vreg, vreg->save_uV,
+			vreg->save_uV, 0);
+
+bail:
+	if (!rc)
+		vreg->is_enabled_pc = false;
+
+	mutex_unlock(&vreg->pc_lock);
+
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_PIN_CTRL);
+
+	return rc;
+}
+
+static int pm8xxx_vs_pin_control_enable(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc;
+	u8 val = 0;
+
+	mutex_lock(&vreg->pc_lock);
+
+	if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN0)
+		val |= VS_PIN_CTRL_EN0;
+	if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN1)
+		val |= VS_PIN_CTRL_EN1;
+	if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN2)
+		val |= VS_PIN_CTRL_EN2;
+	if (vreg->pdata.pin_ctrl & PM8XXX_VREG_PIN_CTRL_EN3)
+		val |= VS_PIN_CTRL_EN3;
+
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, val,
+			VS_PIN_CTRL_MASK | VS_ENABLE_MASK, &vreg->ctrl_reg);
+
+	if (!rc)
+		vreg->is_enabled_pc = true;
+
+	mutex_unlock(&vreg->pc_lock);
+
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_PIN_CTRL);
+
+	return rc;
+}
+
+static int pm8xxx_vs_pin_control_disable(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int rc;
+
+	mutex_lock(&vreg->pc_lock);
+
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr, 0,
+				      VS_PIN_CTRL_MASK, &vreg->ctrl_reg);
+
+	if (!rc)
+		vreg->is_enabled_pc = false;
+
+	mutex_unlock(&vreg->pc_lock);
+
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+	else
+		pm8xxx_vreg_show_state(rdev, PM8XXX_REGULATOR_ACTION_PIN_CTRL);
+
+	return rc;
+}
+
+static int pm8xxx_enable_time(struct regulator_dev *rdev)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+
+	return vreg->pdata.enable_time;
+}
+
+static const char const *pm8xxx_print_actions[] = {
+	[PM8XXX_REGULATOR_ACTION_INIT]		= "initial    ",
+	[PM8XXX_REGULATOR_ACTION_ENABLE]	= "enable     ",
+	[PM8XXX_REGULATOR_ACTION_DISABLE]	= "disable    ",
+	[PM8XXX_REGULATOR_ACTION_VOLTAGE]	= "set voltage",
+	[PM8XXX_REGULATOR_ACTION_MODE]		= "set mode   ",
+	[PM8XXX_REGULATOR_ACTION_PIN_CTRL]	= "pin control",
+};
+
+static void pm8xxx_vreg_show_state(struct regulator_dev *rdev,
+				   enum pm8xxx_regulator_action action)
+{
+	struct pm8xxx_vreg *vreg = rdev_get_drvdata(rdev);
+	int uV, pc;
+	unsigned int mode;
+	const char *pc_en0 = "", *pc_en1 = "", *pc_en2 = "", *pc_en3 = "";
+	const char *pc_total = "";
+	const char *action_label = pm8xxx_print_actions[action];
+	const char *enable_label;
+
+	mutex_lock(&vreg->pc_lock);
+
+	/*
+	 * Do not print unless REQUEST is specified and SSBI writes have taken
+	 * place, or DUPLICATE is specified.
+	 */
+	if (!((pm8xxx_vreg_debug_mask & PM8XXX_VREG_DEBUG_DUPLICATE)
+	      || ((pm8xxx_vreg_debug_mask & PM8XXX_VREG_DEBUG_REQUEST)
+		  && (vreg->write_count != vreg->prev_write_count)))) {
+		mutex_unlock(&vreg->pc_lock);
+		return;
+	}
+
+	vreg->prev_write_count = vreg->write_count;
+
+	pc = vreg->pdata.pin_ctrl;
+	if (vreg->is_enabled_pc) {
+		if (pc & PM8XXX_VREG_PIN_CTRL_EN0)
+			pc_en0 = " EN0";
+		if (pc & PM8XXX_VREG_PIN_CTRL_EN1)
+			pc_en1 = " EN1";
+		if (pc & PM8XXX_VREG_PIN_CTRL_EN2)
+			pc_en2 = " EN2";
+		if (pc & PM8XXX_VREG_PIN_CTRL_EN3)
+			pc_en3 = " EN3";
+		if (pc == PM8XXX_VREG_PIN_CTRL_NONE)
+			pc_total = " none";
+	} else {
+		pc_total = " none";
+	}
+
+	mutex_unlock(&vreg->pc_lock);
+
+	enable_label = pm8xxx_vreg_is_enabled(rdev) ? "on " : "off";
+
+	switch (vreg->type) {
+	case PM8XXX_REGULATOR_TYPE_PLDO:
+		uV = pm8xxx_pldo_get_voltage(rdev);
+		mode = pm8xxx_ldo_get_mode(rdev);
+		pr_info("%s %-9s: %s, v=%7d uV, mode=%s, pc=%s%s%s%s%s\n",
+			action_label, vreg->rdesc.name, enable_label, uV,
+			(mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"),
+			pc_en0, pc_en1, pc_en2, pc_en3, pc_total);
+		break;
+	case PM8XXX_REGULATOR_TYPE_NLDO:
+		uV = pm8xxx_nldo_get_voltage(rdev);
+		mode = pm8xxx_ldo_get_mode(rdev);
+		pr_info("%s %-9s: %s, v=%7d uV, mode=%s, pc=%s%s%s%s%s\n",
+			action_label, vreg->rdesc.name, enable_label, uV,
+			(mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"),
+			pc_en0, pc_en1, pc_en2, pc_en3, pc_total);
+		break;
+	case PM8XXX_REGULATOR_TYPE_NLDO1200:
+		uV = pm8xxx_nldo1200_get_voltage(rdev);
+		mode = pm8xxx_nldo1200_get_mode(rdev);
+		pr_info("%s %-9s: %s, v=%7d uV, mode=%s\n",
+			action_label, vreg->rdesc.name, enable_label, uV,
+			(mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"));
+		break;
+	case PM8XXX_REGULATOR_TYPE_SMPS:
+		uV = pm8xxx_smps_get_voltage(rdev);
+		mode = pm8xxx_smps_get_mode(rdev);
+		pr_info("%s %-9s: %s, v=%7d uV, mode=%s, pc=%s%s%s%s%s\n",
+			action_label, vreg->rdesc.name, enable_label, uV,
+			(mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"),
+			pc_en0, pc_en1, pc_en2, pc_en3, pc_total);
+		break;
+	case PM8XXX_REGULATOR_TYPE_FTSMPS:
+		uV = pm8xxx_ftsmps_get_voltage(rdev);
+		mode = pm8xxx_ftsmps_get_mode(rdev);
+		pr_info("%s %-9s: %s, v=%7d uV, mode=%s\n",
+			action_label, vreg->rdesc.name, enable_label, uV,
+			(mode == REGULATOR_MODE_NORMAL ? "HPM" : "LPM"));
+		break;
+	case PM8XXX_REGULATOR_TYPE_VS:
+		pr_info("%s %-9s: %s, pc=%s%s%s%s%s\n",
+			action_label, vreg->rdesc.name, enable_label,
+			pc_en0, pc_en1, pc_en2, pc_en3, pc_total);
+		break;
+	case PM8XXX_REGULATOR_TYPE_VS300:
+		pr_info("%s %-9s: %s\n",
+			action_label, vreg->rdesc.name, enable_label);
+		break;
+	case PM8XXX_REGULATOR_TYPE_NCP:
+		uV = pm8xxx_ncp_get_voltage(rdev);
+		pr_info("%s %-9s: %s, v=%7d uV\n",
+			action_label, vreg->rdesc.name, enable_label, uV);
+		break;
+	default:
+		break;
+	}
+}
+
+/* Real regulator operations. */
+static struct regulator_ops pm8xxx_pldo_ops = {
+	.enable			= pm8xxx_ldo_enable,
+	.disable		= pm8xxx_ldo_disable,
+	.is_enabled		= pm8xxx_vreg_is_enabled,
+	.set_voltage		= pm8xxx_pldo_set_voltage,
+	.get_voltage		= pm8xxx_pldo_get_voltage,
+	.list_voltage		= pm8xxx_pldo_list_voltage,
+	.set_mode		= pm8xxx_ldo_set_mode,
+	.get_mode		= pm8xxx_ldo_get_mode,
+	.get_optimum_mode	= pm8xxx_vreg_get_optimum_mode,
+	.enable_time		= pm8xxx_enable_time,
+};
+
+static struct regulator_ops pm8xxx_nldo_ops = {
+	.enable			= pm8xxx_ldo_enable,
+	.disable		= pm8xxx_ldo_disable,
+	.is_enabled		= pm8xxx_vreg_is_enabled,
+	.set_voltage		= pm8xxx_nldo_set_voltage,
+	.get_voltage		= pm8xxx_nldo_get_voltage,
+	.list_voltage		= pm8xxx_nldo_list_voltage,
+	.set_mode		= pm8xxx_ldo_set_mode,
+	.get_mode		= pm8xxx_ldo_get_mode,
+	.get_optimum_mode	= pm8xxx_vreg_get_optimum_mode,
+	.enable_time		= pm8xxx_enable_time,
+};
+
+static struct regulator_ops pm8xxx_nldo1200_ops = {
+	.enable			= pm8xxx_nldo1200_enable,
+	.disable		= pm8xxx_nldo1200_disable,
+	.is_enabled		= pm8xxx_vreg_is_enabled,
+	.set_voltage		= pm8xxx_nldo1200_set_voltage,
+	.get_voltage		= pm8xxx_nldo1200_get_voltage,
+	.list_voltage		= pm8xxx_nldo1200_list_voltage,
+	.set_mode		= pm8xxx_nldo1200_set_mode,
+	.get_mode		= pm8xxx_nldo1200_get_mode,
+	.get_optimum_mode	= pm8xxx_vreg_get_optimum_mode,
+	.enable_time		= pm8xxx_enable_time,
+};
+
+static struct regulator_ops pm8xxx_smps_ops = {
+	.enable			= pm8xxx_smps_enable,
+	.disable		= pm8xxx_smps_disable,
+	.is_enabled		= pm8xxx_vreg_is_enabled,
+	.set_voltage		= pm8xxx_smps_set_voltage,
+	.get_voltage		= pm8xxx_smps_get_voltage,
+	.list_voltage		= pm8xxx_smps_list_voltage,
+	.set_mode		= pm8xxx_smps_set_mode,
+	.get_mode		= pm8xxx_smps_get_mode,
+	.get_optimum_mode	= pm8xxx_vreg_get_optimum_mode,
+	.enable_time		= pm8xxx_enable_time,
+};
+
+static struct regulator_ops pm8xxx_ftsmps_ops = {
+	.enable			= pm8xxx_ftsmps_enable,
+	.disable		= pm8xxx_ftsmps_disable,
+	.is_enabled		= pm8xxx_vreg_is_enabled,
+	.set_voltage		= pm8xxx_ftsmps_set_voltage,
+	.get_voltage		= pm8xxx_ftsmps_get_voltage,
+	.list_voltage		= pm8xxx_ftsmps_list_voltage,
+	.set_mode		= pm8xxx_ftsmps_set_mode,
+	.get_mode		= pm8xxx_ftsmps_get_mode,
+	.get_optimum_mode	= pm8xxx_vreg_get_optimum_mode,
+	.enable_time		= pm8xxx_enable_time,
+};
+
+static struct regulator_ops pm8xxx_vs_ops = {
+	.enable			= pm8xxx_vs_enable,
+	.disable		= pm8xxx_vs_disable,
+	.is_enabled		= pm8xxx_vreg_is_enabled,
+	.enable_time		= pm8xxx_enable_time,
+};
+
+static struct regulator_ops pm8xxx_vs300_ops = {
+	.enable			= pm8xxx_vs300_enable,
+	.disable		= pm8xxx_vs300_disable,
+	.is_enabled		= pm8xxx_vreg_is_enabled,
+	.enable_time		= pm8xxx_enable_time,
+};
+
+static struct regulator_ops pm8xxx_ncp_ops = {
+	.enable			= pm8xxx_ncp_enable,
+	.disable		= pm8xxx_ncp_disable,
+	.is_enabled		= pm8xxx_vreg_is_enabled,
+	.set_voltage		= pm8xxx_ncp_set_voltage,
+	.get_voltage		= pm8xxx_ncp_get_voltage,
+	.list_voltage		= pm8xxx_ncp_list_voltage,
+	.enable_time		= pm8xxx_enable_time,
+};
+
+/* Pin control regulator operations. */
+static struct regulator_ops pm8xxx_ldo_pc_ops = {
+	.enable			= pm8xxx_ldo_pin_control_enable,
+	.disable		= pm8xxx_ldo_pin_control_disable,
+	.is_enabled		= pm8xxx_vreg_pin_control_is_enabled,
+};
+
+static struct regulator_ops pm8xxx_smps_pc_ops = {
+	.enable			= pm8xxx_smps_pin_control_enable,
+	.disable		= pm8xxx_smps_pin_control_disable,
+	.is_enabled		= pm8xxx_vreg_pin_control_is_enabled,
+};
+
+static struct regulator_ops pm8xxx_vs_pc_ops = {
+	.enable			= pm8xxx_vs_pin_control_enable,
+	.disable		= pm8xxx_vs_pin_control_disable,
+	.is_enabled		= pm8xxx_vreg_pin_control_is_enabled,
+};
+
+static struct regulator_ops *pm8xxx_reg_ops[PM8XXX_REGULATOR_TYPE_MAX] = {
+	[PM8XXX_REGULATOR_TYPE_PLDO]		= &pm8xxx_pldo_ops,
+	[PM8XXX_REGULATOR_TYPE_NLDO]		= &pm8xxx_nldo_ops,
+	[PM8XXX_REGULATOR_TYPE_NLDO1200]	= &pm8xxx_nldo1200_ops,
+	[PM8XXX_REGULATOR_TYPE_SMPS]		= &pm8xxx_smps_ops,
+	[PM8XXX_REGULATOR_TYPE_FTSMPS]		= &pm8xxx_ftsmps_ops,
+	[PM8XXX_REGULATOR_TYPE_VS]		= &pm8xxx_vs_ops,
+	[PM8XXX_REGULATOR_TYPE_VS300]		= &pm8xxx_vs300_ops,
+	[PM8XXX_REGULATOR_TYPE_NCP]		= &pm8xxx_ncp_ops,
+};
+
+static struct regulator_ops *pm8xxx_reg_pc_ops[PM8XXX_REGULATOR_TYPE_MAX] = {
+	[PM8XXX_REGULATOR_TYPE_PLDO]		= &pm8xxx_ldo_pc_ops,
+	[PM8XXX_REGULATOR_TYPE_NLDO]		= &pm8xxx_ldo_pc_ops,
+	[PM8XXX_REGULATOR_TYPE_SMPS]		= &pm8xxx_smps_pc_ops,
+	[PM8XXX_REGULATOR_TYPE_VS]		= &pm8xxx_vs_pc_ops,
+};
+
+static unsigned pm8xxx_n_voltages[PM8XXX_REGULATOR_TYPE_MAX] = {
+	[PM8XXX_REGULATOR_TYPE_PLDO]		= PLDO_SET_POINTS,
+	[PM8XXX_REGULATOR_TYPE_NLDO]		= NLDO_SET_POINTS,
+	[PM8XXX_REGULATOR_TYPE_NLDO1200]	= NLDO1200_SET_POINTS,
+	[PM8XXX_REGULATOR_TYPE_SMPS]		= SMPS_ADVANCED_SET_POINTS,
+	[PM8XXX_REGULATOR_TYPE_FTSMPS]		= FTSMPS_SET_POINTS,
+	[PM8XXX_REGULATOR_TYPE_VS]		= 0,
+	[PM8XXX_REGULATOR_TYPE_VS300]		= 0,
+	[PM8XXX_REGULATOR_TYPE_NCP]		= NCP_SET_POINTS,
+};
+
+static int pm8xxx_init_ldo(struct pm8xxx_vreg *vreg, bool is_real)
+{
+	int rc = 0;
+	int i;
+	u8 bank;
+
+	/* Save the current control register state. */
+	rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
+	if (rc)
+		goto bail;
+
+	/* Save the current test register state. */
+	for (i = 0; i < LDO_TEST_BANKS; i++) {
+		bank = REGULATOR_BANK_SEL(i);
+		rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
+		if (rc)
+			goto bail;
+
+		rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
+				  &vreg->test_reg[i]);
+		if (rc)
+			goto bail;
+		vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
+	}
+
+	if (is_real) {
+		/* Set pull down enable based on platform data. */
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+		      (vreg->pdata.pull_down_enable ? LDO_PULL_DOWN_ENABLE : 0),
+		      LDO_PULL_DOWN_ENABLE_MASK, &vreg->ctrl_reg);
+
+		vreg->is_enabled = !!_pm8xxx_vreg_is_enabled(vreg);
+
+		vreg->mode = ((vreg->ctrl_reg & LDO_CTRL_PM_MASK)
+					== LDO_CTRL_PM_LPM ?
+				REGULATOR_MODE_IDLE : REGULATOR_MODE_NORMAL);
+	}
+bail:
+	if (rc)
+		vreg_err(vreg, "pm8xxx_readb/writeb failed, rc=%d\n", rc);
+
+	return rc;
+}
+
+static int pm8xxx_init_nldo1200(struct pm8xxx_vreg *vreg)
+{
+	int rc = 0;
+	int i;
+	u8 bank;
+
+	/* Save the current control register state. */
+	rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
+	if (rc)
+		goto bail;
+
+	/* Save the current test register state. */
+	for (i = 0; i < LDO_TEST_BANKS; i++) {
+		bank = REGULATOR_BANK_SEL(i);
+		rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
+		if (rc)
+			goto bail;
+
+		rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
+				  &vreg->test_reg[i]);
+		if (rc)
+			goto bail;
+		vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
+	}
+
+	vreg->save_uV = _pm8xxx_nldo1200_get_voltage(vreg);
+
+	/* Set pull down enable based on platform data. */
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+		 (vreg->pdata.pull_down_enable ? NLDO1200_PULL_DOWN_ENABLE : 0)
+		 | REGULATOR_BANK_SEL(1) | REGULATOR_BANK_WRITE,
+		 NLDO1200_PULL_DOWN_ENABLE_MASK | REGULATOR_BANK_MASK,
+		 &vreg->test_reg[1]);
+
+bail:
+	if (rc)
+		vreg_err(vreg, "pm8xxx_readb/writeb failed, rc=%d\n", rc);
+
+	return rc;
+}
+
+static int pm8xxx_init_smps(struct pm8xxx_vreg *vreg, bool is_real)
+{
+	int rc = 0;
+	int i;
+	u8 bank;
+
+	/* Save the current control register state. */
+	rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
+	if (rc)
+		goto bail;
+
+	/* Save the current test2 register state. */
+	for (i = 0; i < SMPS_TEST_BANKS; i++) {
+		bank = REGULATOR_BANK_SEL(i);
+		rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
+		if (rc)
+			goto bail;
+
+		rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
+				  &vreg->test_reg[i]);
+		if (rc)
+			goto bail;
+		vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
+	}
+
+	/* Save the current clock control register state. */
+	rc = pm8xxx_readb(vreg->dev->parent, vreg->clk_ctrl_addr,
+			  &vreg->clk_ctrl_reg);
+	if (rc)
+		goto bail;
+
+	/* Save the current sleep control register state. */
+	rc = pm8xxx_readb(vreg->dev->parent, vreg->sleep_ctrl_addr,
+			  &vreg->sleep_ctrl_reg);
+	if (rc)
+		goto bail;
+
+	vreg->save_uV = _pm8xxx_smps_get_voltage(vreg);
+
+	if (is_real) {
+		/* Set advanced mode pull down enable based on platform data. */
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->test_addr,
+			(vreg->pdata.pull_down_enable
+				? SMPS_ADVANCED_PULL_DOWN_ENABLE : 0)
+			| REGULATOR_BANK_SEL(6) | REGULATOR_BANK_WRITE,
+			REGULATOR_BANK_MASK | SMPS_ADVANCED_PULL_DOWN_ENABLE,
+			&vreg->test_reg[6]);
+		if (rc)
+			goto bail;
+
+		vreg->is_enabled = !!_pm8xxx_vreg_is_enabled(vreg);
+
+		vreg->mode = ((vreg->clk_ctrl_reg & SMPS_CLK_CTRL_MASK)
+					== SMPS_CLK_CTRL_PFM ?
+				REGULATOR_MODE_IDLE : REGULATOR_MODE_NORMAL);
+	}
+
+	if (!SMPS_IN_ADVANCED_MODE(vreg) && is_real) {
+		/* Set legacy mode pull down enable based on platform data. */
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+			(vreg->pdata.pull_down_enable
+				? SMPS_LEGACY_PULL_DOWN_ENABLE : 0),
+			SMPS_LEGACY_PULL_DOWN_ENABLE, &vreg->ctrl_reg);
+		if (rc)
+			goto bail;
+	}
+
+bail:
+	if (rc)
+		vreg_err(vreg, "pm8xxx_readb/writeb failed, rc=%d\n", rc);
+
+	return rc;
+}
+
+static int pm8xxx_init_ftsmps(struct pm8xxx_vreg *vreg)
+{
+	int rc, i;
+	u8 bank;
+
+	/* Save the current control register state. */
+	rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
+	if (rc)
+		goto bail;
+
+	/* Store current regulator register values. */
+	rc = pm8xxx_readb(vreg->dev->parent, vreg->pfm_ctrl_addr,
+			  &vreg->pfm_ctrl_reg);
+	if (rc)
+		goto bail;
+
+	rc = pm8xxx_readb(vreg->dev->parent, vreg->pwr_cnfg_addr,
+			  &vreg->pwr_cnfg_reg);
+	if (rc)
+		goto bail;
+
+	/* Save the current fts_cnfg1 register state (uses 'test' member). */
+	for (i = 0; i < SMPS_TEST_BANKS; i++) {
+		bank = REGULATOR_BANK_SEL(i);
+		rc = pm8xxx_writeb(vreg->dev->parent, vreg->test_addr, bank);
+		if (rc)
+			goto bail;
+
+		rc = pm8xxx_readb(vreg->dev->parent, vreg->test_addr,
+				  &vreg->test_reg[i]);
+		if (rc)
+			goto bail;
+		vreg->test_reg[i] |= REGULATOR_BANK_WRITE;
+	}
+
+	vreg->save_uV = _pm8xxx_ftsmps_get_voltage(vreg);
+
+	/* Set pull down enable based on platform data. */
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->pwr_cnfg_addr,
+		(vreg->pdata.pull_down_enable ? FTSMPS_PULL_DOWN_ENABLE : 0),
+		FTSMPS_PULL_DOWN_ENABLE_MASK, &vreg->pwr_cnfg_reg);
+
+bail:
+	if (rc)
+		vreg_err(vreg, "pm8xxx_readb/writeb failed, rc=%d\n", rc);
+
+	return rc;
+}
+
+static int pm8xxx_init_vs(struct pm8xxx_vreg *vreg, bool is_real)
+{
+	int rc = 0;
+
+	/* Save the current control register state. */
+	rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
+	if (rc) {
+		vreg_err(vreg, "pm8xxx_readb failed, rc=%d\n", rc);
+		return rc;
+	}
+
+	if (is_real) {
+		/* Set pull down enable based on platform data. */
+		rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+		       (vreg->pdata.pull_down_enable ? VS_PULL_DOWN_ENABLE
+						     : VS_PULL_DOWN_DISABLE),
+		       VS_PULL_DOWN_ENABLE_MASK, &vreg->ctrl_reg);
+
+		if (rc)
+			vreg_err(vreg,
+				"pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+
+		vreg->is_enabled = !!_pm8xxx_vreg_is_enabled(vreg);
+	}
+
+	return rc;
+}
+
+static int pm8xxx_init_vs300(struct pm8xxx_vreg *vreg)
+{
+	int rc;
+
+	/* Save the current control register state. */
+	rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
+	if (rc) {
+		vreg_err(vreg, "pm8xxx_readb failed, rc=%d\n", rc);
+		return rc;
+	}
+
+	/* Set pull down enable based on platform data. */
+	rc = pm8xxx_vreg_masked_write(vreg, vreg->ctrl_addr,
+		    (vreg->pdata.pull_down_enable ? VS300_PULL_DOWN_ENABLE : 0),
+		    VS300_PULL_DOWN_ENABLE_MASK, &vreg->ctrl_reg);
+
+	if (rc)
+		vreg_err(vreg, "pm8xxx_vreg_masked_write failed, rc=%d\n", rc);
+
+	return rc;
+}
+
+static int pm8xxx_init_ncp(struct pm8xxx_vreg *vreg)
+{
+	int rc;
+
+	/* Save the current control register state. */
+	rc = pm8xxx_readb(vreg->dev->parent, vreg->ctrl_addr, &vreg->ctrl_reg);
+	if (rc) {
+		vreg_err(vreg, "pm8xxx_readb failed, rc=%d\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+static int __devinit pm8xxx_vreg_probe(struct platform_device *pdev)
+{
+	struct pm8xxx_regulator_core_platform_data *core_data;
+	const struct pm8xxx_regulator_platform_data *pdata;
+	enum pm8xxx_vreg_pin_function pin_fn;
+	struct regulator_desc *rdesc;
+	struct pm8xxx_vreg *vreg;
+	unsigned pin_ctrl;
+	int rc = 0;
+
+	if (pdev == NULL) {
+		pr_err("no platform device specified\n");
+		return -EINVAL;
+	}
+
+	core_data = pdev->dev.platform_data;
+	if (core_data == NULL) {
+		pr_err("no core data specified\n");
+		return -EINVAL;
+	}
+
+	pdata = core_data->pdata;
+	vreg = core_data->vreg;
+	if (pdata == NULL) {
+		pr_err("no pdata specified\n");
+		return -EINVAL;
+	} else if (vreg == NULL) {
+		pr_err("no vreg specified\n");
+		return -EINVAL;
+	}
+
+	if (vreg->rdesc.name == NULL) {
+		pr_err("regulator name missing\n");
+		return -EINVAL;
+	} else if (vreg->type < 0 || vreg->type > PM8XXX_REGULATOR_TYPE_MAX) {
+		pr_err("%s: regulator type=%d is invalid\n", vreg->rdesc.name,
+			vreg->type);
+		return -EINVAL;
+	} else if (core_data->is_pin_controlled
+		   && pm8xxx_reg_pc_ops[vreg->type] == NULL) {
+		pr_err("%s: regulator type=%d does not support pin control\n",
+			vreg->rdesc.name, vreg->type);
+		return -EINVAL;
+	} else if (core_data->is_pin_controlled
+		   && vreg->rdesc_pc.name == NULL) {
+		pr_err("%s: regulator pin control name missing\n",
+			vreg->rdesc.name);
+		return -EINVAL;
+	}
+
+	if (core_data->is_pin_controlled)
+		rdesc = &vreg->rdesc_pc;
+	else
+		rdesc = &vreg->rdesc;
+	if (!pdata) {
+		pr_err("%s requires platform data\n", vreg->rdesc.name);
+		return -EINVAL;
+	}
+
+	rdesc->id    = pdev->id;
+	rdesc->owner = THIS_MODULE;
+	rdesc->type  = REGULATOR_VOLTAGE;
+	if (core_data->is_pin_controlled) {
+		rdesc->ops = pm8xxx_reg_pc_ops[vreg->type];
+		rdesc->n_voltages = 0;
+	} else {
+		rdesc->ops = pm8xxx_reg_ops[vreg->type];
+		rdesc->n_voltages = pm8xxx_n_voltages[vreg->type];
+	}
+
+	mutex_lock(&vreg->pc_lock);
+
+	if (!core_data->is_pin_controlled) {
+		/* Do not modify pin control and pin function values. */
+		pin_ctrl = vreg->pdata.pin_ctrl;
+		pin_fn = vreg->pdata.pin_fn;
+		memcpy(&(vreg->pdata), pdata,
+			sizeof(struct pm8xxx_regulator_platform_data));
+		vreg->pdata.pin_ctrl = pin_ctrl;
+		vreg->pdata.pin_fn = pin_fn;
+		vreg->dev = &pdev->dev;
+	} else {
+		/* Pin control regulator */
+		if ((pdata->pin_ctrl & PM8XXX_VREG_PIN_CTRL_ALL)
+		    == PM8XXX_VREG_PIN_CTRL_NONE) {
+			pr_err("%s: no pin control input specified\n",
+				vreg->rdesc.name);
+			mutex_unlock(&vreg->pc_lock);
+			return -EINVAL;
+		}
+		vreg->pdata.pin_ctrl = pdata->pin_ctrl;
+		vreg->pdata.pin_fn = pdata->pin_fn;
+		vreg->dev_pc = &pdev->dev;
+		if (!vreg->dev)
+			vreg->dev = &pdev->dev;
+	}
+
+	/* Initialize register values. */
+	switch (vreg->type) {
+	case PM8XXX_REGULATOR_TYPE_PLDO:
+	case PM8XXX_REGULATOR_TYPE_NLDO:
+		rc = pm8xxx_init_ldo(vreg, !core_data->is_pin_controlled);
+		break;
+	case PM8XXX_REGULATOR_TYPE_NLDO1200:
+		rc = pm8xxx_init_nldo1200(vreg);
+		break;
+	case PM8XXX_REGULATOR_TYPE_SMPS:
+		rc = pm8xxx_init_smps(vreg, !core_data->is_pin_controlled);
+		break;
+	case PM8XXX_REGULATOR_TYPE_FTSMPS:
+		rc = pm8xxx_init_ftsmps(vreg);
+		break;
+	case PM8XXX_REGULATOR_TYPE_VS:
+		rc = pm8xxx_init_vs(vreg, !core_data->is_pin_controlled);
+		break;
+	case PM8XXX_REGULATOR_TYPE_VS300:
+		rc = pm8xxx_init_vs300(vreg);
+		break;
+	case PM8XXX_REGULATOR_TYPE_NCP:
+		rc = pm8xxx_init_ncp(vreg);
+		break;
+	default:
+		break;
+	}
+
+	mutex_unlock(&vreg->pc_lock);
+
+	if (rc)
+		goto bail;
+
+	if (!core_data->is_pin_controlled) {
+		vreg->rdev = regulator_register(rdesc, &pdev->dev,
+				&(pdata->init_data), vreg);
+		if (IS_ERR(vreg->rdev)) {
+			rc = PTR_ERR(vreg->rdev);
+			vreg->rdev = NULL;
+			pr_err("regulator_register failed: %s, rc=%d\n",
+				vreg->rdesc.name, rc);
+		}
+	} else {
+		vreg->rdev_pc = regulator_register(rdesc, &pdev->dev,
+				&(pdata->init_data), vreg);
+		if (IS_ERR(vreg->rdev_pc)) {
+			rc = PTR_ERR(vreg->rdev_pc);
+			vreg->rdev_pc = NULL;
+			pr_err("regulator_register failed: %s, rc=%d\n",
+				vreg->rdesc.name, rc);
+		}
+	}
+	if ((pm8xxx_vreg_debug_mask & PM8XXX_VREG_DEBUG_INIT) && !rc
+	    && vreg->rdev)
+		pm8xxx_vreg_show_state(vreg->rdev,
+					PM8XXX_REGULATOR_ACTION_INIT);
+
+	platform_set_drvdata(pdev, core_data);
+
+bail:
+	if (rc)
+		pr_err("error for %s, rc=%d\n", vreg->rdesc.name, rc);
+
+	return rc;
+}
+
+static int __devexit pm8xxx_vreg_remove(struct platform_device *pdev)
+{
+	struct pm8xxx_regulator_core_platform_data *core_data;
+
+	core_data = platform_get_drvdata(pdev);
+	platform_set_drvdata(pdev, NULL);
+
+	if (core_data) {
+		if (core_data->is_pin_controlled)
+			regulator_unregister(core_data->vreg->rdev_pc);
+		else
+			regulator_unregister(core_data->vreg->rdev);
+	}
+
+	return 0;
+}
+
+static struct platform_driver pm8xxx_vreg_driver = {
+	.probe	= pm8xxx_vreg_probe,
+	.remove	= __devexit_p(pm8xxx_vreg_remove),
+	.driver	= {
+		.name	= PM8XXX_REGULATOR_DEV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init pm8xxx_vreg_init(void)
+{
+	return platform_driver_register(&pm8xxx_vreg_driver);
+}
+postcore_initcall(pm8xxx_vreg_init);
+
+static void __exit pm8xxx_vreg_exit(void)
+{
+	platform_driver_unregister(&pm8xxx_vreg_driver);
+}
+module_exit(pm8xxx_vreg_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PMIC PM8XXX regulator driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:" PM8XXX_REGULATOR_DEV_NAME);
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 93feb81..67179e5 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1133,26 +1133,6 @@
 	  This drive can also be built as a module. If so, the module
 	  will be called rtc-puv3.
 
-config RTC_PM8058
-	tristate "PMIC8058 RTC support"
-	default n
-	depends on PMIC8058
-	help
-	  Say Y here if you want support for the PMIC8058 RTC.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called pmic8058-rtc.
-
-config RTC_PM8058_WRITE_ENABLE
-	bool "PM8058 RTC write enable"
-	default n
-	depends on RTC_PM8058
-	help
-	  Say Y here if you want to support the write operation for
-	  PMIC8058 RTC.
-
-	  By default the write operation is not supported.
-
 config RTC_DRV_PM8XXX
 	tristate "Qualcomm PMIC8XXX RTC"
 	depends on MFD_PM8XXX
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 9e41297..bd149ed 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -113,4 +113,3 @@
 obj-$(CONFIG_RTC_DRV_WM831X)	+= rtc-wm831x.o
 obj-$(CONFIG_RTC_DRV_WM8350)	+= rtc-wm8350.o
 obj-$(CONFIG_RTC_DRV_X1205)	+= rtc-x1205.o
-obj-$(CONFIG_RTC_PM8058)	+= rtc-pm8058.o
diff --git a/drivers/rtc/rtc-pm8058.c b/drivers/rtc/rtc-pm8058.c
deleted file mode 100644
index 0376c64..0000000
--- a/drivers/rtc/rtc-pm8058.c
+++ /dev/null
@@ -1,603 +0,0 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. 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 version 2 and
- * only 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.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/rtc.h>
-#include <linux/mfd/pmic8058.h>
-#include <linux/pm.h>
-#include <linux/slab.h>
-#include <linux/rtc/rtc-pm8058.h>
-#include <linux/pm_runtime.h>
-
-#define PM8058_RTC_CTRL		0x1E8
-	#define PM8058_RTC_ENABLE	BIT(7)
-	#define PM8058_RTC_ALARM_ENABLE	BIT(1)
-	#define PM8058_RTC_ABORT_ENABLE	BIT(0)
-#define PM8058_RTC_ALARM_CTRL	0x1E9
-	#define PM8058_RTC_ALARM_CLEAR	BIT(0)
-#define PM8058_RTC_TEST		0x1F6
-#define PM8058_RTC_READ_BASE	0x1EE
-#define PM8058_RTC_WRITE_BASE	0x1EA
-#define PM8058_RTC_ALARM_BASE	0x1F2
-
-struct pm8058_rtc {
-	struct rtc_device *rtc0;
-	u8 rtc_ctrl_reg;
-	int rtc_irq;
-	int rtc_alarm_irq;
-	struct pm8058_chip *pm_chip;
-};
-
-static int
-pm8058_rtc_read_bytes(struct pm8058_rtc *rtc_dd, u8 *rtc_val, int base)
-{
-	int i, rc;
-
-	/*
-	 * Read the 32-bit RTC/Alarm Value.
-	 * These values have to be read 8-bit at a time.
-	 */
-	for (i = 0; i < 4; i++) {
-		rc = pm8058_read(rtc_dd->pm_chip, base + i, &rtc_val[i], 1);
-		if (rc < 0) {
-			pr_err("%s: PM8058 read failed\n", __func__);
-			return rc;
-		}
-	}
-
-	return 0;
-}
-
-static int
-pm8058_rtc_write_bytes(struct pm8058_rtc *rtc_dd, u8 *rtc_val, int base)
-{
-	int i, rc;
-
-	/*
-	 * Write the 32-bit Value.
-	 * These values have to be written 8-bit at a time.
-	 */
-	for (i = 0; i < 4; i++) {
-		rc = pm8058_write(rtc_dd->pm_chip, base + i, &rtc_val[i], 1);
-		if (rc < 0) {
-			pr_err("%s: PM8058 read failed\n", __func__);
-			return rc;
-		}
-	}
-
-	return 0;
-}
-
-/*
- * Steps to write the RTC registers.
- * 1. Disable alarm if enabled.
- * 2. Write 0x00 to LSB.
- * 3. Write Byte[1], Byte[2], Byte[3] then Byte[0].
- * 4. Enable alarm if disabled earlier.
- */
-#ifdef CONFIG_RTC_PM8058_WRITE_ENABLE
-static int
-pm8058_rtc0_set_time(struct device *dev, struct rtc_time *tm)
-{
-	int rc;
-	unsigned long secs = 0;
-	u8 value[4], reg = 0, alarm_enabled = 0, ctrl_reg = 0, i;
-	struct pm8058_rtc *rtc_dd = dev_get_drvdata(dev);
-
-	ctrl_reg = rtc_dd->rtc_ctrl_reg;
-
-	rtc_tm_to_time(tm, &secs);
-
-	value[0] = secs & 0xFF;
-	value[1] = (secs >> 8) & 0xFF;
-	value[2] = (secs >> 16) & 0xFF;
-	value[3] = (secs >> 24) & 0xFF;
-
-	pr_debug("%s: Seconds value to be written to RTC = %lu\n", __func__,
-								secs);
-	 /* Disable alarm before updating RTC */
-	if (ctrl_reg & PM8058_RTC_ALARM_ENABLE) {
-		alarm_enabled = 1;
-		ctrl_reg &= ~PM8058_RTC_ALARM_ENABLE;
-		rc = pm8058_write(rtc_dd->pm_chip, PM8058_RTC_CTRL,
-							&ctrl_reg, 1);
-		if (rc < 0) {
-			pr_err("%s: PM8058 write failed\n", __func__);
-			return rc;
-		}
-	}
-
-	/* Write Byte[1], Byte[2], Byte[3], Byte[0] */
-	reg = 0;
-	rc = pm8058_write(rtc_dd->pm_chip, PM8058_RTC_WRITE_BASE, &reg, 1);
-	if (rc < 0) {
-		pr_err("%s: PM8058 write failed\n", __func__);
-		return rc;
-	}
-
-	for (i = 1; i < 4; i++) {
-		rc = pm8058_write(rtc_dd->pm_chip, PM8058_RTC_WRITE_BASE + i,
-								&value[i], 1);
-		if (rc < 0) {
-			pr_err("%s:Write to RTC registers failed\n", __func__);
-			return rc;
-		}
-	}
-
-	rc = pm8058_write(rtc_dd->pm_chip, PM8058_RTC_WRITE_BASE,
-							&value[0], 1);
-	if (rc < 0) {
-		pr_err("%s: PM8058 write failed\n", __func__);
-		return rc;
-	}
-
-	if (alarm_enabled) {
-		ctrl_reg |= PM8058_RTC_ALARM_ENABLE;
-		rc = pm8058_write(rtc_dd->pm_chip, PM8058_RTC_CTRL,
-							&ctrl_reg, 1);
-		if (rc < 0) {
-			pr_err("%s: PM8058 write failed\n", __func__);
-			return rc;
-		}
-	}
-
-	rtc_dd->rtc_ctrl_reg = ctrl_reg;
-
-	return 0;
-}
-#endif
-
-static int
-pm8058_rtc0_read_time(struct device *dev, struct rtc_time *tm)
-{
-	int rc;
-	u8 value[4], reg;
-	unsigned long secs = 0;
-	struct pm8058_rtc *rtc_dd = dev_get_drvdata(dev);
-
-	rc = pm8058_rtc_read_bytes(rtc_dd, value, PM8058_RTC_READ_BASE);
-	if (rc < 0) {
-		pr_err("%s: RTC time read failed\n", __func__);
-		return rc;
-	}
-
-	/*
-	 * Read the LSB again and check if there has been a carry over.
-	 * If there is, redo the read operation.
-	 */
-	rc = pm8058_read(rtc_dd->pm_chip, PM8058_RTC_READ_BASE, &reg, 1);
-	if (rc < 0) {
-		pr_err("%s: PM8058 read failed\n", __func__);
-		return rc;
-	}
-
-	if (unlikely(reg < value[0])) {
-		rc = pm8058_rtc_read_bytes(rtc_dd, value,
-						PM8058_RTC_READ_BASE);
-		if (rc < 0) {
-			pr_err("%s: RTC time read failed\n", __func__);
-			return rc;
-		}
-	}
-
-	secs = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24);
-
-	rtc_time_to_tm(secs, tm);
-
-	rc = rtc_valid_tm(tm);
-	if (rc < 0) {
-		pr_err("%s: Invalid time read from PMIC8058\n", __func__);
-		return rc;
-	}
-
-	pr_debug("%s: secs = %lu, h::m:s == %d::%d::%d, d/m/y = %d/%d/%d\n",
-		 __func__, secs, tm->tm_hour, tm->tm_min, tm->tm_sec,
-		tm->tm_mday, tm->tm_mon, tm->tm_year);
-
-	return 0;
-}
-
-static int
-pm8058_rtc0_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
-{
-	int rc;
-	u8 value[4], reg;
-	struct rtc_time rtc_tm;
-	unsigned long secs_alarm, secs_rtc;
-	struct pm8058_rtc *rtc_dd = dev_get_drvdata(dev);
-
-	reg = rtc_dd->rtc_ctrl_reg;
-
-	/* Check if the alarm is valid */
-	rc = rtc_valid_tm(&alarm->time);
-	if (rc < 0) {
-		pr_err("%s: Alarm time invalid\n", __func__);
-		return -EINVAL;
-	}
-
-	rtc_tm_to_time(&alarm->time, &secs_alarm);
-
-	/*
-	 * Read the current RTC time and verify if the alarm time is in the
-	 * past. If yes, return invalid.
-	 */
-	rc = pm8058_rtc0_read_time(dev, &rtc_tm);
-	if (rc) {
-		pr_err("%s: Unable to read RTC time\n", __func__);
-		return -EINVAL;
-	}
-	rtc_tm_to_time(&rtc_tm, &secs_rtc);
-
-	if (secs_alarm < secs_rtc) {
-		pr_err("%s: Trying to set alarm in the past\n", __func__);
-		return -EINVAL;
-	}
-
-	value[0] = secs_alarm & 0xFF;
-	value[1] = (secs_alarm >> 8) & 0xFF;
-	value[2] = (secs_alarm >> 16) & 0xFF;
-	value[3] = (secs_alarm >> 24) & 0xFF;
-
-	rc = pm8058_rtc_write_bytes(rtc_dd, value, PM8058_RTC_ALARM_BASE);
-	if (rc < 0) {
-		pr_err("%s: Alarm could not be set\n", __func__);
-		return rc;
-	}
-
-	reg = (alarm->enabled) ? (reg | PM8058_RTC_ALARM_ENABLE) :
-					(reg & ~PM8058_RTC_ALARM_ENABLE);
-
-	rc = pm8058_write(rtc_dd->pm_chip, PM8058_RTC_CTRL, &reg, 1);
-	if (rc < 0) {
-		pr_err("%s: PM8058 write failed\n", __func__);
-		return rc;
-	}
-
-	rtc_dd->rtc_ctrl_reg = reg;
-
-	pr_debug("%s: Alarm Set for h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n",
-			__func__, alarm->time.tm_hour, alarm->time.tm_min,
-				alarm->time.tm_sec, alarm->time.tm_mday,
-				alarm->time.tm_mon, alarm->time.tm_year);
-
-	return 0;
-}
-
-static int
-pm8058_rtc0_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
-{
-	int rc;
-	u8 value[4], reg;
-	unsigned long secs = 0;
-	struct pm8058_rtc *rtc_dd = dev_get_drvdata(dev);
-
-	reg = rtc_dd->rtc_ctrl_reg;
-
-	alarm->enabled = !!(reg & PM8058_RTC_ALARM_ENABLE);
-
-	rc = pm8058_rtc_read_bytes(rtc_dd, value,
-					PM8058_RTC_ALARM_BASE);
-	if (rc < 0) {
-		pr_err("%s: RTC alarm time read failed\n", __func__);
-		return rc;
-	}
-
-	secs = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24);
-
-	rtc_time_to_tm(secs, &alarm->time);
-
-	rc = rtc_valid_tm(&alarm->time);
-	if (rc < 0) {
-		pr_err("%s: Invalid time read from PMIC8058\n", __func__);
-		return rc;
-	}
-
-	pr_debug("%s: Alarm set for - h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n",
-			__func__, alarm->time.tm_hour, alarm->time.tm_min,
-				alarm->time.tm_sec, alarm->time.tm_mday,
-				alarm->time.tm_mon, alarm->time.tm_year);
-
-	return 0;
-}
-
-
-static int
-pm8058_rtc0_alarm_irq_enable(struct device *dev, unsigned int enable)
-{
-	int rc;
-	struct pm8058_rtc *rtc_dd = dev_get_drvdata(dev);
-	u8 reg;
-
-	reg = rtc_dd->rtc_ctrl_reg;
-	reg = (enable) ? (reg | PM8058_RTC_ALARM_ENABLE) :
-				(reg & ~PM8058_RTC_ALARM_ENABLE);
-
-	rc = pm8058_write(rtc_dd->pm_chip, PM8058_RTC_CTRL, &reg, 1);
-	if (rc < 0) {
-		pr_err("%s: PM8058 write failed\n", __func__);
-		return rc;
-	}
-
-	rtc_dd->rtc_ctrl_reg = reg;
-
-	return rc;
-}
-
-static struct rtc_class_ops pm8058_rtc0_ops = {
-	.read_time	= pm8058_rtc0_read_time,
-	.set_alarm	= pm8058_rtc0_set_alarm,
-	.read_alarm	= pm8058_rtc0_read_alarm,
-	.alarm_irq_enable = pm8058_rtc0_alarm_irq_enable,
-};
-
-static irqreturn_t pm8058_alarm_trigger(int irq, void *dev_id)
-{
-	u8 reg;
-	int rc;
-	unsigned long events = 0;
-	struct pm8058_rtc *rtc_dd = dev_id;
-
-	events = RTC_IRQF | RTC_AF;
-	rtc_update_irq(rtc_dd->rtc0, 1, events);
-
-	pr_debug("%s: Alarm Triggered !!\n", __func__);
-
-	/* Clear the alarm enable bit */
-	reg = rtc_dd->rtc_ctrl_reg;
-
-	reg &= ~PM8058_RTC_ALARM_ENABLE;
-	rc = pm8058_write(rtc_dd->pm_chip, PM8058_RTC_CTRL,
-						&reg, 1);
-	if (rc < 0) {
-		pr_err("%s: PM8058 write failed\n", __func__);
-		goto rtc_alarm_handled;
-	}
-
-	rtc_dd->rtc_ctrl_reg = reg;
-
-	/* Clear RTC alarm register */
-	rc = pm8058_read(rtc_dd->pm_chip, PM8058_RTC_ALARM_CTRL, &reg, 1);
-	if (rc < 0) {
-		pr_err("%s: PM8058 read failed\n", __func__);
-		goto rtc_alarm_handled;
-	}
-
-	reg &= ~PM8058_RTC_ALARM_CLEAR;
-	rc = pm8058_write(rtc_dd->pm_chip, PM8058_RTC_ALARM_CTRL, &reg, 1);
-	if (rc < 0) {
-		pr_err("%s: PM8058 write failed\n", __func__);
-		goto rtc_alarm_handled;
-	}
-
-rtc_alarm_handled:
-	return IRQ_HANDLED;
-}
-
-static int __devinit pm8058_rtc_probe(struct platform_device *pdev)
-{
-	int rc;
-	u8 reg, reg_alarm;
-	struct pm8058_rtc *rtc_dd;
-	struct pm8058_chip *pm_chip;
-
-	pm_chip = dev_get_drvdata(pdev->dev.parent);
-	if (pm_chip == NULL) {
-		pr_err("%s: Invalid driver information\n", __func__);
-		return -ENXIO;
-	}
-
-	rtc_dd = kzalloc(sizeof(*rtc_dd), GFP_KERNEL);
-	if (rtc_dd == NULL) {
-		pr_err("%s: Unable to allocate memory\n", __func__);
-		return -ENOMEM;
-	}
-
-	/* Enable runtime PM ops, start in ACTIVE mode */
-	rc = pm_runtime_set_active(&pdev->dev);
-	if (rc < 0)
-		dev_dbg(&pdev->dev, "unable to set runtime pm state\n");
-	pm_runtime_enable(&pdev->dev);
-
-	rtc_dd->rtc_irq = platform_get_irq(pdev, 0);
-	rtc_dd->rtc_alarm_irq = platform_get_irq(pdev, 1);
-	if (!rtc_dd->rtc_alarm_irq || !rtc_dd->rtc_irq) {
-		pr_err("%s: RTC Alarm IRQ absent\n", __func__);
-		rc = -ENXIO;
-		goto fail_rtc_enable;
-	}
-
-	rtc_dd->pm_chip = pm_chip;
-
-	rc = pm8058_read(pm_chip, PM8058_RTC_CTRL, &reg, 1);
-	if (rc < 0) {
-		pr_err("%s: PM8058 read failed\n", __func__);
-		goto fail_rtc_enable;
-	}
-
-	/* Enable RTC, ABORT enable and disable alarm */
-	reg |= ((PM8058_RTC_ENABLE | PM8058_RTC_ABORT_ENABLE) &
-			~PM8058_RTC_ALARM_ENABLE);
-
-	rc = pm8058_write(pm_chip, PM8058_RTC_CTRL, &reg, 1);
-	if (rc < 0) {
-		pr_err("%s: PM8058 write failed\n", __func__);
-		goto fail_rtc_enable;
-	}
-
-	/* Clear RTC alarm control register */
-	rc = pm8058_read(rtc_dd->pm_chip, PM8058_RTC_ALARM_CTRL,
-							&reg_alarm, 1);
-	if (rc < 0) {
-		pr_err("%s: PM8058 read failed\n", __func__);
-		goto fail_rtc_enable;
-	}
-
-	reg_alarm &= ~PM8058_RTC_ALARM_CLEAR;
-	rc = pm8058_write(rtc_dd->pm_chip, PM8058_RTC_ALARM_CTRL,
-							&reg_alarm, 1);
-	if (rc < 0) {
-		pr_err("%s: PM8058 write failed\n", __func__);
-		goto fail_rtc_enable;
-	}
-
-	rtc_dd->rtc_ctrl_reg = reg;
-
-#ifdef CONFIG_RTC_PM8058_WRITE_ENABLE
-	pm8058_rtc0_ops.set_time	= pm8058_rtc0_set_time;
-#endif
-
-	platform_set_drvdata(pdev, rtc_dd);
-
-	/* Register the RTC device */
-	rtc_dd->rtc0 = rtc_device_register("pm8058_rtc0", &pdev->dev,
-				&pm8058_rtc0_ops, THIS_MODULE);
-	if (IS_ERR(rtc_dd->rtc0)) {
-		pr_err("%s: RTC device registration failed (%ld)\n",
-					__func__, PTR_ERR(rtc_dd->rtc0));
-		rc = PTR_ERR(rtc_dd->rtc0);
-		goto fail_rtc_enable;
-	}
-
-	/* Request the alarm IRQ */
-	rc = request_threaded_irq(rtc_dd->rtc_alarm_irq, NULL,
-				 pm8058_alarm_trigger, IRQF_TRIGGER_RISING,
-				 "pm8058_rtc_alarm", rtc_dd);
-	if (rc < 0) {
-		pr_err("%s: Request IRQ failed (%d)\n", __func__, rc);
-		goto fail_req_irq;
-	}
-
-	device_init_wakeup(&pdev->dev, 1);
-
-	pr_debug("%s: Probe success !!\n", __func__);
-
-	return 0;
-
-fail_req_irq:
-	rtc_device_unregister(rtc_dd->rtc0);
-fail_rtc_enable:
-	pm_runtime_set_suspended(&pdev->dev);
-	pm_runtime_disable(&pdev->dev);
-	kfree(rtc_dd);
-	return rc;
-}
-
-#ifdef CONFIG_PM
-static int pm8058_rtc_resume(struct device *dev)
-{
-	struct pm8058_rtc *rtc_dd = dev_get_drvdata(dev);
-
-	if (device_may_wakeup(dev))
-		disable_irq_wake(rtc_dd->rtc_alarm_irq);
-
-	return 0;
-}
-
-static int pm8058_rtc_suspend(struct device *dev)
-{
-	struct pm8058_rtc *rtc_dd = dev_get_drvdata(dev);
-
-	if (device_may_wakeup(dev))
-		enable_irq_wake(rtc_dd->rtc_alarm_irq);
-
-	return 0;
-}
-
-static struct dev_pm_ops pm8058_rtc_pm_ops = {
-	.suspend = pm8058_rtc_suspend,
-	.resume = pm8058_rtc_resume,
-};
-#endif
-
-static int __devexit pm8058_rtc_remove(struct platform_device *pdev)
-{
-	struct pm8058_rtc *rtc_dd = platform_get_drvdata(pdev);
-
-	pm_runtime_set_suspended(&pdev->dev);
-	pm_runtime_disable(&pdev->dev);
-
-	device_init_wakeup(&pdev->dev, 0);
-	free_irq(rtc_dd->rtc_alarm_irq, rtc_dd);
-	rtc_device_unregister(rtc_dd->rtc0);
-	kfree(rtc_dd);
-
-	return 0;
-}
-
-static void pm8058_rtc_shutdown(struct platform_device *pdev)
-{
-	u8 reg;
-	int rc, i;
-	bool rtc_alarm_powerup = false;
-	struct pm8058_rtc *rtc_dd = platform_get_drvdata(pdev);
-	struct pm8058_rtc_platform_data *pdata = pdev->dev.platform_data;
-
-	if (pdata != NULL)
-		rtc_alarm_powerup =  pdata->rtc_alarm_powerup;
-
-	if (!rtc_alarm_powerup) {
-
-		dev_dbg(&pdev->dev, "Disabling alarm interrupts\n");
-
-		/* Disable RTC alarms */
-		reg = rtc_dd->rtc_ctrl_reg;
-		reg &= ~PM8058_RTC_ALARM_ENABLE;
-		rc = pm8058_write(rtc_dd->pm_chip, PM8058_RTC_CTRL, &reg, 1);
-		if (rc < 0) {
-			pr_err("%s: PM8058 write failed\n", __func__);
-			return;
-		}
-
-		/* Clear Alarm register */
-		reg = 0x0;
-		for (i = 0; i < 4; i++) {
-			rc = pm8058_write(rtc_dd->pm_chip,
-					PM8058_RTC_ALARM_BASE + i, &reg, 1);
-			if (rc < 0) {
-				pr_err("%s: PM8058 write failed\n", __func__);
-				return;
-			}
-		}
-
-	}
-}
-
-static struct platform_driver pm8058_rtc_driver = {
-	.probe		= pm8058_rtc_probe,
-	.remove		= __devexit_p(pm8058_rtc_remove),
-	.shutdown	= pm8058_rtc_shutdown,
-	.driver	= {
-		.name	= "pm8058-rtc",
-		.owner	= THIS_MODULE,
-#ifdef CONFIG_PM
-		.pm	= &pm8058_rtc_pm_ops,
-#endif
-	},
-};
-
-static int __init pm8058_rtc_init(void)
-{
-	return platform_driver_register(&pm8058_rtc_driver);
-}
-
-static void __exit pm8058_rtc_exit(void)
-{
-	platform_driver_unregister(&pm8058_rtc_driver);
-}
-
-module_init(pm8058_rtc_init);
-module_exit(pm8058_rtc_exit);
-
-MODULE_ALIAS("platform:pm8058-rtc");
-MODULE_DESCRIPTION("PMIC8058 RTC driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/qcache/fmem.c b/drivers/staging/qcache/fmem.c
index 9ab21da..489d27a 100644
--- a/drivers/staging/qcache/fmem.c
+++ b/drivers/staging/qcache/fmem.c
@@ -17,11 +17,36 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include "tmem.h"
+#include <asm/mach/map.h>
 
 struct fmem_data fmem_data;
 enum fmem_state fmem_state;
 static spinlock_t fmem_state_lock;
 
+void *fmem_map_virtual_area(int cacheability)
+{
+	unsigned long addr;
+	const struct mem_type *type;
+	int ret;
+
+	addr = (unsigned long) fmem_data.area->addr;
+	type = get_mem_type(cacheability);
+	ret = ioremap_page_range(addr, addr + fmem_data.size,
+			fmem_data.phys, __pgprot(type->prot_pte));
+	if (ret)
+		return ERR_PTR(ret);
+
+	fmem_data.virt = fmem_data.area->addr;
+
+	return fmem_data.virt;
+}
+
+void fmem_unmap_virtual_area(void)
+{
+	unmap_kernel_range((unsigned long)fmem_data.virt, fmem_data.size);
+	fmem_data.virt = NULL;
+}
+
 static int fmem_probe(struct platform_device *pdev)
 {
 	struct fmem_platform_data *pdata = pdev->dev.platform_data;
@@ -29,13 +54,16 @@
 	if (!pdata->size)
 		return -ENODEV;
 
-	fmem_data.virt = ioremap_cached(pdata->phys, pdata->size);
-	if (!fmem_data.virt)
-		return -ENOMEM;
-
 	fmem_data.phys = pdata->phys;
 	fmem_data.size = pdata->size;
+	fmem_data.area = get_vm_area(pdata->size, VM_IOREMAP);
+	if (!fmem_data.area)
+		return -ENOMEM;
 
+	if (!fmem_map_virtual_area(MT_DEVICE_CACHED)) {
+		remove_vm_area(fmem_data.area->addr);
+		return -ENOMEM;
+	}
 	pr_info("fmem phys %lx virt %p size %lx\n",
 		fmem_data.phys, fmem_data.virt, fmem_data.size);
 
@@ -159,10 +187,18 @@
 		}
 	}
 
-	if (new_state == FMEM_T_STATE)
+	if (new_state == FMEM_T_STATE) {
+		void *v;
+		v = fmem_map_virtual_area(MT_DEVICE_CACHED);
+		if (IS_ERR_OR_NULL(v)) {
+			ret = PTR_ERR(v);
+			goto out;
+		}
 		tmem_enable(true);
-	else
+	} else {
 		tmem_disable();
+		fmem_unmap_virtual_area();
+	}
 
 out_set:
 	fmem_state = new_state;
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index c44c245..794775a 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -23,31 +23,6 @@
 
 	  Say Y if your user-space is new enough.
 
-config THERMAL_PM8901
-	tristate "Qualcomm PM8901 Temperature Alarm"
-	depends on PMIC8901
-	depends on THERMAL
-	default n
-	help
-	  This enables a thermal Sysfs driver for the PMIC 8901 device. It
-	  shows up in Sysfs as a thermal zone with multiple trip points.
-	  Enabling the thermal zone device via the mode file results in
-	  shifting over temperature shutdown control of the PMIC from hardware
-	  to software.
-
-config THERMAL_PM8058
-	tristate "Qualcomm PM8058 Temperature Alarm"
-	depends on PMIC8058
-	depends on THERMAL
-	depends on SENSORS_MSM_ADC
-	default n
-	help
-	  This enables a thermal Sysfs driver for the PMIC 8058 device. It
-	  shows up in Sysfs as a thermal zone with multiple trip points.
-	  Enabling the thermal zone device via the mode file results in
-	  shifting over temperature shutdown control of the PMIC from hardware
-	  to software.
-
 config THERMAL_MSM_POPMEM
 	tristate "Qualcomm MSM POP memory temperature sensor"
 	depends on THERMAL
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index c5d792c..31b5c3f 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -3,8 +3,6 @@
 #
 
 obj-$(CONFIG_THERMAL)		+= thermal_sys.o
-obj-$(CONFIG_THERMAL_PM8901)	+= pmic8901-tm.o
-obj-$(CONFIG_THERMAL_PM8058)	+= pmic8058-tm.o
 obj-$(CONFIG_THERMAL_MSM_POPMEM)	+= msm_popmem-tm.o
 obj-$(CONFIG_THERMAL_TSENS)	+= msm_tsens.o
 obj-$(CONFIG_THERMAL_TSENS8960) += msm8960_tsens.o
diff --git a/drivers/thermal/pmic8058-tm.c b/drivers/thermal/pmic8058-tm.c
deleted file mode 100644
index 2589494..0000000
--- a/drivers/thermal/pmic8058-tm.c
+++ /dev/null
@@ -1,504 +0,0 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. 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 version 2 and
- * only 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.
- *
- */
-/*
- * Qualcomm PMIC8058 Thermal Manager driver
- *
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/thermal.h>
-#include <linux/interrupt.h>
-#include <linux/mfd/pmic8058.h>
-#include <linux/completion.h>
-
-#include <linux/msm_adc.h>
-
-/* PMIC8058 TEMP_ALRM registers */
-#define	SSBI_REG_TEMP_ALRM_CTRL		0x1B
-#define	SSBI_REG_TEMP_ALRM_PWM		0x9B
-#define	SSBI_REG_TEMP_ALRM_TEST1	0x7A
-#define	SSBI_REG_TEMP_ALRM_TEST2	0xAB
-
-/* TEMP_ALRM_CTRL */
-#define	PM8058_TEMP_ST3_SD		0x80
-#define	PM8058_TEMP_ST2_SD		0x40
-#define	PM8058_TEMP_STATUS_MASK		0x30
-#define	PM8058_TEMP_STATUS_SHIFT	4
-#define	PM8058_TEMP_THRESH_MASK		0x0C
-#define	PM8058_TEMP_THRESH_SHIFT	2
-#define	PM8058_TEMP_OVRD_ST3		0x02
-#define	PM8058_TEMP_OVRD_ST2		0x01
-#define	PM8058_TEMP_OVRD_MASK		0x03
-
-#define	PM8058_TEMP_STAGE_STEP		20000	/* Stage step: 20 C */
-#define	PM8058_TEMP_STAGE_HYSTERESIS	2000
-
-#define	PM8058_TEMP_THRESH_MIN		105000	/* Threshold Min: 105 C */
-#define	PM8058_TEMP_THRESH_STEP		5000	/* Threshold step: 5 C */
-
-/* TEMP_ALRM_PWM */
-#define	PM8058_TEMP_PWM_EN_MASK		0xC0
-#define	PM8058_TEMP_PWM_EN_SHIFT	6
-#define	PM8058_TEMP_PWM_PER_PRE_MASK	0x38
-#define	PM8058_TEMP_PWM_PER_PRE_SHIFT	3
-#define	PM8058_TEMP_PWM_PER_DIV_MASK	0x07
-#define	PM8058_TEMP_PWM_PER_DIV_SHIFT	0
-
-/* Trips: from critical to less critical */
-#define PM8058_TRIP_STAGE3	0
-#define PM8058_TRIP_STAGE2	1
-#define PM8058_TRIP_STAGE1	2
-#define PM8058_TRIP_NUM		3
-
-#define PM8058_TEMP_ADC_CH	CHANNEL_ADC_DIE_TEMP
-
-struct pm8058_tm_device {
-	struct pm8058_chip		*pm_chip;
-	struct thermal_zone_device	*tz_dev;
-	unsigned long			temp;
-	enum thermal_device_mode	mode;
-	unsigned int			thresh;
-	unsigned int			stage;
-	unsigned int			irq;
-	void				*adc_handle;
-};
-
-enum pmic_thermal_override_mode {
-	SOFTWARE_OVERRIDE_DISABLED = 0,
-	SOFTWARE_OVERRIDE_ENABLED,
-};
-
-static inline int pm8058_tm_read_ctrl(struct pm8058_chip *chip, u8 *reg)
-{
-	int rc;
-
-	rc = pm8058_read(chip, SSBI_REG_TEMP_ALRM_CTRL, reg, 1);
-	if (rc)
-		pr_err("%s: pm8058_read FAIL: rc=%d\n", __func__, rc);
-
-	return rc;
-}
-
-static inline int pm8058_tm_write_ctrl(struct pm8058_chip *chip, u8 reg)
-{
-	int rc;
-
-	rc = pm8058_write(chip, SSBI_REG_TEMP_ALRM_CTRL, &reg, 1);
-	if (rc)
-		pr_err("%s: pm8058_write FAIL: rc=%d\n", __func__, rc);
-
-	return rc;
-}
-
-static inline int pm8058_tm_write_pwm(struct pm8058_chip *chip, u8 reg)
-{
-	int rc;
-
-	rc = pm8058_write(chip, SSBI_REG_TEMP_ALRM_PWM, &reg, 1);
-	if (rc)
-		pr_err("%s: pm8058_write FAIL: rc=%d\n", __func__, rc);
-
-	return rc;
-}
-
-static inline int
-pm8058_tm_shutdown_override(struct pm8058_chip *chip,
-			    enum pmic_thermal_override_mode mode)
-{
-	int rc;
-	u8 reg;
-
-	rc = pm8058_tm_read_ctrl(chip, &reg);
-	if (rc < 0)
-		return rc;
-
-	reg &= ~(PM8058_TEMP_OVRD_MASK | PM8058_TEMP_STATUS_MASK);
-	if (mode == SOFTWARE_OVERRIDE_ENABLED)
-		reg |= (PM8058_TEMP_OVRD_ST3 | PM8058_TEMP_OVRD_ST2) &
-			PM8058_TEMP_OVRD_MASK;
-
-	rc = pm8058_tm_write_ctrl(chip, reg);
-
-	return rc;
-}
-
-static int pm8058_tz_get_temp(struct thermal_zone_device *thermal,
-			      unsigned long *temp)
-{
-	struct pm8058_tm_device *tm = thermal->devdata;
-	DECLARE_COMPLETION_ONSTACK(wait);
-	struct adc_chan_result adc_result = {
-		.physical = 0lu,
-	};
-	int rc;
-
-	if (!tm || !temp)
-		return -EINVAL;
-
-	*temp = tm->temp;
-
-	rc = adc_channel_request_conv(tm->adc_handle, &wait);
-	if (rc < 0) {
-		pr_err("%s: adc_channel_request_conv() failed, rc = %d\n",
-			__func__, rc);
-		return rc;
-	}
-
-	wait_for_completion(&wait);
-
-	rc = adc_channel_read_result(tm->adc_handle, &adc_result);
-	if (rc < 0) {
-		pr_err("%s: adc_channel_read_result() failed, rc = %d\n",
-			__func__, rc);
-		return rc;
-	}
-
-	*temp = adc_result.physical;
-	tm->temp = adc_result.physical;
-
-	return 0;
-}
-
-static int pm8058_tz_get_mode(struct thermal_zone_device *thermal,
-			      enum thermal_device_mode *mode)
-{
-	struct pm8058_tm_device *tm = thermal->devdata;
-
-	if (!tm || !mode)
-		return -EINVAL;
-
-	*mode = tm->mode;
-
-	return 0;
-}
-
-static int pm8058_tz_set_mode(struct thermal_zone_device *thermal,
-			      enum thermal_device_mode mode)
-{
-	struct pm8058_tm_device *tm = thermal->devdata;
-
-	if (!tm)
-		return -EINVAL;
-
-	if (mode != tm->mode) {
-		if (mode == THERMAL_DEVICE_ENABLED)
-			pm8058_tm_shutdown_override(tm->pm_chip,
-						    SOFTWARE_OVERRIDE_ENABLED);
-		else
-			pm8058_tm_shutdown_override(tm->pm_chip,
-						    SOFTWARE_OVERRIDE_DISABLED);
-	}
-	tm->mode = mode;
-
-	return 0;
-}
-
-static int pm8058_tz_get_trip_type(struct thermal_zone_device *thermal,
-				   int trip, enum thermal_trip_type *type)
-{
-	struct pm8058_tm_device *tm = thermal->devdata;
-
-	if (!tm || trip < 0 || !type)
-		return -EINVAL;
-
-	switch (trip) {
-	case PM8058_TRIP_STAGE3:
-		*type = THERMAL_TRIP_CRITICAL;
-		break;
-	case PM8058_TRIP_STAGE2:
-		*type = THERMAL_TRIP_HOT;
-		break;
-	case PM8058_TRIP_STAGE1:
-		*type = THERMAL_TRIP_HOT;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int pm8058_tz_get_trip_temp(struct thermal_zone_device *thermal,
-				   int trip, unsigned long *temp)
-{
-	struct pm8058_tm_device *tm = thermal->devdata;
-	int thresh_temp;
-
-	if (!tm || trip < 0 || !temp)
-		return -EINVAL;
-
-	thresh_temp = tm->thresh * PM8058_TEMP_THRESH_STEP +
-		      PM8058_TEMP_THRESH_MIN;
-
-	switch (trip) {
-	case PM8058_TRIP_STAGE3:
-		thresh_temp += 2 * PM8058_TEMP_STAGE_STEP;
-		break;
-	case PM8058_TRIP_STAGE2:
-		thresh_temp += PM8058_TEMP_STAGE_STEP;
-		break;
-	case PM8058_TRIP_STAGE1:
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	*temp = thresh_temp;
-
-	return 0;
-}
-
-static int pm8058_tz_get_crit_temp(struct thermal_zone_device *thermal,
-				   unsigned long *temp)
-{
-	struct pm8058_tm_device *tm = thermal->devdata;
-
-	if (!tm || !temp)
-		return -EINVAL;
-
-	*temp = tm->thresh * PM8058_TEMP_THRESH_STEP + PM8058_TEMP_THRESH_MIN +
-		2 * PM8058_TEMP_STAGE_STEP;
-
-	return 0;
-}
-
-static struct thermal_zone_device_ops pm8058_thermal_zone_ops = {
-	.get_temp = pm8058_tz_get_temp,
-	.get_mode = pm8058_tz_get_mode,
-	.set_mode = pm8058_tz_set_mode,
-	.get_trip_type = pm8058_tz_get_trip_type,
-	.get_trip_temp = pm8058_tz_get_trip_temp,
-	.get_crit_temp = pm8058_tz_get_crit_temp,
-};
-
-static irqreturn_t pm8058_tm_isr(int irq, void *data)
-{
-	struct pm8058_tm_device *tm = data;
-	int rc;
-	u8 reg;
-
-	rc = pm8058_tm_read_ctrl(tm->pm_chip, &reg);
-	if (rc < 0)
-		goto isr_handled;
-
-	tm->stage = (reg & PM8058_TEMP_STATUS_MASK) >> PM8058_TEMP_STATUS_SHIFT;
-	tm->thresh = (reg & PM8058_TEMP_THRESH_MASK) >>
-			PM8058_TEMP_THRESH_SHIFT;
-
-	if (reg & (PM8058_TEMP_ST2_SD | PM8058_TEMP_ST3_SD)) {
-		reg &= ~(PM8058_TEMP_ST2_SD | PM8058_TEMP_ST3_SD |
-			 PM8058_TEMP_STATUS_MASK);
-		pm8058_tm_write_ctrl(tm->pm_chip, reg);
-	}
-
-	thermal_zone_device_update(tm->tz_dev);
-
-	/* Notify user space */
-	if (tm->mode == THERMAL_DEVICE_ENABLED)
-		kobject_uevent(&tm->tz_dev->device.kobj, KOBJ_CHANGE);
-
-isr_handled:
-	return IRQ_HANDLED;
-}
-
-static int pm8058_tm_init_reg(struct pm8058_tm_device *tm)
-{
-	int rc;
-	u8 reg;
-
-	rc = pm8058_tm_read_ctrl(tm->pm_chip, &reg);
-	if (rc < 0)
-		return rc;
-
-	tm->stage = (reg & PM8058_TEMP_STATUS_MASK) >> PM8058_TEMP_STATUS_SHIFT;
-	tm->temp = 0;
-
-	/* Use temperature threshold set 0: (105, 125, 145) */
-	tm->thresh = 0;
-	reg = (tm->thresh << PM8058_TEMP_THRESH_SHIFT) &
-	      PM8058_TEMP_THRESH_MASK;
-	rc = pm8058_tm_write_ctrl(tm->pm_chip, reg);
-	if (rc < 0)
-		return rc;
-
-	/*
-	 * Set the PMIC alarm module PWM to have a frequency of 8 Hz. This
-	 * helps cut down on the number of unnecessary interrupts fired when
-	 * changing between thermal stages.  Also, Enable the over temperature
-	 * PWM whenever the PMIC is enabled.
-	 */
-	reg =  1 << PM8058_TEMP_PWM_EN_SHIFT |
-	       3 << PM8058_TEMP_PWM_PER_PRE_SHIFT |
-	       3 << PM8058_TEMP_PWM_PER_DIV_SHIFT;
-
-	rc = pm8058_tm_write_pwm(tm->pm_chip, reg);
-
-	return rc;
-}
-
-static int __devinit pmic8058_tm_probe(struct platform_device *pdev)
-{
-	struct pm8058_tm_device *tmdev;
-	struct pm8058_chip *pm_chip;
-	unsigned int irq;
-	int rc;
-
-	pm_chip = dev_get_drvdata(pdev->dev.parent);
-	if (pm_chip == NULL) {
-		pr_err("%s: no driver data passed in.\n", __func__);
-		return -EFAULT;
-	}
-
-	irq = platform_get_irq(pdev, 0);
-	if (!irq) {
-		pr_err("%s: no IRQ passed in.\n", __func__);
-		return -EFAULT;
-	}
-
-	tmdev = kzalloc(sizeof *tmdev, GFP_KERNEL);
-	if (tmdev == NULL) {
-		pr_err("%s: kzalloc() failed.\n", __func__);
-		return -ENOMEM;
-	}
-
-	rc = adc_channel_open(PM8058_TEMP_ADC_CH, &(tmdev->adc_handle));
-	if (rc < 0) {
-		pr_err("%s: adc_channel_open() failed.\n", __func__);
-		kfree(tmdev);
-		return rc;
-	}
-
-	tmdev->pm_chip = pm_chip;
-	tmdev->tz_dev = thermal_zone_device_register("pm8058_tz",
-						     PM8058_TRIP_NUM, tmdev,
-						     &pm8058_thermal_zone_ops,
-						     0, 0, 0, 0);
-	if (tmdev->tz_dev == NULL) {
-		pr_err("%s: thermal_zone_device_register() failed.\n",
-		       __func__);
-		adc_channel_close(tmdev->adc_handle);
-		kfree(tmdev);
-		return -ENODEV;
-	}
-
-	rc = pm8058_tm_init_reg(tmdev);
-	pm8058_tm_shutdown_override(tmdev->pm_chip, SOFTWARE_OVERRIDE_DISABLED);
-	if (rc < 0) {
-		thermal_zone_device_unregister(tmdev->tz_dev);
-		adc_channel_close(tmdev->adc_handle);
-		kfree(tmdev);
-		return rc;
-	}
-
-	/* start in HW control, switch to SW control when user changes mode */
-	tmdev->mode = THERMAL_DEVICE_DISABLED;
-	thermal_zone_device_update(tmdev->tz_dev);
-
-	platform_set_drvdata(pdev, tmdev);
-
-	rc = request_threaded_irq(irq, NULL, pm8058_tm_isr,
-			 IRQF_TRIGGER_RISING | IRQF_DISABLED,
-			 "pm8058-tm-irq", tmdev);
-	if (rc < 0) {
-		pr_err("%s: request_irq(%d) FAIL: %d\n", __func__, irq, rc);
-		thermal_zone_device_unregister(tmdev->tz_dev);
-		platform_set_drvdata(pdev, tmdev->pm_chip);
-		adc_channel_close(tmdev->adc_handle);
-		kfree(tmdev);
-		return rc;
-	}
-	tmdev->irq = irq;
-
-	pr_notice("%s: OK\n", __func__);
-	return 0;
-}
-
-static int __devexit pmic8058_tm_remove(struct platform_device *pdev)
-{
-	struct pm8058_tm_device *tmdev = platform_get_drvdata(pdev);
-
-	thermal_zone_device_unregister(tmdev->tz_dev);
-	platform_set_drvdata(pdev, tmdev->pm_chip);
-	pm8058_tm_shutdown_override(tmdev->pm_chip, THERMAL_DEVICE_DISABLED);
-	adc_channel_close(tmdev->adc_handle);
-	free_irq(tmdev->irq, tmdev);
-	kfree(tmdev);
-
-	return 0;
-}
-
-#ifdef CONFIG_PM
-static int pmic8058_tm_suspend(struct device *dev)
-{
-	struct platform_device *pdev = to_platform_device(dev);
-	struct pm8058_tm_device *tm = platform_get_drvdata(pdev);
-
-	/* Clear override bits in suspend to allow hardware control */
-	pm8058_tm_shutdown_override(tm->pm_chip, SOFTWARE_OVERRIDE_DISABLED);
-
-	return 0;
-}
-
-static int pmic8058_tm_resume(struct device *dev)
-{
-	struct platform_device *pdev = to_platform_device(dev);
-	struct pm8058_tm_device *tm = platform_get_drvdata(pdev);
-
-	/* Override hardware actions so software can control */
-	if (tm->mode == THERMAL_DEVICE_ENABLED)
-		pm8058_tm_shutdown_override(tm->pm_chip,
-					    SOFTWARE_OVERRIDE_ENABLED);
-
-	return 0;
-}
-
-static const struct dev_pm_ops pmic8058_tm_pm_ops = {
-	.suspend = pmic8058_tm_suspend,
-	.resume = pmic8058_tm_resume,
-};
-
-#define PM8058_TM_PM_OPS	(&pmic8058_tm_pm_ops)
-#else
-#define PM8058_TM_PM_OPS	NULL
-#endif
-
-static struct platform_driver pmic8058_tm_driver = {
-	.probe	= pmic8058_tm_probe,
-	.remove	= __devexit_p(pmic8058_tm_remove),
-	.driver	= {
-		.name = "pm8058-tm",
-		.owner = THIS_MODULE,
-		.pm = PM8058_TM_PM_OPS,
-	},
-};
-
-static int __init pm8058_tm_init(void)
-{
-	return platform_driver_register(&pmic8058_tm_driver);
-}
-
-static void __exit pm8058_tm_exit(void)
-{
-	platform_driver_unregister(&pmic8058_tm_driver);
-}
-
-module_init(pm8058_tm_init);
-module_exit(pm8058_tm_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("PMIC8058 Thermal Manager driver");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:pmic8058-tm");
diff --git a/drivers/thermal/pmic8901-tm.c b/drivers/thermal/pmic8901-tm.c
deleted file mode 100644
index 0ff5788..0000000
--- a/drivers/thermal/pmic8901-tm.c
+++ /dev/null
@@ -1,594 +0,0 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. 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 version 2 and
- * only 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.
- *
- */
-/*
- * Qualcomm PMIC8901 Thermal Manager driver
- *
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/thermal.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/mfd/pmic8901.h>
-
-/* PMIC8901 TEMP_ALRM registers */
-#define	SSBI_REG_TEMP_ALRM_CTRL		0x23
-#define	SSBI_REG_TEMP_ALRM_PWM		0x24
-
-/* TEMP_ALRM_CTRL */
-#define	PM8901_TEMP_ST3_SD		0x80
-#define	PM8901_TEMP_ST2_SD		0x40
-#define	PM8901_TEMP_STATUS_MASK		0x30
-#define	PM8901_TEMP_STATUS_SHIFT	4
-#define	PM8901_TEMP_THRESH_MASK		0x0C
-#define	PM8901_TEMP_THRESH_SHIFT	2
-#define	PM8901_TEMP_OVRD_ST3		0x02
-#define	PM8901_TEMP_OVRD_ST2		0x01
-#define	PM8901_TEMP_OVRD_MASK		0x03
-
-#define	PM8901_TEMP_STAGE_STEP		20000	/* Stage step: 20 C */
-#define	PM8901_TEMP_STAGE_HYSTERESIS	2000
-
-#define	PM8901_TEMP_THRESH_MIN		105000	/* Threshold Min: 105 C */
-#define	PM8901_TEMP_THRESH_STEP		5000	/* Threshold step: 5 C */
-
-/* TEMP_ALRM_PWM */
-#define	PM8901_TEMP_PWM_EN_MASK		0xC0
-#define	PM8901_TEMP_PWM_EN_SHIFT	6
-#define	PM8901_TEMP_PWM_PER_PRE_MASK	0x38
-#define	PM8901_TEMP_PWM_PER_PRE_SHIFT	3
-#define	PM8901_TEMP_PWM_PER_DIV_MASK	0x07
-#define	PM8901_TEMP_PWM_PER_DIV_SHIFT	0
-
-/* Trips: from critical to less critical */
-#define PM8901_TRIP_STAGE3	0
-#define PM8901_TRIP_STAGE2	1
-#define PM8901_TRIP_STAGE1	2
-#define PM8901_TRIP_NUM		3
-
-/* Used because there is no means to read the die temperature */
-#define DEFAULT_NO_ADC_TEMP	37000
-
-struct pm8901_tm_device {
-	struct pm8901_chip		*pm_chip;
-	struct thermal_zone_device	*tz_dev;
-	unsigned long			temp;
-	enum thermal_device_mode	mode;
-	unsigned int			thresh;
-	unsigned int			stage;
-	unsigned int			irq;
-	unsigned int			hi_irq;
-};
-
-enum pmic_thermal_override_mode {
-	SOFTWARE_OVERRIDE_DISABLED = 0,
-	SOFTWARE_OVERRIDE_ENABLED,
-};
-
-static inline int pm8901_tm_read_ctrl(struct pm8901_chip *chip, u8 *reg)
-{
-	int rc;
-
-	rc = pm8901_read(chip, SSBI_REG_TEMP_ALRM_CTRL, reg, 1);
-	if (rc)
-		pr_err("%s: pm8901_read FAIL: rc=%d\n", __func__, rc);
-
-	return rc;
-}
-
-static inline int pm8901_tm_write_ctrl(struct pm8901_chip *chip, u8 reg)
-{
-	int rc;
-
-	rc = pm8901_write(chip, SSBI_REG_TEMP_ALRM_CTRL, &reg, 1);
-	if (rc)
-		pr_err("%s: pm8901_write FAIL: rc=%d\n", __func__, rc);
-
-	return rc;
-}
-
-static inline int pm8901_tm_read_pwm(struct pm8901_chip *chip, u8 *reg)
-{
-	int rc;
-
-	rc = pm8901_read(chip, SSBI_REG_TEMP_ALRM_PWM, reg, 1);
-	if (rc)
-		pr_err("%s: pm8901_read FAIL: rc=%d\n", __func__, rc);
-
-	return rc;
-}
-
-static inline int pm8901_tm_write_pwm(struct pm8901_chip *chip, u8 reg)
-{
-	int rc;
-
-	rc = pm8901_write(chip, SSBI_REG_TEMP_ALRM_PWM, &reg, 1);
-	if (rc)
-		pr_err("%s: pm8901_write FAIL: rc=%d\n", __func__, rc);
-
-	return rc;
-}
-
-static inline int
-pm8901_tm_shutdown_override(struct pm8901_chip *chip,
-			    enum pmic_thermal_override_mode mode)
-{
-	int rc;
-	u8 reg;
-
-	rc = pm8901_tm_read_ctrl(chip, &reg);
-	if (rc < 0)
-		return rc;
-
-	reg &= ~(PM8901_TEMP_OVRD_MASK | PM8901_TEMP_STATUS_MASK);
-	if (mode == SOFTWARE_OVERRIDE_ENABLED)
-		reg |= (PM8901_TEMP_OVRD_ST3 | PM8901_TEMP_OVRD_ST2) &
-			PM8901_TEMP_OVRD_MASK;
-
-	rc = pm8901_tm_write_ctrl(chip, reg);
-
-	return rc;
-}
-
-/*
- * This function initializes the internal temperature value based on only the
- * current thermal stage and threshold.
- */
-static int pm8901_tm_init_temp(struct pm8901_tm_device *tm)
-{
-	int rc;
-	u8 reg;
-
-	rc = pm8901_tm_read_ctrl(tm->pm_chip, &reg);
-	if (rc < 0)
-		return rc;
-
-	tm->stage = (reg & PM8901_TEMP_STATUS_MASK) >> PM8901_TEMP_STATUS_SHIFT;
-	tm->thresh = (reg & PM8901_TEMP_THRESH_MASK) >>
-			PM8901_TEMP_THRESH_SHIFT;
-
-	if (tm->stage) {
-		tm->temp = tm->thresh * PM8901_TEMP_THRESH_STEP +
-			   (tm->stage - 1) * PM8901_TEMP_STAGE_STEP +
-			   PM8901_TEMP_THRESH_MIN;
-	} else
-		tm->temp = DEFAULT_NO_ADC_TEMP;
-
-	return 0;
-}
-
-/*
- * This function updates the internal temperature value based on the
- * current thermal stage and threshold as well as the previous stage
- */
-static int pm8901_tm_update_temp(struct pm8901_tm_device *tm)
-{
-	unsigned int stage;
-	int rc;
-	u8 reg;
-
-	rc = pm8901_tm_read_ctrl(tm->pm_chip, &reg);
-	if (rc < 0)
-		return rc;
-
-	stage = (reg & PM8901_TEMP_STATUS_MASK) >> PM8901_TEMP_STATUS_SHIFT;
-	tm->thresh = (reg & PM8901_TEMP_THRESH_MASK) >>
-			PM8901_TEMP_THRESH_SHIFT;
-
-	if (stage > tm->stage) {
-		/* increasing stage, use lower bound */
-		tm->temp = (stage-1) * PM8901_TEMP_STAGE_STEP +
-			   tm->thresh * PM8901_TEMP_THRESH_STEP +
-			   PM8901_TEMP_STAGE_HYSTERESIS +
-			   PM8901_TEMP_THRESH_MIN;
-	} else if (stage < tm->stage) {
-		/* decreasing stage, use upper bound */
-		tm->temp = stage * PM8901_TEMP_STAGE_STEP +
-			   tm->thresh * PM8901_TEMP_THRESH_STEP -
-			   PM8901_TEMP_STAGE_HYSTERESIS +
-			   PM8901_TEMP_THRESH_MIN;
-	}
-
-	tm->stage = stage;
-
-	return 0;
-}
-
-static int pm8901_tz_get_temp(struct thermal_zone_device *thermal,
-			      unsigned long *temp)
-{
-	struct pm8901_tm_device *tm = thermal->devdata;
-	int rc;
-
-	if (!tm || !temp)
-		return -EINVAL;
-
-	rc = pm8901_tm_update_temp(tm);
-	if (rc < 0)
-		return rc;
-
-	*temp = tm->temp;
-
-	return 0;
-}
-
-static int pm8901_tz_get_mode(struct thermal_zone_device *thermal,
-			      enum thermal_device_mode *mode)
-{
-	struct pm8901_tm_device *tm = thermal->devdata;
-
-	if (!tm || !mode)
-		return -EINVAL;
-
-	*mode = tm->mode;
-
-	return 0;
-}
-
-static int pm8901_tz_set_mode(struct thermal_zone_device *thermal,
-			      enum thermal_device_mode mode)
-{
-	struct pm8901_tm_device *tm = thermal->devdata;
-
-	if (!tm)
-		return -EINVAL;
-
-	if (mode != tm->mode) {
-		pr_info("%s: mode: %d --> %d\n", __func__, tm->mode, mode);
-
-		if (mode == THERMAL_DEVICE_ENABLED)
-			pm8901_tm_shutdown_override(tm->pm_chip,
-						    SOFTWARE_OVERRIDE_ENABLED);
-		else
-			pm8901_tm_shutdown_override(tm->pm_chip,
-						    SOFTWARE_OVERRIDE_DISABLED);
-	}
-	tm->mode = mode;
-
-	return 0;
-}
-
-static int pm8901_tz_get_trip_type(struct thermal_zone_device *thermal,
-				   int trip, enum thermal_trip_type *type)
-{
-	struct pm8901_tm_device *tm = thermal->devdata;
-
-	if (!tm || trip < 0 || !type)
-		return -EINVAL;
-
-	switch (trip) {
-	case PM8901_TRIP_STAGE3:
-		*type = THERMAL_TRIP_CRITICAL;
-		break;
-	case PM8901_TRIP_STAGE2:
-		*type = THERMAL_TRIP_HOT;
-		break;
-	case PM8901_TRIP_STAGE1:
-		*type = THERMAL_TRIP_HOT;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int pm8901_tz_get_trip_temp(struct thermal_zone_device *thermal,
-				   int trip, unsigned long *temp)
-{
-	struct pm8901_tm_device *tm = thermal->devdata;
-	int thresh_temp;
-
-	if (!tm || trip < 0 || !temp)
-		return -EINVAL;
-
-	thresh_temp = tm->thresh * PM8901_TEMP_THRESH_STEP +
-		      PM8901_TEMP_THRESH_MIN;
-
-	switch (trip) {
-	case PM8901_TRIP_STAGE3:
-		thresh_temp += 2 * PM8901_TEMP_STAGE_STEP;
-		break;
-	case PM8901_TRIP_STAGE2:
-		thresh_temp += PM8901_TEMP_STAGE_STEP;
-		break;
-	case PM8901_TRIP_STAGE1:
-		break;
-	default:
-		return -EINVAL;
-	}
-	*temp = thresh_temp;
-
-	return 0;
-}
-
-static int pm8901_tz_get_crit_temp(struct thermal_zone_device *thermal,
-				   unsigned long *temp)
-{
-	struct pm8901_tm_device *tm = thermal->devdata;
-
-	if (!tm || !temp)
-		return -EINVAL;
-
-	*temp = tm->thresh * PM8901_TEMP_THRESH_STEP +
-			PM8901_TEMP_THRESH_MIN + 2 * PM8901_TEMP_STAGE_STEP;
-
-	return 0;
-}
-
-static struct thermal_zone_device_ops pm8901_thermal_zone_ops = {
-	.get_temp = pm8901_tz_get_temp,
-	.get_mode = pm8901_tz_get_mode,
-	.set_mode = pm8901_tz_set_mode,
-	.get_trip_type = pm8901_tz_get_trip_type,
-	.get_trip_temp = pm8901_tz_get_trip_temp,
-	.get_crit_temp = pm8901_tz_get_crit_temp,
-};
-
-static irqreturn_t pm8901_tm_isr(int irq, void *data)
-{
-	struct pm8901_tm_device *tm = data;
-	int rc;
-	u8 reg;
-
-	rc = pm8901_tm_update_temp(tm);
-	if (rc < 0)
-		goto isr_handled;
-
-	rc = pm8901_tm_read_ctrl(tm->pm_chip, &reg);
-	if (rc < 0)
-		goto isr_handled;
-
-	pr_info("%s: Temp Alarm - stage=%u, threshold=%u, temp=%lu\n",
-		__func__, tm->stage, tm->thresh, tm->temp);
-
-	if (reg & (PM8901_TEMP_ST2_SD | PM8901_TEMP_ST3_SD)) {
-		reg &= ~(PM8901_TEMP_ST2_SD | PM8901_TEMP_ST3_SD |
-			 PM8901_TEMP_STATUS_MASK);
-
-		pm8901_tm_write_ctrl(tm->pm_chip, reg);
-	}
-
-	thermal_zone_device_update(tm->tz_dev);
-
-	/* Notify user space */
-	if (tm->mode == THERMAL_DEVICE_ENABLED)
-		kobject_uevent(&tm->tz_dev->device.kobj, KOBJ_CHANGE);
-
-isr_handled:
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t pm8901_tm_isr1(int irq, void *data)
-{
-	struct pm8901_tm_device *tm = data;
-	irqreturn_t rc;
-
-	disable_irq(tm->hi_irq);
-	rc = pm8901_tm_isr(irq, data);
-	enable_irq(tm->hi_irq);
-
-	return rc;
-}
-
-static irqreturn_t pm8901_tm_isr2(int irq, void *data)
-{
-	struct pm8901_tm_device *tm = data;
-	irqreturn_t rc;
-
-	disable_irq(tm->irq);
-	rc = pm8901_tm_isr(irq, data);
-	enable_irq(tm->irq);
-
-	return rc;
-}
-
-static int pm8901_tm_init_reg(struct pm8901_tm_device *tm)
-{
-	int rc;
-	u8 reg;
-
-	rc = pm8901_tm_init_temp(tm);
-	if (rc < 0)
-		return rc;
-
-	/* Use temperature threshold set 0: (105, 125, 145) */
-	tm->thresh = 0;
-	reg = (tm->thresh << PM8901_TEMP_THRESH_SHIFT) &
-	      PM8901_TEMP_THRESH_MASK;
-	rc = pm8901_tm_write_ctrl(tm->pm_chip, reg);
-	if (rc < 0)
-		return rc;
-
-	/*
-	 * Set the PMIC alarm module PWM to have a frequency of 8 Hz. This
-	 * helps cut down on the number of unnecessary interrupts fired when
-	 * changing between thermal stages.  Also, Enable the over temperature
-	 * PWM whenever the PMIC is enabled.
-	 */
-	reg =  1 << PM8901_TEMP_PWM_EN_SHIFT |
-	       3 << PM8901_TEMP_PWM_PER_PRE_SHIFT |
-	       3 << PM8901_TEMP_PWM_PER_DIV_SHIFT;
-
-	rc = pm8901_tm_write_pwm(tm->pm_chip, reg);
-
-	return rc;
-}
-
-static int __devinit pmic8901_tm_probe(struct platform_device *pdev)
-{
-	struct pm8901_tm_device	*tmdev;
-	struct pm8901_chip *pm_chip;
-	unsigned int irq, hi_irq;
-	int rc;
-
-	pm_chip = dev_get_drvdata(pdev->dev.parent);
-	if (pm_chip == NULL) {
-		pr_err("%s: no driver data passed in.\n", __func__);
-		return -EFAULT;
-	}
-
-	irq = platform_get_irq(pdev, 0);
-	if (!irq) {
-		pr_err("%s: no IRQ passed in.\n", __func__);
-		return -EFAULT;
-	}
-	hi_irq = platform_get_irq(pdev, 1);
-	if (!hi_irq) {
-		pr_err("%s: no HI IRQ passed in.\n", __func__);
-		return -EFAULT;
-	}
-
-	tmdev = kzalloc(sizeof *tmdev, GFP_KERNEL);
-	if (tmdev == NULL) {
-		pr_err("%s: kzalloc() failed.\n", __func__);
-		return -ENOMEM;
-	}
-
-	tmdev->pm_chip = pm_chip;
-	tmdev->tz_dev = thermal_zone_device_register("pm8901_tz",
-						     PM8901_TRIP_NUM, tmdev,
-						     &pm8901_thermal_zone_ops,
-						     0, 0, 0, 0);
-	if (tmdev->tz_dev == NULL) {
-		pr_err("%s: thermal_zone_device_register() failed.\n",
-		       __func__);
-		kfree(tmdev);
-		return -ENODEV;
-	}
-
-	rc = pm8901_tm_init_reg(tmdev);
-	pm8901_tm_shutdown_override(tmdev->pm_chip, SOFTWARE_OVERRIDE_DISABLED);
-	if (rc < 0) {
-		thermal_zone_device_unregister(tmdev->tz_dev);
-		kfree(tmdev);
-		return rc;
-	}
-
-	/* start in HW control, switch to SW control when user changes mode */
-	tmdev->mode = THERMAL_DEVICE_DISABLED;
-	thermal_zone_device_update(tmdev->tz_dev);
-
-	platform_set_drvdata(pdev, tmdev);
-
-	rc = request_threaded_irq(irq, pm8901_tm_isr1, NULL,
-			 IRQF_TRIGGER_RISING | IRQF_DISABLED,
-			 "pm8901-tm-irq", tmdev);
-	if (rc < 0) {
-		pr_err("%s: request_threaded_irq(%d) FAIL: %d\n",
-		       __func__, irq, rc);
-
-		thermal_zone_device_unregister(tmdev->tz_dev);
-		platform_set_drvdata(pdev, tmdev->pm_chip);
-		kfree(tmdev);
-		return -ENODEV;
-	}
-	tmdev->irq = irq;
-
-	rc = request_threaded_irq(hi_irq, pm8901_tm_isr2, NULL,
-			 IRQF_TRIGGER_RISING | IRQF_DISABLED,
-			 "pm8901-tm-irq2", tmdev);
-	if (rc < 0) {
-		pr_err("%s: request_threaded_irq(%d) FAIL: %d\n",
-		       __func__, hi_irq, rc);
-
-		free_irq(irq, tmdev);
-		thermal_zone_device_unregister(tmdev->tz_dev);
-		platform_set_drvdata(pdev, tmdev->pm_chip);
-		kfree(tmdev);
-		return -ENODEV;
-	}
-	tmdev->hi_irq = hi_irq;
-
-	pr_notice("%s: OK\n", __func__);
-	return 0;
-}
-
-static int __devexit pmic8901_tm_remove(struct platform_device *pdev)
-{
-	struct pm8901_tm_device *tmdev = platform_get_drvdata(pdev);
-
-	free_irq(tmdev->hi_irq, tmdev);
-	free_irq(tmdev->irq, tmdev);
-	thermal_zone_device_unregister(tmdev->tz_dev);
-	platform_set_drvdata(pdev, tmdev->pm_chip);
-	pm8901_tm_shutdown_override(tmdev->pm_chip, SOFTWARE_OVERRIDE_DISABLED);
-	kfree(tmdev);
-
-	return 0;
-}
-
-#ifdef CONFIG_PM
-static int pmic8901_tm_suspend(struct device *dev)
-{
-	struct platform_device *pdev = to_platform_device(dev);
-	struct pm8901_tm_device *tm = platform_get_drvdata(pdev);
-
-	pm8901_tm_shutdown_override(tm->pm_chip, SOFTWARE_OVERRIDE_DISABLED);
-
-	return 0;
-}
-
-static int pmic8901_tm_resume(struct device *dev)
-{
-	struct platform_device *pdev = to_platform_device(dev);
-	struct pm8901_tm_device *tm = platform_get_drvdata(pdev);
-
-	pm8901_tm_init_temp(tm);
-
-	if (tm->mode == THERMAL_DEVICE_ENABLED)
-		pm8901_tm_shutdown_override(tm->pm_chip,
-					    SOFTWARE_OVERRIDE_ENABLED);
-
-	return 0;
-}
-
-static const struct dev_pm_ops pmic8901_tm_pm_ops = {
-	.suspend = pmic8901_tm_suspend,
-	.resume = pmic8901_tm_resume,
-};
-
-#define PM8901_TM_PM_OPS	(&pmic8901_tm_pm_ops)
-#else
-#define PM8901_TM_PM_OPS	NULL
-#endif
-
-static struct platform_driver pmic8901_tm_driver = {
-	.probe		= pmic8901_tm_probe,
-	.remove		= __devexit_p(pmic8901_tm_remove),
-	.driver		= {
-		.name = "pm8901-tm",
-		.owner = THIS_MODULE,
-		.pm = PM8901_TM_PM_OPS,
-	},
-};
-
-static int __init pm8901_tm_init(void)
-{
-	return platform_driver_register(&pmic8901_tm_driver);
-}
-
-static void __exit pm8901_tm_exit(void)
-{
-	platform_driver_unregister(&pmic8901_tm_driver);
-}
-
-module_init(pm8901_tm_init);
-module_exit(pm8901_tm_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("PMIC8901 Thermal Manager driver");
-MODULE_VERSION("1.0");
-MODULE_ALIAS("platform:pmic8901-tm");
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 047df1a..9dc4044 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -2,6 +2,7 @@
  * Gadget Driver for Android
  *
  * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
  * Author: Mike Lockwood <lockwood@android.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -60,7 +61,7 @@
 #include "u_ctrl_hsic.c"
 #include "u_data_hsic.c"
 #include "f_serial.c"
-//#include "f_acm.c"
+#include "f_acm.c"
 #include "f_adb.c"
 #include "f_ccid.c"
 #include "f_mtp.c"
@@ -476,6 +477,77 @@
 	.attributes	= serial_function_attributes,
 };
 
+/* ACM */
+static char acm_transports[32];	/*enabled ACM ports - "tty[,sdio]"*/
+static ssize_t acm_transports_store(
+		struct device *device, struct device_attribute *attr,
+		const char *buff, size_t size)
+{
+	strlcpy(acm_transports, buff, sizeof(acm_transports));
+
+	return size;
+}
+
+static DEVICE_ATTR(acm_transports, S_IWUSR, NULL, acm_transports_store);
+static struct device_attribute *acm_function_attributes[] = {
+		&dev_attr_acm_transports, NULL };
+
+static void acm_function_cleanup(struct android_usb_function *f)
+{
+	gserial_cleanup();
+}
+
+static int acm_function_bind_config(struct android_usb_function *f,
+					struct usb_configuration *c)
+{
+	char *name;
+	char buf[32], *b;
+	int err = -1, i;
+	static int acm_initialized, ports;
+
+	if (acm_initialized)
+		goto bind_config;
+
+	acm_initialized = 1;
+	strlcpy(buf, acm_transports, sizeof(buf));
+	b = strim(buf);
+
+	while (b) {
+		name = strsep(&b, ",");
+
+		if (name) {
+			err = acm_init_port(ports, name);
+			if (err) {
+				pr_err("acm: Cannot open port '%s'", name);
+				goto out;
+			}
+			ports++;
+		}
+	}
+	err = acm_port_setup(c);
+	if (err) {
+		pr_err("acm: Cannot setup transports");
+		goto out;
+	}
+
+bind_config:
+	for (i = 0; i < ports; i++) {
+		err = acm_bind_config(c, i);
+		if (err) {
+			pr_err("acm: bind_config failed for port %d", i);
+			goto out;
+		}
+	}
+
+out:
+	return err;
+}
+static struct android_usb_function acm_function = {
+	.name		= "acm",
+	.cleanup	= acm_function_cleanup,
+	.bind_config	= acm_function_bind_config,
+	.attributes	= acm_function_attributes,
+};
 
 /* ADB */
 static int adb_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev)
@@ -525,79 +597,6 @@
 	.bind_config	= ccid_function_bind_config,
 };
 
-#if 0
-#define MAX_ACM_INSTANCES 4
-struct acm_function_config {
-	int instances;
-};
-
-static int acm_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev)
-{
-	f->config = kzalloc(sizeof(struct acm_function_config), GFP_KERNEL);
-	if (!f->config)
-		return -ENOMEM;
-
-	return gserial_setup(cdev->gadget, MAX_ACM_INSTANCES);
-}
-
-static void acm_function_cleanup(struct android_usb_function *f)
-{
-	gserial_cleanup();
-	kfree(f->config);
-	f->config = NULL;
-}
-
-static int acm_function_bind_config(struct android_usb_function *f, struct usb_configuration *c)
-{
-	int i;
-	int ret = 0;
-	struct acm_function_config *config = f->config;
-
-	for (i = 0; i < config->instances; i++) {
-		ret = acm_bind_config(c, i);
-		if (ret) {
-			pr_err("Could not bind acm%u config\n", i);
-			break;
-		}
-	}
-
-	return ret;
-}
-
-static ssize_t acm_instances_show(struct device *dev,
-		struct device_attribute *attr, char *buf)
-{
-	struct android_usb_function *f = dev_get_drvdata(dev);
-	struct acm_function_config *config = f->config;
-	return sprintf(buf, "%d\n", config->instances);
-}
-
-static ssize_t acm_instances_store(struct device *dev,
-		struct device_attribute *attr, const char *buf, size_t size)
-{
-	struct android_usb_function *f = dev_get_drvdata(dev);
-	struct acm_function_config *config = f->config;
-	int value;
-
-	sscanf(buf, "%d", &value);
-	if (value > MAX_ACM_INSTANCES)
-		value = MAX_ACM_INSTANCES;
-	config->instances = value;
-	return size;
-}
-
-static DEVICE_ATTR(instances, S_IRUGO | S_IWUSR, acm_instances_show, acm_instances_store);
-static struct device_attribute *acm_function_attributes[] = { &dev_attr_instances, NULL };
-
-static struct android_usb_function acm_function = {
-	.name		= "acm",
-	.init		= acm_function_init,
-	.cleanup	= acm_function_cleanup,
-	.bind_config	= acm_function_bind_config,
-	.attributes	= acm_function_attributes,
-};
-#endif
-
 static int mtp_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev)
 {
 	return mtp_setup();
@@ -969,7 +968,7 @@
 	&serial_function,
 	&adb_function,
 	&ccid_function,
-//	&acm_function,
+	&acm_function,
 	&mtp_function,
 	&ptp_function,
 	&rndis_function,
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 6282389..703494a 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -1844,6 +1844,14 @@
 		}
 		mReq->req.status = -ESHUTDOWN;
 
+		if (mReq->map) {
+			dma_unmap_single(mEp->device, mReq->req.dma,
+				mReq->req.length,
+				mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+			mReq->req.dma = 0;
+			mReq->map     = 0;
+		}
+
 		if (mReq->req.complete != NULL) {
 			spin_unlock(mEp->lock);
 			if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index 7299dff..69a36af 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -19,6 +19,7 @@
 #include <linux/kernel.h>
 #include <linux/device.h>
 #include <linux/usb/android_composite.h>
+#include <mach/usb_gadget_xport.h>
 
 #include "u_serial.h"
 #include "gadget_chips.h"
@@ -86,12 +87,12 @@
 #define ACM_CTRL_DCD		(1 << 0)
 };
 
-static unsigned int no_tty_ports;
-static unsigned int no_sdio_ports;
-static unsigned int no_smd_ports;
-static unsigned int nr_ports;
+static unsigned int no_acm_tty_ports;
+static unsigned int no_acm_sdio_ports;
+static unsigned int no_acm_smd_ports;
+static unsigned int nr_acm_ports;
 
-static struct port_info {
+static struct acm_port_info {
 	enum transport_type	transport;
 	unsigned		port_num;
 	unsigned		client_port_num;
@@ -107,24 +108,25 @@
 	return container_of(p, struct f_acm, port);
 }
 
-static int gport_setup(struct usb_configuration *c)
+static int acm_port_setup(struct usb_configuration *c)
 {
 	int ret = 0;
 
-	pr_debug("%s: no_tty_ports:%u no_sdio_ports: %u nr_ports:%u\n",
-			__func__, no_tty_ports, no_sdio_ports, nr_ports);
+	pr_debug("%s: no_acm_tty_ports:%u no_acm_sdio_ports: %u nr_acm_ports:%u\n",
+			__func__, no_acm_tty_ports, no_acm_sdio_ports,
+				nr_acm_ports);
 
-	if (no_tty_ports)
-		ret = gserial_setup(c->cdev->gadget, no_tty_ports);
-	if (no_sdio_ports)
-		ret = gsdio_setup(c->cdev->gadget, no_sdio_ports);
-	if (no_smd_ports)
-		ret = gsmd_setup(c->cdev->gadget, no_smd_ports);
+	if (no_acm_tty_ports)
+		ret = gserial_setup(c->cdev->gadget, no_acm_tty_ports);
+	if (no_acm_sdio_ports)
+		ret = gsdio_setup(c->cdev->gadget, no_acm_sdio_ports);
+	if (no_acm_smd_ports)
+		ret = gsmd_setup(c->cdev->gadget, no_acm_smd_ports);
 
 	return ret;
 }
 
-static int gport_connect(struct f_acm *acm)
+static int acm_port_connect(struct f_acm *acm)
 {
 	unsigned port_num;
 
@@ -136,13 +138,13 @@
 			acm, &acm->port, acm->port_num, port_num);
 
 	switch (acm->transport) {
-	case USB_GADGET_FSERIAL_TRANSPORT_TTY:
+	case USB_GADGET_XPORT_TTY:
 		gserial_connect(&acm->port, port_num);
 		break;
-	case USB_GADGET_FSERIAL_TRANSPORT_SDIO:
+	case USB_GADGET_XPORT_SDIO:
 		gsdio_connect(&acm->port, port_num);
 		break;
-	case USB_GADGET_FSERIAL_TRANSPORT_SMD:
+	case USB_GADGET_XPORT_SMD:
 		gsmd_connect(&acm->port, port_num);
 		break;
 	default:
@@ -154,7 +156,7 @@
 	return 0;
 }
 
-static int gport_disconnect(struct f_acm *acm)
+static int acm_port_disconnect(struct f_acm *acm)
 {
 	unsigned port_num;
 
@@ -165,13 +167,13 @@
 			acm, &acm->port, acm->port_num, port_num);
 
 	switch (acm->transport) {
-	case USB_GADGET_FSERIAL_TRANSPORT_TTY:
+	case USB_GADGET_XPORT_TTY:
 		gserial_disconnect(&acm->port);
 		break;
-	case USB_GADGET_FSERIAL_TRANSPORT_SDIO:
+	case USB_GADGET_XPORT_SDIO:
 		gsdio_disconnect(&acm->port, port_num);
 		break;
-	case USB_GADGET_FSERIAL_TRANSPORT_SMD:
+	case USB_GADGET_XPORT_SMD:
 		gsmd_disconnect(&acm->port, port_num);
 		break;
 	default:
@@ -504,7 +506,7 @@
 	} else if (intf == acm->data_id) {
 		if (acm->port.in->driver_data) {
 			DBG(cdev, "reset acm ttyGS%d\n", acm->port_num);
-			gport_disconnect(acm);
+			acm_port_disconnect(acm);
 		} else {
 			DBG(cdev, "activate acm ttyGS%d\n", acm->port_num);
 		}
@@ -512,7 +514,7 @@
 				acm->hs.in, acm->fs.in);
 		acm->port.out_desc = ep_choose(cdev->gadget,
 				acm->hs.out, acm->fs.out);
-		gport_connect(acm);
+		acm_port_connect(acm);
 
 	} else
 		return -EINVAL;
@@ -526,7 +528,7 @@
 	struct usb_composite_dev *cdev = f->config->cdev;
 
 	DBG(cdev, "acm ttyGS%d deactivated\n", acm->port_num);
-	gport_disconnect(acm);
+	acm_port_disconnect(acm);
 	usb_ep_disable(acm->notify);
 	acm->notify->driver_data = NULL;
 }
@@ -888,116 +890,43 @@
 	return status;
 }
 
-#ifdef CONFIG_USB_ANDROID_ACM
-#include <linux/platform_device.h>
-
-static struct acm_platform_data *acm_pdata;
-
-static int acm_probe(struct platform_device *pdev)
+/**
+ * acm_init_port - bind a acm_port to its transport
+ */
+static int acm_init_port(int port_num, const char *name)
 {
-	acm_pdata = pdev->dev.platform_data;
-	return 0;
-}
+	enum transport_type transport;
 
-static struct platform_driver acm_platform_driver = {
-	.driver = { .name = "acm", },
-	.probe = acm_probe,
-};
+	if (port_num >= GSERIAL_NO_PORTS)
+		return -ENODEV;
 
-int acm1_function_bind_config(struct usb_configuration *c)
-{
-	int ret = acm_bind_config(c, 0);
-	if (ret == 0)
-		gport_setup(c);
-	return ret;
-}
+	transport = str_to_xport(name);
+	pr_debug("%s, port:%d, transport:%s\n", __func__,
+			port_num, xport_to_str(transport));
 
-int acm2_function_bind_config(struct usb_configuration *c)
-{
-	int ret = acm_bind_config(c, 1);
+	gacm_ports[port_num].transport = transport;
+	gacm_ports[port_num].port_num = port_num;
 
-	return ret;
-}
-
-static struct android_usb_function acm1_function = {
-	.name = "acm1",
-	.bind_config = acm1_function_bind_config,
-};
-
-static struct android_usb_function acm2_function = {
-	.name = "acm2",
-	.bind_config = acm2_function_bind_config,
-};
-
-static int facm_remove(struct platform_device *pdev)
-{
-	gserial_cleanup();
-
-	return 0;
-}
-
-static struct platform_driver usb_facm = {
-	.remove		= facm_remove,
-	.driver = {
-		.name = "usb_facm",
-		.owner = THIS_MODULE,
-	},
-};
-
-static int __init facm_probe(struct platform_device *pdev)
-{
-	struct usb_gadget_facm_pdata *pdata = pdev->dev.platform_data;
-	int i;
-
-	dev_dbg(&pdev->dev, "%s: probe\n", __func__);
-
-	if (!pdata)
-		goto probe_android_register;
-
-	for (i = 0; i < GSERIAL_NO_PORTS; i++) {
-		gacm_ports[i].transport = pdata->transport[i];
-		gacm_ports[i].port_num = i;
-
-		switch (gacm_ports[i].transport) {
-		case USB_GADGET_FSERIAL_TRANSPORT_TTY:
-			gacm_ports[i].client_port_num = no_tty_ports;
-			no_tty_ports++;
-			break;
-		case USB_GADGET_FSERIAL_TRANSPORT_SDIO:
-			gacm_ports[i].client_port_num = no_sdio_ports;
-			no_sdio_ports++;
-			break;
-		case USB_GADGET_FSERIAL_TRANSPORT_SMD:
-			gacm_ports[i].client_port_num = no_smd_ports;
-			no_smd_ports++;
-			break;
-		default:
-			pr_err("%s: Un-supported transport transport: %u\n",
-					__func__, gacm_ports[i].transport);
-			return -ENODEV;
-		}
-
-		nr_ports++;
+	switch (transport) {
+	case USB_GADGET_XPORT_TTY:
+		gacm_ports[port_num].client_port_num = no_acm_tty_ports;
+		no_acm_tty_ports++;
+		break;
+	case USB_GADGET_XPORT_SDIO:
+		gacm_ports[port_num].client_port_num = no_acm_sdio_ports;
+		no_acm_sdio_ports++;
+		break;
+	case USB_GADGET_XPORT_SMD:
+		gacm_ports[port_num].client_port_num = no_acm_smd_ports;
+		no_acm_smd_ports++;
+		break;
+	default:
+		pr_err("%s: Un-supported transport transport: %u\n",
+				__func__, gacm_ports[port_num].transport);
+		return -ENODEV;
 	}
 
-	pr_info("%s:gport:tty_ports:%u sdio_ports:%u "
-			"smd_ports:%u nr_ports:%u\n",
-			__func__, no_tty_ports, no_sdio_ports,
-			no_smd_ports, nr_ports);
-
-probe_android_register:
-	android_register_function(&acm1_function);
-	android_register_function(&acm2_function);
+	nr_acm_ports++;
 
 	return 0;
 }
-
-static int __init init(void)
-{
-	printk(KERN_INFO "f_acm init\n");
-
-	return platform_driver_probe(&usb_facm, facm_probe);
-}
-module_init(init);
-
-#endif /* CONFIG_USB_ANDROID_ACM */
diff --git a/drivers/usb/gadget/f_rmnet_smd_sdio.c b/drivers/usb/gadget/f_rmnet_smd_sdio.c
index f974b8a..e39125d 100644
--- a/drivers/usb/gadget/f_rmnet_smd_sdio.c
+++ b/drivers/usb/gadget/f_rmnet_smd_sdio.c
@@ -1395,9 +1395,7 @@
 		struct device *device, struct device_attribute *attr,
 		const char *buf, size_t size)
 {
-	struct usb_function *f = dev_get_drvdata(device);
-	struct rmnet_mux_dev *dev = container_of(f, struct rmnet_mux_dev,
-								function);
+	struct rmnet_mux_dev *dev =  rmux_dev;
 	int value;
 	enum transport_type given_xport;
 	enum transport_type t;
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index ec303b9..eb0b203 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -35,6 +35,7 @@
 #include <mach/clk.h>
 #include <mach/msm_iomap.h>
 #include <mach/msm_xo.h>
+#include <linux/spinlock.h>
 
 #define MSM_USB_BASE (hcd->regs)
 
@@ -51,6 +52,7 @@
 	atomic_t                in_lpm;
 	struct msm_xo_voter	*xo_handle;
 	struct wake_lock	wlock;
+	int			peripheral_status_irq;
 };
 
 static inline struct msm_hsic_hcd *hcd_to_hsic(struct usb_hcd *hcd)
@@ -227,15 +229,18 @@
 {
 	int rc = 0;
 	struct msm_hsic_host_platform_data *pdata;
+	static int gpio_status;
 
 	pdata = mehci->dev->platform_data;
-	/*
-	 * In future versions, dedicated lines might be used for HSIC
-	 * strobe and data instead of gpios. Hence returning zero value.
-	 */
+
 	if (!pdata->strobe || !pdata->data)
 		return rc;
 
+	if (gpio_status == gpio_en)
+		return 0;
+
+	gpio_status = gpio_en;
+
 	if (!gpio_en)
 		goto free_gpio;
 
@@ -697,6 +702,18 @@
 
 	return ret;
 }
+static irqreturn_t hsic_peripheral_status_change(int irq, void *dev_id)
+{
+	struct msm_hsic_hcd *mehci = dev_id;
+
+	pr_debug("%s: mechi:%p dev_id:%p\n", __func__, mehci, dev_id);
+
+	if (mehci)
+		msm_hsic_config_gpios(mehci, 0);
+
+	return IRQ_HANDLED;
+}
+
 static int __devinit ehci_hsic_msm_probe(struct platform_device *pdev)
 {
 	struct usb_hcd *hcd;
@@ -740,6 +757,12 @@
 	mehci = hcd_to_hsic(hcd);
 	mehci->dev = &pdev->dev;
 
+	res = platform_get_resource_byname(pdev,
+			IORESOURCE_IRQ,
+			"peripheral_status_irq");
+	if (res)
+		mehci->peripheral_status_irq = res->start;
+
 	ret = msm_hsic_init_clocks(mehci, 1);
 	if (ret) {
 		dev_err(&pdev->dev, "unable to initialize clocks\n");
@@ -793,6 +816,18 @@
 	device_init_wakeup(&pdev->dev, 1);
 	wake_lock_init(&mehci->wlock, WAKE_LOCK_SUSPEND, dev_name(&pdev->dev));
 	wake_lock(&mehci->wlock);
+
+	if (mehci->peripheral_status_irq) {
+		ret = request_threaded_irq(mehci->peripheral_status_irq,
+			NULL, hsic_peripheral_status_change,
+			IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+						| IRQF_SHARED,
+			"hsic_peripheral_status", mehci);
+		if (ret)
+			dev_err(&pdev->dev, "%s:request_irq:%d failed:%d",
+				__func__, mehci->peripheral_status_irq, ret);
+	}
+
 	/*
 	 * This pdev->dev is assigned parent of root-hub by USB core,
 	 * hence, runtime framework automatically calls this driver's
@@ -828,6 +863,9 @@
 	struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
 	struct msm_hsic_host_platform_data *pdata;
 
+	if (mehci->peripheral_status_irq)
+		free_irq(mehci->peripheral_status_irq, mehci);
+
 	device_init_wakeup(&pdev->dev, 0);
 	pm_runtime_disable(&pdev->dev);
 	pm_runtime_set_suspended(&pdev->dev);
diff --git a/drivers/usb/misc/diag_bridge.c b/drivers/usb/misc/diag_bridge.c
index 00b2ec1..88a5993 100644
--- a/drivers/usb/misc/diag_bridge.c
+++ b/drivers/usb/misc/diag_bridge.c
@@ -31,6 +31,7 @@
 	struct usb_anchor	submitted;
 	__u8			in_epAddr;
 	__u8			out_epAddr;
+	int			err;
 	struct kref		kref;
 	struct diag_bridge_ops	*ops;
 	struct platform_device	*pdev;
@@ -47,6 +48,7 @@
 	}
 
 	dev->ops = ops;
+	dev->err = 0;
 
 	return 0;
 }
@@ -72,13 +74,19 @@
 	dev_dbg(&dev->udev->dev, "%s: status:%d actual:%d\n", __func__,
 			urb->status, urb->actual_length);
 
+	if (urb->status == -EPROTO) {
+		/* save error so that subsequent read/write returns ESHUTDOWN */
+		dev->err = urb->status;
+		return;
+	}
+
 	cbs->read_complete_cb(cbs->ctxt,
 			urb->transfer_buffer,
 			urb->transfer_buffer_length,
 			urb->status < 0 ? urb->status : urb->actual_length);
 }
 
-int diag_bridge_read(char *data, size_t size)
+int diag_bridge_read(char *data, int size)
 {
 	struct urb		*urb = NULL;
 	unsigned int		pipe;
@@ -97,6 +105,10 @@
 		return -ENODEV;
 	}
 
+	/* if there was a previous unrecoverable error, just quit */
+	if (dev->err)
+		return -ESHUTDOWN;
+
 	urb = usb_alloc_urb(0, GFP_ATOMIC);
 	if (!urb) {
 		dev_err(&dev->udev->dev, "unable to allocate urb\n");
@@ -129,13 +141,19 @@
 
 	dev_dbg(&dev->udev->dev, "%s:\n", __func__);
 
+	if (urb->status == -EPROTO) {
+		/* save error so that subsequent read/write returns ESHUTDOWN */
+		dev->err = urb->status;
+		return;
+	}
+
 	cbs->write_complete_cb(cbs->ctxt,
 			urb->transfer_buffer,
 			urb->transfer_buffer_length,
 			urb->status < 0 ? urb->status : urb->actual_length);
 }
 
-int diag_bridge_write(char *data, size_t size)
+int diag_bridge_write(char *data, int size)
 {
 	struct urb		*urb = NULL;
 	unsigned int		pipe;
@@ -154,6 +172,10 @@
 		return -ENODEV;
 	}
 
+	/* if there was a previous unrecoverable error, just quit */
+	if (dev->err)
+		return -ESHUTDOWN;
+
 	urb = usb_alloc_urb(0, GFP_ATOMIC);
 	if (!urb) {
 		err("unable to allocate urb");
@@ -271,7 +293,7 @@
 
 #define VALID_INTERFACE_NUM	0
 static const struct usb_device_id diag_bridge_ids[] = {
-	{ USB_DEVICE(0x5c6, 0x9001),
+	{ USB_DEVICE(0x5c6, 0x9048),
 	.driver_info = VALID_INTERFACE_NUM, },
 
 	{} /* terminating entry */
diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c
index 6fe5b1d..89b8e5a 100644
--- a/drivers/usb/misc/mdm_data_bridge.c
+++ b/drivers/usb/misc/mdm_data_bridge.c
@@ -24,7 +24,7 @@
 #define MAX_RX_URBS			50
 #define RMNET_RX_BUFSIZE		2048
 
-#define STOP_SUBMIT_URB_LIMIT		400
+#define STOP_SUBMIT_URB_LIMIT		500
 #define FLOW_CTRL_EN_THRESHOLD		500
 #define FLOW_CTRL_DISABLE		300
 #define FLOW_CTRL_SUPPORT		1
@@ -157,12 +157,9 @@
 	}
 
 	spin_lock_irqsave(&dev->rx_done.lock, flags);
-	if (dev->rx_done.qlen > stop_submit_urb_limit && rx_throttled(brdg)) {
-		spin_unlock_irqrestore(&dev->rx_done.lock, flags);
-		return;
-	}
-
 	while (!list_empty(&dev->rx_idle)) {
+		if (dev->rx_done.qlen > stop_submit_urb_limit)
+			break;
 
 		rx_idle = list_first_entry(&dev->rx_idle, struct urb, urb_list);
 		list_del(&rx_idle->urb_list);
@@ -448,6 +445,8 @@
 		return -ENODEV;
 
 	brdg = dev->brdg;
+	if (!brdg)
+		return -ENODEV;
 
 	dev_dbg(&dev->udev->dev, "%s: write (%d bytes)\n", __func__, skb->len);
 
@@ -754,6 +753,9 @@
 static void data_bridge_debugfs_exit(void) { }
 #endif
 
+#define DUN_IFACE_NUM			3
+#define TETHERED_RMNET_IFACE_NUM	4
+
 static int __devinit
 bridge_probe(struct usb_interface *iface, const struct usb_device_id *id)
 {
@@ -872,7 +874,7 @@
 }
 
 static const struct usb_device_id bridge_ids[] = {
-	{ USB_DEVICE(0x5c6, 0x9001) },
+	{ USB_DEVICE(0x5c6, 0x9048) },
 
 	{ } /* Terminating entry */
 };
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index dc3ff26..d756dd8 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -61,6 +61,7 @@
 #define USB_PHY_VDD_DIG_VOL_MIN	1045000 /* uV */
 #define USB_PHY_VDD_DIG_VOL_MAX	1320000 /* uV */
 
+static DECLARE_COMPLETION(pmic_vbus_init);
 static struct msm_otg *the_msm_otg;
 static bool debug_aca_enabled;
 
@@ -86,7 +87,9 @@
 static struct regulator *hsusb_3p3;
 static struct regulator *hsusb_1p8;
 static struct regulator *hsusb_vddcx;
+static struct regulator *vbus_otg;
 
+static bool aca_id_turned_on;
 static inline bool aca_enabled(void)
 {
 #ifdef CONFIG_USB_MSM_ACA
@@ -527,6 +530,7 @@
 		return ret;
 	}
 
+	aca_id_turned_on = false;
 	ret = msm_otg_link_reset(motg);
 	if (ret) {
 		dev_err(otg->dev, "link reset failed\n");
@@ -541,17 +545,19 @@
 
 	clk_disable(motg->clk);
 
-	val = readl_relaxed(USB_OTGSC);
-	if (pdata->mode == USB_OTG) {
-		ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID;
-		val |= OTGSC_IDIE | OTGSC_BSVIE;
-	} else if (pdata->mode == USB_PERIPHERAL) {
-		ulpi_val = ULPI_INT_SESS_VALID;
-		val |= OTGSC_BSVIE;
+	if (pdata->otg_control == OTG_PHY_CONTROL) {
+		val = readl_relaxed(USB_OTGSC);
+		if (pdata->mode == USB_OTG) {
+			ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID;
+			val |= OTGSC_IDIE | OTGSC_BSVIE;
+		} else if (pdata->mode == USB_PERIPHERAL) {
+			ulpi_val = ULPI_INT_SESS_VALID;
+			val |= OTGSC_BSVIE;
+		}
+		writel_relaxed(val, USB_OTGSC);
+		ulpi_write(otg, ulpi_val, ULPI_USB_INT_EN_RISE);
+		ulpi_write(otg, ulpi_val, ULPI_USB_INT_EN_FALL);
 	}
-	writel_relaxed(val, USB_OTGSC);
-	ulpi_write(otg, ulpi_val, ULPI_USB_INT_EN_RISE);
-	ulpi_write(otg, ulpi_val, ULPI_USB_INT_EN_FALL);
 
 	return 0;
 }
@@ -588,16 +594,16 @@
 	struct usb_bus *bus = otg->host;
 	struct msm_otg_platform_data *pdata = motg->pdata;
 	int cnt = 0;
-	bool session_active;
-	u32 phy_ctrl_val = 0;
+	bool host_bus_suspend;
+	u32 phy_ctrl_val = 0, cmd_val;
 	unsigned ret;
+	u32 portsc;
 
 	if (atomic_read(&motg->in_lpm))
 		return 0;
 
 	disable_irq(motg->irq);
-	session_active = (otg->host && !test_bit(ID, &motg->inputs)) ||
-				test_bit(B_SESS_VLD, &motg->inputs);
+	host_bus_suspend = otg->host && !test_bit(ID, &motg->inputs);
 	/*
 	 * Chipidea 45-nm PHY suspend sequence:
 	 *
@@ -626,23 +632,27 @@
 	 * Turn off the OTG comparators, if depends on PMIC for
 	 * VBUS and ID notifications.
 	 */
-	if ((motg->caps & ALLOW_PHY_COMP_DISABLE) && !session_active) {
+	if ((motg->caps & ALLOW_PHY_COMP_DISABLE) && !host_bus_suspend) {
 		ulpi_write(otg, OTG_COMP_DISABLE,
 			ULPI_SET(ULPI_PWR_CLK_MNG_REG));
 		motg->lpm_flags |= PHY_OTG_COMP_DISABLED;
 	}
 
-	/*
+	/* Set the PHCD bit, only if it is not set by the controller.
 	 * PHY may take some time or even fail to enter into low power
 	 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
 	 * in failure case.
 	 */
-	writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
-	while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
-		if (readl(USB_PORTSC) & PORTSC_PHCD)
-			break;
-		udelay(1);
-		cnt++;
+	portsc = readl_relaxed(USB_PORTSC);
+	if (!(portsc & PORTSC_PHCD)) {
+		writel_relaxed(portsc | PORTSC_PHCD,
+				USB_PORTSC);
+		while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
+			if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
+				break;
+			udelay(1);
+			cnt++;
+		}
 	}
 
 	if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
@@ -659,9 +669,14 @@
 	 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
 	 * block data communication from PHY.
 	 */
-	writel(readl(USB_USBCMD) | ASYNC_INTR_CTRL | ULPI_STP_CTRL, USB_USBCMD);
+	cmd_val = readl_relaxed(USB_USBCMD);
+	if (host_bus_suspend)
+		cmd_val |= ASYNC_INTR_CTRL | ULPI_STP_CTRL;
+	else
+		cmd_val |= ULPI_STP_CTRL;
+	writel_relaxed(cmd_val, USB_USBCMD);
 
-	if (motg->caps & ALLOW_PHY_RETENTION && !session_active) {
+	if (motg->caps & ALLOW_PHY_RETENTION && !host_bus_suspend) {
 		phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
 		if (motg->pdata->otg_control == OTG_PHY_CONTROL)
 			/* Enable PHY HV interrupts to wake MPM/Link */
@@ -690,7 +705,7 @@
 		dev_err(otg->dev, "%s failed to devote for "
 			"TCXO D0 buffer%d\n", __func__, ret);
 
-	if (motg->caps & ALLOW_PHY_POWER_COLLAPSE && !session_active) {
+	if (motg->caps & ALLOW_PHY_POWER_COLLAPSE && !host_bus_suspend) {
 		msm_hsusb_ldo_enable(motg, 0);
 		motg->lpm_flags |= PHY_PWR_COLLAPSED;
 	}
@@ -813,11 +828,6 @@
 
 	atomic_set(&motg->in_lpm, 0);
 
-	if (aca_enabled() && !irq_read_line(motg->pdata->pmic_id_irq)) {
-		clear_bit(ID, &motg->inputs);
-		schedule_work(&motg->sm_work);
-	}
-
 	if (motg->async_int) {
 		motg->async_int = 0;
 		enable_irq(motg->irq);
@@ -943,6 +953,41 @@
 	return NOTIFY_OK;
 }
 
+static void msm_hsusb_vbus_power(struct msm_otg *motg, bool on)
+{
+	int ret;
+	static bool vbus_is_on;
+
+	if (vbus_is_on == on)
+		return;
+
+	if (motg->pdata->vbus_power) {
+		motg->pdata->vbus_power(on);
+		return;
+	}
+
+	if (!vbus_otg) {
+		pr_err("vbus_otg is NULL.");
+		return;
+	}
+
+	if (on) {
+		ret = regulator_enable(vbus_otg);
+		if (ret) {
+			pr_err("unable to enable vbus_otg\n");
+			return;
+		}
+		vbus_is_on = true;
+	} else {
+		ret = regulator_disable(vbus_otg);
+		if (ret) {
+			pr_err("unable to disable vbus_otg\n");
+			return;
+		}
+		vbus_is_on = false;
+	}
+}
+
 static int msm_otg_set_host(struct otg_transceiver *otg, struct usb_bus *host)
 {
 	struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
@@ -957,13 +1002,20 @@
 		return -ENODEV;
 	}
 
+	if (!motg->pdata->vbus_power && host) {
+		vbus_otg = regulator_get(motg->otg.dev, "vbus_otg");
+		if (IS_ERR(vbus_otg)) {
+			pr_err("Unable to get vbus_otg\n");
+			return -ENODEV;
+		}
+	}
+
 	if (!host) {
 		if (otg->state == OTG_STATE_A_HOST) {
 			pm_runtime_get_sync(otg->dev);
 			usb_unregister_notify(&motg->usbdev_nb);
 			msm_otg_start_host(otg, 0);
-			if (motg->pdata->vbus_power)
-				motg->pdata->vbus_power(0);
+			msm_hsusb_vbus_power(motg, 0);
 			otg->host = NULL;
 			otg->state = OTG_STATE_UNDEFINED;
 			schedule_work(&motg->sm_work);
@@ -971,6 +1023,9 @@
 			otg->host = NULL;
 		}
 
+		if (vbus_otg)
+			regulator_put(vbus_otg);
+
 		return 0;
 	}
 
@@ -1159,6 +1214,7 @@
 		ulpi_write(otg, 0x10, 0x12);
 		/* Enable ACA ID detection */
 		ulpi_write(otg, 0x20, 0x85);
+		aca_id_turned_on = true;
 		break;
 	default:
 		break;
@@ -1606,24 +1662,26 @@
 				set_bit(ID, &motg->inputs);
 				clear_bit(B_SESS_VLD, &motg->inputs);
 			}
-		} else {
-			if (aca_enabled()) {
-				if (irq_read_line(motg->pdata->pmic_id_irq))
-					set_bit(ID, &motg->inputs);
-				else
-					clear_bit(ID, &motg->inputs);
-
-			} else {
-				if (otgsc & OTGSC_ID)
-					set_bit(ID, &motg->inputs);
-				else
-					clear_bit(ID, &motg->inputs);
-			}
-
+		} else if (pdata->otg_control == OTG_PHY_CONTROL) {
+			if (otgsc & OTGSC_ID)
+				set_bit(ID, &motg->inputs);
+			else
+				clear_bit(ID, &motg->inputs);
 			if (otgsc & OTGSC_BSV)
 				set_bit(B_SESS_VLD, &motg->inputs);
 			else
 				clear_bit(B_SESS_VLD, &motg->inputs);
+		} else if (pdata->otg_control == OTG_PMIC_CONTROL) {
+			if (irq_read_line(motg->pdata->pmic_id_irq))
+				set_bit(ID, &motg->inputs);
+			else
+				clear_bit(ID, &motg->inputs);
+
+			/*
+			 * VBUS initial state is reported after PMIC
+			 * driver initialization. Wait for it.
+			 */
+			wait_for_completion(&pmic_vbus_init);
 		}
 		break;
 	case USB_HOST:
@@ -1670,8 +1728,8 @@
 			else if (test_bit(ID_A, &motg->inputs))
 				msm_otg_notify_charger(motg,
 						IDEV_ACA_CHG_MAX - IUNIT);
-			else if (motg->pdata->vbus_power)
-				motg->pdata->vbus_power(1);
+			else
+				msm_hsusb_vbus_power(motg, 1);
 			msm_otg_start_host(otg, 1);
 			/*
 			 * Link can not generate PHY_ALT interrupt
@@ -1757,10 +1815,8 @@
 		if (test_bit(ID, &motg->inputs) &&
 				!test_bit(ID_A, &motg->inputs)) {
 			msm_otg_start_host(otg, 0);
-			if (motg->pdata->vbus_power) {
-				motg->pdata->vbus_power(0);
-				msleep(100); /* TA_WAIT_VFALL */
-			}
+			msm_hsusb_vbus_power(motg, 0);
+			msleep(100); /* TA_WAIT_VFALL */
 			/*
 			 * Exit point of host mode.
 			 *
@@ -1782,14 +1838,12 @@
 			otg->state = OTG_STATE_B_IDLE;
 			schedule_work(w);
 		} else if (test_bit(ID_A, &motg->inputs)) {
-			if (motg->pdata->vbus_power)
-				motg->pdata->vbus_power(0);
+			msm_hsusb_vbus_power(motg, 0);
 			msm_otg_notify_charger(motg,
 					IDEV_ACA_CHG_MAX - motg->mA_port);
 		} else if (!test_bit(ID, &motg->inputs)) {
 			msm_otg_notify_charger(motg, 0);
-			if (motg->pdata->vbus_power)
-				motg->pdata->vbus_power(1);
+			msm_hsusb_vbus_power(motg, 1);
 		}
 		break;
 	default:
@@ -1804,6 +1858,7 @@
 	u32 otgsc = 0, usbsts;
 
 	if (atomic_read(&motg->in_lpm)) {
+		pr_debug("OTG IRQ: in LPM\n");
 		disable_irq_nosync(irq);
 		motg->async_int = 1;
 		pm_request_resume(otg->dev);
@@ -1853,25 +1908,44 @@
 
 static void msm_otg_set_vbus_state(int online)
 {
+	static bool init;
 	struct msm_otg *motg = the_msm_otg;
 
-	/* We depend on PMIC for only VBUS ON interrupt */
-	if (!atomic_read(&motg->in_lpm) || !online || motg->async_int)
-		return;
+	if (online) {
+		pr_debug("PMIC: BSV set\n");
+		set_bit(B_SESS_VLD, &motg->inputs);
+	} else {
+		pr_debug("PMIC: BSV clear\n");
+		clear_bit(B_SESS_VLD, &motg->inputs);
+	}
 
-	/*
-	 * Let interrupt handler take care of resuming
-	 * the hardware.
-	 */
-	msm_otg_irq(motg->irq, (void *) motg);
+	if (!init) {
+		init = true;
+		complete(&pmic_vbus_init);
+		pr_debug("PMIC: BSV init complete\n");
+		return;
+	}
+
+	schedule_work(&motg->sm_work);
 }
 
 static irqreturn_t msm_pmic_id_irq(int irq, void *data)
 {
 	struct msm_otg *motg = data;
 
-	if (atomic_read(&motg->in_lpm) && !motg->async_int)
-		msm_otg_irq(motg->irq, motg);
+	if (aca_id_turned_on)
+		return IRQ_HANDLED;
+
+	if (irq_read_line(motg->pdata->pmic_id_irq)) {
+		pr_debug("PMIC: ID set\n");
+		set_bit(ID, &motg->inputs);
+	} else {
+		pr_debug("PMIC: ID clear\n");
+		clear_bit(ID, &motg->inputs);
+	}
+
+	if (motg->otg.state != OTG_STATE_UNDEFINED)
+		schedule_work(&motg->sm_work);
 
 	return IRQ_HANDLED;
 }
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index 6bc70ba..b29a974 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -82,10 +82,13 @@
 	{USB_DEVICE(0x16d8, 0x8002)},	/* CMDTech Gobi 2000 Modem device (VU922) */
 	{USB_DEVICE(0x05c6, 0x9204)},	/* Gobi 2000 QDL device */
 	{USB_DEVICE(0x05c6, 0x9205)},	/* Gobi 2000 Modem device */
+	{USB_DEVICE(0x05c6, 0x9048)},
 	{ }				/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
+#define EFS_SYNC_IFC_NUM	2
+
 static struct usb_driver qcdriver = {
 	.name			= "qcserial",
 	.probe			= usb_serial_probe,
@@ -197,6 +200,14 @@
 		}
 		break;
 
+	case 9:
+		if (ifnum != EFS_SYNC_IFC_NUM) {
+			kfree(data);
+			break;
+		}
+
+		retval = 0;
+		break;
 	default:
 		dev_err(&serial->dev->dev,
 			"unknown number of interfaces: %d\n", nintf);
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 64fc6ea..fcf4b08 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -407,8 +407,8 @@
 	intfdata = serial->private;
 
 	/* explicitly set the driver mode to raw */
-	tty->raw = 0;
-	tty->real_raw = 0;
+	tty->raw = 1;
+	tty->real_raw = 1;
 
 	dbg("%s", __func__);
 
diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig
index 35d1714..de6bf1a 100644
--- a/drivers/video/msm/Kconfig
+++ b/drivers/video/msm/Kconfig
@@ -628,6 +628,15 @@
 	  Support for HDMI CEC Feature
 	  Choose to enable CEC
 
+config FB_MSM_HDMI_MHL
+	depends on FB_MSM_HDMI_MSM_PANEL
+	bool 'HDMI to MHL support'
+	default n
+	---help---
+	  Support the HDMI to MHL conversion.
+	  MHL (Mobile High-Definition Link) technology
+	  uses USB connector to output HDMI content
+
 choice
 	depends on  (FB_MSM_MDP22 || FB_MSM_MDP31 || FB_MSM_MDP40)
 	prompt "TVOut Region"
diff --git a/drivers/video/msm/external_common.c b/drivers/video/msm/external_common.c
index 5d9795a..7fd4c56 100644
--- a/drivers/video/msm/external_common.c
+++ b/drivers/video/msm/external_common.c
@@ -21,6 +21,7 @@
 #include "msm_fb.h"
 #include "hdmi_msm.h"
 #include "external_common.h"
+#include "mhl_api.h"
 
 struct external_common_state_type *external_common_state;
 EXPORT_SYMBOL(external_common_state);
@@ -224,6 +225,70 @@
 };
 EXPORT_SYMBOL(hdmi_common_supported_video_mode_lut);
 
+struct hdmi_disp_mode_timing_type
+	hdmi_mhl_supported_video_mode_lut[HDMI_VFRMT_MAX] = {
+	HDMI_SETTINGS_640x480p60_4_3,
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p60_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p60_16_9),
+	HDMI_SETTINGS_1280x720p60_16_9,
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i60_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i60_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i60_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x240p60_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x240p60_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480i60_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480i60_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x240p60_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x240p60_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480p60_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480p60_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p60_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p50_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p50_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p50_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i50_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i50_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i50_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x288p50_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x288p50_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576i50_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576i50_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x288p50_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x288p50_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576p50_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576p50_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080p50_16_9),
+	HDMI_SETTINGS_1920x1080p24_16_9,
+	HDMI_SETTINGS_1920x1080p25_16_9,
+	HDMI_SETTINGS_1920x1080p30_16_9,
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480p60_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x480p60_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576p50_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_2880x576p50_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1250i50_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i100_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p100_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p100_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p100_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i100_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i100_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1920x1080i120_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1280x720p120_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p120_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p120_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i120_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i120_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p200_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x576p200_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i200_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x576i200_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p240_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_720x480p240_16_9),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i240_4_3),
+	VFRMT_NOT_SUPPORTED(HDMI_VFRMT_1440x480i240_16_9),
+};
+EXPORT_SYMBOL(hdmi_mhl_supported_video_mode_lut);
+
 static ssize_t hdmi_common_rda_edid_modes(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
@@ -537,6 +602,7 @@
 	mutex_unlock(&external_common_state_hpd_mutex);
 
 	video_mode = atoi(buf)-1;
+	DEV_INFO("%s: video_mode is %d\n", __func__, video_mode);
 	kobject_uevent(external_common_state->uevent_kobj, KOBJ_OFFLINE);
 #ifdef CONFIG_FB_MSM_HDMI_COMMON
 	disp_mode = hdmi_common_get_supported_mode(video_mode);
@@ -569,11 +635,27 @@
 	return ret;
 }
 
+static ssize_t external_common_rda_hdmi_mode(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	ssize_t ret;
+
+	ret = snprintf(buf, PAGE_SIZE, "%d\n",
+		external_common_state->hdmi_sink);
+
+	DEV_DBG("%s: '%d'\n", __func__,
+		external_common_state->hdmi_sink);
+
+	return ret;
+}
+
+
 static DEVICE_ATTR(video_mode, S_IRUGO | S_IWUGO,
 	external_common_rda_video_mode, external_common_wta_video_mode);
 static DEVICE_ATTR(video_mode_str, S_IRUGO, external_common_rda_video_mode_str,
 	NULL);
 static DEVICE_ATTR(connected, S_IRUGO, external_common_rda_connected, NULL);
+static DEVICE_ATTR(hdmi_mode, S_IRUGO, external_common_rda_hdmi_mode, NULL);
 #ifdef CONFIG_FB_MSM_HDMI_COMMON
 static DEVICE_ATTR(edid_modes, S_IRUGO, hdmi_common_rda_edid_modes, NULL);
 static DEVICE_ATTR(hpd, S_IRUGO | S_IWUGO, hdmi_common_rda_hpd,
@@ -591,6 +673,7 @@
 	&dev_attr_video_mode.attr,
 	&dev_attr_video_mode_str.attr,
 	&dev_attr_connected.attr,
+	&dev_attr_hdmi_mode.attr,
 #ifdef CONFIG_FB_MSM_HDMI_COMMON
 	&dev_attr_edid_modes.attr,
 	&dev_attr_hdcp.attr,
@@ -1002,7 +1085,11 @@
 	img_size_v = (((uint32)data_buf[0xE] & 0xF) << 8)
 		| data_buf[0xD];
 
-	aspect_ratio_4_3 = (img_size_h * 3 == img_size_v * 4);
+	/*
+	 * aspect ratio as 4:3 if within specificed range , rathaer than being
+	 * absolute value
+	 */
+	aspect_ratio_4_3 = (abs(img_size_h * 3 - img_size_v * 4) < 5) ? 1 : 0;
 
 	max_num_of_elements  = sizeof(hdmi_edid_disp_mode_lut)
 		/ sizeof(*hdmi_edid_disp_mode_lut);
@@ -1061,9 +1148,21 @@
 	DEV_DBG("EDID: format: %d [%s], %s\n",
 		video_format, video_format_2string(video_format),
 		supported ? "Supported" : "Not-Supported");
-	if (supported)
-		disp_mode_list->disp_mode_list[
+	if (supported) {
+		if (mhl_is_connected()) {
+			const struct hdmi_disp_mode_timing_type *mhl_timing =
+				hdmi_mhl_get_supported_mode(video_format);
+			boolean mhl_supported = mhl_timing != NULL;
+			DEV_DBG("EDID: format: %d [%s], %s by MHL\n",
+			video_format, video_format_2string(video_format),
+				mhl_supported ? "Supported" : "Not-Supported");
+			if (mhl_supported)
+				disp_mode_list->disp_mode_list[
 			disp_mode_list->num_of_elements++] = video_format;
+		} else
+			disp_mode_list->disp_mode_list[
+			disp_mode_list->num_of_elements++] = video_format;
+	}
 }
 
 static void hdmi_edid_get_display_mode(const uint8 *data_buf,
@@ -1352,6 +1451,7 @@
 
 	if (var->reserved[3]) {
 		format = var->reserved[3]-1;
+		DEV_DBG("reserved format is %d\n", format);
 	} else {
 		DEV_DBG("detecting resolution from %dx%d use var->reserved[3]"
 			" to specify mode", mfd->var_xres, mfd->var_yres);
@@ -1413,6 +1513,27 @@
 }
 EXPORT_SYMBOL(hdmi_common_get_supported_mode);
 
+const struct hdmi_disp_mode_timing_type *hdmi_mhl_get_mode(uint32 mode)
+{
+	if (mode >= HDMI_VFRMT_MAX)
+		return NULL;
+
+	return &hdmi_mhl_supported_video_mode_lut[mode];
+}
+EXPORT_SYMBOL(hdmi_mhl_get_mode);
+
+const struct hdmi_disp_mode_timing_type *hdmi_mhl_get_supported_mode(
+	uint32 mode)
+{
+	const struct hdmi_disp_mode_timing_type *ret
+		= hdmi_mhl_get_mode(mode);
+
+	if (ret == NULL || !ret->supported)
+		return NULL;
+	return ret;
+}
+EXPORT_SYMBOL(hdmi_mhl_get_supported_mode);
+
 void hdmi_common_init_panel_info(struct msm_panel_info *pinfo)
 {
 	const struct hdmi_disp_mode_timing_type *timing =
diff --git a/drivers/video/msm/external_common.h b/drivers/video/msm/external_common.h
index f629d0f..3d23522 100644
--- a/drivers/video/msm/external_common.h
+++ b/drivers/video/msm/external_common.h
@@ -243,6 +243,9 @@
 const struct hdmi_disp_mode_timing_type *hdmi_common_get_mode(uint32 mode);
 const struct hdmi_disp_mode_timing_type *hdmi_common_get_supported_mode(
 	uint32 mode);
+const struct hdmi_disp_mode_timing_type *hdmi_mhl_get_mode(uint32 mode);
+const struct hdmi_disp_mode_timing_type *hdmi_mhl_get_supported_mode(
+	uint32 mode);
 void hdmi_common_init_panel_info(struct msm_panel_info *pinfo);
 #endif
 
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index c87119f..a449fc7 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -2301,8 +2301,8 @@
 		aksv[4] =  qfprom_aksv_1        & 0xFF;
 		/* check there are 20 ones in AKSV */
 		if (hdmi_msm_count_one(aksv, 5) != 20) {
-			DEV_ERR("HDCP: AKSV read from QFPROM doesn't have\
-				20 1's and 20 0's, FAIL (AKSV=%02x%08x)\n",
+			DEV_ERR("HDCP: AKSV read from QFPROM doesn't have "
+				"20 1's and 20 0's, FAIL (AKSV=%02x%08x)\n",
 			qfprom_aksv_1, qfprom_aksv_0);
 			ret = -EINVAL;
 			goto error;
@@ -2332,9 +2332,9 @@
 		}
 		/* check there are 20 ones in BKSV */
 		if (hdmi_msm_count_one(bksv, 5) != 20) {
-			DEV_ERR("HDCP: BKSV read from Sink doesn't have\
-				20 1's and 20 0's, FAIL (BKSV=\
-				%02x%02x%02x%02x%02x)\n",
+			DEV_ERR("HDCP: BKSV read from Sink doesn't have "
+				"20 1's and 20 0's, FAIL (BKSV="
+				"%02x%02x%02x%02x%02x)\n",
 				bksv[4], bksv[3], bksv[2], bksv[1], bksv[0]);
 			ret = -EINVAL;
 			goto error;
@@ -2507,8 +2507,8 @@
 		hpd_int_status = HDMI_INP_ND(0x0250);
 		/* HDMI_HPD_INT_CTRL[0x0254] */
 		hpd_int_ctrl = HDMI_INP_ND(0x0254);
-		DEV_DBG("[SR-DEUG]: HPD_INTR_CTRL=[%u] HPD_INTR_STATUS=[%u]\
-		    before reading R0'\n", hpd_int_ctrl, hpd_int_status);
+		DEV_DBG("[SR-DEUG]: HPD_INTR_CTRL=[%u] HPD_INTR_STATUS=[%u] "
+			"before reading R0'\n", hpd_int_ctrl, hpd_int_status);
 
 		/*
 		* HDCP Compliace Test case 1B-01:
@@ -2525,12 +2525,12 @@
 			goto error;
 		}
 
+		DEV_DBG("HDCP: R0'=%02x%02x\n", buf[1], buf[0]);
+		INIT_COMPLETION(hdmi_msm_state->hdcp_success_done);
 		/* 0x013C HDCP_RCVPORT_DATA2_0
 		[15:0] LINK0_RI */
 		HDMI_OUTP(0x013C, (((uint32)buf[1]) << 8) | buf[0]);
-		DEV_DBG("HDCP: R0'=%02x%02x\n", buf[1], buf[0]);
 
-		INIT_COMPLETION(hdmi_msm_state->hdcp_success_done);
 		timeout_count = wait_for_completion_interruptible_timeout(
 			&hdmi_msm_state->hdcp_success_done, HZ*2);
 
@@ -2968,8 +2968,8 @@
 	hdmi_msm_state->hdcp_activating = FALSE;
 	mutex_unlock(&hdmi_msm_state_mutex);
 	if (hdmi_msm_state->hpd_during_auth) {
-		DEV_WARN("Calling Deauthentication: HPD occured during\
-		    authentication  from [%s]\n", __func__);
+		DEV_WARN("Calling Deauthentication: HPD occured during "
+			 "authentication  from [%s]\n", __func__);
 		hdcp_deauthenticate();
 		mutex_lock(&hdcp_auth_state_mutex);
 		hdmi_msm_state->hpd_during_auth = FALSE;
@@ -3479,9 +3479,11 @@
 {
 	msm_hdmi_sample_rate = rate;
 
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
 	if (hdmi_msm_has_hdcp())
 		hdcp_deauthenticate();
 	else
+#endif
 		hdmi_msm_turn_on();
 }
 EXPORT_SYMBOL(hdmi_msm_audio_sample_rate_reset);
@@ -3987,7 +3989,6 @@
 		phy_reset_done = 1;
 	}
 
-	hdmi_msm_init_phy(external_common_state->video_resolution);
 	/* HDMI_USEC_REFTIMER[0x0208] */
 	HDMI_OUTP(0x0208, 0x0001001B);
 
@@ -4275,9 +4276,13 @@
 	if (rc)
 		goto error;
 
-	if (hdmi_msm_has_hdcp())
+	if (hdmi_msm_has_hdcp()) {
+		/* Don't Set Encryption in case of non HDCP builds */
+		external_common_state->present_hdcp = FALSE;
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
 		external_common_state->present_hdcp = TRUE;
-	else {
+#endif
+	} else {
 		external_common_state->present_hdcp = FALSE;
 #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
 		/*
diff --git a/drivers/video/msm/mddi_toshiba_wvga_pt.c b/drivers/video/msm/mddi_toshiba_wvga_pt.c
index edf739d..7a9fb2d 100644
--- a/drivers/video/msm/mddi_toshiba_wvga_pt.c
+++ b/drivers/video/msm/mddi_toshiba_wvga_pt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2011, Code Aurora Forum. 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 version 2 and
@@ -44,10 +44,10 @@
 	pinfo.wait_cycle = 0;
 	pinfo.bpp = 18;
 	pinfo.lcd.vsync_enable = TRUE;
-	pinfo.lcd.refx100 = 6096; /* adjust refx100 to prevent tearing */
-	pinfo.lcd.v_back_porch = 2;     /* vsw=1 + vbp = 2 */
-	pinfo.lcd.v_front_porch = 3;
-	pinfo.lcd.v_pulse_width = 1;
+	pinfo.lcd.refx100 = 6102; /* adjust refx100 to prevent tearing */
+	pinfo.lcd.v_back_porch = 8;     /* vsw=10 + vbp = 8 */
+	pinfo.lcd.v_front_porch = 2;
+	pinfo.lcd.v_pulse_width = 10;
 	pinfo.lcd.hw_vsync_mode = FALSE;
 	pinfo.lcd.vsync_notifier_period = (1 * HZ);
 	pinfo.bl_max = 15;
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 462ede1..9380257 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -31,7 +31,7 @@
 #include <linux/mutex.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
-
+#include <linux/memory_alloc.h>
 #include <asm/system.h>
 #include <asm/mach-types.h>
 #include <linux/semaphore.h>
@@ -52,6 +52,7 @@
 int mdp_rev;
 
 static struct regulator *footswitch;
+static unsigned int mdp_footswitch_on;
 
 struct completion mdp_ppp_comp;
 struct semaphore mdp_ppp_mutex;
@@ -104,6 +105,11 @@
 static struct mdp_dma_data dma_e_data;
 #endif
 #endif
+
+#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
+struct mdp_dma_data dma_wb_data;
+#endif
+
 static struct mdp_dma_data dma3_data;
 
 extern ktime_t mdp_dma2_last_update_time;
@@ -600,6 +606,10 @@
 		mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 		mdp_lut_enable();
 		outpdw(MDP_BASE + 0x0008, 0);
+	} else if (term == MDP_OVERLAY2_TERM) {
+		mdp_pipe_ctrl(MDP_OVERLAY2_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+		mdp_lut_enable();
+		outpdw(MDP_BASE + 0x00D0, 0);
 	}
 #else
 	} else if (term == MDP_DMA_S_TERM) {
@@ -958,6 +968,14 @@
 	init_completion(&dma_e_data.comp);
 	mutex_init(&dma_e_data.ov_mutex);
 #endif
+#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
+	dma_wb_data.busy = FALSE;
+	dma_wb_data.waiting = FALSE;
+	init_completion(&dma_wb_data.comp);
+	mutex_init(&dma_wb_data.ov_mutex);
+#endif
+
+
 
 #ifndef CONFIG_FB_MSM_MDP22
 	init_completion(&mdp_hist_comp);
@@ -1122,18 +1140,6 @@
 				__func__, mdp_hw_revision);
 }
 
-int mdp4_writeback_offset(void)
-{
-	int off = 0;
-
-	if (mdp_pdata->writeback_offset)
-		off = mdp_pdata->writeback_offset();
-
-	pr_debug("%s: writeback_offset=%d %x\n", __func__, off, off);
-
-	return off;
-}
-
 #ifdef CONFIG_FB_MSM_MDP40
 static void configure_mdp_core_clk_table(uint32 min_clk_rate)
 {
@@ -1251,8 +1257,10 @@
 	footswitch = regulator_get(NULL, "fs_mdp");
 	if (IS_ERR(footswitch))
 		footswitch = NULL;
-	else
+	else {
 		regulator_enable(footswitch);
+		mdp_footswitch_on = 1;
+	}
 
 	mdp_clk = clk_get(NULL, "mdp_clk");
 	if (IS_ERR(mdp_clk)) {
@@ -1312,6 +1320,7 @@
 #endif
 
 	if ((pdev->id == 0) && (pdev->num_resources > 0)) {
+
 		mdp_pdata = pdev->dev.platform_data;
 
 		size =  resource_size(&pdev->resource[0]);
@@ -1349,6 +1358,28 @@
 #endif
 
 		mdp_resource_initialized = 1;
+
+		if (!mdp_pdata)
+			return 0;
+
+		size = mdp_pdata->mdp_writeback_size_ov0 +
+			mdp_pdata->mdp_writeback_size_ov1;
+		if (size) {
+			mdp_pdata->mdp_writeback_phys =
+				(void *)allocate_contiguous_memory_nomap
+				(size,
+				 mdp_pdata->mdp_writeback_memtype,
+				 4); /* align to word size */
+			if (mdp_pdata->mdp_writeback_phys) {
+				pr_info("allocating %d bytes at %p for mdp writeback\n",
+					size, mdp_pdata->mdp_writeback_phys);
+			} else {
+				pr_err("%s cannot allocate memory for mdp writeback!\n",
+				       __func__);
+			}
+		} else {
+			mdp_pdata->mdp_writeback_phys = 0;
+		}
 		return 0;
 	}
 
@@ -1588,11 +1619,25 @@
 
 #ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
 	case WRITEBACK_PANEL:
-		pdata->on = mdp4_overlay_writeback_on;
-		pdata->off = mdp4_overlay_writeback_off;
-		mfd->dma_fnc = mdp4_writeback_overlay;
-		mfd->dma = &dma_e_data;
-		mdp4_display_intf_sel(EXTERNAL_INTF_SEL, DTV_INTF);
+		{
+			unsigned int mdp_version;
+			mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON,
+						 FALSE);
+			mdp_version = inpdw(MDP_BASE + 0x0);
+			mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF,
+						FALSE);
+			if (mdp_version < 0x04030303) {
+				pr_err("%s: writeback panel not supprted\n",
+					 __func__);
+				rc = -ENODEV;
+				goto mdp_probe_err;
+			}
+			pdata->on = mdp4_overlay_writeback_on;
+			pdata->off = mdp4_overlay_writeback_off;
+			mfd->dma_fnc = mdp4_writeback_overlay;
+			mfd->dma = &dma_wb_data;
+			mdp4_display_intf_sel(EXTERNAL_INTF_SEL, DTV_INTF);
+		}
 		break;
 #endif
 	default:
@@ -1619,6 +1664,20 @@
 		}
 	}
 #endif
+
+	if (mdp_pdata && mdp_pdata->mdp_writeback_phys) {
+		mfd->writeback_overlay0_phys =
+			(mdp_pdata->mdp_writeback_size_ov0) ?
+			mdp_pdata->mdp_writeback_phys : 0;
+		mfd->writeback_overlay1_phys =
+			(mdp_pdata->mdp_writeback_size_ov1) ?
+			(mdp_pdata->mdp_writeback_phys +
+			 mdp_pdata->mdp_writeback_size_ov0) : 0;
+	} else {
+		mfd->writeback_overlay0_phys = 0;
+		mfd->writeback_overlay1_phys = 0;
+	}
+
 	/* set driver data */
 	platform_set_drvdata(msm_fb_dev, mfd);
 
@@ -1644,6 +1703,28 @@
 	return rc;
 }
 
+void mdp_footswitch_ctrl(boolean on)
+{
+	mutex_lock(&mdp_suspend_mutex);
+	if (!mdp_suspended || mdp4_extn_disp || !footswitch ||
+		mdp_rev <= MDP_REV_41) {
+		mutex_unlock(&mdp_suspend_mutex);
+		return;
+	}
+
+	if (on && !mdp_footswitch_on) {
+		pr_debug("Enable MDP FS\n");
+		regulator_enable(footswitch);
+		mdp_footswitch_on = 1;
+	} else if (!on && mdp_footswitch_on) {
+		pr_debug("Disable MDP FS\n");
+		regulator_disable(footswitch);
+		mdp_footswitch_on = 0;
+	}
+
+	mutex_unlock(&mdp_suspend_mutex);
+}
+
 #ifdef CONFIG_PM
 static void mdp_suspend_sub(void)
 {
@@ -1688,15 +1769,12 @@
 #ifdef CONFIG_FB_MSM_DTV
 	mdp4_dtv_set_black_screen();
 #endif
-	if (footswitch && mdp_rev > MDP_REV_42)
-		regulator_disable(footswitch);
+	mdp_footswitch_ctrl(FALSE);
 }
 
 static void mdp_early_resume(struct early_suspend *h)
 {
-	if (footswitch && mdp_rev > MDP_REV_42)
-		regulator_enable(footswitch);
-
+	mdp_footswitch_ctrl(TRUE);
 	mutex_lock(&mdp_suspend_mutex);
 	mdp_suspended = FALSE;
 	mutex_unlock(&mdp_suspend_mutex);
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index 8817213..ceb133b 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -123,6 +123,7 @@
 	MDP_DMA_S_BLOCK,
 	MDP_DMA_E_BLOCK,
 	MDP_OVERLAY1_BLOCK,
+	MDP_OVERLAY2_BLOCK,
 	MDP_MAX_BLOCK
 } MDP_BLOCK_TYPE;
 
@@ -223,6 +224,7 @@
 #define MDP_OVERLAY1_TERM 0x40
 #endif
 #define MDP_HISTOGRAM_TERM 0x80
+#define MDP_OVERLAY2_TERM 0x100
 
 #define ACTIVE_START_X_EN BIT(31)
 #define ACTIVE_START_Y_EN BIT(31)
@@ -722,6 +724,7 @@
 int mdp_start_histogram(struct fb_info *info);
 int mdp_stop_histogram(struct fb_info *info);
 int mdp_histogram_ctrl(boolean en);
+void mdp_footswitch_ctrl(boolean on);
 
 #ifdef CONFIG_FB_MSM_MDP303
 static inline void mdp4_dsi_cmd_dma_busy_wait(struct msm_fb_data_type *mfd)
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 2bcac9c..798cf47 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. 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 version 2 and
@@ -17,6 +17,7 @@
 extern struct mdp_dma_data dma2_data;
 extern struct mdp_dma_data dma_s_data;
 extern struct mdp_dma_data dma_e_data;
+extern struct mdp_dma_data dma_wb_data;
 extern unsigned int mdp_hist_frame_cnt;
 extern struct completion mdp_hist_comp;
 extern boolean mdp_is_hist_start;
@@ -28,6 +29,7 @@
 
 #define MDP4_OVERLAYPROC0_BASE	0x10000
 #define MDP4_OVERLAYPROC1_BASE	0x18000
+#define MDP4_OVERLAYPROC2_BASE	0x88000
 
 #define MDP4_VIDEO_BASE 0x20000
 #define MDP4_VIDEO_OFF 0x10000
@@ -125,6 +127,7 @@
 #define INTR_EXTERNAL_INTF_UDERRUN	BIT(10)
 #define INTR_PRIMARY_READ_PTR		BIT(11)
 #define INTR_DMA_P_HISTOGRAM		BIT(17)
+#define INTR_OVERLAY2_DONE		BIT(30)
 
 #ifdef CONFIG_FB_MSM_OVERLAY
 #define MDP4_ANY_INTR_MASK	(INTR_OVERLAY0_DONE|INTR_DMA_S_DONE | \
@@ -141,6 +144,7 @@
 	OVERLAY_PIPE_VG2,
 	OVERLAY_PIPE_RGB3,
 	OVERLAY_PIPE_VG3,
+	OVERLAY_PIPE_VG4,
 	OVERLAY_PIPE_MAX
 };
 
@@ -153,6 +157,7 @@
 enum {
 	MDP4_MIXER0,
 	MDP4_MIXER1,
+	MDP4_MIXER2,
 	MDP4_MIXER_MAX
 };
 
@@ -219,6 +224,7 @@
 #define MDP4_OP_SCALEX_FIR 		(0 << 2)
 #define MDP4_OP_SCALEX_MN_PHASE 	(1 << 2)
 #define MDP4_OP_SCALEX_PIXEL_RPT 	(2 << 2)
+#define MDP4_OP_SCALE_RGB_ENHANCED	(1 << 4)
 #define MDP4_OP_SCALE_RGB_PIXEL_RPT	(0 << 3)
 #define MDP4_OP_SCALE_RGB_BILINEAR	(1 << 3)
 #define MDP4_OP_SCALE_ALPHA_PIXEL_RPT	(0 << 2)
@@ -327,6 +333,7 @@
 	ulong intr_dma_e;
 	ulong intr_overlay0;
 	ulong intr_overlay1;
+	ulong intr_overlay2;
 	ulong intr_vsync_p;	/* Primary interface */
 	ulong intr_underrun_p;	/* Primary interface */
 	ulong intr_vsync_e;	/* external interface */
@@ -388,7 +395,7 @@
 void mdp4_mixer_blend_init(int mixer_num);
 void mdp4_vg_qseed_init(int vg_num);
 void mdp4_vg_csc_setup(int vp_num);
-void mdp4_mixer1_csc_setup(void);
+void mdp4_mixer_csc_setup(uint32 mixer);
 void mdp4_vg_csc_update(struct mdp_csc *p);
 irqreturn_t mdp4_isr(int irq, void *ptr);
 void mdp4_overlay_format_to_pipe(uint32 format, struct mdp4_overlay_pipe *pipe);
@@ -421,7 +428,9 @@
 static inline int mdp4_overlay_borderfill_supported(void)
 {
 	unsigned int mdp_hw_version;
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 	mdp_hw_version = inpdw(MDP_BASE + 0x0); /* MDP_HW_VERSION */
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 	return (mdp_hw_version >= 0x0402030b);
 }
 
@@ -635,7 +644,6 @@
 			 struct msmfb_overlay_3d *r3d);
 
 int mdp4_mixer_info(int mixer_num, struct mdp_mixer_info *info);
-int mdp4_writeback_offset(void);
 
 void mdp_dmap_vsync_set(int enable);
 int mdp_dmap_vsync_get(void);
diff --git a/drivers/video/msm/mdp4_dtv.c b/drivers/video/msm/mdp4_dtv.c
index a44f7c0..ba774b9 100644
--- a/drivers/video/msm/mdp4_dtv.c
+++ b/drivers/video/msm/mdp4_dtv.c
@@ -109,6 +109,7 @@
 		clk_disable(ebi1_clk);
 #endif
 	mdp4_extn_disp = 0;
+	mdp_footswitch_ctrl(FALSE);
 	return ret;
 }
 
@@ -126,6 +127,7 @@
 		pm_qos_rate = panel_pixclock_freq / 1000 ;
 	else
 		pm_qos_rate = 58000;
+	mdp_footswitch_ctrl(TRUE);
 	mdp4_extn_disp = 1;
 #ifdef CONFIG_MSM_BUS_SCALING
 	if (dtv_bus_scale_handle > 0)
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index a06eef8..543d21a 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. 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 version 2 and
@@ -48,6 +48,7 @@
 	uint32 panel_mode;
 	uint32 mixer0_played;
 	uint32 mixer1_played;
+	uint32 mixer2_played;
 } mdp4_overlay_db = {
 	.cs_controller = CS_CONTROLLER_0,
 	.plist = {
@@ -83,6 +84,12 @@
 			.pipe_ndx = 6,
 			.mixer_num = MDP4_MIXER1,
 		},
+		{
+			.pipe_type = OVERLAY_TYPE_BF,
+			.pipe_num = OVERLAY_PIPE_VG4,
+			.pipe_ndx = 7,
+			.mixer_num = MDP4_MIXER2,
+		},
 	},
 };
 
@@ -104,7 +111,9 @@
 
 int mdp4_overlay_mixer_play(int mixer_num)
 {
-	if (mixer_num == MDP4_MIXER1)
+	if (mixer_num == MDP4_MIXER2)
+		return ctrl->mixer2_played;
+	else if (mixer_num == MDP4_MIXER1)
 		return ctrl->mixer1_played;
 	else
 		return ctrl->mixer0_played;
@@ -365,15 +374,16 @@
 		pipe->op_mode |= MDP4_OP_SCALEY_EN;
 
 		if (pipe->pipe_num >= OVERLAY_PIPE_VG1) {
-			if (pipe->alpha_enable)
+			if (pipe->alpha_enable && pipe->dst_h > pipe->src_h)
 				pipe->op_mode |= MDP4_OP_SCALEY_PIXEL_RPT;
 			else if (pipe->dst_h <= (pipe->src_h / 4))
 				pipe->op_mode |= MDP4_OP_SCALEY_MN_PHASE;
 			else
 				pipe->op_mode |= MDP4_OP_SCALEY_FIR;
 		} else { /* RGB pipe */
-			pipe->op_mode |= MDP4_OP_SCALE_RGB_BILINEAR;
-			pipe->op_mode |= MDP4_OP_SCALE_ALPHA_BILINEAR;
+			pipe->op_mode |= MDP4_OP_SCALE_RGB_ENHANCED |
+				MDP4_OP_SCALE_RGB_BILINEAR |
+				MDP4_OP_SCALE_ALPHA_BILINEAR;
 		}
 
 		pipe->phasey_step = mdp4_scale_phase_step(29,
@@ -386,15 +396,16 @@
 		pipe->op_mode |= MDP4_OP_SCALEX_EN;
 
 		if (pipe->pipe_num >= OVERLAY_PIPE_VG1) {
-			if (pipe->alpha_enable)
+			if (pipe->alpha_enable && pipe->dst_w > pipe->src_w)
 				pipe->op_mode |= MDP4_OP_SCALEX_PIXEL_RPT;
 			else if (pipe->dst_w <= (pipe->src_w / 4))
 				pipe->op_mode |= MDP4_OP_SCALEX_MN_PHASE;
 			else
 				pipe->op_mode |= MDP4_OP_SCALEX_FIR;
 		} else { /* RGB pipe */
-			pipe->op_mode |= MDP4_OP_SCALE_RGB_BILINEAR;
-			pipe->op_mode |= MDP4_OP_SCALE_ALPHA_BILINEAR;
+			pipe->op_mode |= MDP4_OP_SCALE_RGB_ENHANCED |
+				MDP4_OP_SCALE_RGB_BILINEAR |
+				MDP4_OP_SCALE_ALPHA_BILINEAR;
 		}
 
 		pipe->phasex_step = mdp4_scale_phase_step(29,
@@ -1071,7 +1082,9 @@
 	char *overlay_base;
 
 	intf = 0;
-	if (pipe->mixer_num == MDP4_MIXER1) {
+	if (pipe->mixer_num == MDP4_MIXER2)
+		overlay_base = MDP_BASE + MDP4_OVERLAYPROC2_BASE;
+	else if (pipe->mixer_num == MDP4_MIXER1) {
 		overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */
 		intf = inpdw(MDP_BASE + 0x0038); /* MDP_DISP_INTF_SEL */
 		intf >>= 4;
@@ -1112,10 +1125,10 @@
 #else
 			outpdw(overlay_base + 0x0014, 0x0); /* RGB888 */
 #endif
-		} else {
+		} else if (pipe->mixer_num == MDP4_MIXER2) {
 			if (ctrl->panel_mode & MDP4_PANEL_WRITEBACK) {
 				off = 0;
-				bpp = 2;
+				bpp = 1;
 				if (pipe->ov_cnt & 0x01)
 					off = pipe->src_height *
 							pipe->src_width * bpp;
@@ -1124,12 +1137,22 @@
 						pipe->blt_addr + off);
 				/* overlay ouput is RGB888 */
 				outpdw(overlay_base + 0x0010,
-						pipe->src_width * bpp);
+					((pipe->src_width << 16) |
+					 pipe->src_width));
 				outpdw(overlay_base + 0x001c,
 						pipe->blt_addr + off);
+				off = pipe->src_height * pipe->src_width;
+				/* align chroma to 2k address */
+				off = (off + 2047) & ~2047;
+				/* UV plane adress */
+				outpdw(overlay_base + 0x0020,
+						pipe->blt_addr + off);
 				/* MDDI - BLT + on demand */
 				outpdw(overlay_base + 0x0004, 0x08);
-				outpdw(overlay_base + 0x0014, 0x1); /* RGB565 */
+				/* pseudo planar + writeback */
+				outpdw(overlay_base + 0x0014, 0x012);
+				/* rgb->yuv */
+				outpdw(overlay_base + 0x0200, 0x05);
 			}
 		}
 	} else {
@@ -1160,11 +1183,16 @@
 
 int mdp4_overlay_pipe_staged(int mixer)
 {
-	uint32 data, mask, i;
+	uint32 data, mask, i, off;
 	int p1, p2;
 
+	if (mixer == MDP4_MIXER2)
+		off = 0x100F0;
+	else
+		off = 0x10100;
+
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-	data = inpdw(MDP_BASE + 0x10100);
+	data = inpdw(MDP_BASE + off);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 	p1 = 0;
 	p2 = 0;
@@ -1214,7 +1242,7 @@
 
 void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe)
 {
-	uint32 data, mask, snum, stage, mixer, pnum;
+	uint32 data, mask, snum, stage, mixer, pnum, off;
 	struct mdp4_overlay_pipe *spipe;
 
 	spipe = mdp4_overlay_stage_pipe(pipe->mixer_num, pipe->mixer_stage);
@@ -1230,10 +1258,15 @@
 	mixer = pipe->mixer_num;
 	pnum = pipe->pipe_num;
 
-	/* MDP_LAYERMIXER_IN_CFG, shard by both mixer 0 and 1  */
-	data = inpdw(MDP_BASE + 0x10100);
+	if (mixer == MDP4_MIXER2)
+		off = 0x100F0;
+	else
+		off = 0x10100;
 
-	if (mixer == MDP4_MIXER1)
+	/* MDP_LAYERMIXER_IN_CFG, shard by both mixer 0 and 1  */
+	data = inpdw(MDP_BASE + off);
+
+	if (mixer >= MDP4_MIXER1)
 		stage += 8;
 
 	if (pipe->pipe_type == OVERLAY_TYPE_BF) {
@@ -1254,9 +1287,9 @@
 
 	data |= stage;
 
-	outpdw(MDP_BASE + 0x10100, data); /* MDP_LAYERMIXER_IN_CFG */
+	outpdw(MDP_BASE + off, data); /* MDP_LAYERMIXER_IN_CFG */
 
-	data = inpdw(MDP_BASE + 0x10100);
+	data = inpdw(MDP_BASE + off);
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
@@ -1265,7 +1298,7 @@
 
 void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe)
 {
-	uint32 data, mask, snum, stage, mixer, pnum;
+	uint32 data, mask, snum, stage, mixer, pnum, off;
 
 	stage = pipe->mixer_stage;
 	mixer = pipe->mixer_num;
@@ -1276,10 +1309,15 @@
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 
-	/* MDP_LAYERMIXER_IN_CFG, shard by both mixer 0 and 1  */
-	data = inpdw(MDP_BASE + 0x10100);
+	if (mixer == MDP4_MIXER2)
+		off = 0x100F0;
+	else
+		off = 0x10100;
 
-	if (mixer == MDP4_MIXER1)
+	/* MDP_LAYERMIXER_IN_CFG, shard by both mixer 0 and 1  */
+	data = inpdw(MDP_BASE + off);
+
+	if (mixer >= MDP4_MIXER1)
 		stage += 8;
 
 	if (pipe->pipe_type == OVERLAY_TYPE_BF) {
@@ -1297,9 +1335,9 @@
 	mask <<= snum;
 	data &= ~mask;	/* clear old bits */
 
-	outpdw(MDP_BASE + 0x10100, data); /* MDP_LAYERMIXER_IN_CFG */
+	outpdw(MDP_BASE + off, data); /* MDP_LAYERMIXER_IN_CFG */
 
-	data = inpdw(MDP_BASE + 0x10100);
+	data = inpdw(MDP_BASE + off);
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 
@@ -1311,13 +1349,16 @@
 	struct mdp4_overlay_pipe *bg_pipe;
 	unsigned char *overlay_base, *rgb_base;
 	uint32 c0, c1, c2, blend_op, constant_color = 0, rgb_src_format;
-	uint32 fg_color3_out;
+	uint32 fg_color3_out, fg_alpha = 0, bg_alpha = 0;
 	int off;
 
 	if (pipe->mixer_stage == MDP4_MIXER_STAGE_BASE)
 		return;
 
-	if (pipe->mixer_num) 	/* mixer number, /dev/fb0, /dev/fb1 */
+	/* mixer numer, /dev/fb0, /dev/fb1, /dev/fb2 */
+	if (pipe->mixer_num == MDP4_MIXER2)
+		overlay_base = MDP_BASE + MDP4_OVERLAYPROC2_BASE;/* 0x88000 */
+	else if (pipe->mixer_num == MDP4_MIXER1)
 		overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */
 	else
 		overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */
@@ -1332,17 +1373,48 @@
 		return;
 	}
 
+	if (bg_pipe->pipe_type == OVERLAY_TYPE_BF &&
+	    pipe->mixer_stage > MDP4_MIXER_STAGE0) {
+		bg_pipe = mdp4_overlay_stage_pipe(pipe->mixer_num,
+						  MDP4_MIXER_STAGE0);
+	}
+
+	if (pipe->alpha_enable) {
+		/* alpha channel is lost on VG pipe when downscaling */
+		if (pipe->pipe_type == OVERLAY_TYPE_VIDEO &&
+		    (pipe->dst_w < pipe->src_w || pipe->dst_h < pipe->src_h))
+			fg_alpha = 0;
+		else
+			fg_alpha = 1;
+	}
+
+	if (!fg_alpha && bg_pipe && bg_pipe->alpha_enable) {
+		struct mdp4_overlay_pipe *tmp;
+		int stage;
+
+		bg_alpha = 1;
+		/* check all bg layers are opaque to propagate bg alpha */
+		stage = bg_pipe->mixer_stage + 1;
+		for (; stage < pipe->mixer_stage; stage++) {
+			tmp = mdp4_overlay_stage_pipe(pipe->mixer_num, stage);
+			if (!tmp || tmp->alpha_enable || tmp->is_fg) {
+				bg_alpha = 0;
+				break;
+			}
+		}
+	}
+
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 
 	blend_op = (MDP4_BLEND_FG_ALPHA_FG_CONST |
 		    MDP4_BLEND_BG_ALPHA_BG_CONST);
 	outpdw(overlay_base + off + 0x108, pipe->alpha);
 	outpdw(overlay_base + off + 0x10c, 0xff - pipe->alpha);
-	fg_color3_out = 0; /* keep bg alpha by default */
+	fg_color3_out = 1; /* keep fg alpha by default */
 
 	if (pipe->is_fg) {
 		if (pipe->alpha == 0xff &&
-		    bg_pipe->pipe_num <= OVERLAY_PIPE_RGB2) {
+		    bg_pipe && bg_pipe->pipe_num <= OVERLAY_PIPE_RGB2) {
 			rgb_base = MDP_BASE + MDP4_RGB_BASE;
 			rgb_base += MDP4_RGB_OFF * bg_pipe->pipe_num;
 			rgb_src_format = inpdw(rgb_base + 0x50);
@@ -1350,14 +1422,11 @@
 			outpdw(rgb_base + 0x50, rgb_src_format);
 			outpdw(rgb_base + 0x1008, constant_color);
 		}
-	} else if (pipe->alpha_enable) {
-		/* pick fg alpha */
+	} else if (fg_alpha) {
 		blend_op = (MDP4_BLEND_BG_ALPHA_FG_PIXEL |
-			    MDP4_BLEND_FG_ALPHA_FG_PIXEL |
 			    MDP4_BLEND_BG_INV_ALPHA);
 		fg_color3_out = 1; /* keep fg alpha */
-	} else if (bg_pipe->alpha_enable) {
-		/* pick bg alpha */
+	} else if (bg_alpha) {
 		blend_op = (MDP4_BLEND_BG_ALPHA_BG_PIXEL |
 			    MDP4_BLEND_FG_ALPHA_BG_PIXEL |
 			    MDP4_BLEND_FG_INV_ALPHA);
@@ -1378,7 +1447,7 @@
 			outpdw(overlay_base + off + 0x118,
 					(c1 << 16 | c0));
 			outpdw(overlay_base + off + 0x11c, c2);
-		} else {
+		} else if (bg_pipe) {
 			transp_color_key(bg_pipe->src_format,
 				pipe->transp, &c0, &c1, &c2);
 			/* bg blocked */
@@ -1960,16 +2029,16 @@
 	if (req->flags & MDP_DEINTERLACE)
 		return OVERLAY_PERF_LEVEL1;
 
+	if (ctrl->plist[OVERLAY_PIPE_VG1].pipe_used &&
+	    ctrl->plist[OVERLAY_PIPE_VG2].pipe_used)
+		return OVERLAY_PERF_LEVEL1;
+
 	if (mdp4_overlay_is_rgb_type(req->src.format) && is_fg &&
 		((req->src.width * req->src.height) <= OVERLAY_WSVGA_SIZE))
 		return OVERLAY_PERF_LEVEL4;
 	else if (mdp4_overlay_is_rgb_type(req->src.format))
 		return OVERLAY_PERF_LEVEL1;
 
-	if (ctrl->plist[OVERLAY_PIPE_VG1].pipe_used &&
-		ctrl->plist[OVERLAY_PIPE_VG2].pipe_used)
-		return OVERLAY_PERF_LEVEL1;
-
 	if (req->src.width*req->src.height <= OVERLAY_VGA_SIZE)
 		return OVERLAY_PERF_LEVEL3;
 	else if (req->src.width*req->src.height <= OVERLAY_720P_TILE_SIZE)
@@ -2184,7 +2253,9 @@
 		return -ENODEV;
 	}
 
-	if (pipe->mixer_num == MDP4_MIXER1)
+	if (pipe->mixer_num == MDP4_MIXER2)
+		ctrl->mixer2_played = 0;
+	else if (pipe->mixer_num == MDP4_MIXER1)
 		ctrl->mixer1_played = 0;
 	else {
 		/* mixer 0 */
@@ -2483,7 +2554,15 @@
 	mdp4_mixer_blend_setup(pipe);
 	mdp4_mixer_stage_up(pipe);
 
-	if (pipe->mixer_num == MDP4_MIXER1) {
+	if (pipe->mixer_num == MDP4_MIXER2) {
+		ctrl->mixer2_played++;
+#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
+		if (ctrl->panel_mode & MDP4_PANEL_WRITEBACK) {
+			mdp4_writeback_dma_busy_wait(mfd);
+			mdp4_writeback_kickoff_video(mfd, pipe);
+		}
+#endif
+	} else if (pipe->mixer_num == MDP4_MIXER1) {
 		ctrl->mixer1_played++;
 		/* enternal interface */
 		if (ctrl->panel_mode & MDP4_PANEL_DTV)
@@ -2494,12 +2573,6 @@
 #endif
 		else if (ctrl->panel_mode & MDP4_PANEL_ATV)
 			mdp4_overlay_reg_flush(pipe, 1);
-#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
-		else if (ctrl->panel_mode & MDP4_PANEL_WRITEBACK) {
-			mdp4_writeback_dma_busy_wait(mfd);
-			mdp4_writeback_kickoff_video(mfd, pipe);
-		}
-#endif
 	} else {
 
 		/* primary interface */
diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
index 4479ece..484ed7d 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -45,8 +45,6 @@
 
 struct timer_list dsi_clock_timer;
 
-static int writeback_offset;
-
 void mdp4_overlay_dsi_state_set(int state)
 {
 	unsigned long flag;
@@ -119,7 +117,6 @@
 void mdp4_overlay_update_dsi_cmd(struct msm_fb_data_type *mfd)
 {
 	MDPIBUF *iBuf = &mfd->ibuf;
-	struct fb_info *fbi = mfd->fbi;
 	uint8 *src;
 	int ptype;
 	struct mdp4_overlay_pipe *pipe;
@@ -159,14 +156,9 @@
 
 		dsi_pipe = pipe; /* keep it */
 
-		writeback_offset = mdp4_writeback_offset();
+		pipe->blt_base = (ulong) mfd->writeback_overlay0_phys;
+		pipe->blt_addr = 0;
 
-		if (writeback_offset > 0) {
-			pipe->blt_base = (ulong)fbi->fix.smem_start;
-			pipe->blt_base += writeback_offset;
-		} else {
-			pipe->blt_base  = 0;
-		}
 	} else {
 		pipe = dsi_pipe;
 	}
@@ -351,7 +343,7 @@
 int mdp4_dsi_overlay_blt_offset(struct msm_fb_data_type *mfd,
 					struct msmfb_overlay_blt *req)
 {
-	req->offset = writeback_offset;
+	req->offset = 0;
 	req->width = dsi_pipe->src_width;
 	req->height = dsi_pipe->src_height;
 	req->bpp = dsi_pipe->bpp;
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 938d7c6..d68396a 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -37,8 +37,6 @@
 static int first_pixel_start_x;
 static int first_pixel_start_y;
 
-static int writeback_offset;
-
 static struct mdp4_overlay_pipe *dsi_pipe;
 static struct completion dsi_video_comp;
 
@@ -141,14 +139,9 @@
 		dsi_pipe = pipe; /* keep it */
 		init_completion(&dsi_video_comp);
 
-		writeback_offset = mdp4_writeback_offset();
+		pipe->blt_base = (ulong) mfd->writeback_overlay0_phys;
+		pipe->blt_addr = 0;
 
-		if (writeback_offset > 0) {
-			pipe->blt_base = (ulong)fbi->fix.smem_start;
-			pipe->blt_base += writeback_offset;
-		} else {
-			pipe->blt_base  = 0;
-		}
 	} else {
 		pipe = dsi_pipe;
 	}
@@ -634,7 +627,7 @@
 int mdp4_dsi_video_overlay_blt_offset(struct msm_fb_data_type *mfd,
 					struct msmfb_overlay_blt *req)
 {
-	req->offset = writeback_offset;
+	req->offset = 0;
 	req->width = dsi_pipe->src_width;
 	req->height = dsi_pipe->src_height;
 	req->bpp = dsi_pipe->bpp;
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index c8135d4..08eb948 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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 version 2 and
@@ -333,8 +333,6 @@
 		MDP_OUTP(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x5008,
 			(0x0 & 0xFFF));		/* 12-bit R */
 		mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-
-		pipe->src_format = MDP_ARGB_8888;
 	} else {
 		switch (mfd->ibuf.bpp) {
 		case 2:
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index f318691..1dbbf94 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -42,8 +42,6 @@
 int first_pixel_start_x;
 int first_pixel_start_y;
 
-static int writeback_offset;
-
 static struct mdp4_overlay_pipe *lcdc_pipe;
 static struct completion lcdc_comp;
 
@@ -128,14 +126,9 @@
 		lcdc_pipe = pipe; /* keep it */
 		init_completion(&lcdc_comp);
 
-		writeback_offset = mdp4_writeback_offset();
+		pipe->blt_base = (ulong) mfd->writeback_overlay0_phys;
+		pipe->blt_addr = 0;
 
-		if (writeback_offset > 0) {
-			pipe->blt_base = (ulong)fbi->fix.smem_start;
-			pipe->blt_base += writeback_offset;
-		} else {
-			pipe->blt_base  = 0;
-		}
 	} else {
 		pipe = lcdc_pipe;
 	}
@@ -507,7 +500,7 @@
 int mdp4_lcdc_overlay_blt_offset(struct msm_fb_data_type *mfd,
 					struct msmfb_overlay_blt *req)
 {
-	req->offset = writeback_offset;
+	req->offset = 0;
 	req->width = lcdc_pipe->src_width;
 	req->height = lcdc_pipe->src_height;
 	req->bpp = lcdc_pipe->bpp;
diff --git a/drivers/video/msm/mdp4_overlay_writeback.c b/drivers/video/msm/mdp4_overlay_writeback.c
index cd027e9..8f68e11 100644
--- a/drivers/video/msm/mdp4_overlay_writeback.c
+++ b/drivers/video/msm/mdp4_overlay_writeback.c
@@ -48,11 +48,10 @@
 	struct msm_fb_data_type *mfd;
 	struct fb_info *fbi;
 	uint8 *buf;
-	int ptype;
 	struct mdp4_overlay_pipe *pipe;
 	int bpp;
 	int ret;
-	uint32 format;
+	uint32 data;
 
 	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
 
@@ -71,27 +70,17 @@
 	buf += fbi->var.xoffset * bpp +
 		fbi->var.yoffset * fbi->fix.line_length;
 
-	if (bpp == 2)
-		format = MDP_RGB_565;
-	else if (bpp == 3)
-		format = MDP_RGB_888;
-	else
-		format = MDP_ARGB_8888;
-
 	/* MDP cmd block enable */
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 
 	if (writeback_pipe == NULL) {
-		ptype = mdp4_overlay_format2type(format);
-		if (ptype < 0)
-			pr_err("%s: format2type failed\n", __func__);
-		pipe = mdp4_overlay_pipe_alloc(ptype, MDP4_MIXER1);
+		pipe = mdp4_overlay_pipe_alloc(OVERLAY_TYPE_BF, MDP4_MIXER2);
 		if (pipe == NULL)
 			pr_info("%s: pipe_alloc failed\n", __func__);
 		pipe->pipe_used++;
 		pipe->mixer_stage  = MDP4_MIXER_STAGE_BASE;
-		pipe->mixer_num  = MDP4_MIXER1;
-		pipe->src_format = format;
+		pipe->mixer_num  = MDP4_MIXER2;
+		pipe->src_format = MDP_ARGB_8888;
 		mdp4_overlay_panel_mode(pipe->mixer_num, MDP4_PANEL_WRITEBACK);
 		ret = mdp4_overlay_format2pipe(pipe);
 		if (ret < 0)
@@ -103,6 +92,18 @@
 		pipe = writeback_pipe;
 	}
 	ret = panel_next_on(pdev);
+	/* MDP_LAYERMIXER_WB_MUX_SEL to use mixer1 axi for mixer2 writeback */
+	data = inpdw(MDP_BASE + 0x100F4);
+	data &= ~0x02; /* clear the mixer1 mux bit */
+	data |= 0x02;
+	outpdw(MDP_BASE + 0x100F4, data);
+	MDP_OUTP(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x5004,
+		((0x0 & 0xFFF) << 16) | /* 12-bit B */
+			(0x0 & 0xFFF));         /* 12-bit G */
+	/* MSP_BORDER_COLOR */
+	MDP_OUTP(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x5008,
+		(0x0 & 0xFFF));         /* 12-bit R */
+
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 	return ret;
 }
@@ -110,14 +111,24 @@
 int mdp4_overlay_writeback_off(struct platform_device *pdev)
 {
 	int ret;
+	uint32 data;
 	struct msm_fb_data_type *mfd =
 			(struct msm_fb_data_type *)platform_get_drvdata(pdev);
 	if (mfd && writeback_pipe) {
 		mdp4_writeback_dma_busy_wait(mfd);
 		mdp4_overlay_pipe_free(writeback_pipe);
+		mdp4_overlay_panel_mode_unset(writeback_pipe->mixer_num,
+						MDP4_PANEL_WRITEBACK);
 		writeback_pipe = NULL;
 	}
 	ret = panel_next_off(pdev);
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	/* MDP_LAYERMIXER_WB_MUX_SEL to restore
+	 * mixer1 axi for mixer1 writeback */
+	data = inpdw(MDP_BASE + 0x100F4);
+	data &= ~0x02; /* clear the mixer1 mux bit */
+	outpdw(MDP_BASE + 0x100F4, data);
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 	return ret;
 }
 int mdp4_overlay_writeback_update(struct msm_fb_data_type *mfd)
@@ -159,8 +170,6 @@
 	pipe->srcp0_addr = (uint32)buf;
 
 
-	mdp4_overlay_rgb_setup(pipe);
-
 	mdp4_mixer_stage_up(pipe);
 
 	mdp4_overlayproc_cfg(pipe);
@@ -202,7 +211,7 @@
 	if (busy_wait_cnt)
 		busy_wait_cnt--;
 
-	mdp_disable_irq_nosync(MDP_OVERLAY1_TERM);
+	mdp_disable_irq_nosync(MDP_OVERLAY2_TERM);
 	pr_debug("%s ovdone interrupt\n", __func__);
 
 }
@@ -211,17 +220,17 @@
 {
 	unsigned long flag;
 	spin_lock_irqsave(&mdp_spin_lock, flag);
-	mdp_enable_irq(MDP_OVERLAY1_TERM);
+	mdp_enable_irq(MDP_OVERLAY2_TERM);
 	INIT_COMPLETION(writeback_pipe->comp);
 	mfd->dma->busy = TRUE;
-	outp32(MDP_INTR_CLEAR, INTR_OVERLAY1_DONE);
-	mdp_intr_mask |= INTR_OVERLAY1_DONE;
+	outp32(MDP_INTR_CLEAR, INTR_OVERLAY2_DONE);
+	mdp_intr_mask |= INTR_OVERLAY2_DONE;
 	outp32(MDP_INTR_ENABLE, mdp_intr_mask);
 
 	wmb();	/* make sure all registers updated */
 	spin_unlock_irqrestore(&mdp_spin_lock, flag);
 	/* start OVERLAY pipe */
-	mdp_pipe_kickoff(MDP_OVERLAY1_TERM, mfd);
+	mdp_pipe_kickoff(MDP_OVERLAY2_TERM, mfd);
 	wmb();
 	pr_debug("%s: before ov done interrupt\n", __func__);
 	wait_for_completion_killable(&mfd->dma->comp);
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index f51427c..f9edf07 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -79,7 +79,7 @@
 
 	if (overlayer == MDP4_MIXER0)
 		outpdw(MDP_BASE + 0x10004, bits); /* MDP_OVERLAY0_CFG */
-	else
+	else if (overlayer == MDP4_MIXER1)
 		outpdw(MDP_BASE + 0x18004, bits); /* MDP_OVERLAY1_CFG */
 
 	MSM_FB_DEBUG("mdp4_overlay_cfg: 0x%x\n",
@@ -273,7 +273,8 @@
 
 	mdp4_vg_csc_setup(0);
 	mdp4_vg_csc_setup(1);
-	mdp4_mixer1_csc_setup();
+	mdp4_mixer_csc_setup(1);
+	mdp4_mixer_csc_setup(2);
 
 	if (mdp_rev <= MDP_REV_41) {
 		mdp4_mixer_gc_lut_setup(0);
@@ -473,11 +474,21 @@
 		if (panel & MDP4_PANEL_ATV)
 			mdp4_overlay1_done_atv();
 #endif
+	}
 #if defined(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL)
+	if (isr & INTR_OVERLAY2_DONE) {
+		mdp4_stat.intr_overlay2++;
+		/* disable DTV interrupt */
+		dma = &dma_wb_data;
+		spin_lock(&mdp_spin_lock);
+		mdp_intr_mask &= ~INTR_OVERLAY2_DONE;
+		outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+		dma->waiting = FALSE;
+		spin_unlock(&mdp_spin_lock);
 		if (panel & MDP4_PANEL_WRITEBACK)
 			mdp4_overlay1_done_writeback(dma);
-#endif
 	}
+#endif
 #endif	/* OVERLAY */
 
 	if (isr & INTR_DMA_P_DONE) {
@@ -1416,12 +1427,15 @@
 	0x00f0, 0x0010, 0x00f0
 };
 
-void mdp4_mixer1_csc_mv_setup(void)
+void mdp4_mixer_csc_mv_setup(uint32 mixer)
 {
 	uint32 *off;
 	int i;
 
-	off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2400);
+	if (mixer == MDP4_MIXER1)
+		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2400);
+	else
+		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2400);
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 	for (i = 0; i < 9; i++) {
@@ -1431,12 +1445,15 @@
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 }
 
-void mdp4_mixer1_csc_pre_bv_setup(void)
+void mdp4_mixer_csc_pre_bv_setup(uint32 mixer)
 {
 	uint32 *off;
 	int i;
 
-	off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2500);
+	if (mixer == MDP4_MIXER1)
+		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2500);
+	else
+		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2500);
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 	for (i = 0; i < 3; i++) {
@@ -1446,12 +1463,15 @@
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 }
 
-void mdp4_mixer1_csc_post_bv_setup(void)
+void mdp4_mixer_csc_post_bv_setup(uint32 mixer)
 {
 	uint32 *off;
 	int i;
 
-	off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2580);
+	if (mixer == MDP4_MIXER1)
+		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2580);
+	else
+		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2580);
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 	for (i = 0; i < 3; i++) {
@@ -1461,12 +1481,15 @@
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 }
 
-void mdp4_mixer1_csc_pre_lv_setup(void)
+void mdp4_mixer_csc_pre_lv_setup(uint32 mixer)
 {
 	uint32 *off;
 	int i;
 
-	off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2600);
+	if (mixer == MDP4_MIXER1)
+		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2600);
+	else
+		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2600);
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 	for (i = 0; i < 6; i++) {
@@ -1476,12 +1499,15 @@
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 }
 
-void mdp4_mixer1_csc_post_lv_setup(void)
+void mdp4_mixer_csc_post_lv_setup(uint32 mixer)
 {
 	uint32 *off;
 	int i;
 
-	off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2680);
+	if (mixer == MDP4_MIXER1)
+		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x2680);
+	else
+		off = (uint32 *)(MDP_BASE + MDP4_OVERLAYPROC2_BASE + 0x2680);
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 	for (i = 0; i < 6; i++) {
@@ -1491,14 +1517,16 @@
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 }
 
-void mdp4_mixer1_csc_setup(void)
+void mdp4_mixer_csc_setup(uint32 mixer)
 {
+	if (mixer >= MDP4_MIXER1) {
 		/* rgb2yuv */
-		mdp4_mixer1_csc_mv_setup();
-		mdp4_mixer1_csc_pre_bv_setup();
-		mdp4_mixer1_csc_post_bv_setup();
-		mdp4_mixer1_csc_pre_lv_setup();
-		mdp4_mixer1_csc_post_lv_setup();
+		mdp4_mixer_csc_mv_setup(mixer);
+		mdp4_mixer_csc_pre_bv_setup(mixer);
+		mdp4_mixer_csc_post_bv_setup(mixer);
+		mdp4_mixer_csc_pre_lv_setup(mixer);
+		mdp4_mixer_csc_post_lv_setup(mixer);
+	}
 }
 
 char gc_lut[] = {
diff --git a/drivers/video/msm/mdp4_wfd_writeback_panel.c b/drivers/video/msm/mdp4_wfd_writeback_panel.c
index 77f714c..32b0669 100644
--- a/drivers/video/msm/mdp4_wfd_writeback_panel.c
+++ b/drivers/video/msm/mdp4_wfd_writeback_panel.c
@@ -39,7 +39,7 @@
 		.type = WRITEBACK_PANEL,
 		.xres = 800,
 		.yres = 480,
-		.pdest = DISPLAY_2,
+		.pdest = DISPLAY_3,
 		.wait_cycle = 0,
 		.bpp = 24,
 		.fb_num = 1,
diff --git a/drivers/video/msm/mdp_debugfs.c b/drivers/video/msm/mdp_debugfs.c
index 9ae1d9c5..2eb9257 100644
--- a/drivers/video/msm/mdp_debugfs.c
+++ b/drivers/video/msm/mdp_debugfs.c
@@ -297,6 +297,10 @@
 					mdp4_stat.intr_overlay1);
 	bp += len;
 	dlen -= len;
+	len = snprintf(bp, dlen, "int_overlay1: %08lu\n",
+					mdp4_stat.intr_overlay2);
+	bp += len;
+	dlen -= len;
 
 	len = snprintf(bp, dlen, "int_dmap: %08lu\t",
 					mdp4_stat.intr_dma_p);
diff --git a/drivers/video/msm/mhl_api.h b/drivers/video/msm/mhl_api.h
index 3f70dac..627f802 100644
--- a/drivers/video/msm/mhl_api.h
+++ b/drivers/video/msm/mhl_api.h
@@ -14,7 +14,7 @@
 #ifndef __MHL_API_H__
 #define __MHL_API_H__
 
-#ifdef CONFIG_MHL
+#ifdef CONFIG_FB_MSM_HDMI_MHL
 bool mhl_is_connected(void);
 #else
 static bool mhl_is_connected(void)
diff --git a/drivers/video/msm/mipi_novatek.c b/drivers/video/msm/mipi_novatek.c
index 5e2e515..caa4114 100644
--- a/drivers/video/msm/mipi_novatek.c
+++ b/drivers/video/msm/mipi_novatek.c
@@ -432,11 +432,8 @@
 static void mipi_novatek_set_backlight(struct msm_fb_data_type *mfd)
 {
 	struct mipi_panel_info *mipi;
-	static int bl_level_old;
 
 	mipi  = &mfd->panel_info.mipi;
-	if (bl_level_old == mfd->bl_level)
-		return;
 
 	mutex_lock(&mfd->dma->ov_mutex);
 	if (mdp4_overlay_dsi_state_get() <= ST_DSI_SUSPEND) {
@@ -451,7 +448,6 @@
 	led_pwm1[1] = (unsigned char)(mfd->bl_level);
 	mipi_dsi_cmds_tx(mfd, &novatek_tx_buf, novatek_cmd_backlight_cmds,
 			ARRAY_SIZE(novatek_cmd_backlight_cmds));
-	bl_level_old = mfd->bl_level;
 	mutex_unlock(&mfd->dma->ov_mutex);
 	return;
 }
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 59c2afe..ab91e41 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -665,16 +665,31 @@
 }
 #endif
 
+static int unset_bl_level, bl_updated;
+static int bl_level_old;
+
 void msm_fb_set_backlight(struct msm_fb_data_type *mfd, __u32 bkl_lvl)
 {
 	struct msm_fb_panel_data *pdata;
 
+	if (!mfd->panel_power_on || !bl_updated) {
+		unset_bl_level = bkl_lvl;
+		return;
+	} else {
+		unset_bl_level = 0;
+	}
+
 	pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
 
 	if ((pdata) && (pdata->set_backlight)) {
 		down(&mfd->sem);
+		if (bl_level_old == bkl_lvl) {
+			up(&mfd->sem);
+			return;
+		}
 		mfd->bl_level = bkl_lvl;
 		pdata->set_backlight(mfd);
+		bl_level_old = mfd->bl_level;
 		up(&mfd->sem);
 	}
 }
@@ -728,6 +743,7 @@
 			mfd->op_enable = FALSE;
 			curr_pwr_state = mfd->panel_power_on;
 			mfd->panel_power_on = FALSE;
+			bl_updated = 0;
 
 			msleep(16);
 			ret = pdata->off(mfd->pdev);
@@ -1393,6 +1409,7 @@
 	struct mdp_dirty_region dirty;
 	struct mdp_dirty_region *dirtyPtr = NULL;
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	struct msm_fb_panel_data *pdata;
 
 	if ((!mfd->op_enable) || (!mfd->panel_power_on))
 		return -EPERM;
@@ -1459,6 +1476,19 @@
 	mdp_dma_pan_update(info);
 	up(&msm_fb_pan_sem);
 
+	if (unset_bl_level && !bl_updated) {
+		pdata = (struct msm_fb_panel_data *)mfd->pdev->
+			dev.platform_data;
+		if ((pdata) && (pdata->set_backlight)) {
+			down(&mfd->sem);
+			mfd->bl_level = unset_bl_level;
+			pdata->set_backlight(mfd);
+			bl_level_old = unset_bl_level;
+			up(&mfd->sem);
+		}
+		bl_updated = 1;
+	}
+
 	++mfd->panel_info.frame_count;
 	return 0;
 }
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index de2734d..9ee8972 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -166,6 +166,8 @@
 	struct completion msmfb_update_notify;
 	struct completion msmfb_no_update_notify;
 	u32 ov_start, ov_end;
+	void *writeback_overlay0_phys;
+	void *writeback_overlay1_phys;
 	struct mutex writeback_mutex;
 	struct mutex unregister_mutex;
 	struct list_head writeback_busy_queue;
diff --git a/drivers/video/msm/msm_fb_panel.h b/drivers/video/msm/msm_fb_panel.h
index 82ac915..d66d802 100644
--- a/drivers/video/msm/msm_fb_panel.h
+++ b/drivers/video/msm/msm_fb_panel.h
@@ -51,6 +51,7 @@
 typedef enum {
 	DISPLAY_1 = 0,		/* attached as first device */
 	DISPLAY_2,		/* attached on second device */
+	DISPLAY_3,              /* attached on third writeback device */
 	MAX_PHYS_TARGET_NUM,
 } DISP_TARGET_PHYS;
 
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
index 1144166..051d32dc 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
@@ -253,6 +253,7 @@
 	u32  mb_info_enable;
 	u32  ext_enc_control_val;
 	u32  num_references_for_p_frame;
+	u32	 closed_gop;
 };
 struct ddl_decoder_data {
 	struct ddl_codec_data_hdr  hdr;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
index f10abc5..6078821 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
@@ -237,7 +237,6 @@
 	struct ddl_frame_data_tag *frame;
 	u32 luma[DDL_MAX_BUFFER_COUNT], chroma[DDL_MAX_BUFFER_COUNT];
 	u32 mv[DDL_MAX_BUFFER_COUNT], luma_size, i, dpb;
-
 	frame = &decoder->dp_buf.dec_pic_buffers[0];
 	luma_size = ddl_get_yuv_buf_size(decoder->frame_size.width,
 			decoder->frame_size.height, DDL_YUV_BUF_TYPE_TILE);
@@ -248,9 +247,16 @@
 		dpb = DDL_MAX_BUFFER_COUNT;
 	for (i = 0; i < dpb; i++) {
 		if (frame[i].vcd_frm.virtual) {
-			memset(frame[i].vcd_frm.virtual, 0x10101010, luma_size);
-			memset(frame[i].vcd_frm.virtual + luma_size, 0x80808080,
+			if (luma_size <= frame[i].vcd_frm.alloc_len) {
+				memset(frame[i].vcd_frm.virtual,
+					 0x10101010, luma_size);
+				memset(frame[i].vcd_frm.virtual + luma_size,
+					 0x80808080,
 					frame[i].vcd_frm.alloc_len - luma_size);
+			} else {
+				DDL_MSG_ERROR("luma size error");
+				return VCD_ERR_FAIL;
+			}
 		}
 
 		luma[i] = DDL_OFFSET(ddl_context->dram_base_a.
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
index 5485335..d2969b6 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -1540,6 +1540,8 @@
 	encoder->hdr_ext_control = 0;
 	encoder->mb_info_enable  = false;
 	encoder->num_references_for_p_frame = DDL_MIN_NUM_REF_FOR_P_FRAME;
+	if (encoder->codec.codec == VCD_CODEC_MPEG4)
+		encoder->closed_gop = true;
 	ddl_set_default_metadata_flag(ddl);
 	ddl_set_default_encoder_buffer_req(encoder);
 }
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
index ac05364..f8977e9 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
@@ -204,6 +204,9 @@
 #define VIDC_SM_SEI_ENABLE_RECOVERY_POINT_SEI_BMSK  0x00000001
 #define VIDC_SM_SEI_ENABLE_RECOVERY_POINT_SEI_SHFT  0
 
+#define VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_BMSK	0x40
+#define VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_SHFT	6
+
 #define DDL_MEM_WRITE_32(base, offset, val) ddl_mem_write_32(\
 	(u32 *) ((u8 *) (base)->align_virtual_addr + (offset)), (val))
 #define DDL_MEM_READ_32(base, offset) ddl_mem_read_32(\
@@ -348,7 +351,8 @@
 void vidc_sm_set_extended_encoder_control(struct ddl_buf_addr
 	*shared_mem, u32 hec_enable,
 	enum VIDC_SM_frame_skip frame_skip_mode,
-	u32 seq_hdr_in_band, u32 vbv_buffer_size, u32 cpcfc_enable)
+	u32 seq_hdr_in_band, u32 vbv_buffer_size, u32 cpcfc_enable,
+	u32 closed_gop_enable)
 {
 	u32 enc_ctrl;
 
@@ -366,7 +370,10 @@
 			VIDC_SM_ENC_EXT_CTRL_VBV_BUFFER_SIZE_BMSK) |
 			VIDC_SETFIELD((cpcfc_enable) ? 1 : 0,
 			VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_SHFT,
-			VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_BMSK);
+			VIDC_SM_ENC_EXT_CTRL_H263_CPCFC_ENABLE_BMSK) |
+			VIDC_SETFIELD(closed_gop_enable,
+			VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_SHFT,
+			VIDC_SM_ENC_EXT_CTRL_CLOSED_GOP_ENABLE_BMSK);
 	DDL_MEM_WRITE_32(shared_mem, VIDC_SM_ENC_EXT_CTRL_ADDR, enc_ctrl);
 }
 
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
index 8a4b598..78bfee5 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.h
@@ -100,7 +100,7 @@
 void vidc_sm_set_extended_encoder_control(
 	struct ddl_buf_addr *shared_mem, u32 hec_enable,
 	enum VIDC_SM_frame_skip  frame_skip_mode, u32 seq_hdr_in_band,
-	u32 vbv_buffer_size, u32 cpcfc_enable);
+	u32 vbv_buffer_size, u32 cpcfc_enable, u32 closed_gop_enable);
 void vidc_sm_set_encoder_param_change(struct ddl_buf_addr *shared_mem,
 	u32 bit_rate_chg, u32 frame_rate_chg, u32 i_period_chg);
 void vidc_sm_set_encoder_vop_time(struct ddl_buf_addr *shared_mem,
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
index 521e3b6..43aba2e 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
@@ -126,12 +126,13 @@
 		if (addr->alloc_handle) {
 			ion_free(ddl_context->video_ion_client,
 				addr->alloc_handle);
+			addr->alloc_handle = NULL;
 		}
-	} else
+	} else {
 		free_contiguous_memory_by_paddr(
 			(unsigned long)addr->alloced_phys_addr);
-	addr->alloc_handle = NULL;
-	addr->alloced_phys_addr = (phys_addr_t)NULL;
+		addr->alloced_phys_addr = (phys_addr_t)NULL;
+	}
 bail_out:
 	return NULL;
 }
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
index 5ae8d09..ab50258 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -541,7 +541,7 @@
 	vidc_sm_set_extended_encoder_control(&ddl->shared_mem
 		[ddl->command_channel], hdr_ext_control,
 		r_cframe_skip, false, 0,
-		h263_cpfc_enable);
+		h263_cpfc_enable, encoder->closed_gop);
 	vidc_sm_set_encoder_init_rc_value(&ddl->shared_mem
 		[ddl->command_channel],
 		encoder->target_bit_rate.target_bitrate);
@@ -818,7 +818,8 @@
 	if (vidc_msg_timing)
 		ddl_set_core_start_time(__func__, DEC_OP_TIME);
 	ddl_decoder_dpb_transact(decoder, NULL, DDL_DPB_OP_INIT);
-	ddl_decoder_dpb_init(ddl);
+	if (ddl_decoder_dpb_init(ddl) == VCD_ERR_FAIL)
+		return VCD_ERR_FAIL;
 	DDL_MSG_LOW("ddl_state_transition: %s ~~> DDL_CLIENT_WAIT_FOR_DPBDONE",
 	ddl_get_state_string(ddl->client_state));
 	ddl->client_state = DDL_CLIENT_WAIT_FOR_DPBDONE;
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl.c
index d27b354..7c68d63 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl.c
@@ -474,8 +474,7 @@
 	}
 	if (!input_frame ||
 	    !input_frame->vcd_frm.physical ||
-	    ddl->codec_data.encoder.input_buf_req.sz !=
-	    input_frame->vcd_frm.data_len) {
+	    !input_frame->vcd_frm.data_len) {
 		VIDC_LOGERR_STRING("ddl_enc_frame:Bad_input_params");
 		return VCD_ERR_ILLEGAL_PARM;
 	}
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_properties.c
index d1b1952..6d3c666 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_properties.c
@@ -840,6 +840,11 @@
 				ddl, property_hdr, property_value);
 			break;
 		}
+	case VCD_I_META_BUFFER_MODE:
+		{
+			vcd_status = VCD_S_SUCCESS;
+			break;
+		}
 	default:
 		{
 			vcd_status = VCD_ERR_ILLEGAL_OP;
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.c b/drivers/video/msm/vidc/common/enc/venc_internal.c
index ee38098..47f2db5 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.c
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.c
@@ -597,6 +597,9 @@
 		case VEN_LEVEL_H264_3p1:
 			level.level = VCD_LEVEL_H264_3p1;
 			break;
+		case VEN_LEVEL_H264_3p2:
+			level.level = VCD_LEVEL_H264_3p2;
+			break;
 		case VEN_LEVEL_H264_4:
 			level.level = VCD_LEVEL_H264_4;
 			break;
@@ -700,7 +703,7 @@
 				profile_level->level = VEN_LEVEL_H264_3p1;
 				break;
 			case VCD_LEVEL_H264_3p2:
-				status = false;
+				profile_level->level = VEN_LEVEL_H264_3p2;
 				break;
 			case VCD_LEVEL_H264_4:
 				profile_level->level = VEN_LEVEL_H264_4;
diff --git a/drivers/video/msm/vidc/common/init/vidc_init.c b/drivers/video/msm/vidc/common/init/vidc_init.c
index 1217f1f..05df44f 100644
--- a/drivers/video/msm/vidc/common/init/vidc_init.c
+++ b/drivers/video/msm/vidc/common/init/vidc_init.c
@@ -450,7 +450,7 @@
 	unsigned long length)
 {
 	unsigned long len, phys_addr;
-	struct file *file;
+	struct file *file = NULL;
 	u32 *num_of_buffers = NULL;
 	u32 i, flags;
 	struct buf_addr_table *buf_addr_table;
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 4900e9c..9c43f56 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -368,6 +368,7 @@
 header-y += tipc.h
 header-y += tipc_config.h
 header-y += toshiba.h
+header-y += tspp.h
 header-y += tty.h
 header-y += types.h
 header-y += udf_fs_i.h
diff --git a/include/linux/android_pmem.h b/include/linux/android_pmem.h
index c0291969..ab96379 100644
--- a/include/linux/android_pmem.h
+++ b/include/linux/android_pmem.h
@@ -157,12 +157,12 @@
 	 * function to be called when the number of allocations goes from
 	 * 0 -> 1
 	 */
-	void (*request_region)(void *);
+	int (*request_region)(void *);
 	/*
 	 * function to be called when the number of allocations goes from
 	 * 1 -> 0
 	 */
-	void (*release_region)(void *);
+	int (*release_region)(void *);
 	/*
 	 * function to be called upon pmem registration
 	 */
@@ -171,6 +171,10 @@
 	 * indicates that this region should be mapped/unmaped as needed
 	 */
 	int map_on_demand;
+	/*
+	 * indicates this pmem may be reused via fmem
+	 */
+	int reusable;
 };
 
 int pmem_setup(struct android_pmem_platform_data *pdata,
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 5c94a3c..bdbaffd 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -41,9 +41,16 @@
 #define AO8960_MACHINE_ID	87
 #define MSM8660_MACHINE_ID	71
 #define APQ8064_MACHINE_ID	109
+#define MSM8930_MACHINE_ID	116
+#define MSM8630_MACHINE_ID	117
+#define MSM8230_MACHINE_ID	118
+#define APQ8030_MACHINE_ID	119
+#define MSM8627_MACHINE_ID	120
+#define MSM8227_MACHINE_ID	121
 #define APQ8060_TOOLS_ID	4062
 #define AO8960_TOOLS_ID		4064
 #define APQ8064_TOOLS_ID	4072
+#define MSM8930_TOOLS_ID	4072
 
 #define MSG_MASK_0			(0x00000001)
 #define MSG_MASK_1			(0x00000002)
diff --git a/include/linux/export.h b/include/linux/export.h
new file mode 100644
index 0000000..696c0f4
--- /dev/null
+++ b/include/linux/export.h
@@ -0,0 +1,89 @@
+#ifndef _LINUX_EXPORT_H
+#define _LINUX_EXPORT_H
+/*
+ * Export symbols from the kernel to modules.  Forked from module.h
+ * to reduce the amount of pointless cruft we feed to gcc when only
+ * exporting a simple symbol or two.
+ *
+ * If you feel the need to add #include <linux/foo.h> to this file
+ * then you are doing something wrong and should go away silently.
+ */
+
+/* Some toolchains use a `_' prefix for all user symbols. */
+#ifdef CONFIG_SYMBOL_PREFIX
+#define MODULE_SYMBOL_PREFIX CONFIG_SYMBOL_PREFIX
+#else
+#define MODULE_SYMBOL_PREFIX ""
+#endif
+
+struct kernel_symbol
+{
+	unsigned long value;
+	const char *name;
+};
+
+#ifdef MODULE
+extern struct module __this_module;
+#define THIS_MODULE (&__this_module)
+#else
+#define THIS_MODULE ((struct module *)0)
+#endif
+
+#ifdef CONFIG_MODULES
+
+#ifndef __GENKSYMS__
+#ifdef CONFIG_MODVERSIONS
+/* Mark the CRC weak since genksyms apparently decides not to
+ * generate a checksums for some symbols */
+#define __CRC_SYMBOL(sym, sec)					\
+	extern void *__crc_##sym __attribute__((weak));		\
+	static const unsigned long __kcrctab_##sym		\
+	__used							\
+	__attribute__((section("___kcrctab" sec "+" #sym), unused))	\
+	= (unsigned long) &__crc_##sym;
+#else
+#define __CRC_SYMBOL(sym, sec)
+#endif
+
+/* For every exported symbol, place a struct in the __ksymtab section */
+#define __EXPORT_SYMBOL(sym, sec)				\
+	extern typeof(sym) sym;					\
+	__CRC_SYMBOL(sym, sec)					\
+	static const char __kstrtab_##sym[]			\
+	__attribute__((section("__ksymtab_strings"), aligned(1))) \
+	= MODULE_SYMBOL_PREFIX #sym;				\
+	static const struct kernel_symbol __ksymtab_##sym	\
+	__used							\
+	__attribute__((section("___ksymtab" sec "+" #sym), unused))	\
+	= { (unsigned long)&sym, __kstrtab_##sym }
+
+#define EXPORT_SYMBOL(sym)					\
+	__EXPORT_SYMBOL(sym, "")
+
+#define EXPORT_SYMBOL_GPL(sym)					\
+	__EXPORT_SYMBOL(sym, "_gpl")
+
+#define EXPORT_SYMBOL_GPL_FUTURE(sym)				\
+	__EXPORT_SYMBOL(sym, "_gpl_future")
+
+#ifdef CONFIG_UNUSED_SYMBOLS
+#define EXPORT_UNUSED_SYMBOL(sym) __EXPORT_SYMBOL(sym, "_unused")
+#define EXPORT_UNUSED_SYMBOL_GPL(sym) __EXPORT_SYMBOL(sym, "_unused_gpl")
+#else
+#define EXPORT_UNUSED_SYMBOL(sym)
+#define EXPORT_UNUSED_SYMBOL_GPL(sym)
+#endif
+
+#endif	/* __GENKSYMS__ */
+
+#else /* !CONFIG_MODULES... */
+
+#define EXPORT_SYMBOL(sym)
+#define EXPORT_SYMBOL_GPL(sym)
+#define EXPORT_SYMBOL_GPL_FUTURE(sym)
+#define EXPORT_UNUSED_SYMBOL(sym)
+#define EXPORT_UNUSED_SYMBOL_GPL(sym)
+
+#endif /* CONFIG_MODULES */
+
+#endif /* _LINUX_EXPORT_H */
diff --git a/include/linux/fmem.h b/include/linux/fmem.h
index d4d5cc7..c9e36b5 100644
--- a/include/linux/fmem.h
+++ b/include/linux/fmem.h
@@ -15,6 +15,8 @@
 #ifndef _FMEM_H_
 #define _FMEM_H_
 
+#include <linux/vmalloc.h>
+
 struct fmem_platform_data {
 	unsigned long phys;
 	unsigned long size;
@@ -23,6 +25,7 @@
 struct fmem_data {
 	unsigned long phys;
 	void *virt;
+	struct vm_struct *area;
 	unsigned long size;
 };
 
@@ -33,9 +36,22 @@
 	FMEM_O_STATE,
 };
 
+#ifdef CONFIG_QCACHE
 struct fmem_data *fmem_get_info(void);
 int fmem_set_state(enum fmem_state);
 void lock_fmem_state(void);
 void unlock_fmem_state(void);
+void *fmem_map_virtual_area(int cacheability);
+void fmem_unmap_virtual_area(void);
+#else
+static inline struct fmem_data *fmem_get_info(void) { return NULL; }
+static inline int fmem_set_state(enum fmem_state f) { return -ENODEV; }
+static inline void lock_fmem_state(void) { return; }
+static inline void unlock_fmem_state(void) { return; }
+static inline void *fmem_map_virtual_area(int cacheability) { return NULL; }
+static inline void fmem_unmap_virtual_area(void) { return; }
+#endif
 
+int request_fmem_c_region(void *unused);
+int release_fmem_c_region(void *unused);
 #endif
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index c425343..d61b934 100644
--- a/include/linux/i2c/atmel_mxt_ts.h
+++ b/include/linux/i2c/atmel_mxt_ts.h
@@ -35,6 +35,9 @@
 	unsigned int y_size;
 	unsigned long irqflags;
 	bool	i2c_pull_up;
+	bool	digital_pwr_regulator;
+	int reset_gpio;
+	int irq_gpio;
 
 	u8(*read_chg) (void);
 	int (*init_hw) (bool);
diff --git a/include/linux/input/pmic8058-keypad.h b/include/linux/input/pmic8058-keypad.h
deleted file mode 100644
index a2fd6ac..0000000
--- a/include/linux/input/pmic8058-keypad.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* Copyright (c) 2009-2010, Code Aurora Forum. 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 version 2 and
- * only 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.
- *
- */
-
-#ifndef __PMIC8058_KEYPAD_H__
-#define __PMIC8058_KEYPAD_H__
-
-#include <linux/input/matrix_keypad.h>
-
-/*
- * NOTE: Assumption of maximum of five revisions
- * of PMIC8058 chip.
- */
-#define MAX_PM8058_REVS		0x5
-
-struct pmic8058_keypad_data {
-	const struct matrix_keymap_data *keymap_data;
-
-	const char *input_name;
-	const char *input_phys_device;
-
-	unsigned int num_cols;
-	unsigned int num_rows;
-
-	unsigned int rows_gpio_start;
-	unsigned int cols_gpio_start;
-
-	unsigned int debounce_ms[MAX_PM8058_REVS];
-	unsigned int scan_delay_ms;
-	unsigned int row_hold_ns;
-
-	int keymap_size;
-	const unsigned int *keymap;
-	
-	unsigned int wakeup;
-	unsigned int rep;
-};
-
-#endif /*__PMIC8058_KEYPAD_H__ */
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index d042e2a..ed1f112 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -53,6 +53,7 @@
 				    unsigned long iova);
 	int (*domain_has_cap)(struct iommu_domain *domain,
 			      unsigned long cap);
+	phys_addr_t (*get_pt_base_addr)(struct iommu_domain *domain);
 };
 
 #ifdef CONFIG_IOMMU_API
@@ -77,6 +78,7 @@
 				      unsigned long iova);
 extern int iommu_domain_has_cap(struct iommu_domain *domain,
 				unsigned long cap);
+extern phys_addr_t iommu_get_pt_base_addr(struct iommu_domain *domain);
 
 #else /* CONFIG_IOMMU_API */
 
@@ -146,6 +148,10 @@
 	return 0;
 }
 
+static inline phys_addr_t iommu_get_pt_base_addr(struct iommu_domain *domain)
+{
+	return 0;
+}
 #endif /* CONFIG_IOMMU_API */
 
 #endif /* __LINUX_IOMMU_H */
diff --git a/include/linux/ion.h b/include/linux/ion.h
index b396369..2cced6d 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -27,8 +27,8 @@
  * @ION_HEAP_TYPE_SYSTEM:	 memory allocated via vmalloc
  * @ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kmalloc
  * @ION_HEAP_TYPE_CARVEOUT:	 memory allocated from a prereserved
- * 				 carveout heap, allocations are physically
- * 				 contiguous
+ *				 carveout heap, allocations are physically
+ *				 contiguous
  * @ION_HEAP_END:		 helper for iterating over heaps
  */
 enum ion_heap_type {
@@ -97,8 +97,8 @@
 /**
  * struct ion_platform_heap - defines a heap in the given platform
  * @type:	type of the heap from ion_heap_type enum
- * @id:		unique identifier for heap.  When allocating (lower numbers 
- * 		will be allocated from first)
+ * @id:		unique identifier for heap.  When allocating (lower numbers
+ *		will be allocated from first)
  * @name:	used for debug purposes
  * @base:	base address of heap in physical memory if applicable
  * @size:	size of the heap in bytes if applicable
@@ -117,8 +117,8 @@
 	ion_phys_addr_t base;
 	size_t size;
 	enum ion_memory_types memory_type;
-	void (*request_region)(void *);
-	void (*release_region)(void *);
+	int (*request_region)(void *);
+	int (*release_region)(void *);
 	void *(*setup_region)(void);
 };
 
@@ -136,8 +136,8 @@
  */
 struct ion_platform_data {
 	int nr;
-	void (*request_region)(void *);
-	void (*release_region)(void *);
+	int (*request_region)(void *);
+	int (*release_region)(void *);
 	void *(*setup_region)(void);
 	struct ion_platform_heap heaps[];
 };
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index e807ad6..99834e58 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -47,6 +47,7 @@
  *            of the irq_domain is responsible for allocating the array of
  *            irq_desc structures.
  * @nr_irq: Number of irqs managed by the irq domain
+ * @hwirq_base: Starting number for hwirqs managed by the irq domain
  * @ops: pointer to irq_domain methods
  * @priv: private data pointer for use by owner.  Not touched by irq_domain
  *        core code.
@@ -57,6 +58,7 @@
 	struct list_head list;
 	unsigned int irq_base;
 	unsigned int nr_irq;
+	unsigned int hwirq_base;
 	const struct irq_domain_ops *ops;
 	void *priv;
 	struct device_node *of_node;
@@ -72,14 +74,27 @@
 static inline unsigned int irq_domain_to_irq(struct irq_domain *d,
 					     unsigned long hwirq)
 {
-	return d->ops->to_irq ? d->ops->to_irq(d, hwirq) : d->irq_base + hwirq;
+	if (d->ops->to_irq)
+		return d->ops->to_irq(d, hwirq);
+	if (WARN_ON(hwirq < d->hwirq_base))
+		return 0;
+	return d->irq_base + hwirq - d->hwirq_base;
 }
 
+#define irq_domain_for_each_hwirq(d, hw) \
+	for (hw = d->hwirq_base; hw < d->hwirq_base + d->nr_irq; hw++)
+
+#define irq_domain_for_each_irq(d, hw, irq) \
+	for (hw = d->hwirq_base, irq = irq_domain_to_irq(d, hw); \
+	     hw < d->hwirq_base + d->nr_irq; \
+	     hw++, irq = irq_domain_to_irq(d, hw))
+
 extern void irq_domain_add(struct irq_domain *domain);
 extern void irq_domain_del(struct irq_domain *domain);
 #endif /* CONFIG_IRQ_DOMAIN */
 
 #if defined(CONFIG_IRQ_DOMAIN) && defined(CONFIG_OF_IRQ)
+extern struct irq_domain_ops irq_domain_simple_ops;
 extern void irq_domain_add_simple(struct device_node *controller, int irq_base);
 extern void irq_domain_generate_simple(const struct of_device_id *match,
 					u64 phys_base, unsigned int irq_start);
diff --git a/include/linux/lglock.h b/include/linux/lglock.h
index f549056..87f402c 100644
--- a/include/linux/lglock.h
+++ b/include/linux/lglock.h
@@ -22,6 +22,7 @@
 #include <linux/spinlock.h>
 #include <linux/lockdep.h>
 #include <linux/percpu.h>
+#include <linux/cpu.h>
 
 /* can make br locks by using local lock for read side, global lock for write */
 #define br_lock_init(name)	name##_lock_init()
@@ -72,9 +73,31 @@
 
 #define DEFINE_LGLOCK(name)						\
 									\
+ DEFINE_SPINLOCK(name##_cpu_lock);					\
+ cpumask_t name##_cpus __read_mostly;					\
  DEFINE_PER_CPU(arch_spinlock_t, name##_lock);				\
  DEFINE_LGLOCK_LOCKDEP(name);						\
 									\
+ static int								\
+ name##_lg_cpu_callback(struct notifier_block *nb,			\
+				unsigned long action, void *hcpu)	\
+ {									\
+	switch (action & ~CPU_TASKS_FROZEN) {				\
+	case CPU_UP_PREPARE:						\
+		spin_lock(&name##_cpu_lock);				\
+		cpu_set((unsigned long)hcpu, name##_cpus);		\
+		spin_unlock(&name##_cpu_lock);				\
+		break;							\
+	case CPU_UP_CANCELED: case CPU_DEAD:				\
+		spin_lock(&name##_cpu_lock);				\
+		cpu_clear((unsigned long)hcpu, name##_cpus);		\
+		spin_unlock(&name##_cpu_lock);				\
+	}								\
+	return NOTIFY_OK;						\
+ }									\
+ static struct notifier_block name##_lg_cpu_notifier = {		\
+	.notifier_call = name##_lg_cpu_callback,			\
+ };									\
  void name##_lock_init(void) {						\
 	int i;								\
 	LOCKDEP_INIT_MAP(&name##_lock_dep_map, #name, &name##_lock_key, 0); \
@@ -83,6 +106,11 @@
 		lock = &per_cpu(name##_lock, i);			\
 		*lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;	\
 	}								\
+	register_hotcpu_notifier(&name##_lg_cpu_notifier);		\
+	get_online_cpus();						\
+	for_each_online_cpu(i)						\
+		cpu_set(i, name##_cpus);				\
+	put_online_cpus();						\
  }									\
  EXPORT_SYMBOL(name##_lock_init);					\
 									\
@@ -124,9 +152,9 @@
 									\
  void name##_global_lock_online(void) {					\
 	int i;								\
-	preempt_disable();						\
+	spin_lock(&name##_cpu_lock);					\
 	rwlock_acquire(&name##_lock_dep_map, 0, 0, _RET_IP_);		\
-	for_each_online_cpu(i) {					\
+	for_each_cpu(i, &name##_cpus) {					\
 		arch_spinlock_t *lock;					\
 		lock = &per_cpu(name##_lock, i);			\
 		arch_spin_lock(lock);					\
@@ -137,12 +165,12 @@
  void name##_global_unlock_online(void) {				\
 	int i;								\
 	rwlock_release(&name##_lock_dep_map, 1, _RET_IP_);		\
-	for_each_online_cpu(i) {					\
+	for_each_cpu(i, &name##_cpus) {					\
 		arch_spinlock_t *lock;					\
 		lock = &per_cpu(name##_lock, i);			\
 		arch_spin_unlock(lock);					\
 	}								\
-	preempt_enable();						\
+	spin_unlock(&name##_cpu_lock);					\
  }									\
  EXPORT_SYMBOL(name##_global_unlock_online);				\
 									\
diff --git a/include/linux/mfd/pm8xxx/pm8018.h b/include/linux/mfd/pm8xxx/pm8018.h
index 1093409..e0ec0b4 100644
--- a/include/linux/mfd/pm8xxx/pm8018.h
+++ b/include/linux/mfd/pm8xxx/pm8018.h
@@ -25,7 +25,7 @@
 #include <linux/mfd/pm8xxx/rtc.h>
 #include <linux/input/pmic8xxx-pwrkey.h>
 #include <linux/mfd/pm8xxx/misc.h>
-#include <linux/regulator/pm8018-regulator.h>
+#include <linux/regulator/pm8xxx-regulator.h>
 #include <linux/mfd/pm8xxx/pm8xxx-adc.h>
 #include <linux/mfd/pm8xxx/pwm.h>
 #include <linux/leds-pm8xxx.h>
@@ -64,7 +64,7 @@
 	struct pm8xxx_rtc_platform_data         *rtc_pdata;
 	struct pm8xxx_pwrkey_platform_data	*pwrkey_pdata;
 	struct pm8xxx_misc_platform_data	*misc_pdata;
-	struct pm8018_regulator_platform_data	*regulator_pdatas;
+	struct pm8xxx_regulator_platform_data	*regulator_pdatas;
 	struct pm8xxx_adc_platform_data		*adc_pdata;
 	int					num_regulators;
 	struct pm8xxx_led_platform_data		*leds_pdata;
diff --git a/include/linux/mfd/pm8xxx/pm8038.h b/include/linux/mfd/pm8xxx/pm8038.h
index 2c2bb09..caed75c 100644
--- a/include/linux/mfd/pm8xxx/pm8038.h
+++ b/include/linux/mfd/pm8xxx/pm8038.h
@@ -26,6 +26,7 @@
 #include <linux/mfd/pm8xxx/rtc.h>
 #include <linux/input/pmic8xxx-pwrkey.h>
 #include <linux/mfd/pm8xxx/misc.h>
+#include <linux/regulator/pm8xxx-regulator.h>
 
 #define PM8038_CORE_DEV_NAME "pm8038-core"
 
@@ -62,6 +63,8 @@
 	struct pm8xxx_rtc_platform_data         *rtc_pdata;
 	struct pm8xxx_pwrkey_platform_data	*pwrkey_pdata;
 	struct pm8xxx_misc_platform_data	*misc_pdata;
+	struct pm8xxx_regulator_platform_data	*regulator_pdatas;
+	int					num_regulators;
 };
 
 #endif
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index 31fa537..eb1005c 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -33,6 +33,20 @@
 	PM_SMBC_BATT_TEMP_HOT_THR__HIGH
 };
 
+enum pm8921_usb_ov_threshold {
+	PM_USB_OV_5P5V,
+	PM_USB_OV_6V,
+	PM_USB_OV_6P5V,
+	PM_USB_OV_7V,
+};
+
+enum pm8921_usb_debounce_time {
+	PM_USB_BYPASS_DEBOUNCER,
+	PM_USB_DEBOUNCE_20P5MS,
+	PM_USB_DEBOUNCE_40P5MS,
+	PM_USB_DEBOUNCE_80P5MS,
+};
+
 /**
  * struct pm8921_charger_platform_data -
  * @safety_time:	max charging time in minutes incl. fast and trkl
@@ -247,6 +261,31 @@
  */
 void unregister_external_dc_charger(struct ext_chg_pm8921 *ext);
 
+/**
+ * pm8921_usb_ovp_set_threshold -
+ * Set the usb threshold as defined in by
+ * enum usb_ov_threshold
+ */
+int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov);
+
+/**
+ * pm8921_usb_ovp_set_hystersis -
+ * @ms: the debounce time enum
+ *
+ * Sets the debounce time for usb insertion/removal detection
+ *
+ */
+int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms);
+
+/**
+ * pm8921_usb_ovp_disable -
+ *
+ * when disabled there is no over voltage protection. The usb voltage is
+ * fed to the pmic as is. This should be disabled only when there is
+ * over voltage protection circuitry present outside the pmic chip.
+ *
+ */
+int pm8921_usb_ovp_disable(int disable);
 #else
 static inline void pm8921_charger_vbus_draw(unsigned int mA)
 {
@@ -308,6 +347,18 @@
 {
 	pr_err("%s.not implemented.\n", __func__);
 }
+static inline int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
+{
+	return -ENXIO;
+}
+static inline int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms)
+{
+	return -ENXIO;
+}
+static inline int pm8921_usb_ovp_disable(int disable)
+{
+	return -ENXIO;
+}
 #endif
 
 #endif
diff --git a/include/linux/mfd/pm8xxx/pm8921.h b/include/linux/mfd/pm8xxx/pm8921.h
index d4cdc3c..35792d5 100644
--- a/include/linux/mfd/pm8xxx/pm8921.h
+++ b/include/linux/mfd/pm8xxx/pm8921.h
@@ -29,7 +29,7 @@
 #include <linux/mfd/pm8xxx/batt-alarm.h>
 #include <linux/input/pmic8xxx-pwrkey.h>
 #include <linux/input/pmic8xxx-keypad.h>
-#include <linux/regulator/pm8921-regulator.h>
+#include <linux/regulator/pm8xxx-regulator.h>
 #include <linux/mfd/pm8xxx/pm8921-charger.h>
 #include <linux/mfd/pm8xxx/pm8xxx-adc.h>
 #include <linux/mfd/pm8xxx/pm8921-bms.h>
@@ -124,7 +124,7 @@
 	struct pm8921_charger_platform_data	*charger_pdata;
 	struct pm8921_bms_platform_data		*bms_pdata;
 	struct pm8xxx_misc_platform_data	*misc_pdata;
-	struct pm8921_regulator_platform_data	*regulator_pdatas;
+	struct pm8xxx_regulator_platform_data	*regulator_pdatas;
 	int					num_regulators;
 	struct pm8xxx_adc_platform_data		*adc_pdata;
 	struct pm8xxx_led_platform_data		*leds_pdata;
diff --git a/include/linux/mfd/pm8xxx/regulator.h b/include/linux/mfd/pm8xxx/regulator.h
new file mode 100644
index 0000000..38700cb
--- /dev/null
+++ b/include/linux/mfd/pm8xxx/regulator.h
@@ -0,0 +1,258 @@
+/* Copyright (c) 2011, Code Aurora Forum. 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 version 2 and
+ * only 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.
+ */
+
+#ifndef __MFD_PM8XXX_REGULATOR_H__
+#define __MFD_PM8XXX_REGULATOR_H__
+
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/pm8xxx-regulator.h>
+
+/**
+ * enum pm8xxx_regulator_type - possible PM8XXX voltage regulator types
+ * %PM8XXX_REGULATOR_TYPE_PLDO:		PMOS low drop-out linear regulator
+ * %PM8XXX_REGULATOR_TYPE_NLDO:		NMOS low drop-out linear regulator
+ * %PM8XXX_REGULATOR_TYPE_NLDO1200:	NMOS low drop-out linear regulator
+ *					capable of supplying up to 1200 mA
+ * %PM8XXX_REGULATOR_TYPE_SMPS:		switched-mode power supply (buck)
+ * %PM8XXX_REGULATOR_TYPE_FTSMPS:	fast transient switched-mode power
+ *					supply (buck)
+ * %PM8XXX_REGULATOR_TYPE_VS:		voltage switch capable of sourcing 100mA
+ * %PM8XXX_REGULATOR_TYPE_VS300:	voltage switch capable of sourcing 300mA
+ * %PM8XXX_REGULATOR_TYPE_NCP:		negative charge pump
+ * %PM8XXX_REGULATOR_TYPE_MAX:		used internally for error checking; not
+ *					a valid regulator type.
+ *
+ * Each of these has a different register control interface.
+ */
+enum pm8xxx_regulator_type {
+	PM8XXX_REGULATOR_TYPE_PLDO,
+	PM8XXX_REGULATOR_TYPE_NLDO,
+	PM8XXX_REGULATOR_TYPE_NLDO1200,
+	PM8XXX_REGULATOR_TYPE_SMPS,
+	PM8XXX_REGULATOR_TYPE_FTSMPS,
+	PM8XXX_REGULATOR_TYPE_VS,
+	PM8XXX_REGULATOR_TYPE_VS300,
+	PM8XXX_REGULATOR_TYPE_NCP,
+	PM8XXX_REGULATOR_TYPE_MAX,
+};
+
+/**
+ * struct pm8xxx_vreg - regulator configuration and state data used by the
+ *		pm8xxx-regulator driver
+ * @rdesc:		regulator description
+ * @rdesc_pc:		pin control regulator description. rdesc_pc.name == NULL
+ *			implies that there is no pin control version of this
+ *			regulator.
+ * @type:		regulator type
+ * @hpm_min_load:	minimum load in uA that will result in the regulator
+ *			being set to high power mode
+ * @ctrl_addr:		control register SSBI address
+ * @test_addr:		test register SSBI address (not needed for all types)
+ * @clk_ctrl_addr:	clock control register SSBI address (only used by SMPS
+ *			type regulators)
+ * @sleep_ctrl_addr:	sleep control register SSBI address (only used by SMPS
+ *			type regulators)
+ * @pfm_ctrl_addr:	pulse-frequency modulation control register SSBI address
+ *			(only used by FTSMPS type regulators)
+ * @pwr_cnfg_addr:	power configuration register SSBI address (only used by
+ *			FTSMPS type regulators)
+ * @pdata:		this platform data struct is filled based using the
+ *			platform data pointed to in a core platform data struct
+ * @rdev:		pointer to regulator device which is created with
+ *			regulator_register
+ * @rdev_pc:		pointer to pin controlled regulator device which is
+ *			created with regulator_register
+ * @dev:		pointer to pm8xxx-regulator device
+ * @dev_pc:		pointer to pin control pm8xxx-regulator device
+ * @pc_lock:		mutex lock to handle sharing between pin controlled and
+ *			non-pin controlled versions of a given regulator.  Note,
+ *			this lock must be initialized in the PMIC core driver.)
+ * @save_uV:		current regulator voltage in uV
+ * @mode:		current mode of the regulator
+ * @write_count:	number of SSBI writes that have taken place for this
+ *			regulator. This is used for debug printing to determine
+ *			if a given operation is redundant.
+ * @prev_write_count:	number of SSBI writes that have taken place for this
+ *			regulator at the start of an operation. This is used for
+ *			debug printing to determine if a given operation is
+ *			redundant.
+ * @is_enabled:		true if the regulator is currently enabled, false if not
+ * @is_enabled_pc:	true if the pin controlled version of the regulator is
+ *			currently enabled (i.e. pin control is active), false if
+ *			not
+ * @test_reg:		last value read from or written to each of the banks of
+ *			the test register
+ * @ctrl_reg:		last value read from or written to the control register
+ * @clk_ctrl_reg:	last value read from or written to the clock control
+ *			register
+ * @sleep_ctrl_reg:	last value read from or written to the sleep control
+ *			register
+ * @pfm_ctrl_reg:	last value read from or written to the PFM control
+ *			register
+ * @pwr_cnfg_reg:	last value read from or written to the power
+ *			configuration register
+ *
+ * This data structure should only need to be instantiated in a PMIC core driver
+ * It is used to specify PMIC specific as opposed to board specific
+ * configuration data.  It is also used to hold all state variables needed by
+ * the pm8xxx-regulator driver as these variables need to be shared between
+ * pin controlled and non-pin controlled versions of a given regulator, which
+ * are probed separately.
+ */
+struct pm8xxx_vreg {
+	/* Configuration data */
+	struct regulator_desc			rdesc;
+	struct regulator_desc			rdesc_pc;
+	enum pm8xxx_regulator_type		type;
+	const int				hpm_min_load;
+	const u16				ctrl_addr;
+	const u16				test_addr;
+	const u16				clk_ctrl_addr;
+	const u16				sleep_ctrl_addr;
+	const u16				pfm_ctrl_addr;
+	const u16				pwr_cnfg_addr;
+	/* State data */
+	struct pm8xxx_regulator_platform_data	pdata;
+	struct regulator_dev			*rdev;
+	struct regulator_dev			*rdev_pc;
+	struct device				*dev;
+	struct device				*dev_pc;
+	struct mutex				pc_lock;
+	int					save_uV;
+	int					mode;
+	u32					write_count;
+	u32					prev_write_count;
+	bool					is_enabled;
+	bool					is_enabled_pc;
+	u8				test_reg[REGULATOR_TEST_BANKS_MAX];
+	u8					ctrl_reg;
+	u8					clk_ctrl_reg;
+	u8					sleep_ctrl_reg;
+	u8					pfm_ctrl_reg;
+	u8					pwr_cnfg_reg;
+};
+
+/**
+ * struct pm8xxx_regulator_core_platform_data - platform data specified in a
+ *		PMIC core driver and utilized in the pm8xxx-regulator driver
+* @vreg:		pointer to pm8xxx_vreg data structure that may be shared
+*			between pin controlled and non-pin controlled versions
+*			of a given regulator.  Note that this data must persist
+*			as long as the regulator device is in use.
+* @pdata:		pointer to platform data passed in from a board file
+* @is_pin_controlled:	true if the regulator driver represents the pin control
+*			portion of a regulator, false if not.
+*
+* This data structure should only be needed in a PMIC core driver.
+*/
+struct pm8xxx_regulator_core_platform_data {
+	struct pm8xxx_vreg			*vreg;
+	struct pm8xxx_regulator_platform_data	*pdata;
+	bool					is_pin_controlled;
+};
+
+/* Helper macros */
+#define PLDO(_name, _pc_name, _ctrl_addr, _test_addr, _hpm_min_load) \
+	{ \
+		.type		= PM8XXX_REGULATOR_TYPE_PLDO, \
+		.ctrl_addr	= _ctrl_addr, \
+		.test_addr	= _test_addr, \
+		.hpm_min_load	= PM8XXX_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
+		.rdesc.name	= _name, \
+		.rdesc_pc.name	= _pc_name, \
+		.write_count	= 0, \
+		.prev_write_count = -1, \
+	}
+
+#define NLDO(_name, _pc_name, _ctrl_addr, _test_addr, _hpm_min_load) \
+	{ \
+		.type		= PM8XXX_REGULATOR_TYPE_NLDO, \
+		.ctrl_addr	= _ctrl_addr, \
+		.test_addr	= _test_addr, \
+		.hpm_min_load	= PM8XXX_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
+		.rdesc.name	= _name, \
+		.rdesc_pc.name	= _pc_name, \
+		.write_count	= 0, \
+		.prev_write_count = -1, \
+	}
+
+#define NLDO1200(_name, _ctrl_addr, _test_addr, _hpm_min_load) \
+	{ \
+		.type		= PM8XXX_REGULATOR_TYPE_NLDO1200, \
+		.ctrl_addr	= _ctrl_addr, \
+		.test_addr	= _test_addr, \
+		.hpm_min_load	= PM8XXX_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
+		.rdesc.name	= _name, \
+		.write_count	= 0, \
+		.prev_write_count = -1, \
+	}
+
+#define SMPS(_name, _pc_name, _ctrl_addr, _test_addr, _clk_ctrl_addr, \
+	     _sleep_ctrl_addr, _hpm_min_load) \
+	{ \
+		.type		= PM8XXX_REGULATOR_TYPE_SMPS, \
+		.ctrl_addr	= _ctrl_addr, \
+		.test_addr	= _test_addr, \
+		.clk_ctrl_addr	= _clk_ctrl_addr, \
+		.sleep_ctrl_addr = _sleep_ctrl_addr, \
+		.hpm_min_load	= PM8XXX_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
+		.rdesc.name	= _name, \
+		.rdesc_pc.name	= _pc_name, \
+		.write_count	= 0, \
+		.prev_write_count = -1, \
+	}
+
+#define FTSMPS(_name, _pwm_ctrl_addr, _fts_cnfg1_addr, _pfm_ctrl_addr, \
+	       _pwr_cnfg_addr, _hpm_min_load) \
+	{ \
+		.type		= PM8XXX_REGULATOR_TYPE_FTSMPS, \
+		.ctrl_addr	= _pwm_ctrl_addr, \
+		.test_addr	= _fts_cnfg1_addr, \
+		.pfm_ctrl_addr = _pfm_ctrl_addr, \
+		.pwr_cnfg_addr = _pwr_cnfg_addr, \
+		.hpm_min_load	= PM8XXX_VREG_##_hpm_min_load##_HPM_MIN_LOAD, \
+		.rdesc.name	= _name, \
+		.write_count	= 0, \
+		.prev_write_count = -1, \
+	}
+
+#define VS(_name, _pc_name, _ctrl_addr) \
+	{ \
+		.type		= PM8XXX_REGULATOR_TYPE_VS, \
+		.ctrl_addr	= _ctrl_addr, \
+		.rdesc.name	= _name, \
+		.rdesc_pc.name	= _pc_name, \
+		.write_count	= 0, \
+		.prev_write_count = -1, \
+	}
+
+#define VS300(_name, _ctrl_addr) \
+	{ \
+		.type		= PM8XXX_REGULATOR_TYPE_VS300, \
+		.ctrl_addr	= _ctrl_addr, \
+		.rdesc.name	= _name, \
+		.write_count	= 0, \
+		.prev_write_count = -1, \
+	}
+
+#define NCP(_name, _ctrl_addr) \
+	{ \
+		.type		= PM8XXX_REGULATOR_TYPE_NCP, \
+		.ctrl_addr	= _ctrl_addr, \
+		.rdesc.name	= _name, \
+		.write_count	= 0, \
+		.prev_write_count = -1, \
+	}
+
+#endif
diff --git a/include/linux/mfd/pmic8058.h b/include/linux/mfd/pmic8058.h
index 0699c46..ff7a329 100644
--- a/include/linux/mfd/pmic8058.h
+++ b/include/linux/mfd/pmic8058.h
@@ -108,20 +108,6 @@
 	bool charger_data_valid;
 };
 
-enum pon_config{
-	DISABLE_HARD_RESET = 0,
-	SHUTDOWN_ON_HARD_RESET,
-	RESTART_ON_HARD_RESET,
-	MAX_PON_CONFIG,
-};
-
-enum pm8058_smpl_delay {
-	PM8058_SMPL_DELAY_0p5,
-	PM8058_SMPL_DELAY_1p0,
-	PM8058_SMPL_DELAY_1p5,
-	PM8058_SMPL_DELAY_2p0,
-};
-
 struct pm8058_platform_data {
 	struct pm8xxx_mpp_platform_data		*mpp_pdata;
 	struct pm8xxx_keypad_platform_data      *keypad_pdata;
@@ -144,19 +130,4 @@
 	struct pmic8058_charger_data		*charger_pdata;
 };
 
-int pm8058_hard_reset_config(enum pon_config config);
-
-/**
- * pm8058_stay_on - enables stay_on feature
- *
- * PMIC stay-on feature allows PMIC to ignore MSM PS_HOLD=low
- * signal so that some special functions like debugging could be
- * performed.
- *
- * This feature should not be used in any product release.
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_stay_on(void);
-
 #endif  /* __MFD_PMIC8058_H__ */
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 29f5a63..9e82abf8 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -177,6 +177,7 @@
 #define MMC_STATE_HIGHSPEED_DDR (1<<4)		/* card is in high speed mode */
 #define MMC_STATE_ULTRAHIGHSPEED (1<<5)		/* card is in ultra high speed mode */
 #define MMC_CARD_SDXC		(1<<6)		/* card is SDXC */
+#define MMC_CARD_REMOVED	(1<<7)		/* card has been removed */
 	unsigned int		quirks; 	/* card quirks */
 #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)	/* use func->cur_blksize */
@@ -314,6 +315,7 @@
 #define mmc_card_ddr_mode(c)	((c)->state & MMC_STATE_HIGHSPEED_DDR)
 #define mmc_sd_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
+#define mmc_card_removed(c)	((c) && ((c)->state & MMC_CARD_REMOVED))
 
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
@@ -322,6 +324,7 @@
 #define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
 #define mmc_sd_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
 #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
+#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
 
 /*
  * Quirk add/remove for MMC products.
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index b6718e5..279c023 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -166,6 +166,8 @@
 extern void mmc_do_release_host(struct mmc_host *host);
 extern int mmc_try_claim_host(struct mmc_host *host);
 
+extern int mmc_detect_card_removed(struct mmc_host *host);
+
 /**
  *	mmc_claim_host - exclusively claim a host
  *	@host: mmc host to claim
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index d1f478b..d90c779 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -266,6 +266,7 @@
 
 	struct delayed_work	detect;
 	struct wake_lock	detect_wake_lock;
+	int                     detect_change;  /* card detect flag */
 
 	const struct mmc_bus_ops *bus_ops;	/* current bus driver */
 	unsigned int		bus_refs;	/* reference counter */
diff --git a/include/linux/module.h b/include/linux/module.h
index d9ca2d5..e91cc65 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -16,6 +16,7 @@
 #include <linux/kobject.h>
 #include <linux/moduleparam.h>
 #include <linux/tracepoint.h>
+#include <linux/export.h>
 
 #include <linux/percpu.h>
 #include <asm/module.h>
@@ -25,21 +26,8 @@
 /* Not Yet Implemented */
 #define MODULE_SUPPORTED_DEVICE(name)
 
-/* Some toolchains use a `_' prefix for all user symbols. */
-#ifdef CONFIG_SYMBOL_PREFIX
-#define MODULE_SYMBOL_PREFIX CONFIG_SYMBOL_PREFIX
-#else
-#define MODULE_SYMBOL_PREFIX ""
-#endif
-
 #define MODULE_NAME_LEN MAX_PARAM_PREFIX_LEN
 
-struct kernel_symbol
-{
-	unsigned long value;
-	const char *name;
-};
-
 struct modversion_info
 {
 	unsigned long crc;
@@ -96,11 +84,8 @@
 extern const struct gtype##_id __mod_##gtype##_table		\
   __attribute__ ((unused, alias(__stringify(name))))
 
-extern struct module __this_module;
-#define THIS_MODULE (&__this_module)
 #else  /* !MODULE */
 #define MODULE_GENERIC_TABLE(gtype,name)
-#define THIS_MODULE ((struct module *)0)
 #endif
 
 /* Generic info of form tag = "info" */
@@ -216,52 +201,6 @@
 	struct module *source, *target;
 };
 
-#ifndef __GENKSYMS__
-#ifdef CONFIG_MODVERSIONS
-/* Mark the CRC weak since genksyms apparently decides not to
- * generate a checksums for some symbols */
-#define __CRC_SYMBOL(sym, sec)					\
-	extern void *__crc_##sym __attribute__((weak));		\
-	static const unsigned long __kcrctab_##sym		\
-	__used							\
-	__attribute__((section("___kcrctab" sec "+" #sym), unused))	\
-	= (unsigned long) &__crc_##sym;
-#else
-#define __CRC_SYMBOL(sym, sec)
-#endif
-
-/* For every exported symbol, place a struct in the __ksymtab section */
-#define __EXPORT_SYMBOL(sym, sec)				\
-	extern typeof(sym) sym;					\
-	__CRC_SYMBOL(sym, sec)					\
-	static const char __kstrtab_##sym[]			\
-	__attribute__((section("__ksymtab_strings"), aligned(1))) \
-	= MODULE_SYMBOL_PREFIX #sym;                    	\
-	static const struct kernel_symbol __ksymtab_##sym	\
-	__used							\
-	__attribute__((section("___ksymtab" sec "+" #sym), unused))	\
-	= { (unsigned long)&sym, __kstrtab_##sym }
-
-#define EXPORT_SYMBOL(sym)					\
-	__EXPORT_SYMBOL(sym, "")
-
-#define EXPORT_SYMBOL_GPL(sym)					\
-	__EXPORT_SYMBOL(sym, "_gpl")
-
-#define EXPORT_SYMBOL_GPL_FUTURE(sym)				\
-	__EXPORT_SYMBOL(sym, "_gpl_future")
-
-
-#ifdef CONFIG_UNUSED_SYMBOLS
-#define EXPORT_UNUSED_SYMBOL(sym) __EXPORT_SYMBOL(sym, "_unused")
-#define EXPORT_UNUSED_SYMBOL_GPL(sym) __EXPORT_SYMBOL(sym, "_unused_gpl")
-#else
-#define EXPORT_UNUSED_SYMBOL(sym)
-#define EXPORT_UNUSED_SYMBOL_GPL(sym)
-#endif
-
-#endif
-
 enum module_state
 {
 	MODULE_STATE_LIVE,
@@ -582,11 +521,6 @@
 extern int module_get_iter_tracepoints(struct tracepoint_iter *iter);
 
 #else /* !CONFIG_MODULES... */
-#define EXPORT_SYMBOL(sym)
-#define EXPORT_SYMBOL_GPL(sym)
-#define EXPORT_SYMBOL_GPL_FUTURE(sym)
-#define EXPORT_UNUSED_SYMBOL(sym)
-#define EXPORT_UNUSED_SYMBOL_GPL(sym)
 
 /* Given an address, look for it in the exception tables. */
 static inline const struct exception_table_entry *
diff --git a/include/linux/msm_rotator.h b/include/linux/msm_rotator.h
index 611d7b4..72809cf 100644
--- a/include/linux/msm_rotator.h
+++ b/include/linux/msm_rotator.h
@@ -30,6 +30,7 @@
 	unsigned int    dst_y;
 	unsigned char   rotations;
 	int enable;
+	unsigned int	downscale_ratio;
 };
 
 struct msm_rotator_data_info {
diff --git a/include/linux/msm_vidc_enc.h b/include/linux/msm_vidc_enc.h
index 45199cb..1f264e9 100644
--- a/include/linux/msm_vidc_enc.h
+++ b/include/linux/msm_vidc_enc.h
@@ -92,16 +92,17 @@
 #define VEN_LEVEL_H264_2p2	0x10/* H.264 Level 2.2 */
 #define VEN_LEVEL_H264_3	0x11/* H.264 Level 3   */
 #define VEN_LEVEL_H264_3p1	0x12/* H.264 Level 3.1 */
-#define VEN_LEVEL_H264_4	0x13/* H.264 Level 4   */
+#define VEN_LEVEL_H264_3p2	0x13/* H.264 Level 3.2 */
+#define VEN_LEVEL_H264_4	0x14/* H.264 Level 4   */
 
-#define VEN_LEVEL_H263_10	0x14/* H.263 Level 10  */
-#define VEN_LEVEL_H263_20	0x15/* H.263 Level 20  */
-#define VEN_LEVEL_H263_30	0x16/* H.263 Level 30  */
-#define VEN_LEVEL_H263_40	0x17/* H.263 Level 40  */
-#define VEN_LEVEL_H263_45	0x18/* H.263 Level 45  */
-#define VEN_LEVEL_H263_50	0x19/* H.263 Level 50  */
-#define VEN_LEVEL_H263_60	0x1A/* H.263 Level 60  */
-#define VEN_LEVEL_H263_70	0x1B/* H.263 Level 70  */
+#define VEN_LEVEL_H263_10	0x15/* H.263 Level 10  */
+#define VEN_LEVEL_H263_20	0x16/* H.263 Level 20  */
+#define VEN_LEVEL_H263_30	0x17/* H.263 Level 30  */
+#define VEN_LEVEL_H263_40	0x18/* H.263 Level 40  */
+#define VEN_LEVEL_H263_45	0x19/* H.263 Level 45  */
+#define VEN_LEVEL_H263_50	0x1A/* H.263 Level 50  */
+#define VEN_LEVEL_H263_60	0x1B/* H.263 Level 60  */
+#define VEN_LEVEL_H263_70	0x1C/* H.263 Level 70  */
 
 /*Entropy coding model selection for H.264 encoder.*/
 #define VEN_ENTROPY_MODEL_CAVLC	1
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index c7ccaae..70fe6cab 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -161,6 +161,13 @@
  * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface
  *	using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD,
  *	%NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL attributes.
+ *	Following attributes are provided for drivers that generate full Beacon
+ *	and Probe Response frames internally: %NL80211_ATTR_SSID,
+ *	%NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE,
+ *	%NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS,
+ *	%NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY,
+ *	%NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_IE, %NL80211_ATTR_IE_PROBE_RESP,
+ *	%NL80211_ATTR_IE_ASSOC_RESP.
  * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface,
  *	parameters are like for %NL80211_CMD_SET_BEACON.
  * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
@@ -745,8 +752,12 @@
  *
  * @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with
  *	a single scan request, a wiphy attribute.
+ * @NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS: number of SSIDs you can
+ *	scan with a single scheduled scan request, a wiphy attribute.
  * @NL80211_ATTR_MAX_SCAN_IE_LEN: maximum length of information elements
  *	that can be added to a scan request
+ * @NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN: maximum length of information
+ *	elements that can be added to a scheduled scan request
  *
  * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz)
  * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive
@@ -827,18 +838,20 @@
  * @NL80211_ATTR_STATUS_CODE: StatusCode for the %NL80211_CMD_CONNECT
  *	event (u16)
  * @NL80211_ATTR_PRIVACY: Flag attribute, used with connect(), indicating
- *	that protected APs should be used.
+ *	that protected APs should be used. This is also used with NEW_BEACON to
+ *	indicate that the BSS is to use protection.
  *
- * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT and ASSOCIATE to
- *	indicate which unicast key ciphers will be used with the connection
+ * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT, ASSOCIATE, and NEW_BEACON
+ *	to indicate which unicast key ciphers will be used with the connection
  *	(an array of u32).
- * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT and ASSOCIATE to indicate
- *	which group key cipher will be used with the connection (a u32).
- * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT and ASSOCIATE to indicate
- *	which WPA version(s) the AP we want to associate with is using
+ * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
+ *	indicate which group key cipher will be used with the connection (a
+ *	u32).
+ * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
+ *	indicate which WPA version(s) the AP we want to associate with is using
  *	(a u32 with flags from &enum nl80211_wpa_versions).
- * @NL80211_ATTR_AKM_SUITES: Used with CONNECT and ASSOCIATE to indicate
- *	which key management algorithm(s) to use (an array of u32).
+ * @NL80211_ATTR_AKM_SUITES: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
+ *	indicate which key management algorithm(s) to use (an array of u32).
  *
  * @NL80211_ATTR_REQ_IE: (Re)association request information elements as
  *	sent out by the card, for ROAM and successful CONNECT events.
@@ -996,6 +1009,29 @@
  *	are managed in software: interfaces of these types aren't subject to
  *	any restrictions in their number or combinations.
  *
+ * @%NL80211_ATTR_REKEY_DATA: nested attribute containing the information
+ *	necessary for GTK rekeying in the device, see &enum nl80211_rekey_data.
+ *
+ * @NL80211_ATTR_SCAN_SUPP_RATES: rates per to be advertised as supported in
+ *	scan, nested array attribute containing an entry for each band, with
+ *	the entry being a list of supported rates as defined by IEEE 802.11
+ *	7.3.2.2 but without the length restriction
+ *	(at most %NL80211_MAX_SUPP_RATES).
+ *
+ * @NL80211_ATTR_HIDDEN_SSID: indicates whether SSID is to be hidden from Beacon
+ *	and Probe Response (when response to wildcard Probe Request); see
+ *	&enum nl80211_hidden_ssid, represented as a u32
+ *
+ * @NL80211_ATTR_IE_PROBE_RESP: Information element(s) for Probe Response frame.
+ *	This is used with %NL80211_CMD_NEW_BEACON and %NL80211_CMD_SET_BEACON to
+ *	provide extra IEs (e.g., WPS/P2P IE) into Probe Response frames when the
+ *	driver (or firmware) replies to Probe Request frames.
+ * @NL80211_ATTR_IE_ASSOC_RESP: Information element(s) for (Re)Association
+ *	Response frames. This is used with %NL80211_CMD_NEW_BEACON and
+ *	%NL80211_CMD_SET_BEACON to provide extra IEs (e.g., WPS/P2P IE) into
+ *	(Re)Association Response frames when the driver (or firmware) replies to
+ *	(Re)Association Request frames.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1194,6 +1230,18 @@
 	NL80211_ATTR_INTERFACE_COMBINATIONS,
 	NL80211_ATTR_SOFTWARE_IFTYPES,
 
+	NL80211_ATTR_REKEY_DATA,
+
+	NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
+	NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
+
+	NL80211_ATTR_SCAN_SUPP_RATES,
+
+	NL80211_ATTR_HIDDEN_SSID,
+
+	NL80211_ATTR_IE_PROBE_RESP,
+	NL80211_ATTR_IE_ASSOC_RESP,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -2361,4 +2409,19 @@
 	MAX_NL80211_PLINK_STATES = NUM_NL80211_PLINK_STATES - 1
 };
 
+/**
+ * enum nl80211_hidden_ssid - values for %NL80211_ATTR_HIDDEN_SSID
+ * @NL80211_HIDDEN_SSID_NOT_IN_USE: do not hide SSID (i.e., broadcast it in
+ *	Beacon frames)
+ * @NL80211_HIDDEN_SSID_ZERO_LEN: hide SSID by using zero-length SSID element
+ *	in Beacon frames
+ * @NL80211_HIDDEN_SSID_ZERO_CONTENTS: hide SSID by using correct length of SSID
+ *	element in Beacon frames but zero out each byte in the SSID
+ */
+enum nl80211_hidden_ssid {
+	NL80211_HIDDEN_SSID_NOT_IN_USE,
+	NL80211_HIDDEN_SSID_ZERO_LEN,
+	NL80211_HIDDEN_SSID_ZERO_CONTENTS
+};
+
 #endif /* __LINUX_NL80211_H */
diff --git a/include/linux/platform_data/qcom_crypto_device.h b/include/linux/platform_data/qcom_crypto_device.h
index c6ef40a..08aa784 100644
--- a/include/linux/platform_data/qcom_crypto_device.h
+++ b/include/linux/platform_data/qcom_crypto_device.h
@@ -18,6 +18,7 @@
 	uint32_t shared_ce_resource;
 	uint32_t hw_key_support;
 	uint32_t sha_hmac;
+	void *bus_scale_table;
 };
 
 #endif /* __QCOM_CRYPTO_DEVICE__H */
diff --git a/include/linux/pmic8058-batt-alarm.h b/include/linux/pmic8058-batt-alarm.h
deleted file mode 100644
index 0a0ac78..0000000
--- a/include/linux/pmic8058-batt-alarm.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. 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 version 2 and
- * only 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.
- */
-/*
- * Qualcomm PMIC 8058 Battery Alarm Device driver
- *
- */
-#ifndef __PMIC8058_BATT_ALARM_H__
-#define __PMIC8058_BATT_ALARM_H__
-
-#include <linux/bitops.h>
-
-/**
- * enum pm8058_batt_alarm_hold_time - hold time required for out of range
- *	battery voltage needed to trigger a status change.  Enum names denote
- *	hold time in milliseconds.
- */
-enum pm8058_batt_alarm_hold_time {
-	PM8058_BATT_ALARM_HOLD_TIME_0p125_MS = 0,
-	PM8058_BATT_ALARM_HOLD_TIME_0p25_MS,
-	PM8058_BATT_ALARM_HOLD_TIME_0p5_MS,
-	PM8058_BATT_ALARM_HOLD_TIME_1_MS,
-	PM8058_BATT_ALARM_HOLD_TIME_2_MS,
-	PM8058_BATT_ALARM_HOLD_TIME_4_MS,
-	PM8058_BATT_ALARM_HOLD_TIME_8_MS,
-	PM8058_BATT_ALARM_HOLD_TIME_16_MS,
-};
-
-/*
- * Bits that are set in the return value of pm8058_batt_alarm_status_read
- * to indicate crossing of the upper or lower threshold.
- */
-#define PM8058_BATT_ALARM_STATUS_BELOW_LOWER	BIT(0)
-#define PM8058_BATT_ALARM_STATUS_ABOVE_UPPER	BIT(1)
-
-/**
- * pm8058_batt_alarm_state_set - enable or disable the threshold comparators
- * @enable_lower_comparator: 1 = enable comparator, 0 = disable comparator
- * @enable_upper_comparator: 1 = enable comparator, 0 = disable comparator
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_batt_alarm_state_set(int enable_lower_comparator,
-				int enable_upper_comparator);
-
-/**
- * pm8058_batt_alarm_threshold_set - set the lower and upper alarm thresholds
- * @lower_threshold_mV: battery undervoltage threshold in millivolts
- * @upper_threshold_mV: battery overvoltage threshold in millivolts
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_batt_alarm_threshold_set(int lower_threshold_mV,
-				    int upper_threshold_mV);
-
-/**
- * pm8058_batt_alarm_status_read - get status of both threshold comparators
- *
- * RETURNS:	< 0	   = error
- *		  0	   = battery voltage ok
- *		BIT(0) set = battery voltage below lower threshold
- *		BIT(1) set = battery voltage above upper threshold
- */
-int pm8058_batt_alarm_status_read(void);
-
-/**
- * pm8058_batt_alarm_register_notifier - register a notifier to run when a
- *	battery voltage change interrupt fires
- * @nb:	notifier block containing callback function to register
- *
- * nb->notifier_call must point to a function of this form -
- * int (*notifier_call)(struct notifier_block *nb, unsigned long status,
- *			void *unused);
- * "status" will receive the battery alarm status; "unused" will be NULL.
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_batt_alarm_register_notifier(struct notifier_block *nb);
-
-/**
- * pm8058_batt_alarm_unregister_notifier - unregister a notifier that is run
- *	when a battery voltage change interrupt fires
- * @nb:	notifier block containing callback function to unregister
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_batt_alarm_unregister_notifier(struct notifier_block *nb);
-
-/**
- * pm8058_batt_alarm_hold_time_set - set hold time of interrupt output *
- * @hold_time:	amount of time that battery voltage must remain outside of the
- *		threshold range before the battery alarm interrupt triggers
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_batt_alarm_hold_time_set(enum pm8058_batt_alarm_hold_time hold_time);
-
-/**
- * pm8058_batt_alarm_pwm_rate_set - set battery alarm update rate *
- * @use_pwm:		1 = use PWM update rate, 0 = comparators always active
- * @clock_scaler:	PWM clock scaler = 2 to 9
- * @clock_divider:	PWM clock divider = 2 to 8
- *
- * This function sets the rate at which the battery alarm module enables
- * the threshold comparators.  The rate is determined by the following equation:
- *
- * f_update = (1024 Hz) / (clock_divider * (2 ^ clock_scaler))
- *
- * Thus, the update rate can range from 0.25 Hz to 128 Hz.
- *
- * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
- */
-int pm8058_batt_alarm_pwm_rate_set(int use_pwm, int clock_scaler,
-				   int clock_divider);
-
-#endif /* __PMIC8058_BATT_ALARM_H__ */
diff --git a/include/linux/pmic8058-misc.h b/include/linux/pmic8058-misc.h
deleted file mode 100644
index 5675a93..0000000
--- a/include/linux/pmic8058-misc.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. 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 version 2 and
- * only 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.
- */
-
-
-#ifndef __PMIC8058_MISC_H__
-#define __PMIC8058_MISC_H__
-
-enum pm8058_vib_en_mode {
-	PM8058_VIB_MANUAL,
-	PM8058_VIB_DTEST1,
-	PM8058_VIB_DTEST2,
-	PM8058_VIB_DTEST3
-};
-
-enum pm8058_coincell_chg_voltage {
-	PM8058_COINCELL_VOLTAGE_3p2V = 1,
-	PM8058_COINCELL_VOLTAGE_3p1V,
-	PM8058_COINCELL_VOLTAGE_3p0V,
-	PM8058_COINCELL_VOLTAGE_2p5V = 16
-};
-
-enum pm8058_coincell_chg_resistor {
-	PM8058_COINCELL_RESISTOR_2100_OHMS,
-	PM8058_COINCELL_RESISTOR_1700_OHMS,
-	PM8058_COINCELL_RESISTOR_1200_OHMS,
-	PM8058_COINCELL_RESISTOR_800_OHMS
-};
-
-enum pm8058_coincell_chg_state {
-	PM8058_COINCELL_CHG_DISABLE,
-	PM8058_COINCELL_CHG_ENABLE
-};
-
-struct pm8058_vib_config {
-	u16			drive_mV;
-	u8			active_low;
-	enum pm8058_vib_en_mode	enable_mode;
-};
-
-struct pm8058_coincell_chg_config {
-	enum pm8058_coincell_chg_state		state;
-	enum pm8058_coincell_chg_voltage	voltage;
-	enum pm8058_coincell_chg_resistor	resistor;
-};
-
-int pm8058_vibrator_config(struct pm8058_vib_config *vib_config);
-int pm8058_coincell_chg_config(struct pm8058_coincell_chg_config *chg_config);
-
-#endif /* __PMIC8058_MISC_H__ */
diff --git a/include/linux/pmic8058-pwrkey.h b/include/linux/pmic8058-pwrkey.h
deleted file mode 100644
index 6953872..0000000
--- a/include/linux/pmic8058-pwrkey.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (c) 2010, Code Aurora Forum. 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 version 2 and
- * only 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.
- *
- */
-
-#ifndef __PMIC8058_PWRKEY_H__
-#define __PMIC8058_PWRKEY_H__
-
-struct pmic8058_pwrkey_pdata {
-	bool pull_up;
-	/* time after which pwr key event should be generated, if key is
-	 * released before that then end key event is reported
-	 */
-	u16  pwrkey_time_ms;
-	/* time delay for pwr-key state change
-	 * interrupt triggering.
-	 */
-	u32  kpd_trigger_delay_us;
-	u32  wakeup;
-};
-
-#endif /* __PMIC8058_PWRKEY_H__ */
diff --git a/include/linux/pmic8058-vibrator.h b/include/linux/pmic8058-vibrator.h
deleted file mode 100644
index e539058..0000000
--- a/include/linux/pmic8058-vibrator.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* Copyright (c) 2010, Code Aurora Forum. 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 version 2 and
- * only 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.
- *
- */
-#ifndef __PMIC8058_VIBRATOR_H__
-#define __PMIC8058_VIBRATOR_H__
-
-struct pmic8058_vibrator_pdata {
-	int initial_vibrate_ms;
-	int max_timeout_ms;
-
-	int level_mV;
-};
-
-#endif /* __PMIC8058_VIBRATOR_H__ */
diff --git a/include/linux/regulator/pm8018-regulator.h b/include/linux/regulator/pm8018-regulator.h
deleted file mode 100644
index 54515fa..0000000
--- a/include/linux/regulator/pm8018-regulator.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. 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 version 2 and
- * only 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.
- */
-
-#ifndef __PM8018_REGULATOR_H__
-#define __PM8018_REGULATOR_H__
-
-#include <linux/regulator/machine.h>
-
-#define PM8018_REGULATOR_DEV_NAME	"pm8018-regulator"
-
-/**
- * enum pm8018_vreg_id - PMIC 8018 regulator ID numbers
- */
-enum pm8018_vreg_id {
-	PM8018_VREG_ID_L2,
-	PM8018_VREG_ID_L3,
-	PM8018_VREG_ID_L4,
-	PM8018_VREG_ID_L5,
-	PM8018_VREG_ID_L6,
-	PM8018_VREG_ID_L7,
-	PM8018_VREG_ID_L8,
-	PM8018_VREG_ID_L9,
-	PM8018_VREG_ID_L10,
-	PM8018_VREG_ID_L11,
-	PM8018_VREG_ID_L12,
-	PM8018_VREG_ID_L13,
-	PM8018_VREG_ID_L14,
-	PM8018_VREG_ID_S1,
-	PM8018_VREG_ID_S2,
-	PM8018_VREG_ID_S3,
-	PM8018_VREG_ID_S4,
-	PM8018_VREG_ID_S5,
-	PM8018_VREG_ID_LVS1,
-
-	/* The following are IDs for regulator devices to enable pin control. */
-	PM8018_VREG_ID_L2_PC,
-	PM8018_VREG_ID_L3_PC,
-	PM8018_VREG_ID_L4_PC,
-	PM8018_VREG_ID_L5_PC,
-	PM8018_VREG_ID_L6_PC,
-	PM8018_VREG_ID_L7_PC,
-	PM8018_VREG_ID_L8_PC,
-
-	PM8018_VREG_ID_L13_PC,
-	PM8018_VREG_ID_L14_PC,
-	PM8018_VREG_ID_S1_PC,
-	PM8018_VREG_ID_S2_PC,
-	PM8018_VREG_ID_S3_PC,
-	PM8018_VREG_ID_S4_PC,
-	PM8018_VREG_ID_S5_PC,
-	PM8018_VREG_ID_LVS1_PC,
-
-	PM8018_VREG_ID_MAX,
-};
-
-/* Pin control input pins. */
-#define PM8018_VREG_PIN_CTRL_NONE	0x00
-#define PM8018_VREG_PIN_CTRL_D1		0x01
-#define PM8018_VREG_PIN_CTRL_A0		0x02
-#define PM8018_VREG_PIN_CTRL_A1		0x04
-#define PM8018_VREG_PIN_CTRL_A2		0x08
-
-/* Minimum high power mode loads in uA. */
-#define PM8018_VREG_LDO_50_HPM_MIN_LOAD		5000
-#define PM8018_VREG_LDO_150_HPM_MIN_LOAD	10000
-#define PM8018_VREG_LDO_300_HPM_MIN_LOAD	10000
-#define PM8018_VREG_LDO_1200_HPM_MIN_LOAD	10000
-#define PM8018_VREG_SMPS_1500_HPM_MIN_LOAD	100000
-
-/**
- * enum pm8018_vreg_pin_function - action to perform when pin control is active
- * %PM8018_VREG_PIN_FN_ENABLE:	pin control enables the regulator
- * %PM8018_VREG_PIN_FN_MODE:	pin control changes mode from LPM to HPM
- */
-enum pm8018_vreg_pin_function {
-	PM8018_VREG_PIN_FN_ENABLE = 0,
-	PM8018_VREG_PIN_FN_MODE,
-};
-
-/**
- * struct pm8018_regulator_platform_data - PMIC 8018 regulator platform data
- * @init_data:		regulator constraints
- * @id:			regulator id; from enum pm8018_vreg_id
- * @pull_down_enable:	0 = no pulldown, 1 = pulldown when regulator disabled
- * @pin_ctrl:		pin control inputs to use for the regulator; should be
- *			a combination of PM8018_VREG_PIN_CTRL_* values
- * @pin_fn:		action to perform when pin control pin is active
- * @system_uA:		current drawn from regulator not accounted for by any
- *			regulator framework consumer
- * @enable_time:	time in us taken to enable a regulator to the maximum
- *			allowed voltage for the system.  This is dependent upon
- *			the load and capacitance for a regulator on the board.
- */
-struct pm8018_regulator_platform_data {
-	struct regulator_init_data	init_data;
-	enum pm8018_vreg_id		id;
-	unsigned			pull_down_enable;
-	unsigned			pin_ctrl;
-	enum pm8018_vreg_pin_function	pin_fn;
-	int				system_uA;
-	int				enable_time;
-};
-
-#endif
diff --git a/include/linux/regulator/pm8921-regulator.h b/include/linux/regulator/pm8921-regulator.h
deleted file mode 100644
index 2eac548..0000000
--- a/include/linux/regulator/pm8921-regulator.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. 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 version 2 and
- * only 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.
- */
-
-#ifndef __PM8921_REGULATOR_H__
-#define __PM8921_REGULATOR_H__
-
-#include <linux/regulator/machine.h>
-
-#define PM8921_REGULATOR_DEV_NAME	"pm8921-regulator"
-
-/**
- * enum pm8921_vreg_id - PMIC 8921 regulator ID numbers
- */
-enum pm8921_vreg_id {
-	PM8921_VREG_ID_L1 = 0,
-	PM8921_VREG_ID_L2,
-	PM8921_VREG_ID_L3,
-	PM8921_VREG_ID_L4,
-	PM8921_VREG_ID_L5,
-	PM8921_VREG_ID_L6,
-	PM8921_VREG_ID_L7,
-	PM8921_VREG_ID_L8,
-	PM8921_VREG_ID_L9,
-	PM8921_VREG_ID_L10,
-	PM8921_VREG_ID_L11,
-	PM8921_VREG_ID_L12,
-	PM8921_VREG_ID_L14,
-	PM8921_VREG_ID_L15,
-	PM8921_VREG_ID_L16,
-	PM8921_VREG_ID_L17,
-	PM8921_VREG_ID_L18,
-	PM8921_VREG_ID_L21,
-	PM8921_VREG_ID_L22,
-	PM8921_VREG_ID_L23,
-	PM8921_VREG_ID_L24,
-	PM8921_VREG_ID_L25,
-	PM8921_VREG_ID_L26,
-	PM8921_VREG_ID_L27,
-	PM8921_VREG_ID_L28,
-	PM8921_VREG_ID_L29,
-	PM8921_VREG_ID_S1,
-	PM8921_VREG_ID_S2,
-	PM8921_VREG_ID_S3,
-	PM8921_VREG_ID_S4,
-	PM8921_VREG_ID_S5,
-	PM8921_VREG_ID_S6,
-	PM8921_VREG_ID_S7,
-	PM8921_VREG_ID_S8,
-	PM8921_VREG_ID_LVS1,
-	PM8921_VREG_ID_LVS2,
-	PM8921_VREG_ID_LVS3,
-	PM8921_VREG_ID_LVS4,
-	PM8921_VREG_ID_LVS5,
-	PM8921_VREG_ID_LVS6,
-	PM8921_VREG_ID_LVS7,
-	PM8921_VREG_ID_USB_OTG,
-	PM8921_VREG_ID_HDMI_MVS,
-	PM8921_VREG_ID_NCP,
-	/* The following are IDs for regulator devices to enable pin control. */
-	PM8921_VREG_ID_L1_PC,
-	PM8921_VREG_ID_L2_PC,
-	PM8921_VREG_ID_L3_PC,
-	PM8921_VREG_ID_L4_PC,
-	PM8921_VREG_ID_L5_PC,
-	PM8921_VREG_ID_L6_PC,
-	PM8921_VREG_ID_L7_PC,
-	PM8921_VREG_ID_L8_PC,
-	PM8921_VREG_ID_L9_PC,
-	PM8921_VREG_ID_L10_PC,
-	PM8921_VREG_ID_L11_PC,
-	PM8921_VREG_ID_L12_PC,
-	PM8921_VREG_ID_L14_PC,
-	PM8921_VREG_ID_L15_PC,
-	PM8921_VREG_ID_L16_PC,
-	PM8921_VREG_ID_L17_PC,
-	PM8921_VREG_ID_L18_PC,
-	PM8921_VREG_ID_L21_PC,
-	PM8921_VREG_ID_L22_PC,
-	PM8921_VREG_ID_L23_PC,
-
-	PM8921_VREG_ID_L29_PC,
-	PM8921_VREG_ID_S1_PC,
-	PM8921_VREG_ID_S2_PC,
-	PM8921_VREG_ID_S3_PC,
-	PM8921_VREG_ID_S4_PC,
-
-	PM8921_VREG_ID_S7_PC,
-	PM8921_VREG_ID_S8_PC,
-	PM8921_VREG_ID_LVS1_PC,
-
-	PM8921_VREG_ID_LVS3_PC,
-	PM8921_VREG_ID_LVS4_PC,
-	PM8921_VREG_ID_LVS5_PC,
-	PM8921_VREG_ID_LVS6_PC,
-	PM8921_VREG_ID_LVS7_PC,
-
-	PM8921_VREG_ID_MAX,
-};
-
-/* Pin control input pins. */
-#define PM8921_VREG_PIN_CTRL_NONE	0x00
-#define PM8921_VREG_PIN_CTRL_D1		0x01
-#define PM8921_VREG_PIN_CTRL_A0		0x02
-#define PM8921_VREG_PIN_CTRL_A1		0x04
-#define PM8921_VREG_PIN_CTRL_A2		0x08
-
-/* Minimum high power mode loads in uA. */
-#define PM8921_VREG_LDO_50_HPM_MIN_LOAD		5000
-#define PM8921_VREG_LDO_150_HPM_MIN_LOAD	10000
-#define PM8921_VREG_LDO_300_HPM_MIN_LOAD	10000
-#define PM8921_VREG_LDO_600_HPM_MIN_LOAD	10000
-#define PM8921_VREG_LDO_1200_HPM_MIN_LOAD	10000
-#define PM8921_VREG_SMPS_1500_HPM_MIN_LOAD	100000
-#define PM8921_VREG_SMPS_2000_HPM_MIN_LOAD	100000
-
-/**
- * enum pm8921_vreg_pin_function - action to perform when pin control is active
- * %PM8921_VREG_PIN_FN_ENABLE:	pin control enables the regulator
- * %PM8921_VREG_PIN_FN_MODE:	pin control changes mode from LPM to HPM
- */
-enum pm8921_vreg_pin_function {
-	PM8921_VREG_PIN_FN_ENABLE = 0,
-	PM8921_VREG_PIN_FN_MODE,
-};
-
-/**
- * struct pm8921_regulator_platform_data - PMIC 8921 regulator platform data
- * @init_data:		regulator constraints
- * @id:			regulator id; from enum pm8921_vreg_id
- * @pull_down_enable:	0 = no pulldown, 1 = pulldown when regulator disabled
- * @pin_ctrl:		pin control inputs to use for the regulator; should be
- *			a combination of PM8921_VREG_PIN_CTRL_* values
- * @pin_fn:		action to perform when pin control pin is active
- * @system_uA:		current drawn from regulator not accounted for by any
- *			regulator framework consumer
- * @enable_time:	time in us taken to enable a regulator to the maximum
- *			allowed voltage for the system.  This is dependent upon
- *			the load and capacitance for a regulator on the board.
- */
-struct pm8921_regulator_platform_data {
-	struct regulator_init_data	init_data;
-	enum pm8921_vreg_id		id;
-	unsigned			pull_down_enable;
-	unsigned			pin_ctrl;
-	enum pm8921_vreg_pin_function	pin_fn;
-	int				system_uA;
-	int				enable_time;
-};
-
-#endif
diff --git a/include/linux/regulator/pm8xxx-regulator.h b/include/linux/regulator/pm8xxx-regulator.h
new file mode 100644
index 0000000..7c8d778
--- /dev/null
+++ b/include/linux/regulator/pm8xxx-regulator.h
@@ -0,0 +1,80 @@
+/* Copyright (c) 2011, Code Aurora Forum. 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 version 2 and
+ * only 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.
+ */
+
+#ifndef __REGULATOR_PM8XXX_REGULATOR_H__
+#define __REGULATOR_PM8XXX_REGULATOR_H__
+
+#include <linux/regulator/machine.h>
+
+#define PM8XXX_REGULATOR_DEV_NAME	"pm8xxx-regulator"
+
+/* Pin control input pins. */
+#define PM8XXX_VREG_PIN_CTRL_NONE	0x00
+#define PM8XXX_VREG_PIN_CTRL_EN0	0x01
+#define PM8XXX_VREG_PIN_CTRL_EN1	0x02
+#define PM8XXX_VREG_PIN_CTRL_EN2	0x04
+#define PM8XXX_VREG_PIN_CTRL_EN3	0x08
+#define PM8XXX_VREG_PIN_CTRL_ALL	0x0F
+
+#define PM8921_VREG_PIN_CTRL_NONE	PM8XXX_VREG_PIN_CTRL_NONE
+#define PM8921_VREG_PIN_CTRL_D1		PM8XXX_VREG_PIN_CTRL_EN0
+#define PM8921_VREG_PIN_CTRL_A0		PM8XXX_VREG_PIN_CTRL_EN1
+#define PM8921_VREG_PIN_CTRL_A1		PM8XXX_VREG_PIN_CTRL_EN2
+#define PM8921_VREG_PIN_CTRL_A2		PM8XXX_VREG_PIN_CTRL_EN3
+
+/* Minimum high power mode loads in uA. */
+#define PM8XXX_VREG_LDO_50_HPM_MIN_LOAD		5000
+#define PM8XXX_VREG_LDO_150_HPM_MIN_LOAD	10000
+#define PM8XXX_VREG_LDO_300_HPM_MIN_LOAD	10000
+#define PM8XXX_VREG_LDO_600_HPM_MIN_LOAD	10000
+#define PM8XXX_VREG_LDO_1200_HPM_MIN_LOAD	10000
+#define PM8XXX_VREG_SMPS_1500_HPM_MIN_LOAD	100000
+#define PM8XXX_VREG_SMPS_2000_HPM_MIN_LOAD	100000
+
+#define REGULATOR_TEST_BANKS_MAX		8
+
+/**
+ * enum pm8xxx_vreg_pin_function - action to perform when pin control is active
+ * %PM8XXX_VREG_PIN_FN_ENABLE:	pin control enables the regulator
+ * %PM8XXX_VREG_PIN_FN_MODE:	pin control changes mode from LPM to HPM
+ */
+enum pm8xxx_vreg_pin_function {
+	PM8XXX_VREG_PIN_FN_ENABLE = 0,
+	PM8XXX_VREG_PIN_FN_MODE,
+};
+
+/**
+ * struct pm8xxx_regulator_platform_data - PMIC 8921 regulator platform data
+ * @init_data:		regulator constraints
+ * @id:			regulator id. Any value unique among pm8xxx_regulator
+ *			devices is acceptable.
+ * @pull_down_enable:	0 = no pulldown, 1 = pulldown when regulator disabled
+ * @pin_ctrl:		pin control inputs to use for the regulator; should be
+ *			a combination of PM8XXX_VREG_PIN_CTRL_* values
+ * @pin_fn:		action to perform when pin control pin is active
+ * @system_uA:		current drawn from regulator not accounted for by any
+ *			regulator framework consumer
+ * @enable_time:	time in us taken to enable a regulator to the maximum
+ *			allowed voltage for the system.  This is dependent upon
+ *			the load and capacitance for a regulator on the board.
+ */
+struct pm8xxx_regulator_platform_data {
+	struct regulator_init_data	init_data;
+	int				id;
+	unsigned			pull_down_enable;
+	unsigned			pin_ctrl;
+	enum pm8xxx_vreg_pin_function	pin_fn;
+	int				system_uA;
+	int				enable_time;
+};
+
+#endif
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index a8b04df..423a849 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -165,6 +165,9 @@
 #define MSM_CAM_IOCTL_SENSOR_V4l2_QUERY_CTRL \
 	_IOR(MSM_CAM_IOCTL_MAGIC, 49, struct v4l2_queryctrl)
 
+#define MSM_CAM_IOCTL_GET_KERNEL_SYSTEM_TIME \
+	_IOW(MSM_CAM_IOCTL_MAGIC, 50, struct timeval *)
+
 struct msm_mctl_pp_cmd {
 	int32_t  id;
 	uint16_t length;
diff --git a/include/media/tavarua.h b/include/media/tavarua.h
index b7380bc..bedfc7c 100644
--- a/include/media/tavarua.h
+++ b/include/media/tavarua.h
@@ -348,6 +348,8 @@
 #define SET_REG_FIELD(reg, val, offset, mask) \
 	(reg = (reg & ~mask) | (((val) << offset) & mask))
 #define GET_REG_FIELD(reg, offset, mask) ((reg & mask) >> offset)
+#define RSH_DATA(val, offset)    ((val) >> (offset))
+#define GET_ABS_VAL(val)        ((val) & (0xFF))
 
 enum radio_state_t {
 	FM_OFF,
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index ca15ed0..5339785 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1041,6 +1041,7 @@
 
 /* LE SMP Management interface */
 int le_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, void *cp);
+int mgmt_remote_class(u16 index, bdaddr_t *bdaddr, u8 dev_class[3]);
 
 /* HCI info for socket */
 #define hci_pi(sk) ((struct hci_pinfo *) sk)
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 2d3028d..de61c32 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -342,3 +342,8 @@
 } __packed;
 
 
+#define MGMT_EV_REMOTE_CLASS		0x0017
+struct mgmt_ev_remote_class {
+	bdaddr_t bdaddr;
+	__u8 dev_class[3];
+} __packed;
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 396e8fc..8be88bb 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -339,6 +339,36 @@
 };
 
 /**
+ * struct cfg80211_crypto_settings - Crypto settings
+ * @wpa_versions: indicates which, if any, WPA versions are enabled
+ *	(from enum nl80211_wpa_versions)
+ * @cipher_group: group key cipher suite (or 0 if unset)
+ * @n_ciphers_pairwise: number of AP supported unicast ciphers
+ * @ciphers_pairwise: unicast key cipher suites
+ * @n_akm_suites: number of AKM suites
+ * @akm_suites: AKM suites
+ * @control_port: Whether user space controls IEEE 802.1X port, i.e.,
+ *	sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is
+ *	required to assume that the port is unauthorized until authorized by
+ *	user space. Otherwise, port is marked authorized by default.
+ * @control_port_ethertype: the control port protocol that should be
+ *	allowed through even on unauthorized ports
+ * @control_port_no_encrypt: TRUE to prevent encryption of control port
+ *	protocol frames.
+ */
+struct cfg80211_crypto_settings {
+	u32 wpa_versions;
+	u32 cipher_group;
+	int n_ciphers_pairwise;
+	u32 ciphers_pairwise[NL80211_MAX_NR_CIPHER_SUITES];
+	int n_akm_suites;
+	u32 akm_suites[NL80211_MAX_NR_AKM_SUITES];
+	bool control_port;
+	__be16 control_port_ethertype;
+	bool control_port_no_encrypt;
+};
+
+/**
  * struct beacon_parameters - beacon parameters
  *
  * Used to configure the beacon for an interface.
@@ -351,11 +381,38 @@
  * @dtim_period: DTIM period or zero if not changed
  * @head_len: length of @head
  * @tail_len: length of @tail
+ * @ssid: SSID to be used in the BSS (note: may be %NULL if not provided from
+ *	user space)
+ * @ssid_len: length of @ssid
+ * @hidden_ssid: whether to hide the SSID in Beacon/Probe Response frames
+ * @crypto: crypto settings
+ * @privacy: the BSS uses privacy
+ * @auth_type: Authentication type (algorithm)
+ * @beacon_ies: extra information element(s) to add into Beacon frames or %NULL
+ * @beacon_ies_len: length of beacon_ies in octets
+ * @proberesp_ies: extra information element(s) to add into Probe Response
+ *	frames or %NULL
+ * @proberesp_ies_len: length of proberesp_ies in octets
+ * @assocresp_ies: extra information element(s) to add into (Re)Association
+ *	Response frames or %NULL
+ * @assocresp_ies_len: length of assocresp_ies in octets
  */
 struct beacon_parameters {
 	u8 *head, *tail;
 	int interval, dtim_period;
 	int head_len, tail_len;
+	const u8 *ssid;
+	size_t ssid_len;
+	enum nl80211_hidden_ssid hidden_ssid;
+	struct cfg80211_crypto_settings crypto;
+	bool privacy;
+	enum nl80211_auth_type auth_type;
+	const u8 *beacon_ies;
+	size_t beacon_ies_len;
+	const u8 *proberesp_ies;
+	size_t proberesp_ies_len;
+	const u8 *assocresp_ies;
+	size_t assocresp_ies_len;
 };
 
 /**
@@ -536,6 +593,11 @@
  *	This number should increase every time the list of stations
  *	changes, i.e. when a station is added or removed, so that
  *	userspace can tell whether it got a consistent snapshot.
+ * @assoc_req_ies: IEs from (Re)Association Request.
+ *	This is used only when in AP mode with drivers that do not use
+ *	user space MLME/SME implementation. The information is provided for
+ *	the cfg80211_new_sta() calls to notify user space of the IEs.
+ * @assoc_req_ies_len: Length of assoc_req_ies buffer in octets.
  */
 struct station_info {
 	u32 filled;
@@ -558,6 +620,14 @@
 	struct sta_bss_parameters bss_param;
 
 	int generation;
+
+	const u8 *assoc_req_ies;
+	size_t assoc_req_ies_len;
+
+	/*
+	 * Note: Add a new enum station_info_flags value for each new field and
+	 * use it to check which fields are initialized.
+	 */
 };
 
 /**
@@ -893,36 +963,6 @@
 
 
 /**
- * struct cfg80211_crypto_settings - Crypto settings
- * @wpa_versions: indicates which, if any, WPA versions are enabled
- *	(from enum nl80211_wpa_versions)
- * @cipher_group: group key cipher suite (or 0 if unset)
- * @n_ciphers_pairwise: number of AP supported unicast ciphers
- * @ciphers_pairwise: unicast key cipher suites
- * @n_akm_suites: number of AKM suites
- * @akm_suites: AKM suites
- * @control_port: Whether user space controls IEEE 802.1X port, i.e.,
- *	sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is
- *	required to assume that the port is unauthorized until authorized by
- *	user space. Otherwise, port is marked authorized by default.
- * @control_port_ethertype: the control port protocol that should be
- *	allowed through even on unauthorized ports
- * @control_port_no_encrypt: TRUE to prevent encryption of control port
- *	protocol frames.
- */
-struct cfg80211_crypto_settings {
-	u32 wpa_versions;
-	u32 cipher_group;
-	int n_ciphers_pairwise;
-	u32 ciphers_pairwise[NL80211_MAX_NR_CIPHER_SUITES];
-	int n_akm_suites;
-	u32 akm_suites[NL80211_MAX_NR_AKM_SUITES];
-	bool control_port;
-	__be16 control_port_ethertype;
-	bool control_port_no_encrypt;
-};
-
-/**
  * struct cfg80211_auth_request - Authentication request data
  *
  * This structure provides information needed to complete IEEE 802.11
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 9126bbb..798ed89 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -519,6 +519,7 @@
 #define DEFAULT_POPP_TOPOLOGY				0x00010be4
 #define VPM_TX_SM_ECNS_COPP_TOPOLOGY			0x00010F71
 #define VPM_TX_DM_FLUENCE_COPP_TOPOLOGY			0x00010F72
+#define VPM_TX_QMIC_FLUENCE_COPP_TOPOLOGY		0x00010F75
 
 #define ASM_MAX_EQ_BANDS 12
 
diff --git a/include/sound/q6afe.h b/include/sound/q6afe.h
index e913e15..4be1abe 100644
--- a/include/sound/q6afe.h
+++ b/include/sound/q6afe.h
@@ -93,4 +93,6 @@
  */
 int afe_convert_virtual_to_portid(u16 port_id);
 
+int afe_pseudo_port_start_nowait(u16 port_id);
+int afe_pseudo_port_stop_nowait(u16 port_id);
 #endif /* __Q6AFE_H__ */
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index d5828da..200ce83 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -20,16 +20,20 @@
 void irq_domain_add(struct irq_domain *domain)
 {
 	struct irq_data *d;
-	int hwirq;
+	int hwirq, irq;
 
 	/*
 	 * This assumes that the irq_domain owner has already allocated
 	 * the irq_descs.  This block will be removed when support for dynamic
 	 * allocation of irq_descs is added to irq_domain.
 	 */
-	for (hwirq = 0; hwirq < domain->nr_irq; hwirq++) {
-		d = irq_get_irq_data(irq_domain_to_irq(domain, hwirq));
-		if (d || d->domain) {
+	irq_domain_for_each_irq(domain, hwirq, irq) {
+		d = irq_get_irq_data(irq);
+		if (!d) {
+			WARN(1, "error: assigning domain to non existant irq_desc");
+			return;
+		}
+		if (d->domain) {
 			/* things are broken; just report, don't clean up */
 			WARN(1, "error: irq_desc already assigned to a domain");
 			return;
@@ -50,15 +54,15 @@
 void irq_domain_del(struct irq_domain *domain)
 {
 	struct irq_data *d;
-	int hwirq;
+	int hwirq, irq;
 
 	mutex_lock(&irq_domain_mutex);
 	list_del(&domain->list);
 	mutex_unlock(&irq_domain_mutex);
 
 	/* Clear the irq_domain assignments */
-	for (hwirq = 0; hwirq < domain->nr_irq; hwirq++) {
-		d = irq_get_irq_data(irq_domain_to_irq(domain, hwirq));
+	irq_domain_for_each_irq(domain, hwirq, irq) {
+		d = irq_get_irq_data(irq);
 		d->domain = NULL;
 	}
 }
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 6a9e368..75b5d6b 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1079,7 +1079,7 @@
 	depends on FAULT_INJECTION_DEBUG_FS && STACKTRACE_SUPPORT
 	depends on !X86_64
 	select STACKTRACE
-	select FRAME_POINTER if !PPC && !S390 && !MICROBLAZE
+	select FRAME_POINTER if !PPC && !S390 && !MICROBLAZE && !ARM_UNWIND
 	help
 	  Provide stacktrace filter for fault-injection capabilities
 
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 25b80df..78d1c61 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -366,6 +366,7 @@
 	switch (type) {
 	case ACL_LINK:
 		conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK;
+		conn->link_policy = hdev->link_policy;
 		break;
 	case SCO_LINK:
 		if (!pkt_type)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index e1a90f8..dd1d6e8 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -639,6 +639,12 @@
 
 	hci_notify(hdev, HCI_DEV_DOWN);
 
+	if (hdev->dev_type == HCI_BREDR) {
+		hci_dev_lock_bh(hdev);
+		mgmt_powered(hdev->id, 0);
+		hci_dev_unlock_bh(hdev);
+	}
+
 	if (hdev->flush)
 		hdev->flush(hdev);
 
@@ -671,12 +677,6 @@
 	 * and no tasks are scheduled. */
 	hdev->close(hdev);
 
-	if (hdev->dev_type == HCI_BREDR) {
-		hci_dev_lock_bh(hdev);
-		mgmt_powered(hdev->id, 0);
-		hci_dev_unlock_bh(hdev);
-	}
-
 	/* Clear only non-persistent flags */
 	if (test_bit(HCI_MGMT, &hdev->flags))
 		set_bit(HCI_MGMT, &keepflags);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 45aa228..be0f55c 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1678,6 +1678,8 @@
 		}
 
 		memcpy(conn->dev_class, ev->dev_class, 3);
+		/* For incoming connection update remote class to userspace */
+		mgmt_remote_class(hdev->id, &ev->bdaddr, ev->dev_class);
 		conn->state = BT_CONNECT;
 
 		hci_dev_unlock(hdev);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index a3f3563..7e17a28 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -569,6 +569,7 @@
 	} else
 		sk->sk_state_change(sk);
 
+	sk->sk_send_head = NULL;
 	skb_queue_purge(TX_QUEUE(sk));
 
 	if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
@@ -782,6 +783,7 @@
 	if (!conn)
 		return;
 
+	sk->sk_send_head = NULL;
 	skb_queue_purge(TX_QUEUE(sk));
 
 	if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
@@ -1452,10 +1454,6 @@
 		tx_skb->destructor = l2cap_skb_destructor;
 		atomic_inc(&pi->ertm_queued);
 
-		l2cap_do_send(sk, tx_skb);
-
-		BT_DBG("Sent txseq %d", (int)control->txseq);
-
 		l2cap_ertm_start_retrans_timer(pi);
 
 		pi->next_tx_seq = __next_seq(pi->next_tx_seq, pi);
@@ -1467,6 +1465,9 @@
 			sk->sk_send_head = NULL;
 		else
 			sk->sk_send_head = skb_queue_next(TX_QUEUE(sk), skb);
+
+		l2cap_do_send(sk, tx_skb);
+		BT_DBG("Sent txseq %d", (int)control->txseq);
 	}
 
 	BT_DBG("Sent %d, %d unacked, %d in ERTM queue, %d in HCI queue", sent,
@@ -4515,6 +4516,7 @@
 	if (sk->sk_state != BT_DISCONN) {
 		sk->sk_shutdown = SHUTDOWN_MASK;
 
+		sk->sk_send_head = NULL;
 		skb_queue_purge(TX_QUEUE(sk));
 
 		if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index b413a9c..7f2cff8 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2905,3 +2905,14 @@
 									NULL);
 }
 
+int mgmt_remote_class(u16 index, bdaddr_t *bdaddr, u8 dev_class[3])
+{
+	struct mgmt_ev_remote_class ev;
+
+	memset(&ev, 0, sizeof(ev));
+
+	bacpy(&ev.bdaddr, bdaddr);
+	memcpy(ev.dev_class, dev_class, 3);
+
+	return mgmt_event(MGMT_EV_REMOTE_CLASS, index, &ev, sizeof(ev), NULL);
+}
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index ca7bf10..3ff633e 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -334,6 +334,7 @@
 	ieee80211_sta_debugfs_add(sta);
 	rate_control_add_sta_debugfs(sta);
 
+	memset(&sinfo, 0, sizeof(sinfo));
 	sinfo.filled = 0;
 	sinfo.generation = local->sta_generation;
 	cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 584a7cd..0fc46b3 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -23,6 +23,12 @@
 #include "nl80211.h"
 #include "reg.h"
 
+static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type);
+static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
+				   struct genl_info *info,
+				   struct cfg80211_crypto_settings *settings,
+				   int cipher_limit);
+
 static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
 			    struct genl_info *info);
 static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb,
@@ -176,6 +182,11 @@
 	[NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED },
 	[NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 },
 	[NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 },
+	[NL80211_ATTR_HIDDEN_SSID] = { .type = NLA_U32 },
+	[NL80211_ATTR_IE_PROBE_RESP] = { .type = NLA_BINARY,
+					 .len = IEEE80211_MAX_DATA_LEN },
+	[NL80211_ATTR_IE_ASSOC_RESP] = { .type = NLA_BINARY,
+					 .len = IEEE80211_MAX_DATA_LEN },
 };
 
 /* policy for the key attributes */
@@ -1957,7 +1968,10 @@
 	struct beacon_parameters params;
 	int haveinfo = 0, err;
 
-	if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]))
+	if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]) ||
+	    !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]) ||
+	    !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_PROBE_RESP]) ||
+	    !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]))
 		return -EINVAL;
 
 	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
@@ -1983,6 +1997,49 @@
 		if (err)
 			return err;
 
+		/*
+		 * In theory, some of these attributes could be required for
+		 * NEW_BEACON, but since they were not used when the command was
+		 * originally added, keep them optional for old user space
+		 * programs to work with drivers that do not need the additional
+		 * information.
+		 */
+		if (info->attrs[NL80211_ATTR_SSID]) {
+			params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
+			params.ssid_len =
+				nla_len(info->attrs[NL80211_ATTR_SSID]);
+			if (params.ssid_len == 0 ||
+			    params.ssid_len > IEEE80211_MAX_SSID_LEN)
+				return -EINVAL;
+		}
+
+		if (info->attrs[NL80211_ATTR_HIDDEN_SSID]) {
+			params.hidden_ssid = nla_get_u32(
+				info->attrs[NL80211_ATTR_HIDDEN_SSID]);
+			if (params.hidden_ssid !=
+			    NL80211_HIDDEN_SSID_NOT_IN_USE &&
+			    params.hidden_ssid !=
+			    NL80211_HIDDEN_SSID_ZERO_LEN &&
+			    params.hidden_ssid !=
+			    NL80211_HIDDEN_SSID_ZERO_CONTENTS)
+				return -EINVAL;
+		}
+
+		params.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
+
+		if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
+			params.auth_type = nla_get_u32(
+				info->attrs[NL80211_ATTR_AUTH_TYPE]);
+			if (!nl80211_valid_auth_type(params.auth_type))
+				return -EINVAL;
+		} else
+			params.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
+
+		err = nl80211_crypto_settings(rdev, info, &params.crypto,
+					      NL80211_MAX_NR_CIPHER_SUITES);
+		if (err)
+			return err;
+
 		call = rdev->ops->add_beacon;
 		break;
 	case NL80211_CMD_SET_BEACON:
@@ -2013,6 +2070,25 @@
 	if (!haveinfo)
 		return -EINVAL;
 
+	if (info->attrs[NL80211_ATTR_IE]) {
+		params.beacon_ies = nla_data(info->attrs[NL80211_ATTR_IE]);
+		params.beacon_ies_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+	}
+
+	if (info->attrs[NL80211_ATTR_IE_PROBE_RESP]) {
+		params.proberesp_ies =
+			nla_data(info->attrs[NL80211_ATTR_IE_PROBE_RESP]);
+		params.proberesp_ies_len =
+			nla_len(info->attrs[NL80211_ATTR_IE_PROBE_RESP]);
+	}
+
+	if (info->attrs[NL80211_ATTR_IE_ASSOC_RESP]) {
+		params.assocresp_ies =
+			nla_data(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
+		params.assocresp_ies_len =
+			nla_len(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
+	}
+
 	err = call(&rdev->wiphy, dev, &params);
 	if (!err && params.interval)
 		wdev->beacon_interval = params.interval;
@@ -2209,6 +2285,10 @@
 	}
 	nla_nest_end(msg, sinfoattr);
 
+	if (sinfo->assoc_req_ies)
+		NLA_PUT(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len,
+			sinfo->assoc_req_ies);
+
 	return genlmsg_end(msg, hdr);
 
  nla_put_failure:
@@ -2236,6 +2316,7 @@
 	}
 
 	while (1) {
+		memset(&sinfo, 0, sizeof(sinfo));
 		err = dev->ops->dump_station(&dev->wiphy, netdev, sta_idx,
 					     mac_addr, &sinfo);
 		if (err == -ENOENT)
diff --git a/scripts/build-all.py b/scripts/build-all.py
index dbf7b80..296d9ad 100755
--- a/scripts/build-all.py
+++ b/scripts/build-all.py
@@ -83,7 +83,7 @@
 def scan_configs():
     """Get the full list of defconfigs appropriate for this tree."""
     names = {}
-    for n in glob.glob('arch/arm/configs/[fm]sm[0-9]*_defconfig'):
+    for n in glob.glob('arch/arm/configs/[fm]sm[0-9-]*_defconfig'):
         names[os.path.basename(n)[:-10]] = n
     for n in glob.glob('arch/arm/configs/qsd*_defconfig'):
         names[os.path.basename(n)[:-10]] = n
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 5003ab5..33afdc9d 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012, Code Aurora Forum. 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 version 2 and
@@ -46,6 +46,8 @@
 
 #define TABLA_I2S_MASTER_MODE_MASK 0x08
 
+#define TABLA_OCP_ATTEMPT 1
+
 static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
 static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
 static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
@@ -81,6 +83,16 @@
 	BAND_MAX,
 };
 
+/* Flags to track of PA and DAC state.
+ * PA and DAC should be tracked separately as AUXPGA loopback requires
+ * only PA to be turned on without DAC being on. */
+enum tabla_priv_ack_flags {
+	TABLA_HPHL_PA_OFF_ACK = 0,
+	TABLA_HPHR_PA_OFF_ACK,
+	TABLA_HPHL_DAC_OFF_ACK,
+	TABLA_HPHR_DAC_OFF_ACK
+};
+
 struct tabla_priv {
 	struct snd_soc_codec *codec;
 	u32 adc_count;
@@ -112,6 +124,9 @@
 	u8 cfilt_k_value;
 	bool mbhc_micbias_switched;
 
+	/* track PA/DAC state */
+	unsigned long hph_pa_dac_state;
+
 	/*track tabla interface type*/
 	u8 intf_type;
 
@@ -122,6 +137,14 @@
 	 */
 	struct work_struct hphlocp_work; /* reporting left hph ocp off */
 	struct work_struct hphrocp_work; /* reporting right hph ocp off */
+
+	/* pm_cnt holds number of sleep lock holders + 1
+	 * so if pm_cnt is 1 system is sleep-able. */
+	atomic_t pm_cnt;
+	wait_queue_head_t pm_wq;
+
+	u8 hphlocp_cnt; /* headphone left ocp retry */
+	u8 hphrocp_cnt; /* headphone right ocp retry */
 };
 
 #ifdef CONFIG_DEBUG_FS
@@ -945,6 +968,7 @@
 {
 	struct snd_soc_codec *codec = w->codec;
 	u16 adc_reg;
+	u8 init_bit_shift;
 
 	pr_debug("%s %d\n", __func__, event);
 
@@ -959,16 +983,28 @@
 		return -EINVAL;
 	}
 
+	if (w->shift == 3)
+		init_bit_shift = 6;
+	else if  (w->shift == 7)
+		init_bit_shift = 7;
+	else {
+		pr_err("%s: Error, invalid init bit postion adc register\n",
+				__func__);
+		return -EINVAL;
+	}
+
+
+
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		tabla_codec_enable_adc_block(codec, 1);
+		snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
+				1 << init_bit_shift);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
-		snd_soc_update_bits(codec, adc_reg, 1 << w->shift,
-			1 << w->shift);
-		usleep_range(1000, 1000);
-		snd_soc_update_bits(codec, adc_reg, 1 << w->shift, 0x00);
-		usleep_range(1000, 1000);
+
+		snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
+
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		tabla_codec_enable_adc_block(codec, 0);
@@ -1012,9 +1048,9 @@
 		snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
 		break;
 	case SND_SOC_DAPM_POST_PMU:
-		pr_debug("%s: sleeping 40 ms after %s PA turn on\n",
+		pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
 				__func__, w->name);
-		usleep_range(40000, 40000);
+		usleep_range(16000, 16000);
 		break;
 	case SND_SOC_DAPM_POST_PMD:
 		snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
@@ -1348,6 +1384,19 @@
 	return (hph_reg_val & 0x30) ? true : false;
 }
 
+static bool tabla_is_hph_dac_on(struct snd_soc_codec *codec, int left)
+{
+	u8 hph_reg_val = 0;
+	if (left)
+		hph_reg_val = snd_soc_read(codec,
+					   TABLA_A_RX_HPH_L_DAC_CTL);
+	else
+		hph_reg_val = snd_soc_read(codec,
+					   TABLA_A_RX_HPH_R_DAC_CTL);
+
+	return (hph_reg_val & 0xC0) ? true : false;
+}
+
 static void tabla_codec_switch_micbias(struct snd_soc_codec *codec,
 	int vddio_switch)
 {
@@ -1603,6 +1652,14 @@
 	return 0;
 }
 
+static void tabla_snd_soc_jack_report(struct tabla_priv *tabla,
+				      struct snd_soc_jack *jack, int status,
+				      int mask)
+{
+	/* XXX: wake_lock_timeout()? */
+	snd_soc_jack_report(jack, status, mask);
+}
+
 static void hphocp_off_report(struct tabla_priv *tabla,
 	u32 jack_status, int irq)
 {
@@ -1613,12 +1670,20 @@
 		codec = tabla->codec;
 		tabla->hph_status &= ~jack_status;
 		if (tabla->headset_jack)
-			snd_soc_jack_report(tabla->headset_jack,
-			tabla->hph_status, TABLA_JACK_MASK);
+			tabla_snd_soc_jack_report(tabla, tabla->headset_jack,
+						  tabla->hph_status,
+						  TABLA_JACK_MASK);
 		snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
 		0x00);
 		snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
 		0x10);
+		/* reset retry counter as PA is turned off signifying
+		 * start of new OCP detection session
+		 */
+		if (TABLA_IRQ_HPH_PA_OCPL_FAULT)
+			tabla->hphlocp_cnt = 0;
+		else
+			tabla->hphrocp_cnt = 0;
 		tabla_enable_irq(codec->control_data, irq);
 	} else {
 		pr_err("%s: Bad tabla private data\n", __func__);
@@ -1664,12 +1729,22 @@
 		 * would have been locked while snd_soc_jack_report also
 		 * attempts to acquire same lock.
 		 */
-		if ((tabla->hph_status & SND_JACK_OC_HPHL) &&
-			strnstr(w->name, "HPHL", 4))
-			schedule_work(&tabla->hphlocp_work);
-		else if ((tabla->hph_status & SND_JACK_OC_HPHR) &&
-			strnstr(w->name, "HPHR", 4))
-			schedule_work(&tabla->hphrocp_work);
+		if (w->shift == 5) {
+			clear_bit(TABLA_HPHL_PA_OFF_ACK,
+				  &tabla->hph_pa_dac_state);
+			clear_bit(TABLA_HPHL_DAC_OFF_ACK,
+				  &tabla->hph_pa_dac_state);
+			if (tabla->hph_status & SND_JACK_OC_HPHL)
+				schedule_work(&tabla->hphlocp_work);
+		} else if (w->shift == 4) {
+			clear_bit(TABLA_HPHR_PA_OFF_ACK,
+				  &tabla->hph_pa_dac_state);
+			clear_bit(TABLA_HPHR_DAC_OFF_ACK,
+				  &tabla->hph_pa_dac_state);
+			if (tabla->hph_status & SND_JACK_OC_HPHR)
+				schedule_work(&tabla->hphrocp_work);
+		}
+
 		if (tabla->mbhc_micbias_switched)
 			tabla_codec_switch_micbias(codec, 0);
 
@@ -1717,6 +1792,7 @@
 	default:
 		/* Should never reach here */
 		pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
+		return;
 	}
 
 	micbias_regs->cfilt_sel = cfilt;
@@ -3069,6 +3145,24 @@
 	return 0;
 }
 
+static void tabla_lock_sleep(struct tabla_priv *tabla)
+{
+	int ret;
+	while (!(ret = wait_event_timeout(tabla->pm_wq,
+					  atomic_inc_not_zero(&tabla->pm_cnt),
+					  2 * HZ))) {
+		pr_err("%s: didn't wake up for 2000ms (%d), pm_cnt %d\n",
+		       __func__, ret, atomic_read(&tabla->pm_cnt));
+		WARN_ON_ONCE(1);
+	}
+}
+
+static void tabla_unlock_sleep(struct tabla_priv *tabla)
+{
+	atomic_dec(&tabla->pm_cnt);
+	wake_up(&tabla->pm_wq);
+}
+
 static void btn0_lpress_fn(struct work_struct *work)
 {
 	struct delayed_work *delayed_work;
@@ -3083,13 +3177,15 @@
 		if (tabla->button_jack) {
 			pr_debug("%s: Reporting long button press event\n",
 					__func__);
-			snd_soc_jack_report(tabla->button_jack, SND_JACK_BTN_0,
-					SND_JACK_BTN_0);
+			tabla_snd_soc_jack_report(tabla, tabla->button_jack,
+						  SND_JACK_BTN_0,
+						  SND_JACK_BTN_0);
 		}
 	} else {
 		pr_err("%s: Bad tabla private data\n", __func__);
 	}
 
+	tabla_unlock_sleep(tabla);
 }
 
 int tabla_hs_detect(struct snd_soc_codec *codec,
@@ -3139,6 +3235,7 @@
 
 	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
 	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
+	tabla_lock_sleep(priv);
 
 	bias_value = tabla_codec_read_dce_result(codec);
 	pr_debug("%s: button press interrupt, bias value(DCE Read)=%d\n",
@@ -3155,7 +3252,11 @@
 
 	msleep(100);
 
-	schedule_delayed_work(&priv->btn0_dwork, msecs_to_jiffies(400));
+	if (schedule_delayed_work(&priv->btn0_dwork,
+				  msecs_to_jiffies(400)) == 0) {
+		WARN(1, "Button pressed twice without release event\n");
+		tabla_unlock_sleep(priv);
+	}
 
 	return IRQ_HANDLED;
 }
@@ -3168,6 +3269,7 @@
 
 	pr_debug("%s\n", __func__);
 	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
+	tabla_lock_sleep(priv);
 
 	mic_voltage = tabla_codec_read_dce_result(codec);
 	pr_debug("%s: Microphone Voltage on release(DCE Read) = %d\n",
@@ -3181,12 +3283,15 @@
 			pr_debug("%s: Reporting long button release event\n",
 					__func__);
 			if (priv->button_jack) {
-				snd_soc_jack_report(priv->button_jack, 0,
-					SND_JACK_BTN_0);
+				tabla_snd_soc_jack_report(priv,
+							  priv->button_jack, 0,
+							  SND_JACK_BTN_0);
 			}
 
 		} else {
-
+			/* if scheduled btn0_dwork is canceled from here,
+			 * we have to unlock from here instead btn0_work */
+			tabla_unlock_sleep(priv);
 			mic_voltage =
 				tabla_codec_measure_micbias_voltage(codec, 0);
 			pr_debug("%s: Mic Voltage on release(new STA) = %d\n",
@@ -3201,10 +3306,12 @@
 					pr_debug("%s:reporting short button press and release\n",
 							__func__);
 
-					snd_soc_jack_report(priv->button_jack,
+					tabla_snd_soc_jack_report(priv,
+							      priv->button_jack,
 						SND_JACK_BTN_0, SND_JACK_BTN_0);
-					snd_soc_jack_report(priv->button_jack,
-						0, SND_JACK_BTN_0);
+					tabla_snd_soc_jack_report(priv,
+							     priv->button_jack,
+							     0, SND_JACK_BTN_0);
 				}
 			}
 		}
@@ -3213,7 +3320,7 @@
 	}
 
 	tabla_codec_start_hs_polling(codec);
-
+	tabla_unlock_sleep(priv);
 	return IRQ_HANDLED;
 }
 
@@ -3264,12 +3371,22 @@
 
 	if (tabla) {
 		codec = tabla->codec;
-		tabla_disable_irq(codec->control_data,
-			TABLA_IRQ_HPH_PA_OCPL_FAULT);
-		tabla->hph_status |= SND_JACK_OC_HPHL;
-		if (tabla->headset_jack) {
-			snd_soc_jack_report(tabla->headset_jack,
-				tabla->hph_status, TABLA_JACK_MASK);
+		if (tabla->hphlocp_cnt++ < TABLA_OCP_ATTEMPT) {
+			pr_info("%s: retry\n", __func__);
+			snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
+					    0x00);
+			snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
+					    0x10);
+		} else {
+			tabla_disable_irq(codec->control_data,
+					  TABLA_IRQ_HPH_PA_OCPL_FAULT);
+			tabla->hphlocp_cnt = 0;
+			tabla->hph_status |= SND_JACK_OC_HPHL;
+			if (tabla->headset_jack)
+				tabla_snd_soc_jack_report(tabla,
+							  tabla->headset_jack,
+							  tabla->hph_status,
+							  TABLA_JACK_MASK);
 		}
 	} else {
 		pr_err("%s: Bad tabla private data\n", __func__);
@@ -3287,12 +3404,22 @@
 
 	if (tabla) {
 		codec = tabla->codec;
-		tabla_disable_irq(codec->control_data,
-			TABLA_IRQ_HPH_PA_OCPR_FAULT);
-		tabla->hph_status |= SND_JACK_OC_HPHR;
-		if (tabla->headset_jack) {
-			snd_soc_jack_report(tabla->headset_jack,
-				tabla->hph_status, TABLA_JACK_MASK);
+		if (tabla->hphrocp_cnt++ < TABLA_OCP_ATTEMPT) {
+			pr_info("%s: retry\n", __func__);
+			snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
+					    0x00);
+			snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
+					    0x10);
+		} else {
+			tabla_disable_irq(codec->control_data,
+					  TABLA_IRQ_HPH_PA_OCPR_FAULT);
+			tabla->hphrocp_cnt = 0;
+			tabla->hph_status |= SND_JACK_OC_HPHR;
+			if (tabla->headset_jack)
+				tabla_snd_soc_jack_report(tabla,
+							  tabla->headset_jack,
+							  tabla->hph_status,
+							  TABLA_JACK_MASK);
 		}
 	} else {
 		pr_err("%s: Bad tabla private data\n", __func__);
@@ -3301,6 +3428,35 @@
 	return IRQ_HANDLED;
 }
 
+static void tabla_sync_hph_state(struct tabla_priv *tabla)
+{
+	if (test_and_clear_bit(TABLA_HPHR_PA_OFF_ACK,
+			       &tabla->hph_pa_dac_state)) {
+		pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
+		snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x10,
+				    1 << 4);
+	}
+	if (test_and_clear_bit(TABLA_HPHL_PA_OFF_ACK,
+			       &tabla->hph_pa_dac_state)) {
+		pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
+		snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x20,
+				    1 << 5);
+	}
+
+	if (test_and_clear_bit(TABLA_HPHR_DAC_OFF_ACK,
+			       &tabla->hph_pa_dac_state)) {
+		pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
+		snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_R_DAC_CTL,
+				    0xC0, 0xC0);
+	}
+	if (test_and_clear_bit(TABLA_HPHL_DAC_OFF_ACK,
+			       &tabla->hph_pa_dac_state)) {
+		pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
+		snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_L_DAC_CTL,
+				    0xC0, 0xC0);
+	}
+}
+
 static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
 {
 	struct tabla_priv *priv = data;
@@ -3311,9 +3467,10 @@
 	short threshold_fake_insert = 0xFD30;
 	u8 is_removal;
 
-
 	pr_debug("%s\n", __func__);
 	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
+	tabla_lock_sleep(priv);
+
 	is_removal = snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02;
 	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
 
@@ -3359,13 +3516,30 @@
 		if (priv->mbhc_micbias_switched)
 			tabla_codec_switch_micbias(codec, 0);
 		priv->hph_status &= ~SND_JACK_HEADPHONE;
+
+		/* If headphone PA is on, check if userspace receives
+		 * removal event to sync-up PA's state */
+		if (tabla_is_hph_pa_on(codec)) {
+			set_bit(TABLA_HPHL_PA_OFF_ACK, &priv->hph_pa_dac_state);
+			set_bit(TABLA_HPHR_PA_OFF_ACK, &priv->hph_pa_dac_state);
+		}
+
+		if (tabla_is_hph_dac_on(codec, 1))
+			set_bit(TABLA_HPHL_DAC_OFF_ACK,
+				&priv->hph_pa_dac_state);
+		if (tabla_is_hph_dac_on(codec, 0))
+			set_bit(TABLA_HPHR_DAC_OFF_ACK,
+				&priv->hph_pa_dac_state);
+
 		if (priv->headset_jack) {
 			pr_debug("%s: Reporting removal\n", __func__);
-			snd_soc_jack_report(priv->headset_jack,
-				priv->hph_status, TABLA_JACK_MASK);
+			tabla_snd_soc_jack_report(priv, priv->headset_jack,
+						  priv->hph_status,
+						  TABLA_JACK_MASK);
 		}
 		tabla_codec_shutdown_hs_removal_detect(codec);
 		tabla_codec_enable_hs_detect(codec, 1);
+		tabla_unlock_sleep(priv);
 		return IRQ_HANDLED;
 	}
 
@@ -3400,12 +3574,13 @@
 		if (priv->headset_jack) {
 			pr_debug("%s: Reporting insertion %d\n", __func__,
 				SND_JACK_HEADPHONE);
-			snd_soc_jack_report(priv->headset_jack,
-				priv->hph_status, TABLA_JACK_MASK);
+			tabla_snd_soc_jack_report(priv, priv->headset_jack,
+						  priv->hph_status,
+						  TABLA_JACK_MASK);
 		}
 		tabla_codec_shutdown_hs_polling(codec);
 		tabla_codec_enable_hs_detect(codec, 0);
-
+		tabla_sync_hph_state(priv);
 	} else {
 		pr_debug("%s: Headset detected, mic_voltage = %x\n",
 			__func__, mic_voltage);
@@ -3413,12 +3588,15 @@
 		if (priv->headset_jack) {
 			pr_debug("%s: Reporting insertion %d\n", __func__,
 				SND_JACK_HEADSET);
-			snd_soc_jack_report(priv->headset_jack,
-				priv->hph_status,  TABLA_JACK_MASK);
+			tabla_snd_soc_jack_report(priv, priv->headset_jack,
+						  priv->hph_status,
+						  TABLA_JACK_MASK);
 		}
 		tabla_codec_start_hs_polling(codec);
+		tabla_sync_hph_state(priv);
 	}
 
+	tabla_unlock_sleep(priv);
 	return IRQ_HANDLED;
 }
 
@@ -3431,6 +3609,7 @@
 	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
 	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
 	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
+	tabla_lock_sleep(priv);
 
 	usleep_range(priv->calibration->shutdown_plug_removal,
 		priv->calibration->shutdown_plug_removal);
@@ -3452,13 +3631,15 @@
 		priv->hph_status &= ~SND_JACK_HEADSET;
 		if (priv->headset_jack) {
 			pr_debug("%s: Reporting removal\n", __func__);
-			snd_soc_jack_report(priv->headset_jack, 0,
-				 TABLA_JACK_MASK);
+			tabla_snd_soc_jack_report(priv, priv->headset_jack, 0,
+						  TABLA_JACK_MASK);
 		}
 		tabla_codec_shutdown_hs_polling(codec);
 
 		tabla_codec_enable_hs_detect(codec, 1);
 	}
+
+	tabla_unlock_sleep(priv);
 	return IRQ_HANDLED;
 }
 
@@ -3471,6 +3652,8 @@
 	int i, j;
 	u8 val;
 
+	tabla_lock_sleep(priv);
+
 	for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++) {
 		slimbus_value = tabla_interface_reg_read(codec->control_data,
 			TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
@@ -3488,6 +3671,7 @@
 			TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
 	}
 
+	tabla_unlock_sleep(priv);
 	return IRQ_HANDLED;
 }
 
@@ -3667,8 +3851,11 @@
 }
 
 static const struct tabla_reg_mask_val tabla_codec_reg_init_val[] = {
-	/* Initialize current threshold to 350MA */
+	/* Initialize current threshold to 350MA
+	 * number of wait and run cycles to 4096
+	 */
 	{TABLA_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
+	{TABLA_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
 
 	{TABLA_A_QFUSE_CTL, 0xFF, 0x03},
 
@@ -3765,6 +3952,8 @@
 	tabla->codec = codec;
 	tabla->pdata = dev_get_platdata(codec->dev->parent);
 	tabla->intf_type = tabla_get_intf_type();
+	atomic_set(&tabla->pm_cnt, 1);
+	init_waitqueue_head(&tabla->pm_wq);
 
 	tabla_update_reg_defaults(codec);
 	tabla_codec_init_reg(codec);
@@ -3869,6 +4058,7 @@
 			TABLA_IRQ_HPH_PA_OCPL_FAULT);
 		goto err_hphl_ocp_irq;
 	}
+	tabla_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
 
 	ret = tabla_request_irq(codec->control_data,
 		TABLA_IRQ_HPH_PA_OCPR_FAULT, tabla_hphr_ocp_irq,
@@ -3878,6 +4068,7 @@
 			TABLA_IRQ_HPH_PA_OCPR_FAULT);
 		goto err_hphr_ocp_irq;
 	}
+	tabla_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
 
 #ifdef CONFIG_DEBUG_FS
 	debug_tabla_priv = tabla;
@@ -3966,6 +4157,64 @@
 };
 #endif
 
+#ifdef CONFIG_PM
+static int tabla_suspend(struct device *dev)
+{
+	int ret = 0, cnt;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct tabla_priv *tabla = platform_get_drvdata(pdev);
+
+	cnt = atomic_read(&tabla->pm_cnt);
+	if (cnt > 0) {
+		if (wait_event_timeout(tabla->pm_wq,
+				       (atomic_cmpxchg(&tabla->pm_cnt, 1, 0)
+						== 1), 5 * HZ)) {
+			dev_dbg(dev, "system suspend pm_cnt %d\n",
+				atomic_read(&tabla->pm_cnt));
+		} else {
+			dev_err(dev, "%s timed out pm_cnt = %d\n",
+				__func__, atomic_read(&tabla->pm_cnt));
+			WARN_ON_ONCE(1);
+			ret = -EBUSY;
+		}
+	} else if (cnt == 0)
+		dev_warn(dev, "system is already in suspend, pm_cnt %d\n",
+			 atomic_read(&tabla->pm_cnt));
+	else {
+		WARN(1, "unexpected pm_cnt %d\n", cnt);
+		ret = -EFAULT;
+	}
+
+	return ret;
+}
+
+static int tabla_resume(struct device *dev)
+{
+	int ret = 0, cnt;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct tabla_priv *tabla = platform_get_drvdata(pdev);
+
+	cnt = atomic_cmpxchg(&tabla->pm_cnt, 0, 1);
+	if (cnt == 0) {
+		dev_dbg(dev, "system resume, pm_cnt %d\n",
+			atomic_read(&tabla->pm_cnt));
+		wake_up_all(&tabla->pm_wq);
+	} else if (cnt > 0)
+		dev_warn(dev, "system is already awake, pm_cnt %d\n", cnt);
+	else {
+		WARN(1, "unexpected pm_cnt %d\n", cnt);
+		ret = -EFAULT;
+	}
+
+	return ret;
+}
+
+static const struct dev_pm_ops tabla_pm_ops = {
+	.suspend	= tabla_suspend,
+	.resume		= tabla_resume,
+};
+#endif
+
 static int __devinit tabla_probe(struct platform_device *pdev)
 {
 	int ret = 0;
@@ -3997,6 +4246,9 @@
 	.driver = {
 		.name = "tabla_codec",
 		.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm = &tabla_pm_ops,
+#endif
 	},
 };
 
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index 5e02797..4af4f06 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -300,6 +300,11 @@
 	case RT_PROXY_DAI_002_RX:
 		rc = msm_dai_q6_afe_rtproxy_hw_params(params, dai);
 		break;
+	case VOICE_PLAYBACK_TX:
+	case VOICE_RECORD_RX:
+	case VOICE_RECORD_TX:
+		rc = 0;
+		break;
 	default:
 		dev_err(dai->dev, "invalid AFE port ID\n");
 		rc = -EINVAL;
@@ -343,7 +348,18 @@
 	int rc = 0;
 
 	if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
-		rc = afe_close(dai->id); /* can block */
+		switch (dai->id) {
+		case VOICE_PLAYBACK_TX:
+		case VOICE_RECORD_TX:
+		case VOICE_RECORD_RX:
+			pr_debug("%s, stop pseudo port:%d\n",
+						__func__,  dai->id);
+			rc = afe_stop_pseudo_port(dai->id);
+			break;
+		default:
+			rc = afe_close(dai->id); /* can block */
+			break;
+		}
 		if (IS_ERR_VALUE(rc))
 			dev_err(dai->dev, "fail to close AFE port\n");
 		pr_debug("%s: dai_data->status_mask = %ld\n", __func__,
@@ -478,8 +494,17 @@
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
-			afe_port_start_nowait(dai->id, &dai_data->port_config,
-				dai_data->rate);
+			switch (dai->id) {
+			case VOICE_PLAYBACK_TX:
+			case VOICE_RECORD_TX:
+			case VOICE_RECORD_RX:
+				afe_pseudo_port_start_nowait(dai->id);
+				break;
+			default:
+				afe_port_start_nowait(dai->id,
+					&dai_data->port_config, dai_data->rate);
+				break;
+			}
 			set_bit(STATUS_PORT_STARTED,
 				dai_data->status_mask);
 		}
@@ -488,7 +513,16 @@
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
-			afe_port_stop_nowait(dai->id);
+			switch (dai->id) {
+			case VOICE_PLAYBACK_TX:
+			case VOICE_RECORD_TX:
+			case VOICE_RECORD_RX:
+				afe_pseudo_port_stop_nowait(dai->id);
+				break;
+			default:
+				afe_port_stop_nowait(dai->id);
+				break;
+			}
 			clear_bit(STATUS_PORT_STARTED,
 				dai_data->status_mask);
 		}
@@ -586,7 +620,17 @@
 
 	/* If AFE port is still up, close it */
 	if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
-		rc = afe_close(dai->id); /* can block */
+		switch (dai->id) {
+		case VOICE_PLAYBACK_TX:
+		case VOICE_RECORD_TX:
+		case VOICE_RECORD_RX:
+			pr_debug("%s, stop pseudo port:%d\n",
+						__func__,  dai->id);
+			rc = afe_stop_pseudo_port(dai->id);
+			break;
+		default:
+			rc = afe_close(dai->id); /* can block */
+		}
 		if (IS_ERR_VALUE(rc))
 			dev_err(dai->dev, "fail to close AFE port\n");
 		clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
@@ -705,6 +749,21 @@
 	.remove = msm_dai_q6_dai_remove,
 };
 
+static struct snd_soc_dai_driver msm_dai_q6_voice_playback_tx_dai = {
+	.playback = {
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+		SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 2,
+		.rate_max =     48000,
+		.rate_min =     8000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
 static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai = {
 	.playback = {
 		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
@@ -735,6 +794,21 @@
 	.remove = msm_dai_q6_dai_remove,
 };
 
+static struct snd_soc_dai_driver msm_dai_q6_incall_record_dai = {
+	.capture = {
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+		SNDRV_PCM_RATE_16000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		.channels_min = 1,
+		.channels_max = 2,
+		.rate_min =     8000,
+		.rate_max =     48000,
+	},
+	.ops = &msm_dai_q6_ops,
+	.probe = msm_dai_q6_dai_probe,
+	.remove = msm_dai_q6_dai_remove,
+};
+
 static struct snd_soc_dai_driver msm_dai_q6_bt_sco_rx_dai = {
 	.playback = {
 		.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
@@ -872,6 +946,15 @@
 	case RT_PROXY_DAI_002_TX:
 		rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_tx_dai);
 		break;
+	case VOICE_PLAYBACK_TX:
+		rc = snd_soc_register_dai(&pdev->dev,
+					&msm_dai_q6_voice_playback_tx_dai);
+		break;
+	case VOICE_RECORD_RX:
+	case VOICE_RECORD_TX:
+		rc = snd_soc_register_dai(&pdev->dev,
+						&msm_dai_q6_incall_record_dai);
+		break;
 	default:
 		rc = -ENODEV;
 		break;
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 9a076d6..453bce4 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -114,6 +114,9 @@
 	{ RT_PROXY_PORT_001_TX, 0, NULL, 0, 0},
 	{ PCM_RX, 0, NULL, 0, 0},
 	{ PCM_TX, 0, NULL, 0, 0},
+	{ VOICE_PLAYBACK_TX, 0, NULL, 0, 0},
+	{ VOICE_RECORD_RX, 0, NULL, 0, 0},
+	{ VOICE_RECORD_TX, 0, NULL, 0, 0},
 };
 
 
@@ -259,6 +262,10 @@
 	mutex_lock(&routing_lock);
 
 	if (set) {
+		if (!test_bit(val, &msm_bedais[reg].fe_sessions) &&
+			(msm_bedais[reg].port_id == VOICE_PLAYBACK_TX))
+			voc_start_playback(set);
+
 		set_bit(val, &msm_bedais[reg].fe_sessions);
 		if (msm_bedais[reg].active && fe_dai_map[val][session_type] !=
 			INVALID_SESSION) {
@@ -270,6 +277,9 @@
 				fe_dai_map[val][session_type], path_type);
 		}
 	} else {
+		if (test_bit(val, &msm_bedais[reg].fe_sessions) &&
+			(msm_bedais[reg].port_id == VOICE_PLAYBACK_TX))
+			voc_start_playback(set);
 		clear_bit(val, &msm_bedais[reg].fe_sessions);
 		if (msm_bedais[reg].active && fe_dai_map[val][session_type] !=
 			INVALID_SESSION) {
@@ -278,6 +288,9 @@
 				fe_dai_map[val][session_type], path_type);
 		}
 	}
+	if ((msm_bedais[reg].port_id == VOICE_RECORD_RX)
+			|| (msm_bedais[reg].port_id == VOICE_RECORD_TX))
+		voc_start_record(msm_bedais[reg].port_id, set);
 
 	mutex_unlock(&routing_lock);
 }
@@ -683,6 +696,15 @@
 	MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
 	msm_routing_put_audio_mixer),
 };
+	/* incall music delivery mixer */
+static const struct snd_kcontrol_new incall_music_delivery_mixer_controls[] = {
+	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+	MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+	msm_routing_put_audio_mixer),
+};
 
 static const struct snd_kcontrol_new int_bt_sco_rx_mixer_controls[] = {
 	SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_INT_BT_SCO_RX,
@@ -763,6 +785,12 @@
 	SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
 		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
 		msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX,
+		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+		msm_routing_put_audio_mixer),
+	SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX,
+		MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+		msm_routing_put_audio_mixer),
 };
 
 static const struct snd_kcontrol_new mmul2_mixer_controls[] = {
@@ -1103,6 +1131,13 @@
 	SND_SOC_DAPM_AIF_OUT("PCM_RX", "AFE Playback",
 				0, 0, 0 , 0),
 	SND_SOC_DAPM_AIF_IN("PCM_TX", "AFE Capture",
+				0, 0, 0 , 0),
+	/* incall */
+	SND_SOC_DAPM_AIF_OUT("VOICE_PLAYBACK_TX", "Voice Farend Playback",
+				0, 0, 0 , 0),
+	SND_SOC_DAPM_AIF_IN("INCALL_RECORD_TX", "Voice Uplink Capture",
+				0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("INCALL_RECORD_RX", "Voice Downlink Capture",
 				0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("AUX_PCM_RX", "AUX PCM Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("AUX_PCM_TX", "AUX PCM Capture", 0, 0, 0, 0),
@@ -1122,6 +1157,10 @@
 	mmul2_mixer_controls, ARRAY_SIZE(mmul2_mixer_controls)),
 	SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
 	auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
+	/* incall */
+	SND_SOC_DAPM_MIXER("Incall_Music Audio Mixer", SND_SOC_NOPM, 0, 0,
+			incall_music_delivery_mixer_controls,
+			ARRAY_SIZE(incall_music_delivery_mixer_controls)),
 	/* Voice Mixer */
 	SND_SOC_DAPM_MIXER("PRI_RX_Voice Mixer",
 				SND_SOC_NOPM, 0, 0, pri_rx_voice_mixer_controls,
@@ -1182,6 +1221,14 @@
 	{"HDMI Mixer", "MultiMedia4", "MM_DL4"},
 	{"HDMI", NULL, "HDMI Mixer"},
 
+		/* incall */
+	{"Incall_Music Audio Mixer", "MultiMedia1", "MM_DL1"},
+	{"Incall_Music Audio Mixer", "MultiMedia2", "MM_DL2"},
+	{"VOICE_PLAYBACK_TX", NULL, "Incall_Music Audio Mixer"},
+
+	{"MultiMedia1 Mixer", "VOC_REC_UL", "INCALL_RECORD_TX"},
+	{"MultiMedia1 Mixer", "VOC_REC_DL", "INCALL_RECORD_RX"},
+
 	{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
 	{"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
 	{"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index b3a8210..2020939 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -26,6 +26,10 @@
 #define LPASS_BE_AFE_PCM_TX "(Backend) RT_PROXY_DAI_002_TX"
 #define LPASS_BE_AUXPCM_RX "(Backend) AUX_PCM_RX"
 #define LPASS_BE_AUXPCM_TX "(Backend) AUX_PCM_TX"
+#define LPASS_BE_VOICE_PLAYBACK_TX "(Backend) VOICE_PLAYBACK_TX"
+#define LPASS_BE_INCALL_RECORD_RX "(Backend) INCALL_RECORD_TX"
+#define LPASS_BE_INCALL_RECORD_TX "(Backend) INCALL_RECORD_RX"
+
 
 /* For multimedia front-ends, asm session is allocated dynamically.
  * Hence, asm session/multimedia front-end mapping has to be maintained.
@@ -62,6 +66,9 @@
 	MSM_BACKEND_DAI_AFE_PCM_TX,
 	MSM_BACKEND_DAI_AUXPCM_RX,
 	MSM_BACKEND_DAI_AUXPCM_TX,
+	MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+	MSM_BACKEND_DAI_INCALL_RECORD_RX,
+	MSM_BACKEND_DAI_INCALL_RECORD_TX,
 	MSM_BACKEND_DAI_MAX,
 };
 
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index d3f02a9..2e98627 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -1061,6 +1061,45 @@
 		.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
 		.be_hw_params_fixup = msm8960_auxpcm_be_params_fixup,
 	},
+	/* Incall Music BACK END DAI Link */
+	{
+		.name = LPASS_BE_VOICE_PLAYBACK_TX,
+		.stream_name = "Voice Farend Playback",
+		.cpu_dai_name = "msm-dai-q6.32773",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.no_codec = 1,
+		.be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+		.be_hw_params_fixup = msm8960_be_hw_params_fixup,
+	},
+	/* Incall Record Uplink BACK END DAI Link */
+	{
+		.name = LPASS_BE_INCALL_RECORD_TX,
+		.stream_name = "Voice Uplink Capture",
+		.cpu_dai_name = "msm-dai-q6.32772",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.no_codec = 1,
+		.be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
+		.be_hw_params_fixup = msm8960_be_hw_params_fixup,
+	},
+	/* Incall Record Downlink BACK END DAI Link */
+	{
+		.name = LPASS_BE_INCALL_RECORD_RX,
+		.stream_name = "Voice Downlink Capture",
+		.cpu_dai_name = "msm-dai-q6.32771",
+		.platform_name = "msm-pcm-routing",
+		.codec_name     = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-tx",
+		.no_pcm = 1,
+		.no_codec = 1,
+		.be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
+		.be_hw_params_fixup = msm8960_be_hw_params_fixup,
+	},
 };
 
 struct snd_soc_card snd_soc_card_msm8960 = {
@@ -1126,7 +1165,7 @@
 {
 	int ret;
 
-	if (!cpu_is_msm8960()) {
+	if (!cpu_is_msm8960() && !cpu_is_msm8930()) {
 		pr_err("%s: Not the right machine type\n", __func__);
 		return -ENODEV ;
 	}
@@ -1156,7 +1195,7 @@
 
 static void __exit msm8960_audio_exit(void)
 {
-	if (!cpu_is_msm8960()) {
+	if (!cpu_is_msm8960() && !cpu_is_msm8930()) {
 		pr_err("%s: Not the right machine type\n", __func__);
 		return ;
 	}
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index ee6116a..68cb2b4 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -130,16 +130,18 @@
 	return 0;
 }
 
-void send_cal(int port_id, struct acdb_cal_block *aud_cal)
+int send_adm_cal_block(int port_id, struct acdb_cal_block *aud_cal)
 {
-	s32				result;
+	s32				result = 0;
 	struct adm_set_params_command	adm_params;
 	int index = afe_get_port_index(port_id);
 
 	pr_debug("%s: Port id %d, index %d\n", __func__, port_id, index);
 
 	if (!aud_cal || aud_cal->cal_size == 0) {
-		pr_err("%s: No calibration data to send!\n", __func__);
+		pr_debug("%s: No ADM cal to send for port_id = %d!\n",
+			__func__, port_id);
+		result = -EINVAL;
 		goto done;
 	}
 
@@ -165,17 +167,23 @@
 	if (result < 0) {
 		pr_err("%s: Set params failed port = %d payload = 0x%x\n",
 			__func__, port_id, aud_cal->cal_paddr);
+		result = -EINVAL;
 		goto done;
 	}
 	/* Wait for the callback */
 	result = wait_event_timeout(this_adm.wait,
 		atomic_read(&this_adm.copp_stat[index]),
 		msecs_to_jiffies(TIMEOUT_MS));
-	if (!result)
+	if (!result) {
 		pr_err("%s: Set params timed out port = %d, payload = 0x%x\n",
 			__func__, port_id, aud_cal->cal_paddr);
+		result = -EINVAL;
+		goto done;
+	}
+
+	result = 0;
 done:
-	return;
+	return result;
 }
 
 void send_adm_cal(int port_id, int path)
@@ -187,22 +195,24 @@
 
 	/* Maps audio_dev_ctrl path definition to ACDB definition */
 	acdb_path = path - 1;
-	if ((acdb_path >= NUM_AUDPROC_BUFFERS) ||
-		(acdb_path < 0)) {
-		pr_err("%s: Path is not RX or TX, path = %d\n",
-			__func__, path);
-		goto done;
-	}
 
 	pr_debug("%s: Sending audproc cal\n", __func__);
 	get_audproc_cal(acdb_path, &aud_cal);
-	send_cal(port_id, &aud_cal);
+	if (!send_adm_cal_block(port_id, &aud_cal))
+		pr_info("%s: Audproc cal sent for port id: %d, path %d\n",
+			__func__, port_id, acdb_path);
+	else
+		pr_info("%s: Audproc cal not sent for port id: %d, path %d\n",
+			__func__, port_id, acdb_path);
 
 	pr_debug("%s: Sending audvol cal\n", __func__);
 	get_audvol_cal(acdb_path, &aud_cal);
-	send_cal(port_id, &aud_cal);
-done:
-	return;
+	if (!send_adm_cal_block(port_id, &aud_cal))
+		pr_info("%s: Audvol cal sent for port id: %d, path %d\n",
+			__func__, port_id, acdb_path);
+	else
+		pr_info("%s: Audvol cal not sent for port id: %d, path %d\n",
+			__func__, port_id, acdb_path);
 }
 
 int adm_open(int port_id, int path, int rate, int channel_mode, int topology)
@@ -263,7 +273,9 @@
 			if ((open.topology_id ==
 				VPM_TX_SM_ECNS_COPP_TOPOLOGY) ||
 			    (open.topology_id ==
-				VPM_TX_DM_FLUENCE_COPP_TOPOLOGY))
+				VPM_TX_DM_FLUENCE_COPP_TOPOLOGY) ||
+			    (open.topology_id ==
+				VPM_TX_QMIC_FLUENCE_COPP_TOPOLOGY))
 				rate = 16000;
 		}
 
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
index 017c1b6..21bbcf2 100644
--- a/sound/soc/msm/qdsp6/q6afe.c
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -677,6 +677,39 @@
 fail_cmd:
 	return ret;
 }
+
+int afe_pseudo_port_start_nowait(u16 port_id)
+{
+	int ret = 0;
+	struct afe_pseudoport_start_command start;
+
+	pr_debug("%s: port_id=%d\n", __func__, port_id);
+	if (this_afe.apr == NULL) {
+		pr_err("%s: AFE APR is not registered\n", __func__);
+		return -ENODEV;
+	}
+
+
+	start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	start.hdr.pkt_size = sizeof(start);
+	start.hdr.src_port = 0;
+	start.hdr.dest_port = 0;
+	start.hdr.token = 0;
+	start.hdr.opcode = AFE_PSEUDOPORT_CMD_START;
+	start.port_id = port_id;
+	start.timing = 1;
+
+	atomic_set(&this_afe.state, 1);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
+	if (ret < 0) {
+		pr_err("%s: AFE enable for port %d failed %d\n",
+		       __func__, port_id, ret);
+		return -EINVAL;
+	}
+	return 0;
+}
+
 int afe_start_pseudo_port(u16 port_id)
 {
 	int ret = 0;
@@ -703,8 +736,7 @@
 	if (ret < 0) {
 		pr_err("%s: AFE enable for port %d failed %d\n",
 		       __func__, port_id, ret);
-		ret = -EINVAL;
-		return ret;
+		return -EINVAL;
 	}
 
 	ret = wait_event_timeout(this_afe.wait,
@@ -712,24 +744,22 @@
 				 msecs_to_jiffies(TIMEOUT_MS));
 	if (!ret) {
 		pr_err("%s: wait_event timeout\n", __func__);
-		ret = -EINVAL;
-		return ret;
+		return -EINVAL;
 	}
 
 	return 0;
 }
 
-int afe_stop_pseudo_port(u16 port_id)
+int afe_pseudo_port_stop_nowait(u16 port_id)
 {
 	int ret = 0;
 	struct afe_pseudoport_stop_command stop;
 
-	pr_info("%s: port_id=%d\n", __func__, port_id);
+	pr_debug("%s: port_id=%d\n", __func__, port_id);
 
 	if (this_afe.apr == NULL) {
 		pr_err("%s: AFE is already closed\n", __func__);
-		ret = -EINVAL;
-		return ret;
+		return -EINVAL;
 	}
 
 	stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -746,8 +776,40 @@
 	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
 	if (ret < 0) {
 		pr_err("%s: AFE close failed %d\n", __func__, ret);
-		ret = -EINVAL;
-		return ret;
+		return -EINVAL;
+	}
+
+	return 0;
+
+}
+
+int afe_stop_pseudo_port(u16 port_id)
+{
+	int ret = 0;
+	struct afe_pseudoport_stop_command stop;
+
+	pr_info("%s: port_id=%d\n", __func__, port_id);
+
+	if (this_afe.apr == NULL) {
+		pr_err("%s: AFE is already closed\n", __func__);
+		return -EINVAL;
+	}
+
+	stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	stop.hdr.pkt_size = sizeof(stop);
+	stop.hdr.src_port = 0;
+	stop.hdr.dest_port = 0;
+	stop.hdr.token = 0;
+	stop.hdr.opcode = AFE_PSEUDOPORT_CMD_STOP;
+	stop.port_id = port_id;
+	stop.reserved = 0;
+
+	atomic_set(&this_afe.state, 1);
+	ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
+	if (ret < 0) {
+		pr_err("%s: AFE close failed %d\n", __func__, ret);
+		return -EINVAL;
 	}
 
 	ret = wait_event_timeout(this_afe.wait,
@@ -755,8 +817,7 @@
 				 msecs_to_jiffies(TIMEOUT_MS));
 	if (!ret) {
 		pr_err("%s: wait_event timeout\n", __func__);
-		ret = -EINVAL;
-		return ret;
+		return -EINVAL;
 	}
 
 	return 0;
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index c899b2a..de63fa0 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -54,6 +54,10 @@
 static int voice_send_set_widevoice_enable_cmd(struct voice_data *v);
 static int voice_send_set_slowtalk_enable_cmd(struct voice_data *v);
 
+static int voice_cvs_stop_playback(struct voice_data *v);
+static int voice_cvs_start_playback(struct voice_data *v);
+static int voice_cvs_start_record(struct voice_data *v, uint32_t rec_mode);
+static int voice_cvs_stop_record(struct voice_data *v);
 
 static int32_t qdsp_mvm_callback(struct apr_client_data *data, void *priv);
 static int32_t qdsp_cvs_callback(struct apr_client_data *data, void *priv);
@@ -1919,6 +1923,14 @@
 	if (is_voip_session(v->session_id))
 		voice_send_netid_timing_cmd(v);
 
+	/* Start in-call music delivery if this feature is enabled */
+	if (v->music_info.play_enable)
+		voice_cvs_start_playback(v);
+
+	/* Start in-call recording if this feature is enabled */
+	if (v->rec_info.rec_enable)
+		voice_cvs_start_record(v, v->rec_info.rec_mode);
+
 	rtac_add_voice(voice_get_cvs_handle(v),
 		voice_get_cvp_handle(v),
 		v->dev_rx.port_id, v->dev_tx.port_id,
@@ -2150,6 +2162,10 @@
 	mvm_handle = voice_get_mvm_handle(v);
 	cvp_handle = voice_get_cvp_handle(v);
 
+	/* stop playback or recording */
+	v->music_info.force = 1;
+	voice_cvs_stop_playback(v);
+	voice_cvs_stop_record(v);
 	/* send stop voice cmd */
 	voice_send_stop_voice_cmd(v);
 
@@ -2322,6 +2338,423 @@
 	return 0;
 }
 
+static int voice_cvs_start_record(struct voice_data *v, uint32_t rec_mode)
+{
+	int ret = 0;
+	void *apr_cvs;
+	u16 cvs_handle;
+
+	struct cvs_start_record_cmd cvs_start_record;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_cvs = common.apr_q6_cvs;
+
+	if (!apr_cvs) {
+		pr_err("%s: apr_cvs is NULL.\n", __func__);
+		return -EINVAL;
+	}
+
+	cvs_handle = voice_get_cvs_handle(v);
+
+	if (!v->rec_info.recording) {
+		cvs_start_record.hdr.hdr_field = APR_HDR_FIELD(
+					APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE),
+					APR_PKT_VER);
+		cvs_start_record.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				  sizeof(cvs_start_record) - APR_HDR_SIZE);
+		cvs_start_record.hdr.src_port = v->session_id;
+		cvs_start_record.hdr.dest_port = cvs_handle;
+		cvs_start_record.hdr.token = 0;
+		cvs_start_record.hdr.opcode = VSS_ISTREAM_CMD_START_RECORD;
+
+		if (rec_mode == VOC_REC_UPLINK) {
+			cvs_start_record.rec_mode.rx_tap_point =
+						VSS_TAP_POINT_NONE;
+			cvs_start_record.rec_mode.tx_tap_point =
+						VSS_TAP_POINT_STREAM_END;
+		} else if (rec_mode == VOC_REC_DOWNLINK) {
+			cvs_start_record.rec_mode.rx_tap_point =
+						VSS_TAP_POINT_STREAM_END;
+			cvs_start_record.rec_mode.tx_tap_point =
+						VSS_TAP_POINT_NONE;
+		} else if (rec_mode == VOC_REC_BOTH) {
+			cvs_start_record.rec_mode.rx_tap_point =
+						VSS_TAP_POINT_STREAM_END;
+			cvs_start_record.rec_mode.tx_tap_point =
+						VSS_TAP_POINT_STREAM_END;
+		} else {
+			pr_err("%s: Invalid in-call rec_mode %d\n", __func__,
+				rec_mode);
+
+			ret = -EINVAL;
+			goto fail;
+		}
+
+		v->cvs_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_start_record);
+		if (ret < 0) {
+			pr_err("%s: Error %d sending START_RECORD\n", __func__,
+				ret);
+
+			goto fail;
+		}
+
+		ret = wait_event_timeout(v->cvs_wait,
+				 (v->cvs_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+
+			goto fail;
+		}
+		v->rec_info.recording = 1;
+	} else {
+		pr_debug("%s: Start record already sent\n", __func__);
+	}
+
+	return 0;
+
+fail:
+	return ret;
+}
+
+static int voice_cvs_stop_record(struct voice_data *v)
+{
+	int ret = 0;
+	void *apr_cvs;
+	u16 cvs_handle;
+	struct apr_hdr cvs_stop_record;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_cvs = common.apr_q6_cvs;
+
+	if (!apr_cvs) {
+		pr_err("%s: apr_cvs is NULL.\n", __func__);
+		return -EINVAL;
+	}
+
+	cvs_handle = voice_get_cvs_handle(v);
+
+	if (v->rec_info.recording) {
+		cvs_stop_record.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				  APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+		cvs_stop_record.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				  sizeof(cvs_stop_record) - APR_HDR_SIZE);
+		cvs_stop_record.src_port = v->session_id;
+		cvs_stop_record.dest_port = cvs_handle;
+		cvs_stop_record.token = 0;
+		cvs_stop_record.opcode = VSS_ISTREAM_CMD_STOP_RECORD;
+
+		v->cvs_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_stop_record);
+		if (ret < 0) {
+			pr_err("%s: Error %d sending STOP_RECORD\n",
+				__func__, ret);
+
+			goto fail;
+		}
+
+		ret = wait_event_timeout(v->cvs_wait,
+				 (v->cvs_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+
+			goto fail;
+		}
+		v->rec_info.recording = 0;
+	} else {
+		pr_debug("%s: Stop record already sent\n", __func__);
+	}
+
+	return 0;
+
+fail:
+
+	return ret;
+}
+
+int voc_start_record(uint32_t port_id, uint32_t set)
+{
+	int ret = 0;
+	int rec_mode = 0;
+	u16 cvs_handle;
+	int i, rec_set = 0;
+
+	for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+		struct voice_data *v = &common.voice[i];
+		pr_debug("%s: i:%d port_id: %d, set: %d\n",
+			__func__, i, port_id, set);
+
+		mutex_lock(&v->lock);
+		rec_mode = v->rec_info.rec_mode;
+		rec_set = set;
+		if (set) {
+			if ((v->rec_route_state.ul_flag != 0) &&
+				(v->rec_route_state.dl_flag != 0)) {
+				pr_debug("%s: i=%d, rec mode already set.\n",
+					__func__, i);
+				mutex_unlock(&v->lock);
+				if (i < MAX_VOC_SESSIONS)
+					continue;
+				else
+					return 0;
+			}
+
+			if (port_id == VOICE_RECORD_TX) {
+				if ((v->rec_route_state.ul_flag == 0)
+				&& (v->rec_route_state.dl_flag == 0)) {
+					rec_mode = VOC_REC_UPLINK;
+					v->rec_route_state.ul_flag = 1;
+				} else if ((v->rec_route_state.ul_flag == 0)
+					&& (v->rec_route_state.dl_flag != 0)) {
+					voice_cvs_stop_record(v);
+					rec_mode = VOC_REC_BOTH;
+					v->rec_route_state.ul_flag = 1;
+				}
+			} else if (port_id == VOICE_RECORD_RX) {
+				if ((v->rec_route_state.ul_flag == 0)
+					&& (v->rec_route_state.dl_flag == 0)) {
+					rec_mode = VOC_REC_DOWNLINK;
+					v->rec_route_state.dl_flag = 1;
+				} else if ((v->rec_route_state.ul_flag != 0)
+					&& (v->rec_route_state.dl_flag == 0)) {
+					voice_cvs_stop_record(v);
+					rec_mode = VOC_REC_BOTH;
+					v->rec_route_state.dl_flag = 1;
+				}
+			}
+			rec_set = 1;
+		} else {
+			if ((v->rec_route_state.ul_flag == 0) &&
+				(v->rec_route_state.dl_flag == 0)) {
+				pr_debug("%s: i=%d, rec already stops.\n",
+					__func__, i);
+				mutex_unlock(&v->lock);
+				if (i < MAX_VOC_SESSIONS)
+					continue;
+				else
+					return 0;
+			}
+
+			if (port_id == VOICE_RECORD_TX) {
+				if ((v->rec_route_state.ul_flag != 0)
+					&& (v->rec_route_state.dl_flag == 0)) {
+					v->rec_route_state.ul_flag = 0;
+					rec_set = 0;
+				} else if ((v->rec_route_state.ul_flag != 0)
+					&& (v->rec_route_state.dl_flag != 0)) {
+					voice_cvs_stop_record(v);
+					v->rec_route_state.ul_flag = 0;
+					rec_mode = VOC_REC_DOWNLINK;
+					rec_set = 1;
+				}
+			} else if (port_id == VOICE_RECORD_RX) {
+				if ((v->rec_route_state.ul_flag == 0)
+					&& (v->rec_route_state.dl_flag != 0)) {
+					v->rec_route_state.dl_flag = 0;
+					rec_set = 0;
+				} else if ((v->rec_route_state.ul_flag != 0)
+					&& (v->rec_route_state.dl_flag != 0)) {
+					voice_cvs_stop_record(v);
+					v->rec_route_state.dl_flag = 0;
+					rec_mode = VOC_REC_UPLINK;
+					rec_set = 1;
+				}
+			}
+		}
+		pr_debug("%s: i=%d, mode =%d, set =%d\n", __func__,
+			i, rec_mode, rec_set);
+		cvs_handle = voice_get_cvs_handle(v);
+
+		if (cvs_handle != 0) {
+			if (rec_set)
+				ret = voice_cvs_start_record(v, rec_mode);
+			else
+				ret = voice_cvs_stop_record(v);
+		}
+
+		/* Cache the value */
+		v->rec_info.rec_enable = rec_set;
+		v->rec_info.rec_mode = rec_mode;
+
+		mutex_unlock(&v->lock);
+	}
+
+	return ret;
+}
+
+static int voice_cvs_start_playback(struct voice_data *v)
+{
+	int ret = 0;
+	struct apr_hdr cvs_start_playback;
+	void *apr_cvs;
+	u16 cvs_handle;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_cvs = common.apr_q6_cvs;
+
+	if (!apr_cvs) {
+		pr_err("%s: apr_cvs is NULL.\n", __func__);
+		return -EINVAL;
+	}
+
+	cvs_handle = voice_get_cvs_handle(v);
+
+	if (!v->music_info.playing && v->music_info.count) {
+		cvs_start_playback.hdr_field = APR_HDR_FIELD(
+					APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE),
+					APR_PKT_VER);
+		cvs_start_playback.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(cvs_start_playback) - APR_HDR_SIZE);
+		cvs_start_playback.src_port = v->session_id;
+		cvs_start_playback.dest_port = cvs_handle;
+		cvs_start_playback.token = 0;
+		cvs_start_playback.opcode = VSS_ISTREAM_CMD_START_PLAYBACK;
+
+		v->cvs_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_start_playback);
+
+		if (ret < 0) {
+			pr_err("%s: Error %d sending START_PLAYBACK\n",
+				__func__, ret);
+
+			goto fail;
+		}
+
+		ret = wait_event_timeout(v->cvs_wait,
+				 (v->cvs_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+
+			goto fail;
+		}
+
+		v->music_info.playing = 1;
+	} else {
+		pr_debug("%s: Start playback already sent\n", __func__);
+	}
+
+	return 0;
+
+fail:
+	return ret;
+}
+
+static int voice_cvs_stop_playback(struct voice_data *v)
+{
+	 int ret = 0;
+	 struct apr_hdr cvs_stop_playback;
+	 void *apr_cvs;
+	 u16 cvs_handle;
+
+	if (v == NULL) {
+		pr_err("%s: v is NULL\n", __func__);
+		return -EINVAL;
+	}
+	apr_cvs = common.apr_q6_cvs;
+
+	if (!apr_cvs) {
+		pr_err("%s: apr_cvs is NULL.\n", __func__);
+		return -EINVAL;
+	}
+
+	cvs_handle = voice_get_cvs_handle(v);
+
+	if (v->music_info.playing && ((!v->music_info.count) ||
+						(v->music_info.force))) {
+		cvs_stop_playback.hdr_field =
+				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+		cvs_stop_playback.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(cvs_stop_playback) - APR_HDR_SIZE);
+		cvs_stop_playback.src_port = v->session_id;
+		cvs_stop_playback.dest_port = cvs_handle;
+		cvs_stop_playback.token = 0;
+
+		cvs_stop_playback.opcode = VSS_ISTREAM_CMD_STOP_PLAYBACK;
+
+		v->cvs_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_stop_playback);
+		if (ret < 0) {
+			pr_err("%s: Error %d sending STOP_PLAYBACK\n",
+			       __func__, ret);
+
+
+			goto fail;
+		}
+
+		ret = wait_event_timeout(v->cvs_wait,
+					 (v->cvs_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+
+			goto fail;
+		}
+
+		v->music_info.playing = 0;
+		v->music_info.force = 0;
+	} else {
+		pr_debug("%s: Stop playback already sent\n", __func__);
+	}
+
+	return 0;
+
+fail:
+	return ret;
+}
+
+int voc_start_playback(uint32_t set)
+{
+	int ret = 0;
+	u16 cvs_handle;
+	int i;
+
+
+	for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+		struct voice_data *v = &common.voice[i];
+
+		mutex_lock(&v->lock);
+		v->music_info.play_enable = set;
+		if (set)
+			v->music_info.count++;
+		else
+			v->music_info.count--;
+		pr_debug("%s: music_info count =%d\n", __func__,
+			v->music_info.count);
+
+		cvs_handle = voice_get_cvs_handle(v);
+		if (cvs_handle != 0) {
+			if (set)
+				ret = voice_cvs_start_playback(v);
+			else
+				ret = voice_cvs_stop_playback(v);
+		}
+
+		mutex_unlock(&v->lock);
+	}
+
+	return ret;
+}
+
 int voc_disable_cvp(uint16_t session_id)
 {
 	struct voice_data *v = voice_get_session(session_id);
@@ -2937,6 +3370,10 @@
 			case VSS_ICOMMON_CMD_MAP_MEMORY:
 			case VSS_ICOMMON_CMD_UNMAP_MEMORY:
 			case VSS_ICOMMON_CMD_SET_UI_PROPERTY:
+			case VSS_ISTREAM_CMD_START_PLAYBACK:
+			case VSS_ISTREAM_CMD_STOP_PLAYBACK:
+			case VSS_ISTREAM_CMD_START_RECORD:
+			case VSS_ISTREAM_CMD_STOP_RECORD:
 				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
 				v->cvs_state = CMD_STATUS_SUCCESS;
 				wake_up(&v->cvs_wait);
diff --git a/sound/soc/msm/qdsp6/q6voice.h b/sound/soc/msm/qdsp6/q6voice.h
index edde0aa..d330ada 100644
--- a/sound/soc/msm/qdsp6/q6voice.h
+++ b/sound/soc/msm/qdsp6/q6voice.h
@@ -17,6 +17,10 @@
 #define MAX_VOC_PKT_SIZE 642
 #define SESSION_NAME_LEN 20
 
+#define VOC_REC_UPLINK		0x00
+#define VOC_REC_DOWNLINK	0x01
+#define VOC_REC_BOTH		0x02
+
 struct voice_header {
 	uint32_t id;
 	uint32_t data_len;
@@ -43,6 +47,11 @@
 	u16 tx_route_flag;
 };
 
+struct voice_rec_route_state {
+	u16 ul_flag;
+	u16 dl_flag;
+};
+
 enum {
 	VOC_INIT = 0,
 	VOC_RUN,
@@ -318,6 +327,36 @@
 #define VOICE_PARAM_MOD_ENABLE				0x00010E00
 #define MOD_ENABLE_PARAM_LEN				4
 
+#define VSS_ISTREAM_CMD_START_PLAYBACK                  0x00011238
+/* Start in-call music delivery on the Tx voice path. */
+
+#define VSS_ISTREAM_CMD_STOP_PLAYBACK                   0x00011239
+/* Stop the in-call music delivery on the Tx voice path. */
+
+#define VSS_ISTREAM_CMD_START_RECORD                    0x00011236
+/* Start in-call conversation recording. */
+#define VSS_ISTREAM_CMD_STOP_RECORD                     0x00011237
+/* Stop in-call conversation recording. */
+
+#define VSS_TAP_POINT_NONE                              0x00010F78
+/* Indicates no tapping for specified path. */
+
+#define VSS_TAP_POINT_STREAM_END                        0x00010F79
+/* Indicates that specified path should be tapped at the end of the stream. */
+
+struct vss_istream_cmd_start_record_t {
+	uint32_t rx_tap_point;
+	/* Tap point to use on the Rx path. Supported values are:
+	 * VSS_TAP_POINT_NONE : Do not record Rx path.
+	 * VSS_TAP_POINT_STREAM_END : Rx tap point is at the end of the stream.
+	 */
+	uint32_t tx_tap_point;
+	/* Tap point to use on the Tx path. Supported values are:
+	 * VSS_TAP_POINT_NONE : Do not record tx path.
+	 * VSS_TAP_POINT_STREAM_END : Tx tap point is at the end of the stream.
+	 */
+} __packed;
+
 struct vss_istream_cmd_create_passive_control_session_t {
 	char name[SESSION_NAME_LEN];
 	/**<
@@ -538,6 +577,10 @@
 	struct apr_hdr hdr;
 	struct vss_icommon_cmd_set_ui_property_st_enable_t vss_set_st;
 } __packed;
+struct cvs_start_record_cmd {
+	struct apr_hdr hdr;
+	struct vss_istream_cmd_start_record_t rec_mode;
+} __packed;
 
 /* TO CVP commands */
 
@@ -747,13 +790,16 @@
 };
 
 struct incall_rec_info {
-	uint32_t pending;
+	uint32_t rec_enable;
 	uint32_t rec_mode;
+	uint32_t recording;
 };
 
 struct incall_music_info {
-	uint32_t pending;
+	uint32_t play_enable;
 	uint32_t playing;
+	int count;
+	int force;
 };
 
 struct voice_data {
@@ -790,6 +836,12 @@
 	struct voice_dev_route_state voc_route_state;
 
 	u16 session_id;
+
+	struct incall_rec_info rec_info;
+
+	struct incall_music_info music_info;
+
+	struct voice_rec_route_state rec_route_state;
 };
 
 #define MAX_VOC_SESSIONS 2
@@ -856,4 +908,6 @@
 #define VOIP_SESSION_NAME "VoIP session"
 uint16_t voc_get_session_id(char *name);
 
+int voc_start_playback(uint32_t set);
+int voc_start_record(uint32_t port_id, uint32_t set);
 #endif