Merge "msm: clock-rpm: Fix branch clocks so that they can be enabled" into msm-3.4
diff --git a/arch/arm/boot/dts/msmcopper.dtsi b/arch/arm/boot/dts/msmcopper.dtsi
index a37f4ff..79d6814 100644
--- a/arch/arm/boot/dts/msmcopper.dtsi
+++ b/arch/arm/boot/dts/msmcopper.dtsi
@@ -274,7 +274,7 @@
 
 	qcom,ssusb@F9200000 {
 		compatible = "qcom,dwc-usb3-msm";
-		reg = <0xF9200000 0xCCFF>;
+		reg = <0xF9200000 0xFA000>;
 		interrupts = <0 131 0>;
 		SSUSB_VDDCX-supply = <&pm8841_s2>;
 		SSUSB_1p8-supply = <&pm8941_l6>;
@@ -296,6 +296,53 @@
 		qcom,firmware-name = "adsp";
 	};
 
+        qcom,msm-pcm {
+                compatible = "qcom,msm-pcm-dsp";
+        };
+
+        qcom,msm-pcm-routing {
+                compatible = "qcom,msm-pcm-routing";
+        };
+
+        qcom,msm-pcm-lpa {
+                compatible = "qcom,msm-pcm-lpa";
+        };
+
+        qcom,msm-voip-dsp {
+                compatible = "qcom,msm-voip-dsp";
+        };
+
+        qcom,msm-stub-codec {
+                compatible = "qcom,msm-stub-codec";
+        };
+
+        qcom,msm-dai-fe {
+                compatible = "qcom,msm-dai-fe";
+        };
+
+        qcom,msm-dai-q6 {
+                compatible = "qcom,msm-dai-q6";
+                qcom,msm-cpudai-auxpcm-clk = "pcm_clk";
+                qcom,msm-cpudai-auxpcm-mode = <0>;
+                qcom,msm-cpudai-auxpcm-sync = <1>;
+                qcom,msm-cpudai-auxpcm-frame = <5>;
+                qcom,msm-cpudai-auxpcm-quant = <2>;
+                qcom,msm-cpudai-auxpcm-slot = <1>;
+                qcom,msm-cpudai-auxpcm-data = <0>;
+                qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>;
+
+                qcom,msm-dai-q6-rx {
+                        qcom,msm-dai-q6-id = <4106>;
+                };
+                qcom,msm-dai-q6-tx {
+                        qcom,msm-dai-q6-id = <4107>;
+                };
+        };
+
+        qcom,msm-pcm-hostless {
+                compatible = "qcom,msm-pcm-hostless";
+        };
+
 	qcom,mss@fc880000 {
 		compatible = "qcom,pil-q6v5-mss";
 		reg = <0xfc880000 0x100>,
@@ -345,4 +392,18 @@
 	qcom,qseecom@fe806000 {
 		compatible = "qcom,qseecom";
 	};
+
+	qcom,mdss_mdp@fd900000 {
+		cell-index = <0>;
+		compatible = "qcom,mdss_mdp";
+		reg = <0xfd900000 0x22100>;
+		interrupts = <0 72 0>;
+	};
+
+	qcom,mdss_wb_panel {
+		cell-index = <1>;
+		compatible = "qcom,mdss_wb";
+		qcom,mdss_pan_res = <640 480>;
+		qcom,mdss_pan_bpp = <24>;
+	};
 };
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 174a799..b14ecf8 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -1062,9 +1062,11 @@
 	return 0;
 }
 #endif
-/* before calling this function the interrupts should be disabled
- * and the irq must be disabled at gic to avoid spurious interrupts */
-bool gic_is_spi_pending(unsigned int irq)
+/*
+ * Before calling this function the interrupts should be disabled
+ * and the irq must be disabled at gic to avoid spurious interrupts
+ */
+bool gic_is_irq_pending(unsigned int irq)
 {
 	struct irq_data *d = irq_get_irq_data(irq);
 	struct gic_chip_data *gic_data = &gic_data[0];
@@ -1083,9 +1085,11 @@
 	return (bool) (val & mask);
 }
 
-/* before calling this function the interrupts should be disabled
- * and the irq must be disabled at gic to avoid spurious interrupts */
-void gic_clear_spi_pending(unsigned int irq)
+/*
+ * Before calling this function the interrupts should be disabled
+ * and the irq must be disabled at gic to avoid spurious interrupts
+ */
+void gic_clear_irq_pending(unsigned int irq)
 {
 	struct gic_chip_data *gic_data = &gic_data[0];
 	struct irq_data *d = irq_get_irq_data(irq);
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
index f6764d4..78ab155 100644
--- a/arch/arm/configs/msm-copper_defconfig
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -155,7 +155,14 @@
 CONFIG_ION=y
 CONFIG_ION_MSM=y
 CONFIG_FB=y
-CONFIG_FB_VIRTUAL=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
 # CONFIG_HID_SUPPORT is not set
 CONFIG_USB_GADGET=y
 CONFIG_USB_CI13XXX_MSM=y
@@ -168,8 +175,6 @@
 # CONFIG_MMC_BLOCK_BOUNCE is not set
 CONFIG_MMC_TEST=m
 CONFIG_MMC_MSM=y
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
 CONFIG_SWITCH=y
 CONFIG_STAGING=y
 CONFIG_ANDROID=y
@@ -221,3 +226,7 @@
 CONFIG_CRYPTO_DEFLATE=y
 CONFIG_CRC_CCITT=y
 CONFIG_LIBCRC32C=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_MSM8974=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 362b4b2..57e644d 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -389,6 +389,7 @@
 CONFIG_USB_EHCI_EHSET=y
 CONFIG_USB_EHCI_MSM=y
 CONFIG_USB_EHCI_MSM_HSIC=y
+CONFIG_USB_EHCI_MSM_HOST4=y
 CONFIG_USB_ACM=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_STORAGE_DEBUG=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 8f4937a..ca8a909 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -392,6 +392,7 @@
 CONFIG_USB_EHCI_EHSET=y
 CONFIG_USB_EHCI_MSM=y
 CONFIG_USB_EHCI_MSM_HSIC=y
+CONFIG_USB_EHCI_MSM_HOST4=y
 CONFIG_USB_ACM=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_STORAGE_DEBUG=y
diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h
index 3fb0a1c..3783ff3 100644
--- a/arch/arm/include/asm/hardware/gic.h
+++ b/arch/arm/include/asm/hardware/gic.h
@@ -46,6 +46,8 @@
 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);
+bool gic_is_irq_pending(unsigned int irq);
+void gic_clear_irq_pending(unsigned int irq);
 #ifdef CONFIG_ARM_GIC
 void gic_set_irq_secure(unsigned int irq);
 #else
@@ -56,8 +58,6 @@
 {
 	gic_init_bases(nr, start, dist, cpu, 0);
 }
-bool gic_is_spi_pending(unsigned int irq);
-void gic_clear_spi_pending(unsigned int irq);
 void gic_set_irq_secure(unsigned int irq);
 #endif
 
diff --git a/arch/arm/include/asm/mach/mmc.h b/arch/arm/include/asm/mach/mmc.h
index a6ec7b2..4bcbfc2 100644
--- a/arch/arm/include/asm/mach/mmc.h
+++ b/arch/arm/include/asm/mach/mmc.h
@@ -148,7 +148,7 @@
 	bool nonremovable;
 	unsigned int mpm_sdiowakeup_int;
 	unsigned int wpswitch_gpio;
-	unsigned char wpswitch_polarity;
+	bool is_wpswitch_active_low;
 	struct msm_mmc_slot_reg_data *vreg_data;
 	int is_sdio_al_client;
 	unsigned int *sup_clk_table;
diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h
index 2fecc60..a40f81e 100644
--- a/arch/arm/include/asm/perf_event.h
+++ b/arch/arm/include/asm/perf_event.h
@@ -25,7 +25,9 @@
 	ARM_PERF_PMU_ID_CA7,
 	ARM_PERF_PMU_ID_SCORPION,
 	ARM_PERF_PMU_ID_SCORPIONMP,
+	ARM_PERF_PMU_ID_SCORPIONMP_L2,
 	ARM_PERF_PMU_ID_KRAIT,
+	ARM_PERF_PMU_ID_KRAIT_L2,
 	ARM_NUM_PMU_IDS,
 };
 
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index 1e54b58..37cbfcb 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -21,7 +21,7 @@
  */
 enum arm_pmu_type {
 	ARM_PMU_DEVICE_CPU	= 0,
-	ARM_PMU_DEVICE_L2	= 1,
+	ARM_PMU_DEVICE_L2CC	= 1,
 	ARM_NUM_PMU_DEVICES,
 };
 
@@ -129,11 +129,13 @@
 	u64		max_period;
 	struct platform_device	*plat_device;
 	struct pmu_hw_events	*(*get_hw_events)(void);
+	int	(*test_set_event_constraints)(struct perf_event *event);
+	int	(*clear_event_constraints)(struct perf_event *event);
 };
 
 #define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu))
 
-int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type);
+int armpmu_register(struct arm_pmu *armpmu, char *name, int type);
 
 u64 armpmu_event_update(struct perf_event *event,
 			struct hw_perf_event *hwc,
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index af6e7e6..e37b28b 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -28,6 +28,8 @@
 #include <asm/pmu.h>
 #include <asm/stacktrace.h>
 
+#include <linux/cpu_pm.h>
+
 /*
  * ARMv6 supports a maximum of 3 events, starting from index 0. If we add
  * another platform that supports more, we need to increase this to be the
@@ -271,6 +273,10 @@
 	hw_events->events[idx] = NULL;
 	clear_bit(idx, hw_events->used_mask);
 
+	/* Clear event constraints. */
+	if (armpmu->clear_event_constraints)
+		armpmu->clear_event_constraints(event);
+
 	perf_event_update_userpage(event);
 }
 
@@ -284,6 +290,17 @@
 	int err = 0;
 
 	perf_pmu_disable(event->pmu);
+	/*
+	 * Tests if event is constrained. If not sets it so that next
+	 * collision can be detected.
+	 */
+	if (armpmu->test_set_event_constraints)
+		if (armpmu->test_set_event_constraints(event) < 0) {
+			pr_err("Event: %llx failed constraint check.\n",
+					event->attr.config);
+			event->state = PERF_EVENT_STATE_OFF;
+			goto out;
+		}
 
 	/* If we don't have a space for the counter then finish early. */
 	idx = armpmu->get_event_idx(hw_events, hwc);
@@ -383,10 +400,7 @@
 {
 	int i, irq, irqs;
 	struct platform_device *pmu_device = armpmu->plat_device;
-#if 0
-	struct arm_pmu_platdata *plat =
-		dev_get_platdata(&pmu_device->dev);
-#endif
+
 	irqs = min(pmu_device->num_resources, num_possible_cpus());
 
 	for (i = 0; i < irqs; ++i) {
@@ -394,13 +408,6 @@
 			continue;
 		irq = platform_get_irq(pmu_device, i);
 		armpmu->free_pmu_irq(irq);
-#if 0
-		if (irq >= 0) {
-			if (plat && plat->disable_irq)
-				plat->disable_irq(irq);
-			free_irq(irq, armpmu);
-		}
-#endif
 	}
 
 	release_pmu(armpmu->type);
@@ -462,19 +469,6 @@
                         return err;
                 }
 
-#if 0
-		err = request_irq(irq, handle_irq,
-				  IRQF_DISABLED | IRQF_NOBALANCING,
-				  "arm-pmu", armpmu);
-		if (err) {
-			pr_err("unable to request IRQ%d for ARM PMU counters\n",
-				irq);
-			armpmu_release_hardware(armpmu);
-			return err;
-		} else if (plat && plat->enable_irq)
-			plat->enable_irq(irq);
-#endif
-
 		cpumask_set_cpu(i, &armpmu->active_irqs);
 	}
 
@@ -538,6 +532,7 @@
 		return -EPERM;
 	}
 
+
 	/*
 	 * Store the event encoding into the config_base field.
 	 */
@@ -616,7 +611,7 @@
 	armpmu->stop();
 }
 
-static void __init armpmu_init(struct arm_pmu *armpmu)
+static void armpmu_init(struct arm_pmu *armpmu)
 {
 	atomic_set(&armpmu->active_events, 0);
 	mutex_init(&armpmu->reserve_mutex);
@@ -633,7 +628,7 @@
 	};
 }
 
-int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type)
+int armpmu_register(struct arm_pmu *armpmu, char *name, int type)
 {
 	armpmu_init(armpmu);
 	return perf_pmu_register(&armpmu->pmu, name, type);
@@ -644,6 +639,7 @@
 #include "perf_event_v6.c"
 #include "perf_event_v7.c"
 #include "perf_event_msm_krait.c"
+#include "perf_event_msm.c"
 
 /*
  * Ensure the PMU has sane values out of reset.
@@ -734,10 +730,76 @@
 	return NOTIFY_OK;
 }
 
+static void armpmu_update_counters(void)
+{
+	struct pmu_hw_events *hw_events;
+	int idx;
+
+	if (!cpu_pmu)
+		return;
+
+	hw_events = cpu_pmu->get_hw_events();
+
+	for (idx = 0; idx <= cpu_pmu->num_events; ++idx) {
+		struct perf_event *event = hw_events->events[idx];
+
+		if (!event)
+			continue;
+
+		armpmu_read(event);
+	}
+}
+
+static int cpu_has_active_perf(void)
+{
+	struct pmu_hw_events *hw_events;
+	int enabled;
+
+	if (!cpu_pmu)
+		return 0;
+
+	hw_events = cpu_pmu->get_hw_events();
+	enabled = bitmap_weight(hw_events->used_mask, cpu_pmu->num_events);
+
+	if (enabled)
+		/*Even one event's existence is good enough.*/
+		return 1;
+
+	return 0;
+}
+
 static struct notifier_block __cpuinitdata pmu_cpu_notifier = {
 	.notifier_call = pmu_cpu_notify,
 };
 
+/*TODO: Unify with pending patch from ARM */
+static int perf_cpu_pm_notifier(struct notifier_block *self, unsigned long cmd,
+		void *v)
+{
+	switch (cmd) {
+	case CPU_PM_ENTER:
+		if (cpu_has_active_perf()) {
+			armpmu_update_counters();
+			perf_pmu_disable(&cpu_pmu->pmu);
+		}
+		break;
+
+	case CPU_PM_ENTER_FAILED:
+	case CPU_PM_EXIT:
+		if (cpu_has_active_perf() && cpu_pmu->reset) {
+			cpu_pmu->reset(NULL);
+			perf_pmu_enable(&cpu_pmu->pmu);
+		}
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block perf_cpu_pm_notifier_block = {
+	.notifier_call = perf_cpu_pm_notifier,
+};
+
 /*
  * CPU PMU identification and registration.
  */
@@ -790,11 +852,11 @@
 	} else if (0x51 == implementor) {
 		switch (part_number) {
 		case 0x00F0:    /* 8x50 & 7x30*/
-//			cpu_pmu = armv7_scorpion_pmu_init();
+			cpu_pmu = armv7_scorpion_pmu_init();
 			break;
 		case 0x02D0:    /* 8x60 */
 //			fabricmon_pmu_init();
-//			cpu_pmu = armv7_scorpionmp_pmu_init();
+			cpu_pmu = armv7_scorpionmp_pmu_init();
 //			scorpionmp_l2_pmu_init();
 			break;
 		case 0x0490:    /* 8960 sim */
@@ -814,6 +876,7 @@
 		cpu_pmu_init(cpu_pmu);
 		register_cpu_notifier(&pmu_cpu_notifier);
 		armpmu_register(cpu_pmu, "cpu", PERF_TYPE_RAW);
+		cpu_pm_register_notifier(&perf_cpu_pm_notifier_block);
 	} else {
 		pr_info("no hardware support available\n");
 	}
diff --git a/arch/arm/kernel/perf_event_msm.c b/arch/arm/kernel/perf_event_msm.c
index 0ca5164..46fa8fe 100644
--- a/arch/arm/kernel/perf_event_msm.c
+++ b/arch/arm/kernel/perf_event_msm.c
@@ -12,7 +12,7 @@
  */
 
 #include <linux/cpumask.h>
-
+#include <asm/cp15.h>
 #include <asm/vfp.h>
 #include <asm/system.h>
 #include "../vfp/vfpinstr.h"
@@ -143,12 +143,16 @@
 		 * combined.
 		 */
 		[C(OP_READ)] = {
-			[C(RESULT_ACCESS)]	= ARMV7_PERFCTR_DCACHE_ACCESS,
-			[C(RESULT_MISS)]	= ARMV7_PERFCTR_DCACHE_REFILL,
+			[C(RESULT_ACCESS)]
+					= ARMV7_PERFCTR_L1_DCACHE_ACCESS,
+			[C(RESULT_MISS)]
+					= ARMV7_PERFCTR_L1_DCACHE_REFILL,
 		},
 		[C(OP_WRITE)] = {
-			[C(RESULT_ACCESS)]	= ARMV7_PERFCTR_DCACHE_ACCESS,
-			[C(RESULT_MISS)]	= ARMV7_PERFCTR_DCACHE_REFILL,
+			[C(RESULT_ACCESS)]
+					= ARMV7_PERFCTR_L1_DCACHE_ACCESS,
+			[C(RESULT_MISS)]
+					= ARMV7_PERFCTR_L1_DCACHE_REFILL,
 		},
 		[C(OP_PREFETCH)] = {
 			[C(RESULT_ACCESS)]	= CACHE_OP_UNSUPPORTED,
@@ -236,6 +240,13 @@
 	},
 };
 
+static int msm_scorpion_map_event(struct perf_event *event)
+{
+	return map_cpu_event(event, &armv7_scorpion_perf_map,
+			&armv7_scorpion_perf_cache_map, 0xfffff);
+}
+
+
 struct scorpion_evt {
 	/*
 	 * The scorpion_evt_type field corresponds to the actual Scorpion
@@ -483,9 +494,9 @@
 	u32 v_orig_val;
 	u32 f_orig_val;
 
-	/* CPACR Enable CP10 access */
+	/* CPACR Enable CP10 and CP11 access */
 	v_orig_val = get_copro_access();
-	venum_new_val = v_orig_val | CPACC_SVC(10);
+	venum_new_val = v_orig_val | CPACC_SVC(10) | CPACC_SVC(11);
 	set_copro_access(venum_new_val);
 	/* Store orig venum val */
 	__get_cpu_var(venum_orig_val) = v_orig_val;
@@ -551,17 +562,13 @@
 
 static void scorpion_clear_pmuregs(void)
 {
-	unsigned long flags;
-
 	scorpion_write_lpm0(0);
 	scorpion_write_lpm1(0);
 	scorpion_write_lpm2(0);
 	scorpion_write_l2lpm(0);
-	raw_spin_lock_irqsave(&pmu_lock, flags);
 	scorpion_pre_vlpm();
 	scorpion_write_vlpm(0);
 	scorpion_post_vlpm();
-	raw_spin_unlock_irqrestore(&pmu_lock, flags);
 }
 
 static void scorpion_clearpmu(u32 grp, u32 val, u32 evt_code)
@@ -585,9 +592,11 @@
 	u32 gr;
 	unsigned long event;
 	struct scorpion_evt evtinfo;
+	struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+
 
 	/* Disable counter and interrupt */
-	raw_spin_lock_irqsave(&pmu_lock, flags);
+	raw_spin_lock_irqsave(&events->pmu_lock, flags);
 
 	/* Disable counter */
 	armv7_pmnc_disable_counter(idx);
@@ -596,7 +605,7 @@
 	 * Clear lpm code (if destined for PMNx counters)
 	 * We don't need to set the event if it's a cycle count
 	 */
-	if (idx != ARMV7_CYCLE_COUNTER) {
+	if (idx != ARMV7_IDX_CYCLE_COUNTER) {
 		val = hwc->config_base;
 		val &= SCORPION_EVTYPE_EVENT;
 
@@ -613,10 +622,11 @@
 	armv7_pmnc_disable_intens(idx);
 
 scorpion_dis_out:
-	raw_spin_unlock_irqrestore(&pmu_lock, flags);
+	raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
 }
 
-static void scorpion_pmu_enable_event(struct hw_perf_event *hwc, int idx)
+static void scorpion_pmu_enable_event(struct hw_perf_event *hwc,
+		int idx, int cpu)
 {
 	unsigned long flags;
 	u32 val = 0;
@@ -624,12 +634,13 @@
 	unsigned long event;
 	struct scorpion_evt evtinfo;
 	unsigned long long prev_count = local64_read(&hwc->prev_count);
+	struct pmu_hw_events *events = cpu_pmu->get_hw_events();
 
 	/*
 	 * Enable counter and interrupt, and set the counter to count
 	 * the event that we're interested in.
 	 */
-	raw_spin_lock_irqsave(&pmu_lock, flags);
+	raw_spin_lock_irqsave(&events->pmu_lock, flags);
 
 	/* Disable counter */
 	armv7_pmnc_disable_counter(idx);
@@ -638,7 +649,7 @@
 	 * Set event (if destined for PMNx counters)
 	 * We don't need to set the event if it's a cycle count
 	 */
-	if (idx != ARMV7_CYCLE_COUNTER) {
+	if (idx != ARMV7_IDX_CYCLE_COUNTER) {
 		val = hwc->config_base;
 		val &= SCORPION_EVTYPE_EVENT;
 
@@ -673,59 +684,12 @@
 	armv7_pmnc_enable_counter(idx);
 
 scorpion_out:
-	raw_spin_unlock_irqrestore(&pmu_lock, flags);
-}
-
-static void enable_irq_callback(void *info)
-{
-	int irq = *(unsigned int *)info;
-
-	enable_percpu_irq(irq, IRQ_TYPE_EDGE_RISING);
-}
-
-static void disable_irq_callback(void *info)
-{
-	int irq = *(unsigned int *)info;
-
-	disable_percpu_irq(irq);
-}
-
-static int
-msm_request_irq(int irq, irq_handler_t *handle_irq)
-{
-	int err = 0;
-	int cpu;
-
-	err = request_percpu_irq(irq, *handle_irq, "armpmu",
-			&cpu_hw_events);
-
-	if (!err) {
-		for_each_cpu(cpu, cpu_online_mask) {
-			smp_call_function_single(cpu,
-					enable_irq_callback, &irq, 1);
-		}
-	}
-
-	return err;
-}
-
-static void
-msm_free_irq(int irq)
-{
-	int cpu;
-
-	if (irq >= 0) {
-		for_each_cpu(cpu, cpu_online_mask) {
-			smp_call_function_single(cpu,
-					disable_irq_callback, &irq, 1);
-		}
-		free_percpu_irq(irq, &cpu_hw_events);
-	}
+	raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
 }
 
 static void scorpion_pmu_reset(void *info)
 {
-	u32 idx, nb_cnt = armpmu->num_events;
+	u32 idx, nb_cnt = cpu_pmu->num_events;
 
 	/* Stop all counters and their interrupts */
 	for (idx = 1; idx < nb_cnt; ++idx) {
@@ -751,7 +715,7 @@
 	.disable		= scorpion_pmu_disable_event,
 	.read_counter		= armv7pmu_read_counter,
 	.write_counter		= armv7pmu_write_counter,
-	.raw_event_mask		= 0xFFFFF,
+	.map_event		= msm_scorpion_map_event,
 	.get_event_idx		= armv7pmu_get_event_idx,
 	.start			= armv7pmu_start,
 	.stop			= armv7pmu_stop,
@@ -759,33 +723,29 @@
 	.max_period		= (1LLU << 32) - 1,
 };
 
-static const struct arm_pmu *__init armv7_scorpion_pmu_init(void)
+static struct arm_pmu *__init armv7_scorpion_pmu_init(void)
 {
 	scorpion_pmu.id		= ARM_PERF_PMU_ID_SCORPION;
 	scorpion_pmu.name	= "ARMv7 Scorpion";
-	scorpion_pmu.cache_map	= &armv7_scorpion_perf_cache_map;
-	scorpion_pmu.event_map	= &armv7_scorpion_perf_map;
 	scorpion_pmu.num_events	= armv7_read_num_pmnc_events();
 	scorpion_clear_pmuregs();
 	return &scorpion_pmu;
 }
 
-static const struct arm_pmu *__init armv7_scorpionmp_pmu_init(void)
+static struct arm_pmu *__init armv7_scorpionmp_pmu_init(void)
 {
 	scorpion_pmu.id		= ARM_PERF_PMU_ID_SCORPIONMP;
 	scorpion_pmu.name	= "ARMv7 Scorpion-MP";
-	scorpion_pmu.cache_map	= &armv7_scorpion_perf_cache_map;
-	scorpion_pmu.event_map	= &armv7_scorpion_perf_map;
 	scorpion_pmu.num_events	= armv7_read_num_pmnc_events();
 	scorpion_clear_pmuregs();
 	return &scorpion_pmu;
 }
 #else
-static const struct arm_pmu *__init armv7_scorpion_pmu_init(void)
+static struct arm_pmu *__init armv7_scorpion_pmu_init(void)
 {
 	return NULL;
 }
-static const struct arm_pmu *__init armv7_scorpionmp_pmu_init(void)
+static struct arm_pmu *__init armv7_scorpionmp_pmu_init(void)
 {
 	return NULL;
 }
diff --git a/arch/arm/kernel/perf_event_msm_krait.c b/arch/arm/kernel/perf_event_msm_krait.c
index 8dbd047..1b115b4 100644
--- a/arch/arm/kernel/perf_event_msm_krait.c
+++ b/arch/arm/kernel/perf_event_msm_krait.c
@@ -58,6 +58,17 @@
 static u32 krait_ver, evt_index;
 static u32 krait_max_l1_reg;
 
+
+/*
+ * Every 4 bytes represents a prefix.
+ * Every nibble represents a register.
+ * Every bit represents a group within a register.
+ *
+ * This supports up to 4 groups per register, upto 8
+ * registers per prefix and upto 2 prefixes.
+ */
+static DEFINE_PER_CPU(u64, pmu_bitmap);
+
 static const unsigned armv7_krait_perf_map[PERF_COUNT_HW_MAX] = {
 	[PERF_COUNT_HW_CPU_CYCLES]	    = ARMV7_PERFCTR_CPU_CYCLES,
 	[PERF_COUNT_HW_INSTRUCTIONS]	    = ARMV7_PERFCTR_INSTR_EXECUTED,
@@ -556,6 +567,58 @@
         }
 }
 
+/*
+ * We check for column exclusion constraints here.
+ * Two events cant have same reg and same group.
+ */
+static int msm_test_set_ev_constraint(struct perf_event *event)
+{
+	u32 krait_evt_type = event->attr.config & KRAIT_EVENT_MASK;
+	u8 prefix = (krait_evt_type & 0xF0000) >> 16;
+	u8 reg = (krait_evt_type & 0x0F000) >> 12;
+	u8 group = krait_evt_type & 0x0000F;
+	u64 cpu_pmu_bitmap = __get_cpu_var(pmu_bitmap);
+	u64 bitmap_t;
+
+	/* Return if non MSM event. */
+	if (!prefix)
+		return 0;
+
+	bitmap_t = 1 << (((prefix - 1) * 32) + (reg * 4) + group);
+
+	/* Set it if not already set. */
+	if (!(cpu_pmu_bitmap & bitmap_t)) {
+		cpu_pmu_bitmap |= bitmap_t;
+		__get_cpu_var(pmu_bitmap) = cpu_pmu_bitmap;
+		return 1;
+	}
+	/* Bit is already set. Constraint failed. */
+	return -EPERM;
+}
+
+static int msm_clear_ev_constraint(struct perf_event *event)
+{
+	u32 krait_evt_type = event->attr.config & KRAIT_EVENT_MASK;
+	u8 prefix = (krait_evt_type & 0xF0000) >> 16;
+	u8 reg = (krait_evt_type & 0x0F000) >> 12;
+	u8 group = krait_evt_type & 0x0000F;
+	u64 cpu_pmu_bitmap = __get_cpu_var(pmu_bitmap);
+	u64 bitmap_t;
+
+	/* Return if non MSM event. */
+	if (!prefix)
+		return 0;
+
+	bitmap_t = 1 << (((prefix - 1) * 32) + (reg * 4) + group);
+
+	/* Clear constraint bit. */
+	cpu_pmu_bitmap &= ~(bitmap_t);
+
+	__get_cpu_var(pmu_bitmap) = cpu_pmu_bitmap;
+
+	return 1;
+}
+
 static struct arm_pmu krait_pmu = {
 	.handle_irq		= armv7pmu_handle_irq,
 	.request_pmu_irq	= msm_request_irq,
@@ -568,6 +631,8 @@
 	.start			= armv7pmu_start,
 	.stop			= armv7pmu_stop,
 	.reset			= krait_pmu_reset,
+	.test_set_event_constraints	= msm_test_set_ev_constraint,
+	.clear_event_constraints	= msm_clear_ev_constraint,
 	.max_period		= (1LLU << 32) - 1,
 };
 
diff --git a/arch/arm/kernel/perf_event_msm_krait_l2.c b/arch/arm/kernel/perf_event_msm_krait_l2.c
deleted file mode 100644
index baa05ac..0000000
--- a/arch/arm/kernel/perf_event_msm_krait_l2.c
+++ /dev/null
@@ -1,667 +0,0 @@
-/*
- * 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
- * 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.
- */
-#ifdef CONFIG_ARCH_MSM_KRAIT
-
-#include <linux/irq.h>
-
-#include <mach/msm-krait-l2-accessors.h>
-
-#define MAX_L2_PERIOD	((1ULL << 32) - 1)
-#define MAX_KRAIT_L2_CTRS 5
-
-#define L2PMCCNTR 0x409
-#define L2PMCCNTCR 0x408
-#define L2PMCCNTSR 0x40A
-#define L2CYCLE_CTR_BIT 31
-#define L2CYCLE_CTR_EVENT_IDX 4
-#define L2CYCLE_CTR_RAW_CODE 0xfe
-
-#define L2PMOVSR	0x406
-
-#define L2PMCR	0x400
-#define L2PMCR_RESET_ALL	0x6
-#define L2PMCR_GLOBAL_ENABLE	0x1
-#define L2PMCR_GLOBAL_DISABLE	0x0
-
-#define L2PMCNTENSET	0x403
-#define L2PMCNTENCLR	0x402
-
-#define L2PMINTENSET	0x405
-#define L2PMINTENCLR	0x404
-
-#define IA_L2PMXEVCNTCR_BASE	0x420
-#define IA_L2PMXEVTYPER_BASE	0x424
-#define IA_L2PMRESX_BASE	0x410
-#define IA_L2PMXEVFILTER_BASE	0x423
-#define IA_L2PMXEVCNTR_BASE	0x421
-
-/* event format is -e rsRCCG See get_event_desc() */
-
-#define EVENT_REG_MASK		0xf000
-#define EVENT_GROUPSEL_MASK	0x000f
-#define	EVENT_GROUPCODE_MASK	0x0ff0
-#define EVENT_REG_SHIFT		12
-#define EVENT_GROUPCODE_SHIFT	4
-
-#define	RESRX_VALUE_EN	0x80000000
-
-static struct platform_device *l2_pmu_device;
-
-struct hw_krait_l2_pmu {
-	struct perf_event *events[MAX_KRAIT_L2_CTRS];
-	unsigned long active_mask[BITS_TO_LONGS(MAX_KRAIT_L2_CTRS)];
-	raw_spinlock_t lock;
-};
-
-struct hw_krait_l2_pmu hw_krait_l2_pmu;
-
-struct event_desc {
-	int event_groupsel;
-	int event_reg;
-	int event_group_code;
-};
-
-void get_event_desc(u64 config, struct event_desc *evdesc)
-{
-	/* L2PMEVCNTRX */
-	evdesc->event_reg = (config & EVENT_REG_MASK) >> EVENT_REG_SHIFT;
-	/* Group code (row ) */
-	evdesc->event_group_code =
-	    (config & EVENT_GROUPCODE_MASK) >> EVENT_GROUPCODE_SHIFT;
-	/* Group sel (col) */
-	evdesc->event_groupsel = (config & EVENT_GROUPSEL_MASK);
-
-	pr_debug("%s: reg: %x, group_code: %x, groupsel: %x\n", __func__,
-		 evdesc->event_reg, evdesc->event_group_code,
-		 evdesc->event_groupsel);
-}
-
-static void set_evcntcr(int ctr)
-{
-	u32 evtcr_reg = (ctr * 16) + IA_L2PMXEVCNTCR_BASE;
-
-	set_l2_indirect_reg(evtcr_reg, 0x0);
-}
-
-static void set_evtyper(int event_groupsel, int event_reg, int ctr)
-{
-	u32 evtype_reg = (ctr * 16) + IA_L2PMXEVTYPER_BASE;
-	u32 evtype_val = event_groupsel + (4 * event_reg);
-
-	set_l2_indirect_reg(evtype_reg, evtype_val);
-}
-
-static void set_evres(int event_groupsel, int event_reg, int event_group_code)
-{
-	u32 group_reg = event_reg + IA_L2PMRESX_BASE;
-	u32 group_val =
-		RESRX_VALUE_EN | (event_group_code << (8 * event_groupsel));
-	u32 resr_val;
-	u32 group_byte = 0xff;
-	u32 group_mask = ~(group_byte << (8 * event_groupsel));
-
-	resr_val = get_l2_indirect_reg(group_reg);
-	resr_val &= group_mask;
-	resr_val |= group_val;
-
-	set_l2_indirect_reg(group_reg, resr_val);
-}
-
-static void set_evfilter_task_mode(int ctr)
-{
-	u32 filter_reg = (ctr * 16) + IA_L2PMXEVFILTER_BASE;
-	u32 filter_val = 0x000f0030 | 1 << smp_processor_id();
-
-	set_l2_indirect_reg(filter_reg, filter_val);
-}
-
-static void set_evfilter_sys_mode(int ctr)
-{
-	u32 filter_reg = (ctr * 16) + IA_L2PMXEVFILTER_BASE;
-	u32 filter_val = 0x000f003f;
-
-	set_l2_indirect_reg(filter_reg, filter_val);
-}
-
-static void enable_intenset(u32 idx)
-{
-	if (idx == L2CYCLE_CTR_EVENT_IDX)
-		set_l2_indirect_reg(L2PMINTENSET, 1 << L2CYCLE_CTR_BIT);
-	else
-		set_l2_indirect_reg(L2PMINTENSET, 1 << idx);
-}
-
-static void disable_intenclr(u32 idx)
-{
-	if (idx == L2CYCLE_CTR_EVENT_IDX)
-		set_l2_indirect_reg(L2PMINTENCLR, 1 << L2CYCLE_CTR_BIT);
-	else
-		set_l2_indirect_reg(L2PMINTENCLR, 1 << idx);
-}
-
-static void enable_counter(u32 idx)
-{
-	if (idx == L2CYCLE_CTR_EVENT_IDX)
-		set_l2_indirect_reg(L2PMCNTENSET, 1 << L2CYCLE_CTR_BIT);
-	else
-		set_l2_indirect_reg(L2PMCNTENSET, 1 << idx);
-}
-
-static void disable_counter(u32 idx)
-{
-	if (idx == L2CYCLE_CTR_EVENT_IDX)
-		set_l2_indirect_reg(L2PMCNTENCLR, 1 << L2CYCLE_CTR_BIT);
-	else
-		set_l2_indirect_reg(L2PMCNTENCLR, 1 << idx);
-}
-
-static u64 read_counter(u32 idx)
-{
-	u32 val;
-	u32 counter_reg = (idx * 16) + IA_L2PMXEVCNTR_BASE;
-
-	if (idx == L2CYCLE_CTR_EVENT_IDX)
-		val = get_l2_indirect_reg(L2PMCCNTR);
-	else
-		val = get_l2_indirect_reg(counter_reg);
-
-	return val;
-}
-
-static void write_counter(u32 idx, u32 val)
-{
-	u32 counter_reg = (idx * 16) + IA_L2PMXEVCNTR_BASE;
-
-	if (idx == L2CYCLE_CTR_EVENT_IDX)
-		set_l2_indirect_reg(L2PMCCNTR, val);
-	else
-		set_l2_indirect_reg(counter_reg, val);
-}
-
-static int
-pmu_event_set_period(struct perf_event *event,
-		     struct hw_perf_event *hwc, int idx)
-{
-	s64 left = local64_read(&hwc->period_left);
-	s64 period = hwc->sample_period;
-	int ret = 0;
-
-	if (unlikely(left <= -period)) {
-		left = period;
-		local64_set(&hwc->period_left, left);
-		hwc->last_period = period;
-		ret = 1;
-	}
-
-	if (unlikely(left <= 0)) {
-		left += period;
-		local64_set(&hwc->period_left, left);
-		hwc->last_period = period;
-		ret = 1;
-	}
-
-	if (left > (s64) MAX_L2_PERIOD)
-		left = MAX_L2_PERIOD;
-
-	local64_set(&hwc->prev_count, (u64)-left);
-
-	write_counter(idx, (u64) (-left) & 0xffffffff);
-
-	perf_event_update_userpage(event);
-
-	return ret;
-}
-
-static u64
-pmu_event_update(struct perf_event *event, struct hw_perf_event *hwc, int idx,
-		 int overflow)
-{
-	u64 prev_raw_count, new_raw_count;
-	u64 delta;
-
-again:
-	prev_raw_count = local64_read(&hwc->prev_count);
-	new_raw_count = read_counter(idx);
-
-	if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
-			    new_raw_count) != prev_raw_count)
-		goto again;
-
-	new_raw_count &= MAX_L2_PERIOD;
-	prev_raw_count &= MAX_L2_PERIOD;
-
-	if (overflow)
-		delta = MAX_L2_PERIOD - prev_raw_count + new_raw_count;
-	else
-		delta = new_raw_count - prev_raw_count;
-
-	local64_add(delta, &event->count);
-	local64_sub(delta, &hwc->period_left);
-
-	pr_debug("%s: new: %lld, prev: %lld, event: %ld count: %lld\n",
-		 __func__, new_raw_count, prev_raw_count,
-		 hwc->config_base, local64_read(&event->count));
-
-	return new_raw_count;
-}
-
-static void krait_l2_read(struct perf_event *event)
-{
-	struct hw_perf_event *hwc = &event->hw;
-
-	pmu_event_update(event, hwc, hwc->idx, 0);
-}
-
-static void krait_l2_stop_counter(struct perf_event *event, int flags)
-{
-	struct hw_perf_event *hwc = &event->hw;
-	int idx = hwc->idx;
-
-	if (!(hwc->state & PERF_HES_STOPPED)) {
-		disable_intenclr(idx);
-		disable_counter(idx);
-
-		pmu_event_update(event, hwc, idx, 0);
-		hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
-	}
-
-	pr_debug("%s: event: %ld ctr: %d stopped\n", __func__, hwc->config_base,
-		 idx);
-}
-
-static void krait_l2_start_counter(struct perf_event *event, int flags)
-{
-	struct hw_perf_event *hwc = &event->hw;
-	int idx = hwc->idx;
-	struct event_desc evdesc;
-
-	if (flags & PERF_EF_RELOAD)
-		WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
-
-	hwc->state = 0;
-
-	pmu_event_set_period(event, hwc, idx);
-
-	if (hwc->config_base == L2CYCLE_CTR_RAW_CODE)
-		goto out;
-
-	set_evcntcr(idx);
-
-	memset(&evdesc, 0, sizeof(evdesc));
-
-	get_event_desc(hwc->config_base, &evdesc);
-
-	set_evtyper(evdesc.event_groupsel, evdesc.event_reg, idx);
-
-	set_evres(evdesc.event_groupsel, evdesc.event_reg,
-		  evdesc.event_group_code);
-
-	if (event->cpu < 0)
-		set_evfilter_task_mode(idx);
-	else
-		set_evfilter_sys_mode(idx);
-
-out:
-	enable_intenset(idx);
-	enable_counter(idx);
-
-	pr_debug
-	    ("%s: ctr: %d group: %ld group_code: %lld started from cpu:%d\n",
-	     __func__, idx, hwc->config_base, hwc->config, smp_processor_id());
-}
-
-static void krait_l2_del_event(struct perf_event *event, int flags)
-{
-	struct hw_perf_event *hwc = &event->hw;
-	int idx = hwc->idx;
-	unsigned long iflags;
-
-	raw_spin_lock_irqsave(&hw_krait_l2_pmu.lock, iflags);
-
-	clear_bit(idx, (long unsigned int *)(&hw_krait_l2_pmu.active_mask));
-
-	krait_l2_stop_counter(event, PERF_EF_UPDATE);
-	hw_krait_l2_pmu.events[idx] = NULL;
-	hwc->idx = -1;
-
-	raw_spin_unlock_irqrestore(&hw_krait_l2_pmu.lock, iflags);
-
-	pr_debug("%s: event: %ld deleted\n", __func__, hwc->config_base);
-
-	perf_event_update_userpage(event);
-}
-
-static int krait_l2_add_event(struct perf_event *event, int flags)
-{
-	int ctr = 0;
-	struct hw_perf_event *hwc = &event->hw;
-	unsigned long iflags;
-	int err = 0;
-
-	perf_pmu_disable(event->pmu);
-
-	raw_spin_lock_irqsave(&hw_krait_l2_pmu.lock, iflags);
-
-	/* Cycle counter has a resrvd index */
-	if (hwc->config_base == L2CYCLE_CTR_RAW_CODE) {
-		if (hw_krait_l2_pmu.events[L2CYCLE_CTR_EVENT_IDX]) {
-			pr_err("%s: Stale cycle ctr event ptr !\n", __func__);
-			err = -EINVAL;
-			goto out;
-		}
-		hwc->idx = L2CYCLE_CTR_EVENT_IDX;
-		hw_krait_l2_pmu.events[L2CYCLE_CTR_EVENT_IDX] = event;
-		set_bit(L2CYCLE_CTR_EVENT_IDX,
-			(long unsigned int *)&hw_krait_l2_pmu.active_mask);
-		goto skip_ctr_loop;
-	}
-
-	for (ctr = 0; ctr < MAX_KRAIT_L2_CTRS - 1; ctr++) {
-		if (!hw_krait_l2_pmu.events[ctr]) {
-			hwc->idx = ctr;
-			hw_krait_l2_pmu.events[ctr] = event;
-			set_bit(ctr,
-				(long unsigned int *)
-				&hw_krait_l2_pmu.active_mask);
-			break;
-		}
-	}
-
-	if (hwc->idx < 0) {
-		err = -ENOSPC;
-		pr_err("%s: No space for event: %llx!!\n", __func__,
-		       event->attr.config);
-		goto out;
-	}
-
-skip_ctr_loop:
-
-	disable_counter(hwc->idx);
-
-	hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
-
-	if (flags & PERF_EF_START)
-		krait_l2_start_counter(event, PERF_EF_RELOAD);
-
-	perf_event_update_userpage(event);
-
-	pr_debug("%s: event: %ld, ctr: %d added from cpu:%d\n",
-		 __func__, hwc->config_base, hwc->idx, smp_processor_id());
-out:
-	raw_spin_unlock_irqrestore(&hw_krait_l2_pmu.lock, iflags);
-
-	/* Resume the PMU even if this event could not be added */
-	perf_pmu_enable(event->pmu);
-
-	return err;
-}
-
-static void krait_l2_pmu_enable(struct pmu *pmu)
-{
-	isb();
-	set_l2_indirect_reg(L2PMCR, L2PMCR_GLOBAL_ENABLE);
-}
-
-static void krait_l2_pmu_disable(struct pmu *pmu)
-{
-	set_l2_indirect_reg(L2PMCR, L2PMCR_GLOBAL_DISABLE);
-	isb();
-}
-
-u32 get_reset_pmovsr(void)
-{
-	int val;
-
-	val = get_l2_indirect_reg(L2PMOVSR);
-	/* reset it */
-	val &= 0xffffffff;
-	set_l2_indirect_reg(L2PMOVSR, val);
-
-	return val;
-}
-
-static irqreturn_t krait_l2_handle_irq(int irq_num, void *dev)
-{
-	unsigned long pmovsr;
-	struct perf_sample_data data;
-	struct pt_regs *regs;
-	struct perf_event *event;
-	struct hw_perf_event *hwc;
-	int bitp;
-	int idx = 0;
-
-	pmovsr = get_reset_pmovsr();
-
-	if (!(pmovsr & 0xffffffff))
-		return IRQ_NONE;
-
-	regs = get_irq_regs();
-
-	perf_sample_data_init(&data, 0);
-
-	raw_spin_lock(&hw_krait_l2_pmu.lock);
-
-	while (pmovsr) {
-		bitp = __ffs(pmovsr);
-
-		if (bitp == L2CYCLE_CTR_BIT)
-			idx = L2CYCLE_CTR_EVENT_IDX;
-		else
-			idx = bitp;
-
-		event = hw_krait_l2_pmu.events[idx];
-
-		if (!event)
-			goto next;
-
-		if (!test_bit(idx, hw_krait_l2_pmu.active_mask))
-			goto next;
-
-		hwc = &event->hw;
-		pmu_event_update(event, hwc, idx, 1);
-		data.period = event->hw.last_period;
-
-		if (!pmu_event_set_period(event, hwc, idx))
-			goto next;
-
-		if (perf_event_overflow(event, 0, &data, regs))
-			disable_counter(hwc->idx);
-next:
-		pmovsr &= (pmovsr - 1);
-	}
-
-	raw_spin_unlock(&hw_krait_l2_pmu.lock);
-
-	irq_work_run();
-
-	return IRQ_HANDLED;
-}
-
-static atomic_t active_l2_events = ATOMIC_INIT(0);
-static DEFINE_MUTEX(krait_pmu_reserve_mutex);
-
-static int pmu_reserve_hardware(void)
-{
-	int i, err = -ENODEV, irq;
-
-	l2_pmu_device = reserve_pmu(ARM_PMU_DEVICE_L2);
-
-	if (IS_ERR(l2_pmu_device)) {
-		pr_warning("unable to reserve pmu\n");
-		return PTR_ERR(l2_pmu_device);
-	}
-
-	if (l2_pmu_device->num_resources < 1) {
-		pr_err("no irqs for PMUs defined\n");
-		return -ENODEV;
-	}
-
-	if (strncmp(l2_pmu_device->name, "l2-arm-pmu", 6)) {
-		pr_err("Incorrect pdev reserved !\n");
-		return -EINVAL;
-	}
-
-	for (i = 0; i < l2_pmu_device->num_resources; ++i) {
-		irq = platform_get_irq(l2_pmu_device, i);
-		if (irq < 0)
-			continue;
-
-		err = request_irq(irq, krait_l2_handle_irq,
-				  IRQF_DISABLED | IRQF_NOBALANCING,
-				  "krait-l2-pmu", NULL);
-		if (err) {
-			pr_warning("unable to request IRQ%d for Krait L2 perf "
-				   "counters\n", irq);
-			break;
-		}
-
-		irq_get_chip(irq)->irq_unmask(irq_get_irq_data(irq));
-	}
-
-	if (err) {
-		for (i = i - 1; i >= 0; --i) {
-			irq = platform_get_irq(l2_pmu_device, i);
-			if (irq >= 0)
-				free_irq(irq, NULL);
-		}
-		release_pmu(l2_pmu_device);
-		l2_pmu_device = NULL;
-	}
-
-	return err;
-}
-
-static void pmu_release_hardware(void)
-{
-	int i, irq;
-
-	for (i = l2_pmu_device->num_resources - 1; i >= 0; --i) {
-		irq = platform_get_irq(l2_pmu_device, i);
-		if (irq >= 0)
-			free_irq(irq, NULL);
-	}
-
-	krait_l2_pmu_disable(NULL);
-
-	release_pmu(l2_pmu_device);
-	l2_pmu_device = NULL;
-}
-
-static void pmu_perf_event_destroy(struct perf_event *event)
-{
-	if (atomic_dec_and_mutex_lock
-	    (&active_l2_events, &krait_pmu_reserve_mutex)) {
-		pmu_release_hardware();
-		mutex_unlock(&krait_pmu_reserve_mutex);
-	}
-}
-
-static int krait_l2_event_init(struct perf_event *event)
-{
-	int err = 0;
-	struct hw_perf_event *hwc = &event->hw;
-	int status = 0;
-
-	switch (event->attr.type) {
-	case PERF_TYPE_SHARED:
-		break;
-
-	default:
-		return -ENOENT;
-	}
-
-	hwc->idx = -1;
-
-	event->destroy = pmu_perf_event_destroy;
-
-	if (!atomic_inc_not_zero(&active_l2_events)) {
-		/* 0 active events */
-		mutex_lock(&krait_pmu_reserve_mutex);
-		err = pmu_reserve_hardware();
-		mutex_unlock(&krait_pmu_reserve_mutex);
-		if (!err)
-			atomic_inc(&active_l2_events);
-		else
-			return err;
-	}
-
-	hwc->config = 0;
-	hwc->event_base = 0;
-
-	/* Check if we came via perf default syms */
-	if (event->attr.config == PERF_COUNT_HW_L2_CYCLES)
-		hwc->config_base = L2CYCLE_CTR_RAW_CODE;
-	else
-		hwc->config_base = event->attr.config;
-
-	/* Only one CPU can control the cycle counter */
-	if (hwc->config_base == L2CYCLE_CTR_RAW_CODE) {
-		/* Check if its already running */
-		status = get_l2_indirect_reg(L2PMCCNTSR);
-		if (status == 0x2) {
-			err = -ENOSPC;
-			goto out;
-		}
-	}
-
-	if (!hwc->sample_period) {
-		hwc->sample_period = MAX_L2_PERIOD;
-		hwc->last_period = hwc->sample_period;
-		local64_set(&hwc->period_left, hwc->sample_period);
-	}
-
-	pr_debug("%s: event: %lld init'd\n", __func__, event->attr.config);
-
-out:
-	if (err < 0)
-		pmu_perf_event_destroy(event);
-
-	return err;
-}
-
-static struct pmu krait_l2_pmu = {
-	.pmu_enable = krait_l2_pmu_enable,
-	.pmu_disable = krait_l2_pmu_disable,
-	.event_init = krait_l2_event_init,
-	.add = krait_l2_add_event,
-	.del = krait_l2_del_event,
-	.start = krait_l2_start_counter,
-	.stop = krait_l2_stop_counter,
-	.read = krait_l2_read,
-};
-
-static const struct arm_pmu *__init krait_l2_pmu_init(void)
-{
-	/* Register our own PMU here */
-	perf_pmu_register(&krait_l2_pmu, "Krait L2", PERF_TYPE_SHARED);
-
-	memset(&hw_krait_l2_pmu, 0, sizeof(hw_krait_l2_pmu));
-
-	/* Reset all ctrs */
-	set_l2_indirect_reg(L2PMCR, L2PMCR_RESET_ALL);
-
-	/* Avoid spurious interrupt if any */
-	get_reset_pmovsr();
-
-	raw_spin_lock_init(&hw_krait_l2_pmu.lock);
-
-	/* Don't return an arm_pmu here */
-	return NULL;
-}
-#else
-
-static const struct arm_pmu *__init krait_l2_pmu_init(void)
-{
-	return NULL;
-}
-#endif
diff --git a/arch/arm/kernel/perf_event_msm_l2.c b/arch/arm/kernel/perf_event_msm_l2.c
deleted file mode 100644
index 26753d8..0000000
--- a/arch/arm/kernel/perf_event_msm_l2.c
+++ /dev/null
@@ -1,1013 +0,0 @@
-/*
- * 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
- * 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.
- */
-#ifdef CONFIG_ARCH_MSM8X60
-
-#include <linux/irq.h>
-
-#define MAX_BB_L2_PERIOD	((1ULL << 32) - 1)
-#define MAX_BB_L2_CTRS 5
-#define BB_L2CYCLE_CTR_BIT 31
-#define BB_L2CYCLE_CTR_EVENT_IDX 4
-#define BB_L2CYCLE_CTR_RAW_CODE 0xfe
-#define SCORPIONL2_PMNC_E       (1 << 0)	/* Enable all counters */
-#define SCORPION_L2_EVT_PREFIX 3
-#define SCORPION_MAX_L2_REG 4
-
-/*
- * Lock to protect r/m/w sequences to the L2 PMU.
- */
-DEFINE_RAW_SPINLOCK(bb_l2_pmu_lock);
-
-static struct platform_device *bb_l2_pmu_device;
-
-struct hw_bb_l2_pmu {
-	struct perf_event *events[MAX_BB_L2_CTRS];
-	unsigned long active_mask[BITS_TO_LONGS(MAX_BB_L2_CTRS)];
-	raw_spinlock_t lock;
-};
-
-struct hw_bb_l2_pmu hw_bb_l2_pmu;
-
-struct bb_l2_scorp_evt {
-	u32 evt_type;
-	u32 val;
-	u8 grp;
-	u32 evt_type_act;
-};
-
-enum scorpion_perf_types {
-	SCORPIONL2_TOTAL_BANK_REQ = 0x90,
-	SCORPIONL2_DSIDE_READ = 0x91,
-	SCORPIONL2_DSIDE_WRITE = 0x92,
-	SCORPIONL2_ISIDE_READ = 0x93,
-	SCORPIONL2_L2CACHE_ISIDE_READ = 0x94,
-	SCORPIONL2_L2CACHE_BANK_REQ = 0x95,
-	SCORPIONL2_L2CACHE_DSIDE_READ = 0x96,
-	SCORPIONL2_L2CACHE_DSIDE_WRITE = 0x97,
-	SCORPIONL2_L2NOCACHE_DSIDE_WRITE = 0x98,
-	SCORPIONL2_L2NOCACHE_ISIDE_READ = 0x99,
-	SCORPIONL2_L2NOCACHE_TOTAL_REQ = 0x9a,
-	SCORPIONL2_L2NOCACHE_DSIDE_READ = 0x9b,
-	SCORPIONL2_DSIDE_READ_NOL1 = 0x9c,
-	SCORPIONL2_L2CACHE_WRITETHROUGH = 0x9d,
-	SCORPIONL2_BARRIERS = 0x9e,
-	SCORPIONL2_HARDWARE_TABLE_WALKS = 0x9f,
-	SCORPIONL2_MVA_POC = 0xa0,
-	SCORPIONL2_L2CACHE_HW_TABLE_WALKS = 0xa1,
-	SCORPIONL2_SETWAY_CACHE_OPS = 0xa2,
-	SCORPIONL2_DSIDE_WRITE_HITS = 0xa3,
-	SCORPIONL2_ISIDE_READ_HITS = 0xa4,
-	SCORPIONL2_CACHE_DSIDE_READ_NOL1 = 0xa5,
-	SCORPIONL2_TOTAL_CACHE_HITS = 0xa6,
-	SCORPIONL2_CACHE_MATCH_MISS = 0xa7,
-	SCORPIONL2_DREAD_HIT_L1_DATA = 0xa8,
-	SCORPIONL2_L2LINE_LOCKED = 0xa9,
-	SCORPIONL2_HW_TABLE_WALK_HIT = 0xaa,
-	SCORPIONL2_CACHE_MVA_POC = 0xab,
-	SCORPIONL2_L2ALLOC_DWRITE_MISS = 0xac,
-	SCORPIONL2_CORRECTED_TAG_ARRAY = 0xad,
-	SCORPIONL2_CORRECTED_DATA_ARRAY = 0xae,
-	SCORPIONL2_CORRECTED_REPLACEMENT_ARRAY = 0xaf,
-	SCORPIONL2_PMBUS_MPAAF = 0xb0,
-	SCORPIONL2_PMBUS_MPWDAF = 0xb1,
-	SCORPIONL2_PMBUS_MPBRT = 0xb2,
-	SCORPIONL2_CPU0_GRANT = 0xb3,
-	SCORPIONL2_CPU1_GRANT = 0xb4,
-	SCORPIONL2_CPU0_NOGRANT = 0xb5,
-	SCORPIONL2_CPU1_NOGRANT = 0xb6,
-	SCORPIONL2_CPU0_LOSING_ARB = 0xb7,
-	SCORPIONL2_CPU1_LOSING_ARB = 0xb8,
-	SCORPIONL2_SLAVEPORT_NOGRANT = 0xb9,
-	SCORPIONL2_SLAVEPORT_BPQ_FULL = 0xba,
-	SCORPIONL2_SLAVEPORT_LOSING_ARB = 0xbb,
-	SCORPIONL2_SLAVEPORT_GRANT = 0xbc,
-	SCORPIONL2_SLAVEPORT_GRANTLOCK = 0xbd,
-	SCORPIONL2_L2EM_STREX_PASS = 0xbe,
-	SCORPIONL2_L2EM_STREX_FAIL = 0xbf,
-	SCORPIONL2_LDREX_RESERVE_L2EM = 0xc0,
-	SCORPIONL2_SLAVEPORT_LDREX = 0xc1,
-	SCORPIONL2_CPU0_L2EM_CLEARED = 0xc2,
-	SCORPIONL2_CPU1_L2EM_CLEARED = 0xc3,
-	SCORPIONL2_SLAVEPORT_L2EM_CLEARED = 0xc4,
-	SCORPIONL2_CPU0_CLAMPED = 0xc5,
-	SCORPIONL2_CPU1_CLAMPED = 0xc6,
-	SCORPIONL2_CPU0_WAIT = 0xc7,
-	SCORPIONL2_CPU1_WAIT = 0xc8,
-	SCORPIONL2_CPU0_NONAMBAS_WAIT = 0xc9,
-	SCORPIONL2_CPU1_NONAMBAS_WAIT = 0xca,
-	SCORPIONL2_CPU0_DSB_WAIT = 0xcb,
-	SCORPIONL2_CPU1_DSB_WAIT = 0xcc,
-	SCORPIONL2_AXI_READ = 0xcd,
-	SCORPIONL2_AXI_WRITE = 0xce,
-
-	SCORPIONL2_1BEAT_WRITE = 0xcf,
-	SCORPIONL2_2BEAT_WRITE = 0xd0,
-	SCORPIONL2_4BEAT_WRITE = 0xd1,
-	SCORPIONL2_8BEAT_WRITE = 0xd2,
-	SCORPIONL2_12BEAT_WRITE = 0xd3,
-	SCORPIONL2_16BEAT_WRITE = 0xd4,
-	SCORPIONL2_1BEAT_DSIDE_READ = 0xd5,
-	SCORPIONL2_2BEAT_DSIDE_READ = 0xd6,
-	SCORPIONL2_4BEAT_DSIDE_READ = 0xd7,
-	SCORPIONL2_8BEAT_DSIDE_READ = 0xd8,
-	SCORPIONL2_CSYS_READ_1BEAT = 0xd9,
-	SCORPIONL2_CSYS_READ_2BEAT = 0xda,
-	SCORPIONL2_CSYS_READ_4BEAT = 0xdb,
-	SCORPIONL2_CSYS_READ_8BEAT = 0xdc,
-	SCORPIONL2_4BEAT_IFETCH_READ = 0xdd,
-	SCORPIONL2_8BEAT_IFETCH_READ = 0xde,
-	SCORPIONL2_CSYS_WRITE_1BEAT = 0xdf,
-	SCORPIONL2_CSYS_WRITE_2BEAT = 0xe0,
-	SCORPIONL2_AXI_READ_DATA_BEAT = 0xe1,
-	SCORPIONL2_AXI_WRITE_EVT1 = 0xe2,
-	SCORPIONL2_AXI_WRITE_EVT2 = 0xe3,
-	SCORPIONL2_LDREX_REQ = 0xe4,
-	SCORPIONL2_STREX_PASS = 0xe5,
-	SCORPIONL2_STREX_FAIL = 0xe6,
-	SCORPIONL2_CPREAD = 0xe7,
-	SCORPIONL2_CPWRITE = 0xe8,
-	SCORPIONL2_BARRIER_REQ = 0xe9,
-	SCORPIONL2_AXI_READ_SLVPORT = 0xea,
-	SCORPIONL2_AXI_WRITE_SLVPORT = 0xeb,
-	SCORPIONL2_AXI_READ_SLVPORT_DATABEAT = 0xec,
-	SCORPIONL2_AXI_WRITE_SLVPORT_DATABEAT = 0xed,
-	SCORPIONL2_SNOOPKILL_PREFILTER = 0xee,
-	SCORPIONL2_SNOOPKILL_FILTEROUT = 0xef,
-	SCORPIONL2_SNOOPED_IC = 0xf0,
-	SCORPIONL2_SNOOPED_BP = 0xf1,
-	SCORPIONL2_SNOOPED_BARRIERS = 0xf2,
-	SCORPIONL2_SNOOPED_TLB = 0xf3,
-	BB_L2_MAX_EVT,
-};
-
-static const struct bb_l2_scorp_evt sc_evt[] = {
-	{SCORPIONL2_TOTAL_BANK_REQ, 0x80000001, 0, 0x00},
-	{SCORPIONL2_DSIDE_READ, 0x80000100, 0, 0x01},
-	{SCORPIONL2_DSIDE_WRITE, 0x80010000, 0, 0x02},
-	{SCORPIONL2_ISIDE_READ, 0x81000000, 0, 0x03},
-	{SCORPIONL2_L2CACHE_ISIDE_READ, 0x80000002, 0, 0x00},
-	{SCORPIONL2_L2CACHE_BANK_REQ, 0x80000200, 0, 0x01},
-	{SCORPIONL2_L2CACHE_DSIDE_READ, 0x80020000, 0, 0x02},
-	{SCORPIONL2_L2CACHE_DSIDE_WRITE, 0x82000000, 0, 0x03},
-	{SCORPIONL2_L2NOCACHE_DSIDE_WRITE, 0x80000003, 0, 0x00},
-	{SCORPIONL2_L2NOCACHE_ISIDE_READ, 0x80000300, 0, 0x01},
-	{SCORPIONL2_L2NOCACHE_TOTAL_REQ, 0x80030000, 0, 0x02},
-	{SCORPIONL2_L2NOCACHE_DSIDE_READ, 0x83000000, 0, 0x03},
-	{SCORPIONL2_DSIDE_READ_NOL1, 0x80000004, 0, 0x00},
-	{SCORPIONL2_L2CACHE_WRITETHROUGH, 0x80000400, 0, 0x01},
-	{SCORPIONL2_BARRIERS, 0x84000000, 0, 0x03},
-	{SCORPIONL2_HARDWARE_TABLE_WALKS, 0x80000005, 0, 0x00},
-	{SCORPIONL2_MVA_POC, 0x80000500, 0, 0x01},
-	{SCORPIONL2_L2CACHE_HW_TABLE_WALKS, 0x80050000, 0, 0x02},
-	{SCORPIONL2_SETWAY_CACHE_OPS, 0x85000000, 0, 0x03},
-	{SCORPIONL2_DSIDE_WRITE_HITS, 0x80000006, 0, 0x00},
-	{SCORPIONL2_ISIDE_READ_HITS, 0x80000600, 0, 0x01},
-	{SCORPIONL2_CACHE_DSIDE_READ_NOL1, 0x80060000, 0, 0x02},
-	{SCORPIONL2_TOTAL_CACHE_HITS, 0x86000000, 0, 0x03},
-	{SCORPIONL2_CACHE_MATCH_MISS, 0x80000007, 0, 0x00},
-	{SCORPIONL2_DREAD_HIT_L1_DATA, 0x87000000, 0, 0x03},
-	{SCORPIONL2_L2LINE_LOCKED, 0x80000008, 0, 0x00},
-	{SCORPIONL2_HW_TABLE_WALK_HIT, 0x80000800, 0, 0x01},
-	{SCORPIONL2_CACHE_MVA_POC, 0x80080000, 0, 0x02},
-	{SCORPIONL2_L2ALLOC_DWRITE_MISS, 0x88000000, 0, 0x03},
-	{SCORPIONL2_CORRECTED_TAG_ARRAY, 0x80001A00, 0, 0x01},
-	{SCORPIONL2_CORRECTED_DATA_ARRAY, 0x801A0000, 0, 0x02},
-	{SCORPIONL2_CORRECTED_REPLACEMENT_ARRAY, 0x9A000000, 0, 0x03},
-	{SCORPIONL2_PMBUS_MPAAF, 0x80001C00, 0, 0x01},
-	{SCORPIONL2_PMBUS_MPWDAF, 0x801C0000, 0, 0x02},
-	{SCORPIONL2_PMBUS_MPBRT, 0x9C000000, 0, 0x03},
-
-	{SCORPIONL2_CPU0_GRANT, 0x80000001, 1, 0x04},
-	{SCORPIONL2_CPU1_GRANT, 0x80000100, 1, 0x05},
-	{SCORPIONL2_CPU0_NOGRANT, 0x80020000, 1, 0x06},
-	{SCORPIONL2_CPU1_NOGRANT, 0x82000000, 1, 0x07},
-	{SCORPIONL2_CPU0_LOSING_ARB, 0x80040000, 1, 0x06},
-	{SCORPIONL2_CPU1_LOSING_ARB, 0x84000000, 1, 0x07},
-	{SCORPIONL2_SLAVEPORT_NOGRANT, 0x80000007, 1, 0x04},
-	{SCORPIONL2_SLAVEPORT_BPQ_FULL, 0x80000700, 1, 0x05},
-	{SCORPIONL2_SLAVEPORT_LOSING_ARB, 0x80070000, 1, 0x06},
-	{SCORPIONL2_SLAVEPORT_GRANT, 0x87000000, 1, 0x07},
-	{SCORPIONL2_SLAVEPORT_GRANTLOCK, 0x80000008, 1, 0x04},
-	{SCORPIONL2_L2EM_STREX_PASS, 0x80000009, 1, 0x04},
-	{SCORPIONL2_L2EM_STREX_FAIL, 0x80000900, 1, 0x05},
-	{SCORPIONL2_LDREX_RESERVE_L2EM, 0x80090000, 1, 0x06},
-	{SCORPIONL2_SLAVEPORT_LDREX, 0x89000000, 1, 0x07},
-	{SCORPIONL2_CPU0_L2EM_CLEARED, 0x800A0000, 1, 0x06},
-	{SCORPIONL2_CPU1_L2EM_CLEARED, 0x8A000000, 1, 0x07},
-	{SCORPIONL2_SLAVEPORT_L2EM_CLEARED, 0x80000B00, 1, 0x05},
-	{SCORPIONL2_CPU0_CLAMPED, 0x8000000E, 1, 0x04},
-	{SCORPIONL2_CPU1_CLAMPED, 0x80000E00, 1, 0x05},
-	{SCORPIONL2_CPU0_WAIT, 0x800F0000, 1, 0x06},
-	{SCORPIONL2_CPU1_WAIT, 0x8F000000, 1, 0x07},
-	{SCORPIONL2_CPU0_NONAMBAS_WAIT, 0x80000010, 1, 0x04},
-	{SCORPIONL2_CPU1_NONAMBAS_WAIT, 0x80001000, 1, 0x05},
-	{SCORPIONL2_CPU0_DSB_WAIT, 0x80000014, 1, 0x04},
-	{SCORPIONL2_CPU1_DSB_WAIT, 0x80001400, 1, 0x05},
-
-	{SCORPIONL2_AXI_READ, 0x80000001, 2, 0x08},
-	{SCORPIONL2_AXI_WRITE, 0x80000100, 2, 0x09},
-	{SCORPIONL2_1BEAT_WRITE, 0x80010000, 2, 0x0a},
-	{SCORPIONL2_2BEAT_WRITE, 0x80010000, 2, 0x0b},
-	{SCORPIONL2_4BEAT_WRITE, 0x80000002, 2, 0x08},
-	{SCORPIONL2_8BEAT_WRITE, 0x80000200, 2, 0x09},
-	{SCORPIONL2_12BEAT_WRITE, 0x80020000, 2, 0x0a},
-	{SCORPIONL2_16BEAT_WRITE, 0x82000000, 2, 0x0b},
-	{SCORPIONL2_1BEAT_DSIDE_READ, 0x80000003, 2, 0x08},
-	{SCORPIONL2_2BEAT_DSIDE_READ, 0x80000300, 2, 0x09},
-	{SCORPIONL2_4BEAT_DSIDE_READ, 0x80030000, 2, 0x0a},
-	{SCORPIONL2_8BEAT_DSIDE_READ, 0x83000000, 2, 0x0b},
-	{SCORPIONL2_CSYS_READ_1BEAT, 0x80000004, 2, 0x08},
-	{SCORPIONL2_CSYS_READ_2BEAT, 0x80000400, 2, 0x09},
-	{SCORPIONL2_CSYS_READ_4BEAT, 0x80040000, 2, 0x0a},
-	{SCORPIONL2_CSYS_READ_8BEAT, 0x84000000, 2, 0x0b},
-	{SCORPIONL2_4BEAT_IFETCH_READ, 0x80000005, 2, 0x08},
-	{SCORPIONL2_8BEAT_IFETCH_READ, 0x80000500, 2, 0x09},
-	{SCORPIONL2_CSYS_WRITE_1BEAT, 0x80050000, 2, 0x0a},
-	{SCORPIONL2_CSYS_WRITE_2BEAT, 0x85000000, 2, 0x0b},
-	{SCORPIONL2_AXI_READ_DATA_BEAT, 0x80000600, 2, 0x09},
-	{SCORPIONL2_AXI_WRITE_EVT1, 0x80060000, 2, 0x0a},
-	{SCORPIONL2_AXI_WRITE_EVT2, 0x86000000, 2, 0x0b},
-	{SCORPIONL2_LDREX_REQ, 0x80000007, 2, 0x08},
-	{SCORPIONL2_STREX_PASS, 0x80000700, 2, 0x09},
-	{SCORPIONL2_STREX_FAIL, 0x80070000, 2, 0x0a},
-	{SCORPIONL2_CPREAD, 0x80000008, 2, 0x08},
-	{SCORPIONL2_CPWRITE, 0x80000800, 2, 0x09},
-	{SCORPIONL2_BARRIER_REQ, 0x88000000, 2, 0x0b},
-
-	{SCORPIONL2_AXI_READ_SLVPORT, 0x80000001, 3, 0x0c},
-	{SCORPIONL2_AXI_WRITE_SLVPORT, 0x80000100, 3, 0x0d},
-	{SCORPIONL2_AXI_READ_SLVPORT_DATABEAT, 0x80010000, 3, 0x0e},
-	{SCORPIONL2_AXI_WRITE_SLVPORT_DATABEAT, 0x81000000, 3, 0x0f},
-
-	{SCORPIONL2_SNOOPKILL_PREFILTER, 0x80000001, 4, 0x10},
-	{SCORPIONL2_SNOOPKILL_FILTEROUT, 0x80000100, 4, 0x11},
-	{SCORPIONL2_SNOOPED_IC, 0x80000002, 4, 0x10},
-	{SCORPIONL2_SNOOPED_BP, 0x80000200, 4, 0x11},
-	{SCORPIONL2_SNOOPED_BARRIERS, 0x80020000, 4, 0x12},
-	{SCORPIONL2_SNOOPED_TLB, 0x82000000, 4, 0x13},
-};
-
-static u32 bb_l2_read_l2pm0(void)
-{
-	u32 val;
-	asm volatile ("mrc p15, 3, %0, c15, c7, 0" : "=r" (val));
-	return val;
-}
-
-static void bb_l2_write_l2pm0(u32 val)
-{
-	asm volatile ("mcr p15, 3, %0, c15, c7, 0" : : "r" (val));
-}
-
-static u32 bb_l2_read_l2pm1(void)
-{
-	u32 val;
-	asm volatile ("mrc p15, 3, %0, c15, c7, 1" : "=r" (val));
-	return val;
-}
-
-static void bb_l2_write_l2pm1(u32 val)
-{
-	asm volatile ("mcr p15, 3, %0, c15, c7, 1" : : "r" (val));
-}
-
-static u32 bb_l2_read_l2pm2(void)
-{
-	u32 val;
-	asm volatile ("mrc p15, 3, %0, c15, c7, 2" : "=r" (val));
-	return val;
-}
-
-static void bb_l2_write_l2pm2(u32 val)
-{
-	asm volatile ("mcr p15, 3, %0, c15, c7, 2" : : "r" (val));
-}
-
-static u32 bb_l2_read_l2pm3(void)
-{
-	u32 val;
-	asm volatile ("mrc p15, 3, %0, c15, c7, 3" : "=r" (val));
-	return val;
-}
-
-static void bb_l2_write_l2pm3(u32 val)
-{
-	asm volatile ("mcr p15, 3, %0, c15, c7, 3" : : "r" (val));
-}
-
-static u32 bb_l2_read_l2pm4(void)
-{
-	u32 val;
-	asm volatile ("mrc p15, 3, %0, c15, c7, 4" : "=r" (val));
-	return val;
-}
-
-static void bb_l2_write_l2pm4(u32 val)
-{
-	asm volatile ("mcr p15, 3, %0, c15, c7, 4" : : "r" (val));
-}
-
-struct bb_scorpion_access_funcs {
-	u32(*read) (void);
-	void (*write) (u32);
-	void (*pre) (void);
-	void (*post) (void);
-};
-
-struct bb_scorpion_access_funcs bb_l2_func[] = {
-	{bb_l2_read_l2pm0, bb_l2_write_l2pm0, NULL, NULL},
-	{bb_l2_read_l2pm1, bb_l2_write_l2pm1, NULL, NULL},
-	{bb_l2_read_l2pm2, bb_l2_write_l2pm2, NULL, NULL},
-	{bb_l2_read_l2pm3, bb_l2_write_l2pm3, NULL, NULL},
-	{bb_l2_read_l2pm4, bb_l2_write_l2pm4, NULL, NULL},
-};
-
-#define COLMN0MASK 0x000000ff
-#define COLMN1MASK 0x0000ff00
-#define COLMN2MASK 0x00ff0000
-
-static u32 bb_l2_get_columnmask(u32 setval)
-{
-	if (setval & COLMN0MASK)
-		return 0xffffff00;
-	else if (setval & COLMN1MASK)
-		return 0xffff00ff;
-	else if (setval & COLMN2MASK)
-		return 0xff00ffff;
-	else
-		return 0x80ffffff;
-}
-
-static void bb_l2_evt_setup(u32 gr, u32 setval)
-{
-	u32 val;
-	if (bb_l2_func[gr].pre)
-		bb_l2_func[gr].pre();
-	val = bb_l2_get_columnmask(setval) & bb_l2_func[gr].read();
-	val = val | setval;
-	bb_l2_func[gr].write(val);
-	if (bb_l2_func[gr].post)
-		bb_l2_func[gr].post();
-}
-
-#define BB_L2_EVT_START_IDX 0x90
-#define BB_L2_INV_EVTYPE 0
-
-static unsigned int get_bb_l2_evtinfo(unsigned int evt_type,
-				      struct bb_l2_scorp_evt *evtinfo)
-{
-	u32 idx;
-	u8 prefix;
-	u8 reg;
-	u8 code;
-	u8 group;
-
-	prefix = (evt_type & 0xF0000) >> 16;
-	if (prefix == SCORPION_L2_EVT_PREFIX) {
-		reg   = (evt_type & 0x0F000) >> 12;
-		code  = (evt_type & 0x00FF0) >> 4;
-		group =  evt_type & 0x0000F;
-
-		if ((group > 3) || (reg > SCORPION_MAX_L2_REG))
-			return BB_L2_INV_EVTYPE;
-
-		evtinfo->val = 0x80000000 | (code << (group * 8));
-		evtinfo->grp = reg;
-		evtinfo->evt_type_act = group | (reg << 2);
-		return evtinfo->evt_type_act;
-	}
-
-	if (evt_type < BB_L2_EVT_START_IDX || evt_type >= BB_L2_MAX_EVT)
-		return BB_L2_INV_EVTYPE;
-	idx = evt_type - BB_L2_EVT_START_IDX;
-	if (sc_evt[idx].evt_type == evt_type) {
-		evtinfo->val = sc_evt[idx].val;
-		evtinfo->grp = sc_evt[idx].grp;
-		evtinfo->evt_type_act = sc_evt[idx].evt_type_act;
-		return sc_evt[idx].evt_type_act;
-	}
-	return BB_L2_INV_EVTYPE;
-}
-
-static inline void bb_l2_pmnc_write(unsigned long val)
-{
-	val &= 0xff;
-	asm volatile ("mcr p15, 3, %0, c15, c4, 0" : : "r" (val));
-}
-
-static inline unsigned long bb_l2_pmnc_read(void)
-{
-	u32 val;
-	asm volatile ("mrc p15, 3, %0, c15, c4, 0" : "=r" (val));
-	return val;
-}
-
-static void bb_l2_set_evcntcr(void)
-{
-	u32 val = 0x0;
-	asm volatile ("mcr p15, 3, %0, c15, c6, 4" : : "r" (val));
-}
-
-static inline void bb_l2_set_evtyper(int ctr, int val)
-{
-	/* select ctr */
-	asm volatile ("mcr p15, 3, %0, c15, c6, 0" : : "r" (ctr));
-
-	/* write into EVTYPER */
-	asm volatile ("mcr p15, 3, %0, c15, c6, 7" : : "r" (val));
-}
-
-static void bb_l2_set_evfilter_task_mode(void)
-{
-	u32 filter_val = 0x000f0030 | 1 << smp_processor_id();
-
-	asm volatile ("mcr p15, 3, %0, c15, c6, 3" : : "r" (filter_val));
-}
-
-static void bb_l2_set_evfilter_sys_mode(void)
-{
-	u32 filter_val = 0x000f003f;
-
-	asm volatile ("mcr p15, 3, %0, c15, c6, 3" : : "r" (filter_val));
-}
-
-static void bb_l2_enable_intenset(u32 idx)
-{
-	if (idx == BB_L2CYCLE_CTR_EVENT_IDX) {
-		asm volatile ("mcr p15, 3, %0, c15, c5, 1" : : "r"
-			      (1 << BB_L2CYCLE_CTR_BIT));
-	} else {
-		asm volatile ("mcr p15, 3, %0, c15, c5, 1" : : "r" (1 << idx));
-	}
-}
-
-static void bb_l2_disable_intenclr(u32 idx)
-{
-	if (idx == BB_L2CYCLE_CTR_EVENT_IDX) {
-		asm volatile ("mcr p15, 3, %0, c15, c5, 0" : : "r"
-			      (1 << BB_L2CYCLE_CTR_BIT));
-	} else {
-		asm volatile ("mcr p15, 3, %0, c15, c5, 0" : : "r" (1 << idx));
-	}
-}
-
-static void bb_l2_enable_counter(u32 idx)
-{
-	if (idx == BB_L2CYCLE_CTR_EVENT_IDX) {
-		asm volatile ("mcr p15, 3, %0, c15, c4, 3" : : "r"
-			      (1 << BB_L2CYCLE_CTR_BIT));
-	} else {
-		asm volatile ("mcr p15, 3, %0, c15, c4, 3" : : "r" (1 << idx));
-	}
-}
-
-static void bb_l2_disable_counter(u32 idx)
-{
-	if (idx == BB_L2CYCLE_CTR_EVENT_IDX) {
-		asm volatile ("mcr p15, 3, %0, c15, c4, 2" : : "r"
-			      (1 << BB_L2CYCLE_CTR_BIT));
-
-	} else {
-		asm volatile ("mcr p15, 3, %0, c15, c4, 2" : : "r" (1 << idx));
-	}
-}
-
-static u64 bb_l2_read_counter(u32 idx)
-{
-	u32 val;
-	unsigned long flags;
-
-	if (idx == BB_L2CYCLE_CTR_EVENT_IDX) {
-		asm volatile ("mrc p15, 3, %0, c15, c4, 5" : "=r" (val));
-	} else {
-		raw_spin_lock_irqsave(&bb_l2_pmu_lock, flags);
-		asm volatile ("mcr p15, 3, %0, c15, c6, 0" : : "r" (idx));
-
-		/* read val from counter */
-		asm volatile ("mrc p15, 3, %0, c15, c6, 5" : "=r" (val));
-		raw_spin_unlock_irqrestore(&bb_l2_pmu_lock, flags);
-	}
-
-	return val;
-}
-
-static void bb_l2_write_counter(u32 idx, u32 val)
-{
-	unsigned long flags;
-
-	if (idx == BB_L2CYCLE_CTR_EVENT_IDX) {
-		asm volatile ("mcr p15, 3, %0, c15, c4, 5" : : "r" (val));
-	} else {
-		raw_spin_lock_irqsave(&bb_l2_pmu_lock, flags);
-		/* select counter */
-		asm volatile ("mcr p15, 3, %0, c15, c6, 0" : : "r" (idx));
-
-		/* write val into counter */
-		asm volatile ("mcr p15, 3, %0, c15, c6, 5" : : "r" (val));
-		raw_spin_unlock_irqrestore(&bb_l2_pmu_lock, flags);
-	}
-}
-
-static int
-bb_pmu_event_set_period(struct perf_event *event,
-			struct hw_perf_event *hwc, int idx)
-{
-	s64 left = local64_read(&hwc->period_left);
-	s64 period = hwc->sample_period;
-	int ret = 0;
-
-	if (unlikely(left <= -period)) {
-		left = period;
-		local64_set(&hwc->period_left, left);
-		hwc->last_period = period;
-		ret = 1;
-	}
-
-	if (unlikely(left <= 0)) {
-		left += period;
-		local64_set(&hwc->period_left, left);
-		hwc->last_period = period;
-		ret = 1;
-	}
-
-	if (left > (s64) MAX_BB_L2_PERIOD)
-		left = MAX_BB_L2_PERIOD;
-
-	local64_set(&hwc->prev_count, (u64)-left);
-
-	bb_l2_write_counter(idx, (u64) (-left) & 0xffffffff);
-
-	perf_event_update_userpage(event);
-
-	return ret;
-}
-
-static u64
-bb_pmu_event_update(struct perf_event *event, struct hw_perf_event *hwc,
-		    int idx, int overflow)
-{
-	u64 prev_raw_count, new_raw_count;
-	u64 delta;
-
-again:
-	prev_raw_count = local64_read(&hwc->prev_count);
-	new_raw_count = bb_l2_read_counter(idx);
-
-	if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
-			    new_raw_count) != prev_raw_count)
-		goto again;
-
-	new_raw_count &= MAX_BB_L2_PERIOD;
-	prev_raw_count &= MAX_BB_L2_PERIOD;
-
-	if (overflow) {
-		delta = MAX_BB_L2_PERIOD - prev_raw_count + new_raw_count;
-		pr_err("%s: delta: %lld\n", __func__, delta);
-	} else
-		delta = new_raw_count - prev_raw_count;
-
-	local64_add(delta, &event->count);
-	local64_sub(delta, &hwc->period_left);
-
-	pr_debug("%s: new: %lld, prev: %lld, event: %ld count: %lld\n",
-		 __func__, new_raw_count, prev_raw_count,
-		 hwc->config_base, local64_read(&event->count));
-
-	return new_raw_count;
-}
-
-static void bb_l2_read(struct perf_event *event)
-{
-	struct hw_perf_event *hwc = &event->hw;
-
-	bb_pmu_event_update(event, hwc, hwc->idx, 0);
-}
-
-static void bb_l2_stop_counter(struct perf_event *event, int flags)
-{
-	struct hw_perf_event *hwc = &event->hw;
-	int idx = hwc->idx;
-
-	if (!(hwc->state & PERF_HES_STOPPED)) {
-		bb_l2_disable_intenclr(idx);
-		bb_l2_disable_counter(idx);
-
-		bb_pmu_event_update(event, hwc, idx, 0);
-		hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
-	}
-
-	pr_debug("%s: event: %ld ctr: %d stopped\n", __func__, hwc->config_base,
-		 idx);
-}
-
-static void bb_l2_start_counter(struct perf_event *event, int flags)
-{
-	struct hw_perf_event *hwc = &event->hw;
-	int idx = hwc->idx;
-	struct bb_l2_scorp_evt evtinfo;
-	int evtype = hwc->config_base;
-	int ev_typer;
-	unsigned long iflags;
-	int cpu_id = smp_processor_id();
-
-	if (flags & PERF_EF_RELOAD)
-		WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
-
-	hwc->state = 0;
-
-	bb_pmu_event_set_period(event, hwc, idx);
-
-	if (hwc->config_base == BB_L2CYCLE_CTR_RAW_CODE)
-		goto out;
-
-	memset(&evtinfo, 0, sizeof(evtinfo));
-
-	ev_typer = get_bb_l2_evtinfo(evtype, &evtinfo);
-
-	raw_spin_lock_irqsave(&bb_l2_pmu_lock, iflags);
-
-	bb_l2_set_evtyper(idx, ev_typer);
-
-	bb_l2_set_evcntcr();
-
-	if (event->cpu < 0)
-		bb_l2_set_evfilter_task_mode();
-	else
-		bb_l2_set_evfilter_sys_mode();
-
-	bb_l2_evt_setup(evtinfo.grp, evtinfo.val);
-
-	raw_spin_unlock_irqrestore(&bb_l2_pmu_lock, iflags);
-
-out:
-
-	bb_l2_enable_intenset(idx);
-
-	bb_l2_enable_counter(idx);
-
-	pr_debug("%s: idx: %d, event: %d, val: %x, cpu: %d\n",
-		 __func__, idx, evtype, evtinfo.val, cpu_id);
-}
-
-static void bb_l2_del_event(struct perf_event *event, int flags)
-{
-	struct hw_perf_event *hwc = &event->hw;
-	int idx = hwc->idx;
-	unsigned long iflags;
-
-	raw_spin_lock_irqsave(&hw_bb_l2_pmu.lock, iflags);
-
-	clear_bit(idx, (long unsigned int *)(&hw_bb_l2_pmu.active_mask));
-
-	bb_l2_stop_counter(event, PERF_EF_UPDATE);
-	hw_bb_l2_pmu.events[idx] = NULL;
-	hwc->idx = -1;
-
-	raw_spin_unlock_irqrestore(&hw_bb_l2_pmu.lock, iflags);
-
-	pr_debug("%s: event: %ld deleted\n", __func__, hwc->config_base);
-
-	perf_event_update_userpage(event);
-}
-
-static int bb_l2_add_event(struct perf_event *event, int flags)
-{
-	int ctr = 0;
-	struct hw_perf_event *hwc = &event->hw;
-	unsigned long iflags;
-	int err = 0;
-
-	perf_pmu_disable(event->pmu);
-
-	raw_spin_lock_irqsave(&hw_bb_l2_pmu.lock, iflags);
-
-	/* Cycle counter has a resrvd index */
-	if (hwc->config_base == BB_L2CYCLE_CTR_RAW_CODE) {
-		if (hw_bb_l2_pmu.events[BB_L2CYCLE_CTR_EVENT_IDX]) {
-			pr_err("%s: Stale cycle ctr event ptr !\n", __func__);
-			err = -EINVAL;
-			goto out;
-		}
-		hwc->idx = BB_L2CYCLE_CTR_EVENT_IDX;
-		hw_bb_l2_pmu.events[BB_L2CYCLE_CTR_EVENT_IDX] = event;
-		set_bit(BB_L2CYCLE_CTR_EVENT_IDX,
-			(long unsigned int *)&hw_bb_l2_pmu.active_mask);
-		goto skip_ctr_loop;
-	}
-
-	for (ctr = 0; ctr < MAX_BB_L2_CTRS - 1; ctr++) {
-		if (!hw_bb_l2_pmu.events[ctr]) {
-			hwc->idx = ctr;
-			hw_bb_l2_pmu.events[ctr] = event;
-			set_bit(ctr, (long unsigned int *)
-				&hw_bb_l2_pmu.active_mask);
-			break;
-		}
-	}
-
-	if (hwc->idx < 0) {
-		err = -ENOSPC;
-		pr_err("%s: No space for event: %llx!!\n", __func__,
-		       event->attr.config);
-		goto out;
-	}
-
-skip_ctr_loop:
-
-	bb_l2_disable_counter(hwc->idx);
-
-	hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
-
-	if (flags & PERF_EF_START)
-		bb_l2_start_counter(event, PERF_EF_RELOAD);
-
-	perf_event_update_userpage(event);
-
-	pr_debug("%s: event: %ld, ctr: %d added from cpu:%d\n",
-		 __func__, hwc->config_base, hwc->idx, smp_processor_id());
-out:
-	raw_spin_unlock_irqrestore(&hw_bb_l2_pmu.lock, iflags);
-
-	/* Resume the PMU even if this event could not be added */
-	perf_pmu_enable(event->pmu);
-
-	return err;
-}
-
-static void bb_l2_pmu_enable(struct pmu *pmu)
-{
-	unsigned long flags;
-	isb();
-	raw_spin_lock_irqsave(&bb_l2_pmu_lock, flags);
-	/* Enable all counters */
-	bb_l2_pmnc_write(bb_l2_pmnc_read() | SCORPIONL2_PMNC_E);
-	raw_spin_unlock_irqrestore(&bb_l2_pmu_lock, flags);
-}
-
-static void bb_l2_pmu_disable(struct pmu *pmu)
-{
-	unsigned long flags;
-	raw_spin_lock_irqsave(&bb_l2_pmu_lock, flags);
-	/* Disable all counters */
-	bb_l2_pmnc_write(bb_l2_pmnc_read() & ~SCORPIONL2_PMNC_E);
-	raw_spin_unlock_irqrestore(&bb_l2_pmu_lock, flags);
-	isb();
-}
-
-static inline u32 bb_l2_get_reset_pmovsr(void)
-{
-	u32 val;
-
-	/* Read */
-	asm volatile ("mrc p15, 3, %0, c15, c4, 1" : "=r" (val));
-
-	/* Write to clear flags */
-	val &= 0xffffffff;
-	asm volatile ("mcr p15, 3, %0, c15, c4, 1" : : "r" (val));
-
-	return val;
-}
-
-static irqreturn_t bb_l2_handle_irq(int irq_num, void *dev)
-{
-	unsigned long pmovsr;
-	struct perf_sample_data data;
-	struct pt_regs *regs;
-	struct perf_event *event;
-	struct hw_perf_event *hwc;
-	int bitp;
-	int idx = 0;
-
-	pmovsr = bb_l2_get_reset_pmovsr();
-
-	if (!(pmovsr & 0xffffffff))
-		return IRQ_NONE;
-
-	regs = get_irq_regs();
-
-	perf_sample_data_init(&data, 0);
-
-	raw_spin_lock(&hw_bb_l2_pmu.lock);
-
-	while (pmovsr) {
-		bitp = __ffs(pmovsr);
-
-		if (bitp == BB_L2CYCLE_CTR_BIT)
-			idx = BB_L2CYCLE_CTR_EVENT_IDX;
-		else
-			idx = bitp;
-
-		event = hw_bb_l2_pmu.events[idx];
-
-		if (!event)
-			goto next;
-
-		if (!test_bit(idx, hw_bb_l2_pmu.active_mask))
-			goto next;
-
-		hwc = &event->hw;
-		bb_pmu_event_update(event, hwc, idx, 1);
-		data.period = event->hw.last_period;
-
-		if (!bb_pmu_event_set_period(event, hwc, idx))
-			goto next;
-
-		if (perf_event_overflow(event, 0, &data, regs))
-			bb_l2_disable_counter(hwc->idx);
-next:
-		pmovsr &= (pmovsr - 1);
-	}
-
-	raw_spin_unlock(&hw_bb_l2_pmu.lock);
-
-	irq_work_run();
-
-	return IRQ_HANDLED;
-}
-
-static atomic_t active_bb_l2_events = ATOMIC_INIT(0);
-static DEFINE_MUTEX(bb_pmu_reserve_mutex);
-
-static int bb_pmu_reserve_hardware(void)
-{
-	int i, err = -ENODEV, irq;
-
-	bb_l2_pmu_device = reserve_pmu(ARM_PMU_DEVICE_L2);
-
-	if (IS_ERR(bb_l2_pmu_device)) {
-		pr_warning("unable to reserve pmu\n");
-		return PTR_ERR(bb_l2_pmu_device);
-	}
-
-	if (bb_l2_pmu_device->num_resources < 1) {
-		pr_err("no irqs for PMUs defined\n");
-		return -ENODEV;
-	}
-
-	if (strncmp(bb_l2_pmu_device->name, "l2-arm-pmu", 6)) {
-		pr_err("Incorrect pdev reserved !\n");
-		return -EINVAL;
-	}
-
-	for (i = 0; i < bb_l2_pmu_device->num_resources; ++i) {
-		irq = platform_get_irq(bb_l2_pmu_device, i);
-		if (irq < 0)
-			continue;
-
-		err = request_irq(irq, bb_l2_handle_irq,
-				  IRQF_DISABLED | IRQF_NOBALANCING,
-				  "bb-l2-pmu", NULL);
-		if (err) {
-			pr_warning("unable to request IRQ%d for Krait L2 perf "
-				   "counters\n", irq);
-			break;
-		}
-
-		irq_get_chip(irq)->irq_unmask(irq_get_irq_data(irq));
-	}
-
-	if (err) {
-		for (i = i - 1; i >= 0; --i) {
-			irq = platform_get_irq(bb_l2_pmu_device, i);
-			if (irq >= 0)
-				free_irq(irq, NULL);
-		}
-		release_pmu(bb_l2_pmu_device);
-		bb_l2_pmu_device = NULL;
-	}
-
-	return err;
-}
-
-static void bb_pmu_release_hardware(void)
-{
-	int i, irq;
-
-	for (i = bb_l2_pmu_device->num_resources - 1; i >= 0; --i) {
-		irq = platform_get_irq(bb_l2_pmu_device, i);
-		if (irq >= 0)
-			free_irq(irq, NULL);
-	}
-
-	bb_l2_pmu_disable(NULL);
-
-	release_pmu(bb_l2_pmu_device);
-	bb_l2_pmu_device = NULL;
-}
-
-static void bb_pmu_perf_event_destroy(struct perf_event *event)
-{
-	if (atomic_dec_and_mutex_lock
-	    (&active_bb_l2_events, &bb_pmu_reserve_mutex)) {
-		bb_pmu_release_hardware();
-		mutex_unlock(&bb_pmu_reserve_mutex);
-	}
-}
-
-static int bb_l2_event_init(struct perf_event *event)
-{
-	int err = 0;
-	struct hw_perf_event *hwc = &event->hw;
-	int status = 0;
-
-	switch (event->attr.type) {
-	case PERF_TYPE_SHARED:
-		break;
-
-	default:
-		return -ENOENT;
-	}
-
-	hwc->idx = -1;
-
-	event->destroy = bb_pmu_perf_event_destroy;
-
-	if (!atomic_inc_not_zero(&active_bb_l2_events)) {
-		/* 0 active events */
-		mutex_lock(&bb_pmu_reserve_mutex);
-		err = bb_pmu_reserve_hardware();
-		mutex_unlock(&bb_pmu_reserve_mutex);
-		if (!err)
-			atomic_inc(&active_bb_l2_events);
-		else
-			return err;
-	}
-
-	hwc->config = 0;
-	hwc->event_base = 0;
-
-	/* Check if we came via perf default syms */
-	if (event->attr.config == PERF_COUNT_HW_L2_CYCLES)
-		hwc->config_base = BB_L2CYCLE_CTR_RAW_CODE;
-	else
-		hwc->config_base = event->attr.config;
-
-	/* Only one CPU can control the cycle counter */
-	if (hwc->config_base == BB_L2CYCLE_CTR_RAW_CODE) {
-		/* Check if its already running */
-		asm volatile ("mrc p15, 3, %0, c15, c4, 6" : "=r" (status));
-		if (status == 0x2) {
-			err = -ENOSPC;
-			goto out;
-		}
-	}
-
-	if (!hwc->sample_period) {
-		hwc->sample_period = MAX_BB_L2_PERIOD;
-		hwc->last_period = hwc->sample_period;
-		local64_set(&hwc->period_left, hwc->sample_period);
-	}
-
-	pr_debug("%s: event: %lld init'd\n", __func__, event->attr.config);
-
-out:
-	if (err < 0)
-		bb_pmu_perf_event_destroy(event);
-
-	return err;
-}
-
-static struct pmu bb_l2_pmu = {
-	.pmu_enable = bb_l2_pmu_enable,
-	.pmu_disable = bb_l2_pmu_disable,
-	.event_init = bb_l2_event_init,
-	.add = bb_l2_add_event,
-	.del = bb_l2_del_event,
-	.start = bb_l2_start_counter,
-	.stop = bb_l2_stop_counter,
-	.read = bb_l2_read,
-};
-
-static const struct arm_pmu *__init scorpionmp_l2_pmu_init(void)
-{
-	/* Register our own PMU here */
-	perf_pmu_register(&bb_l2_pmu, "BB L2", PERF_TYPE_SHARED);
-
-	memset(&hw_bb_l2_pmu, 0, sizeof(hw_bb_l2_pmu));
-
-	/* Avoid spurious interrupts at startup */
-	bb_l2_get_reset_pmovsr();
-
-	raw_spin_lock_init(&hw_bb_l2_pmu.lock);
-
-	/* Don't return an arm_pmu here */
-	return NULL;
-}
-#else
-
-static const struct arm_pmu *__init scorpionmp_l2_pmu_init(void)
-{
-	return NULL;
-}
-
-#endif
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 304520b..24c57ae 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -2088,6 +2088,17 @@
 	help
 	  Enables support for Qualcomm Debug Subsystem.
 
+config MSM_QDSS_STM_DEFAULT_ENABLE
+	bool "Turn on QDSS STM Tracing by Default"
+	depends on MSM_QDSS
+	help
+	  Turns on QDSS STM tracing (hardware assisted software
+	  instrumentation based tracing) by default. Otherwise, tracing is
+	  disabled by default but can be enabled via sysfs.
+
+	  For production builds, you should probably say 'N' here to avoid
+	  potential power, performance and memory penalty.
+
 config MSM_QDSS_ETM_DEFAULT_ENABLE
 	bool "Turn on QDSS ETM Tracing by Default"
 	depends on MSM_QDSS
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 6034fe9..c3b13ec 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -25,7 +25,8 @@
 obj-y += acpuclock.o
 obj-$(CONFIG_ARCH_MSM7X27) += acpuclock-7627.o clock-pll.o
 obj-$(CONFIG_ARCH_MSM_SCORPION) += pmu.o
-obj-$(CONFIG_ARCH_MSM_KRAIT) += msm-krait-l2-accessors.o pmu.o
+obj-$(CONFIG_ARCH_MSM_SCORPIONMP) += perf_event_msm_l2.o
+obj-$(CONFIG_ARCH_MSM_KRAIT) += msm-krait-l2-accessors.o pmu.o perf_event_msm_krait_l2.o
 obj-$(CONFIG_ARCH_MSM7X27A) += pmu.o
 
 ifndef CONFIG_MSM_SMP
@@ -54,7 +55,7 @@
 
 msm-etm-objs := etm.o
 obj-$(CONFIG_MSM_ETM) += msm-etm.o
-obj-$(CONFIG_MSM_QDSS) += qdss.o qdss-etb.o qdss-tpiu.o qdss-funnel.o qdss-etm.o
+obj-$(CONFIG_MSM_QDSS) += qdss.o qdss-etb.o qdss-tpiu.o qdss-funnel.o qdss-stm.o qdss-etm.o
 
 quiet_cmd_mkrpcsym = MKCAP   $@
       cmd_mkrpcsym = $(PERL) $(srctree)/$(src)/mkrpcsym.pl $< $@
diff --git a/arch/arm/mach-msm/acpuclock-7627.c b/arch/arm/mach-msm/acpuclock-7627.c
index 7c2c556..f9ff226 100644
--- a/arch/arm/mach-msm/acpuclock-7627.c
+++ b/arch/arm/mach-msm/acpuclock-7627.c
@@ -18,6 +18,7 @@
 
 #include <linux/version.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/string.h>
@@ -27,6 +28,8 @@
 #include <linux/mutex.h>
 #include <linux/io.h>
 #include <linux/sort.h>
+#include <linux/platform_device.h>
+
 #include <mach/board.h>
 #include <mach/msm_iomap.h>
 #include <mach/socinfo.h>
@@ -402,7 +405,7 @@
 #ifdef CONFIG_CPU_FREQ_MSM
 static struct cpufreq_frequency_table freq_table[NR_CPUS][20];
 
-static void __init cpufreq_table_init(void)
+static void __devinit cpufreq_table_init(void)
 {
 	int cpu;
 	for_each_possible_cpu(cpu) {
@@ -693,7 +696,7 @@
 	return rc;
 }
 
-static void __init acpuclk_hw_init(void)
+static void __devinit acpuclk_hw_init(void)
 {
 	struct clkctl_acpu_speed *speed;
 	uint32_t div, sel, reg_clksel;
@@ -775,7 +778,7 @@
  * Clock driver initialization
  *---------------------------------------------------------------------------*/
 #define MHZ 1000000
-static void __init select_freq_plan(void)
+static void __devinit select_freq_plan(void)
 {
 	unsigned long pll_mhz[ACPU_PLL_END];
 	struct pll_freq_tbl_map *t;
@@ -835,7 +838,7 @@
  * Hardware requires the CPU to be dropped to less than MAX_WAIT_FOR_IRQ_KHZ
  * before entering a wait for irq low-power mode. Find a suitable rate.
  */
-static unsigned long __init find_wait_for_irq_khz(void)
+static unsigned long __devinit find_wait_for_irq_khz(void)
 {
 	unsigned long found_khz = 0;
 	int i;
@@ -847,7 +850,7 @@
 	return found_khz;
 }
 
-static void __init lpj_init(void)
+static void __devinit lpj_init(void)
 {
 	int i = 0, cpu;
 	const struct clkctl_acpu_speed *base_clk = drv_state.current_speed;
@@ -868,7 +871,7 @@
 	}
 }
 
-static void __init precompute_stepping(void)
+static void __devinit precompute_stepping(void)
 {
 	int i, step_idx;
 
@@ -909,7 +912,7 @@
 	}
 }
 
-static void __init print_acpu_freq_tbl(void)
+static void __devinit print_acpu_freq_tbl(void)
 {
 	struct clkctl_acpu_speed *t;
 	short down_idx[ACPU_PLL_END];
@@ -947,15 +950,17 @@
 	.switch_time_us = 50,
 };
 
-static int __init acpuclk_7627_init(struct acpuclk_soc_data *soc_data)
+static int __devinit acpuclk_7627_probe(struct platform_device *pdev)
 {
+	const struct acpuclk_pdata *pdata = pdev->dev.platform_data;
+
 	pr_info("%s()\n", __func__);
 
 	drv_state.ebi1_clk = clk_get(NULL, "ebi1_acpu_clk");
 	BUG_ON(IS_ERR(drv_state.ebi1_clk));
 
 	mutex_init(&drv_state.lock);
-	drv_state.max_speed_delta_khz = soc_data->max_speed_delta_khz;
+	drv_state.max_speed_delta_khz = pdata->max_speed_delta_khz;
 	select_freq_plan();
 	acpuclk_7627_data.wait_for_irq_khz = find_wait_for_irq_khz();
 	precompute_stepping();
@@ -970,23 +975,16 @@
 	return 0;
 }
 
-struct acpuclk_soc_data acpuclk_7x27_soc_data __initdata = {
-	.max_speed_delta_khz = 400000,
-	.init = acpuclk_7627_init,
+static struct platform_driver acpuclk_7627_driver = {
+	.probe = acpuclk_7627_probe,
+	.driver = {
+		.name = "acpuclk-7627",
+		.owner = THIS_MODULE,
+	},
 };
 
-struct acpuclk_soc_data acpuclk_7x27a_soc_data __initdata = {
-	.max_speed_delta_khz = 400000,
-	.init = acpuclk_7627_init,
-};
-
-struct acpuclk_soc_data acpuclk_7x27aa_soc_data __initdata = {
-	.max_speed_delta_khz = 504000,
-	.init = acpuclk_7627_init,
-};
-
-struct acpuclk_soc_data acpuclk_8625_soc_data __initdata = {
-	/* TODO: Need to update speed delta from H/w Team */
-	.max_speed_delta_khz = 604800,
-	.init = acpuclk_7627_init,
-};
+static int __init acpuclk_7627_init(void)
+{
+	return platform_driver_register(&acpuclk_7627_driver);
+}
+postcore_initcall(acpuclk_7627_init);
diff --git a/arch/arm/mach-msm/acpuclock-7x30.c b/arch/arm/mach-msm/acpuclock-7x30.c
index 29b0065..b49613e 100644
--- a/arch/arm/mach-msm/acpuclock-7x30.c
+++ b/arch/arm/mach-msm/acpuclock-7x30.c
@@ -16,6 +16,7 @@
 
 #include <linux/version.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/string.h>
@@ -25,6 +26,7 @@
 #include <linux/mutex.h>
 #include <linux/io.h>
 #include <linux/sort.h>
+#include <linux/platform_device.h>
 #include <mach/board.h>
 #include <mach/msm_iomap.h>
 #include <asm/mach-types.h>
@@ -315,7 +317,7 @@
  * Clock driver initialization
  *---------------------------------------------------------------------------*/
 
-static void __init acpuclk_hw_init(void)
+static void __devinit acpuclk_hw_init(void)
 {
 	struct clkctl_acpu_speed *s;
 	uint32_t div, sel, src_num;
@@ -393,7 +395,7 @@
 }
 
 /* Initalize the lpj field in the acpu_freq_tbl. */
-static void __init lpj_init(void)
+static void __devinit lpj_init(void)
 {
 	int i;
 	const struct clkctl_acpu_speed *base_clk = drv_state.current_speed;
@@ -431,7 +433,7 @@
  * Truncate the frequency table at the current PLL2 rate and determine the
  * backup PLL to use when scaling PLL2.
  */
-void __init pll2_fixup(void)
+void __devinit pll2_fixup(void)
 {
 	struct clkctl_acpu_speed *speed = acpu_freq_tbl;
 	u8 pll2_l = readl_relaxed(PLL2_L_VAL_ADDR) & 0xFF;
@@ -453,7 +455,7 @@
 #define RPM_BYPASS_MASK	(1 << 3)
 #define PMIC_MODE_MASK	(1 << 4)
 
-static void __init populate_plls(void)
+static void __devinit populate_plls(void)
 {
 	acpuclk_sources[PLL_1] = clk_get_sys("acpu", "pll1_clk");
 	BUG_ON(IS_ERR(acpuclk_sources[PLL_1]));
@@ -479,7 +481,7 @@
 	.switch_time_us = 50,
 };
 
-static int __init acpuclk_7x30_init(struct acpuclk_soc_data *soc_data)
+static int __devinit acpuclk_7x30_probe(struct platform_device *pdev)
 {
 	pr_info("%s()\n", __func__);
 
@@ -494,6 +496,16 @@
 	return 0;
 }
 
-struct acpuclk_soc_data acpuclk_7x30_soc_data __initdata = {
-	.init = acpuclk_7x30_init,
+static struct platform_driver acpuclk_7x30_driver = {
+	.probe = acpuclk_7x30_probe,
+	.driver = {
+		.name = "acpuclk-7x30",
+		.owner = THIS_MODULE,
+	},
 };
+
+static int __init acpuclk_7x30_init(void)
+{
+	return platform_driver_register(&acpuclk_7x30_driver);
+}
+postcore_initcall(acpuclk_7x30_init);
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index 99003f9..d29fee6 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -13,6 +13,7 @@
 #define pr_fmt(fmt) "%s: " fmt, __func__
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/delay.h>
@@ -22,6 +23,7 @@
 #include <linux/cpufreq.h>
 #include <linux/cpu.h>
 #include <linux/regulator/consumer.h>
+#include <linux/platform_device.h>
 
 #include <asm/mach-types.h>
 #include <asm/cpu.h>
@@ -660,7 +662,7 @@
 	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1175000 },
 	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1187500 },
 	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1187500 },
-	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1212500 },
+	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1200000 },
 	{ 0, { 0 } }
 };
 
@@ -687,7 +689,7 @@
 	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1125000 },
 	{ 0, {  1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1137500 },
 	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1137500 },
-	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1175000 },
+	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1150000 },
 	{ 0, { 0 } }
 };
 
@@ -1649,7 +1651,7 @@
 	.wait_for_irq_khz = STBY_KHZ,
 };
 
-static int __init acpuclk_8960_init(struct acpuclk_soc_data *soc_data)
+static int __init acpuclk_8960_probe(struct platform_device *pdev)
 {
 	struct acpu_level *max_acpu_level = select_freq_plan();
 
@@ -1667,14 +1669,15 @@
 	return 0;
 }
 
-struct acpuclk_soc_data acpuclk_8960_soc_data __initdata = {
-	.init = acpuclk_8960_init,
+static struct platform_driver acpuclk_8960_driver = {
+	.driver = {
+		.name = "acpuclk-8960",
+		.owner = THIS_MODULE,
+	},
 };
 
-struct acpuclk_soc_data acpuclk_8930_soc_data __initdata = {
-	.init = acpuclk_8960_init,
-};
-
-struct acpuclk_soc_data acpuclk_8064_soc_data __initdata = {
-	.init = acpuclk_8960_init,
-};
+static int __init acpuclk_8960_init(void)
+{
+	return platform_driver_probe(&acpuclk_8960_driver, acpuclk_8960_probe);
+}
+device_initcall(acpuclk_8960_init);
diff --git a/arch/arm/mach-msm/acpuclock-8x50.c b/arch/arm/mach-msm/acpuclock-8x50.c
index cde5a14..996f883 100644
--- a/arch/arm/mach-msm/acpuclock-8x50.c
+++ b/arch/arm/mach-msm/acpuclock-8x50.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
@@ -12,6 +12,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/delay.h>
@@ -20,6 +21,7 @@
 #include <linux/cpufreq.h>
 #include <linux/clk.h>
 #include <linux/mfd/tps65023.h>
+#include <linux/platform_device.h>
 
 #include <mach/board.h>
 #include <mach/msm_iomap.h>
@@ -130,7 +132,7 @@
 #ifdef CONFIG_CPU_FREQ_MSM
 static struct cpufreq_frequency_table freq_table[20];
 
-static void __init cpufreq_table_init(void)
+static void __devinit cpufreq_table_init(void)
 {
 	unsigned int i;
 	unsigned int freq_cnt = 0;
@@ -504,7 +506,7 @@
 	return rc;
 }
 
-static void __init acpuclk_hw_init(void)
+static void __devinit acpuclk_hw_init(void)
 {
 	struct clkctl_acpu_speed *speed;
 	uint32_t div, sel, regval;
@@ -582,7 +584,7 @@
 
 #define PLL0_M_VAL_ADDR		(MSM_CLK_CTL_BASE + 0x308)
 
-static void __init acpu_freq_tbl_fixup(void)
+static void __devinit acpu_freq_tbl_fixup(void)
 {
 	void __iomem *ct_csr_base;
 	uint32_t tcsr_spare2, pll0_m_val;
@@ -645,7 +647,7 @@
 }
 
 /* Initalize the lpj field in the acpu_freq_tbl. */
-static void __init lpj_init(void)
+static void __devinit lpj_init(void)
 {
 	int i;
 	const struct clkctl_acpu_speed *base_clk = drv_state.current_speed;
@@ -657,7 +659,7 @@
 }
 
 #ifdef CONFIG_MSM_CPU_AVS
-static int __init acpu_avs_init(int (*set_vdd) (int), int khz)
+static int __devinit acpu_avs_init(int (*set_vdd) (int), int khz)
 {
 	int i;
 	int freq_count = 0;
@@ -704,7 +706,7 @@
 	.switch_time_us = 20,
 };
 
-static int __init acpuclk_8x50_init(struct acpuclk_soc_data *soc_data)
+static int __devinit acpuclk_8x50_probe(struct platform_device *pdev)
 {
 	mutex_init(&drv_state.lock);
 	drv_state.acpu_set_vdd = qsd8x50_tps65023_set_dcdc1;
@@ -736,6 +738,16 @@
 	return 0;
 }
 
-struct acpuclk_soc_data acpuclk_8x50_soc_data __initdata = {
-	.init = acpuclk_8x50_init,
+static struct platform_driver acpuclk_8x50_driver = {
+	.probe = acpuclk_8x50_probe,
+	.driver = {
+		.name = "acpuclk-8x50",
+		.owner = THIS_MODULE,
+	},
 };
+
+static int __init acpuclk_8x50_init(void)
+{
+	return platform_driver_register(&acpuclk_8x50_driver);
+}
+postcore_initcall(acpuclk_8x50_init);
diff --git a/arch/arm/mach-msm/acpuclock-8x60.c b/arch/arm/mach-msm/acpuclock-8x60.c
index 48efa18..ef34b3c 100644
--- a/arch/arm/mach-msm/acpuclock-8x60.c
+++ b/arch/arm/mach-msm/acpuclock-8x60.c
@@ -11,6 +11,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/delay.h>
@@ -20,6 +21,7 @@
 #include <linux/cpufreq.h>
 #include <linux/cpu.h>
 #include <linux/regulator/consumer.h>
+#include <linux/platform_device.h>
 
 #include <asm/cpu.h>
 
@@ -734,7 +736,7 @@
 	}
 
 	/* AVS needs SAW_VCTL to be intitialized correctly, before enable,
-	 * and is not initialized at acpuclk_init().
+	 * and is not initialized during probe.
 	 */
 	if (reason == SETRATE_CPUFREQ)
 		AVS_DISABLE(cpu);
@@ -1062,7 +1064,7 @@
 	.wait_for_irq_khz = MAX_AXI,
 };
 
-static int __init acpuclk_8x60_init(struct acpuclk_soc_data *soc_data)
+static int __init acpuclk_8x60_probe(struct platform_device *pdev)
 {
 	struct clkctl_acpu_speed *max_freq;
 	int cpu;
@@ -1091,6 +1093,15 @@
 	return 0;
 }
 
-struct acpuclk_soc_data acpuclk_8x60_soc_data __initdata = {
-	.init = acpuclk_8x60_init,
+static struct platform_driver acpuclk_8x60_driver = {
+	.driver = {
+		.name = "acpuclk-8x60",
+		.owner = THIS_MODULE,
+	},
 };
+
+static int __init acpuclk_8x60_init(void)
+{
+	return platform_driver_probe(&acpuclk_8x60_driver, acpuclk_8x60_probe);
+}
+device_initcall(acpuclk_8x60_init);
diff --git a/arch/arm/mach-msm/acpuclock-9615.c b/arch/arm/mach-msm/acpuclock-9615.c
index 24b81b9..db7bab3 100644
--- a/arch/arm/mach-msm/acpuclock-9615.c
+++ b/arch/arm/mach-msm/acpuclock-9615.c
@@ -14,6 +14,7 @@
 #define pr_fmt(fmt) "%s: " fmt, __func__
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/delay.h>
@@ -22,6 +23,7 @@
 #include <linux/errno.h>
 #include <linux/cpufreq.h>
 #include <linux/clk.h>
+#include <linux/platform_device.h>
 
 #include <asm/cpu.h>
 
@@ -306,7 +308,7 @@
 	.wait_for_irq_khz = 19200,
 };
 
-static int __init acpuclk_9615_init(struct acpuclk_soc_data *soc_data)
+static int __init acpuclk_9615_probe(struct platform_device *pdev)
 {
 	unsigned long max_cpu_khz = 0;
 	int i;
@@ -351,6 +353,15 @@
 	return 0;
 }
 
-struct acpuclk_soc_data acpuclk_9615_soc_data __initdata = {
-	.init = acpuclk_9615_init,
+static struct platform_driver acpuclk_9615_driver = {
+	.driver = {
+		.name = "acpuclk-9615",
+		.owner = THIS_MODULE,
+	},
 };
+
+static int __init acpuclk_9615_init(void)
+{
+	return platform_driver_probe(&acpuclk_9615_driver, acpuclk_9615_probe);
+}
+device_initcall(acpuclk_9615_init);
diff --git a/arch/arm/mach-msm/acpuclock-fsm9xxx.c b/arch/arm/mach-msm/acpuclock-fsm9xxx.c
index 3cdc58d..af1c0eb 100644
--- a/arch/arm/mach-msm/acpuclock-fsm9xxx.c
+++ b/arch/arm/mach-msm/acpuclock-fsm9xxx.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -11,8 +11,10 @@
  *
  */
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/platform_device.h>
 #include <mach/board.h>
 
 #include "acpuclock.h"
@@ -40,13 +42,22 @@
 	.get_rate = acpuclk_9xxx_get_rate,
 };
 
-static int __init acpuclk_9xxx_init(struct acpuclk_soc_data *soc_data)
+static int __init acpuclk_9xxx_probe(struct platform_device *pdev)
 {
 	acpuclk_register(&acpuclk_9xxx_data);
 	pr_info("ACPU running at %lu KHz\n", acpuclk_get_rate(0));
 	return 0;
 }
 
-struct acpuclk_soc_data acpuclk_9xxx_soc_data __initdata = {
-	.init = acpuclk_9xxx_init,
+static struct platform_driver acpuclk_9xxx_driver = {
+	.driver = {
+		.name = "acpuclk-9xxx",
+		.owner = THIS_MODULE,
+	},
 };
+
+static int __init acpuclk_9xxx_init(void)
+{
+	return platform_driver_probe(&acpuclk_9xxx_driver, acpuclk_9xxx_probe);
+}
+device_initcall(acpuclk_9xxx_init);
diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c
index 91071c4..be056e6 100644
--- a/arch/arm/mach-msm/acpuclock.c
+++ b/arch/arm/mach-msm/acpuclock.c
@@ -53,24 +53,7 @@
 	return rate;
 }
 
-void __init acpuclk_register(struct acpuclk_data *data)
+void __devinit acpuclk_register(struct acpuclk_data *data)
 {
 	acpuclk_data = data;
 }
-
-int __init acpuclk_init(struct acpuclk_soc_data *soc_data)
-{
-	int rc;
-
-	if (!soc_data->init)
-		return -EINVAL;
-
-	rc = soc_data->init(soc_data);
-	if (rc)
-		return rc;
-
-	if (!acpuclk_data)
-		return -ENODEV;
-
-	return 0;
-}
diff --git a/arch/arm/mach-msm/acpuclock.h b/arch/arm/mach-msm/acpuclock.h
index c5f0ee3..e73a2af 100644
--- a/arch/arm/mach-msm/acpuclock.h
+++ b/arch/arm/mach-msm/acpuclock.h
@@ -31,12 +31,11 @@
 };
 
 /**
- * struct acpuclk_soc_data - SoC data for acpuclk_init()
+ * struct acpuclk_pdata - Platform data for acpuclk
  */
-struct acpuclk_soc_data {
+struct acpuclk_pdata {
 	unsigned long max_speed_delta_khz;
 	unsigned int max_axi_khz;
-	int (*init)(struct acpuclk_soc_data *);
 };
 
 /**
@@ -91,25 +90,4 @@
  */
 void acpuclk_register(struct acpuclk_data *data);
 
-/**
- * acpuclk_init() - acpuclock driver initialization function
- *
- * Return 0 for success.
- */
-int acpuclk_init(struct acpuclk_soc_data *);
-
-/* SoC-specific acpuclock initialization functions. */
-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_7x30_soc_data;
-extern struct acpuclk_soc_data acpuclk_8x50_soc_data;
-extern struct acpuclk_soc_data acpuclk_8x60_soc_data;
-extern struct acpuclk_soc_data acpuclk_8960_soc_data;
-extern struct acpuclk_soc_data acpuclk_9xxx_soc_data;
-extern struct acpuclk_soc_data acpuclk_9615_soc_data;
-extern struct acpuclk_soc_data acpuclk_8930_soc_data;
-extern struct acpuclk_soc_data acpuclk_8064_soc_data;
-extern struct acpuclk_soc_data acpuclk_8625_soc_data;
-
 #endif
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index f7d5403..622b213 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -560,7 +560,7 @@
 	RPM_SMPS(S2, 0, 1, 0, 1300000, 1300000, NULL,      0, 1p60, NONE, NONE),
 	RPM_SMPS(S3, 0, 1, 1,  500000, 1150000, NULL, 100000, 4p80, NONE, NONE),
 	RPM_SMPS(S4, 1, 1, 0, 1800000, 1800000, NULL, 100000, 1p60, AUTO, AUTO),
-	RPM_SMPS(S7, 0, 1, 0, 1300000, 1300000, NULL, 100000, 3p20, NONE, NONE),
+	RPM_SMPS(S7, 0, 0, 0, 1300000, 1300000, NULL, 100000, 3p20, NONE, NONE),
 	RPM_SMPS(S8, 0, 1, 0, 2200000, 2200000, NULL,      0, 1p60, NONE, NONE),
 
 	/*	ID a_on pd ss min_uV   max_uV   supply    sys_uA init_ip */
@@ -586,7 +586,7 @@
 	RPM_LDO(L23, 0, 1, 0, 1800000, 1800000, NULL,          0,     0),
 	RPM_LDO(L24, 0, 1, 1,  750000, 1150000, "8921_s1", 10000, 10000),
 	RPM_LDO(L25, 1, 1, 0, 1250000, 1250000, "8921_s1", 10000, 10000),
-	RPM_LDO(L27, 0, 1, 0, 1100000, 1100000, "8921_s7",     0,     0),
+	RPM_LDO(L27, 0, 0, 0, 1100000, 1100000, "8921_s7",     0,     0),
 	RPM_LDO(L28, 0, 1, 0, 1050000, 1050000, "8921_s7",     0,     0),
 	RPM_LDO(L29, 0, 1, 0, 2000000, 2000000, NULL,          0,     0),
 
diff --git a/arch/arm/mach-msm/board-8064-storage.c b/arch/arm/mach-msm/board-8064-storage.c
index fe4beab..a53f771 100644
--- a/arch/arm/mach-msm/board-8064-storage.c
+++ b/arch/arm/mach-msm/board-8064-storage.c
@@ -291,7 +291,7 @@
 	.pin_data	= &mmc_slot_pin_data[SDCC3],
 	.vreg_data	= &mmc_slot_vreg_data[SDCC3],
 	.wpswitch_gpio	= PM8921_GPIO_PM_TO_SYS(17),
-	.wpswitch_polarity = 1,
+	.is_wpswitch_active_low = true,
 	.status_gpio	= 26,
 	.status_irq	= MSM_GPIO_TO_INT(26),
 	.irq_flags	= IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
@@ -354,7 +354,7 @@
 	if (apq8064_sdc3_pdata) {
 		if (!machine_is_apq8064_cdp()) {
 			apq8064_sdc3_pdata->wpswitch_gpio = 0;
-			apq8064_sdc3_pdata->wpswitch_polarity = 0;
+			apq8064_sdc3_pdata->is_wpswitch_active_low = false;
 		}
 		if (machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
 			machine_is_mpq8064_dtv()) {
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 40b87fc..e4958f5 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -29,6 +29,7 @@
 #include <linux/ion.h>
 #include <linux/memory.h>
 #include <linux/memblock.h>
+#include <linux/msm_thermal.h>
 #include <linux/i2c/atmel_mxt_ts.h>
 #include <linux/cyttsp-qc.h>
 #include <linux/i2c/isa1200.h>
@@ -74,7 +75,6 @@
 
 #include "msm_watchdog.h"
 #include "board-8064.h"
-#include "acpuclock.h"
 #include "spm.h"
 #include <mach/mpm.h>
 #include "rpm_resources.h"
@@ -1717,6 +1717,14 @@
 	.id = -1,
 };
 
+static struct msm_thermal_data msm_thermal_pdata = {
+	.sensor_id = 7,
+	.poll_ms = 1000,
+	.limit_temp = 60,
+	.temp_hysteresis = 10,
+	.limit_freq = 918000,
+};
+
 #define MSM_SHARED_RAM_PHYS 0x80000000
 static void __init apq8064_map_io(void)
 {
@@ -2110,6 +2118,7 @@
 };
 
 static struct platform_device *common_devices[] __initdata = {
+	&msm8960_device_acpuclk,
 	&apq8064_device_dmov,
 	&apq8064_device_qup_spi_gsbi5,
 	&apq8064_device_ext_5v_vreg,
@@ -2864,6 +2873,7 @@
 static void __init apq8064_common_init(void)
 {
 	msm_tsens_early_init(&apq_tsens_pdata);
+	msm_thermal_init(&msm_thermal_pdata);
 	if (socinfo_init() < 0)
 		pr_err("socinfo_init() failed!\n");
 	BUG_ON(msm_rpm_init(&apq8064_rpm_data));
@@ -2911,7 +2921,6 @@
 		ARRAY_SIZE(apq8064_slim_devices));
 	apq8064_init_dsps();
 	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
-	acpuclk_init(&acpuclk_8064_soc_data);
 	msm_spm_l2_init(msm_spm_l2_data);
 	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 	msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data);
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
index 65da578..739b1c7 100644
--- a/arch/arm/mach-msm/board-8930-storage.c
+++ b/arch/arm/mach-msm/board-8930-storage.c
@@ -220,7 +220,7 @@
 #define MSM_MPM_PIN_SDC3_DAT1	21
 
 static unsigned int sdc1_sup_clk_rates[] = {
-	400000, 24000000, 48000000,
+	400000, 24000000, 48000000, 96000000
 };
 
 #ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
@@ -259,7 +259,7 @@
 	.wpswitch_gpio	= PM8921_GPIO_PM_TO_SYS(16),
 #else
 	.wpswitch_gpio	= 66,
-	.wpswitch_polarity = 1,
+	.is_wpswitch_active_low = true,
 #endif
 #endif
 	.vreg_data	= &mmc_slot_vreg_data[SDCC3],
@@ -288,6 +288,16 @@
 void __init msm8930_init_mmc(void)
 {
 #ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+	/*
+	 * When eMMC runs in DDR mode on CDP platform, we have
+	 * seen instability due to DATA CRC errors. These errors are
+	 * attributed to long physical path between MSM and eMMC on CDP.
+	 * So let's not enable the DDR mode on CDP platform but let other
+	 * platforms take advantage of eMMC DDR mode.
+	 */
+	if (!machine_is_msm8930_cdp())
+		msm8960_sdc1_data.uhs_caps |= (MMC_CAP_1_8V_DDR |
+					       MMC_CAP_UHS_DDR50);
 	/* SDC1 : eMMC card connected */
 	msm_add_sdcc(1, &msm8960_sdc1_data);
 #endif
@@ -295,7 +305,7 @@
 	/* SDC3: External card slot */
 	if (!machine_is_msm8930_cdp()) {
 		msm8960_sdc3_data.wpswitch_gpio = 0;
-		msm8960_sdc3_data.wpswitch_polarity = 0;
+		msm8960_sdc3_data.is_wpswitch_active_low = false;
 	}
 	msm_add_sdcc(3, &msm8960_sdc3_data);
 #endif
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 6c4cbd3..ab9fe5e 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -42,6 +42,7 @@
 #include <linux/gpio_keys.h>
 #include <linux/memory.h>
 #include <linux/memblock.h>
+#include <linux/msm_thermal.h>
 
 #include <linux/slimbus/slimbus.h>
 #include <linux/mfd/wcd9xxx/core.h>
@@ -86,7 +87,6 @@
 #include <mach/cpuidle.h>
 #include "rpm_resources.h"
 #include <mach/mpm.h>
-#include "acpuclock.h"
 #include "smd_private.h"
 #include "pm-boot.h"
 #include "msm_watchdog.h"
@@ -1415,6 +1415,14 @@
 };
 #endif
 
+static int hsusb_phy_init_seq[] = {
+	0x44, 0x80, /* set VBUS valid threshold
+			and disconnect valid threshold */
+	0x38, 0x81, /* update DC voltage level */
+	0x24, 0x82, /* set preemphasis and rise/fall time */
+	0x13, 0x83, /* set source impedance adjusment */
+	-1};
+
 static struct msm_otg_platform_data msm_otg_pdata = {
 	.mode			= USB_OTG,
 	.otg_control		= OTG_PMIC_CONTROL,
@@ -1974,6 +1982,14 @@
 	.id = -1,
 };
 
+static struct msm_thermal_data msm_thermal_pdata = {
+	.sensor_id = 9,
+	.poll_ms = 1000,
+	.limit_temp = 60,
+	.temp_hysteresis = 10,
+	.limit_freq = 918000,
+};
+
 #ifdef CONFIG_MSM_FAKE_BATTERY
 static struct platform_device fish_battery_device = {
 	.name = "fish_battery",
@@ -2035,6 +2051,7 @@
 };
 
 static struct platform_device *common_devices[] __initdata = {
+	&msm8960_device_acpuclk,
 	&msm8960_device_dmov,
 	&msm_device_smd,
 	&msm8960_device_uart_gsbi5,
@@ -2384,6 +2401,7 @@
 		pr_err("meminfo_init() failed!\n");
 
 	msm_tsens_early_init(&msm_tsens_pdata);
+	msm_thermal_init(&msm_thermal_pdata);
 	BUG_ON(msm_rpm_init(&msm8930_rpm_data));
 	BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
 
@@ -2392,6 +2410,7 @@
 		pr_err("Failed to initialize XO votes\n");
 	platform_device_register(&msm8930_device_rpm_regulator);
 	msm_clock_init(&msm8930_clock_init_data);
+	msm_otg_pdata.phy_init_seq = hsusb_phy_init_seq;
 	msm8960_device_otg.dev.platform_data = &msm_otg_pdata;
 	android_usb_pdata.swfi_latency =
 			msm_rpmrs_levels[0].latency_us;
@@ -2433,7 +2452,6 @@
 	msm8930_init_cam();
 #endif
 	msm8930_init_mmc();
-	acpuclk_init(&acpuclk_8930_soc_data);
 	mxt_init_vkeys_8930();
 	register_i2c_devices();
 	msm8930_init_fb();
diff --git a/arch/arm/mach-msm/board-8960-storage.c b/arch/arm/mach-msm/board-8960-storage.c
index e674e91..4b09f82 100644
--- a/arch/arm/mach-msm/board-8960-storage.c
+++ b/arch/arm/mach-msm/board-8960-storage.c
@@ -271,7 +271,7 @@
 #define MSM_MPM_PIN_SDC3_DAT1	21
 
 static unsigned int sdc1_sup_clk_rates[] = {
-	400000, 24000000, 48000000
+	400000, 24000000, 48000000, 96000000
 };
 
 #ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
@@ -361,6 +361,16 @@
 void __init msm8960_init_mmc(void)
 {
 #ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+	/*
+	 * When eMMC runs in DDR mode on CDP platform, we have
+	 * seen instability due to DATA CRC errors. These errors are
+	 * attributed to long physical path between MSM and eMMC on CDP.
+	 * So let's not enable the DDR mode on CDP platform but let other
+	 * platforms take advantage of eMMC DDR mode.
+	 */
+	if (!machine_is_msm8960_cdp())
+		msm8960_sdc1_data.uhs_caps |= (MMC_CAP_1_8V_DDR |
+					       MMC_CAP_UHS_DDR50);
 	/* SDC1 : eMMC card connected */
 	msm_add_sdcc(1, &msm8960_sdc1_data);
 #endif
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 8f49afd..628a324 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -42,6 +42,7 @@
 #include <linux/i2c/isa1200.h>
 #include <linux/memory.h>
 #include <linux/memblock.h>
+#include <linux/msm_thermal.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -97,7 +98,6 @@
 #include <mach/cpuidle.h>
 #include "rpm_resources.h"
 #include <mach/mpm.h>
-#include "acpuclock.h"
 #include "smd_private.h"
 #include "pm-boot.h"
 #include "msm_watchdog.h"
@@ -2428,6 +2428,14 @@
 	.id = -1,
 };
 
+static struct msm_thermal_data msm_thermal_pdata = {
+	.sensor_id = 0,
+	.poll_ms = 1000,
+	.limit_temp = 60,
+	.temp_hysteresis = 10,
+	.limit_freq = 918000,
+};
+
 #ifdef CONFIG_MSM_FAKE_BATTERY
 static struct platform_device fish_battery_device = {
 	.name = "fish_battery",
@@ -2508,6 +2516,7 @@
 #endif
 
 static struct platform_device *common_devices[] __initdata = {
+	&msm8960_device_acpuclk,
 	&msm8960_device_dmov,
 	&msm_device_smd,
 	&msm_device_uart_dm6,
@@ -3044,6 +3053,7 @@
 
 	wdog_pdata->bark_time = 15000;
 	msm_tsens_early_init(&msm_tsens_pdata);
+	msm_thermal_init(&msm_thermal_pdata);
 	BUG_ON(msm_rpm_init(&msm8960_rpm_data));
 	BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
 	regulator_suppress_info_printing();
@@ -3060,7 +3070,6 @@
 	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
 	msm8960_pm8921_gpio_mpp_init();
 	platform_add_devices(sim_devices, ARRAY_SIZE(sim_devices));
-	acpuclk_init(&acpuclk_8960_soc_data);
 
 	msm8960_device_qup_spi_gsbi1.dev.platform_data =
 				&msm8960_qup_spi_gsbi1_pdata;
@@ -3077,6 +3086,7 @@
 static void __init msm8960_rumi3_init(void)
 {
 	msm_tsens_early_init(&msm_tsens_pdata);
+	msm_thermal_init(&msm_thermal_pdata);
 	BUG_ON(msm_rpm_init(&msm8960_rpm_data));
 	BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
 	regulator_suppress_info_printing();
@@ -3109,6 +3119,7 @@
 		pr_err("meminfo_init() failed!\n");
 
 	msm_tsens_early_init(&msm_tsens_pdata);
+	msm_thermal_init(&msm_thermal_pdata);
 	BUG_ON(msm_rpm_init(&msm8960_rpm_data));
 	BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
 
@@ -3173,7 +3184,6 @@
 	msm8960_init_cam();
 #endif
 	msm8960_init_mmc();
-	acpuclk_init(&acpuclk_8960_soc_data);
 	if (machine_is_msm8960_liquid())
 		mxt_init_hw_liquid();
 	register_i2c_devices();
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index dc376b5..568de46 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -50,7 +50,6 @@
 #include "devices.h"
 #include "board-9615.h"
 #include "pm.h"
-#include "acpuclock.h"
 #include "pm-boot.h"
 #include <mach/gpiomux.h>
 
@@ -759,10 +758,11 @@
 	.vbus_power		= msm_hsusb_vbus_power,
 	.disable_reset_on_disconnect	= true,
 	.enable_lpm_on_dev_suspend	= true,
+	.core_clk_always_on_workaround = true,
 };
 
 static struct msm_hsic_peripheral_platform_data msm_hsic_peripheral_pdata = {
-	.keep_core_clk_on_suspend_workaround = true,
+	.core_clk_always_on_workaround = true,
 };
 
 #define PID_MAGIC_ID		0x71432909
@@ -850,6 +850,7 @@
 };
 
 static struct platform_device *common_devices[] = {
+	&msm9615_device_acpuclk,
 	&msm9615_device_dmov,
 	&msm_device_smd,
 #ifdef CONFIG_LTC4088_CHARGER
@@ -979,7 +980,6 @@
 	msm_device_usb_bam.dev.platform_data = &msm_usb_bam_pdata;
 	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
 	msm9615_pm8xxx_gpio_mpp_init();
-	acpuclk_init(&acpuclk_9615_soc_data);
 
 	/* Ensure ar6000pm device is registered before MMC/SDC */
 	msm9615_init_ar6000pm();
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index 4dda0b7..94a73c6 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -443,6 +443,12 @@
 	CLK_DUMMY("core_clk",	NULL,	"f9966000.i2c", 0),
 	CLK_DUMMY("iface_clk",	NULL,	"f9966000.i2c", 0),
 	CLK_DUMMY("core_clk",	NULL,	"fe12f000.slim",	OFF),
+	CLK_DUMMY("core_clk", "mdp.0", NULL, 0),
+	CLK_DUMMY("core_clk_src", "mdp.0", NULL, 0),
+	CLK_DUMMY("lut_clk", "mdp.0", NULL, 0),
+	CLK_DUMMY("vsync_clk", "mdp.0", NULL, 0),
+	CLK_DUMMY("iface_clk", "mdp.0", NULL, 0),
+	CLK_DUMMY("bus_clk", "mdp.0", NULL, 0),
 };
 
 struct clock_init_data msm_dummy_clock_init_data __initdata = {
@@ -511,6 +517,7 @@
 			"msm_rng", NULL),
 	OF_DEV_AUXDATA("qcom,qseecom", 0xFE806000, \
 			"qseecom", NULL),
+	OF_DEV_AUXDATA("qcom,mdss_mdp", 0xFD900000, "mdp.0", NULL),
 	{}
 };
 
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
index 6ad3cef..b071353 100644
--- a/arch/arm/mach-msm/board-fsm9xxx.c
+++ b/arch/arm/mach-msm/board-fsm9xxx.c
@@ -38,7 +38,6 @@
 #include <mach/socinfo.h>
 #include "devices.h"
 #include "timer.h"
-#include "acpuclock.h"
 #include "pm.h"
 #include "spm.h"
 #include <linux/regulator/consumer.h>
@@ -804,11 +803,17 @@
 	},
 };
 
+static struct platform_device fsm9xxx_device_acpuclk = {
+	.name		= "acpuclk-9xxx",
+	.id		= -1,
+};
+
 /*
  * Devices
  */
 
 static struct platform_device *devices[] __initdata = {
+	&fsm9xxx_device_acpuclk,
 	&msm_device_smd,
 	&msm_device_dmov,
 	&msm_device_nand,
@@ -873,8 +878,6 @@
 
 static void __init fsm9xxx_init(void)
 {
-	acpuclk_init(&acpuclk_9xxx_soc_data);
-
 	regulator_has_full_constraints();
 
 #if defined(CONFIG_I2C_SSBI) || defined(CONFIG_MSM_SSBI)
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index 38bdeca..3ab5ba0 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -120,6 +120,21 @@
 	{"usb2", REG_LDO, 1800000, 1800000, 0},
 };
 
+static struct camera_vreg_t ov5647_gpio_vreg[] = {
+	{"cam_ov5647_avdd", REG_GPIO, 0, 0, 0},
+	{"cam_ov5647_vdd", REG_GPIO, 0, 0, 0},
+};
+
+static struct camera_vreg_t ov8825_gpio_vreg[] = {
+	{"cam_ov8825_avdd", REG_GPIO, 0, 0, 0},
+	{"cam_ov8825_vdd", REG_GPIO, 0, 0, 0},
+};
+
+static struct camera_vreg_t ov7692_gpio_vreg[] = {
+	{"cam_ov7692_avdd", REG_GPIO, 0, 0, 0},
+	{"cam_ov7692_vdd", REG_GPIO, 0, 0, 0},
+};
+
 static struct msm_camera_sensor_info msm_camera_sensor_s5k4e1_data;
 
 struct msm_camera_device_platform_data msm_camera_device_data_csi1[] = {
@@ -180,7 +195,6 @@
 static struct msm_camera_sensor_info msm_camera_sensor_s5k4e1_data = {
 	.sensor_name    = "s5k4e1",
 	.sensor_reset_enable = 1,
-	.pmic_gpio_enable    = 0,
 	.pdata                  = &msm_camera_device_data_csi1[0],
 	.flash_data             = &flash_s5k4e1,
 	.sensor_platform_info   = &sensor_board_info_s5k4e1,
@@ -206,8 +220,6 @@
 static struct msm_camera_sensor_info msm_camera_sensor_ov7692_data = {
 	.sensor_name	    = "ov7692",
 	.sensor_reset_enable    = 0,
-	.pmic_gpio_enable  = 1,
-	.sensor_lcd_gpio_onoff = lcd_camera_power_onoff,
 	.sensor_reset	   = GPIO_SKU1_CAM_VGA_RESET_N,
 	.sensor_pwd	     = GPIO_SKU1_CAM_VGA_SHDN,
 	.pdata			= &msm_camera_device_data_csi0[0],
@@ -250,8 +262,6 @@
 static struct msm_camera_sensor_info msm_camera_sensor_ov5647_data = {
 	.sensor_name    = "ov5647",
 	.sensor_reset_enable = 1,
-	.pmic_gpio_enable  = 1,
-	.sensor_lcd_gpio_onoff = lcd_camera_power_onoff,
 	.sensor_reset   = GPIO_SKU3_CAM_5MP_CAMIF_RESET,
 	.sensor_pwd     = GPIO_SKU3_CAM_5MP_SHDN_N,
 	.pdata          = &msm_camera_device_data_csi1[0],
@@ -311,7 +321,6 @@
 static struct msm_camera_sensor_info msm_camera_sensor_mt9e013_data = {
 	.sensor_name    = "mt9e013",
 	.sensor_reset_enable = 1,
-	.pmic_gpio_enable    = 0,
 	.pdata                  = &msm_camera_device_data_csi1[1],
 	.flash_data             = &flash_mt9e013,
 	.sensor_platform_info   = &sensor_board_info_mt9e013,
@@ -337,7 +346,6 @@
 static struct msm_camera_sensor_info msm_camera_sensor_ov9726_data = {
 	.sensor_name    = "ov9726",
 	.sensor_reset_enable = 0,
-	.pmic_gpio_enable  = 0,
 	.pdata                  = &msm_camera_device_data_csi0[0],
 	.flash_data             = &flash_ov9726,
 	.sensor_platform_info   = &sensor_board_info_ov9726,
@@ -371,6 +379,21 @@
 		sensor_board_info_ov8825.num_vreg = 0;
 
 	}
+	if (machine_is_msm8625_evb()
+			|| machine_is_msm8625_evt()) {
+		sensor_board_info_ov7692.cam_vreg =
+			ov7692_gpio_vreg;
+		sensor_board_info_ov7692.num_vreg =
+			ARRAY_SIZE(ov7692_gpio_vreg);
+		sensor_board_info_ov5647.cam_vreg =
+			ov5647_gpio_vreg;
+		sensor_board_info_ov5647.num_vreg =
+			ARRAY_SIZE(ov5647_gpio_vreg);
+		sensor_board_info_ov8825.cam_vreg =
+			ov8825_gpio_vreg;
+		sensor_board_info_ov8825.num_vreg =
+			ARRAY_SIZE(ov8825_gpio_vreg);
+	}
 	platform_device_register(&msm_camera_server);
 	if (machine_is_msm8625_surf() || machine_is_msm8625_evb()
 			|| machine_is_msm8625_evt()
@@ -1022,6 +1045,7 @@
 				ARRAY_SIZE(cam_exp_i2c_info));
 }
 
+#ifndef CONFIG_MSM_CAMERA_V4L2
 #define LCD_CAMERA_LDO_2V8 35 /* SKU1&SKU3 2.8V LDO */
 #define SKU3_LCD_CAMERA_LDO_1V8 40 /* SKU3 1.8V LDO */
 #define SKU7_LCD_CAMERA_LDO_1V8 58 /* SKU7 1.8V LDO */
@@ -1120,6 +1144,7 @@
 	return rc;
 }
 EXPORT_SYMBOL(lcd_camera_power_onoff);
+#endif
 
 void __init msm7627a_camera_init(void)
 {
@@ -1140,7 +1165,6 @@
 			GPIO_SKU7_CAM_5MP_SHDN_N;
 		msm_camera_sensor_ov5647_data.sensor_reset =
 			GPIO_SKU7_CAM_5MP_CAMIF_RESET;
-
 	}
 
 	/* LCD and camera power (VREG & LDO) init */
@@ -1148,8 +1172,9 @@
 			|| machine_is_msm8625_evt()
 			|| machine_is_msm7627a_qrd3()
 			|| machine_is_msm8625_qrd7()) {
-
+#ifndef CONFIG_MSM_CAMERA_V4L2
 		lcd_camera_power_init();
+#endif
 		evb_camera_gpio_cfg();
 	}
 
diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c
index d42458f..a7fed3e 100644
--- a/arch/arm/mach-msm/board-msm7x27.c
+++ b/arch/arm/mach-msm/board-msm7x27.c
@@ -65,7 +65,6 @@
 #include "board-msm7627-regulator.h"
 #include "devices.h"
 #include "clock.h"
-#include "acpuclock.h"
 #include "msm-keypad-devices.h"
 #include "pm.h"
 #include "pm-boot.h"
@@ -1775,7 +1774,7 @@
 		}
 	}
 #endif
-	acpuclk_init(&acpuclk_7x27_soc_data);
+	platform_device_register(&msm7x27_device_acpuclk);
 
 	usb_mpp_init();
 
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 1521a6c..dc473e6 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -162,7 +162,7 @@
 #define MSM_PMEM_MDP_SIZE       0x2300000
 #define MSM7x25A_MSM_PMEM_MDP_SIZE       0x1500000
 
-#define MSM_PMEM_ADSP_SIZE      0x1100000
+#define MSM_PMEM_ADSP_SIZE      0x1200000
 #define MSM7x25A_MSM_PMEM_ADSP_SIZE      0xB91000
 
 #endif
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 010d9ec..2834f24 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -105,7 +105,7 @@
  */
 #define MSM_V4L2_VIDEO_OVERLAY_BUF_SIZE 2764800
 
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+#ifdef CONFIG_FB_MSM_HDMI_ADV7520_PANEL
 #define MSM_FB_EXT_BUF_SIZE (1280 * 720 * 2 * 1) /* 2 bpp x 1 page */
 #else
 #define MSM_FB_EXT_BUF_SIZE    0
@@ -6956,7 +6956,7 @@
 	msm7x30_init_uart2();
 #endif
 	msm_spm_init(&msm_spm_data, 1);
-	acpuclk_init(&acpuclk_7x30_soc_data);
+	platform_device_register(&msm7x30_device_acpuclk);
 	if (machine_is_msm7x30_surf() || machine_is_msm7x30_fluid())
 		msm7x30_cfg_smsc911x();
 
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 54c8fbd..098ad6e 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -100,7 +100,6 @@
 #include "peripheral-loader.h"
 #include <linux/platform_data/qcom_crypto_device.h>
 #include "rpm_resources.h"
-#include "acpuclock.h"
 #include "pm-boot.h"
 #include "board-storage-common-a.h"
 
@@ -5135,6 +5134,7 @@
 };
 
 static struct platform_device *surf_devices[] __initdata = {
+	&msm8x60_device_acpuclk,
 	&msm_device_smd,
 	&msm_device_uart_dm12,
 	&msm_pil_q6v3,
@@ -10339,9 +10339,6 @@
 	 */
 	msm8x60_init_buses();
 	platform_add_devices(early_devices, ARRAY_SIZE(early_devices));
-	/* CPU frequency control is not supported on simulated targets. */
-	if (!machine_is_msm8x60_rumi3() && !machine_is_msm8x60_sim())
-		acpuclk_init(&acpuclk_8x60_soc_data);
 
 	/*
 	 * Enable EBI2 only for boards which make use of it. Leave
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index d8d8934..9c80c8b 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -130,7 +130,7 @@
 
 #ifdef CONFIG_ARCH_MSM7X27A
 #define MSM_PMEM_MDP_SIZE       0x2300000
-#define MSM_PMEM_ADSP_SIZE      0x1100000
+#define MSM_PMEM_ADSP_SIZE      0x1200000
 #endif
 
 static struct android_usb_platform_data android_usb_pdata = {
diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c
index 6a39316..4df4266 100644
--- a/arch/arm/mach-msm/board-qsd8x50.c
+++ b/arch/arm/mach-msm/board-qsd8x50.c
@@ -2409,7 +2409,7 @@
 {
 	msm_clock_init(&qds8x50_clock_init_data);
 	qsd8x50_cfg_smc91x();
-	acpuclk_init(&acpuclk_8x50_soc_data);
+	platform_device_register(&msm8x50_device_acpuclk);
 
 	msm_hsusb_pdata.swfi_latency =
 		msm_pm_data
diff --git a/arch/arm/mach-msm/clock-copper.c b/arch/arm/mach-msm/clock-copper.c
index 99443a5..87a8998 100644
--- a/arch/arm/mach-msm/clock-copper.c
+++ b/arch/arm/mach-msm/clock-copper.c
@@ -746,6 +746,11 @@
 static DEFINE_CLK_VOTER(ocmemgx_msmbus_clk, &ocmemgx_clk.c, LONG_MAX);
 static DEFINE_CLK_VOTER(ocmemgx_msmbus_a_clk, &ocmemgx_a_clk.c, LONG_MAX);
 
+static DEFINE_CLK_VOTER(pnoc_sdcc1_clk, &pnoc_clk.c, 0);
+static DEFINE_CLK_VOTER(pnoc_sdcc2_clk, &pnoc_clk.c, 0);
+static DEFINE_CLK_VOTER(pnoc_sdcc3_clk, &pnoc_clk.c, 0);
+static DEFINE_CLK_VOTER(pnoc_sdcc4_clk, &pnoc_clk.c, 0);
+
 static struct clk_freq_tbl ftbl_gcc_usb30_master_clk[] = {
 	F(125000000,  gpll0,   1,   5,  24),
 	F_END
@@ -3716,7 +3721,8 @@
 static struct branch_clk mmss_mmssnoc_axi_clk = {
 	.cbcr_reg = MMSS_MMSSNOC_AXI_CBCR,
 	.parent = &axi_clk_src.c,
-	.has_sibling = 1,
+	/* The bus driver needs set_rate to go through to the parent */
+	.has_sibling = 0,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "mmss_mmssnoc_axi_clk",
@@ -4667,12 +4673,16 @@
 
 	CLK_LOOKUP("iface_clk", gcc_sdcc1_ahb_clk.c, "msm_sdcc.1"),
 	CLK_LOOKUP("core_clk", gcc_sdcc1_apps_clk.c, "msm_sdcc.1"),
+	CLK_LOOKUP("bus_clk", pnoc_sdcc1_clk.c, "msm_sdcc.1"),
 	CLK_LOOKUP("iface_clk", gcc_sdcc2_ahb_clk.c, "msm_sdcc.2"),
 	CLK_LOOKUP("core_clk", gcc_sdcc2_apps_clk.c, "msm_sdcc.2"),
+	CLK_LOOKUP("bus_clk", pnoc_sdcc2_clk.c, "msm_sdcc.2"),
 	CLK_LOOKUP("iface_clk", gcc_sdcc3_ahb_clk.c, "msm_sdcc.3"),
 	CLK_LOOKUP("core_clk", gcc_sdcc3_apps_clk.c, "msm_sdcc.3"),
+	CLK_LOOKUP("bus_clk", pnoc_sdcc3_clk.c, "msm_sdcc.3"),
 	CLK_LOOKUP("iface_clk", gcc_sdcc4_ahb_clk.c, "msm_sdcc.4"),
 	CLK_LOOKUP("core_clk", gcc_sdcc4_apps_clk.c, "msm_sdcc.4"),
+	CLK_LOOKUP("bus_clk", pnoc_sdcc4_clk.c, "msm_sdcc.4"),
 
 	CLK_LOOKUP("iface_clk", gcc_tsif_ahb_clk.c, ""),
 	CLK_LOOKUP("ref_clk", gcc_tsif_ref_clk.c, ""),
@@ -4696,10 +4706,10 @@
 	CLK_LOOKUP("core_clk", mdss_esc1_clk.c, ""),
 	CLK_LOOKUP("iface_clk", mdss_hdmi_ahb_clk.c, ""),
 	CLK_LOOKUP("core_clk", mdss_hdmi_clk.c, ""),
-	CLK_LOOKUP("core_clk", mdss_mdp_clk.c, ""),
-	CLK_LOOKUP("core_clk", mdss_mdp_lut_clk.c, ""),
-	CLK_LOOKUP("core_clk", mdp_clk_src.c, ""),
-	CLK_LOOKUP("core_clk", mdss_vsync_clk.c, ""),
+	CLK_LOOKUP("core_clk", mdss_mdp_clk.c, "mdp.0"),
+	CLK_LOOKUP("lut_clk", mdss_mdp_lut_clk.c, "mdp.0"),
+	CLK_LOOKUP("core_clk_src", mdp_clk_src.c, "mdp.0"),
+	CLK_LOOKUP("vsync_clk", mdss_vsync_clk.c, "mdp.0"),
 	CLK_LOOKUP("iface_clk", camss_cci_cci_ahb_clk.c, ""),
 	CLK_LOOKUP("core_clk", camss_cci_cci_clk.c, ""),
 	CLK_LOOKUP("iface_clk", camss_csi0_ahb_clk.c, ""),
@@ -4758,9 +4768,10 @@
 	CLK_LOOKUP("iface_clk", camss_vfe_vfe_ahb_clk.c, ""),
 	CLK_LOOKUP("bus_clk", camss_vfe_vfe_axi_clk.c, ""),
 	CLK_LOOKUP("bus_clk", camss_vfe_vfe_ocmemnoc_clk.c, ""),
+	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "mdp.0"),
 	CLK_LOOKUP("iface_clk", mdss_ahb_clk.c, "fd928000.qcom,iommu"),
 	CLK_LOOKUP("core_clk", mdss_axi_clk.c, "fd928000.qcom,iommu"),
-	CLK_LOOKUP("bus_clk", mdss_axi_clk.c, ""),
+	CLK_LOOKUP("bus_clk", mdss_axi_clk.c, "mdp.0"),
 	CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, ""),
 	CLK_LOOKUP("iface_clk", oxilicx_ahb_clk.c, ""),
 	CLK_LOOKUP("bus_clk", oxilicx_axi_clk.c, ""),
@@ -4837,8 +4848,8 @@
 	CLK_LOOKUP("ocmem_a_clk", ocmemgx_msmbus_a_clk.c, "msm_bus"),
 	CLK_LOOKUP("bus_clk",	ocmemnoc_clk.c,		"msm_ocmem_noc"),
 	CLK_LOOKUP("bus_a_clk",	ocmemnoc_clk.c,		"msm_ocmem_noc"),
-	CLK_LOOKUP("bus_clk",	axi_clk_src.c,		"msm_mmss_noc"),
-	CLK_LOOKUP("bus_a_clk",	axi_clk_src.c,		"msm_mmss_noc"),
+	CLK_LOOKUP("bus_clk",	mmss_mmssnoc_axi_clk.c,	"msm_mmss_noc"),
+	CLK_LOOKUP("bus_a_clk",	mmss_mmssnoc_axi_clk.c,	"msm_mmss_noc"),
 };
 
 static struct pll_config_regs gpll0_regs __initdata = {
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index 467d5d1..9fe9591 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -408,6 +408,19 @@
 	return -EPERM;
 }
 
+static long branch_clk_round_rate(struct clk *c, unsigned long rate)
+{
+	struct branch_clk *branch = to_branch_clk(c);
+
+	if (branch->max_div)
+		return rate <= (branch->max_div) ? rate : -EPERM;
+
+	if (!branch->has_sibling)
+		return clk_round_rate(branch->parent, rate);
+
+	return -EPERM;
+}
+
 static unsigned long branch_clk_get_rate(struct clk *c)
 {
 	struct branch_clk *branch = to_branch_clk(c);
@@ -580,6 +593,7 @@
 	.set_rate = branch_clk_set_rate,
 	.get_rate = branch_clk_get_rate,
 	.list_rate = branch_clk_list_rate,
+	.round_rate = branch_clk_round_rate,
 	.reset = branch_clk_reset,
 	.get_parent = branch_clk_get_parent,
 	.handoff = branch_clk_handoff,
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 66ce30e..f6ce848 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -2586,15 +2586,15 @@
 		.name = "jpegd_dst",
 		.domain = CAMERA_DOMAIN,
 	},
-	/* Rotator */
+	/* Rotator src*/
 	{
 		.name = "rot_src",
-		.domain = ROTATOR_DOMAIN,
+		.domain = ROTATOR_SRC_DOMAIN,
 	},
-	/* Rotator */
+	/* Rotator dst */
 	{
 		.name = "rot_dst",
-		.domain = ROTATOR_DOMAIN,
+		.domain = ROTATOR_DST_DOMAIN,
 	},
 	/* Video */
 	{
@@ -2650,18 +2650,36 @@
 		},
 };
 
-static struct mem_pool apq8064_display_pools[] =  {
+static struct mem_pool apq8064_display_read_pools[] =  {
 	[GEN_POOL] =
-	/* One address space for display */
+	/* One address space for display reads */
 		{
 			.paddr	= SZ_128K,
 			.size	= SZ_2G - SZ_128K,
 		},
 };
 
-static struct mem_pool apq8064_rotator_pools[] =  {
+static struct mem_pool apq8064_display_write_pools[] =  {
 	[GEN_POOL] =
-	/* One address space for rotator */
+	/* One address space for display writes */
+		{
+			.paddr	= SZ_128K,
+			.size	= SZ_2G - SZ_128K,
+		},
+};
+
+static struct mem_pool apq8064_rotator_src_pools[] =  {
+	[GEN_POOL] =
+	/* One address space for rotator src */
+		{
+			.paddr	= SZ_128K,
+			.size	= SZ_2G - SZ_128K,
+		},
+};
+
+static struct mem_pool apq8064_rotator_dst_pools[] =  {
+	[GEN_POOL] =
+	/* One address space for rotator dst */
 		{
 			.paddr	= SZ_128K,
 			.size	= SZ_2G - SZ_128K,
@@ -2677,13 +2695,21 @@
 			.iova_pools = apq8064_camera_pools,
 			.npools = ARRAY_SIZE(apq8064_camera_pools),
 		},
-		[DISPLAY_DOMAIN] = {
-			.iova_pools = apq8064_display_pools,
-			.npools = ARRAY_SIZE(apq8064_display_pools),
+		[DISPLAY_READ_DOMAIN] = {
+			.iova_pools = apq8064_display_read_pools,
+			.npools = ARRAY_SIZE(apq8064_display_read_pools),
 		},
-		[ROTATOR_DOMAIN] = {
-			.iova_pools = apq8064_rotator_pools,
-			.npools = ARRAY_SIZE(apq8064_rotator_pools),
+		[DISPLAY_WRITE_DOMAIN] = {
+			.iova_pools = apq8064_display_write_pools,
+			.npools = ARRAY_SIZE(apq8064_display_write_pools),
+		},
+		[ROTATOR_SRC_DOMAIN] = {
+			.iova_pools = apq8064_rotator_src_pools,
+			.npools = ARRAY_SIZE(apq8064_rotator_src_pools),
+		},
+		[ROTATOR_DST_DOMAIN] = {
+			.iova_pools = apq8064_rotator_dst_pools,
+			.npools = ARRAY_SIZE(apq8064_rotator_dst_pools),
 		},
 };
 
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index c480bba..03685da 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -765,12 +765,12 @@
 	/* Rotator */
 	{
 		.name = "rot_src",
-		.domain = ROTATOR_DOMAIN,
+		.domain = ROTATOR_SRC_DOMAIN,
 	},
 	/* Rotator */
 	{
 		.name = "rot_dst",
-		.domain = ROTATOR_DOMAIN,
+		.domain = ROTATOR_DST_DOMAIN,
 	},
 	/* Video */
 	{
@@ -826,18 +826,36 @@
 		},
 };
 
-static struct mem_pool msm8930_display_pools[] =  {
+static struct mem_pool msm8930_display_read_pools[] =  {
 	[GEN_POOL] =
-	/* One address space for display */
+	/* One address space for display reads */
 		{
 			.paddr	= SZ_128K,
 			.size	= SZ_2G - SZ_128K,
 		},
 };
 
-static struct mem_pool msm8930_rotator_pools[] =  {
+static struct mem_pool msm8930_display_write_pools[] =  {
 	[GEN_POOL] =
-	/* One address space for rotator */
+	/* One address space for display writes */
+		{
+			.paddr	= SZ_128K,
+			.size	= SZ_2G - SZ_128K,
+		},
+};
+
+static struct mem_pool msm8930_rotator_src_pools[] =  {
+	[GEN_POOL] =
+	/* One address space for rotator src */
+		{
+			.paddr	= SZ_128K,
+			.size	= SZ_2G - SZ_128K,
+		},
+};
+
+static struct mem_pool msm8930_rotator_dst_pools[] =  {
+	[GEN_POOL] =
+	/* One address space for rotator dst */
 		{
 			.paddr	= SZ_128K,
 			.size	= SZ_2G - SZ_128K,
@@ -853,13 +871,21 @@
 			.iova_pools = msm8930_camera_pools,
 			.npools = ARRAY_SIZE(msm8930_camera_pools),
 		},
-		[DISPLAY_DOMAIN] = {
-			.iova_pools = msm8930_display_pools,
-			.npools = ARRAY_SIZE(msm8930_display_pools),
+		[DISPLAY_READ_DOMAIN] = {
+			.iova_pools = msm8930_display_read_pools,
+			.npools = ARRAY_SIZE(msm8930_display_read_pools),
 		},
-		[ROTATOR_DOMAIN] = {
-			.iova_pools = msm8930_rotator_pools,
-			.npools = ARRAY_SIZE(msm8930_rotator_pools),
+		[DISPLAY_WRITE_DOMAIN] = {
+			.iova_pools = msm8930_display_write_pools,
+			.npools = ARRAY_SIZE(msm8930_display_write_pools),
+		},
+		[ROTATOR_SRC_DOMAIN] = {
+			.iova_pools = msm8930_rotator_src_pools,
+			.npools = ARRAY_SIZE(msm8930_rotator_src_pools),
+		},
+		[ROTATOR_DST_DOMAIN] = {
+			.iova_pools = msm8930_rotator_dst_pools,
+			.npools = ARRAY_SIZE(msm8930_rotator_dst_pools),
 		},
 };
 
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 6a9f7f0..0d417bd 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -202,6 +202,11 @@
 	},
 };
 
+struct platform_device msm8960_device_acpuclk = {
+	.name		= "acpuclk-8960",
+	.id		= -1,
+};
+
 #define SHARED_IMEM_TZ_BASE 0x2a03f720
 static struct resource tzlog_resources[] = {
 	{
@@ -3634,15 +3639,15 @@
 		.name = "jpegd_dst",
 		.domain = CAMERA_DOMAIN,
 	},
-	/* Rotator */
+	/* Rotator src*/
 	{
 		.name = "rot_src",
-		.domain = ROTATOR_DOMAIN,
+		.domain = ROTATOR_SRC_DOMAIN,
 	},
-	/* Rotator */
+	/* Rotator dst */
 	{
 		.name = "rot_dst",
-		.domain = ROTATOR_DOMAIN,
+		.domain = ROTATOR_DST_DOMAIN,
 	},
 	/* Video */
 	{
@@ -3698,18 +3703,36 @@
 		},
 };
 
-static struct mem_pool msm8960_display_pools[] =  {
+static struct mem_pool msm8960_display_read_pools[] =  {
 	[GEN_POOL] =
-	/* One address space for display */
+	/* One address space for display reads */
 		{
 			.paddr	= SZ_128K,
 			.size	= SZ_2G - SZ_128K,
 		},
 };
 
-static struct mem_pool msm8960_rotator_pools[] =  {
+static struct mem_pool msm8960_display_write_pools[] =  {
 	[GEN_POOL] =
-	/* One address space for rotator */
+	/* One address space for display writes */
+		{
+			.paddr	= SZ_128K,
+			.size	= SZ_2G - SZ_128K,
+		},
+};
+
+static struct mem_pool msm8960_rotator_src_pools[] =  {
+	[GEN_POOL] =
+	/* One address space for rotator src */
+		{
+			.paddr	= SZ_128K,
+			.size	= SZ_2G - SZ_128K,
+		},
+};
+
+static struct mem_pool msm8960_rotator_dst_pools[] =  {
+	[GEN_POOL] =
+	/* One address space for rotator dst */
 		{
 			.paddr	= SZ_128K,
 			.size	= SZ_2G - SZ_128K,
@@ -3725,13 +3748,21 @@
 			.iova_pools = msm8960_camera_pools,
 			.npools = ARRAY_SIZE(msm8960_camera_pools),
 		},
-		[DISPLAY_DOMAIN] = {
-			.iova_pools = msm8960_display_pools,
-			.npools = ARRAY_SIZE(msm8960_display_pools),
+		[DISPLAY_READ_DOMAIN] = {
+			.iova_pools = msm8960_display_read_pools,
+			.npools = ARRAY_SIZE(msm8960_display_read_pools),
 		},
-		[ROTATOR_DOMAIN] = {
-			.iova_pools = msm8960_rotator_pools,
-			.npools = ARRAY_SIZE(msm8960_rotator_pools),
+		[DISPLAY_WRITE_DOMAIN] = {
+			.iova_pools = msm8960_display_write_pools,
+			.npools = ARRAY_SIZE(msm8960_display_write_pools),
+		},
+		[ROTATOR_SRC_DOMAIN] = {
+			.iova_pools = msm8960_rotator_src_pools,
+			.npools = ARRAY_SIZE(msm8960_rotator_src_pools),
+		},
+		[ROTATOR_DST_DOMAIN] = {
+			.iova_pools = msm8960_rotator_dst_pools,
+			.npools = ARRAY_SIZE(msm8960_rotator_dst_pools),
 		},
 };
 
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index f13c266..06d8653 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -107,6 +107,11 @@
 	},
 };
 
+struct platform_device msm9615_device_acpuclk = {
+	.name           = "acpuclk-9615",
+	.id             = -1,
+};
+
 #define MSM_USB_BAM_BASE     0x12502000
 #define MSM_USB_BAM_SIZE     SZ_16K
 #define MSM_HSIC_BAM_BASE    0x12542000
diff --git a/arch/arm/mach-msm/devices-msm7x27.c b/arch/arm/mach-msm/devices-msm7x27.c
index ffd10fa..4619cca 100644
--- a/arch/arm/mach-msm/devices-msm7x27.c
+++ b/arch/arm/mach-msm/devices-msm7x27.c
@@ -27,6 +27,7 @@
 
 #include "devices.h"
 #include "footswitch.h"
+#include "acpuclock.h"
 
 #include <asm/mach/flash.h>
 
@@ -431,6 +432,16 @@
 	msm_pm_set_irq_extns(&msm7x27_pm_irq_calls);
 }
 
+static struct acpuclk_pdata msm7x27_acpuclk_pdata = {
+	.max_speed_delta_khz = 400000,
+};
+
+struct platform_device msm7x27_device_acpuclk = {
+	.name		= "acpuclk-7627",
+	.id		= -1,
+	.dev.platform_data = &msm7x27_acpuclk_pdata,
+};
+
 #define MSM_SDC1_BASE         0xA0400000
 #define MSM_SDC2_BASE         0xA0500000
 #define MSM_SDC3_BASE         0xA0600000
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index adc9169..b3454cd 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -211,6 +211,37 @@
 	},
 };
 
+static struct acpuclk_pdata msm7x27a_acpuclk_pdata = {
+	.max_speed_delta_khz = 400000,
+};
+
+struct platform_device msm7x27a_device_acpuclk = {
+	.name		= "acpuclk-7627",
+	.id		= -1,
+	.dev.platform_data = &msm7x27a_acpuclk_pdata,
+};
+
+static struct acpuclk_pdata msm7x27aa_acpuclk_pdata = {
+	.max_speed_delta_khz = 504000,
+};
+
+struct platform_device msm7x27aa_device_acpuclk = {
+	.name		= "acpuclk-7627",
+	.id		= -1,
+	.dev.platform_data = &msm7x27aa_acpuclk_pdata,
+};
+
+static struct acpuclk_pdata msm8625_acpuclk_pdata = {
+	/* TODO: Need to update speed delta from H/w Team */
+	.max_speed_delta_khz = 604800,
+};
+
+struct platform_device msm8625_device_acpuclk = {
+	.name		= "acpuclk-7627",
+	.id		= -1,
+	.dev.platform_data = &msm8625_acpuclk_pdata,
+};
+
 struct platform_device msm_device_smd = {
 	.name	= "msm_smd",
 	.id	= -1,
@@ -1623,16 +1654,15 @@
 
 	msm_clock_init(&msm7x27a_clock_init_data);
 	if (cpu_is_msm7x27aa() || cpu_is_msm7x25ab())
-		acpuclk_init(&acpuclk_7x27aa_soc_data);
+		platform_device_register(&msm7x27aa_device_acpuclk);
 	else if (cpu_is_msm8625()) {
 		if (msm8625_cpu_id() == MSM8625)
-			acpuclk_init(&acpuclk_7x27aa_soc_data);
+			platform_device_register(&msm7x27aa_device_acpuclk);
 		else if (msm8625_cpu_id() == MSM8625A)
-			acpuclk_init(&acpuclk_8625_soc_data);
-	 } else {
-		acpuclk_init(&acpuclk_7x27a_soc_data);
-	 }
-
+			platform_device_register(&msm8625_device_acpuclk);
+	} else {
+		platform_device_register(&msm7x27a_device_acpuclk);
+	}
 
 	return 0;
 }
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index de70429..ff747e2 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -42,6 +42,11 @@
 #include "pm.h"
 #include "irq.h"
 
+struct platform_device msm7x30_device_acpuclk = {
+	.name		= "acpuclk-7x30",
+	.id		= -1,
+};
+
 /* EBI THERMAL DRIVER */
 static struct resource msm_ebi0_thermal_resources[] = {
 	{
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 37844c1..d8bf054 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -163,6 +163,11 @@
 	},
 };
 
+struct platform_device msm8x60_device_acpuclk = {
+	.name		= "acpuclk-8x60",
+	.id		= -1,
+};
+
 #ifdef CONFIG_MSM_DSPS
 #define GSBI12_DEV (&msm_dsps_device.dev)
 #else
diff --git a/arch/arm/mach-msm/devices-qsd8x50.c b/arch/arm/mach-msm/devices-qsd8x50.c
index ee8a2cf..2ecc852 100644
--- a/arch/arm/mach-msm/devices-qsd8x50.c
+++ b/arch/arm/mach-msm/devices-qsd8x50.c
@@ -34,6 +34,11 @@
 #include <mach/rpc_hsusb.h>
 #include "pm.h"
 
+struct platform_device msm8x50_device_acpuclk = {
+	.name		= "acpuclk-8x50",
+	.id		= -1,
+};
+
 static struct resource resources_uart1[] = {
 	{
 		.start	= INT_UART1,
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 17cce7b..ea47727 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -412,3 +412,13 @@
 extern struct platform_device mdm_sglte_device;
 
 extern struct platform_device apq_device_tz_log;
+
+extern struct platform_device msm7x27_device_acpuclk;
+extern struct platform_device msm7x27a_device_acpuclk;
+extern struct platform_device msm7x27aa_device_acpuclk;
+extern struct platform_device msm7x30_device_acpuclk;
+extern struct platform_device msm8625_device_acpuclk;
+extern struct platform_device msm8x50_device_acpuclk;
+extern struct platform_device msm8x60_device_acpuclk;
+extern struct platform_device msm8960_device_acpuclk;
+extern struct platform_device msm9615_device_acpuclk;
diff --git a/arch/arm/mach-msm/hsic_sysmon.c b/arch/arm/mach-msm/hsic_sysmon.c
index 07a9dbb..153e1b4 100644
--- a/arch/arm/mach-msm/hsic_sysmon.c
+++ b/arch/arm/mach-msm/hsic_sysmon.c
@@ -314,6 +314,8 @@
 static inline void hsic_sysmon_debugfs_cleanup(void) { }
 #endif
 
+static void hsic_sysmon_pdev_release(struct device *dev) { }
+
 static int
 hsic_sysmon_probe(struct usb_interface *ifc, const struct usb_device_id *id)
 {
@@ -371,6 +373,7 @@
 
 	hs->pdev.name = "sys_mon";
 	hs->pdev.id = SYSMON_SS_EXT_MODEM;
+	hs->pdev.dev.release = hsic_sysmon_pdev_release;
 	platform_device_register(&hs->pdev);
 
 	pr_debug("complete");
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index be254f6..460eefc 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -183,6 +183,7 @@
 enum camera_vreg_type {
 	REG_LDO,
 	REG_VS,
+	REG_GPIO,
 };
 
 struct camera_vreg_t {
@@ -290,7 +291,6 @@
 	enum msm_sensor_type sensor_type;
 	struct msm_actuator_info *actuator_info;
 	int pmic_gpio_enable;
-	int (*sensor_lcd_gpio_onoff)(int on);
 	struct msm_eeprom_info *eeprom_info;
 };
 
diff --git a/arch/arm/mach-msm/include/mach/iommu_domains.h b/arch/arm/mach-msm/include/mach/iommu_domains.h
index 1a3a022..1d538f2 100644
--- a/arch/arm/mach-msm/include/mach/iommu_domains.h
+++ b/arch/arm/mach-msm/include/mach/iommu_domains.h
@@ -18,8 +18,10 @@
 enum {
 	VIDEO_DOMAIN,
 	CAMERA_DOMAIN,
-	DISPLAY_DOMAIN,
-	ROTATOR_DOMAIN,
+	DISPLAY_READ_DOMAIN,
+	DISPLAY_WRITE_DOMAIN,
+	ROTATOR_SRC_DOMAIN,
+	ROTATOR_DST_DOMAIN,
 	MAX_DOMAINS
 };
 
diff --git a/arch/arm/mach-msm/include/mach/stm.h b/arch/arm/mach-msm/include/mach/stm.h
new file mode 100644
index 0000000..20c4963
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/stm.h
@@ -0,0 +1,60 @@
+/* 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 __MACH_STM_H
+#define __MACH_STM_H
+
+enum {
+	OST_ENTITY_NONE			= 0x0,
+	OST_ENTITY_FTRACE_EVENTS	= 0x1,
+	OST_ENTITY_TRACE_PRINTK		= 0x2,
+	OST_ENTITY_TRACE_MARKER		= 0x4,
+	OST_ENTITY_DEV_NODE		= 0x8,
+	OST_ENTITY_ALL			= 0xF,
+};
+
+enum {
+	STM_OPTION_NONE			= 0x0,
+	STM_OPTION_TIMESTAMPED		= 0x08,
+	STM_OPTION_GUARANTEED		= 0x80,
+};
+
+#define stm_log_inv(entity_id, proto_id, data, size)			\
+	stm_trace(STM_OPTION_NONE, entity_id, proto_id, data, size)
+
+#define stm_log_inv_ts(entity_id, proto_id, data, size)			\
+	stm_trace(STM_OPTION_TIMESTAMPED, entity_id, proto_id,		\
+		  data, size)
+
+#define stm_log_gtd(entity_id, proto_id, data, size)			\
+	stm_trace(STM_OPTION_GUARANTEED, entity_id, proto_id,		\
+		  data, size)
+
+#define stm_log_gtd_ts(entity_id, proto_id, data, size)			\
+	stm_trace(STM_OPTION_GUARANTEED | STM_OPTION_TIMESTAMPED,	\
+		  entity_id, proto_id, data, size)
+
+#define stm_log(entity_id, data, size)					\
+	stm_log_inv_ts(entity_id, 0, data, size)
+
+#ifdef CONFIG_MSM_QDSS
+extern int stm_trace(uint32_t options, uint8_t entity_id, uint8_t proto_id,
+		     const void *data, uint32_t size);
+#else
+static inline int stm_trace(uint32_t options, uint8_t entity_id,
+			    uint8_t proto_id, const void *data, uint32_t size)
+{
+	return 0;
+}
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/perf_event_msm_krait_l2.c b/arch/arm/mach-msm/perf_event_msm_krait_l2.c
new file mode 100644
index 0000000..d82f4dd
--- /dev/null
+++ b/arch/arm/mach-msm/perf_event_msm_krait_l2.c
@@ -0,0 +1,428 @@
+/*
+ * 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
+ * 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/irq.h>
+#include <asm/pmu.h>
+#include <linux/platform_device.h>
+
+#include <mach/msm-krait-l2-accessors.h>
+
+#define MAX_L2_PERIOD	((1ULL << 32) - 1)
+#define MAX_KRAIT_L2_CTRS 5
+
+#define L2PMCCNTR 0x409
+#define L2PMCCNTCR 0x408
+#define L2PMCCNTSR 0x40A
+#define L2CYCLE_CTR_BIT 31
+#define L2CYCLE_CTR_EVENT_IDX 4
+#define L2CYCLE_CTR_RAW_CODE 0xfe
+
+#define L2PMOVSR	0x406
+
+#define L2PMCR	0x400
+#define L2PMCR_RESET_ALL	0x6
+#define L2PMCR_GLOBAL_ENABLE	0x1
+#define L2PMCR_GLOBAL_DISABLE	0x0
+
+#define L2PMCNTENSET	0x403
+#define L2PMCNTENCLR	0x402
+
+#define L2PMINTENSET	0x405
+#define L2PMINTENCLR	0x404
+
+#define IA_L2PMXEVCNTCR_BASE	0x420
+#define IA_L2PMXEVTYPER_BASE	0x424
+#define IA_L2PMRESX_BASE	0x410
+#define IA_L2PMXEVFILTER_BASE	0x423
+#define IA_L2PMXEVCNTR_BASE	0x421
+
+/* event format is -e rsRCCG See get_event_desc() */
+
+#define EVENT_REG_MASK		0xf000
+#define EVENT_GROUPSEL_MASK	0x000f
+#define	EVENT_GROUPCODE_MASK	0x0ff0
+#define EVENT_REG_SHIFT		12
+#define EVENT_GROUPCODE_SHIFT	4
+
+#define	RESRX_VALUE_EN	0x80000000
+
+static u32 l2_orig_filter_prefix = 0x000f0030;
+
+static u32 pmu_type;
+
+static struct arm_pmu krait_l2_pmu;
+
+static struct perf_event *l2_events[MAX_KRAIT_L2_CTRS];
+static unsigned long l2_used_mask[BITS_TO_LONGS(MAX_KRAIT_L2_CTRS)];
+
+static struct pmu_hw_events krait_l2_pmu_hw_events = {
+	.events = l2_events,
+	.used_mask = l2_used_mask,
+	.pmu_lock = __RAW_SPIN_LOCK_UNLOCKED(krait_l2_pmu_hw_events.pmu_lock),
+};
+
+struct event_desc {
+	int event_groupsel;
+	int event_reg;
+	int event_group_code;
+};
+
+static struct pmu_hw_events *krait_l2_get_hw_events(void)
+{
+	return &krait_l2_pmu_hw_events;
+}
+
+void get_event_desc(u64 config, struct event_desc *evdesc)
+{
+	/* L2PMEVCNTRX */
+	evdesc->event_reg = (config & EVENT_REG_MASK) >> EVENT_REG_SHIFT;
+	/* Group code (row ) */
+	evdesc->event_group_code =
+	    (config & EVENT_GROUPCODE_MASK) >> EVENT_GROUPCODE_SHIFT;
+	/* Group sel (col) */
+	evdesc->event_groupsel = (config & EVENT_GROUPSEL_MASK);
+
+	pr_debug("%s: reg: %x, group_code: %x, groupsel: %x\n", __func__,
+		 evdesc->event_reg, evdesc->event_group_code,
+		 evdesc->event_groupsel);
+}
+
+static void set_evcntcr(int ctr)
+{
+	u32 evtcr_reg = (ctr * 16) + IA_L2PMXEVCNTCR_BASE;
+
+	set_l2_indirect_reg(evtcr_reg, 0x0);
+}
+
+static void set_evtyper(int event_groupsel, int event_reg, int ctr)
+{
+	u32 evtype_reg = (ctr * 16) + IA_L2PMXEVTYPER_BASE;
+	u32 evtype_val = event_groupsel + (4 * event_reg);
+
+	set_l2_indirect_reg(evtype_reg, evtype_val);
+}
+
+static void set_evres(int event_groupsel, int event_reg, int event_group_code)
+{
+	u32 group_reg = event_reg + IA_L2PMRESX_BASE;
+	u32 group_val =
+		RESRX_VALUE_EN | (event_group_code << (8 * event_groupsel));
+	u32 resr_val;
+	u32 group_byte = 0xff;
+	u32 group_mask = ~(group_byte << (8 * event_groupsel));
+
+	resr_val = get_l2_indirect_reg(group_reg);
+	resr_val &= group_mask;
+	resr_val |= group_val;
+
+	set_l2_indirect_reg(group_reg, resr_val);
+}
+
+static void set_evfilter_task_mode(int ctr)
+{
+	u32 filter_reg = (ctr * 16) + IA_L2PMXEVFILTER_BASE;
+	u32 filter_val = l2_orig_filter_prefix | 1 << smp_processor_id();
+
+	set_l2_indirect_reg(filter_reg, filter_val);
+}
+
+static void set_evfilter_sys_mode(int ctr)
+{
+	u32 filter_reg = (ctr * 16) + IA_L2PMXEVFILTER_BASE;
+	u32 filter_val = l2_orig_filter_prefix | 0xf;
+
+	set_l2_indirect_reg(filter_reg, filter_val);
+}
+
+static void enable_intenset(u32 idx)
+{
+	if (idx == L2CYCLE_CTR_EVENT_IDX)
+		set_l2_indirect_reg(L2PMINTENSET, 1 << L2CYCLE_CTR_BIT);
+	else
+		set_l2_indirect_reg(L2PMINTENSET, 1 << idx);
+}
+
+static void disable_intenclr(u32 idx)
+{
+	if (idx == L2CYCLE_CTR_EVENT_IDX)
+		set_l2_indirect_reg(L2PMINTENCLR, 1 << L2CYCLE_CTR_BIT);
+	else
+		set_l2_indirect_reg(L2PMINTENCLR, 1 << idx);
+}
+
+static void enable_counter(u32 idx)
+{
+	if (idx == L2CYCLE_CTR_EVENT_IDX)
+		set_l2_indirect_reg(L2PMCNTENSET, 1 << L2CYCLE_CTR_BIT);
+	else
+		set_l2_indirect_reg(L2PMCNTENSET, 1 << idx);
+}
+
+static void disable_counter(u32 idx)
+{
+	if (idx == L2CYCLE_CTR_EVENT_IDX)
+		set_l2_indirect_reg(L2PMCNTENCLR, 1 << L2CYCLE_CTR_BIT);
+	else
+		set_l2_indirect_reg(L2PMCNTENCLR, 1 << idx);
+}
+
+static u32 krait_l2_read_counter(int idx)
+{
+	u32 val;
+	u32 counter_reg = (idx * 16) + IA_L2PMXEVCNTR_BASE;
+
+	if (idx == L2CYCLE_CTR_EVENT_IDX)
+		val = get_l2_indirect_reg(L2PMCCNTR);
+	else
+		val = get_l2_indirect_reg(counter_reg);
+
+	return val;
+}
+
+static void krait_l2_write_counter(int idx, u32 val)
+{
+	u32 counter_reg = (idx * 16) + IA_L2PMXEVCNTR_BASE;
+
+	if (idx == L2CYCLE_CTR_EVENT_IDX)
+		set_l2_indirect_reg(L2PMCCNTR, val);
+	else
+		set_l2_indirect_reg(counter_reg, val);
+}
+
+static void krait_l2_stop_counter(struct hw_perf_event *hwc, int idx)
+{
+	disable_intenclr(idx);
+	disable_counter(idx);
+
+	pr_debug("%s: event: %ld ctr: %d stopped\n", __func__,
+			hwc->config_base, idx);
+}
+
+static void krait_l2_enable(struct hw_perf_event *hwc, int idx, int cpu)
+{
+	struct event_desc evdesc;
+	unsigned long iflags;
+
+	raw_spin_lock_irqsave(&krait_l2_pmu_hw_events.pmu_lock, iflags);
+
+	if (hwc->config_base == L2CYCLE_CTR_RAW_CODE)
+		goto out;
+
+	set_evcntcr(idx);
+
+	memset(&evdesc, 0, sizeof(evdesc));
+
+	get_event_desc(hwc->config_base, &evdesc);
+
+	set_evtyper(evdesc.event_groupsel, evdesc.event_reg, idx);
+
+	set_evres(evdesc.event_groupsel, evdesc.event_reg,
+		  evdesc.event_group_code);
+
+	if (cpu < 0)
+		set_evfilter_task_mode(idx);
+	else
+		set_evfilter_sys_mode(idx);
+
+out:
+	enable_intenset(idx);
+	enable_counter(idx);
+
+	raw_spin_unlock_irqrestore(&krait_l2_pmu_hw_events.pmu_lock, iflags);
+
+	pr_debug("%s: ctr: %d group: %ld group_code: %lld started from cpu:%d\n",
+	     __func__, idx, hwc->config_base, hwc->config, smp_processor_id());
+}
+
+static void krait_l2_disable(struct hw_perf_event *hwc, int idx)
+{
+	unsigned long iflags;
+
+	raw_spin_lock_irqsave(&krait_l2_pmu_hw_events.pmu_lock, iflags);
+
+	krait_l2_stop_counter(hwc, idx);
+
+	raw_spin_unlock_irqrestore(&krait_l2_pmu_hw_events.pmu_lock, iflags);
+
+	pr_debug("%s: event: %ld deleted\n", __func__, hwc->config_base);
+
+}
+
+static int krait_l2_get_event_idx(struct pmu_hw_events *cpuc,
+				  struct hw_perf_event *hwc)
+{
+	int ctr = 0;
+
+	if (hwc->config_base == L2CYCLE_CTR_RAW_CODE) {
+		if (!test_and_set_bit(L2CYCLE_CTR_EVENT_IDX, cpuc->used_mask))
+			return L2CYCLE_CTR_EVENT_IDX;
+	}
+
+	for (ctr = 0; ctr < MAX_KRAIT_L2_CTRS - 1; ctr++) {
+		if (!test_and_set_bit(ctr, cpuc->used_mask))
+			return ctr;
+	}
+
+	return -EAGAIN;
+}
+
+static void krait_l2_start(void)
+{
+	isb();
+	set_l2_indirect_reg(L2PMCR, L2PMCR_GLOBAL_ENABLE);
+}
+
+static void krait_l2_stop(void)
+{
+	set_l2_indirect_reg(L2PMCR, L2PMCR_GLOBAL_DISABLE);
+	isb();
+}
+
+u32 get_reset_pmovsr(void)
+{
+	int val;
+
+	val = get_l2_indirect_reg(L2PMOVSR);
+	/* reset it */
+	val &= 0xffffffff;
+	set_l2_indirect_reg(L2PMOVSR, val);
+
+	return val;
+}
+
+static irqreturn_t krait_l2_handle_irq(int irq_num, void *dev)
+{
+	unsigned long pmovsr;
+	struct perf_sample_data data;
+	struct pt_regs *regs;
+	struct perf_event *event;
+	struct hw_perf_event *hwc;
+	int bitp;
+	int idx = 0;
+
+	pmovsr = get_reset_pmovsr();
+
+	if (!(pmovsr & 0xffffffff))
+		return IRQ_NONE;
+
+	regs = get_irq_regs();
+
+	perf_sample_data_init(&data, 0);
+
+	while (pmovsr) {
+		bitp = __ffs(pmovsr);
+
+		if (bitp == L2CYCLE_CTR_BIT)
+			idx = L2CYCLE_CTR_EVENT_IDX;
+		else
+			idx = bitp;
+
+		event = krait_l2_pmu_hw_events.events[idx];
+
+		if (!event)
+			goto next;
+
+		if (!test_bit(idx, krait_l2_pmu_hw_events.used_mask))
+			goto next;
+
+		hwc = &event->hw;
+
+		armpmu_event_update(event, hwc, idx);
+
+		data.period = event->hw.last_period;
+
+		if (!armpmu_event_set_period(event, hwc, idx))
+			goto next;
+
+		if (perf_event_overflow(event, &data, regs))
+			disable_counter(hwc->idx);
+next:
+		pmovsr &= (pmovsr - 1);
+	}
+
+	irq_work_run();
+
+	return IRQ_HANDLED;
+}
+
+static int krait_l2_map_event(struct perf_event *event)
+{
+	if (pmu_type > 0 && pmu_type == event->attr.type)
+		return event->attr.config & 0xfffff;
+	else
+		return -ENOENT;
+}
+
+static int
+krait_l2_pmu_generic_request_irq(int irq, irq_handler_t *handle_irq)
+{
+	return request_irq(irq, *handle_irq,
+			IRQF_DISABLED | IRQF_NOBALANCING,
+			"krait-l2-armpmu", NULL);
+}
+
+static void
+krait_l2_pmu_generic_free_irq(int irq)
+{
+	if (irq >= 0)
+		free_irq(irq, NULL);
+}
+
+static struct arm_pmu krait_l2_pmu = {
+	.id		=	ARM_PERF_PMU_ID_KRAIT_L2,
+	.type		=	ARM_PMU_DEVICE_L2CC,
+	.name		=	"Krait L2CC PMU",
+	.start		=	krait_l2_start,
+	.stop		=	krait_l2_stop,
+	.handle_irq	=	krait_l2_handle_irq,
+	.request_pmu_irq	= krait_l2_pmu_generic_request_irq,
+	.free_pmu_irq		= krait_l2_pmu_generic_free_irq,
+	.enable		=	krait_l2_enable,
+	.disable	=	krait_l2_disable,
+	.get_event_idx	=	krait_l2_get_event_idx,
+	.read_counter	=	krait_l2_read_counter,
+	.write_counter	=	krait_l2_write_counter,
+	.map_event	=	krait_l2_map_event,
+	.max_period	=	(1LLU << 32) - 1,
+	.get_hw_events	=	krait_l2_get_hw_events,
+	.num_events	=	MAX_KRAIT_L2_CTRS,
+};
+
+static int __devinit krait_l2_pmu_device_probe(struct platform_device *pdev)
+{
+	krait_l2_pmu.plat_device = pdev;
+
+	if (!armpmu_register(&krait_l2_pmu, "krait-l2", -1))
+		pmu_type = krait_l2_pmu.pmu.type;
+
+	return 0;
+}
+
+static struct platform_driver krait_l2_pmu_driver = {
+	.driver		= {
+		.name	= "l2-arm-pmu",
+	},
+	.probe		= krait_l2_pmu_device_probe,
+};
+
+static int __init register_krait_l2_pmu_driver(void)
+{
+	/* Reset all ctrs */
+	set_l2_indirect_reg(L2PMCR, L2PMCR_RESET_ALL);
+
+	/* Avoid spurious interrupt if any */
+	get_reset_pmovsr();
+
+	return platform_driver_register(&krait_l2_pmu_driver);
+}
+device_initcall(register_krait_l2_pmu_driver);
diff --git a/arch/arm/mach-msm/perf_event_msm_l2.c b/arch/arm/mach-msm/perf_event_msm_l2.c
new file mode 100644
index 0000000..3310d92
--- /dev/null
+++ b/arch/arm/mach-msm/perf_event_msm_l2.c
@@ -0,0 +1,760 @@
+/*
+ * 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
+ * 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/irq.h>
+#include <asm/pmu.h>
+#include <linux/platform_device.h>
+
+
+#define MAX_SCORPION_L2_CTRS 5
+#define SCORPION_L2CYCLE_CTR_BIT 31
+#define SCORPION_L2CYCLE_CTR_EVENT_IDX 4
+#define SCORPION_L2CYCLE_CTR_RAW_CODE 0xfe
+#define SCORPIONL2_PMNC_E       (1 << 0)	/* Enable all counters */
+#define SCORPION_L2_EVT_PREFIX 3
+#define SCORPION_MAX_L2_REG 4
+
+static u32 pmu_type;
+
+static struct arm_pmu scorpion_l2_pmu;
+
+static struct perf_event *l2_events[MAX_SCORPION_L2_CTRS];
+static unsigned long l2_used_mask[BITS_TO_LONGS(MAX_SCORPION_L2_CTRS)];
+
+static struct pmu_hw_events scorpion_l2_pmu_hw_events = {
+	.events = l2_events,
+	.used_mask = l2_used_mask,
+	.pmu_lock =
+		__RAW_SPIN_LOCK_UNLOCKED(scorpion_l2_pmu_hw_events.pmu_lock),
+};
+
+struct scorpion_l2_scorp_evt {
+	u32 evt_type;
+	u32 val;
+	u8 grp;
+	u32 evt_type_act;
+};
+
+enum scorpion_perf_types {
+	SCORPIONL2_TOTAL_BANK_REQ = 0x90,
+	SCORPIONL2_DSIDE_READ = 0x91,
+	SCORPIONL2_DSIDE_WRITE = 0x92,
+	SCORPIONL2_ISIDE_READ = 0x93,
+	SCORPIONL2_L2CACHE_ISIDE_READ = 0x94,
+	SCORPIONL2_L2CACHE_BANK_REQ = 0x95,
+	SCORPIONL2_L2CACHE_DSIDE_READ = 0x96,
+	SCORPIONL2_L2CACHE_DSIDE_WRITE = 0x97,
+	SCORPIONL2_L2NOCACHE_DSIDE_WRITE = 0x98,
+	SCORPIONL2_L2NOCACHE_ISIDE_READ = 0x99,
+	SCORPIONL2_L2NOCACHE_TOTAL_REQ = 0x9a,
+	SCORPIONL2_L2NOCACHE_DSIDE_READ = 0x9b,
+	SCORPIONL2_DSIDE_READ_NOL1 = 0x9c,
+	SCORPIONL2_L2CACHE_WRITETHROUGH = 0x9d,
+	SCORPIONL2_BARRIERS = 0x9e,
+	SCORPIONL2_HARDWARE_TABLE_WALKS = 0x9f,
+	SCORPIONL2_MVA_POC = 0xa0,
+	SCORPIONL2_L2CACHE_HW_TABLE_WALKS = 0xa1,
+	SCORPIONL2_SETWAY_CACHE_OPS = 0xa2,
+	SCORPIONL2_DSIDE_WRITE_HITS = 0xa3,
+	SCORPIONL2_ISIDE_READ_HITS = 0xa4,
+	SCORPIONL2_CACHE_DSIDE_READ_NOL1 = 0xa5,
+	SCORPIONL2_TOTAL_CACHE_HITS = 0xa6,
+	SCORPIONL2_CACHE_MATCH_MISS = 0xa7,
+	SCORPIONL2_DREAD_HIT_L1_DATA = 0xa8,
+	SCORPIONL2_L2LINE_LOCKED = 0xa9,
+	SCORPIONL2_HW_TABLE_WALK_HIT = 0xaa,
+	SCORPIONL2_CACHE_MVA_POC = 0xab,
+	SCORPIONL2_L2ALLOC_DWRITE_MISS = 0xac,
+	SCORPIONL2_CORRECTED_TAG_ARRAY = 0xad,
+	SCORPIONL2_CORRECTED_DATA_ARRAY = 0xae,
+	SCORPIONL2_CORRECTED_REPLACEMENT_ARRAY = 0xaf,
+	SCORPIONL2_PMBUS_MPAAF = 0xb0,
+	SCORPIONL2_PMBUS_MPWDAF = 0xb1,
+	SCORPIONL2_PMBUS_MPBRT = 0xb2,
+	SCORPIONL2_CPU0_GRANT = 0xb3,
+	SCORPIONL2_CPU1_GRANT = 0xb4,
+	SCORPIONL2_CPU0_NOGRANT = 0xb5,
+	SCORPIONL2_CPU1_NOGRANT = 0xb6,
+	SCORPIONL2_CPU0_LOSING_ARB = 0xb7,
+	SCORPIONL2_CPU1_LOSING_ARB = 0xb8,
+	SCORPIONL2_SLAVEPORT_NOGRANT = 0xb9,
+	SCORPIONL2_SLAVEPORT_BPQ_FULL = 0xba,
+	SCORPIONL2_SLAVEPORT_LOSING_ARB = 0xbb,
+	SCORPIONL2_SLAVEPORT_GRANT = 0xbc,
+	SCORPIONL2_SLAVEPORT_GRANTLOCK = 0xbd,
+	SCORPIONL2_L2EM_STREX_PASS = 0xbe,
+	SCORPIONL2_L2EM_STREX_FAIL = 0xbf,
+	SCORPIONL2_LDREX_RESERVE_L2EM = 0xc0,
+	SCORPIONL2_SLAVEPORT_LDREX = 0xc1,
+	SCORPIONL2_CPU0_L2EM_CLEARED = 0xc2,
+	SCORPIONL2_CPU1_L2EM_CLEARED = 0xc3,
+	SCORPIONL2_SLAVEPORT_L2EM_CLEARED = 0xc4,
+	SCORPIONL2_CPU0_CLAMPED = 0xc5,
+	SCORPIONL2_CPU1_CLAMPED = 0xc6,
+	SCORPIONL2_CPU0_WAIT = 0xc7,
+	SCORPIONL2_CPU1_WAIT = 0xc8,
+	SCORPIONL2_CPU0_NONAMBAS_WAIT = 0xc9,
+	SCORPIONL2_CPU1_NONAMBAS_WAIT = 0xca,
+	SCORPIONL2_CPU0_DSB_WAIT = 0xcb,
+	SCORPIONL2_CPU1_DSB_WAIT = 0xcc,
+	SCORPIONL2_AXI_READ = 0xcd,
+	SCORPIONL2_AXI_WRITE = 0xce,
+
+	SCORPIONL2_1BEAT_WRITE = 0xcf,
+	SCORPIONL2_2BEAT_WRITE = 0xd0,
+	SCORPIONL2_4BEAT_WRITE = 0xd1,
+	SCORPIONL2_8BEAT_WRITE = 0xd2,
+	SCORPIONL2_12BEAT_WRITE = 0xd3,
+	SCORPIONL2_16BEAT_WRITE = 0xd4,
+	SCORPIONL2_1BEAT_DSIDE_READ = 0xd5,
+	SCORPIONL2_2BEAT_DSIDE_READ = 0xd6,
+	SCORPIONL2_4BEAT_DSIDE_READ = 0xd7,
+	SCORPIONL2_8BEAT_DSIDE_READ = 0xd8,
+	SCORPIONL2_CSYS_READ_1BEAT = 0xd9,
+	SCORPIONL2_CSYS_READ_2BEAT = 0xda,
+	SCORPIONL2_CSYS_READ_4BEAT = 0xdb,
+	SCORPIONL2_CSYS_READ_8BEAT = 0xdc,
+	SCORPIONL2_4BEAT_IFETCH_READ = 0xdd,
+	SCORPIONL2_8BEAT_IFETCH_READ = 0xde,
+	SCORPIONL2_CSYS_WRITE_1BEAT = 0xdf,
+	SCORPIONL2_CSYS_WRITE_2BEAT = 0xe0,
+	SCORPIONL2_AXI_READ_DATA_BEAT = 0xe1,
+	SCORPIONL2_AXI_WRITE_EVT1 = 0xe2,
+	SCORPIONL2_AXI_WRITE_EVT2 = 0xe3,
+	SCORPIONL2_LDREX_REQ = 0xe4,
+	SCORPIONL2_STREX_PASS = 0xe5,
+	SCORPIONL2_STREX_FAIL = 0xe6,
+	SCORPIONL2_CPREAD = 0xe7,
+	SCORPIONL2_CPWRITE = 0xe8,
+	SCORPIONL2_BARRIER_REQ = 0xe9,
+	SCORPIONL2_AXI_READ_SLVPORT = 0xea,
+	SCORPIONL2_AXI_WRITE_SLVPORT = 0xeb,
+	SCORPIONL2_AXI_READ_SLVPORT_DATABEAT = 0xec,
+	SCORPIONL2_AXI_WRITE_SLVPORT_DATABEAT = 0xed,
+	SCORPIONL2_SNOOPKILL_PREFILTER = 0xee,
+	SCORPIONL2_SNOOPKILL_FILTEROUT = 0xef,
+	SCORPIONL2_SNOOPED_IC = 0xf0,
+	SCORPIONL2_SNOOPED_BP = 0xf1,
+	SCORPIONL2_SNOOPED_BARRIERS = 0xf2,
+	SCORPIONL2_SNOOPED_TLB = 0xf3,
+	SCORPION_L2_MAX_EVT,
+};
+
+static const struct scorpion_l2_scorp_evt sc_evt[] = {
+	{SCORPIONL2_TOTAL_BANK_REQ, 0x80000001, 0, 0x00},
+	{SCORPIONL2_DSIDE_READ, 0x80000100, 0, 0x01},
+	{SCORPIONL2_DSIDE_WRITE, 0x80010000, 0, 0x02},
+	{SCORPIONL2_ISIDE_READ, 0x81000000, 0, 0x03},
+	{SCORPIONL2_L2CACHE_ISIDE_READ, 0x80000002, 0, 0x00},
+	{SCORPIONL2_L2CACHE_BANK_REQ, 0x80000200, 0, 0x01},
+	{SCORPIONL2_L2CACHE_DSIDE_READ, 0x80020000, 0, 0x02},
+	{SCORPIONL2_L2CACHE_DSIDE_WRITE, 0x82000000, 0, 0x03},
+	{SCORPIONL2_L2NOCACHE_DSIDE_WRITE, 0x80000003, 0, 0x00},
+	{SCORPIONL2_L2NOCACHE_ISIDE_READ, 0x80000300, 0, 0x01},
+	{SCORPIONL2_L2NOCACHE_TOTAL_REQ, 0x80030000, 0, 0x02},
+	{SCORPIONL2_L2NOCACHE_DSIDE_READ, 0x83000000, 0, 0x03},
+	{SCORPIONL2_DSIDE_READ_NOL1, 0x80000004, 0, 0x00},
+	{SCORPIONL2_L2CACHE_WRITETHROUGH, 0x80000400, 0, 0x01},
+	{SCORPIONL2_BARRIERS, 0x84000000, 0, 0x03},
+	{SCORPIONL2_HARDWARE_TABLE_WALKS, 0x80000005, 0, 0x00},
+	{SCORPIONL2_MVA_POC, 0x80000500, 0, 0x01},
+	{SCORPIONL2_L2CACHE_HW_TABLE_WALKS, 0x80050000, 0, 0x02},
+	{SCORPIONL2_SETWAY_CACHE_OPS, 0x85000000, 0, 0x03},
+	{SCORPIONL2_DSIDE_WRITE_HITS, 0x80000006, 0, 0x00},
+	{SCORPIONL2_ISIDE_READ_HITS, 0x80000600, 0, 0x01},
+	{SCORPIONL2_CACHE_DSIDE_READ_NOL1, 0x80060000, 0, 0x02},
+	{SCORPIONL2_TOTAL_CACHE_HITS, 0x86000000, 0, 0x03},
+	{SCORPIONL2_CACHE_MATCH_MISS, 0x80000007, 0, 0x00},
+	{SCORPIONL2_DREAD_HIT_L1_DATA, 0x87000000, 0, 0x03},
+	{SCORPIONL2_L2LINE_LOCKED, 0x80000008, 0, 0x00},
+	{SCORPIONL2_HW_TABLE_WALK_HIT, 0x80000800, 0, 0x01},
+	{SCORPIONL2_CACHE_MVA_POC, 0x80080000, 0, 0x02},
+	{SCORPIONL2_L2ALLOC_DWRITE_MISS, 0x88000000, 0, 0x03},
+	{SCORPIONL2_CORRECTED_TAG_ARRAY, 0x80001A00, 0, 0x01},
+	{SCORPIONL2_CORRECTED_DATA_ARRAY, 0x801A0000, 0, 0x02},
+	{SCORPIONL2_CORRECTED_REPLACEMENT_ARRAY, 0x9A000000, 0, 0x03},
+	{SCORPIONL2_PMBUS_MPAAF, 0x80001C00, 0, 0x01},
+	{SCORPIONL2_PMBUS_MPWDAF, 0x801C0000, 0, 0x02},
+	{SCORPIONL2_PMBUS_MPBRT, 0x9C000000, 0, 0x03},
+
+	{SCORPIONL2_CPU0_GRANT, 0x80000001, 1, 0x04},
+	{SCORPIONL2_CPU1_GRANT, 0x80000100, 1, 0x05},
+	{SCORPIONL2_CPU0_NOGRANT, 0x80020000, 1, 0x06},
+	{SCORPIONL2_CPU1_NOGRANT, 0x82000000, 1, 0x07},
+	{SCORPIONL2_CPU0_LOSING_ARB, 0x80040000, 1, 0x06},
+	{SCORPIONL2_CPU1_LOSING_ARB, 0x84000000, 1, 0x07},
+	{SCORPIONL2_SLAVEPORT_NOGRANT, 0x80000007, 1, 0x04},
+	{SCORPIONL2_SLAVEPORT_BPQ_FULL, 0x80000700, 1, 0x05},
+	{SCORPIONL2_SLAVEPORT_LOSING_ARB, 0x80070000, 1, 0x06},
+	{SCORPIONL2_SLAVEPORT_GRANT, 0x87000000, 1, 0x07},
+	{SCORPIONL2_SLAVEPORT_GRANTLOCK, 0x80000008, 1, 0x04},
+	{SCORPIONL2_L2EM_STREX_PASS, 0x80000009, 1, 0x04},
+	{SCORPIONL2_L2EM_STREX_FAIL, 0x80000900, 1, 0x05},
+	{SCORPIONL2_LDREX_RESERVE_L2EM, 0x80090000, 1, 0x06},
+	{SCORPIONL2_SLAVEPORT_LDREX, 0x89000000, 1, 0x07},
+	{SCORPIONL2_CPU0_L2EM_CLEARED, 0x800A0000, 1, 0x06},
+	{SCORPIONL2_CPU1_L2EM_CLEARED, 0x8A000000, 1, 0x07},
+	{SCORPIONL2_SLAVEPORT_L2EM_CLEARED, 0x80000B00, 1, 0x05},
+	{SCORPIONL2_CPU0_CLAMPED, 0x8000000E, 1, 0x04},
+	{SCORPIONL2_CPU1_CLAMPED, 0x80000E00, 1, 0x05},
+	{SCORPIONL2_CPU0_WAIT, 0x800F0000, 1, 0x06},
+	{SCORPIONL2_CPU1_WAIT, 0x8F000000, 1, 0x07},
+	{SCORPIONL2_CPU0_NONAMBAS_WAIT, 0x80000010, 1, 0x04},
+	{SCORPIONL2_CPU1_NONAMBAS_WAIT, 0x80001000, 1, 0x05},
+	{SCORPIONL2_CPU0_DSB_WAIT, 0x80000014, 1, 0x04},
+	{SCORPIONL2_CPU1_DSB_WAIT, 0x80001400, 1, 0x05},
+
+	{SCORPIONL2_AXI_READ, 0x80000001, 2, 0x08},
+	{SCORPIONL2_AXI_WRITE, 0x80000100, 2, 0x09},
+	{SCORPIONL2_1BEAT_WRITE, 0x80010000, 2, 0x0a},
+	{SCORPIONL2_2BEAT_WRITE, 0x80010000, 2, 0x0b},
+	{SCORPIONL2_4BEAT_WRITE, 0x80000002, 2, 0x08},
+	{SCORPIONL2_8BEAT_WRITE, 0x80000200, 2, 0x09},
+	{SCORPIONL2_12BEAT_WRITE, 0x80020000, 2, 0x0a},
+	{SCORPIONL2_16BEAT_WRITE, 0x82000000, 2, 0x0b},
+	{SCORPIONL2_1BEAT_DSIDE_READ, 0x80000003, 2, 0x08},
+	{SCORPIONL2_2BEAT_DSIDE_READ, 0x80000300, 2, 0x09},
+	{SCORPIONL2_4BEAT_DSIDE_READ, 0x80030000, 2, 0x0a},
+	{SCORPIONL2_8BEAT_DSIDE_READ, 0x83000000, 2, 0x0b},
+	{SCORPIONL2_CSYS_READ_1BEAT, 0x80000004, 2, 0x08},
+	{SCORPIONL2_CSYS_READ_2BEAT, 0x80000400, 2, 0x09},
+	{SCORPIONL2_CSYS_READ_4BEAT, 0x80040000, 2, 0x0a},
+	{SCORPIONL2_CSYS_READ_8BEAT, 0x84000000, 2, 0x0b},
+	{SCORPIONL2_4BEAT_IFETCH_READ, 0x80000005, 2, 0x08},
+	{SCORPIONL2_8BEAT_IFETCH_READ, 0x80000500, 2, 0x09},
+	{SCORPIONL2_CSYS_WRITE_1BEAT, 0x80050000, 2, 0x0a},
+	{SCORPIONL2_CSYS_WRITE_2BEAT, 0x85000000, 2, 0x0b},
+	{SCORPIONL2_AXI_READ_DATA_BEAT, 0x80000600, 2, 0x09},
+	{SCORPIONL2_AXI_WRITE_EVT1, 0x80060000, 2, 0x0a},
+	{SCORPIONL2_AXI_WRITE_EVT2, 0x86000000, 2, 0x0b},
+	{SCORPIONL2_LDREX_REQ, 0x80000007, 2, 0x08},
+	{SCORPIONL2_STREX_PASS, 0x80000700, 2, 0x09},
+	{SCORPIONL2_STREX_FAIL, 0x80070000, 2, 0x0a},
+	{SCORPIONL2_CPREAD, 0x80000008, 2, 0x08},
+	{SCORPIONL2_CPWRITE, 0x80000800, 2, 0x09},
+	{SCORPIONL2_BARRIER_REQ, 0x88000000, 2, 0x0b},
+
+	{SCORPIONL2_AXI_READ_SLVPORT, 0x80000001, 3, 0x0c},
+	{SCORPIONL2_AXI_WRITE_SLVPORT, 0x80000100, 3, 0x0d},
+	{SCORPIONL2_AXI_READ_SLVPORT_DATABEAT, 0x80010000, 3, 0x0e},
+	{SCORPIONL2_AXI_WRITE_SLVPORT_DATABEAT, 0x81000000, 3, 0x0f},
+
+	{SCORPIONL2_SNOOPKILL_PREFILTER, 0x80000001, 4, 0x10},
+	{SCORPIONL2_SNOOPKILL_FILTEROUT, 0x80000100, 4, 0x11},
+	{SCORPIONL2_SNOOPED_IC, 0x80000002, 4, 0x10},
+	{SCORPIONL2_SNOOPED_BP, 0x80000200, 4, 0x11},
+	{SCORPIONL2_SNOOPED_BARRIERS, 0x80020000, 4, 0x12},
+	{SCORPIONL2_SNOOPED_TLB, 0x82000000, 4, 0x13},
+};
+
+static struct pmu_hw_events *scorpion_l2_get_hw_events(void)
+{
+	return &scorpion_l2_pmu_hw_events;
+}
+static u32 scorpion_l2_read_l2pm0(void)
+{
+	u32 val;
+	asm volatile ("mrc p15, 3, %0, c15, c7, 0" : "=r" (val));
+	return val;
+}
+
+static void scorpion_l2_write_l2pm0(u32 val)
+{
+	asm volatile ("mcr p15, 3, %0, c15, c7, 0" : : "r" (val));
+}
+
+static u32 scorpion_l2_read_l2pm1(void)
+{
+	u32 val;
+	asm volatile ("mrc p15, 3, %0, c15, c7, 1" : "=r" (val));
+	return val;
+}
+
+static void scorpion_l2_write_l2pm1(u32 val)
+{
+	asm volatile ("mcr p15, 3, %0, c15, c7, 1" : : "r" (val));
+}
+
+static u32 scorpion_l2_read_l2pm2(void)
+{
+	u32 val;
+	asm volatile ("mrc p15, 3, %0, c15, c7, 2" : "=r" (val));
+	return val;
+}
+
+static void scorpion_l2_write_l2pm2(u32 val)
+{
+	asm volatile ("mcr p15, 3, %0, c15, c7, 2" : : "r" (val));
+}
+
+static u32 scorpion_l2_read_l2pm3(void)
+{
+	u32 val;
+	asm volatile ("mrc p15, 3, %0, c15, c7, 3" : "=r" (val));
+	return val;
+}
+
+static void scorpion_l2_write_l2pm3(u32 val)
+{
+	asm volatile ("mcr p15, 3, %0, c15, c7, 3" : : "r" (val));
+}
+
+static u32 scorpion_l2_read_l2pm4(void)
+{
+	u32 val;
+	asm volatile ("mrc p15, 3, %0, c15, c7, 4" : "=r" (val));
+	return val;
+}
+
+static void scorpion_l2_write_l2pm4(u32 val)
+{
+	asm volatile ("mcr p15, 3, %0, c15, c7, 4" : : "r" (val));
+}
+
+struct scorpion_scorpion_access_funcs {
+	u32(*read) (void);
+	void (*write) (u32);
+	void (*pre) (void);
+	void (*post) (void);
+};
+
+struct scorpion_scorpion_access_funcs scorpion_l2_func[] = {
+	{scorpion_l2_read_l2pm0, scorpion_l2_write_l2pm0, NULL, NULL},
+	{scorpion_l2_read_l2pm1, scorpion_l2_write_l2pm1, NULL, NULL},
+	{scorpion_l2_read_l2pm2, scorpion_l2_write_l2pm2, NULL, NULL},
+	{scorpion_l2_read_l2pm3, scorpion_l2_write_l2pm3, NULL, NULL},
+	{scorpion_l2_read_l2pm4, scorpion_l2_write_l2pm4, NULL, NULL},
+};
+
+#define COLMN0MASK 0x000000ff
+#define COLMN1MASK 0x0000ff00
+#define COLMN2MASK 0x00ff0000
+
+static u32 scorpion_l2_get_columnmask(u32 setval)
+{
+	if (setval & COLMN0MASK)
+		return 0xffffff00;
+	else if (setval & COLMN1MASK)
+		return 0xffff00ff;
+	else if (setval & COLMN2MASK)
+		return 0xff00ffff;
+	else
+		return 0x80ffffff;
+}
+
+static void scorpion_l2_evt_setup(u32 gr, u32 setval)
+{
+	u32 val;
+	if (scorpion_l2_func[gr].pre)
+		scorpion_l2_func[gr].pre();
+	val = scorpion_l2_get_columnmask(setval) & scorpion_l2_func[gr].read();
+	val = val | setval;
+	scorpion_l2_func[gr].write(val);
+	if (scorpion_l2_func[gr].post)
+		scorpion_l2_func[gr].post();
+}
+
+#define SCORPION_L2_EVT_START_IDX 0x90
+#define SCORPION_L2_INV_EVTYPE 0
+
+static unsigned int get_scorpion_l2_evtinfo(unsigned int evt_type,
+				      struct scorpion_l2_scorp_evt *evtinfo)
+{
+	u32 idx;
+	u8 prefix;
+	u8 reg;
+	u8 code;
+	u8 group;
+
+	prefix = (evt_type & 0xF0000) >> 16;
+	if (prefix == SCORPION_L2_EVT_PREFIX) {
+		reg   = (evt_type & 0x0F000) >> 12;
+		code  = (evt_type & 0x00FF0) >> 4;
+		group =  evt_type & 0x0000F;
+
+		if ((group > 3) || (reg > SCORPION_MAX_L2_REG))
+			return SCORPION_L2_INV_EVTYPE;
+
+		evtinfo->val = 0x80000000 | (code << (group * 8));
+		evtinfo->grp = reg;
+		evtinfo->evt_type_act = group | (reg << 2);
+		return evtinfo->evt_type_act;
+	}
+
+	if (evt_type < SCORPION_L2_EVT_START_IDX
+			|| evt_type >= SCORPION_L2_MAX_EVT)
+		return SCORPION_L2_INV_EVTYPE;
+
+	idx = evt_type - SCORPION_L2_EVT_START_IDX;
+
+	if (sc_evt[idx].evt_type == evt_type) {
+		evtinfo->val = sc_evt[idx].val;
+		evtinfo->grp = sc_evt[idx].grp;
+		evtinfo->evt_type_act = sc_evt[idx].evt_type_act;
+		return sc_evt[idx].evt_type_act;
+	}
+	return SCORPION_L2_INV_EVTYPE;
+}
+
+static inline void scorpion_l2_pmnc_write(unsigned long val)
+{
+	val &= 0xff;
+	asm volatile ("mcr p15, 3, %0, c15, c4, 0" : : "r" (val));
+}
+
+static inline unsigned long scorpion_l2_pmnc_read(void)
+{
+	u32 val;
+	asm volatile ("mrc p15, 3, %0, c15, c4, 0" : "=r" (val));
+	return val;
+}
+
+static void scorpion_l2_set_evcntcr(void)
+{
+	u32 val = 0x0;
+	asm volatile ("mcr p15, 3, %0, c15, c6, 4" : : "r" (val));
+}
+
+static inline void scorpion_l2_set_evtyper(int ctr, int val)
+{
+	/* select ctr */
+	asm volatile ("mcr p15, 3, %0, c15, c6, 0" : : "r" (ctr));
+
+	/* write into EVTYPER */
+	asm volatile ("mcr p15, 3, %0, c15, c6, 7" : : "r" (val));
+}
+
+static void scorpion_l2_set_evfilter_task_mode(void)
+{
+	u32 filter_val = 0x000f0030 | 1 << smp_processor_id();
+
+	asm volatile ("mcr p15, 3, %0, c15, c6, 3" : : "r" (filter_val));
+}
+
+static void scorpion_l2_set_evfilter_sys_mode(void)
+{
+	u32 filter_val = 0x000f003f;
+
+	asm volatile ("mcr p15, 3, %0, c15, c6, 3" : : "r" (filter_val));
+}
+
+static void scorpion_l2_enable_intenset(u32 idx)
+{
+	if (idx == SCORPION_L2CYCLE_CTR_EVENT_IDX) {
+		asm volatile ("mcr p15, 3, %0, c15, c5, 1" : : "r"
+			      (1 << SCORPION_L2CYCLE_CTR_BIT));
+	} else {
+		asm volatile ("mcr p15, 3, %0, c15, c5, 1" : : "r" (1 << idx));
+	}
+}
+
+static void scorpion_l2_disable_intenclr(u32 idx)
+{
+	if (idx == SCORPION_L2CYCLE_CTR_EVENT_IDX) {
+		asm volatile ("mcr p15, 3, %0, c15, c5, 0" : : "r"
+			      (1 << SCORPION_L2CYCLE_CTR_BIT));
+	} else {
+		asm volatile ("mcr p15, 3, %0, c15, c5, 0" : : "r" (1 << idx));
+	}
+}
+
+static void scorpion_l2_enable_counter(u32 idx)
+{
+	if (idx == SCORPION_L2CYCLE_CTR_EVENT_IDX) {
+		asm volatile ("mcr p15, 3, %0, c15, c4, 3" : : "r"
+			      (1 << SCORPION_L2CYCLE_CTR_BIT));
+	} else {
+		asm volatile ("mcr p15, 3, %0, c15, c4, 3" : : "r" (1 << idx));
+	}
+}
+
+static void scorpion_l2_disable_counter(u32 idx)
+{
+	if (idx == SCORPION_L2CYCLE_CTR_EVENT_IDX) {
+		asm volatile ("mcr p15, 3, %0, c15, c4, 2" : : "r"
+			      (1 << SCORPION_L2CYCLE_CTR_BIT));
+	} else {
+		asm volatile ("mcr p15, 3, %0, c15, c4, 2" : : "r" (1 << idx));
+	}
+}
+
+static u32 scorpion_l2_read_counter(int idx)
+{
+	u32 val;
+	unsigned long iflags;
+
+	if (idx == SCORPION_L2CYCLE_CTR_EVENT_IDX) {
+		asm volatile ("mrc p15, 3, %0, c15, c4, 5" : "=r" (val));
+	} else {
+		raw_spin_lock_irqsave(&scorpion_l2_pmu_hw_events.pmu_lock,
+				iflags);
+		asm volatile ("mcr p15, 3, %0, c15, c6, 0" : : "r" (idx));
+
+		/* read val from counter */
+		asm volatile ("mrc p15, 3, %0, c15, c6, 5" : "=r" (val));
+		raw_spin_unlock_irqrestore(&scorpion_l2_pmu_hw_events.pmu_lock,
+				iflags);
+	}
+
+	return val;
+}
+
+static void scorpion_l2_write_counter(int idx, u32 val)
+{
+	unsigned long iflags;
+
+	if (idx == SCORPION_L2CYCLE_CTR_EVENT_IDX) {
+		asm volatile ("mcr p15, 3, %0, c15, c4, 5" : : "r" (val));
+	} else {
+		raw_spin_lock_irqsave(&scorpion_l2_pmu_hw_events.pmu_lock,
+				iflags);
+
+		/* select counter */
+		asm volatile ("mcr p15, 3, %0, c15, c6, 0" : : "r" (idx));
+
+		/* write val into counter */
+		asm volatile ("mcr p15, 3, %0, c15, c6, 5" : : "r" (val));
+		raw_spin_unlock_irqrestore(&scorpion_l2_pmu_hw_events.pmu_lock,
+				iflags);
+	}
+}
+
+static void scorpion_l2_stop_counter(struct hw_perf_event *hwc, int idx)
+{
+	scorpion_l2_disable_intenclr(idx);
+	scorpion_l2_disable_counter(idx);
+	pr_debug("%s: event: %ld ctr: %d stopped\n", __func__,
+			hwc->config_base, idx);
+}
+
+static void scorpion_l2_enable(struct hw_perf_event *hwc, int idx, int cpu)
+{
+	struct scorpion_l2_scorp_evt evtinfo;
+	int evtype = hwc->config_base;
+	int ev_typer;
+	unsigned long iflags;
+
+	raw_spin_lock_irqsave(&scorpion_l2_pmu_hw_events.pmu_lock, iflags);
+
+	if (hwc->config_base == SCORPION_L2CYCLE_CTR_RAW_CODE)
+		goto out;
+
+	memset(&evtinfo, 0, sizeof(evtinfo));
+
+	ev_typer = get_scorpion_l2_evtinfo(evtype, &evtinfo);
+
+	scorpion_l2_set_evtyper(idx, ev_typer);
+
+	scorpion_l2_set_evcntcr();
+
+	if (cpu < 0)
+		scorpion_l2_set_evfilter_task_mode();
+	else
+		scorpion_l2_set_evfilter_sys_mode();
+
+	scorpion_l2_evt_setup(evtinfo.grp, evtinfo.val);
+
+out:
+
+	scorpion_l2_enable_intenset(idx);
+
+	scorpion_l2_enable_counter(idx);
+
+	raw_spin_unlock_irqrestore(&scorpion_l2_pmu_hw_events.pmu_lock, iflags);
+
+	pr_debug("%s: ctr: %d group: %ld group_code: %lld started from cpu:%d\n",
+	     __func__, idx, hwc->config_base, hwc->config, smp_processor_id());
+}
+
+static void scorpion_l2_disable(struct hw_perf_event *hwc, int idx)
+{
+	unsigned long iflags;
+
+	raw_spin_lock_irqsave(&scorpion_l2_pmu_hw_events.pmu_lock, iflags);
+
+	scorpion_l2_stop_counter(hwc, idx);
+
+	raw_spin_unlock_irqrestore(&scorpion_l2_pmu_hw_events.pmu_lock, iflags);
+
+	pr_debug("%s: event: %ld deleted\n", __func__, hwc->config_base);
+}
+
+static int scorpion_l2_get_event_idx(struct pmu_hw_events *cpuc,
+				  struct hw_perf_event *hwc)
+{
+	int ctr = 0;
+
+	if (hwc->config_base == SCORPION_L2CYCLE_CTR_RAW_CODE) {
+		if (!test_and_set_bit(SCORPION_L2CYCLE_CTR_EVENT_IDX,
+					cpuc->used_mask))
+			return SCORPION_L2CYCLE_CTR_EVENT_IDX;
+	}
+
+	for (ctr = 0; ctr < MAX_SCORPION_L2_CTRS - 1; ctr++) {
+		if (!test_and_set_bit(ctr, cpuc->used_mask))
+			return ctr;
+	}
+
+	return -EAGAIN;
+}
+
+static void scorpion_l2_start(void)
+{
+	isb();
+	/* Enable all counters */
+	scorpion_l2_pmnc_write(scorpion_l2_pmnc_read() | SCORPIONL2_PMNC_E);
+}
+
+static void scorpion_l2_stop(void)
+{
+	/* Disable all counters */
+	scorpion_l2_pmnc_write(scorpion_l2_pmnc_read() & ~SCORPIONL2_PMNC_E);
+	isb();
+}
+
+static inline u32 scorpion_l2_get_reset_pmovsr(void)
+{
+	u32 val;
+
+	/* Read */
+	asm volatile ("mrc p15, 3, %0, c15, c4, 1" : "=r" (val));
+
+	/* Write to clear flags */
+	val &= 0xffffffff;
+	asm volatile ("mcr p15, 3, %0, c15, c4, 1" : : "r" (val));
+
+	return val;
+}
+
+static irqreturn_t scorpion_l2_handle_irq(int irq_num, void *dev)
+{
+	unsigned long pmovsr;
+	struct perf_sample_data data;
+	struct pt_regs *regs;
+	struct perf_event *event;
+	struct hw_perf_event *hwc;
+	int bitp;
+	int idx = 0;
+
+	pmovsr = scorpion_l2_get_reset_pmovsr();
+
+	if (!(pmovsr & 0xffffffff))
+		return IRQ_NONE;
+
+	regs = get_irq_regs();
+
+	perf_sample_data_init(&data, 0);
+
+	while (pmovsr) {
+		bitp = __ffs(pmovsr);
+
+		if (bitp == SCORPION_L2CYCLE_CTR_BIT)
+			idx = SCORPION_L2CYCLE_CTR_EVENT_IDX;
+		else
+			idx = bitp;
+
+		event = scorpion_l2_pmu_hw_events.events[idx];
+
+		if (!event)
+			goto next;
+
+		if (!test_bit(idx, scorpion_l2_pmu_hw_events.used_mask))
+			goto next;
+
+		hwc = &event->hw;
+
+		armpmu_event_update(event, hwc, idx);
+
+		data.period = event->hw.last_period;
+
+		if (!armpmu_event_set_period(event, hwc, idx))
+			goto next;
+
+		if (perf_event_overflow(event, &data, regs))
+			scorpion_l2_disable_counter(hwc->idx);
+next:
+		pmovsr &= (pmovsr - 1);
+	}
+
+	irq_work_run();
+
+	return IRQ_HANDLED;
+}
+
+static int scorpion_l2_map_event(struct perf_event *event)
+{
+	if (pmu_type > 0 && pmu_type == event->attr.type)
+		return event->attr.config & 0xfffff;
+	else
+		return -ENOENT;
+}
+
+static int
+scorpion_l2_pmu_generic_request_irq(int irq, irq_handler_t *handle_irq)
+{
+	return request_irq(irq, *handle_irq,
+			IRQF_DISABLED | IRQF_NOBALANCING,
+			"scorpion-l2-armpmu", NULL);
+}
+
+static void
+scorpion_l2_pmu_generic_free_irq(int irq)
+{
+	if (irq >= 0)
+		free_irq(irq, NULL);
+}
+
+static struct arm_pmu scorpion_l2_pmu = {
+	.id		=	ARM_PERF_PMU_ID_SCORPIONMP_L2,
+	.type		=	ARM_PMU_DEVICE_L2CC,
+	.name		=	"Scorpion L2CC PMU",
+	.start		=	scorpion_l2_start,
+	.stop		=	scorpion_l2_stop,
+	.handle_irq	=	scorpion_l2_handle_irq,
+	.request_pmu_irq	= scorpion_l2_pmu_generic_request_irq,
+	.free_pmu_irq		= scorpion_l2_pmu_generic_free_irq,
+	.enable		=	scorpion_l2_enable,
+	.disable	=	scorpion_l2_disable,
+	.read_counter	=	scorpion_l2_read_counter,
+	.get_event_idx	=	scorpion_l2_get_event_idx,
+	.write_counter	=	scorpion_l2_write_counter,
+	.map_event	=	scorpion_l2_map_event,
+	.max_period	=	(1LLU << 32) - 1,
+	.get_hw_events	=	scorpion_l2_get_hw_events,
+	.num_events	=	MAX_SCORPION_L2_CTRS,
+};
+
+static int __devinit scorpion_l2_pmu_device_probe(struct platform_device *pdev)
+{
+	scorpion_l2_pmu.plat_device = pdev;
+
+	if (!armpmu_register(&scorpion_l2_pmu, "scorpion-l2", -1))
+		pmu_type = scorpion_l2_pmu.pmu.type;
+
+	return 0;
+}
+
+static struct platform_driver scorpion_l2_pmu_driver = {
+	.driver		= {
+		.name	= "l2-arm-pmu",
+	},
+	.probe		= scorpion_l2_pmu_device_probe,
+};
+
+static int __init register_scorpion_l2_pmu_driver(void)
+{
+	/* Avoid spurious interrupt if any */
+	scorpion_l2_get_reset_pmovsr();
+
+	return platform_driver_register(&scorpion_l2_pmu_driver);
+}
+device_initcall(register_scorpion_l2_pmu_driver);
diff --git a/arch/arm/mach-msm/platsmp-8625.c b/arch/arm/mach-msm/platsmp-8625.c
index 915047a..b31d94b 100644
--- a/arch/arm/mach-msm/platsmp-8625.c
+++ b/arch/arm/mach-msm/platsmp-8625.c
@@ -86,7 +86,7 @@
 	c->irq_mask(d);
 	local_irq_disable();
 	/* Clear the IRQ from the ENABLE_SET */
-	gic_clear_spi_pending(irq);
+	gic_clear_irq_pending(irq);
 	local_irq_enable();
 }
 
diff --git a/arch/arm/mach-msm/pmu.c b/arch/arm/mach-msm/pmu.c
index 1f82468..5e339da 100644
--- a/arch/arm/mach-msm/pmu.c
+++ b/arch/arm/mach-msm/pmu.c
@@ -33,7 +33,7 @@
 
 static struct platform_device l2_pmu_device = {
 	.name		= "l2-arm-pmu",
-	.id		= ARM_PMU_DEVICE_L2,
+	.id		= ARM_PMU_DEVICE_L2CC,
 	.resource	= l2_pmu_resource,
 	.num_resources	= ARRAY_SIZE(l2_pmu_resource),
 };
diff --git a/arch/arm/mach-msm/qdss-stm.c b/arch/arm/mach-msm/qdss-stm.c
new file mode 100644
index 0000000..9ce6318
--- /dev/null
+++ b/arch/arm/mach-msm/qdss-stm.c
@@ -0,0 +1,595 @@
+/* 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
+#include <mach/stm.h>
+
+#include "qdss-priv.h"
+
+#define stm_writel(stm, val, off)	\
+			__raw_writel((val), stm.base + off)
+#define stm_readl(stm, val, off)	\
+			__raw_readl(stm.base + off)
+
+#define NR_STM_CHANNEL		(32)
+#define BYTES_PER_CHANNEL	(256)
+
+enum {
+	STM_PKT_TYPE_DATA	= 0x98,
+	STM_PKT_TYPE_FLAG	= 0xE8,
+	STM_PKT_TYPE_TRIG	= 0xF8,
+};
+
+enum {
+	STM_OPTION_MARKED	= 0x10,
+};
+
+#define STM_TRACE_BUF_SIZE	(1024)
+
+#define OST_START_TOKEN		(0x30)
+#define OST_VERSION		(0x1)
+
+#define stm_channel_addr(ch)						\
+				(stm.chs.base + (ch * BYTES_PER_CHANNEL))
+#define stm_channel_off(type, opts)	(type & ~opts)
+
+#define STM_LOCK()							\
+do {									\
+	mb();								\
+	stm_writel(stm, 0x0, CS_LAR);					\
+} while (0)
+#define STM_UNLOCK()							\
+do {									\
+	stm_writel(stm, CS_UNLOCK_MAGIC, CS_LAR);			\
+	mb();								\
+} while (0)
+
+#define STMSPER		(0xE00)
+#define STMSPTER	(0xE20)
+#define STMTCSR		(0xE80)
+#define STMSYNCR	(0xE90)
+
+#ifdef CONFIG_MSM_QDSS_STM_DEFAULT_ENABLE
+static int stm_boot_enable = 1;
+#else
+static int stm_boot_enable;
+#endif
+
+module_param_named(
+	stm_boot_enable, stm_boot_enable, int, S_IRUGO
+);
+
+static int stm_boot_nr_channel;
+
+module_param_named(
+	stm_boot_nr_channel, stm_boot_nr_channel, int, S_IRUGO
+);
+
+struct channel_space {
+	void __iomem		*base;
+	unsigned long		*bitmap;
+};
+
+struct stm_ctx {
+	void __iomem		*base;
+	bool			enabled;
+	struct qdss_source	*src;
+	struct device		*dev;
+	struct kobject		*kobj;
+	uint32_t		entity;
+	struct channel_space	chs;
+};
+
+static struct stm_ctx stm = {
+	.entity		= OST_ENTITY_ALL,
+};
+
+
+static void __stm_enable(void)
+{
+	STM_UNLOCK();
+
+	stm_writel(stm, 0x80, STMSYNCR);
+	stm_writel(stm, 0xFFFFFFFF, STMSPTER);
+	stm_writel(stm, 0xFFFFFFFF, STMSPER);
+	stm_writel(stm, 0x30003, STMTCSR);
+
+	STM_LOCK();
+}
+
+static int stm_enable(void)
+{
+	int ret;
+
+	if (stm.enabled) {
+		dev_err(stm.dev, "STM tracing already enabled\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	ret = qdss_enable(stm.src);
+	if (ret)
+		goto err;
+
+	__stm_enable();
+
+	stm.enabled = true;
+
+	dev_info(stm.dev, "STM tracing enabled\n");
+	return 0;
+
+err:
+	return ret;
+}
+
+static void __stm_disable(void)
+{
+	STM_UNLOCK();
+
+	stm_writel(stm, 0x30000, STMTCSR);
+	stm_writel(stm, 0x0, STMSPER);
+	stm_writel(stm, 0x0, STMSPTER);
+
+	STM_LOCK();
+}
+
+static int stm_disable(void)
+{
+	int ret;
+
+	if (!stm.enabled) {
+		dev_err(stm.dev, "STM tracing already disabled\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	__stm_disable();
+
+	qdss_disable(stm.src);
+
+	stm.enabled = false;
+
+	dev_info(stm.dev, "STM tracing disabled\n");
+	return 0;
+
+err:
+	return ret;
+}
+
+static uint32_t stm_channel_alloc(uint32_t off)
+{
+	uint32_t ch;
+
+	do {
+		ch = find_next_zero_bit(stm.chs.bitmap,	NR_STM_CHANNEL, off);
+	} while ((ch < NR_STM_CHANNEL) && test_and_set_bit(ch, stm.chs.bitmap));
+
+	return ch;
+}
+
+static void stm_channel_free(uint32_t ch)
+{
+	clear_bit(ch, stm.chs.bitmap);
+}
+
+static int stm_send(void *addr, const void *data, uint32_t size)
+{
+	uint64_t prepad = 0;
+	uint64_t postpad = 0;
+	char *pad;
+	uint8_t off, endoff;
+	uint32_t len = size;
+
+	/* only 64bit writes are supported, we rely on the compiler to
+	 * generate STRD instruction for the casted 64bit assignments
+	 */
+
+	off = (unsigned long)data & 0x7;
+
+	if (off) {
+		endoff = 8 - off;
+		pad = (char *)&prepad;
+		pad += off;
+
+		while (endoff && size) {
+			*pad++ = *(char *)data++;
+			endoff--;
+			size--;
+		}
+		*(volatile uint64_t __force *)addr = prepad;
+	}
+
+	/* now we are 64bit aligned */
+	while (size >= 8) {
+		*(volatile uint64_t __force *)addr = *(uint64_t *)data;
+		data += 8;
+		size -= 8;
+	}
+
+	if (size) {
+		pad = (char *)&postpad;
+
+		while (size) {
+			*pad++ = *(char *)data++;
+			size--;
+		}
+		*(volatile uint64_t __force *)addr = postpad;
+	}
+
+	return roundup(len + off, 8);
+}
+
+static int stm_trace_ost_header(unsigned long ch_addr, uint32_t options,
+				uint8_t entity_id, uint8_t proto_id,
+				const void *payload_data, uint32_t payload_size)
+{
+	void *addr;
+	uint8_t prepad_size;
+	uint64_t header;
+	char *hdr;
+
+	hdr = (char *)&header;
+
+	hdr[0] = OST_START_TOKEN;
+	hdr[1] = OST_VERSION;
+	hdr[2] = entity_id;
+	hdr[3] = proto_id;
+	prepad_size = (unsigned long)payload_data & 0x7;
+	*(uint32_t *)(hdr + 4) = (prepad_size << 24) | payload_size;
+
+	/* for 64bit writes, header is expected to be of the D32M, D32M */
+	options |= STM_OPTION_MARKED;
+	options &= ~STM_OPTION_TIMESTAMPED;
+	addr =  (void *)(ch_addr | stm_channel_off(STM_PKT_TYPE_DATA, options));
+
+	return stm_send(addr, &header, sizeof(header));
+}
+
+static int stm_trace_data(unsigned long ch_addr, uint32_t options,
+			  const void *data, uint32_t size)
+{
+	void *addr;
+
+	options &= ~STM_OPTION_TIMESTAMPED;
+	addr = (void *)(ch_addr | stm_channel_off(STM_PKT_TYPE_DATA, options));
+
+	return stm_send(addr, data, size);
+}
+
+static int stm_trace_ost_tail(unsigned long ch_addr, uint32_t options)
+{
+	void *addr;
+	uint64_t tail = 0x0;
+
+	addr = (void *)(ch_addr | stm_channel_off(STM_PKT_TYPE_FLAG, options));
+
+	return stm_send(addr, &tail, sizeof(tail));
+}
+
+static inline int __stm_trace(uint32_t options, uint8_t entity_id,
+			      uint8_t proto_id, const void *data, uint32_t size)
+{
+	int len = 0;
+	uint32_t ch;
+	unsigned long ch_addr;
+
+	/* allocate channel and get the channel address */
+	ch = stm_channel_alloc(0);
+	ch_addr = (unsigned long)stm_channel_addr(ch);
+
+	/* send the ost header */
+	len += stm_trace_ost_header(ch_addr, options, entity_id, proto_id, data,
+				    size);
+
+	/* send the payload data */
+	len += stm_trace_data(ch_addr, options, data, size);
+
+	/* send the ost tail */
+	len += stm_trace_ost_tail(ch_addr, options);
+
+	/* we are done, free the channel */
+	stm_channel_free(ch);
+
+	return len;
+}
+
+/**
+ * stm_trace - trace the binary or string data through STM
+ * @options: tracing options - guaranteed, timestamped, etc
+ * @entity_id: entity representing the trace data
+ * @proto_id: protocol id to distinguish between different binary formats
+ * @data: pointer to binary or string data buffer
+ * @size: size of data to send
+ *
+ * Packetizes the data as the payload to an OST packet and sends it over STM
+ *
+ * CONTEXT:
+ * Can be called from any context.
+ *
+ * RETURNS:
+ * number of bytes transfered over STM
+ */
+int stm_trace(uint32_t options, uint8_t entity_id, uint8_t proto_id,
+	      const void *data, uint32_t size)
+{
+	/* we don't support sizes more than 24bits (0 to 23) */
+	if (!(stm.enabled && (stm.entity & entity_id) &&
+	      (size < 0x1000000)))
+		return 0;
+
+	return __stm_trace(options, entity_id, proto_id, data, size);
+}
+EXPORT_SYMBOL(stm_trace);
+
+static ssize_t stm_write(struct file *file, const char __user *data,
+			 size_t size, loff_t *ppos)
+{
+	char *buf;
+
+	if (!stm.enabled)
+		return -EINVAL;
+
+	if (!(stm.entity & OST_ENTITY_DEV_NODE))
+		return size;
+
+	if (size > STM_TRACE_BUF_SIZE)
+		size = STM_TRACE_BUF_SIZE;
+
+	buf = kmalloc(size, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	if (copy_from_user(buf, data, size)) {
+		kfree(buf);
+		dev_dbg(stm.dev, "%s: copy_from_user failed\n", __func__);
+		return -EFAULT;
+	}
+
+	__stm_trace(STM_OPTION_TIMESTAMPED, OST_ENTITY_DEV_NODE, 0, buf, size);
+
+	kfree(buf);
+
+	return size;
+}
+
+static const struct file_operations stm_fops = {
+	.owner		= THIS_MODULE,
+	.write		= stm_write,
+	.llseek		= no_llseek,
+};
+
+static struct miscdevice stm_misc = {
+	.name		= "msm_stm",
+	.minor		= MISC_DYNAMIC_MINOR,
+	.fops		= &stm_fops,
+};
+
+#define STM_ATTR(__name)						\
+static struct kobj_attribute __name##_attr =				\
+	__ATTR(__name, S_IRUGO | S_IWUSR, __name##_show, __name##_store)
+
+static ssize_t enabled_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	int ret = 0;
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	if (val)
+		ret = stm_enable();
+	else
+		ret = stm_disable();
+
+	if (ret)
+		return ret;
+	return n;
+}
+static ssize_t enabled_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val = stm.enabled;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+STM_ATTR(enabled);
+
+static ssize_t entity_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	stm.entity = val;
+	return n;
+}
+static ssize_t entity_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val = stm.entity;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+STM_ATTR(entity);
+
+static int __devinit stm_sysfs_init(void)
+{
+	int ret;
+
+	stm.kobj = kobject_create_and_add("stm", qdss_get_modulekobj());
+	if (!stm.kobj) {
+		dev_err(stm.dev, "failed to create STM sysfs kobject\n");
+		ret = -ENOMEM;
+		goto err_create;
+	}
+
+	ret = sysfs_create_file(stm.kobj, &enabled_attr.attr);
+	if (ret) {
+		dev_err(stm.dev, "failed to create STM sysfs enabled attr\n");
+		goto err_file;
+	}
+
+	if (sysfs_create_file(stm.kobj, &entity_attr.attr))
+		dev_err(stm.dev, "failed to create STM sysfs entity attr\n");
+
+	return 0;
+err_file:
+	kobject_put(stm.kobj);
+err_create:
+	return ret;
+}
+
+static void __devexit stm_sysfs_exit(void)
+{
+	sysfs_remove_file(stm.kobj, &entity_attr.attr);
+	sysfs_remove_file(stm.kobj, &enabled_attr.attr);
+	kobject_put(stm.kobj);
+}
+
+static int __devinit stm_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct resource *res;
+	size_t res_size, bitmap_size;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -EINVAL;
+		goto err_res0;
+	}
+
+	stm.base = ioremap_nocache(res->start, resource_size(res));
+	if (!stm.base) {
+		ret = -EINVAL;
+		goto err_ioremap0;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		ret = -EINVAL;
+		goto err_res1;
+	}
+
+	if (stm_boot_nr_channel) {
+		res_size = min((resource_size_t)(stm_boot_nr_channel *
+				  BYTES_PER_CHANNEL), resource_size(res));
+		bitmap_size = stm_boot_nr_channel * sizeof(long);
+	} else {
+		res_size = min((resource_size_t)(NR_STM_CHANNEL *
+				 BYTES_PER_CHANNEL), resource_size(res));
+		bitmap_size = NR_STM_CHANNEL * sizeof(long);
+	}
+
+	stm.chs.bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+	if (!stm.chs.bitmap) {
+		ret = -ENOMEM;
+		goto err_bitmap;
+	}
+
+	stm.chs.base = ioremap_nocache(res->start, res_size);
+	if (!stm.chs.base) {
+		ret = -EINVAL;
+		goto err_ioremap1;
+	}
+
+	stm.dev = &pdev->dev;
+
+	ret = misc_register(&stm_misc);
+	if (ret)
+		goto err_misc;
+
+	stm.src = qdss_get("msm_stm");
+	if (IS_ERR(stm.src)) {
+		ret = PTR_ERR(stm.src);
+		goto err_qdssget;
+	}
+
+	ret = stm_sysfs_init();
+	if (ret)
+		goto err_sysfs;
+
+	if (stm_boot_enable)
+		stm_enable();
+
+	dev_info(stm.dev, "STM initialized\n");
+	return 0;
+
+err_sysfs:
+	qdss_put(stm.src);
+err_qdssget:
+	misc_deregister(&stm_misc);
+err_misc:
+	iounmap(stm.chs.base);
+err_ioremap1:
+	kfree(stm.chs.bitmap);
+err_bitmap:
+err_res1:
+	iounmap(stm.base);
+err_ioremap0:
+err_res0:
+	dev_err(stm.dev, "STM init failed\n");
+	return ret;
+}
+
+static int __devexit stm_remove(struct platform_device *pdev)
+{
+	if (stm.enabled)
+		stm_disable();
+	stm_sysfs_exit();
+	qdss_put(stm.src);
+	misc_deregister(&stm_misc);
+	iounmap(stm.chs.base);
+	kfree(stm.chs.bitmap);
+	iounmap(stm.base);
+
+	return 0;
+}
+
+static struct platform_driver stm_driver = {
+	.probe          = stm_probe,
+	.remove         = __devexit_p(stm_remove),
+	.driver         = {
+		.name   = "msm_stm",
+	},
+};
+
+static int __init stm_init(void)
+{
+	return platform_driver_register(&stm_driver);
+}
+module_init(stm_init);
+
+static void __exit stm_exit(void)
+{
+	platform_driver_unregister(&stm_driver);
+}
+module_exit(stm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CoreSight System Trace Macrocell driver");
diff --git a/arch/arm/mach-msm/rpm.c b/arch/arm/mach-msm/rpm.c
index 44e50dd..5ab484e2 100644
--- a/arch/arm/mach-msm/rpm.c
+++ b/arch/arm/mach-msm/rpm.c
@@ -275,13 +275,13 @@
 	int rc;
 
 	do {
-		while (!gic_is_spi_pending(msm_rpm_data.irq_ack) &&
+		while (!gic_is_irq_pending(msm_rpm_data.irq_ack) &&
 				msm_rpm_request) {
 			if (allow_async_completion)
 				spin_unlock(&msm_rpm_irq_lock);
-			if (gic_is_spi_pending(msm_rpm_data.irq_err))
+			if (gic_is_irq_pending(msm_rpm_data.irq_err))
 				msm_rpm_err_fatal();
-			gic_clear_spi_pending(msm_rpm_data.irq_err);
+			gic_clear_irq_pending(msm_rpm_data.irq_err);
 			udelay(1);
 			if (allow_async_completion)
 				spin_lock(&msm_rpm_irq_lock);
@@ -291,7 +291,7 @@
 			break;
 
 		rc = msm_rpm_process_ack_interrupt();
-		gic_clear_spi_pending(msm_rpm_data.irq_ack);
+		gic_clear_irq_pending(msm_rpm_data.irq_ack);
 	} while (rc);
 }
 
diff --git a/arch/arm/mach-msm/subsystem_map.c b/arch/arm/mach-msm/subsystem_map.c
index fcb8517..5f5a02b 100644
--- a/arch/arm/mach-msm/subsystem_map.c
+++ b/arch/arm/mach-msm/subsystem_map.c
@@ -38,8 +38,10 @@
 	VIDEO_DOMAIN,
 	VIDEO_DOMAIN,
 	CAMERA_DOMAIN,
-	DISPLAY_DOMAIN,
-	ROTATOR_DOMAIN,
+	DISPLAY_READ_DOMAIN,
+	DISPLAY_WRITE_DOMAIN,
+	ROTATOR_SRC_DOMAIN,
+	ROTATOR_DST_DOMAIN,
 	0xFFFFFFFF
 };
 
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 5cbf888..2860055 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -16,6 +16,7 @@
 #include <linux/diagchar.h>
 #include <linux/sched.h>
 #include <linux/err.h>
+#include <linux/delay.h>
 #include <linux/workqueue.h>
 #include <linux/pm_runtime.h>
 #include <linux/platform_device.h>
@@ -115,6 +116,23 @@
 	queue_work(driver->diag_wq, &(driver->diag_read_smd_dci_work));
 }
 
+void diag_dci_notify_client(int peripheral_mask)
+{
+	int i, stat;
+
+	/* Notify the DCI process that the peripheral DCI Channel is up */
+	for (i = 0; i < MAX_DCI_CLIENT; i++) {
+		if (driver->dci_notify_tbl[i].list & peripheral_mask) {
+			pr_debug("diag: sending signal now\n");
+			stat = send_sig(driver->dci_notify_tbl[i].signal_type,
+					 driver->dci_notify_tbl[i].client, 0);
+			if (stat)
+				pr_err("diag: Err send sig stat: %d\n", stat);
+			break;
+		}
+	} /* end of loop for all DCI clients */
+}
+
 static int diag_dci_probe(struct platform_device *pdev)
 {
 	int err = 0;
@@ -125,6 +143,8 @@
 		if (err)
 			pr_err("diag: cannot open DCI port, Id = %d, err ="
 				" %d\n", pdev->id, err);
+		else
+			diag_dci_notify_client(DIAG_CON_MPSS);
 	}
 	return err;
 }
@@ -302,6 +322,12 @@
 		if (driver->dci_tbl == NULL)
 			goto err;
 	}
+	if (driver->dci_notify_tbl == NULL) {
+		driver->dci_notify_tbl = kzalloc(MAX_DCI_CLIENT *
+			sizeof(struct dci_notification_tbl), GFP_KERNEL);
+		if (driver->dci_notify_tbl == NULL)
+			goto err;
+	}
 	if (driver->apps_dci_buf == NULL) {
 		driver->apps_dci_buf = kzalloc(APPS_BUF_SIZE, GFP_KERNEL);
 		if (driver->apps_dci_buf == NULL)
@@ -316,6 +342,7 @@
 err:
 	pr_err("diag: Could not initialize diag DCI buffers");
 	kfree(driver->dci_tbl);
+	kfree(driver->dci_notify_tbl);
 	kfree(driver->apps_dci_buf);
 	kfree(driver->buf_in_dci);
 	kfree(driver->write_ptr_dci);
@@ -328,6 +355,7 @@
 	driver->ch_dci = 0;
 	platform_driver_unregister(&msm_diag_dci_driver);
 	kfree(driver->dci_tbl);
+	kfree(driver->dci_notify_tbl);
 	kfree(driver->apps_dci_buf);
 	kfree(driver->buf_in_dci);
 	kfree(driver->write_ptr_dci);
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index cc6e0cf..c0b82df 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -22,6 +22,12 @@
 	int tag;
 };
 
+struct dci_notification_tbl {
+	struct task_struct *client;
+	uint16_t list; /* bit mask */
+	int signal_type;
+};
+
 #define DIAG_CON_APSS (0x0001)	/* Bit mask for APSS */
 #define DIAG_CON_MPSS (0x0002)	/* Bit mask for MPSS */
 #define DIAG_CON_LPASS (0x0004)	/* Bit mask for LPASS */
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 7e7b514..6a7b931 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -18,6 +18,7 @@
 #include <linux/mempool.h>
 #include <linux/mutex.h>
 #include <linux/workqueue.h>
+#include <linux/sched.h>
 #include <mach/msm_smd.h>
 #include <asm/atomic.h>
 #include <asm/mach-types.h>
@@ -139,6 +140,7 @@
 	int use_device_tree;
 	/* DCI related variables */
 	struct diag_dci_tbl *dci_tbl;
+	struct dci_notification_tbl *dci_notify_tbl;
 	int dci_tag;
 	int dci_client_id;
 	struct mutex dci_mutex;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index d6a6e66..547f42f 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -343,6 +343,7 @@
 	int success = -1;
 	void *temp_buf;
 	uint16_t support_list = 0;
+	struct dci_notification_tbl *notify_params;
 
 	if (iocmd == DIAG_IOCTL_COMMAND_REG) {
 		struct bindpkt_params_per_process *pkt_params =
@@ -413,13 +414,23 @@
 	} else if (iocmd == DIAG_IOCTL_DCI_REG) {
 		if (driver->dci_state == DIAG_DCI_NO_REG)
 			return DIAG_DCI_NO_REG;
-		/* use the 'list' later on to notify user space */
 		if (driver->num_dci_client >= MAX_DCI_CLIENT)
 			return DIAG_DCI_NO_REG;
+		notify_params = (struct dci_notification_tbl *) ioarg;
 		mutex_lock(&driver->dci_mutex);
 		driver->num_dci_client++;
 		pr_debug("diag: id = %d\n", driver->dci_client_id);
 		driver->dci_client_id++;
+		for (i = 0; i < MAX_DCI_CLIENT; i++) {
+			if (driver->dci_notify_tbl[i].client == NULL) {
+				driver->dci_notify_tbl[i].client = current;
+				driver->dci_notify_tbl[i].list =
+							 notify_params->list;
+				driver->dci_notify_tbl[i].signal_type =
+					 notify_params->signal_type;
+				break;
+			}
+		}
 		mutex_unlock(&driver->dci_mutex);
 		return driver->dci_client_id;
 	} else if (iocmd == DIAG_IOCTL_DCI_DEINIT) {
@@ -433,6 +444,12 @@
 				success = i;
 			}
 		}
+		for (i = 0; i < MAX_DCI_CLIENT; i++) {
+			if (driver->dci_notify_tbl[i].client == current) {
+				driver->dci_notify_tbl[i].client = NULL;
+				break;
+			}
+		}
 		/* if any registrations were deleted successfully OR a valid
 		   client_id was sent in DEINIT call , then its DCI client */
 		if (success >= 0 || ioarg)
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 83d65b1..69aa411 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -1016,7 +1016,7 @@
 					ENCODE_RSP_AND_SEND(8+rt_mask_size-1);
 					return 0;
 				}
-				ptr += MAX_SSID_PER_RANGE*4;
+				rt_mask_ptr += MAX_SSID_PER_RANGE*4;
 			}
 		} else
 			buf = temp;
diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c
index 6cd1806..dae64cb 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -174,6 +174,7 @@
 	unsigned long *start, unsigned long *len,
 	struct ion_handle **pihdl)
 {
+	int domain;
 	if (!msm_rotator_dev->client)
 		return -EINVAL;
 
@@ -185,8 +186,9 @@
 	pr_debug("%s(): ion_hdl %p, ion_buf %p\n", __func__, *pihdl,
 		ion_share(msm_rotator_dev->client, *pihdl));
 
+	domain = src ? ROTATOR_SRC_DOMAIN : ROTATOR_DST_DOMAIN;
 	if (ion_map_iommu(msm_rotator_dev->client,
-		*pihdl,	ROTATOR_DOMAIN, GEN_POOL,
+		*pihdl,	domain, GEN_POOL,
 		SZ_4K, 0, start, len, 0, ION_IOMMU_UNMAP_DELAYED)) {
 		pr_err("ion_map_iommu() failed\n");
 		return -EINVAL;
@@ -862,17 +864,21 @@
 
 }
 
-static void put_img(struct file *p_file, struct ion_handle *p_ihdl)
+static void put_img(struct file *p_file, struct ion_handle *p_ihdl,
+	unsigned char src)
 {
 #ifdef CONFIG_ANDROID_PMEM
 	if (p_file != NULL)
 		put_pmem_file(p_file);
 #endif
+
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 	if (!IS_ERR_OR_NULL(p_ihdl)) {
+		int domain = src ? ROTATOR_SRC_DOMAIN : \
+			ROTATOR_DST_DOMAIN;
 		pr_debug("%s(): p_ihdl %p\n", __func__, p_ihdl);
 		ion_unmap_iommu(msm_rotator_dev->client,
-			p_ihdl, ROTATOR_DOMAIN, GEN_POOL);
+			p_ihdl, domain, GEN_POOL);
 
 		ion_free(msm_rotator_dev->client, p_ihdl);
 	}
@@ -1162,15 +1168,15 @@
 #endif
 	schedule_delayed_work(&msm_rotator_dev->rot_clk_work, HZ);
 do_rotate_unlock_mutex:
-	put_img(dstp1_file, dstp1_ihdl);
-	put_img(srcp1_file, srcp1_ihdl);
-	put_img(dstp0_file, dstp0_ihdl);
+	put_img(dstp1_file, dstp1_ihdl, 0);
+	put_img(srcp1_file, srcp1_ihdl, 1);
+	put_img(dstp0_file, dstp0_ihdl, 0);
 
 	/* only source may use frame buffer */
 	if (info.src.flags & MDP_MEMORY_ID_TYPE_FB)
 		fput_light(srcp0_file, ps0_need);
 	else
-		put_img(srcp0_file, srcp0_ihdl);
+		put_img(srcp0_file, srcp0_ihdl, 1);
 	mutex_unlock(&msm_rotator_dev->rotator_lock);
 	dev_dbg(msm_rotator_dev->device, "%s() returning rc = %d\n",
 		__func__, rc);
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index fdff32e..826ba9a 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -122,7 +122,7 @@
 }
 EXPORT_SYMBOL(clkdev_add);
 
-void __init clkdev_add_table(struct clk_lookup *cl, size_t num)
+void clkdev_add_table(struct clk_lookup *cl, size_t num)
 {
 	mutex_lock(&clocks_mutex);
 	while (num--) {
diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c
index fb43562..bac9f8a 100644
--- a/drivers/gpio/gpio-msm-v2.c
+++ b/drivers/gpio/gpio-msm-v2.c
@@ -12,6 +12,7 @@
  */
 #include <linux/bitmap.h>
 #include <linux/bitops.h>
+#include <linux/delay.h>
 #include <linux/gpio.h>
 #include <linux/init.h>
 #include <linux/io.h>
@@ -147,14 +148,12 @@
 void __msm_gpio_set_intr_cfg_enable(unsigned gpio, unsigned val)
 {
 	if (val) {
-		set_gpio_bits(INTR_RAW_STATUS_EN | INTR_ENABLE,
-				GPIO_INTR_CFG(gpio));
+		set_gpio_bits(INTR_ENABLE, GPIO_INTR_CFG(gpio));
 		__raw_writel(TARGET_PROC_SCORPION, GPIO_INTR_CFG_SU(gpio));
 
 	} else {
 		__raw_writel(TARGET_PROC_NONE, GPIO_INTR_CFG_SU(gpio));
-		clr_gpio_bits(INTR_RAW_STATUS_EN | INTR_ENABLE,
-				GPIO_INTR_CFG(gpio));
+		clr_gpio_bits(INTR_ENABLE, GPIO_INTR_CFG(gpio));
 	}
 }
 
@@ -173,7 +172,23 @@
 	else
 		cfg &= ~INTR_POL_CTL_HI;
 
+	/* RAW_STATUS_EN is left on for all gpio irqs. Due to the
+	 * internal circuitry of TLMM, toggling the RAW_STATUS
+	 * could cause the INTR_STATUS to be set for EDGE interrupts.
+	 */
+	cfg |= INTR_RAW_STATUS_EN;
 	__raw_writel(cfg, GPIO_INTR_CFG(gpio));
+
+	/* Sometimes it might take a little while to update
+	 * the interrupt status after the RAW_STATUS is enabled
+	 */
+	udelay(5);
+
+	/* Clear the interrupt status to clear out any spurious
+	 * irq as a result of the above operation
+	 */
+	__msm_gpio_set_intr_status(gpio);
+
 }
 
 void __gpio_tlmm_config(unsigned config)
diff --git a/drivers/gpio/gpio-msm-v3.c b/drivers/gpio/gpio-msm-v3.c
index 49ad517..6086de3 100644
--- a/drivers/gpio/gpio-msm-v3.c
+++ b/drivers/gpio/gpio-msm-v3.c
@@ -12,6 +12,7 @@
  */
 #include <linux/bitmap.h>
 #include <linux/bitops.h>
+#include <linux/delay.h>
 #include <linux/gpio.h>
 #include <linux/init.h>
 #include <linux/io.h>
@@ -155,10 +156,9 @@
 	cfg = __raw_readl(GPIO_INTR_CFG(gpio));
 	if (val) {
 		cfg &= ~(INTR_TARGET_PROC_NONE | INTR_DIR_CONN_EN);
-		cfg |= INTR_RAW_STATUS_EN | INTR_ENABLE | INTR_TARGET_PROC_APPS;
+		cfg |= INTR_ENABLE | INTR_TARGET_PROC_APPS;
 	} else {
-		cfg &= ~(INTR_TARGET_PROC_APPS | INTR_RAW_STATUS_EN |
-			INTR_ENABLE);
+		cfg &= ~(INTR_TARGET_PROC_APPS | INTR_ENABLE);
 		cfg |= INTR_TARGET_PROC_NONE;
 	}
 	__raw_writel(cfg, GPIO_INTR_CFG(gpio));
@@ -184,7 +184,22 @@
 	else
 		cfg &= ~INTR_POL_CTL_HI;
 
+	/* RAW_STATUS_EN is left on for all gpio irqs. Due to the
+	 * internal circuitry of TLMM, toggling the RAW_STATUS
+	 * could cause the INTR_STATUS to be set for EDGE interrupts.
+	 */
+	cfg |= INTR_RAW_STATUS_EN;
 	__raw_writel(cfg, GPIO_INTR_CFG(gpio));
+
+	/* Sometimes it might take a little while to update
+	 * the interrupt status after the RAW_STATUS is enabled
+	 */
+	udelay(5);
+
+	/* Clear the interrupt status to clear out any spurious
+	 * irq as a result of the above operation
+	 */
+	__msm_gpio_set_intr_status(gpio);
 }
 
 void __gpio_tlmm_config(unsigned config)
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 7e84aa7..5c7ab3a 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -1898,7 +1898,8 @@
 	mutex_unlock(&dev->lock);
 }
 
-int ion_secure_heap(struct ion_device *dev, int heap_id)
+int ion_secure_heap(struct ion_device *dev, int heap_id, int version,
+			void *data)
 {
 	struct rb_node *n;
 	int ret_val = 0;
@@ -1915,7 +1916,7 @@
 		if (ION_HEAP(heap->id) != heap_id)
 			continue;
 		if (heap->ops->secure_heap)
-			ret_val = heap->ops->secure_heap(heap);
+			ret_val = heap->ops->secure_heap(heap, version, data);
 		else
 			ret_val = -EINVAL;
 		break;
@@ -1924,7 +1925,8 @@
 	return ret_val;
 }
 
-int ion_unsecure_heap(struct ion_device *dev, int heap_id)
+int ion_unsecure_heap(struct ion_device *dev, int heap_id, int version,
+			void *data)
 {
 	struct rb_node *n;
 	int ret_val = 0;
@@ -1941,7 +1943,7 @@
 		if (ION_HEAP(heap->id) != heap_id)
 			continue;
 		if (heap->ops->secure_heap)
-			ret_val = heap->ops->unsecure_heap(heap);
+			ret_val = heap->ops->unsecure_heap(heap, version, data);
 		else
 			ret_val = -EINVAL;
 		break;
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index a857988a..c5e9caf 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -40,6 +40,7 @@
 #include <asm/mach/map.h>
 #include <asm/cacheflush.h>
 
+#include "msm/ion_cp_common.h"
 /**
  * struct ion_cp_heap - container for the heap and shared heap data
 
@@ -97,6 +98,7 @@
 	int iommu_map_all;
 	int iommu_2x_map_domain;
 	unsigned int has_outer_cache;
+	atomic_t protect_cnt;
 };
 
 enum {
@@ -105,10 +107,12 @@
 };
 
 static int ion_cp_protect_mem(unsigned int phy_base, unsigned int size,
-			unsigned int permission_type);
+			unsigned int permission_type, int version,
+			void *data);
 
 static int ion_cp_unprotect_mem(unsigned int phy_base, unsigned int size,
-				unsigned int permission_type);
+				unsigned int permission_type, int version,
+				void *data);
 
 /**
  * Get the total number of kernel mappings.
@@ -125,13 +129,13 @@
  * the correct FMEM state if this heap is a reusable heap.
  * Must be called with heap->lock locked.
  */
-static int ion_cp_protect(struct ion_heap *heap)
+static int ion_cp_protect(struct ion_heap *heap, int version, void *data)
 {
 	struct ion_cp_heap *cp_heap =
 		container_of(heap, struct ion_cp_heap, heap);
 	int ret_value = 0;
 
-	if (cp_heap->heap_protected == HEAP_NOT_PROTECTED) {
+	if (atomic_inc_return(&cp_heap->protect_cnt) == 1) {
 		/* Make sure we are in C state when the heap is protected. */
 		if (cp_heap->reusable && !cp_heap->allocated_bytes) {
 			ret_value = fmem_set_state(FMEM_C_STATE);
@@ -140,7 +144,8 @@
 		}
 
 		ret_value = ion_cp_protect_mem(cp_heap->secure_base,
-				cp_heap->secure_size, cp_heap->permission_type);
+				cp_heap->secure_size, cp_heap->permission_type,
+				version, data);
 		if (ret_value) {
 			pr_err("Failed to protect memory for heap %s - "
 				"error code: %d\n", heap->name, ret_value);
@@ -150,6 +155,7 @@
 					pr_err("%s: unable to transition heap to T-state\n",
 						__func__);
 			}
+			atomic_dec(&cp_heap->protect_cnt);
 		} else {
 			cp_heap->heap_protected = HEAP_PROTECTED;
 			pr_debug("Protected heap %s @ 0x%lx\n",
@@ -157,6 +163,9 @@
 		}
 	}
 out:
+	pr_debug("%s: protect count is %d\n", __func__,
+		atomic_read(&cp_heap->protect_cnt));
+	BUG_ON(atomic_read(&cp_heap->protect_cnt) < 0);
 	return ret_value;
 }
 
@@ -165,15 +174,15 @@
  * the correct FMEM state if this heap is a reusable heap.
  * Must be called with heap->lock locked.
  */
-static void ion_cp_unprotect(struct ion_heap *heap)
+static void ion_cp_unprotect(struct ion_heap *heap, int version, void *data)
 {
 	struct ion_cp_heap *cp_heap =
 		container_of(heap, struct ion_cp_heap, heap);
 
-	if (cp_heap->heap_protected == HEAP_PROTECTED) {
+	if (atomic_dec_and_test(&cp_heap->protect_cnt)) {
 		int error_code = ion_cp_unprotect_mem(
 			cp_heap->secure_base, cp_heap->secure_size,
-			cp_heap->permission_type);
+			cp_heap->permission_type, version, data);
 		if (error_code) {
 			pr_err("Failed to un-protect memory for heap %s - "
 				"error code: %d\n", heap->name, error_code);
@@ -189,6 +198,9 @@
 			}
 		}
 	}
+	pr_debug("%s: protect count is %d\n", __func__,
+		atomic_read(&cp_heap->protect_cnt));
+	BUG_ON(atomic_read(&cp_heap->protect_cnt) < 0);
 }
 
 ion_phys_addr_t ion_cp_allocate(struct ion_heap *heap,
@@ -641,14 +653,14 @@
 	return 0;
 }
 
-int ion_cp_secure_heap(struct ion_heap *heap)
+int ion_cp_secure_heap(struct ion_heap *heap, int version, void *data)
 {
 	int ret_value;
 	struct ion_cp_heap *cp_heap =
 		container_of(heap, struct ion_cp_heap, heap);
 	mutex_lock(&cp_heap->lock);
 	if (cp_heap->umap_count == 0 && cp_heap->kmap_cached_count == 0) {
-		ret_value = ion_cp_protect(heap);
+		ret_value = ion_cp_protect(heap, version, data);
 	} else {
 		pr_err("ION cannot secure heap with outstanding mappings: "
 		       "User space: %lu, kernel space (cached): %lu\n",
@@ -660,13 +672,13 @@
 	return ret_value;
 }
 
-int ion_cp_unsecure_heap(struct ion_heap *heap)
+int ion_cp_unsecure_heap(struct ion_heap *heap, int version, void *data)
 {
 	int ret_value = 0;
 	struct ion_cp_heap *cp_heap =
 		container_of(heap, struct ion_cp_heap, heap);
 	mutex_lock(&cp_heap->lock);
-	ion_cp_unprotect(heap);
+	ion_cp_unprotect(heap, version, data);
 	mutex_unlock(&cp_heap->lock);
 	return ret_value;
 }
@@ -925,6 +937,7 @@
 	cp_heap->secure_base = cp_heap->base;
 	cp_heap->secure_size = heap_data->size;
 	cp_heap->has_outer_cache = heap_data->has_outer_cache;
+	atomic_set(&cp_heap->protect_cnt, 0);
 	if (heap_data->extra_data) {
 		struct ion_cp_heap_pdata *extra_data =
 				heap_data->extra_data;
@@ -991,8 +1004,7 @@
 	unsigned char lock;
 } __attribute__ ((__packed__));
 
-
-static int ion_cp_protect_mem(unsigned int phy_base, unsigned int size,
+static int ion_cp_protect_mem_v1(unsigned int phy_base, unsigned int size,
 			      unsigned int permission_type)
 {
 	struct cp_lock_msg cmd;
@@ -1005,7 +1017,7 @@
 			&cmd, sizeof(cmd), NULL, 0);
 }
 
-static int ion_cp_unprotect_mem(unsigned int phy_base, unsigned int size,
+static int ion_cp_unprotect_mem_v1(unsigned int phy_base, unsigned int size,
 				unsigned int permission_type)
 {
 	struct cp_lock_msg cmd;
@@ -1017,3 +1029,70 @@
 	return scm_call(SCM_SVC_CP, SCM_CP_LOCK_CMD_ID,
 			&cmd, sizeof(cmd), NULL, 0);
 }
+
+#define V2_CHUNK_SIZE	SZ_1M
+
+static int ion_cp_change_mem_v2(unsigned int phy_base, unsigned int size,
+			      void *data, int lock)
+{
+	enum cp_mem_usage usage = (enum cp_mem_usage) data;
+	unsigned long *chunk_list;
+	int nchunks;
+	int ret;
+	int i;
+
+	if (usage < 0 || usage >= MAX_USAGE)
+		return -EINVAL;
+
+	if (!IS_ALIGNED(size, V2_CHUNK_SIZE)) {
+		pr_err("%s: heap size is not aligned to %x\n",
+			__func__, V2_CHUNK_SIZE);
+		return -EINVAL;
+	}
+
+	nchunks = size / V2_CHUNK_SIZE;
+
+	chunk_list = allocate_contiguous_ebi(sizeof(unsigned long)*nchunks,
+						SZ_4K, 0);
+	if (!chunk_list)
+		return -ENOMEM;
+
+	for (i = 0; i < nchunks; i++)
+		chunk_list[i] = phy_base + i * V2_CHUNK_SIZE;
+
+	ret = ion_cp_change_chunks_state(memory_pool_node_paddr(chunk_list),
+					nchunks, V2_CHUNK_SIZE, usage, lock);
+
+	free_contiguous_memory(chunk_list);
+	return ret;
+}
+
+static int ion_cp_protect_mem(unsigned int phy_base, unsigned int size,
+			      unsigned int permission_type, int version,
+			      void *data)
+{
+	switch (version) {
+	case ION_CP_V1:
+		return ion_cp_protect_mem_v1(phy_base, size, permission_type);
+	case ION_CP_V2:
+		return ion_cp_change_mem_v2(phy_base, size, data,
+						SCM_CP_PROTECT);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int ion_cp_unprotect_mem(unsigned int phy_base, unsigned int size,
+			      unsigned int permission_type, int version,
+			      void *data)
+{
+	switch (version) {
+	case ION_CP_V1:
+		return ion_cp_unprotect_mem_v1(phy_base, size, permission_type);
+	case ION_CP_V2:
+		return ion_cp_change_mem_v2(phy_base, size, data,
+						SCM_CP_UNPROTECT);
+	default:
+		return -EINVAL;
+	}
+}
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index 621144b..9ea6f2b 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -196,7 +196,7 @@
 						data->mapped_size, align,
 						&data->iova_addr);
 
-	if (!data->iova_addr)
+	if (ret)
 		goto out;
 
 	domain = msm_get_iommu_domain(domain_num);
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 6d636ee..6940e2f 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -158,8 +158,8 @@
 	void (*unmap_iommu)(struct ion_iommu_map *data);
 	int (*print_debug)(struct ion_heap *heap, struct seq_file *s,
 			   const struct rb_root *mem_map);
-	int (*secure_heap)(struct ion_heap *heap);
-	int (*unsecure_heap)(struct ion_heap *heap);
+	int (*secure_heap)(struct ion_heap *heap, int version, void *data);
+	int (*unsecure_heap)(struct ion_heap *heap, int version, void *data);
 };
 
 /**
diff --git a/drivers/gpu/ion/msm/Makefile b/drivers/gpu/ion/msm/Makefile
index bedd8d2..1893405 100644
--- a/drivers/gpu/ion/msm/Makefile
+++ b/drivers/gpu/ion/msm/Makefile
@@ -1 +1 @@
-obj-y += msm_ion.o
+obj-y += msm_ion.o ion_cp_common.o
diff --git a/drivers/gpu/ion/msm/ion_cp_common.c b/drivers/gpu/ion/msm/ion_cp_common.c
new file mode 100644
index 0000000..b274ba2
--- /dev/null
+++ b/drivers/gpu/ion/msm/ion_cp_common.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011 Google, Inc
+ * 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
+ * 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/types.h>
+#include <mach/scm.h>
+
+#include "ion_cp_common.h"
+
+#define MEM_PROTECT_LOCK_ID	0x05
+
+struct cp2_mem_chunks {
+	unsigned int *chunk_list;
+	unsigned int chunk_list_size;
+	unsigned int chunk_size;
+} __attribute__ ((__packed__));
+
+struct cp2_lock_req {
+	struct cp2_mem_chunks chunks;
+	unsigned int mem_usage;
+	unsigned int lock;
+} __attribute__ ((__packed__));
+
+int ion_cp_change_chunks_state(unsigned long chunks, unsigned int nchunks,
+				unsigned int chunk_size,
+				enum cp_mem_usage usage,
+				int lock)
+{
+	struct cp2_lock_req request;
+
+	request.mem_usage = usage;
+	request.lock = lock;
+
+	request.chunks.chunk_list = (unsigned int *)chunks;
+	request.chunks.chunk_list_size = nchunks;
+	request.chunks.chunk_size = chunk_size;
+
+	return scm_call(SCM_SVC_CP, MEM_PROTECT_LOCK_ID,
+			&request, sizeof(request), NULL, 0);
+
+}
+
diff --git a/drivers/gpu/ion/msm/ion_cp_common.h b/drivers/gpu/ion/msm/ion_cp_common.h
new file mode 100644
index 0000000..69dd19e
--- /dev/null
+++ b/drivers/gpu/ion/msm/ion_cp_common.h
@@ -0,0 +1,49 @@
+/*
+ * 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 ION_CP_COMMON_H
+#define ION_CP_COMMON_H
+
+#include <asm-generic/errno-base.h>
+#include <linux/ion.h>
+
+#define ION_CP_V1	1
+#define ION_CP_V2	2
+
+#if defined(CONFIG_ION_MSM)
+/*
+ * ion_cp2_protect_mem - secures memory via trustzone
+ *
+ * @chunks - physical address of the array containing the chunks to
+ *		be locked down
+ * @nchunks - number of entries in the array
+ * @chunk_size - size of each memory chunk
+ * @usage - usage hint
+ * @lock - 1 for lock, 0 for unlock
+ *
+ * return value is the result of the scm call
+ */
+int ion_cp_change_chunks_state(unsigned long chunks, unsigned int nchunks,
+			unsigned int chunk_size, enum cp_mem_usage usage,
+			int lock);
+
+#else
+static inline int ion_cp_change_chunks_state(unsigned long chunks,
+			unsigned int nchunks, unsigned int chunk_size,
+			enum cp_mem_usage usage, int lock)
+{
+	return -ENODEV;
+}
+#endif
+
+#endif
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index f6a4cf4..eec3fe0 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -21,6 +21,7 @@
 #include <mach/ion.h>
 #include <mach/msm_memtypes.h>
 #include "../ion_priv.h"
+#include "ion_cp_common.h"
 
 static struct ion_device *idev;
 static int num_heaps;
@@ -35,16 +36,28 @@
 
 int msm_ion_secure_heap(int heap_id)
 {
-	return ion_secure_heap(idev, heap_id);
+	return ion_secure_heap(idev, heap_id, ION_CP_V1, NULL);
 }
 EXPORT_SYMBOL(msm_ion_secure_heap);
 
 int msm_ion_unsecure_heap(int heap_id)
 {
-	return ion_unsecure_heap(idev, heap_id);
+	return ion_unsecure_heap(idev, heap_id, ION_CP_V1, NULL);
 }
 EXPORT_SYMBOL(msm_ion_unsecure_heap);
 
+int msm_ion_secure_heap_2_0(int heap_id, enum cp_mem_usage usage)
+{
+	return ion_secure_heap(idev, heap_id, ION_CP_V2, (void *)usage);
+}
+EXPORT_SYMBOL(msm_ion_secure_heap_2_0);
+
+int msm_ion_unsecure_heap_2_0(int heap_id, enum cp_mem_usage usage)
+{
+	return ion_unsecure_heap(idev, heap_id, ION_CP_V2, (void *)usage);
+}
+EXPORT_SYMBOL(msm_ion_unsecure_heap_2_0);
+
 int msm_ion_do_cache_op(struct ion_client *client, struct ion_handle *handle,
 			void *vaddr, unsigned long len, unsigned int cmd)
 {
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 0a71982..bd58b4e 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -46,6 +46,7 @@
 #define A3XX_RBBM_HW_VERSION 0x000
 #define A3XX_RBBM_HW_RELEASE 0x001
 #define A3XX_RBBM_HW_CONFIGURATION 0x002
+#define A3XX_RBBM_CLOCK_CTL 0x010
 #define A3XX_RBBM_SP_HYST_CNT 0x012
 #define A3XX_RBBM_SW_RESET_CMD 0x018
 #define A3XX_RBBM_AHB_CTL0 0x020
@@ -507,4 +508,7 @@
 #define RBBM_BLOCK_ID_MARB_2           0x2a
 #define RBBM_BLOCK_ID_MARB_3           0x2b
 
+/* RBBM_CLOCK_CTL default value */
+#define A3XX_RBBM_CLOCK_CTL_DEFAULT 0x00000000
+
 #endif
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 3de3af9..f5cb888 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -267,7 +267,7 @@
 				KGSL_IOMMU_CONTEXT_USER))
 		goto done;
 
-	if (adreno_is_a225(adreno_dev))
+	if (cpu_is_msm8960())
 		cmds += adreno_add_change_mh_phys_limit_cmds(cmds, 0xFFFFF000,
 					device->mmu.setstate_memory.gpuaddr +
 					KGSL_IOMMU_SETSTATE_NOP_OFFSET);
@@ -362,7 +362,7 @@
 		}
 	}
 
-	if (adreno_is_a225(adreno_dev))
+	if (cpu_is_msm8960())
 		cmds += adreno_add_change_mh_phys_limit_cmds(cmds,
 			reg_map_desc[num_iommu_units - 1]->gpuaddr - PAGE_SIZE,
 			device->mmu.setstate_memory.gpuaddr +
@@ -1592,10 +1592,17 @@
 	adreno_dev->gpudev->irq_control(adreno_dev, state);
 }
 
-static unsigned int adreno_gpuid(struct kgsl_device *device)
+static unsigned int adreno_gpuid(struct kgsl_device *device,
+	unsigned int *chipid)
 {
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 
+	/* Some applications need to know the chip ID too, so pass
+	 * that as a parameter */
+
+	if (chipid != NULL)
+		*chipid = adreno_dev->chip_id;
+
 	/* Standard KGSL gpuid format:
 	 * top word is 0x0002 for 2D or 0x0003 for 3D
 	 * Bottom word is core specific identifer
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index c3c266e..d846d3d 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1450,43 +1450,55 @@
 	return ret;
 }
 
-static void a2xx_drawctxt_draw_workaround(struct adreno_device *adreno_dev)
+static void a2xx_drawctxt_workaround(struct adreno_device *adreno_dev)
 {
 	struct kgsl_device *device = &adreno_dev->dev;
 	unsigned int cmd[11];
 	unsigned int *cmds = &cmd[0];
 
-	adreno_dev->gpudev->ctx_switches_since_last_draw++;
-	/* If there have been > than ADRENO_NUM_CTX_SWITCH_ALLOWED_BEFORE_DRAW
-	 * calls to context switches w/o gmem being saved then we need to
-	 * execute this workaround */
-	if (adreno_dev->gpudev->ctx_switches_since_last_draw >
-		ADRENO_NUM_CTX_SWITCH_ALLOWED_BEFORE_DRAW)
-		adreno_dev->gpudev->ctx_switches_since_last_draw = 0;
-	else
-		return;
-	/*
-	 * Issue an empty draw call to avoid possible hangs due to
-	 * repeated idles without intervening draw calls.
-	 * On adreno 225 the PC block has a cache that is only
-	 * flushed on draw calls and repeated idles can make it
-	 * overflow. The gmem save path contains draw calls so
-	 * this workaround isn't needed there.
-	 */
-	*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
-	*cmds++ = (0x4 << 16) | (REG_PA_SU_SC_MODE_CNTL - 0x2000);
-	*cmds++ = 0;
-	*cmds++ = cp_type3_packet(CP_DRAW_INDX, 5);
-	*cmds++ = 0;
-	*cmds++ = 1<<14;
-	*cmds++ = 0;
-	*cmds++ = device->mmu.setstate_memory.gpuaddr;
-	*cmds++ = 0;
-	*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
-	*cmds++ = 0x00000000;
+	if (adreno_is_a225(adreno_dev)) {
+		adreno_dev->gpudev->ctx_switches_since_last_draw++;
+		/* If there have been > than
+		 * ADRENO_NUM_CTX_SWITCH_ALLOWED_BEFORE_DRAW calls to context
+		 * switches w/o gmem being saved then we need to execute
+		 * this workaround */
+		if (adreno_dev->gpudev->ctx_switches_since_last_draw >
+				ADRENO_NUM_CTX_SWITCH_ALLOWED_BEFORE_DRAW)
+			adreno_dev->gpudev->ctx_switches_since_last_draw = 0;
+		else
+			return;
+		/*
+		 * Issue an empty draw call to avoid possible hangs due to
+		 * repeated idles without intervening draw calls.
+		 * On adreno 225 the PC block has a cache that is only
+		 * flushed on draw calls and repeated idles can make it
+		 * overflow. The gmem save path contains draw calls so
+		 * this workaround isn't needed there.
+		 */
+		*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
+		*cmds++ = (0x4 << 16) | (REG_PA_SU_SC_MODE_CNTL - 0x2000);
+		*cmds++ = 0;
+		*cmds++ = cp_type3_packet(CP_DRAW_INDX, 5);
+		*cmds++ = 0;
+		*cmds++ = 1<<14;
+		*cmds++ = 0;
+		*cmds++ = device->mmu.setstate_memory.gpuaddr;
+		*cmds++ = 0;
+		*cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+		*cmds++ = 0x00000000;
+	} else {
+		/* On Adreno 20x/220, if the events for shader space reuse
+		 * gets dropped, the CP block would wait indefinitely.
+		 * Sending CP_SET_SHADER_BASES packet unblocks the CP from
+		 * this wait.
+		 */
+		*cmds++ = cp_type3_packet(CP_SET_SHADER_BASES, 1);
+		*cmds++ = adreno_encode_istore_size(adreno_dev)
+					| adreno_dev->pix_shader_start;
+	}
 
 	adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_PMODE,
-				    &cmd[0], 11);
+			&cmd[0], cmds - cmd);
 }
 
 static void a2xx_drawctxt_save(struct adreno_device *adreno_dev,
@@ -1540,8 +1552,8 @@
 		adreno_dev->gpudev->ctx_switches_since_last_draw = 0;
 
 		context->flags |= CTXT_FLAGS_GMEM_RESTORE;
-	} else if (adreno_is_a225(adreno_dev))
-		a2xx_drawctxt_draw_workaround(adreno_dev);
+	} else if (adreno_is_a2xx(adreno_dev))
+		a2xx_drawctxt_workaround(adreno_dev);
 }
 
 static void a2xx_drawctxt_restore(struct adreno_device *adreno_dev,
@@ -1999,7 +2011,7 @@
 	.ctxt_create = a2xx_drawctxt_create,
 	.ctxt_save = a2xx_drawctxt_save,
 	.ctxt_restore = a2xx_drawctxt_restore,
-	.ctxt_draw_workaround = a2xx_drawctxt_draw_workaround,
+	.ctxt_draw_workaround = a2xx_drawctxt_workaround,
 	.irq_handler = a2xx_irq_handler,
 	.irq_control = a2xx_irq_control,
 	.snapshot = a2xx_snapshot,
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index e258072..58a0963 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -433,6 +433,9 @@
 	unsigned int *cmds = tmp_ctx.cmd;
 	unsigned int *start = cmds;
 
+	*cmds++ = cp_type0_packet(A3XX_RBBM_CLOCK_CTL, 1);
+	*cmds++ = A3XX_RBBM_CLOCK_CTL_DEFAULT;
+
 	*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 3);
 	*cmds++ = CP_REG(A3XX_RB_MODE_CONTROL);
 
@@ -1162,6 +1165,9 @@
 	unsigned int *cmds = tmp_ctx.cmd;
 	unsigned int *start = cmds;
 
+	*cmds++ = cp_type0_packet(A3XX_RBBM_CLOCK_CTL, 1);
+	*cmds++ = A3XX_RBBM_CLOCK_CTL_DEFAULT;
+
 	*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 5);
 	*cmds++ = CP_REG(A3XX_HLSQ_CONTROL_0_REG);
 	/* HLSQ_CONTROL_0_REG */
diff --git a/drivers/gpu/msm/adreno_a3xx_snapshot.c b/drivers/gpu/msm/adreno_a3xx_snapshot.c
index c8c7c44..60aab64 100644
--- a/drivers/gpu/msm/adreno_a3xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a3xx_snapshot.c
@@ -19,6 +19,29 @@
 #define DEBUG_SECTION_SZ(_dwords) (((_dwords) * sizeof(unsigned int)) \
 		+ sizeof(struct kgsl_snapshot_debug))
 
+#define SHADER_MEMORY_SIZE 0x4000
+
+static int a3xx_snapshot_shader_memory(struct kgsl_device *device,
+	void *snapshot, int remain, void *priv)
+{
+	struct kgsl_snapshot_debug *header = snapshot;
+	unsigned int *data = snapshot + sizeof(*header);
+	int i;
+
+	if (remain < DEBUG_SECTION_SZ(SHADER_MEMORY_SIZE)) {
+		SNAPSHOT_ERR_NOMEM(device, "SHADER MEMORY");
+		return 0;
+	}
+
+	header->type = SNAPSHOT_DEBUG_SHADER_MEMORY;
+	header->size = SHADER_MEMORY_SIZE;
+
+	for (i = 0; i < SHADER_MEMORY_SIZE; i++)
+		adreno_regread(device, 0x4000 + i, &data[i]);
+
+	return DEBUG_SECTION_SZ(SHADER_MEMORY_SIZE);
+}
+
 #define VPC_MEMORY_BANKS 4
 #define VPC_MEMORY_SIZE 512
 
@@ -272,6 +295,12 @@
 			KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
 			a3xx_snapshot_cp_meq, NULL);
 
+	/* Shader working/shadow memory */
+	snapshot = kgsl_snapshot_add_section(device,
+			KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
+			a3xx_snapshot_shader_memory, NULL);
+
+
 	/* CP PFP and PM4 */
 	/* Reading these will hang the GPU if it isn't already hung */
 
diff --git a/drivers/gpu/msm/adreno_pm4types.h b/drivers/gpu/msm/adreno_pm4types.h
index fb44b25..016862b 100644
--- a/drivers/gpu/msm/adreno_pm4types.h
+++ b/drivers/gpu/msm/adreno_pm4types.h
@@ -203,7 +203,14 @@
 #define type0_pkt_size(pkt) ((((pkt) >> 16) & 0x3FFF) + 1)
 #define type0_pkt_offset(pkt) ((pkt) & 0x7FFF)
 
-#define pkt_is_type3(pkt) (((pkt) & 0xC0000000) == CP_TYPE3_PKT)
+/*
+ * Check both for the type3 opcode and make sure that the reserved bits [1:7]
+ * and 15 are 0
+ */
+
+#define pkt_is_type3(pkt) \
+	((((pkt) & 0xC0000000) == CP_TYPE3_PKT) && \
+	 (((pkt) & 0x80FE) == 0))
 
 #define cp_type3_opcode(pkt) (((pkt) >> 8) & 0xFF)
 #define type3_pkt_size(pkt) ((((pkt) >> 16) & 0x3FFF) + 1)
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index 5572695..08a01b0 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -161,6 +161,22 @@
 static unsigned int sp_vs_pvt_mem_addr;
 static unsigned int sp_fs_pvt_mem_addr;
 
+/*
+ * Each load state block has two possible types.  Each type has a different
+ * number of dwords per unit.  Use this handy lookup table to make sure
+ * we dump the right amount of data from the indirect buffer
+ */
+
+static int load_state_unit_sizes[7][2] = {
+	{ 2, 4 },
+	{ 0, 1 },
+	{ 2, 4 },
+	{ 0, 1 },
+	{ 8, 2 },
+	{ 8, 2 },
+	{ 8, 2 },
+};
+
 static void ib_parse_load_state(struct kgsl_device *device, unsigned int *pkt,
 	unsigned int ptbase)
 {
@@ -170,11 +186,9 @@
 	 * The object here is to find indirect shaders i.e - shaders loaded from
 	 * GPU memory instead of directly in the command.  These should be added
 	 * to the list of memory objects to dump. So look at the load state
-	 * call and see if 1) the shader block is a shader (block = 4, 5 or 6)
-	 * 2) that the block is indirect (source = 4). If these all match then
-	 * add the memory address to the list.  The size of the object will
-	 * differ depending on the type.  Type 0 (instructions) are 8 dwords per
-	 * unit and type 1 (constants) are 2 dwords per unit.
+	 * if the block is indirect (source = 4). If so then add the memory
+	 * address to the list.  The size of the object differs depending on the
+	 * type per the load_state_unit_sizes array above.
 	 */
 
 	if (type3_pkt_size(pkt[0]) < 2)
@@ -192,9 +206,13 @@
 	source = (pkt[1] >> 16) & 0x07;
 	type = pkt[2] & 0x03;
 
-	if ((block == 4 || block == 5 || block == 6) && source == 4) {
-		int unitsize = (type == 0) ? 8 : 2;
-		int ret;
+	if (source == 4) {
+		int unitsize, ret;
+
+		if (type == 0)
+			unitsize = load_state_unit_sizes[block][0];
+		else
+			unitsize = load_state_unit_sizes[block][1];
 
 		/* Freeze the GPU buffer containing the shader */
 
@@ -528,7 +546,6 @@
 	unsigned int ptbase, rptr, *rbptr, ibbase;
 	int index, size, i;
 	int parse_ibs = 0, ib_parse_start;
-	int skip_pktsize = 1;
 
 	/* Get the physical address of the MMU pagetable */
 	ptbase = kgsl_mmu_get_current_ptbase(&device->mmu);
@@ -541,13 +558,14 @@
 
 	/*
 	 * Figure out the window of ringbuffer data to dump.  First we need to
-	 * find where the last processed IB ws submitted
+	 * find where the last processed IB ws submitted.  Start walking back
+	 * from the rptr
 	 */
 
 	index = rptr;
 	rbptr = rb->buffer_desc.hostptr;
 
-	while (index != rb->wptr) {
+	do {
 		index--;
 
 		if (index < 0) {
@@ -563,7 +581,7 @@
 		if (adreno_cmd_is_ib(rbptr[index]) &&
 			rbptr[index + 1] == ibbase)
 			break;
-	}
+	} while (index != rb->wptr);
 
 	/*
 	 * index points at the last submitted IB. We can only trust that the
@@ -636,18 +654,15 @@
 		 * try to adust for that by modifying the rptr to match a
 		 * packet boundary. Unfortunately for us, it is hard to tell
 		 * which dwords are legitimate type0 header and which are just
-		 * random data so just walk over type0 packets until we get
-		 * to the first type3, and from that point on start checking the
-		 * size of the packet and adjusting accordingly
+		 * random data so only do the adjustments for type3 packets
 		 */
 
-		if (skip_pktsize && pkt_is_type3(rbptr[index]))
-			skip_pktsize = 0;
-
-		if (skip_pktsize == 0) {
-			unsigned int pktsize = type3_pkt_size(rbptr[index]);
+		if (pkt_is_type3(rbptr[index])) {
+			unsigned int pktsize =
+				type3_pkt_size(rbptr[index]);
 			if (index +  pktsize > rptr)
-				rptr = (index + pktsize) % rb->sizedwords;
+				rptr = (index + pktsize) %
+					rb->sizedwords;
 		}
 
 		/*
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 81de64f..5883f08 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2598,9 +2598,17 @@
 	kgsl_drm_exit();
 	kgsl_cffdump_destroy();
 	kgsl_core_debugfs_close();
-	kgsl_sharedmem_uninit_sysfs();
 
-	device_unregister(&kgsl_driver.virtdev);
+	/*
+	 * We call kgsl_sharedmem_uninit_sysfs() and device_unregister()
+	 * only if kgsl_driver.virtdev has been populated.
+	 * We check at least one member of kgsl_driver.virtdev to
+	 * see if it is not NULL (and thus, has been populated).
+	 */
+	if (kgsl_driver.virtdev.class) {
+		kgsl_sharedmem_uninit_sysfs();
+		device_unregister(&kgsl_driver.virtdev);
+	}
 
 	if (kgsl_driver.class) {
 		class_destroy(kgsl_driver.class);
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 64acff8..932c995 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -90,7 +90,7 @@
 	void (*power_stats)(struct kgsl_device *device,
 		struct kgsl_power_stats *stats);
 	void (*irqctrl)(struct kgsl_device *device, int state);
-	unsigned int (*gpuid)(struct kgsl_device *device);
+	unsigned int (*gpuid)(struct kgsl_device *device, unsigned int *chipid);
 	void * (*snapshot)(struct kgsl_device *device, void *snapshot,
 		int *remain, int hang);
 	irqreturn_t (*irq_handler)(struct kgsl_device *device);
@@ -287,9 +287,10 @@
 	return device->ftbl->idle(device, timeout);
 }
 
-static inline unsigned int kgsl_gpuid(struct kgsl_device *device)
+static inline unsigned int kgsl_gpuid(struct kgsl_device *device,
+	unsigned int *chipid)
 {
-	return device->ftbl->gpuid(device);
+	return device->ftbl->gpuid(device, chipid);
 }
 
 static inline unsigned int kgsl_readtimestamp(struct kgsl_device *device,
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index b3f2d1e..d20cf7e 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -17,6 +17,7 @@
 #include <linux/slab.h>
 #include <linux/iommu.h>
 #include <linux/msm_kgsl.h>
+#include <mach/socinfo.h>
 
 #include "kgsl.h"
 #include "kgsl_device.h"
@@ -268,14 +269,17 @@
 	struct kgsl_iommu *iommu = mmu->priv;
 	int i, j;
 
-	BUG_ON(mmu->hwpagetable == NULL);
-	BUG_ON(mmu->hwpagetable->priv == NULL);
-
-	iommu_pt = mmu->hwpagetable->priv;
-
 	for (i = 0; i < iommu->unit_count; i++) {
 		struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
+		iommu_pt = mmu->defaultpagetable->priv;
 		for (j = 0; j < iommu_unit->dev_count; j++) {
+			/*
+			 * If there is a 2nd default pagetable then priv domain
+			 * is attached with this pagetable
+			 */
+			if (mmu->priv_bank_table &&
+				(KGSL_IOMMU_CONTEXT_PRIV == j))
+				iommu_pt = mmu->priv_bank_table->priv;
 			if (iommu_unit->dev[j].attached) {
 				iommu_detach_device(iommu_pt->domain,
 						iommu_unit->dev[j].dev);
@@ -307,18 +311,21 @@
 	struct kgsl_iommu *iommu = mmu->priv;
 	int i, j, ret = 0;
 
-	BUG_ON(mmu->hwpagetable == NULL);
-	BUG_ON(mmu->hwpagetable->priv == NULL);
-
-	iommu_pt = mmu->hwpagetable->priv;
-
 	/*
 	 * Loop through all the iommu devcies under all iommu units and
 	 * attach the domain
 	 */
 	for (i = 0; i < iommu->unit_count; i++) {
 		struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
+		iommu_pt = mmu->defaultpagetable->priv;
 		for (j = 0; j < iommu_unit->dev_count; j++) {
+			/*
+			 * If there is a 2nd default pagetable then priv domain
+			 * is attached to this pagetable
+			 */
+			if (mmu->priv_bank_table &&
+				(KGSL_IOMMU_CONTEXT_PRIV == j))
+				iommu_pt = mmu->priv_bank_table->priv;
 			if (!iommu_unit->dev[j].attached) {
 				ret = iommu_attach_device(iommu_pt->domain,
 							iommu_unit->dev[j].dev);
@@ -614,17 +621,32 @@
 	int i = 0;
 	struct kgsl_iommu *iommu = mmu->priv;
 	struct kgsl_iommu_pt *iommu_pt;
+	struct kgsl_pagetable *pagetable = NULL;
 
+	/* If chip is not 8960 then we use the 2nd context bank for pagetable
+	 * switching on the 3D side for which a separate table is allocated */
+	if (!cpu_is_msm8960()) {
+		mmu->priv_bank_table =
+			kgsl_mmu_getpagetable(KGSL_MMU_PRIV_BANK_TABLE_NAME);
+		if (mmu->priv_bank_table == NULL) {
+			status = -ENOMEM;
+			goto err;
+		}
+		iommu_pt = mmu->priv_bank_table->priv;
+		iommu_pt->asid = 1;
+	}
 	mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
 	/* Return error if the default pagetable doesn't exist */
 	if (mmu->defaultpagetable == NULL) {
 		status = -ENOMEM;
 		goto err;
 	}
+	pagetable = mmu->priv_bank_table ? mmu->priv_bank_table :
+				mmu->defaultpagetable;
 	/* Map the IOMMU regsiters to only defaultpagetable */
 	for (i = 0; i < iommu->unit_count; i++) {
 		iommu->iommu_units[i].reg_map.priv |= KGSL_MEMFLAGS_GLOBAL;
-		status = kgsl_mmu_map(mmu->defaultpagetable,
+		status = kgsl_mmu_map(pagetable,
 			&(iommu->iommu_units[i].reg_map),
 			GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
 		if (status) {
@@ -644,10 +666,14 @@
 	return status;
 err:
 	for (i--; i >= 0; i--) {
-		kgsl_mmu_unmap(mmu->defaultpagetable,
+		kgsl_mmu_unmap(pagetable,
 				&(iommu->iommu_units[i].reg_map));
 		iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMFLAGS_GLOBAL;
 	}
+	if (mmu->priv_bank_table) {
+		kgsl_mmu_putpagetable(mmu->priv_bank_table);
+		mmu->priv_bank_table = NULL;
+	}
 	if (mmu->defaultpagetable) {
 		kgsl_mmu_putpagetable(mmu->defaultpagetable);
 		mmu->defaultpagetable = NULL;
@@ -669,9 +695,9 @@
 		if (status)
 			return -ENOMEM;
 	}
-	/* We use the GPU MMU to control access to IOMMU registers on a225,
-	 * hence we still keep the MMU active on a225 */
-	if (adreno_is_a225(ADRENO_DEVICE(mmu->device))) {
+	/* We use the GPU MMU to control access to IOMMU registers on 8960 with
+	 * a225, hence we still keep the MMU active on 8960 */
+	if (cpu_is_msm8960()) {
 		struct kgsl_mh *mh = &(mmu->device->mh);
 		kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000001);
 		kgsl_regwrite(mmu->device, MH_MMU_MPU_END,
@@ -707,6 +733,12 @@
 	 */
 	for (i = 0; i < iommu->unit_count; i++) {
 		struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
+		/* Make sure that the ASID of the priv bank is set to 1.
+		 * When we a different pagetable for the priv bank then the
+		 * iommu driver sets the ASID to 0 instead of 1 */
+		KGSL_IOMMU_SET_IOMMU_REG(iommu->iommu_units[i].reg_map.hostptr,
+					KGSL_IOMMU_CONTEXT_PRIV,
+					CONTEXTIDR, 1);
 		for (j = 0; j < iommu_unit->dev_count; j++)
 			iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(
 						KGSL_IOMMU_GET_IOMMU_REG(
@@ -816,14 +848,19 @@
 	struct kgsl_iommu *iommu = mmu->priv;
 	int i;
 	for (i = 0; i < iommu->unit_count; i++) {
+		struct kgsl_pagetable *pagetable = (mmu->priv_bank_table ?
+			mmu->priv_bank_table : mmu->defaultpagetable);
 		if (iommu->iommu_units[i].reg_map.gpuaddr)
-			kgsl_mmu_unmap(mmu->defaultpagetable,
+			kgsl_mmu_unmap(pagetable,
 			&(iommu->iommu_units[i].reg_map));
 		if (iommu->iommu_units[i].reg_map.hostptr)
 			iounmap(iommu->iommu_units[i].reg_map.hostptr);
 		kgsl_sg_free(iommu->iommu_units[i].reg_map.sg,
 				iommu->iommu_units[i].reg_map.sglen);
 	}
+
+	if (mmu->priv_bank_table)
+		kgsl_mmu_putpagetable(mmu->priv_bank_table);
 	if (mmu->defaultpagetable)
 		kgsl_mmu_putpagetable(mmu->defaultpagetable);
 	kfree(iommu->asids);
@@ -837,6 +874,10 @@
 {
 	unsigned int pt_base;
 	struct kgsl_iommu *iommu = mmu->priv;
+	/* We cannot enable or disable the clocks in interrupt context, this
+	 function is called from interrupt context if there is an axi error */
+	if (in_interrupt())
+		return 0;
 	/* Return the current pt base by reading IOMMU pt_base register */
 	kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
 	pt_base = readl_relaxed(iommu->iommu_units[0].reg_map.hostptr +
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 5216b34..dfaadba 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -39,7 +39,8 @@
 	/* For IOMMU only unmap the global structures to global pt */
 	if ((KGSL_MMU_TYPE_NONE != kgsl_mmu_type) &&
 		(KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type) &&
-		(KGSL_MMU_GLOBAL_PT !=  pt->name))
+		(KGSL_MMU_GLOBAL_PT !=  pt->name) &&
+		(KGSL_MMU_PRIV_BANK_TABLE_NAME !=  pt->name))
 		return 0;
 	for (i = 0; i < KGSL_DEVICE_MAX; i++) {
 		struct kgsl_device *device = kgsl_driver.devp[i];
@@ -58,7 +59,8 @@
 	/* For IOMMU only map the global structures to global pt */
 	if ((KGSL_MMU_TYPE_NONE != kgsl_mmu_type) &&
 		(KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type) &&
-		(KGSL_MMU_GLOBAL_PT !=  pt->name))
+		(KGSL_MMU_GLOBAL_PT !=  pt->name) &&
+		(KGSL_MMU_PRIV_BANK_TABLE_NAME !=  pt->name))
 		return 0;
 	for (i = 0; i < KGSL_DEVICE_MAX; i++) {
 		struct kgsl_device *device = kgsl_driver.devp[i];
@@ -453,9 +455,9 @@
 	 * just once from this pool of the defaultpagetable
 	 */
 	if ((KGSL_MMU_TYPE_IOMMU == kgsl_mmu_get_mmutype()) &&
-		(KGSL_MMU_GLOBAL_PT == name)) {
-		pagetable->kgsl_pool = gen_pool_create(KGSL_MMU_ALIGN_SHIFT,
-						       -1);
+		((KGSL_MMU_GLOBAL_PT == name) ||
+		(KGSL_MMU_PRIV_BANK_TABLE_NAME == name))) {
+		pagetable->kgsl_pool = gen_pool_create(PAGE_SHIFT, -1);
 		if (pagetable->kgsl_pool == NULL) {
 			KGSL_CORE_ERR("gen_pool_create(%d) failed\n",
 					KGSL_MMU_ALIGN_SHIFT);
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index 2db327b..4c0c015 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -29,6 +29,7 @@
    as an identifier */
 
 #define KGSL_MMU_GLOBAL_PT 0
+#define KGSL_MMU_PRIV_BANK_TABLE_NAME 0xFFFFFFFF
 
 struct kgsl_device;
 
@@ -165,6 +166,8 @@
 	struct kgsl_memdesc    setstate_memory;
 	/* current page table object being used by device mmu */
 	struct kgsl_pagetable  *defaultpagetable;
+	/* pagetable object used for priv bank of IOMMU */
+	struct kgsl_pagetable  *priv_bank_table;
 	struct kgsl_pagetable  *hwpagetable;
 	const struct kgsl_mmu_ops *mmu_ops;
 	void *priv;
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 8935b29..824d806 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -35,6 +35,56 @@
 	struct list_head node;
 };
 
+struct snapshot_obj_itr {
+	void *buf;      /* Buffer pointer to write to */
+	int pos;        /* Current position in the sequence */
+	loff_t offset;  /* file offset to start writing from */
+	size_t remain;  /* Bytes remaining in buffer */
+	size_t write;   /* Bytes written so far */
+};
+
+static void obj_itr_init(struct snapshot_obj_itr *itr, void *buf,
+	loff_t offset, size_t remain)
+{
+	itr->buf = buf;
+	itr->offset = offset;
+	itr->remain = remain;
+	itr->pos = 0;
+	itr->write = 0;
+}
+
+static int obj_itr_out(struct snapshot_obj_itr *itr, void *src, int size)
+{
+	if (itr->remain == 0)
+		return 0;
+
+	if ((itr->pos + size) <= itr->offset)
+		goto done;
+
+	/* Handle the case that offset is in the middle of the buffer */
+
+	if (itr->offset > itr->pos) {
+		src += (itr->offset - itr->pos);
+		size -= (itr->offset - itr->pos);
+
+		/* Advance pos to the offset start */
+		itr->pos = itr->offset;
+	}
+
+	if (size > itr->remain)
+		size = itr->remain;
+
+	memcpy(itr->buf, src, size);
+
+	itr->buf += size;
+	itr->write += size;
+	itr->remain -= size;
+
+done:
+	itr->pos += size;
+	return size;
+}
+
 /* idr_for_each function to count the number of contexts */
 
 static int snapshot_context_count(int id, void *ptr, void *data)
@@ -182,76 +232,46 @@
 	(sizeof(struct kgsl_snapshot_section_header) + \
 	 sizeof(struct kgsl_snapshot_gpu_object))
 
-#define GPU_OBJ_SECTION_SIZE(_o) \
-	(GPU_OBJ_HEADER_SZ + ((_o)->size))
-
 static int kgsl_snapshot_dump_object(struct kgsl_device *device,
-		struct kgsl_snapshot_object *obj, void *buf,
-		unsigned int off, unsigned int count)
+	struct kgsl_snapshot_object *obj, struct snapshot_obj_itr *itr)
 {
-	unsigned char headers[GPU_OBJ_HEADER_SZ];
-	struct kgsl_snapshot_section_header *sect =
-		(struct kgsl_snapshot_section_header *) headers;
-	struct kgsl_snapshot_gpu_object *header =
-		(struct kgsl_snapshot_gpu_object *) (headers + sizeof(*sect));
-	int ret = 0;
+	struct kgsl_snapshot_section_header sect;
+	struct kgsl_snapshot_gpu_object header;
+	int ret;
 
-	/* Construct a local copy of the headers */
+	sect.magic = SNAPSHOT_SECTION_MAGIC;
+	sect.id = KGSL_SNAPSHOT_SECTION_GPU_OBJECT;
 
-	sect->magic = SNAPSHOT_SECTION_MAGIC;
-	sect->id = KGSL_SNAPSHOT_SECTION_GPU_OBJECT;
-	sect->size = GPU_OBJ_SECTION_SIZE(obj);
+	/*
+	 * Header size is in dwords, object size is in bytes -
+	 * round up if the object size isn't dword aligned
+	 */
 
-	header->type = obj->type;
+	sect.size = GPU_OBJ_HEADER_SZ + ALIGN(obj->size, 4);
 
-	/* Header size is in dwords, object size is in bytes */
-	header->size = obj->size >> 2;
-	header->gpuaddr = obj->gpuaddr;
-	header->ptbase = obj->ptbase;
+	ret = obj_itr_out(itr, &sect, sizeof(sect));
+	if (ret == 0)
+		return 0;
 
-	/* Copy out any part of the header block that is needed */
+	header.size = ALIGN(obj->size, 4) >> 2;
+	header.gpuaddr = obj->gpuaddr;
+	header.ptbase = obj->ptbase;
+	header.type = obj->type;
 
-	if (off < GPU_OBJ_HEADER_SZ) {
-		int size = count < GPU_OBJ_HEADER_SZ - off ?
-			count : GPU_OBJ_HEADER_SZ - off;
+	ret = obj_itr_out(itr, &header, sizeof(header));
+	if (ret == 0)
+		return 0;
 
-		memcpy(buf, headers + off, size);
+	ret = obj_itr_out(itr, obj->entry->memdesc.hostptr + obj->offset,
+		obj->size);
+	if (ret == 0)
+		return 0;
 
-		count -= size;
-		ret += size;
-	}
+	/* Pad the end to a dword boundary if we need to */
 
-	/* Now copy whatever part of the data is needed */
-
-	if (off < (GPU_OBJ_HEADER_SZ + obj->size)) {
-		int offset;
-		int size = count < obj->size ? count : obj->size;
-
-		/*
-		 * If the desired gpuaddr isn't at the beginning of the region,
-		 * then offset the source pointer
-		 */
-
-		offset = obj->offset;
-
-		/*
-		 * Then  adjust it to account for the offset for the output
-		 * buffer.
-		 */
-
-		if (off > GPU_OBJ_HEADER_SZ) {
-			int loff = (off - GPU_OBJ_HEADER_SZ);
-
-			/* Adjust the size so we don't walk off the end */
-
-			if ((loff + size) > obj->size)
-				size = obj->size - loff;
-
-			offset += loff;
-		}
-
-		memcpy(buf + ret, obj->entry->memdesc.hostptr + offset, size);
-		ret += size;
+	if (obj->size % 4) {
+		unsigned int dummy = 0;
+		ret = obj_itr_out(itr, &dummy, obj->size % 4);
 	}
 
 	return ret;
@@ -488,7 +508,7 @@
 
 	header->magic = SNAPSHOT_MAGIC;
 
-	header->gpuid = kgsl_gpuid(device);
+	header->gpuid = kgsl_gpuid(device, &header->chipid);
 
 	/* Get a pointer to the first section (right after the header) */
 	snapshot = ((void *) device->snapshot) + sizeof(*header);
@@ -539,7 +559,9 @@
 {
 	struct kgsl_device *device = kobj_to_device(kobj);
 	struct kgsl_snapshot_object *obj, *tmp;
-	unsigned int size, src, dst = 0;
+	struct kgsl_snapshot_section_header head;
+	struct snapshot_obj_itr itr;
+	int ret;
 
 	if (device == NULL)
 		return 0;
@@ -551,80 +573,46 @@
 	/* Get the mutex to keep things from changing while we are dumping */
 	mutex_lock(&device->mutex);
 
-	if (off < device->snapshot_size) {
-		size = count < (device->snapshot_size - off) ?
-			count : device->snapshot_size - off;
+	obj_itr_init(&itr, buf, off, count);
 
-		memcpy(buf, device->snapshot + off, size);
+	ret = obj_itr_out(&itr, device->snapshot, device->snapshot_size);
 
-		count -= size;
-		dst += size;
-	}
-
-	if (count == 0)
+	if (ret == 0)
 		goto done;
 
-	src = device->snapshot_size;
+	list_for_each_entry(obj, &device->snapshot_obj_list, node)
+		kgsl_snapshot_dump_object(device, obj, &itr);
 
-	list_for_each_entry(obj, &device->snapshot_obj_list, node) {
+	{
+		head.magic = SNAPSHOT_SECTION_MAGIC;
+		head.id = KGSL_SNAPSHOT_SECTION_END;
+		head.size = sizeof(head);
 
-		int objsize = GPU_OBJ_SECTION_SIZE(obj);
-		int offset;
-
-		/* If the offset is beyond this object, then move on */
-
-		if (off >= (src + objsize)) {
-			src += objsize;
-			continue;
-		}
-
-		/* Adjust the offset to be relative to the object */
-		offset = (off >= src) ? (off - src) : 0;
-
-		size = kgsl_snapshot_dump_object(device, obj, buf + dst,
-			offset, count);
-
-		count -= size;
-		dst += size;
-
-		if (count == 0)
-			goto done;
-
-		/* Move on to the next object - update src accordingly */
-		src += objsize;
+		obj_itr_out(&itr, &head, sizeof(head));
 	}
 
-	/* Add the end section */
+	/*
+	 * Make sure everything has been written out before destroying things.
+	 * The best way to confirm this is to go all the way through without
+	 * writing any bytes - so only release if we get this far and
+	 * itr->write is 0
+	 */
 
-	if (off < (src + sizeof(struct kgsl_snapshot_section_header))) {
-		if (count >= sizeof(struct kgsl_snapshot_section_header)) {
-			struct kgsl_snapshot_section_header *head =
-				(void *) (buf + dst);
+	if (itr.write == 0) {
+		list_for_each_entry_safe(obj, tmp, &device->snapshot_obj_list,
+			node)
+			kgsl_snapshot_put_object(device, obj);
 
-			head->magic = SNAPSHOT_SECTION_MAGIC;
-			head->id = KGSL_SNAPSHOT_SECTION_END;
-			head->size = sizeof(*head);
+		if (device->snapshot_frozen)
+			KGSL_DRV_ERR(device, "Snapshot objects released\n");
 
-			dst += sizeof(*head);
-		} else {
-			goto done;
-		}
+		device->snapshot_frozen = 0;
 	}
 
-	/* Release the buffers and unfreeze the snapshot */
-
-	list_for_each_entry_safe(obj, tmp, &device->snapshot_obj_list, node)
-		kgsl_snapshot_put_object(device, obj);
-
-	if (device->snapshot_frozen)
-		KGSL_DRV_ERR(device, "Snapshot objects released\n");
-
-	device->snapshot_frozen = 0;
-
 done:
 	mutex_unlock(&device->mutex);
 
-	return dst;
+	return itr.write;
 }
 
 /* Show the timestamp of the last collected snapshot */
diff --git a/drivers/gpu/msm/kgsl_snapshot.h b/drivers/gpu/msm/kgsl_snapshot.h
index 304f4bb..d54afcf 100644
--- a/drivers/gpu/msm/kgsl_snapshot.h
+++ b/drivers/gpu/msm/kgsl_snapshot.h
@@ -18,7 +18,8 @@
 
 /* Snapshot header */
 
-#define SNAPSHOT_MAGIC 0x504D0001
+/* High word is static, low word is snapshot version ID */
+#define SNAPSHOT_MAGIC 0x504D0002
 
 /* GPU ID scheme:
  * [16:31] - core identifer (0x0002 for 2D or 0x0003 for 3D)
@@ -28,6 +29,8 @@
 struct kgsl_snapshot_header {
 	__u32 magic; /* Magic identifier */
 	__u32 gpuid; /* GPU ID - see above */
+	/* Added in snapshot version 2 */
+	__u32 chipid; /* Chip ID from the GPU */
 } __packed;
 
 /* Section header */
@@ -140,6 +143,7 @@
 #define SNAPSHOT_DEBUG_CP_PM4_RAM 8
 #define SNAPSHOT_DEBUG_CP_PFP_RAM 9
 #define SNAPSHOT_DEBUG_CP_ROQ     10
+#define SNAPSHOT_DEBUG_SHADER_MEMORY 11
 
 struct kgsl_snapshot_debug {
 	int type;    /* Type identifier for the attached tata */
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index f4bbf69..bc2685c 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -896,8 +896,11 @@
 	}
 }
 
-static unsigned int z180_gpuid(struct kgsl_device *device)
+static unsigned int z180_gpuid(struct kgsl_device *device, unsigned int *chipid)
 {
+	if (chipid != NULL)
+		*chipid = 0;
+
 	/* Standard KGSL gpuid format:
 	 * top word is 0x0002 for 2D or 0x0003 for 3D
 	 * Bottom word is core specific identifer
diff --git a/drivers/i2c/busses/i2c-msm.c b/drivers/i2c/busses/i2c-msm.c
index b753fd0..4b48a69 100644
--- a/drivers/i2c/busses/i2c-msm.c
+++ b/drivers/i2c/busses/i2c-msm.c
@@ -636,7 +636,7 @@
 	spin_lock_init(&dev->lock);
 	platform_set_drvdata(pdev, dev);
 
-	clk_enable(clk);
+	clk_prepare_enable(clk);
 
 	if (pdata->rmutex) {
 		struct remote_mutex_id rmid;
@@ -697,7 +697,8 @@
 	/* Config GPIOs for primary and secondary lines */
 	pdata->msm_i2c_config_gpio(dev->adap_pri.nr, 1);
 	pdata->msm_i2c_config_gpio(dev->adap_aux.nr, 1);
-	clk_disable(dev->clk);
+	clk_disable_unprepare(dev->clk);
+	clk_prepare(dev->clk);
 	setup_timer(&dev->pwr_timer, msm_i2c_pwr_timer, (unsigned long) dev);
 
 	return 0;
@@ -706,7 +707,7 @@
 	i2c_del_adapter(&dev->adap_pri);
 	i2c_del_adapter(&dev->adap_aux);
 err_i2c_add_adapter_failed:
-	clk_disable(clk);
+	clk_disable_unprepare(clk);
 	iounmap(dev->base);
 err_ioremap_failed:
 	kfree(dev);
@@ -736,6 +737,7 @@
 	free_irq(dev->irq, dev);
 	i2c_del_adapter(&dev->adap_pri);
 	i2c_del_adapter(&dev->adap_aux);
+	clk_unprepare(dev->clk);
 	clk_put(dev->clk);
 	iounmap(dev->base);
 	kfree(dev);
@@ -759,6 +761,7 @@
 		del_timer_sync(&dev->pwr_timer);
 		if (dev->clk_state != 0)
 			msm_i2c_pwr_mgmt(dev, 0);
+		clk_unprepare(dev->clk);
 	}
 
 	return 0;
@@ -767,6 +770,7 @@
 static int msm_i2c_resume(struct platform_device *pdev)
 {
 	struct msm_i2c_dev *dev = platform_get_drvdata(pdev);
+	clk_prepare(dev->clk);
 	dev->suspended = 0;
 	return 0;
 }
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index daf21b8..78fc3ec 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -1769,7 +1769,7 @@
 		kref_put(&send_ioctx->kref, srpt_put_send_ioctx_kref);
 		goto send_sense;
 	}
-	ret = transport_generic_allocate_tasks(cmd, srp_cmd->cdb);
+	ret = target_setup_cmd_from_cdb(cmd, srp_cmd->cdb);
 	if (ret < 0) {
 		kref_put(&send_ioctx->kref, srpt_put_send_ioctx_kref);
 		if (cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT) {
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index 5403c57..8b6e172 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -40,6 +40,8 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
+#include <linux/input/mpu3050.h>
+#include <linux/regulator/consumer.h>
 
 #define MPU3050_CHIP_ID		0x69
 
@@ -112,8 +114,81 @@
 	struct i2c_client *client;
 	struct device *dev;
 	struct input_dev *idev;
+	struct mpu3050_gyro_platform_data *platform_data;
+	struct delayed_work input_work;
+	u32    use_poll;
 };
 
+struct sensor_regulator {
+	struct regulator *vreg;
+	const char *name;
+	u32	min_uV;
+	u32	max_uV;
+};
+
+struct sensor_regulator mpu_vreg[] = {
+	{NULL, "vdd", 2100000, 3600000},
+	{NULL, "vlogic", 1800000, 1800000},
+};
+
+static int mpu3050_config_regulator(struct i2c_client *client, bool on)
+{
+	int rc = 0, i;
+	int num_reg = sizeof(mpu_vreg) / sizeof(struct sensor_regulator);
+
+	if (on) {
+		for (i = 0; i < num_reg; i++) {
+			mpu_vreg[i].vreg = regulator_get(&client->dev,
+						mpu_vreg[i].name);
+			if (IS_ERR(mpu_vreg[i].vreg)) {
+				rc = PTR_ERR(mpu_vreg[i].vreg);
+				pr_err("%s:regulator get failed rc=%d\n",
+						__func__, rc);
+				goto error_vdd;
+			}
+
+			if (regulator_count_voltages(mpu_vreg[i].vreg) > 0) {
+				rc = regulator_set_voltage(mpu_vreg[i].vreg,
+					mpu_vreg[i].min_uV, mpu_vreg[i].max_uV);
+				if (rc) {
+					pr_err("%s:set_voltage failed rc=%d\n",
+						__func__, rc);
+					regulator_put(mpu_vreg[i].vreg);
+					goto error_vdd;
+				}
+			}
+
+			rc = regulator_enable(mpu_vreg[i].vreg);
+			if (rc) {
+				pr_err("%s: regulator_enable failed rc =%d\n",
+						__func__,
+						rc);
+
+				if (regulator_count_voltages(
+					mpu_vreg[i].vreg) > 0) {
+					regulator_set_voltage(mpu_vreg[i].vreg,
+						0, mpu_vreg[i].max_uV);
+				}
+				regulator_put(mpu_vreg[i].vreg);
+				goto error_vdd;
+			}
+		}
+		return rc;
+	} else {
+		i = num_reg;
+	}
+error_vdd:
+	while (--i >= 0) {
+		if (regulator_count_voltages(mpu_vreg[i].vreg) > 0) {
+			regulator_set_voltage(mpu_vreg[i].vreg, 0,
+						mpu_vreg[i].max_uV);
+		}
+		regulator_disable(mpu_vreg[i].vreg);
+		regulator_put(mpu_vreg[i].vreg);
+	}
+	return rc;
+}
+
 /**
  *	mpu3050_xyz_read_reg	-	read the axes values
  *	@buffer: provide register addr and get register
@@ -179,11 +254,21 @@
 {
 	u8 value;
 
+	if (val) {
+		mpu3050_config_regulator(client, 1);
+		udelay(10);
+	}
+
 	value = i2c_smbus_read_byte_data(client, MPU3050_PWR_MGM);
 	value = (value & ~MPU3050_PWR_MGM_MASK) |
 		(((val << MPU3050_PWR_MGM_POS) & MPU3050_PWR_MGM_MASK) ^
 		 MPU3050_PWR_MGM_MASK);
 	i2c_smbus_write_byte_data(client, MPU3050_PWR_MGM, value);
+
+	if (!val) {
+		udelay(10);
+		mpu3050_config_regulator(client, 0);
+	}
 }
 
 /**
@@ -210,6 +295,9 @@
 		pm_runtime_put(sensor->dev);
 		return error;
 	}
+	if (sensor->use_poll)
+		schedule_delayed_work(&sensor->input_work,
+			msecs_to_jiffies(MPU3050_DEFAULT_POLL_INTERVAL));
 
 	return 0;
 }
@@ -225,6 +313,9 @@
 {
 	struct mpu3050_sensor *sensor = input_get_drvdata(input);
 
+	if (sensor->use_poll)
+		cancel_delayed_work_sync(&sensor->input_work);
+
 	pm_runtime_put(sensor->dev);
 }
 
@@ -252,6 +343,33 @@
 }
 
 /**
+ *	mpu3050_input_work_fn -		polling work
+ *	@work: the work struct
+ *
+ *	Called by the work queue; read sensor data and generate an input
+ *	event
+ */
+static void mpu3050_input_work_fn(struct work_struct *work)
+{
+	struct mpu3050_sensor *sensor;
+	struct axis_data axis;
+
+	sensor = container_of((struct delayed_work *)work,
+				struct mpu3050_sensor, input_work);
+
+	mpu3050_read_xyz(sensor->client, &axis);
+
+	input_report_abs(sensor->idev, ABS_X, axis.x);
+	input_report_abs(sensor->idev, ABS_Y, axis.y);
+	input_report_abs(sensor->idev, ABS_Z, axis.z);
+	input_sync(sensor->idev);
+
+	if (sensor->use_poll)
+		schedule_delayed_work(&sensor->input_work,
+			msecs_to_jiffies(MPU3050_DEFAULT_POLL_INTERVAL));
+}
+
+/**
  *	mpu3050_hw_init	-	initialize hardware
  *	@sensor: the sensor
  *
@@ -325,6 +443,7 @@
 	sensor->client = client;
 	sensor->dev = &client->dev;
 	sensor->idev = idev;
+	sensor->platform_data = client->dev.platform_data;
 
 	mpu3050_set_power_mode(client, 1);
 	msleep(10);
@@ -365,14 +484,22 @@
 	if (error)
 		goto err_pm_set_suspended;
 
-	error = request_threaded_irq(client->irq,
+	if (client->irq == 0) {
+		INIT_DELAYED_WORK(&sensor->input_work, mpu3050_input_work_fn);
+		sensor->use_poll = 1;
+	} else {
+		sensor->use_poll = 0;
+
+		error = request_threaded_irq(client->irq,
 				     NULL, mpu3050_interrupt_thread,
 				     IRQF_TRIGGER_RISING,
 				     "mpu3050", sensor);
-	if (error) {
-		dev_err(&client->dev,
-			"can't get IRQ %d, error %d\n", client->irq, error);
-		goto err_pm_set_suspended;
+		if (error) {
+			dev_err(&client->dev,
+				"can't get IRQ %d, error %d\n",
+				client->irq, error);
+			goto err_pm_set_suspended;
+		}
 	}
 
 	error = input_register_device(idev);
@@ -387,7 +514,8 @@
 	return 0;
 
 err_free_irq:
-	free_irq(client->irq, sensor);
+	if (client->irq > 0)
+		free_irq(client->irq, sensor);
 err_pm_set_suspended:
 	pm_runtime_set_suspended(&client->dev);
 err_free_mem:
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 09ff05d..23317d6 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -2296,6 +2296,7 @@
 	__set_bit(EV_ABS, input_dev->evbit);
 	__set_bit(EV_KEY, input_dev->evbit);
 	__set_bit(BTN_TOUCH, input_dev->keybit);
+	__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
 
 	/* For single touch */
 	input_set_abs_params(input_dev, ABS_X,
diff --git a/drivers/input/touchscreen/cyttsp-i2c-qc.c b/drivers/input/touchscreen/cyttsp-i2c-qc.c
index e82dd13..5af4534 100644
--- a/drivers/input/touchscreen/cyttsp-i2c-qc.c
+++ b/drivers/input/touchscreen/cyttsp-i2c-qc.c
@@ -2510,6 +2510,8 @@
 	set_bit(EV_ABS, input_device->evbit);
 	set_bit(BTN_TOUCH, input_device->keybit);
 	set_bit(BTN_2, input_device->keybit);
+	set_bit(INPUT_PROP_DIRECT, input_device->propbit);
+
 	if (ts->platform_data->use_gestures)
 		set_bit(BTN_3, input_device->keybit);
 
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
index 964218f..5ffc133 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -261,6 +261,16 @@
 	---help---
 	  Enable support for Video Pre-processing Engine
 
+config MSM_CAM_IRQ_ROUTER
+	bool "Enable MSM CAM IRQ Router"
+	depends on MSM_CAMERA
+	---help---
+	Enable IRQ Router for Camera. Depending on the
+	configuration, this module can handle the
+	interrupts from multiple camera hardware
+	cores and composite them into a single
+	interrupt to the MSM.
+
 config QUP_EXCLUSIVE_TO_CAMERA
 	bool "QUP exclusive to camera"
 	depends on MSM_CAMERA
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 9ed6cca..431da2e 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -14,6 +14,7 @@
   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) += server/ eeprom/ sensors/ actuators/ csi/
   obj-$(CONFIG_MSM_CAMERA) += msm_gesture.o
+  obj-$(CONFIG_MSM_CAM_IRQ_ROUTER) += msm_camirq_router.o
 else
   obj-$(CONFIG_MSM_CAMERA) += msm_camera.o
 endif
diff --git a/drivers/media/video/msm/csi/msm_csic.c b/drivers/media/video/msm/csi/msm_csic.c
index a217f9d..dbb4f32 100644
--- a/drivers/media/video/msm/csi/msm_csic.c
+++ b/drivers/media/video/msm/csi/msm_csic.c
@@ -388,6 +388,8 @@
 {
 	struct csic_device *new_csic_dev;
 	int rc = 0;
+	struct msm_cam_subdev_info sd_info;
+
 	CDBG("%s: device id = %d\n", __func__, pdev->id);
 	new_csic_dev = kzalloc(sizeof(struct csic_device), GFP_KERNEL);
 	if (!new_csic_dev) {
@@ -455,8 +457,11 @@
 
 	iounmap(new_csic_dev->base);
 	new_csic_dev->base = NULL;
+	sd_info.sdev_type = CSIC_DEV;
+	sd_info.sd_index = pdev->id;
+	sd_info.irq_num = new_csic_dev->irq->start;
 	msm_cam_register_subdev_node(
-		&new_csic_dev->subdev, CSIC_DEV, pdev->id);
+		&new_csic_dev->subdev, &sd_info);
 
 	return 0;
 
diff --git a/drivers/media/video/msm/csi/msm_csid.c b/drivers/media/video/msm/csi/msm_csid.c
index bb2a1d4..1ab4e66 100644
--- a/drivers/media/video/msm/csi/msm_csid.c
+++ b/drivers/media/video/msm/csi/msm_csid.c
@@ -298,6 +298,8 @@
 static int __devinit csid_probe(struct platform_device *pdev)
 {
 	struct csid_device *new_csid_dev;
+	struct msm_cam_subdev_info sd_info;
+
 	int rc = 0;
 	CDBG("%s: device id = %d\n", __func__, pdev->id);
 	new_csid_dev = kzalloc(sizeof(struct csid_device), GFP_KERNEL);
@@ -338,7 +340,10 @@
 	}
 
 	new_csid_dev->pdev = pdev;
-	msm_cam_register_subdev_node(&new_csid_dev->subdev, CSID_DEV, pdev->id);
+	sd_info.sdev_type = CSID_DEV;
+	sd_info.sd_index = pdev->id;
+	sd_info.irq_num = new_csid_dev->irq->start;
+	msm_cam_register_subdev_node(&new_csid_dev->subdev, &sd_info);
 	return 0;
 
 csid_no_resource:
diff --git a/drivers/media/video/msm/csi/msm_csiphy.c b/drivers/media/video/msm/csi/msm_csiphy.c
index e25660b..4693a8a 100644
--- a/drivers/media/video/msm/csi/msm_csiphy.c
+++ b/drivers/media/video/msm/csi/msm_csiphy.c
@@ -282,6 +282,8 @@
 {
 	struct csiphy_device *new_csiphy_dev;
 	int rc = 0;
+	struct msm_cam_subdev_info sd_info;
+
 	CDBG("%s: device id = %d\n", __func__, pdev->id);
 	new_csiphy_dev = kzalloc(sizeof(struct csiphy_device), GFP_KERNEL);
 	if (!new_csiphy_dev) {
@@ -333,8 +335,11 @@
 	disable_irq(new_csiphy_dev->irq->start);
 
 	new_csiphy_dev->pdev = pdev;
+	sd_info.sdev_type = CSIPHY_DEV;
+	sd_info.sd_index = pdev->id;
+	sd_info.irq_num = new_csiphy_dev->irq->start;
 	msm_cam_register_subdev_node(
-		&new_csiphy_dev->subdev, CSIPHY_DEV, pdev->id);
+		&new_csiphy_dev->subdev, &sd_info);
 	return 0;
 
 csiphy_no_resource:
diff --git a/drivers/media/video/msm/csi/msm_ispif.c b/drivers/media/video/msm/csi/msm_ispif.c
index be97091..0f16bbf 100644
--- a/drivers/media/video/msm/csi/msm_ispif.c
+++ b/drivers/media/video/msm/csi/msm_ispif.c
@@ -640,6 +640,8 @@
 static int __devinit ispif_probe(struct platform_device *pdev)
 {
 	int rc = 0;
+	struct msm_cam_subdev_info sd_info;
+
 	CDBG("%s\n", __func__);
 	ispif = kzalloc(sizeof(struct ispif_device), GFP_KERNEL);
 	if (!ispif) {
@@ -687,7 +689,10 @@
 	}
 
 	ispif->pdev = pdev;
-	msm_cam_register_subdev_node(&ispif->subdev, ISPIF_DEV, pdev->id);
+	sd_info.sdev_type = ISPIF_DEV;
+	sd_info.sd_index = pdev->id;
+	sd_info.irq_num = ispif->irq->start;
+	msm_cam_register_subdev_node(&ispif->subdev, &sd_info);
 	return 0;
 
 ispif_no_mem:
diff --git a/drivers/media/video/msm/io/msm_io_vfe31.c b/drivers/media/video/msm/io/msm_io_vfe31.c
index 0c0c450..8c733a0 100644
--- a/drivers/media/video/msm/io/msm_io_vfe31.c
+++ b/drivers/media/video/msm/io/msm_io_vfe31.c
@@ -247,7 +247,7 @@
 	}
 
 	if (!IS_ERR(clk))
-		clk_enable(clk);
+		clk_prepare_enable(clk);
 	else
 		rc = -1;
 	return rc;
@@ -303,10 +303,11 @@
 	}
 
 	if (!IS_ERR(clk)) {
-		clk_disable(clk);
+		clk_disable_unprepare(clk);
 		clk_put(clk);
-	} else
+	} else {
 		rc = -1;
+	}
 
 	return rc;
 }
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index c3c09d4..d34b8e1 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -1277,6 +1277,7 @@
 	struct msm_camera_sensor_info *sdata;
 	struct msm_cam_v4l2_device *pcam;
 	struct msm_sensor_ctrl_t *s_ctrl;
+	struct msm_cam_subdev_info sd_info;
 
 	D("%s for %s\n", __func__, sensor_sd->name);
 
@@ -1321,8 +1322,11 @@
 	}
 	msm_server_update_sensor_info(pcam, sdata);
 
+	sd_info.sdev_type = SENSOR_DEV;
+	sd_info.sd_index = vnode_count;
+	sd_info.irq_num = 0;
 	/* register the subdevice, must be done for callbacks */
-	rc = msm_cam_register_subdev_node(sensor_sd, SENSOR_DEV, vnode_count);
+	rc = msm_cam_register_subdev_node(sensor_sd, &sd_info);
 	if (rc < 0) {
 		D("%s sensor sub device register failed\n",
 			__func__);
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 7bc6cff..d0322d1 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -58,14 +58,16 @@
 #define MSM_GEMINI_DRV_NAME "msm_gemini"
 #define MSM_MERCURY_DRV_NAME "msm_mercury"
 #define MSM_I2C_MUX_DRV_NAME "msm_cam_i2c_mux"
+#define MSM_IRQ_ROUTER_DRV_NAME "msm_cam_irq_router"
 
 #define MAX_NUM_CSIPHY_DEV 3
-#define MAX_NUM_CSID_DEV 3
+#define MAX_NUM_CSID_DEV 4
 #define MAX_NUM_CSIC_DEV 3
 #define MAX_NUM_ISPIF_DEV 1
 #define MAX_NUM_VFE_DEV 2
 #define MAX_NUM_AXI_DEV 2
 #define MAX_NUM_VPE_DEV 1
+#define MAX_NUM_JPEG_DEV 3
 
 enum msm_cam_subdev_type {
 	CSIPHY_DEV,
@@ -79,6 +81,7 @@
 	ACTUATOR_DEV,
 	EEPROM_DEV,
 	GESTURE_DEV,
+	IRQ_ROUTER_DEV,
 };
 
 /* msm queue management APIs*/
@@ -129,6 +132,7 @@
 
 struct msm_free_buf {
 	uint8_t num_planes;
+	int32_t image_mode;
 	uint32_t ch_paddr[VIDEO_MAX_PLANES];
 	uint32_t vb;
 };
@@ -404,6 +408,15 @@
 	struct msm_mem_map_info mem_map;
 };
 
+struct msm_cam_subdev_info {
+	uint8_t sdev_type;
+	/* Subdev index. For eg: CSIPHY0, CSIPHY1 etc */
+	uint8_t sd_index;
+	/* This device/subdev's interrupt number, assigned
+	 * from the hardware document. */
+	uint8_t irq_num;
+};
+
 /* 2 for camera, 1 for gesture */
 #define MAX_NUM_ACTIVE_CAMERA 3
 
@@ -420,6 +433,68 @@
 	uint32_t handle;
 };
 
+struct msm_cam_server_irqmap_entry {
+	int irq_num;
+	int irq_idx;
+	uint8_t cam_hw_idx;
+	uint8_t is_composite;
+};
+
+struct intr_table_entry {
+	/* irq_num as understood by msm.
+	 * Unique for every camera hw core & target. Use a mapping function
+	 * to map this irq number to its equivalent index in camera side. */
+	int irq_num;
+	/* Camera hw core idx, in case of non-composite IRQs*/
+	uint8_t cam_hw_idx;
+	/* Camera hw core mask, in case of composite IRQs. */
+	uint32_t cam_hw_mask;
+	/* Each interrupt is mapped to an index, which is used
+	 * to add/delete entries into the lookup table. Both the information
+	 * are needed in the lookup table to avoid another subdev call into
+	 * the IRQ Router subdev to get the irq_idx in the interrupt context */
+	int irq_idx;
+	/* Is this irq composite? */
+	uint8_t is_composite;
+	/* IRQ Trigger type: TRIGGER_RAISING, TRIGGER_HIGH, etc. */
+	uint32_t irq_trigger_type;
+	/* If IRQ Router hw is present,
+	 * this field holds the number of camera hw core
+	 * which are bundled together in the above
+	 * interrupt. > 1 in case of composite irqs.
+	 * If IRQ Router hw is not present, this field should be set to 1. */
+	int num_hwcore;
+	/* Pointers to the subdevs composited in this
+	 * irq. If not composite, the 0th index stores the subdev to which
+	 * this irq needs to be dispatched to. */
+	struct v4l2_subdev *subdev_list[CAMERA_SS_IRQ_MAX];
+	/* Device requesting the irq. */
+	const char *dev_name;
+	/* subdev private data, if any */
+	void *data;
+};
+
+struct irqmgr_intr_lkup_table {
+	/* Individual(hw) interrupt lookup table:
+	 * This table is populated during initialization and doesnt
+	 * change, unless the IRQ Router has been configured
+	 * for composite IRQs. If the IRQ Router has been configured
+	 * for composite IRQs, the is_composite field of that IRQ will
+	 * be set to 1(default 0). And when there is an interrupt on
+	 * that line, the composite interrupt lookup table is used
+	 * for handling the interrupt. */
+	struct intr_table_entry ind_intr_tbl[CAMERA_SS_IRQ_MAX];
+
+	/* Composite interrupt lookup table:
+	 * This table can be dynamically modified based on the usecase.
+	 * If the usecase requires two or more HW core IRQs to be bundled
+	 * into a single composite IRQ, then this table is populated
+	 * accordingly. Also when this is done, the composite field
+	 * in the intr_lookup_table has to be updated to reflect that
+	 * the irq 'irq_num' will now  be triggered in composite mode. */
+	struct intr_table_entry comp_intr_tbl[CAMERA_SS_IRQ_MAX];
+};
+
 /* abstract camera server device for all sensor successfully probed*/
 struct msm_cam_server_dev {
 
@@ -465,9 +540,18 @@
 	struct v4l2_subdev *axi_device[MAX_NUM_AXI_DEV];
 	struct v4l2_subdev *vpe_device[MAX_NUM_VPE_DEV];
 	struct v4l2_subdev *gesture_device;
-};
+	struct v4l2_subdev *irqr_device;
 
-/* camera server related functions */
+	spinlock_t  intr_table_lock;
+	struct irqmgr_intr_lkup_table irq_lkup_table;
+	/* Stores the pointer to the subdev when the individual
+	 * subdevices register themselves with the server. This
+	 * will be used while dispatching composite irqs. The
+	 * cam_hw_idx will serve as the index into this array to
+	 * dispatch the irq to the corresponding subdev. */
+	struct v4l2_subdev *subdev_table[MSM_CAM_HW_MAX];
+	struct msm_cam_server_irqmap_entry hw_irqmap[CAMERA_SS_IRQ_MAX];
+};
 
 /* ISP related functions */
 void msm_isp_vfe_dev_init(struct v4l2_subdev *vd);
@@ -582,7 +666,7 @@
 					void __user *arg);
 void msm_release_ion_client(struct kref *ref);
 int msm_cam_register_subdev_node(struct v4l2_subdev *sd,
-			enum msm_cam_subdev_type sdev_type, uint8_t index);
+	struct msm_cam_subdev_info *sd_info);
 int msm_server_open_client(int *p_qidx);
 int msm_server_send_ctrl(struct msm_ctrl_cmd *out, int ctrl_id);
 int msm_server_close_client(int idx);
diff --git a/drivers/media/video/msm/msm_camirq_router.c b/drivers/media/video/msm/msm_camirq_router.c
new file mode 100644
index 0000000..52dd175
--- /dev/null
+++ b/drivers/media/video/msm/msm_camirq_router.c
@@ -0,0 +1,266 @@
+/* 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/module.h>
+#include <linux/interrupt.h>
+#include <mach/irqs.h>
+#include <media/msm_isp.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include "msm.h"
+#include "server/msm_cam_server.h"
+#include "msm_camirq_router.h"
+
+#ifdef CONFIG_MSM_CAMERA_DEBUG
+#define D(fmt, args...) pr_debug("msm: " fmt, ##args)
+#else
+#define D(fmt, args...) do {} while (0)
+#endif
+
+static void msm_irqrouter_update_irqmap_entry(
+	struct msm_cam_server_irqmap_entry *entry,
+	int is_composite, int irq_idx, int cam_hw_idx)
+{
+	int rc = 0;
+	entry->irq_idx = irq_idx;
+	entry->is_composite = is_composite;
+	entry->cam_hw_idx = cam_hw_idx;
+	rc = msm_cam_server_update_irqmap(entry);
+	if (rc < 0)
+		pr_err("%s Error updating irq %d information ",
+			__func__, irq_idx);
+}
+
+static void msm_irqrouter_send_default_irqmap(
+	struct irqrouter_ctrl_type *irqrouter_ctrl)
+{
+	struct msm_cam_server_irqmap_entry *irqmap =
+		&irqrouter_ctrl->def_hw_irqmap[0];
+
+	msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_0],
+		0, CAMERA_SS_IRQ_0, MSM_CAM_HW_MICRO);
+
+	msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_1],
+		0, CAMERA_SS_IRQ_1, MSM_CAM_HW_CCI);
+
+	msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_2],
+		0, CAMERA_SS_IRQ_2, MSM_CAM_HW_CSI0);
+
+	msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_3],
+		0, CAMERA_SS_IRQ_3, MSM_CAM_HW_CSI1);
+
+	msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_4],
+		0, CAMERA_SS_IRQ_4, MSM_CAM_HW_CSI2);
+
+	msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_5],
+		0, CAMERA_SS_IRQ_5, MSM_CAM_HW_CSI3);
+
+	msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_6],
+		0, CAMERA_SS_IRQ_6, MSM_CAM_HW_ISPIF);
+
+	msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_7],
+		0, CAMERA_SS_IRQ_7, MSM_CAM_HW_CPP);
+
+	msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_8],
+		0, CAMERA_SS_IRQ_8, MSM_CAM_HW_VFE0);
+
+	msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_9],
+		0, CAMERA_SS_IRQ_9, MSM_CAM_HW_VFE1);
+
+	msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_10],
+		0, CAMERA_SS_IRQ_10, MSM_CAM_HW_JPEG0);
+
+	msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_11],
+		0, CAMERA_SS_IRQ_11, MSM_CAM_HW_JPEG1);
+
+	msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_12],
+		0, CAMERA_SS_IRQ_12, MSM_CAM_HW_JPEG2);
+}
+
+static int msm_irqrouter_open(struct v4l2_subdev *sd,
+	struct v4l2_subdev_fh *fh)
+{
+	struct irqrouter_ctrl_type *irqrouter_ctrl = v4l2_get_subdevdata(sd);
+	/* Only one object of IRQ Router allowed. */
+	if (atomic_read(&irqrouter_ctrl->active) != 0) {
+		pr_err("%s IRQ router is already opened\n", __func__);
+		return -EINVAL;
+	}
+
+	D("%s E ", __func__);
+	atomic_inc(&irqrouter_ctrl->active);
+
+	return 0;
+}
+
+static int msm_irqrouter_close(struct v4l2_subdev *sd,
+	struct v4l2_subdev_fh *fh)
+{
+	struct irqrouter_ctrl_type *irqrouter_ctrl = v4l2_get_subdevdata(sd);
+	if (atomic_read(&irqrouter_ctrl->active) == 0) {
+		pr_err("%s IRQ router is already closed\n", __func__);
+		return -EINVAL;
+	}
+	D("%s E ", __func__);
+	atomic_dec(&irqrouter_ctrl->active);
+	return 0;
+}
+
+static const struct v4l2_subdev_internal_ops msm_irqrouter_internal_ops = {
+	.open = msm_irqrouter_open,
+	.close = msm_irqrouter_close,
+};
+
+long msm_irqrouter_subdev_ioctl(struct v4l2_subdev *sd,
+	unsigned int cmd, void *arg)
+{
+	struct irqrouter_ctrl_type *irqrouter_ctrl = v4l2_get_subdevdata(sd);
+	struct msm_camera_irq_cfg *irq_cfg;
+	struct intr_table_entry irq_req;
+	int rc = 0;
+
+	/* Handle all IRQ Router Subdev IOCTLs here.
+	 * Userspace sends the composite irq configuration.
+	 * IRQ Router subdev then configures the registers to group
+	 * together individual core hw irqs into a composite IRQ
+	 * to the MSM IRQ controller. It also registers them with
+	 * the irq manager in the camera server. */
+	switch (cmd) {
+	case MSM_IRQROUTER_CFG_COMPIRQ:
+		COPY_FROM_USER(rc, &irq_cfg, (void __user *)arg,
+			sizeof(struct msm_camera_irq_cfg));
+		if (rc) {
+			ERR_COPY_FROM_USER();
+			break;
+		}
+
+		if (!irq_cfg ||
+			(irq_cfg->irq_idx < CAMERA_SS_IRQ_0) ||
+			(irq_cfg->irq_idx >= CAMERA_SS_IRQ_MAX)) {
+			pr_err("%s Invalid input", __func__);
+			return -EINVAL;
+		} else {
+			irq_req.cam_hw_mask      = irq_cfg->cam_hw_mask;
+			irq_req.irq_idx          = irq_cfg->irq_idx;
+			irq_req.irq_num          =
+			irqrouter_ctrl->def_hw_irqmap[irq_cfg->irq_idx].irq_num;
+			irq_req.is_composite     = 1;
+			irq_req.irq_trigger_type = IRQF_TRIGGER_RISING;
+			irq_req.num_hwcore       = irq_cfg->num_hwcore;
+			irq_req.data             = NULL;
+			rc = msm_cam_server_request_irq(&irq_req);
+			if (rc < 0) {
+				pr_err("%s Error requesting comp irq %d ",
+					__func__, irq_req.irq_idx);
+				return rc;
+			}
+			irqrouter_ctrl->def_hw_irqmap
+				[irq_cfg->irq_idx].is_composite = 1;
+		}
+		break;
+	default:
+		pr_err("%s Invalid cmd %d ", __func__, cmd);
+		break;
+	}
+
+	return rc;
+}
+
+static const struct v4l2_subdev_core_ops msm_irqrouter_subdev_core_ops = {
+	.ioctl = msm_irqrouter_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_irqrouter_subdev_ops = {
+	.core = &msm_irqrouter_subdev_core_ops,
+};
+
+static int __devinit irqrouter_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct irqrouter_ctrl_type *irqrouter_ctrl;
+	struct msm_cam_subdev_info sd_info;
+
+	D("%s: device id = %d\n", __func__, pdev->id);
+
+	irqrouter_ctrl = kzalloc(sizeof(struct irqrouter_ctrl_type),
+				GFP_KERNEL);
+	if (!irqrouter_ctrl) {
+		pr_err("%s: not enough memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	v4l2_subdev_init(&irqrouter_ctrl->subdev, &msm_irqrouter_subdev_ops);
+	irqrouter_ctrl->subdev.internal_ops = &msm_irqrouter_internal_ops;
+	irqrouter_ctrl->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(irqrouter_ctrl->subdev.name,
+			 sizeof(irqrouter_ctrl->subdev.name), "msm_irqrouter");
+	v4l2_set_subdevdata(&irqrouter_ctrl->subdev, irqrouter_ctrl);
+	irqrouter_ctrl->pdev = pdev;
+
+	msm_irqrouter_send_default_irqmap(irqrouter_ctrl);
+
+	media_entity_init(&irqrouter_ctrl->subdev.entity, 0, NULL, 0);
+	irqrouter_ctrl->subdev.entity.type = MEDIA_ENT_T_DEVNODE_V4L;
+	irqrouter_ctrl->subdev.entity.group_id = IRQ_ROUTER_DEV;
+	irqrouter_ctrl->subdev.entity.name = pdev->name;
+
+	sd_info.sdev_type = IRQ_ROUTER_DEV;
+	sd_info.sd_index = 0;
+	sd_info.irq_num = 0;
+	/* Now register this subdev with the camera server. */
+	rc = msm_cam_register_subdev_node(&irqrouter_ctrl->subdev, &sd_info);
+	if (rc < 0) {
+		pr_err("%s Error registering irqr subdev %d", __func__, rc);
+		goto error;
+	}
+	irqrouter_ctrl->subdev.entity.revision =
+		irqrouter_ctrl->subdev.devnode->num;
+	atomic_set(&irqrouter_ctrl->active, 0);
+
+	platform_set_drvdata(pdev, &irqrouter_ctrl->subdev);
+
+	return rc;
+error:
+	kfree(irqrouter_ctrl);
+	return rc;
+}
+
+static int __exit irqrouter_exit(struct platform_device *pdev)
+{
+	kfree(irqrouter_ctrl);
+	return 0;
+}
+
+static struct platform_driver msm_irqrouter_driver = {
+	.probe = irqrouter_probe,
+	.remove = irqrouter_exit,
+	.driver = {
+		.name = MSM_IRQ_ROUTER_DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_irqrouter_init_module(void)
+{
+	return platform_driver_register(&msm_irqrouter_driver);
+}
+
+static void __exit msm_irqrouter_exit_module(void)
+{
+	platform_driver_unregister(&msm_irqrouter_driver);
+}
+
+module_init(msm_irqrouter_init_module);
+module_exit(msm_irqrouter_exit_module);
+MODULE_DESCRIPTION("msm camera irq router");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/msm_camirq_router.h b/drivers/media/video/msm/msm_camirq_router.h
new file mode 100644
index 0000000..2c9cb73
--- /dev/null
+++ b/drivers/media/video/msm/msm_camirq_router.h
@@ -0,0 +1,206 @@
+/* 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 __MSM_CAM_IRQROUTER_H__
+#define __MSM_CAM_IRQROUTER_H__
+
+#include <linux/bitops.h>
+
+/* Camera SS common registers defines - Start */
+/* These registers are not directly related to
+ * IRQ Router, but are common to the Camera SS.
+ * IRQ Router registers dont have a unique base address
+ * in the memory mapped address space. It is offset from
+ * the Camera SS base address. So keep the common Camera
+ * SS registers also in the IRQ Router subdev for now. */
+
+/* READ ONLY: Camera Subsystem HW version */
+#define CAMSS_HW_VERSION			0x00000000
+
+/* Bits 4:0 of this register can be used to select a desired
+ * camera core test bus to drive the Camera_SS test bus output */
+#define CAMSS_TESTBUS_SEL			0x00000004
+
+/* Bits 4:0 of this register is used to allow either Microcontroller
+ * or the CCI drive the corresponding GPIO output.
+ * For eg: Setting bit 0 of this register allows Microcontroller to
+ * drive GPIO #0. Clearing the bit allows CCI to drive GPIO #0. */
+#define CAMSS_GPIO_MUX_SEL			0x00000008
+
+/* Bit 0 of this register is used to set the default AHB master
+ * for the AHB Arbiter. 0 - AHB Master 0, 1 - AHB Master 1*/
+#define CAMSS_AHB_ARB_CTL			0x0000000C
+
+/* READ ONLY */
+#define CAMSS_XPU2_STATUS			0x00000010
+
+/* Select the appropriate CSI clock for CSID Pixel pipes */
+#define CAMSS_CSI_PIX_CLK_MUX_SEL		0x00000020
+#define CAMSS_CSI_PIX_CLK_CGC_EN		0x00000024
+
+/* Select the appropriate CSI clock for CSID RDI pipes */
+#define CAMSS_CSI_RDI_CLK_MUX_SEL		0x00000028
+#define CAMSS_CSI_RDI_CLK_CGC_EN		0x0000002C
+
+/* Select the appropriate CSI clock for CSI Phy0 */
+#define CAMSS_CSI_PHY_0_CLK_MUX_SEL		0x00000030
+#define CAMSS_CSI_PHY_0_CLK_CGC_EN		0x00000034
+
+/* Select the appropriate CSI clock for CSI Phy1 */
+#define CAMSS_CSI_PHY_1_CLK_MUX_SEL		0x00000038
+#define CAMSS_CSI_PHY_1_CLK_CGC_EN		0x0000003C
+
+/* Select the appropriate CSI clock for CSI Phy2 */
+#define CAMSS_CSI_PHY_2_CLK_MUX_SEL		0x00000040
+#define CAMSS_CSI_PHY_2_CLK_CGC_EN		0x00000044
+/* Camera SS common registers defines - End */
+
+/* IRQ Router registers defines - Start */
+/* This register is used to reset the composite
+ * IRQ outputs of the Camera_SS IRQ Router */
+#define CAMSS_IRQ_COMPOSITE_RESET_CTRL		0x00000060
+
+/* By default, this 'allows' the interrupts from
+ * Micro to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_0		0x00000064
+
+/* By default, this 'allows' the interrupts from
+ * CCI to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_1		0x00000068
+
+/* By default, this 'allows' the interrupts from
+ * CSI_0 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_2		0x0000006C
+
+/* By default, this 'allows' the interrupts from
+ * CSI_1 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_3		0x00000070
+
+/* By default, this 'allows' the interrupts from
+ * CSI_2 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_4		0x00000074
+
+/* By default, this 'allows' the interrupts from
+ * CSI_3 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_5		0x00000078
+
+/* By default, this 'allows' the interrupts from
+ * ISPIF to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_6		0x0000007C
+
+/* By default, this 'allows' the interrupts from
+ * CPP to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_7		0x00000080
+
+/* By default, this 'allows' the interrupts from
+ * VFE_0 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_8		0x00000084
+
+/* By default, this 'allows' the interrupts from
+ * VFE_1 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_9		0x00000088
+
+/* By default, this 'allows' the interrupts from
+ * JPEG_0 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_10		0x0000008C
+
+/* By default, this 'allows' the interrupts from
+ * JPEG_1 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_11		0x00000090
+
+/* By default, this 'allows' the interrupts from
+ * JPEG_2 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_12		0x00000094
+
+/* The following IRQ_COMPOSITE_MICRO_MASK registers
+ * allow the interrupts from the individual hw
+ * cores to be composited into an IRQ for Micro. */
+#define CAMSS_IRQ_COMPOSITE_MICRO_MASK_0	0x000000A4
+#define CAMSS_IRQ_COMPOSITE_MICRO_MASK_1	0x000000A8
+#define CAMSS_IRQ_COMPOSITE_MICRO_MASK_2	0x000000AC
+#define CAMSS_IRQ_COMPOSITE_MICRO_MASK_3	0x000000B0
+#define CAMSS_IRQ_COMPOSITE_MICRO_MASK_4	0x000000B4
+#define CAMSS_IRQ_COMPOSITE_MICRO_MASK_5	0x000000B8
+/* IRQ Router register defines - End */
+
+/* Writing this mask will reset all the composite
+ * IRQs of the Camera_SS IRQ Router */
+#define CAMSS_IRQ_COMPOSITE_RESET_MASK		0x003F1FFF
+
+/* Use this to enable Micro IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_MICRO_IRQ_IN_COMPOSITE		BIT(0)
+/* Use this to enable CCI IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_CCI_IRQ_IN_COMPOSITE		BIT(1)
+/* Use this to enable CSI0 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_CSI0_IRQ_IN_COMPOSITE		BIT(2)
+/* Use this to enable CSI1 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_CSI1_IRQ_IN_COMPOSITE		BIT(3)
+/* Use this to enable CSI2 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_CSI2_IRQ_IN_COMPOSITE		BIT(4)
+/* Use this to enable CSI3 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_CSI3_IRQ_IN_COMPOSITE		BIT(5)
+/* Use this to enable ISPIF IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_ISPIF_IRQ_IN_COMPOSITE		BIT(6)
+/* Use this to enable CPP IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_CPP_IRQ_IN_COMPOSITE		BIT(7)
+/* Use this to enable VFE0 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_VFE0_IRQ_IN_COMPOSITE		BIT(8)
+/* Use this to enable VFE1 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_VFE1_IRQ_IN_COMPOSITE		BIT(9)
+/* Use this to enable JPEG0 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_JPEG0_IRQ_IN_COMPOSITE		BIT(10)
+/* Use this to enable JPEG1 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_JPEG1_IRQ_IN_COMPOSITE		BIT(11)
+/* Use this to enable JPEG2 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_JPEG2_IRQ_IN_COMPOSITE		BIT(12)
+
+struct irqrouter_ctrl_type {
+	/* v4l2 subdev */
+	struct v4l2_subdev subdev;
+	struct platform_device *pdev;
+
+	void __iomem *irqr_dev_base;
+
+	struct resource	*irqr_dev_mem;
+	struct resource *irqr_dev_io;
+	atomic_t active;
+	struct msm_cam_server_irqmap_entry def_hw_irqmap[CAMERA_SS_IRQ_MAX];
+};
+
+#endif /* __MSM_CAM_IRQROUTER_H__ */
diff --git a/drivers/media/video/msm/msm_gesture.c b/drivers/media/video/msm/msm_gesture.c
index 6b81d15..5777cb5 100644
--- a/drivers/media/video/msm/msm_gesture.c
+++ b/drivers/media/video/msm/msm_gesture.c
@@ -455,6 +455,8 @@
 	struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
 	struct v4l2_subdev *gesture_subdev =
 		kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+	struct msm_cam_subdev_info sd_info;
+
 	D("%s\n", __func__);
 	if (!gesture_subdev) {
 		pr_err("%s: no enough memory\n", __func__);
@@ -475,7 +477,10 @@
 	/* events */
 	gesture_subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
 
-	msm_cam_register_subdev_node(gesture_subdev, GESTURE_DEV, 0);
+	sd_info.sdev_type = GESTURE_DEV;
+	sd_info.sd_index = 0;
+	sd_info.irq_num = 0;
+	msm_cam_register_subdev_node(gesture_subdev, &sd_info);
 
 	gesture_subdev->entity.revision = gesture_subdev->devnode->num;
 
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index fab0095..834c9b0 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -146,7 +146,7 @@
 
 static int msm_isp_notify_VFE_BUF_EVT(struct v4l2_subdev *sd, void *arg)
 {
-	int rc = -EINVAL, image_mode;
+	int rc = -EINVAL;
 	struct msm_vfe_resp *vdata = (struct msm_vfe_resp *)arg;
 	struct msm_free_buf free_buf, temp_free_buf;
 	struct msm_camvfe_params vfe_params;
@@ -154,16 +154,22 @@
 	struct msm_cam_media_controller *pmctl =
 		(struct msm_cam_media_controller *)v4l2_get_subdev_hostdata(sd);
 	struct msm_cam_v4l2_device *pcam = pmctl->pcam_ptr;
-
-	int vfe_id = vdata->evt_msg.msg_id;
+	struct msm_frame_info *frame_info =
+		(struct msm_frame_info *)vdata->evt_msg.data;
+	uint32_t vfe_id, image_mode;
 	if (!pcam) {
 		pr_debug("%s pcam is null. return\n", __func__);
 		msm_isp_sync_free(vdata);
 		return rc;
 	}
-	/* Convert the vfe msg to the image mode */
-	image_mode = msm_isp_vfe_msg_to_img_mode(pmctl, vfe_id);
-	BUG_ON(image_mode < 0);
+	if (frame_info) {
+		vfe_id = frame_info->path;
+		image_mode = frame_info->image_mode;
+	} else {
+		vfe_id = vdata->evt_msg.msg_id;
+		image_mode = msm_isp_vfe_msg_to_img_mode(pmctl, vfe_id);
+	}
+
 	switch (vdata->type) {
 	case VFE_MSG_V32_START:
 	case VFE_MSG_V32_START_RECORDING:
@@ -302,45 +308,49 @@
 	}
 	case NOTIFY_VFE_MSG_OUT: {
 		uint8_t msgid;
+		int32_t image_mode = -1;
 		struct isp_msg_output *isp_output =
 				(struct isp_msg_output *)arg;
-		switch (isp_output->output_id) {
-		case MSG_ID_OUTPUT_P:
-			msgid = VFE_MSG_OUTPUT_P;
-			break;
-		case MSG_ID_OUTPUT_V:
-			msgid = VFE_MSG_OUTPUT_V;
-			break;
-		case MSG_ID_OUTPUT_T:
-			msgid = VFE_MSG_OUTPUT_T;
-			break;
-		case MSG_ID_OUTPUT_S:
-			msgid = VFE_MSG_OUTPUT_S;
-			break;
-		case MSG_ID_OUTPUT_PRIMARY:
-			msgid = VFE_MSG_OUTPUT_PRIMARY;
-			break;
-		case MSG_ID_OUTPUT_SECONDARY:
-			msgid = VFE_MSG_OUTPUT_SECONDARY;
-			break;
-		default:
-			pr_err("%s: Invalid VFE output id: %d\n",
-				__func__, isp_output->output_id);
-			rc = -EINVAL;
-			break;
+		if (isp_output->buf.image_mode < 0) {
+			switch (isp_output->output_id) {
+			case MSG_ID_OUTPUT_P:
+				msgid = VFE_MSG_OUTPUT_P;
+				break;
+			case MSG_ID_OUTPUT_V:
+				msgid = VFE_MSG_OUTPUT_V;
+				break;
+			case MSG_ID_OUTPUT_T:
+				msgid = VFE_MSG_OUTPUT_T;
+				break;
+			case MSG_ID_OUTPUT_S:
+				msgid = VFE_MSG_OUTPUT_S;
+				break;
+			case MSG_ID_OUTPUT_PRIMARY:
+				msgid = VFE_MSG_OUTPUT_PRIMARY;
+				break;
+			case MSG_ID_OUTPUT_SECONDARY:
+				msgid = VFE_MSG_OUTPUT_SECONDARY;
+				break;
+			default:
+				pr_err("%s: Invalid VFE output id: %d\n",
+					   __func__, isp_output->output_id);
+				rc = -EINVAL;
+				break;
+			}
+			if (!rc)
+				image_mode =
+				msm_isp_vfe_msg_to_img_mode(pmctl, msgid);
+		} else {
+			image_mode = isp_output->buf.image_mode;
 		}
-
-		if (!rc) {
-			isp_event->isp_data.isp_msg.msg_id =
-				isp_output->output_id;
-			isp_event->isp_data.isp_msg.frame_id =
-				isp_output->frameCounter;
-			buf = isp_output->buf;
-			msgid = msm_isp_vfe_msg_to_img_mode(pmctl, msgid);
-			BUG_ON(msgid < 0);
-			msm_mctl_buf_done(pmctl, msgid,
-				&buf, isp_output->frameCounter);
-		}
+		isp_event->isp_data.isp_msg.msg_id =
+			isp_output->output_id;
+		isp_event->isp_data.isp_msg.frame_id =
+			isp_output->frameCounter;
+		buf = isp_output->buf;
+		BUG_ON(image_mode < 0);
+		msm_mctl_buf_done(pmctl, image_mode,
+			&buf, isp_output->frameCounter);
 		}
 		break;
 	case NOTIFY_VFE_MSG_COMP_STATS: {
diff --git a/drivers/media/video/msm/msm_vfe31_v4l2.c b/drivers/media/video/msm/msm_vfe31_v4l2.c
index 7a2670c..885cd90 100644
--- a/drivers/media/video/msm/msm_vfe31_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe31_v4l2.c
@@ -420,15 +420,18 @@
 		vfe31_ctrl->vfebase + VFE_GLOBAL_RESET);
 }
 
-static void vfe31_subdev_notify(int id, int path)
+static void vfe31_subdev_notify(int id, int path, int image_mode)
 {
 	struct msm_vfe_resp rp;
+	struct msm_frame_info frame_info;
 	unsigned long flags;
 	spin_lock_irqsave(&vfe31_ctrl->sd_notify_lock, flags);
 	memset(&rp, 0, sizeof(struct msm_vfe_resp));
 	CDBG("vfe31_subdev_notify : msgId = %d\n", id);
 	rp.evt_msg.type   = MSM_CAMERA_MSG;
-	rp.evt_msg.msg_id = path;
+	frame_info.image_mode = image_mode;
+	frame_info.path = path;
+	rp.evt_msg.data = &frame_info;
 	rp.type	   = id;
 	v4l2_subdev_notify(&vfe31_ctrl->subdev, NOTIFY_VFE_BUF_EVT, &rp);
 	spin_unlock_irqrestore(&vfe31_ctrl->sd_notify_lock, flags);
@@ -442,10 +445,12 @@
 	ch_info = axi_cfg + V31_AXI_CFG_LEN;
 	vfe31_ctrl->outpath.out0.ch0 = 0x0000FFFF & *ch_info;
 	vfe31_ctrl->outpath.out0.ch1 = 0x0000FFFF & (*ch_info++ >> 16);
-	vfe31_ctrl->outpath.out0.ch2 = 0x0000FFFF & *ch_info++;
+	vfe31_ctrl->outpath.out0.ch2 = 0x0000FFFF & *ch_info;
+	vfe31_ctrl->outpath.out0.image_mode = 0x0000FFFF & (*ch_info++ >> 16);
 	vfe31_ctrl->outpath.out1.ch0 = 0x0000FFFF & *ch_info;
 	vfe31_ctrl->outpath.out1.ch1 = 0x0000FFFF & (*ch_info++ >> 16);
-	vfe31_ctrl->outpath.out1.ch2 = 0x0000FFFF & *ch_info++;
+	vfe31_ctrl->outpath.out1.ch2 = 0x0000FFFF & *ch_info;
+	vfe31_ctrl->outpath.out1.image_mode = 0x0000FFFF & (*ch_info++ >> 16);
 	vfe31_ctrl->outpath.out2.ch0 = 0x0000FFFF & *ch_info;
 	vfe31_ctrl->outpath.out2.ch1 = 0x0000FFFF & (*ch_info++ >> 16);
 	vfe31_ctrl->outpath.out2.ch2 = 0x0000FFFF & *ch_info++;
@@ -1168,7 +1173,14 @@
 {
 	struct vfe31_output_ch *outch = NULL;
 	struct msm_free_buf *b = NULL;
-	vfe31_subdev_notify(id, path);
+	uint32_t image_mode = 0;
+
+	if (path == VFE_MSG_OUTPUT_PRIMARY)
+		image_mode = vfe31_ctrl->outpath.out0.image_mode;
+	else
+		image_mode = vfe31_ctrl->outpath.out1.image_mode;
+
+	vfe31_subdev_notify(id, path, image_mode);
 	outch = vfe31_get_ch(path);
 	if (outch->free_buf.ch_paddr[0])
 		b = &outch->free_buf;
@@ -1178,7 +1190,14 @@
 {
 	struct vfe31_output_ch *outch = NULL;
 	int rc = 0;
-	vfe31_subdev_notify(id, path);
+	uint32_t image_mode = 0;
+
+	if (path == VFE_MSG_OUTPUT_PRIMARY)
+		image_mode = vfe31_ctrl->outpath.out0.image_mode;
+	else
+		image_mode = vfe31_ctrl->outpath.out1.image_mode;
+
+	vfe31_subdev_notify(id, path, image_mode);
 	outch = vfe31_get_ch(path);
 	if (outch->ping.ch_paddr[0] && outch->pong.ch_paddr[0]) {
 		/* Configure Preview Ping Pong */
@@ -2595,11 +2614,13 @@
 	}
 }
 static void vfe_send_outmsg(struct v4l2_subdev *sd, uint8_t msgid,
-	uint32_t ch0_paddr, uint32_t ch1_paddr, uint32_t ch2_paddr)
+	uint32_t ch0_paddr, uint32_t ch1_paddr,
+	uint32_t ch2_paddr, uint32_t image_mode)
 {
 	struct isp_msg_output msg;
 
 	msg.output_id		= msgid;
+	msg.buf.image_mode	= image_mode;
 	msg.buf.ch_paddr[0]	= ch0_paddr;
 	msg.buf.ch_paddr[1]	= ch1_paddr;
 	msg.buf.ch_paddr[2]	= ch2_paddr;
@@ -2681,7 +2702,8 @@
 
 		vfe_send_outmsg(&vfe31_ctrl->subdev,
 			MSG_ID_OUTPUT_PRIMARY, ch0_paddr,
-			ch1_paddr, ch2_paddr);
+			ch1_paddr, ch2_paddr,
+			vfe31_ctrl->outpath.out0.image_mode);
 
 		if (vfe31_ctrl->liveshot_state == VFE_STATE_STOPPED)
 			vfe31_ctrl->liveshot_state = VFE_STATE_IDLE;
@@ -2753,7 +2775,8 @@
 
 		vfe_send_outmsg(&vfe31_ctrl->subdev,
 			MSG_ID_OUTPUT_SECONDARY, ch0_paddr,
-			ch1_paddr, ch2_paddr);
+			ch1_paddr, ch2_paddr,
+			vfe31_ctrl->outpath.out1.image_mode);
 	} else {
 		vfe31_ctrl->outpath.out1.frame_drop_cnt++;
 		CDBG("path_irq_1 - no free buffer!\n");
@@ -3821,7 +3844,10 @@
 static int __devinit vfe31_probe(struct platform_device *pdev)
 {
 	int rc = 0;
+	struct msm_cam_subdev_info sd_info;
+
 	CDBG("%s: device id = %d\n", __func__, pdev->id);
+
 	vfe31_ctrl = kzalloc(sizeof(struct vfe31_ctrl_type), GFP_KERNEL);
 	if (!vfe31_ctrl) {
 		pr_err("%s: no enough memory\n", __func__);
@@ -3893,7 +3919,10 @@
 	disable_irq(vfe31_ctrl->vfeirq->start);
 
 	vfe31_ctrl->pdev = pdev;
-	msm_cam_register_subdev_node(&vfe31_ctrl->subdev, VFE_DEV, 0);
+	sd_info.sdev_type = VFE_DEV;
+	sd_info.sd_index = 0;
+	sd_info.irq_num = vfe31_ctrl->vfeirq->start;
+	msm_cam_register_subdev_node(&vfe31_ctrl->subdev, &sd_info);
 	return 0;
 
 vfe31_no_resource:
diff --git a/drivers/media/video/msm/msm_vfe31_v4l2.h b/drivers/media/video/msm/msm_vfe31_v4l2.h
index e94f286..739d157 100644
--- a/drivers/media/video/msm/msm_vfe31_v4l2.h
+++ b/drivers/media/video/msm/msm_vfe31_v4l2.h
@@ -695,7 +695,7 @@
 struct vfe31_output_ch {
 	struct list_head free_buf_queue;
 	spinlock_t free_buf_lock;
-	uint16_t output_fmt;
+	uint16_t image_mode;
 	int8_t ch0;
 	int8_t ch1;
 	int8_t ch2;
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index 3611656..9382292 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -25,6 +25,7 @@
 #include <media/msm_isp.h>
 
 #include "msm.h"
+#include "msm_cam_server.h"
 #include "msm_vfe32.h"
 
 atomic_t irq_cnt;
@@ -389,16 +390,19 @@
 		vfe32_ctrl->share_ctrl->vfebase + VFE_CAMIF_COMMAND);
 }
 
-static void vfe32_subdev_notify(int id, int path,
+static void vfe32_subdev_notify(int id, int path, int image_mode,
 	struct v4l2_subdev *sd, struct vfe_share_ctrl_t *share_ctrl)
 {
 	struct msm_vfe_resp rp;
+	struct msm_frame_info frame_info;
 	unsigned long flags = 0;
 	spin_lock_irqsave(&share_ctrl->sd_notify_lock, flags);
 	CDBG("vfe32_subdev_notify : msgId = %d\n", id);
 	memset(&rp, 0, sizeof(struct msm_vfe_resp));
 	rp.evt_msg.type   = MSM_CAMERA_MSG;
-	rp.evt_msg.msg_id = path;
+	frame_info.image_mode = image_mode;
+	frame_info.path = path;
+	rp.evt_msg.data = &frame_info;
 	rp.type	   = id;
 	v4l2_subdev_notify(sd, NOTIFY_VFE_BUF_EVT, &rp);
 	spin_unlock_irqrestore(&share_ctrl->sd_notify_lock, flags);
@@ -415,11 +419,15 @@
 	axi_ctrl->share_ctrl->outpath.out0.ch0 = 0x0000FFFF & *ch_info;
 	axi_ctrl->share_ctrl->outpath.out0.ch1 =
 		0x0000FFFF & (*ch_info++ >> 16);
-	axi_ctrl->share_ctrl->outpath.out0.ch2 = 0x0000FFFF & *ch_info++;
+	axi_ctrl->share_ctrl->outpath.out0.ch2 = 0x0000FFFF & *ch_info;
+	axi_ctrl->share_ctrl->outpath.out0.image_mode =
+		0x0000FFFF & (*ch_info++ >> 16);
 	axi_ctrl->share_ctrl->outpath.out1.ch0 = 0x0000FFFF & *ch_info;
 	axi_ctrl->share_ctrl->outpath.out1.ch1 =
 		0x0000FFFF & (*ch_info++ >> 16);
-	axi_ctrl->share_ctrl->outpath.out1.ch2 = 0x0000FFFF & *ch_info++;
+	axi_ctrl->share_ctrl->outpath.out1.ch2 = 0x0000FFFF & *ch_info;
+	axi_ctrl->share_ctrl->outpath.out1.image_mode =
+		0x0000FFFF & (*ch_info++ >> 16);
 	axi_ctrl->share_ctrl->outpath.out2.ch0 = 0x0000FFFF & *ch_info;
 	axi_ctrl->share_ctrl->outpath.out2.ch1 =
 		0x0000FFFF & (*ch_info++ >> 16);
@@ -1239,7 +1247,14 @@
 {
 	struct vfe32_output_ch *outch = NULL;
 	struct msm_free_buf *b = NULL;
-	vfe32_subdev_notify(id, path,
+	uint32_t image_mode = 0;
+
+	if (path == VFE_MSG_OUTPUT_PRIMARY)
+		image_mode = axi_ctrl->share_ctrl->outpath.out0.image_mode;
+	else
+		image_mode = axi_ctrl->share_ctrl->outpath.out1.image_mode;
+
+	vfe32_subdev_notify(id, path, image_mode,
 		&axi_ctrl->subdev, axi_ctrl->share_ctrl);
 	outch = vfe32_get_ch(path, axi_ctrl->share_ctrl);
 	if (outch->free_buf.ch_paddr[0])
@@ -1251,7 +1266,13 @@
 {
 	struct vfe32_output_ch *outch = NULL;
 	int rc = 0;
-	vfe32_subdev_notify(id, path,
+	uint32_t image_mode = 0;
+	if (path == VFE_MSG_OUTPUT_PRIMARY)
+		image_mode = vfe32_ctrl->share_ctrl->outpath.out0.image_mode;
+	else
+		image_mode = vfe32_ctrl->share_ctrl->outpath.out1.image_mode;
+
+	vfe32_subdev_notify(id, path, image_mode,
 		&vfe32_ctrl->subdev, vfe32_ctrl->share_ctrl);
 	outch = vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
 	if (outch->ping.ch_paddr[0] && outch->pong.ch_paddr[0]) {
@@ -3163,11 +3184,13 @@
 
 static void vfe_send_outmsg(
 	struct axi_ctrl_t *axi_ctrl, uint8_t msgid,
-	uint32_t ch0_paddr, uint32_t ch1_paddr, uint32_t ch2_paddr)
+	uint32_t ch0_paddr, uint32_t ch1_paddr,
+	uint32_t ch2_paddr, uint32_t image_mode)
 {
 	struct isp_msg_output msg;
 
 	msg.output_id = msgid;
+	msg.buf.image_mode = image_mode;
 	msg.buf.ch_paddr[0]	= ch0_paddr;
 	msg.buf.ch_paddr[1]	= ch1_paddr;
 	msg.buf.ch_paddr[2]	= ch2_paddr;
@@ -3268,7 +3291,8 @@
 
 		vfe_send_outmsg(axi_ctrl,
 			MSG_ID_OUTPUT_PRIMARY, ch0_paddr,
-			ch1_paddr, ch2_paddr);
+			ch1_paddr, ch2_paddr,
+			axi_ctrl->share_ctrl->outpath.out0.image_mode);
 
 		if (axi_ctrl->share_ctrl->liveshot_state == VFE_STATE_STOPPED)
 			axi_ctrl->share_ctrl->liveshot_state = VFE_STATE_IDLE;
@@ -3348,7 +3372,9 @@
 
 		vfe_send_outmsg(axi_ctrl,
 			MSG_ID_OUTPUT_SECONDARY, ch0_paddr,
-			ch1_paddr, ch2_paddr);
+			ch1_paddr, ch2_paddr,
+			axi_ctrl->share_ctrl->outpath.out1.image_mode);
+
 	} else {
 		axi_ctrl->share_ctrl->outpath.out1.frame_drop_cnt++;
 		CDBG("path_irq_1 - no free buffer!\n");
@@ -3954,6 +3980,17 @@
 	return IRQ_HANDLED;
 }
 
+int msm_axi_subdev_isr_routine(struct v4l2_subdev *sd,
+	u32 status, bool *handled)
+{
+	struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+	irqreturn_t ret;
+	pr_info("%s E ", __func__);
+	ret = vfe32_parse_irq(axi_ctrl->vfeirq->start, axi_ctrl);
+	*handled = TRUE;
+	return 0;
+}
+
 static long msm_vfe_subdev_ioctl(struct v4l2_subdev *sd,
 			unsigned int subdev_cmd, void *arg)
 {
@@ -4653,6 +4690,7 @@
 
 static const struct v4l2_subdev_core_ops msm_axi_subdev_core_ops = {
 	.ioctl = msm_axi_subdev_ioctl,
+	.interrupt_service_routine = msm_axi_subdev_isr_routine,
 };
 
 static const struct v4l2_subdev_video_ops msm_axi_subdev_video_ops = {
@@ -4672,6 +4710,9 @@
 	struct axi_ctrl_t *axi_ctrl;
 	struct vfe32_ctrl_type *vfe32_ctrl;
 	struct vfe_share_ctrl_t *share_ctrl;
+	struct intr_table_entry irq_req;
+	struct msm_cam_subdev_info sd_info;
+
 	CDBG("%s: device id = %d\n", __func__, pdev->id);
 
 	share_ctrl = kzalloc(sizeof(struct vfe_share_ctrl_t), GFP_KERNEL);
@@ -4707,7 +4748,11 @@
 			 sizeof(axi_ctrl->subdev.name), "axi");
 	v4l2_set_subdevdata(&axi_ctrl->subdev, axi_ctrl);
 	axi_ctrl->pdev = pdev;
-	msm_cam_register_subdev_node(&axi_ctrl->subdev, AXI_DEV, 0);
+
+	sd_info.sdev_type = AXI_DEV;
+	sd_info.sd_index = 0;
+	sd_info.irq_num = 0;
+	msm_cam_register_subdev_node(&axi_ctrl->subdev, &sd_info);
 
 	v4l2_subdev_init(&vfe32_ctrl->subdev, &msm_vfe_subdev_ops);
 	vfe32_ctrl->subdev.internal_ops = &msm_vfe_internal_ops;
@@ -4740,23 +4785,49 @@
 		goto vfe32_no_resource;
 	}
 
-	rc = request_irq(axi_ctrl->vfeirq->start, vfe32_parse_irq,
-		IRQF_TRIGGER_RISING, "vfe", axi_ctrl);
-	if (rc < 0) {
-		release_mem_region(axi_ctrl->vfemem->start,
-			resource_size(axi_ctrl->vfemem));
-		pr_err("%s: irq request fail\n", __func__);
-		rc = -EBUSY;
+	/* Request for this device irq from the camera server. If the
+	 * IRQ Router is present on this target, the interrupt will be
+	 * handled by the camera server and the interrupt service
+	 * routine called. If the request_irq call returns ENXIO, then
+	 * the IRQ Router hardware is not present on this target. We
+	 * have to request for the irq ourselves and register the
+	 * appropriate interrupt handler. */
+	irq_req.cam_hw_idx       = MSM_CAM_HW_VFE0;
+	irq_req.dev_name         = "vfe";
+	irq_req.irq_idx          = CAMERA_SS_IRQ_8;
+	irq_req.irq_num          = axi_ctrl->vfeirq->start;
+	irq_req.is_composite     = 0;
+	irq_req.irq_trigger_type = IRQF_TRIGGER_RISING;
+	irq_req.num_hwcore       = 1;
+	irq_req.subdev_list[0]   = &axi_ctrl->subdev;
+	irq_req.data             = (void *)axi_ctrl;
+	rc = msm_cam_server_request_irq(&irq_req);
+	if (rc == -ENXIO) {
+		/* IRQ Router hardware is not present on this hardware.
+		 * Request for the IRQ and register the interrupt handler. */
+		rc = request_irq(axi_ctrl->vfeirq->start, vfe32_parse_irq,
+			IRQF_TRIGGER_RISING, "vfe", axi_ctrl);
+		if (rc < 0) {
+			release_mem_region(axi_ctrl->vfemem->start,
+				resource_size(axi_ctrl->vfemem));
+			pr_err("%s: irq request fail\n", __func__);
+			rc = -EBUSY;
+			goto vfe32_no_resource;
+		}
+		disable_irq(axi_ctrl->vfeirq->start);
+	} else if (rc < 0) {
+		pr_err("%s Error registering irq ", __func__);
 		goto vfe32_no_resource;
 	}
 
-	disable_irq(axi_ctrl->vfeirq->start);
-
 	tasklet_init(&axi_ctrl->vfe32_tasklet,
 		axi32_do_tasklet, (unsigned long)axi_ctrl);
 
 	vfe32_ctrl->pdev = pdev;
-	msm_cam_register_subdev_node(&vfe32_ctrl->subdev, VFE_DEV, 0);
+	sd_info.sdev_type = VFE_DEV;
+	sd_info.sd_index = 0;
+	sd_info.irq_num = axi_ctrl->vfeirq->start;
+	msm_cam_register_subdev_node(&vfe32_ctrl->subdev, &sd_info);
 	return 0;
 
 vfe32_no_resource:
diff --git a/drivers/media/video/msm/msm_vfe32.h b/drivers/media/video/msm/msm_vfe32.h
index 086600a..d5da432 100644
--- a/drivers/media/video/msm/msm_vfe32.h
+++ b/drivers/media/video/msm/msm_vfe32.h
@@ -741,7 +741,7 @@
 struct vfe32_output_ch {
 	struct list_head free_buf_queue;
 	spinlock_t free_buf_lock;
-	uint16_t output_fmt;
+	uint16_t image_mode;
 	int8_t ch0;
 	int8_t ch1;
 	int8_t ch2;
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
index 893fc06..398621f 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
@@ -370,6 +370,7 @@
 	struct isp_msg_output msg;
 
 	msg.output_id = msgid;
+	msg.buf.image_mode = -1;
 	msg.buf.ch_paddr[0]     = ch0_paddr;
 	msg.buf.ch_paddr[1]     = ch1_paddr;
 	msg.frameCounter = vfe2x_ctrl->vfeFrameId;
@@ -859,6 +860,7 @@
 	CDBG("vfe2x_subdev_notify : msgId = %d\n", id);
 	rp.evt_msg.type   = MSM_CAMERA_MSG;
 	rp.evt_msg.msg_id = path;
+	rp.evt_msg.data = NULL;
 	rp.type	   = id;
 	v4l2_subdev_notify(&vfe2x_ctrl->subdev, NOTIFY_VFE_BUF_EVT, &rp);
 	spin_unlock_irqrestore(&vfe2x_ctrl->sd_notify_lock, flags);
@@ -1793,6 +1795,8 @@
 
 static int __devinit vfe2x_probe(struct platform_device *pdev)
 {
+	struct msm_cam_subdev_info sd_info;
+
 	CDBG("%s: device id = %d\n", __func__, pdev->id);
 	vfe2x_ctrl = kzalloc(sizeof(struct vfe2x_ctrl_type), GFP_KERNEL);
 	if (!vfe2x_ctrl) {
@@ -1809,7 +1813,10 @@
 	platform_set_drvdata(pdev, &vfe2x_ctrl->subdev);
 
 	vfe2x_ctrl->pdev = pdev;
-	msm_cam_register_subdev_node(&vfe2x_ctrl->subdev, VFE_DEV, 0);
+	sd_info.sdev_type = VFE_DEV;
+	sd_info.sd_index = 0;
+	sd_info.irq_num = 0;
+	msm_cam_register_subdev_node(&vfe2x_ctrl->subdev, &sd_info);
 	return 0;
 }
 
diff --git a/drivers/media/video/msm/msm_vpe.c b/drivers/media/video/msm/msm_vpe.c
index 54e9582..fb22cf9 100644
--- a/drivers/media/video/msm/msm_vpe.c
+++ b/drivers/media/video/msm/msm_vpe.c
@@ -970,6 +970,8 @@
 static int __devinit msm_vpe_probe(struct platform_device *pdev)
 {
 	int rc = 0;
+	struct msm_cam_subdev_info sd_info;
+
 	D("%s: device id = %d\n", __func__, pdev->id);
 	vpe_ctrl = kzalloc(sizeof(struct vpe_ctrl_type), GFP_KERNEL);
 	if (!vpe_ctrl) {
@@ -1028,7 +1030,10 @@
 
 	atomic_set(&vpe_ctrl->active, 0);
 	vpe_ctrl->pdev = pdev;
-	msm_cam_register_subdev_node(&vpe_ctrl->subdev, VPE_DEV, pdev->id);
+	sd_info.sdev_type = VPE_DEV;
+	sd_info.sd_index = pdev->id;
+	sd_info.irq_num = vpe_ctrl->vpeirq->start;
+	msm_cam_register_subdev_node(&vpe_ctrl->subdev, &sd_info);
 	vpe_ctrl->subdev.entity.revision = vpe_ctrl->subdev.devnode->num;
 	msm_queue_init(&vpe_ctrl->eventData_q, "ackevents");
 
diff --git a/drivers/media/video/msm/sensors/msm_sensor.h b/drivers/media/video/msm/sensors/msm_sensor.h
index 7697a79..b1e584d 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.h
+++ b/drivers/media/video/msm/sensors/msm_sensor.h
@@ -255,10 +255,6 @@
 
 struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd);
 
-#if defined(CONFIG_OV5647)
-	extern int lcd_camera_power_onoff(int on);
-#endif
-
 #define VIDIOC_MSM_SENSOR_CFG \
 	_IOWR('V', BASE_VIDIOC_PRIVATE + 10, void __user *)
 
diff --git a/drivers/media/video/msm/sensors/ov5647_v4l2.c b/drivers/media/video/msm/sensors/ov5647_v4l2.c
index eab0899..d192563 100644
--- a/drivers/media/video/msm/sensors/ov5647_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov5647_v4l2.c
@@ -643,8 +643,6 @@
 	}
 
 	s_ctrl = client->dev.platform_data;
-	if (s_ctrl->sensordata->pmic_gpio_enable)
-		lcd_camera_power_onoff(0);
 
 	return rc;
 }
@@ -716,11 +714,6 @@
 	gpio_direction_output(info->sensor_pwd, 1);
 	gpio_direction_output(info->sensor_reset, 0);
 	usleep_range(10000, 11000);
-	if (info->pmic_gpio_enable) {
-		info->pmic_gpio_enable = 0;
-		lcd_camera_power_onoff(1);
-	}
-	usleep_range(10000, 11000);
 	rc = msm_sensor_power_up(s_ctrl);
 	if (rc < 0) {
 		CDBG("%s: msm_sensor_power_up failed\n", __func__);
diff --git a/drivers/media/video/msm/sensors/ov7692_v4l2.c b/drivers/media/video/msm/sensors/ov7692_v4l2.c
index a6af770..6fc1da1 100644
--- a/drivers/media/video/msm/sensors/ov7692_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov7692_v4l2.c
@@ -585,7 +585,8 @@
 static struct msm_camera_i2c_reg_conf ov7692_wb_oem[][4] = {
 	{{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
 		{-1, -1, -1},},/*WHITEBALNACE OFF*/
-	{{0x13, 0xf7}, {0x15, 0x00},},		/*WHITEBALNACE AUTO*/
+	{{0x13, 0xf7}, {0x15, 0x00}, {-1, -1, -1},
+		{-1, -1, -1},}, /*WHITEBALNACE AUTO*/
 	{{0x13, 0xf5}, {0x01, 0x56}, {0x02, 0x50},
 		{0x15, 0x00},},	/*WHITEBALNACE CUSTOM*/
 	{{0x13, 0xf5}, {0x01, 0x66}, {0x02, 0x40},
@@ -861,44 +862,6 @@
 	.video  = &ov7692_subdev_video_ops,
 };
 
-int32_t ov7692_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl)
-{
-	int32_t rc = 0;
-	struct msm_camera_sensor_info *info = NULL;
-
-	info = s_ctrl->sensordata;
-	if (info->pmic_gpio_enable) {
-		info->sensor_lcd_gpio_onoff(1);
-		usleep_range(5000, 5100);
-	}
-
-	rc = msm_sensor_power_up(s_ctrl);
-	if (rc < 0) {
-		CDBG("%s: msm_sensor_power_up failed\n", __func__);
-		return rc;
-	}
-
-	return rc;
-}
-
-int32_t ov7692_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl)
-{
-	int32_t rc = 0;
-	struct msm_camera_sensor_info *info = NULL;
-
-	rc = msm_sensor_power_down(s_ctrl);
-	if (rc < 0)
-		CDBG("%s: msm_sensor_power_down failed\n", __func__);
-
-	info = s_ctrl->sensordata;
-	if (info->pmic_gpio_enable) {
-		info->pmic_gpio_enable = 0;
-		info->sensor_lcd_gpio_onoff(0);
-		usleep_range(5000, 5100);
-	}
-	return rc;
-}
-
 static struct msm_sensor_fn_t ov7692_func_tbl = {
 	.sensor_start_stream = msm_sensor_start_stream,
 	.sensor_stop_stream = msm_sensor_stop_stream,
@@ -907,8 +870,8 @@
 	.sensor_mode_init = msm_sensor_mode_init,
 	.sensor_get_output_info = msm_sensor_get_output_info,
 	.sensor_config = msm_sensor_config,
-	.sensor_power_up = ov7692_sensor_power_up,
-	.sensor_power_down = ov7692_sensor_power_down,
+	.sensor_power_up = msm_sensor_power_up,
+	.sensor_power_down = msm_sensor_power_down,
 	.sensor_get_csi_params = msm_sensor_get_csi_params,
 };
 
diff --git a/drivers/media/video/msm/sensors/ov8825_v4l2.c b/drivers/media/video/msm/sensors/ov8825_v4l2.c
index bb846e9..9f09208 100644
--- a/drivers/media/video/msm/sensors/ov8825_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov8825_v4l2.c
@@ -808,33 +808,12 @@
 	{ }
 };
 
-int32_t ov8825_sensor_i2c_probe(struct i2c_client *client,
-		const struct i2c_device_id *id)
-{
-	int32_t rc = 0;
-	struct msm_sensor_ctrl_t *s_ctrl;
-
-	CDBG("\n in ov8825_sensor_i2c_probe\n");
-	rc = msm_sensor_i2c_probe(client, id);
-	if (client->dev.platform_data == NULL) {
-		pr_err("%s: NULL sensor data\n", __func__);
-		return -EFAULT;
-	}
-	s_ctrl = client->dev.platform_data;
-	if (s_ctrl->sensordata->pmic_gpio_enable)
-		lcd_camera_power_onoff(0);
-	return rc;
-}
-
 int32_t ov8825_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl)
 {
 	int32_t rc = 0;
 	struct msm_camera_sensor_info *info = NULL;
+
 	info = s_ctrl->sensordata;
-	if (info->pmic_gpio_enable) {
-		info->pmic_gpio_enable = 0;
-		lcd_camera_power_onoff(1);
-	}
 	gpio_direction_output(info->sensor_pwd, 0);
 	gpio_direction_output(info->sensor_reset, 0);
 	usleep_range(10000, 11000);
@@ -853,7 +832,7 @@
 
 static struct i2c_driver ov8825_i2c_driver = {
 	.id_table = ov8825_i2c_id,
-	.probe  = ov8825_sensor_i2c_probe,
+	.probe  = msm_sensor_i2c_probe,
 	.driver = {
 		.name = SENSOR_NAME,
 	},
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index fc1e713..dfa7fbe 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -1435,20 +1435,379 @@
 	}
 
 	return;
-}

-

-void msm_cam_release_subdev_node(struct video_device *vdev)

-{

-	struct v4l2_subdev *sd = video_get_drvdata(vdev);

-	sd->devnode = NULL;

-	kfree(vdev);

+}
+
+void msm_cam_release_subdev_node(struct video_device *vdev)
+{
+	struct v4l2_subdev *sd = video_get_drvdata(vdev);
+	sd->devnode = NULL;
+	kfree(vdev);
+}
+
+/* Helper function to get the irq_idx corresponding
+ * to the irq_num. */
+int get_irq_idx_from_irq_num(int irq_num)
+{
+	int i;
+	for (i = 0; i < CAMERA_SS_IRQ_MAX; i++)
+		if (irq_num == g_server_dev.hw_irqmap[i].irq_num)
+			return g_server_dev.hw_irqmap[i].irq_idx;
+
+	return -EINVAL;
+}
+
+static irqreturn_t msm_camera_server_parse_irq(int irq_num, void *data)
+{
+	unsigned long flags;
+	int irq_idx, i, rc;
+	u32 status = 0;
+	struct intr_table_entry *ind_irq_tbl;
+	struct intr_table_entry *comp_irq_tbl;
+	bool subdev_handled = 0;
+
+	irq_idx = get_irq_idx_from_irq_num(irq_num);
+	if (irq_idx < 0) {
+		pr_err("server_parse_irq: no clients for irq #%d. returning ",
+			irq_num);
+		return IRQ_HANDLED;
+	}
+
+	spin_lock_irqsave(&g_server_dev.intr_table_lock, flags);
+	ind_irq_tbl = &g_server_dev.irq_lkup_table.ind_intr_tbl[0];
+	comp_irq_tbl = &g_server_dev.irq_lkup_table.comp_intr_tbl[0];
+	if (ind_irq_tbl[irq_idx].is_composite) {
+		for (i = 0; i < comp_irq_tbl[irq_idx].num_hwcore; i++) {
+			if (comp_irq_tbl[irq_idx].subdev_list[i]) {
+				rc = v4l2_subdev_call(
+					comp_irq_tbl[irq_idx].subdev_list[i],
+					core, interrupt_service_routine,
+					status, &subdev_handled);
+				if ((rc < 0) || !subdev_handled) {
+					pr_err("server_parse_irq:Error\n"
+						"handling irq %d rc = %d",
+						irq_num, rc);
+					/* Dispatch the irq to the remaining
+					 * subdevs in the list. */
+					continue;
+				}
+			}
+		}
+	} else {
+		rc = v4l2_subdev_call(ind_irq_tbl[irq_idx].subdev_list[0],
+			core, interrupt_service_routine,
+			status, &subdev_handled);
+		if ((rc < 0) || !subdev_handled) {
+			pr_err("server_parse_irq: Error handling irq %d rc = %d",
+				irq_num, rc);
+			spin_unlock_irqrestore(&g_server_dev.intr_table_lock,
+				flags);
+			return IRQ_HANDLED;
+		}
+	}
+	spin_unlock_irqrestore(&g_server_dev.intr_table_lock, flags);
+	return IRQ_HANDLED;
+}
+
+/* Helper function to get the irq_idx corresponding
+ * to the camera hwcore. This function should _only_
+ * be invoked when the IRQ Router is configured
+ * non-composite mode. */
+int get_irq_idx_from_camhw_idx(int cam_hw_idx)
+{
+	int i;
+	for (i = 0; i < MSM_CAM_HW_MAX; i++)
+		if (cam_hw_idx == g_server_dev.hw_irqmap[i].cam_hw_idx)
+			return g_server_dev.hw_irqmap[i].irq_idx;
+
+	return -EINVAL;
+}
+
+static inline void update_compirq_subdev_info(
+	struct intr_table_entry *irq_entry,
+	uint32_t cam_hw_mask, uint8_t cam_hw_id,
+	int *num_hwcore)
+{
+	if (cam_hw_mask & (0x1 << cam_hw_id)) {
+		/* If the mask has been set for this cam hwcore
+		 * update the subdev ptr......*/
+		irq_entry->subdev_list[cam_hw_id] =
+			g_server_dev.subdev_table[cam_hw_id];
+		(*num_hwcore)++;
+	} else {
+		/*....else, just clear it, so that the irq will
+		 * not be dispatched to this hw. */
+		irq_entry->subdev_list[cam_hw_id] = NULL;
+	}
+}
+
+static int msm_server_update_composite_irq_info(
+	struct intr_table_entry *irq_req)
+{
+	int num_hwcore = 0, rc = 0;
+	struct intr_table_entry *comp_irq_tbl =
+		&g_server_dev.irq_lkup_table.comp_intr_tbl[0];
+
+	comp_irq_tbl[irq_req->irq_idx].is_composite = 1;
+	comp_irq_tbl[irq_req->irq_idx].irq_trigger_type =
+		irq_req->irq_trigger_type;
+	comp_irq_tbl[irq_req->irq_idx].num_hwcore = irq_req->num_hwcore;
+
+	update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+		irq_req->cam_hw_mask, MSM_CAM_HW_MICRO, &num_hwcore);
+
+	update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+		irq_req->cam_hw_mask, MSM_CAM_HW_CCI, &num_hwcore);
+
+	update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+		irq_req->cam_hw_mask, MSM_CAM_HW_CSI0, &num_hwcore);
+
+	update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+		irq_req->cam_hw_mask, MSM_CAM_HW_CSI1, &num_hwcore);
+
+	update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+		irq_req->cam_hw_mask, MSM_CAM_HW_CSI2, &num_hwcore);
+
+	update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+		irq_req->cam_hw_mask, MSM_CAM_HW_CSI3, &num_hwcore);
+
+	update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+		irq_req->cam_hw_mask, MSM_CAM_HW_ISPIF, &num_hwcore);
+
+	update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+		irq_req->cam_hw_mask, MSM_CAM_HW_CPP, &num_hwcore);
+
+	update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+		irq_req->cam_hw_mask, MSM_CAM_HW_VFE0, &num_hwcore);
+
+	update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+		irq_req->cam_hw_mask, MSM_CAM_HW_VFE1, &num_hwcore);
+
+	update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+		irq_req->cam_hw_mask, MSM_CAM_HW_JPEG0, &num_hwcore);
+
+	update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+		irq_req->cam_hw_mask, MSM_CAM_HW_JPEG1, &num_hwcore);
+
+	update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+		irq_req->cam_hw_mask, MSM_CAM_HW_JPEG2, &num_hwcore);
+
+	if (num_hwcore != irq_req->num_hwcore) {
+		pr_warn("%s Mismatch!! requested cam hwcores: %d, Mask set %d",
+			__func__, irq_req->num_hwcore, num_hwcore);
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+int msm_cam_server_request_irq(void *arg)
+{
+	unsigned long flags;
+	int rc = 0;
+	struct intr_table_entry *irq_req =  (struct intr_table_entry *)arg;
+	struct intr_table_entry *ind_irq_tbl =
+		&g_server_dev.irq_lkup_table.ind_intr_tbl[0];
+	struct intr_table_entry *comp_irq_tbl =
+		&g_server_dev.irq_lkup_table.comp_intr_tbl[0];
+
+	if (!irq_req || !irq_req->irq_num || !irq_req->num_hwcore) {
+		pr_err("%s Invalid input ", __func__);
+		return -EINVAL;
+	}
+
+	if (!g_server_dev.irqr_device) {
+		/* This either means, the current target does not
+		 * have a IRQ Router hw or the IRQ Router device is
+		 * not probed yet. The latter should not happen.
+		 * In any case, just return back without updating
+		 * the interrupt lookup table. */
+		pr_info("%s IRQ Router hw is not present. ", __func__);
+		return -ENXIO;
+	}
+
+	if (irq_req->is_composite) {
+		if (irq_req->irq_idx >= CAMERA_SS_IRQ_0 &&
+				irq_req->irq_idx < CAMERA_SS_IRQ_MAX) {
+			spin_lock_irqsave(&g_server_dev.intr_table_lock, flags);
+			/* Update the composite irq information into
+			 * the composite irq lookup table.... */
+			if (msm_server_update_composite_irq_info(irq_req)) {
+				pr_err("%s Invalid configuration", __func__);
+				spin_unlock_irqrestore(
+					&g_server_dev.intr_table_lock, flags);
+				return -EINVAL;
+			}
+			spin_unlock_irqrestore(&g_server_dev.intr_table_lock,
+				flags);
+			/*...and then update the corresponding entry
+			 * in the individual irq lookup table to indicate
+			 * that this IRQ is a composite irq and needs to be
+			 * sent to multiple subdevs. */
+			ind_irq_tbl[irq_req->irq_idx].is_composite = 1;
+			rc = request_irq(comp_irq_tbl[irq_req->irq_idx].irq_num,
+				msm_camera_server_parse_irq,
+				irq_req->irq_trigger_type,
+				ind_irq_tbl[irq_req->irq_idx].dev_name,
+				ind_irq_tbl[irq_req->irq_idx].data);
+			if (rc < 0) {
+				pr_err("%s: request_irq failed for %s\n",
+					__func__, irq_req->dev_name);
+				return -EBUSY;
+			}
+		} else {
+			pr_err("%s Invalid irq_idx %d ",
+				__func__, irq_req->irq_idx);
+			return -EINVAL;
+		}
+	} else {
+		if (irq_req->cam_hw_idx >= MSM_CAM_HW_MICRO &&
+				irq_req->cam_hw_idx < MSM_CAM_HW_MAX) {
+			/* Update the irq information into
+			 * the individual irq lookup table.... */
+			irq_req->irq_idx =
+				get_irq_idx_from_camhw_idx(irq_req->cam_hw_idx);
+			if (irq_req->cam_hw_idx < 0) {
+				pr_err("%s Invalid hw index %d ", __func__,
+					irq_req->cam_hw_idx);
+				return -EINVAL;
+			}
+			spin_lock_irqsave(&g_server_dev.intr_table_lock, flags);
+			/* Make sure the composite irq is not configured for
+			 * this IRQ already. */
+			BUG_ON(ind_irq_tbl[irq_req->irq_idx].is_composite);
+
+			ind_irq_tbl[irq_req->irq_idx] = *irq_req;
+			/* irq_num is stored inside the server's hw_irqmap
+			 * during the device subdevice registration. */
+			ind_irq_tbl[irq_req->irq_idx].irq_num =
+			g_server_dev.hw_irqmap[irq_req->irq_idx].irq_num;
+
+			/*...and clear the corresponding entry in the
+			 * compsoite irq lookup table to indicate that this
+			 * IRQ will only be dispatched to single subdev. */
+			memset(&comp_irq_tbl[irq_req->irq_idx], 0,
+					sizeof(struct intr_table_entry));
+			D("%s Saving Entry %d %d %d %p",
+			__func__,
+			ind_irq_tbl[irq_req->cam_hw_idx].irq_num,
+			ind_irq_tbl[irq_req->cam_hw_idx].cam_hw_idx,
+			ind_irq_tbl[irq_req->cam_hw_idx].is_composite,
+			ind_irq_tbl[irq_req->cam_hw_idx].subdev_list[0]);
+
+			spin_unlock_irqrestore(&g_server_dev.intr_table_lock,
+				flags);
+
+			rc = request_irq(ind_irq_tbl[irq_req->irq_idx].irq_num,
+				msm_camera_server_parse_irq,
+				irq_req->irq_trigger_type,
+				ind_irq_tbl[irq_req->irq_idx].dev_name,
+				ind_irq_tbl[irq_req->irq_idx].data);
+			if (rc < 0) {
+				pr_err("%s: request_irq failed for %s\n",
+					__func__, irq_req->dev_name);
+				return -EBUSY;
+			}
+		} else {
+			pr_err("%s Invalid hw index %d ", __func__,
+				irq_req->cam_hw_idx);
+			return -EINVAL;
+		}
+	}
+	D("%s Successfully requested for IRQ for device %s ", __func__,
+		irq_req->dev_name);
+	return rc;
+}
+
+int msm_cam_server_update_irqmap(
+	struct msm_cam_server_irqmap_entry *irqmap_entry)
+{
+	if (!irqmap_entry || (irqmap_entry->irq_idx < CAMERA_SS_IRQ_0 ||
+		irqmap_entry->irq_idx >= CAMERA_SS_IRQ_MAX)) {
+		pr_err("%s Invalid irqmap entry ", __func__);
+		return -EINVAL;
+	}
+	g_server_dev.hw_irqmap[irqmap_entry->irq_idx] = *irqmap_entry;
+	return 0;
+}
+
+static int msm_cam_server_register_subdev(struct v4l2_device *v4l2_dev,
+	struct v4l2_subdev *sd)
+{
+	int rc = 0;
+	struct video_device *vdev;
+
+	if (v4l2_dev == NULL || sd == NULL || !sd->name[0]) {
+		pr_err("%s Invalid input ", __func__);
+		return -EINVAL;
+	}
+
+	rc = v4l2_device_register_subdev(v4l2_dev, sd);
+	if (rc < 0) {
+		pr_err("%s v4l2 subdev register failed for %s ret = %d",
+			__func__, sd->name, rc);
+		return rc;
+	}
+
+	/* Register a device node for every subdev marked with the
+	 * V4L2_SUBDEV_FL_HAS_DEVNODE flag.
+	 */
+	if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))
+		return rc;
+
+	vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
+	if (!vdev) {
+		pr_err("%s Not enough memory ", __func__);
+		rc = -ENOMEM;
+		goto clean_up;
+	}
+
+	video_set_drvdata(vdev, sd);
+	strlcpy(vdev->name, sd->name, sizeof(vdev->name));
+	vdev->v4l2_dev = v4l2_dev;
+	vdev->fops = &v4l2_subdev_fops;
+	vdev->release = msm_cam_release_subdev_node;
+	rc = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
+						  sd->owner);
+	if (rc < 0) {
+		pr_err("%s Error registering video device %s", __func__,
+			sd->name);
+		kfree(vdev);
+		goto clean_up;
+	}
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	sd->entity.info.v4l.major = VIDEO_MAJOR;
+	sd->entity.info.v4l.minor = vdev->minor;
+#endif
+	sd->devnode = vdev;
+	return 0;
+
+clean_up:
+	if (sd->devnode)
+		video_unregister_device(sd->devnode);
+	return rc;
+}
+
+static int msm_cam_server_fill_sdev_irqnum(int cam_hw_idx,
+	int irq_num)
+{
+	int rc = 0, irq_idx;
+	irq_idx = get_irq_idx_from_camhw_idx(cam_hw_idx);
+	if (irq_idx < 0) {
+		pr_err("%s Invalid cam_hw_idx %d ", __func__, cam_hw_idx);
+		rc = -EINVAL;
+	} else {
+		g_server_dev.hw_irqmap[irq_idx].irq_num = irq_num;
+	}
+	return rc;
 }
 
 int msm_cam_register_subdev_node(struct v4l2_subdev *sd,
-	enum msm_cam_subdev_type sdev_type, uint8_t index)
+	struct msm_cam_subdev_info *sd_info)
 {
-	struct video_device *vdev;
-	int err = 0;
+	int err = 0, cam_hw_idx;
+	uint8_t sdev_type, index;
+
+	sdev_type = sd_info->sdev_type;
+	index     = sd_info->sd_index;
 
 	switch (sdev_type) {
 	case CSIPHY_DEV:
@@ -1466,7 +1825,13 @@
 			err = -EINVAL;
 			break;
 		}
+		cam_hw_idx = MSM_CAM_HW_CSI0 + index;
 		g_server_dev.csid_device[index] = sd;
+		if (g_server_dev.irqr_device) {
+			g_server_dev.subdev_table[cam_hw_idx] = sd;
+			err = msm_cam_server_fill_sdev_irqnum(cam_hw_idx,
+				sd_info->irq_num);
+		}
 		break;
 
 	case CSIC_DEV:
@@ -1480,6 +1845,11 @@
 
 	case ISPIF_DEV:
 		g_server_dev.ispif_device = sd;
+		if (g_server_dev.irqr_device) {
+			g_server_dev.subdev_table[cam_hw_idx] = sd;
+			err = msm_cam_server_fill_sdev_irqnum(MSM_CAM_HW_ISPIF,
+				sd_info->irq_num);
+		}
 		break;
 
 	case VFE_DEV:
@@ -1488,7 +1858,13 @@
 			err = -EINVAL;
 			break;
 		}
+		cam_hw_idx = MSM_CAM_HW_VFE0 + index;
 		g_server_dev.vfe_device[index] = sd;
+		if (g_server_dev.irqr_device) {
+			g_server_dev.subdev_table[cam_hw_idx] = sd;
+			err = msm_cam_server_fill_sdev_irqnum(cam_hw_idx,
+				sd_info->irq_num);
+		}
 		break;
 
 	case VPE_DEV:
@@ -1512,6 +1888,9 @@
 	case GESTURE_DEV:
 		g_server_dev.gesture_device = sd;
 		break;
+	case IRQ_ROUTER_DEV:
+		g_server_dev.irqr_device = sd;
+		break;
 	default:
 		break;
 	}
@@ -1519,49 +1898,11 @@
 	if (err < 0)
 		return err;
 
-	err = v4l2_device_register_subdev(&g_server_dev.v4l2_dev, sd);
-	if (err < 0) {
-		pr_err("%s v4l2 subdev register failed for %d ret = %d",
-			__func__, sdev_type, err);
-		return err;
-	}
-
-	/* Register a device node for every subdev marked with the
-	 * V4L2_SUBDEV_FL_HAS_DEVNODE flag.
-	 */
-	if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))
-		return err;
-
-	vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);

-	if (!vdev) {

-		err = -ENOMEM;

-		goto clean_up;

-	}

-

-	video_set_drvdata(vdev, sd);

-	strlcpy(vdev->name, sd->name, sizeof(vdev->name));
-	vdev->v4l2_dev = &g_server_dev.v4l2_dev;
-	vdev->fops = &v4l2_subdev_fops;
-	vdev->release = msm_cam_release_subdev_node;

-	err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
-						  sd->owner);
-	if (err < 0) {

-		kfree(vdev);

-		goto clean_up;

-	}

-#if defined(CONFIG_MEDIA_CONTROLLER)
-	sd->entity.info.v4l.major = VIDEO_MAJOR;

-	sd->entity.info.v4l.minor = vdev->minor;

-#endif
-	sd->devnode = vdev;

-	return 0;
-

-clean_up:

-	if (sd->devnode)

-		video_unregister_device(sd->devnode);

-	return err;

+	err = msm_cam_server_register_subdev(&g_server_dev.v4l2_dev, sd);
+	return err;
 }
 
+
 static int msm_setup_server_dev(struct platform_device *pdev)
 {
 	int rc = -ENODEV, i;
@@ -1604,6 +1945,9 @@
 
 	mutex_init(&g_server_dev.server_lock);
 	mutex_init(&g_server_dev.server_queue_lock);
+	spin_lock_init(&g_server_dev.intr_table_lock);
+	memset(&g_server_dev.irq_lkup_table, 0,
+			sizeof(struct irqmgr_intr_lkup_table));
 	g_server_dev.pcam_active = NULL;
 	g_server_dev.camera_info.num_cameras = 0;
 	atomic_set(&g_server_dev.number_pcam_active, 0);
@@ -1760,16 +2104,20 @@
 
 	struct v4l2_event v4l2_evt;
 	struct msm_isp_event_ctrl *isp_event;
-	isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl), GFP_KERNEL);
-	if (!isp_event) {
-		pr_err("%s Insufficient memory. return", __func__);
-		return -ENOMEM;
-	}
+	void *ctrlcmd_data;
+
 	event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
 	if (!event_qcmd) {
 		pr_err("%s Insufficient memory. return", __func__);
-		kfree(isp_event);
-		return -ENOMEM;
+		rc = -ENOMEM;
+		goto event_qcmd_alloc_fail;
+	}
+
+	isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl), GFP_KERNEL);
+	if (!isp_event) {
+		pr_err("%s Insufficient memory. return", __func__);
+		rc = -ENOMEM;
+		goto isp_event_alloc_fail;
 	}
 
 	D("%s\n", __func__);
@@ -1782,12 +2130,23 @@
 	server_dev->server_queue[out->queue_idx].evt_id =
 		server_dev->server_evt_id;
 	v4l2_evt.type = V4L2_EVENT_PRIVATE_START + ctrl_id;
+	v4l2_evt.id = 0;
 	v4l2_evt.u.data[0] = out->queue_idx;
 	/* setup event object to transfer the command; */
 	isp_event->resptype = MSM_CAM_RESP_V4L2;
 	isp_event->isp_data.ctrl = *out;
 	isp_event->isp_data.ctrl.evt_id = server_dev->server_evt_id;
 
+	if (out->value != NULL && out->length != 0) {
+		ctrlcmd_data = kzalloc(out->length, GFP_KERNEL);
+		if (!ctrlcmd_data) {
+			rc = -ENOMEM;
+			goto ctrlcmd_alloc_fail;
+		}
+		memcpy(ctrlcmd_data, out->value, out->length);
+		isp_event->isp_data.ctrl.value = ctrlcmd_data;
+	}
+
 	atomic_set(&event_qcmd->on_heap, 1);
 	event_qcmd->command = isp_event;
 
@@ -1811,7 +2170,8 @@
 		if (!rc)
 			rc = -ETIMEDOUT;
 		if (rc < 0) {
-			kfree(isp_event);
+			if (++server_dev->server_evt_id == 0)
+				server_dev->server_evt_id++;
 			pr_err("%s: wait_event error %d\n", __func__, rc);
 			return rc;
 		}
@@ -1832,7 +2192,6 @@
 
 	kfree(ctrlcmd);
 	free_qcmd(rcmd);
-	kfree(isp_event);
 	D("%s: rc %d\n", __func__, rc);
 	/* rc is the time elapsed. */
 	if (rc >= 0) {
@@ -1845,6 +2204,13 @@
 			rc = -EINVAL;
 	}
 	return rc;
+
+ctrlcmd_alloc_fail:
+	kfree(isp_event);
+isp_event_alloc_fail:
+	kfree(event_qcmd);
+event_qcmd_alloc_fail:
+	return rc;
 }
 
 int msm_server_close_client(int idx)
diff --git a/drivers/media/video/msm/server/msm_cam_server.h b/drivers/media/video/msm/server/msm_cam_server.h
index 677feaa..8a02d32 100644
--- a/drivers/media/video/msm/server/msm_cam_server.h
+++ b/drivers/media/video/msm/server/msm_cam_server.h
@@ -61,5 +61,7 @@
 	struct v4l2_event_subscription *sub);
 int msm_server_get_crop(struct msm_cam_v4l2_device *pcam,
 	int idx, struct v4l2_crop *crop);
-
+int msm_cam_server_request_irq(void *arg);
+int msm_cam_server_update_irqmap(
+	struct msm_cam_server_irqmap_entry *entry);
 #endif /* _MSM_CAM_SERVER_H */
diff --git a/drivers/media/video/msm/wfd/wfd-ioctl.c b/drivers/media/video/msm/wfd/wfd-ioctl.c
index c198815..68a8a7d 100644
--- a/drivers/media/video/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm/wfd/wfd-ioctl.c
@@ -288,7 +288,7 @@
 		mdp_mregion->ion_handle = enc_mregion->ion_handle;
 
 		rc = ion_map_iommu(wfd_dev->ion_client, mdp_mregion->ion_handle,
-				DISPLAY_DOMAIN, GEN_POOL, SZ_4K,
+				DISPLAY_WRITE_DOMAIN, GEN_POOL, SZ_4K,
 				0, (unsigned long *)&mdp_mregion->paddr,
 				(unsigned long *)&mdp_mregion->size, 0, 0);
 		if (rc) {
@@ -363,7 +363,7 @@
 			if (mpair->mdp->paddr)
 				ion_unmap_iommu(wfd_dev->ion_client,
 						mpair->mdp->ion_handle,
-						DISPLAY_DOMAIN, GEN_POOL);
+						DISPLAY_WRITE_DOMAIN, GEN_POOL);
 
 			if (mpair->enc->paddr)
 				ion_unmap_iommu(wfd_dev->ion_client,
diff --git a/drivers/media/video/msm_vidc/msm_smem.c b/drivers/media/video/msm_vidc/msm_smem.c
index 25b5c5c..bdace3c 100644
--- a/drivers/media/video/msm_vidc/msm_smem.c
+++ b/drivers/media/video/msm_vidc/msm_smem.c
@@ -69,6 +69,8 @@
 	struct ion_handle *hndl;
 	size_t len;
 	int rc = 0;
+	if (size == 0)
+		goto skip_mem_alloc;
 	flags = flags | ION_HEAP(ION_CP_MM_HEAP_ID);
 	hndl = ion_alloc(client->clnt, size, align, flags);
 	if (IS_ERR_OR_NULL(hndl)) {
@@ -96,6 +98,7 @@
 fail_map:
 	ion_free(client->clnt, hndl);
 fail_shared_mem_alloc:
+skip_mem_alloc:
 	return rc;
 }
 
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index 1c646dd..6cd9e6b 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -28,6 +28,7 @@
 #include "msm_smem.h"
 
 #define BASE_DEVICE_NUMBER 32
+#define MAX_EVENTS 30
 
 struct msm_vidc_drv *vidc_driver;
 
@@ -215,21 +216,20 @@
 	int rc;
 	struct buffer_info *bi;
 	struct v4l2_buffer buffer_info;
+	struct v4l2_plane plane;
 	v4l2_inst = get_v4l2_inst(file, NULL);
 	if (b->count == 0) {
 		list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
 			bi = list_entry(ptr, struct buffer_info, list);
 			if (bi->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
 				buffer_info.type = bi->type;
-				buffer_info.m.planes[0].reserved[0] =
-					bi->fd;
-				buffer_info.m.planes[0].reserved[1] =
-					bi->buff_off;
-				buffer_info.m.planes[0].length = bi->size;
-				buffer_info.m.planes[0].m.userptr =
-					bi->uvaddr;
+				plane.reserved[0] = bi->fd;
+				plane.reserved[1] = bi->buff_off;
+				plane.length = bi->size;
+				plane.m.userptr = bi->uvaddr;
+				buffer_info.m.planes = &plane;
 				buffer_info.length = 1;
-				pr_err("Releasing buffer: %d, %d, %d\n",
+				pr_info("Releasing buffer: %d, %d, %d\n",
 				buffer_info.m.planes[0].reserved[0],
 				buffer_info.m.planes[0].reserved[1],
 				buffer_info.m.planes[0].length);
@@ -359,9 +359,7 @@
 				struct v4l2_event_subscription *sub)
 {
 	int rc = 0;
-	if (sub->type == V4L2_EVENT_ALL)
-		sub->type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
-	rc = v4l2_event_subscribe(fh, sub, 0);
+	rc = v4l2_event_subscribe(fh, sub, MAX_EVENTS);
 	return rc;
 }
 
@@ -445,7 +443,7 @@
 	INIT_LIST_HEAD(&core->instances);
 	mutex_init(&core->sync_lock);
 	spin_lock_init(&core->lock);
-	core->base_addr = 0x34f00000;
+	core->base_addr = 0x14f00000;
 	core->state = VIDC_CORE_UNINIT;
 	for (i = SYS_MSG_INDEX(SYS_MSG_START);
 		i <= SYS_MSG_INDEX(SYS_MSG_END); i++) {
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index ed99d35..ec93628 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -348,7 +348,7 @@
 	{
 		.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
 		.name = "H.264 Loop Filter Mode",
-		.type = V4L2_CTRL_TYPE_INTEGER,
+		.type = V4L2_CTRL_TYPE_MENU,
 		.minimum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
 		.maximum = L_MODE,
 		.default_value = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
@@ -375,7 +375,9 @@
 
 static u32 get_frame_size_compressed(int plane, u32 height, u32 width)
 {
-	return ((height + 31) & (~31)) * ((width + 31) & (~31)) * 3/2;
+	int sz = ((height + 31) & (~31)) * ((width + 31) & (~31)) * 3/2;
+	sz = (sz + 4095) & (~4095);
+	return sz;
 }
 
 static struct hal_quantization
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
index a11f817..11fbcf4 100644
--- a/drivers/media/video/msm_vidc/msm_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -186,7 +186,7 @@
 void *vidc_get_userptr(void *alloc_ctx, unsigned long vaddr,
 				unsigned long size, int write)
 {
-	return NULL;
+	return (void *)0xdeadbeef;
 }
 
 void vidc_put_userptr(void *buf_priv)
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index 52f1dca..9b617aa 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -183,21 +183,9 @@
 {
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
-	struct video_device *vdev;
-	struct v4l2_event dqevent;
-	struct msm_vidc_core *core;
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
 		signal_session_msg_receipt(cmd, inst);
-		core = inst->core;
-		if (inst->session_type == MSM_VIDC_ENCODER)
-			vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
-		else
-			vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
-		dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
-		dqevent.u.data[0] = (uint8_t)MSM_VIDC_OPEN_DONE;
-		v4l2_event_queue(vdev, &dqevent);
-		return;
 	} else {
 		pr_err("Failed to get valid response for session init\n");
 	}
@@ -207,24 +195,17 @@
 {
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
-	struct video_device *vdev;
 	struct v4l2_event dqevent;
 	struct msm_vidc_cb_event *event_notify;
-	struct msm_vidc_core *core;
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
-		core = inst->core;
-		if (inst->session_type == MSM_VIDC_ENCODER)
-			vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
-		else
-			vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
-		dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
-		dqevent.u.data[0] = (uint8_t)MSM_VIDC_DECODER_EVENT_CHANGE;
+		dqevent.type = V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED;
+		dqevent.id = 0;
 		event_notify = (struct msm_vidc_cb_event *) response->data;
 		inst->reconfig_height = event_notify->height;
 		inst->reconfig_width = event_notify->width;
 		inst->in_reconfig = true;
-		v4l2_event_queue(vdev, &dqevent);
+		v4l2_event_queue_fh(&inst->event_handler, &dqevent);
 		return;
 	} else {
 		pr_err("Failed to get valid response for event_change\n");
@@ -262,20 +243,9 @@
 {
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
-	struct video_device *vdev;
-	struct v4l2_event dqevent;
-	struct msm_vidc_core *core;
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
 		signal_session_msg_receipt(cmd, inst);
-		core = inst->core;
-		if (inst->session_type == MSM_VIDC_ENCODER)
-			vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
-		else
-			vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
-		dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
-		dqevent.u.data[0] = (uint8_t)MSM_VIDC_START_DONE;
-		v4l2_event_queue(vdev, &dqevent);
 	} else {
 		pr_err("Failed to get valid response for start\n");
 	}
@@ -285,20 +255,9 @@
 {
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
-	struct video_device *vdev;
-	struct v4l2_event dqevent;
-	struct msm_vidc_core *core;
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
 		signal_session_msg_receipt(cmd, inst);
-		core = inst->core;
-		if (inst->session_type == MSM_VIDC_ENCODER)
-			vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
-		else
-			vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
-		dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
-		dqevent.u.data[0] = (uint8_t)MSM_VIDC_STOP_DONE;
-		v4l2_event_queue(vdev, &dqevent);
 	} else {
 		pr_err("Failed to get valid response for stop\n");
 	}
@@ -320,19 +279,12 @@
 {
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
-	struct video_device *vdev;
 	struct v4l2_event dqevent;
-	struct msm_vidc_core *core;
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
-		core = inst->core;
-		if (inst->session_type == MSM_VIDC_ENCODER)
-			vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
-		else
-			vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
-		dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
-		dqevent.u.data[0] = (uint8_t)MSM_VIDC_DECODER_FLUSH_DONE;
-		v4l2_event_queue(vdev, &dqevent);
+		dqevent.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
+		dqevent.id = 0;
+		v4l2_event_queue_fh(&inst->event_handler, &dqevent);
 	} else {
 		pr_err("Failed to get valid response for flush\n");
 	}
@@ -343,20 +295,13 @@
 {
 	struct msm_vidc_cb_cmd_done *response = data;
 	struct msm_vidc_inst *inst;
-	struct video_device *vdev;
 	struct v4l2_event dqevent;
-	struct msm_vidc_core *core;
 	if (response) {
 		inst = (struct msm_vidc_inst *)response->session_id;
 		signal_session_msg_receipt(cmd, inst);
-		core = inst->core;
-		if (inst->session_type == MSM_VIDC_ENCODER)
-			vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
-		else
-			vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
-		dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
-		dqevent.u.data[0] = (uint8_t)MSM_VIDC_CLOSE_DONE;
-		v4l2_event_queue(vdev, &dqevent);
+		dqevent.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
+		dqevent.id = 0;
+		v4l2_event_queue_fh(&inst->event_handler, &dqevent);
 	} else {
 		pr_err("Failed to get valid response for session close\n");
 	}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index fb1ab58..fb8fbc4 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -75,11 +75,6 @@
 	MSM_VIDC_CORE_UNINIT,
 };
 
-enum vidc_resposes_id {
-	MSM_VIDC_DECODER_FLUSH_DONE = 0x11,
-	MSM_VIDC_DECODER_EVENT_CHANGE,
-};
-
 struct buf_info {
 	struct list_head list;
 	struct vb2_buffer *buf;
diff --git a/drivers/mfd/pm8038-core.c b/drivers/mfd/pm8038-core.c
index 4271a2a..8fef786 100644
--- a/drivers/mfd/pm8038-core.c
+++ b/drivers/mfd/pm8038-core.c
@@ -36,6 +36,9 @@
 #define REG_SPK_BASE		0x253
 #define REG_SPK_REGISTERS	3
 
+#define REG_TEMP_ALARM_CTRL	0x01B
+#define REG_TEMP_ALARM_PWM	0x09B
+
 #define PM8038_VERSION_MASK	0xFFF0
 #define PM8038_VERSION_VALUE	0x09F0
 #define PM8038_REVISION_MASK	0x000F
@@ -300,6 +303,30 @@
 	.pdata_size	= sizeof("pm8038-dbg"),
 };
 
+static const struct resource thermal_alarm_cell_resources[] __devinitconst = {
+	SINGLE_IRQ_RESOURCE("pm8038_tempstat_irq", PM8038_TEMPSTAT_IRQ),
+	SINGLE_IRQ_RESOURCE("pm8038_overtemp_irq", PM8038_OVERTEMP_IRQ),
+};
+
+static struct pm8xxx_tm_core_data thermal_alarm_cdata = {
+	.adc_channel			= CHANNEL_DIE_TEMP,
+	.adc_type			= PM8XXX_TM_ADC_PM8XXX_ADC,
+	.reg_addr_temp_alarm_ctrl	= REG_TEMP_ALARM_CTRL,
+	.reg_addr_temp_alarm_pwm	= REG_TEMP_ALARM_PWM,
+	.tm_name			= "pm8038_tz",
+	.irq_name_temp_stat		= "pm8038_tempstat_irq",
+	.irq_name_over_temp		= "pm8038_overtemp_irq",
+};
+
+static struct mfd_cell thermal_alarm_cell __devinitdata = {
+	.name		= PM8XXX_TM_DEV_NAME,
+	.id		= -1,
+	.resources	= thermal_alarm_cell_resources,
+	.num_resources	= ARRAY_SIZE(thermal_alarm_cell_resources),
+	.platform_data	= &thermal_alarm_cdata,
+	.pdata_size	= sizeof(struct pm8xxx_tm_core_data),
+};
+
 static struct pm8xxx_vreg regulator_data[] = {
 	/*   name	     pc_name	    ctrl   test   hpm_min */
 	NLDO1200("8038_l1",		    0x0AE, 0x0AF, LDO_1200),
@@ -606,6 +633,14 @@
 			goto bail;
 		}
 	}
+
+	ret = mfd_add_devices(pmic->dev, 0, &thermal_alarm_cell, 1, NULL,
+				irq_base);
+	if (ret) {
+		pr_err("Failed to add thermal alarm subdevice ret=%d\n", ret);
+		goto bail;
+	}
+
 	return 0;
 bail:
 	if (pmic->irq_chip) {
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index bbb2509..021dcf1 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -31,7 +31,8 @@
 #define WCD9XXX_SLIM_RW_MAX_TRIES 3
 
 #define MAX_WCD9XXX_DEVICE	4
-#define WCD9XXX_I2C_MODE	0x03
+#define TABLA_I2C_MODE	0x03
+#define SITAR_I2C_MODE	0x01
 
 struct wcd9xxx_i2c {
 	struct i2c_client *client;
@@ -351,15 +352,15 @@
 		 * care of now only tabla.
 		 */
 		pr_debug("%s : Read codec version using I2C\n",	__func__);
-		if (TABLA_IS_1_X(wcd9xxx->version)) {
+		if (!strncmp(wcd9xxx_modules[0].client->name, "sitar", 5)) {
+			wcd9xxx_dev = sitar_devs;
+			wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
+		} else if (TABLA_IS_1_X(wcd9xxx->version)) {
 			wcd9xxx_dev = tabla1x_devs;
 			wcd9xxx_dev_size = ARRAY_SIZE(tabla1x_devs);
 		} else if (TABLA_IS_2_0(wcd9xxx->version)) {
 			wcd9xxx_dev = tabla_devs;
 			wcd9xxx_dev_size = ARRAY_SIZE(tabla_devs);
-		} else {
-			wcd9xxx_dev = sitar_devs;
-			wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
 		}
 	}
 
@@ -712,8 +713,10 @@
 	struct wcd9xxx_pdata *pdata = client->dev.platform_data;
 	int val = 0;
 	int ret = 0;
+	int i2c_mode = 0;
 	static int device_id;
 
+	pr_info("%s\n", __func__);
 	if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
 		pr_info("tabla card is already detected in slimbus mode\n");
 		return -ENODEV;
@@ -765,10 +768,13 @@
 
 	/*read the tabla status before initializing the device type*/
 	ret = wcd9xxx_read(wcd9xxx, WCD9XXX_A_CHIP_STATUS, 1, &val, 0);
-	if ((ret < 0) || (val != WCD9XXX_I2C_MODE)) {
-		pr_err("failed to read the wcd9xxx status\n");
-		goto err_device_init;
-	}
+	if (!strncmp(wcd9xxx_modules[0].client->name, "sitar", 5))
+		i2c_mode = SITAR_I2C_MODE;
+	else if (!strncmp(wcd9xxx_modules[0].client->name, "tabla", 5))
+		i2c_mode = TABLA_I2C_MODE;
+
+	if ((ret < 0) || (val != i2c_mode))
+		pr_err("failed to read the wcd9xxx status ret = %d\n", ret);
 
 	ret = wcd9xxx_device_init(wcd9xxx, wcd9xxx->irq);
 	if (ret) {
@@ -1107,16 +1113,25 @@
 	.suspend = wcd9xxx_slim_suspend,
 };
 
-#define TABLA_I2C_TOP_LEVEL 0
-#define TABLA_I2C_ANALOG       1
-#define TABLA_I2C_DIGITAL_1    2
-#define TABLA_I2C_DIGITAL_2    3
+#define WCD9XXX_I2C_TOP_LEVEL	0
+#define WCD9XXX_I2C_ANALOG	1
+#define WCD9XXX_I2C_DIGITAL_1	2
+#define WCD9XXX_I2C_DIGITAL_2	3
 
 static struct i2c_device_id tabla_id_table[] = {
-	{"tabla top level", TABLA_I2C_TOP_LEVEL},
-	{"tabla analog", TABLA_I2C_TOP_LEVEL},
-	{"tabla digital1", TABLA_I2C_TOP_LEVEL},
-	{"tabla digital2", TABLA_I2C_TOP_LEVEL},
+	{"tabla top level", WCD9XXX_I2C_TOP_LEVEL},
+	{"tabla analog", WCD9XXX_I2C_ANALOG},
+	{"tabla digital1", WCD9XXX_I2C_DIGITAL_1},
+	{"tabla digital2", WCD9XXX_I2C_DIGITAL_2},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, tabla_id_table);
+
+static struct i2c_device_id sitar_id_table[] = {
+	{"sitar top level", WCD9XXX_I2C_TOP_LEVEL},
+	{"sitar analog", WCD9XXX_I2C_ANALOG},
+	{"sitar digital1", WCD9XXX_I2C_DIGITAL_1},
+	{"sitar digital2", WCD9XXX_I2C_DIGITAL_2},
 	{}
 };
 MODULE_DEVICE_TABLE(i2c, tabla_id_table);
@@ -1133,9 +1148,21 @@
 	.suspend = wcd9xxx_i2c_suspend,
 };
 
+static struct i2c_driver sitar_i2c_driver = {
+	.driver                 = {
+		.owner          =       THIS_MODULE,
+		.name           =       "sitar-i2c-core",
+	},
+	.id_table               =       sitar_id_table,
+	.probe                  =       wcd9xxx_i2c_probe,
+	.remove                 =       __devexit_p(wcd9xxx_i2c_remove),
+	.resume	= wcd9xxx_i2c_resume,
+	.suspend = wcd9xxx_i2c_suspend,
+};
+
 static int __init wcd9xxx_init(void)
 {
-	int ret1, ret2, ret3, ret4, ret5;
+	int ret1, ret2, ret3, ret4, ret5, ret6;
 
 	ret1 = slim_driver_register(&tabla_slim_driver);
 	if (ret1 != 0)
@@ -1157,7 +1184,11 @@
 	if (ret5 != 0)
 		pr_err("Failed to register sitar SB driver: %d\n", ret5);
 
-	return (ret1 && ret2 && ret3 && ret4 && ret5) ? -1 : 0;
+	ret6 = i2c_add_driver(&sitar_i2c_driver);
+	if (ret6 != 0)
+		pr_err("failed to add the I2C driver\n");
+
+	return (ret1 && ret2 && ret3 && ret4 && ret5 && ret6) ? -1 : 0;
 }
 module_init(wcd9xxx_init);
 
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index a21b39d..b5ffe94 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1455,7 +1455,15 @@
 		err = mmc_poweroff_notify(host, MMC_PW_OFF_NOTIFY_SHORT);
 	} else {
 		if (mmc_card_can_sleep(host))
-			err = mmc_card_sleep(host);
+			/*
+			 * If sleep command has error it doesn't mean host
+			 * cannot suspend, but a deeper low power state
+			 * transition for the card has failed. Ignore
+			 * sleep errors so that the suspend is not aborted.
+			 * In error case, mmc_resume() takes care of
+			 * complete intialization of the card.
+			 */
+			mmc_card_sleep(host);
 		else if (!mmc_host_is_spi(host))
 			mmc_deselect_cards(host);
 	}
@@ -1512,7 +1520,7 @@
 	if (card && card->ext_csd.rev >= 3) {
 		err = mmc_card_sleepawake(host, 1);
 		if (err < 0)
-			pr_debug("%s: Error %d while putting card into sleep",
+			pr_warn("%s: Error %d while putting card into sleep",
 				 mmc_hostname(host), err);
 	}
 
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index e9ccbc7..edf4400 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -3062,7 +3062,7 @@
 				msleep(300);
 				status = gpio_get_value_cansleep(
 						host->plat->wpswitch_gpio);
-				status ^= !host->plat->wpswitch_polarity;
+				status ^= !host->plat->is_wpswitch_active_low;
 			}
 			gpio_free(host->plat->wpswitch_gpio);
 		}
diff --git a/drivers/net/usb/rmnet_usb_data.c b/drivers/net/usb/rmnet_usb_data.c
index ee9737a..9e1e252 100644
--- a/drivers/net/usb/rmnet_usb_data.c
+++ b/drivers/net/usb/rmnet_usb_data.c
@@ -505,6 +505,7 @@
 {
 	struct usbnet		*unet;
 	struct driver_info	*info;
+	struct usb_device	*udev;
 	unsigned int		iface_num;
 	static int		first_rmnet_iface_num = -EINVAL;
 	int			status = 0;
@@ -555,8 +556,17 @@
 	if (status)
 		dev_dbg(&iface->dev, "mode debugfs file is not available\n");
 
+	udev = unet->udev;
+
 	/* allow modem to wake up suspended system */
-	device_set_wakeup_enable(&unet->udev->dev, 1);
+	device_set_wakeup_enable(&udev->dev, 1);
+
+	/* set default autosuspend timeout for modem and roothub */
+	if (udev->parent && !udev->parent->parent) {
+		pm_runtime_set_autosuspend_delay(&udev->dev, 1000);
+		pm_runtime_set_autosuspend_delay(&udev->parent->dev, 200);
+	}
+
 out:
 	return status;
 }
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index c983389..a1561f0 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -3308,6 +3308,9 @@
 	int rc;
 	int vdd_safe;
 
+	/* forcing 19p2mhz before accessing any charger registers */
+	pm8921_chg_force_19p2mhz_clk(chip);
+
 	rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
 					BOOT_DONE_BIT, BOOT_DONE_BIT);
 	if (rc) {
@@ -3501,8 +3504,6 @@
 	/* Disable EOC FSM processing */
 	pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x91);
 
-	pm8921_chg_force_19p2mhz_clk(chip);
-
 	rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
 						VREF_BATT_THERM_FORCE_ON);
 	if (rc)
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 8b1d5e6..e569132 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -1016,13 +1016,8 @@
 		send_check_condition = 1;
 		goto attach_cmd;
 	}
-	/*
-	 * The Initiator Node has access to the LUN (the addressing method
-	 * is handled inside of iscsit_get_lun_for_cmd()).  Now it's time to
-	 * allocate 1->N transport tasks (depending on sector count and
-	 * maximum request size the physical HBA(s) can handle.
-	 */
-	transport_ret = transport_generic_allocate_tasks(&cmd->se_cmd, hdr->cdb);
+
+	transport_ret = target_setup_cmd_from_cdb(&cmd->se_cmd, hdr->cdb);
 	if (transport_ret == -ENOMEM) {
 		return iscsit_add_reject_from_cmd(
 				ISCSI_REASON_BOOKMARK_NO_RESOURCES,
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c
index a9b4eee..38dfac2 100644
--- a/drivers/target/loopback/tcm_loop.c
+++ b/drivers/target/loopback/tcm_loop.c
@@ -213,7 +213,7 @@
 	 * associated read buffers, go ahead and do that here for type
 	 * SCF_SCSI_CONTROL_SG_IO_CDB.  Also note that this is currently
 	 * guaranteed to be a single SGL for SCF_SCSI_CONTROL_SG_IO_CDB
-	 * by target core in transport_generic_allocate_tasks() ->
+	 * by target core in target_setup_cmd_from_cdb() ->
 	 * transport_generic_cmd_sequencer().
 	 */
 	if (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB &&
@@ -227,7 +227,7 @@
 		}
 	}
 
-	ret = transport_generic_allocate_tasks(se_cmd, sc->cmnd);
+	ret = target_setup_cmd_from_cdb(se_cmd, sc->cmnd);
 	if (ret == -ENOMEM) {
 		transport_send_check_condition_and_sense(se_cmd,
 				TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 443704f..843ad54 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -1550,11 +1550,11 @@
 	return 0;
 }
 
-/*	transport_generic_allocate_tasks():
+/*	target_setup_cmd_from_cdb():
  *
  *	Called from fabric RX Thread.
  */
-int transport_generic_allocate_tasks(
+int target_setup_cmd_from_cdb(
 	struct se_cmd *cmd,
 	unsigned char *cdb)
 {
@@ -1620,7 +1620,7 @@
 	spin_unlock(&cmd->se_lun->lun_sep_lock);
 	return 0;
 }
-EXPORT_SYMBOL(transport_generic_allocate_tasks);
+EXPORT_SYMBOL(target_setup_cmd_from_cdb);
 
 /*
  * Used by fabric module frontends to queue tasks directly.
@@ -1701,6 +1701,8 @@
 	 */
 	transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess,
 				data_length, data_dir, task_attr, sense);
+	if (flags & TARGET_SCF_UNKNOWN_SIZE)
+		se_cmd->unknown_data_length = 1;
 	/*
 	 * Obtain struct se_cmd->cmd_kref reference and add new cmd to
 	 * se_sess->sess_cmd_list.  A second kref_get here is necessary
@@ -1726,7 +1728,7 @@
 	 * Sanitize CDBs via transport_generic_cmd_sequencer() and
 	 * allocate the necessary tasks to complete the received CDB+data
 	 */
-	rc = transport_generic_allocate_tasks(se_cmd, cdb);
+	rc = target_setup_cmd_from_cdb(se_cmd, cdb);
 	if (rc != 0) {
 		transport_generic_request_failure(se_cmd);
 		return;
@@ -2581,7 +2583,7 @@
  *	Generic Command Sequencer that should work for most DAS transport
  *	drivers.
  *
- *	Called from transport_generic_allocate_tasks() in the $FABRIC_MOD
+ *	Called from target_setup_cmd_from_cdb() in the $FABRIC_MOD
  *	RX Thread.
  *
  *	FIXME: Need to support other SCSI OPCODES where as well.
@@ -3142,6 +3144,9 @@
 		goto out_unsupported_cdb;
 	}
 
+	if (cmd->unknown_data_length)
+		cmd->data_length = size;
+
 	if (size != cmd->data_length) {
 		pr_warn("TARGET_CORE[%s]: Expected Transfer Length:"
 			" %u does not match SCSI CDB Length: %u for SAM Opcode:"
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index fbe0dd7..d99a02a 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -66,6 +66,7 @@
 config THERMAL_MONITOR
 	bool "Monitor thermal state and limit CPU Frequency"
 	depends on THERMAL_TSENS8960
+	depends on CPU_FREQ_MSM
 	default n
 	help
 	  This enables thermal monitoring capability in the kernel in the
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index e0d8d14..a8d3720 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -14,60 +14,51 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/cpufreq.h>
 #include <linux/mutex.h>
 #include <linux/msm_tsens.h>
 #include <linux/workqueue.h>
 #include <linux/cpu.h>
-
-#define DEF_TEMP_SENSOR      0
-#define DEF_THERMAL_CHECK_MS 1000
-#define DEF_ALLOWED_MAX_HIGH 60
-#define DEF_ALLOWED_MAX_FREQ 918000
+#include <linux/cpufreq.h>
+#include <linux/msm_tsens.h>
+#include <linux/msm_thermal.h>
+#include <mach/cpufreq.h>
 
 static int enabled;
-static int allowed_max_high = DEF_ALLOWED_MAX_HIGH;
-static int allowed_max_low = (DEF_ALLOWED_MAX_HIGH - 10);
-static int allowed_max_freq = DEF_ALLOWED_MAX_FREQ;
-static int check_interval_ms = DEF_THERMAL_CHECK_MS;
-
-module_param(allowed_max_high, int, 0);
-module_param(allowed_max_freq, int, 0);
-module_param(check_interval_ms, int, 0);
-
+static struct msm_thermal_data msm_thermal_info;
+static uint32_t limited_max_freq = MSM_CPUFREQ_NO_LIMIT;
 static struct delayed_work check_temp_work;
 
-static int update_cpu_max_freq(struct cpufreq_policy *cpu_policy,
-			       int cpu, int max_freq)
+static int update_cpu_max_freq(int cpu, uint32_t max_freq)
 {
 	int ret = 0;
 
-	if (!cpu_policy)
-		return -EINVAL;
-
-	cpufreq_verify_within_limits(cpu_policy,
-				cpu_policy->min, max_freq);
-	cpu_policy->user_policy.max = max_freq;
+	ret = msm_cpufreq_set_freq_limits(cpu, MSM_CPUFREQ_NO_LIMIT, max_freq);
+	if (ret)
+		return ret;
 
 	ret = cpufreq_update_policy(cpu);
-	if (!ret)
-		pr_info("msm_thermal: Limiting core%d max frequency to %d\n",
-			cpu, max_freq);
+	if (ret)
+		return ret;
+
+	limited_max_freq = max_freq;
+	if (max_freq != MSM_CPUFREQ_NO_LIMIT)
+		pr_info("msm_thermal: Limiting cpu%d max frequency to %d\n",
+				cpu, max_freq);
+	else
+		pr_info("msm_thermal: Max frequency reset for cpu%d\n", cpu);
 
 	return ret;
 }
 
 static void check_temp(struct work_struct *work)
 {
-	struct cpufreq_policy *cpu_policy = NULL;
 	struct tsens_device tsens_dev;
 	unsigned long temp = 0;
-	unsigned int max_freq = 0;
-	int update_policy = 0;
+	uint32_t max_freq = limited_max_freq;
 	int cpu = 0;
 	int ret = 0;
 
-	tsens_dev.sensor_num = DEF_TEMP_SENSOR;
+	tsens_dev.sensor_num = msm_thermal_info.sensor_id;
 	ret = tsens_get_temp(&tsens_dev, &temp);
 	if (ret) {
 		pr_debug("msm_thermal: Unable to read TSENS sensor %d\n",
@@ -75,61 +66,42 @@
 		goto reschedule;
 	}
 
+	if (temp >= msm_thermal_info.limit_temp)
+		max_freq = msm_thermal_info.limit_freq;
+	else if (temp <
+		msm_thermal_info.limit_temp - msm_thermal_info.temp_hysteresis)
+		max_freq = MSM_CPUFREQ_NO_LIMIT;
+
+	if (max_freq == limited_max_freq)
+		goto reschedule;
+
+	/* Update new limits */
 	for_each_possible_cpu(cpu) {
-		update_policy = 0;
-		cpu_policy = cpufreq_cpu_get(cpu);
-		if (!cpu_policy) {
-			pr_debug("msm_thermal: NULL policy on cpu %d\n", cpu);
-			continue;
-		}
-		if (temp >= allowed_max_high) {
-			if (cpu_policy->max > allowed_max_freq) {
-				update_policy = 1;
-				max_freq = allowed_max_freq;
-			} else {
-				pr_debug("msm_thermal: policy max for cpu %d "
-					 "already < allowed_max_freq\n", cpu);
-			}
-		} else if (temp < allowed_max_low) {
-			if (cpu_policy->max < cpu_policy->cpuinfo.max_freq) {
-				max_freq = cpu_policy->cpuinfo.max_freq;
-				update_policy = 1;
-			} else {
-				pr_debug("msm_thermal: policy max for cpu %d "
-					 "already at max allowed\n", cpu);
-			}
-		}
-
-		if (update_policy)
-			update_cpu_max_freq(cpu_policy, cpu, max_freq);
-
-		cpufreq_cpu_put(cpu_policy);
+		ret = update_cpu_max_freq(cpu, max_freq);
+		if (ret)
+			pr_debug("Unable to limit cpu%d max freq to %d\n",
+					cpu, max_freq);
 	}
 
 reschedule:
 	if (enabled)
 		schedule_delayed_work(&check_temp_work,
-				msecs_to_jiffies(check_interval_ms));
+				msecs_to_jiffies(msm_thermal_info.poll_ms));
 }
 
 static void disable_msm_thermal(void)
 {
 	int cpu = 0;
-	struct cpufreq_policy *cpu_policy = NULL;
 
 	/* make sure check_temp is no longer running */
 	cancel_delayed_work(&check_temp_work);
 	flush_scheduled_work();
 
+	if (limited_max_freq == MSM_CPUFREQ_NO_LIMIT)
+		return;
+
 	for_each_possible_cpu(cpu) {
-		cpu_policy = cpufreq_cpu_get(cpu);
-		if (cpu_policy) {
-			if (cpu_policy->max < cpu_policy->cpuinfo.max_freq)
-				update_cpu_max_freq(cpu_policy, cpu,
-						    cpu_policy->
-						    cpuinfo.max_freq);
-			cpufreq_cpu_put(cpu_policy);
-		}
+		update_cpu_max_freq(cpu, MSM_CPUFREQ_NO_LIMIT);
 	}
 }
 
@@ -156,16 +128,17 @@
 module_param_cb(enabled, &module_ops, &enabled, 0644);
 MODULE_PARM_DESC(enabled, "enforce thermal limit on cpu");
 
-static int __init msm_thermal_init(void)
+int __init msm_thermal_init(struct msm_thermal_data *pdata)
 {
 	int ret = 0;
 
+	BUG_ON(!pdata);
+	BUG_ON(pdata->sensor_id >= TSENS_MAX_SENSORS);
+	memcpy(&msm_thermal_info, pdata, sizeof(struct msm_thermal_data));
+
 	enabled = 1;
 	INIT_DELAYED_WORK(&check_temp_work, check_temp);
-
 	schedule_delayed_work(&check_temp_work, 0);
 
 	return ret;
 }
-fs_initcall(msm_thermal_init);
-
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 21b9669..083ed19 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -95,6 +95,8 @@
 struct msm_hs_tx {
 	unsigned int tx_ready_int_en;  /* ok to dma more tx */
 	unsigned int dma_in_flight;    /* tx dma in progress */
+	enum flush_reason flush;
+	wait_queue_head_t wait;
 	struct msm_dmov_cmd xfer;
 	dmov_box *command_ptr;
 	u32 *command_ptr_ptr;
@@ -895,7 +897,7 @@
 
 	dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr_ptr,
 				   sizeof(u32), DMA_TO_DEVICE);
-
+	msm_uport->tx.flush = FLUSH_NONE;
 	msm_dmov_enqueue_cmd(msm_uport->dma_tx_channel, &tx->xfer);
 }
 
@@ -1115,9 +1117,13 @@
 {
 	struct msm_hs_port *msm_uport;
 
-	WARN_ON(result != 0x80000002);  /* DMA did not finish properly */
-
 	msm_uport = container_of(cmd_ptr, struct msm_hs_port, tx.xfer);
+	if (msm_uport->tx.flush == FLUSH_STOP)
+		/* DMA FLUSH unsuccesfful */
+		WARN_ON(!(result & DMOV_RSLT_FLUSH));
+	else
+		/* DMA did not finish properly */
+		WARN_ON(!(result & DMOV_RSLT_DONE));
 
 	tasklet_schedule(&msm_uport->tx.tlet);
 }
@@ -1129,6 +1135,12 @@
 				tlet_ptr, struct msm_hs_port, tx.tlet);
 
 	spin_lock_irqsave(&(msm_uport->uport.lock), flags);
+	if (msm_uport->tx.flush == FLUSH_STOP) {
+		msm_uport->tx.flush = FLUSH_SHUTDOWN;
+		wake_up(&msm_uport->tx.wait);
+		spin_unlock_irqrestore(&(msm_uport->uport.lock), flags);
+		return;
+	}
 
 	msm_uport->imr_reg |= UARTDM_ISR_TX_READY_BMSK;
 	msm_hs_write(&(msm_uport->uport), UARTDM_IMR_ADDR, msm_uport->imr_reg);
@@ -1770,6 +1782,7 @@
 	tx->xfer.cmdptr = DMOV_CMD_ADDR(tx->mapped_cmd_ptr_ptr);
 
 	init_waitqueue_head(&rx->wait);
+	init_waitqueue_head(&tx->wait);
 	wake_lock_init(&rx->wake_lock, WAKE_LOCK_SUSPEND, "msm_serial_hs_rx");
 	wake_lock_init(&msm_uport->dma_wake_lock, WAKE_LOCK_SUSPEND,
 		       "msm_serial_hs_dma");
@@ -2043,19 +2056,41 @@
  */
 static void msm_hs_shutdown(struct uart_port *uport)
 {
+	int ret;
+	unsigned int data;
+	unsigned long flags;
 	struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
 
-	BUG_ON(msm_uport->rx.flush < FLUSH_STOP);
+	if (msm_uport->tx.dma_in_flight) {
+		spin_lock_irqsave(&uport->lock, flags);
+		/* disable UART TX interface to DM */
+		data = msm_hs_read(uport, UARTDM_DMEN_ADDR);
+		data &= ~UARTDM_TX_DM_EN_BMSK;
+		msm_hs_write(uport, UARTDM_DMEN_ADDR, data);
+		/* turn OFF UART Transmitter */
+		msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_TX_DISABLE_BMSK);
+		/* reset UART TX */
+		msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX);
+		/* reset UART TX Error */
+		msm_hs_write(uport, UARTDM_CR_ADDR, RESET_TX_ERROR);
+		msm_uport->tx.flush = FLUSH_STOP;
+		spin_unlock_irqrestore(&uport->lock, flags);
+		/* discard flush */
+		msm_dmov_flush(msm_uport->dma_tx_channel, 0);
+		ret = wait_event_timeout(msm_uport->tx.wait,
+			msm_uport->tx.flush == FLUSH_SHUTDOWN, 100);
+		if (!ret)
+			pr_err("%s():HSUART TX Stalls.\n", __func__);
+	}
 	tasklet_kill(&msm_uport->tx.tlet);
+	BUG_ON(msm_uport->rx.flush < FLUSH_STOP);
 	wait_event(msm_uport->rx.wait, msm_uport->rx.flush == FLUSH_SHUTDOWN);
 	tasklet_kill(&msm_uport->rx.tlet);
 	cancel_delayed_work_sync(&msm_uport->rx.flip_insert_work);
-
 	flush_workqueue(msm_uport->hsuart_wq);
 	pm_runtime_disable(uport->dev);
 	pm_runtime_set_suspended(uport->dev);
 
-	mutex_lock(&msm_uport->clk_mutex);
 	/* Disable the transmitter */
 	msm_hs_write(uport, UARTDM_CR_ADDR, UARTDM_CR_TX_DISABLE_BMSK);
 	/* Disable the receiver */
@@ -2068,7 +2103,6 @@
 	 * Hence mb() requires here.
 	 */
 	mb();
-
 	if (msm_uport->clk_state != MSM_HS_CLK_OFF) {
 		/* to balance clk_state */
 		clk_disable_unprepare(msm_uport->clk);
@@ -2076,8 +2110,8 @@
 			clk_disable_unprepare(msm_uport->pclk);
 		wake_unlock(&msm_uport->dma_wake_lock);
 	}
-	msm_uport->clk_state = MSM_HS_CLK_PORT_OFF;
 
+	msm_uport->clk_state = MSM_HS_CLK_PORT_OFF;
 	dma_unmap_single(uport->dev, msm_uport->tx.dma_base,
 			 UART_XMIT_SIZE, DMA_TO_DEVICE);
 
@@ -2088,7 +2122,6 @@
 	free_irq(uport->irq, msm_uport);
 	if (use_low_power_wakeup(msm_uport))
 		free_irq(msm_uport->wakeup.irq, msm_uport);
-	mutex_unlock(&msm_uport->clk_mutex);
 	mutex_destroy(&msm_uport->clk_mutex);
 }
 
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index 742beef..882eb97 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -1,6 +1,6 @@
 config USB_DWC3
 	tristate "DesignWare USB3 DRD Core Support"
-	depends on (USB && USB_GADGET)
+	depends on (USB || USB_GADGET)
 	select USB_OTG_UTILS
 	select USB_GADGET_DUALSPEED
 	select USB_XHCI_PLATFORM
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index 3227508..0b46082 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -1,11 +1,13 @@
 ccflags-$(CONFIG_USB_DWC3_DEBUG)	:= -DDEBUG
 ccflags-$(CONFIG_USB_DWC3_VERBOSE)	+= -DVERBOSE_DEBUG
+ccflags-y += -Idrivers/usb/host
 
 obj-$(CONFIG_USB_DWC3)			+= dwc3.o
 
 dwc3-y					:= core.o
 dwc3-y					+= host.o
 dwc3-y					+= gadget.o ep0.o
+dwc3-y					+= dwc3_otg.o
 
 ifneq ($(CONFIG_DEBUG_FS),)
 	dwc3-y				+= debugfs.o
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 99b58d8..1fbfdd8 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -372,6 +372,32 @@
 
 	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
 
+	/*
+	 * Currently, the default and the recommended value for GUSB3PIPECTL
+	 * [21:19] in the RTL is 3'b100 or 32 consecutive errors. Based on
+	 * analysis and experiments in the lab, it is found that there is a
+	 * relatively low probability of getting 32 consecutive word errors
+	 * in the presence of random recovered noise (during electrical idle).
+	 * This can delay the entry to a low power state such that for
+	 * applications where the link stays in a non-U0 state for a short
+	 * duration (< 1 microsecond), the local PHY does not enter the low
+	 * power state prior to receiving a potential LFPS wakeup. This causes
+	 * the PHY CDR (Clock and Data Recovery) operation to be unstable for
+	 * some Synopsys PHYs.
+	 *
+	 * The proposal now is to change the default and the recommended value
+	 * for GUSB3PIPECTL[21:19] in the RTL from 3'b100 to a minimum of
+	 * 3'b001. Perform the same in software for controllers prior to 2.30a
+	 * revision.
+	 */
+
+	if (dwc->revision < DWC3_REVISION_230A) {
+		reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+		reg &= ~DWC3_GUSB3PIPECTL_DELAY_P1P2P3;
+		reg |= 1 << __ffs(DWC3_GUSB3PIPECTL_DELAY_P1P2P3);
+		dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+	}
+
 	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
 	if (ret) {
 		dev_err(dwc->dev, "failed to allocate event buffers\n");
@@ -410,7 +436,6 @@
 	struct device		*dev = &pdev->dev;
 
 	int			ret = -ENOMEM;
-	int			irq;
 
 	void __iomem		*regs;
 	void			*mem;
@@ -425,16 +450,30 @@
 	dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
 	dwc->mem = mem;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (!res) {
-		dev_err(dev, "missing resource\n");
+		dev_err(dev, "missing IRQ\n");
 		return -ENODEV;
 	}
+	dwc->xhci_resources[1] = *res;
 
-	dwc->res = res;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "missing memory resource\n");
+		return -ENODEV;
+	}
+	dwc->xhci_resources[0] = *res;
+	dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
+					DWC3_XHCI_REGS_END;
 
-	res = devm_request_mem_region(dev, res->start, resource_size(res),
+	 /*
+	  * Request memory region but exclude xHCI regs,
+	  * since it will be requested by the xhci-plat driver.
+	  */
+	res = devm_request_mem_region(dev, res->start + DWC3_GLOBALS_REGS_START,
+			resource_size(res) - DWC3_GLOBALS_REGS_START,
 			dev_name(dev));
+
 	if (!res) {
 		dev_err(dev, "can't request mem region\n");
 		return -ENOMEM;
@@ -446,19 +485,12 @@
 		return -ENOMEM;
 	}
 
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
-		dev_err(dev, "missing IRQ\n");
-		return -ENODEV;
-	}
-
 	spin_lock_init(&dwc->lock);
 	platform_set_drvdata(pdev, dwc);
 
 	dwc->regs	= regs;
 	dwc->regs_size	= resource_size(res);
 	dwc->dev	= dev;
-	dwc->irq	= irq;
 
 	if (!strncmp("super", maximum_speed, 5))
 		dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
@@ -505,15 +537,24 @@
 		break;
 	case DWC3_MODE_DRD:
 		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
+		ret = dwc3_otg_init(dwc);
+		if (ret) {
+			dev_err(dev, "failed to initialize otg\n");
+			goto err1;
+		}
+
 		ret = dwc3_host_init(dwc);
 		if (ret) {
 			dev_err(dev, "failed to initialize host\n");
+			dwc3_otg_exit(dwc);
 			goto err1;
 		}
 
 		ret = dwc3_gadget_init(dwc);
 		if (ret) {
 			dev_err(dev, "failed to initialize gadget\n");
+			dwc3_host_exit(dwc);
+			dwc3_otg_exit(dwc);
 			goto err1;
 		}
 		break;
@@ -542,8 +583,9 @@
 		dwc3_host_exit(dwc);
 		break;
 	case DWC3_MODE_DRD:
-		dwc3_host_exit(dwc);
 		dwc3_gadget_exit(dwc);
+		dwc3_host_exit(dwc);
+		dwc3_otg_exit(dwc);
 		break;
 	default:
 		/* do nothing */
@@ -576,8 +618,9 @@
 		dwc3_host_exit(dwc);
 		break;
 	case DWC3_MODE_DRD:
-		dwc3_host_exit(dwc);
 		dwc3_gadget_exit(dwc);
+		dwc3_host_exit(dwc);
+		dwc3_otg_exit(dwc);
 		break;
 	default:
 		/* do nothing */
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 6c7945b..98adff7 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -50,10 +50,13 @@
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 
+#include "dwc3_otg.h"
+
 /* Global constants */
 #define DWC3_ENDPOINTS_NUM	32
+#define DWC3_XHCI_RESOURCES_NUM	2
 
-#define DWC3_EVENT_BUFFERS_SIZE	PAGE_SIZE
+#define DWC3_EVENT_BUFFERS_SIZE	(2 * PAGE_SIZE)
 #define DWC3_EVENT_TYPE_MASK	0xfe
 
 #define DWC3_EVENT_TYPE_DEV	0
@@ -70,11 +73,22 @@
 #define DWC3_DEVICE_EVENT_ERRATIC_ERROR		9
 #define DWC3_DEVICE_EVENT_CMD_CMPL		10
 #define DWC3_DEVICE_EVENT_OVERFLOW		11
+#define DWC3_DEVICE_EVENT_VENDOR_DEV_TEST_LMP	12
 
 #define DWC3_GEVNTCOUNT_MASK	0xfffc
 #define DWC3_GSNPSID_MASK	0xffff0000
 #define DWC3_GSNPSREV_MASK	0xffff
 
+/* DWC3 registers memory space boundries */
+#define DWC3_XHCI_REGS_START		0x0
+#define DWC3_XHCI_REGS_END		0x7fff
+#define DWC3_GLOBALS_REGS_START		0xc100
+#define DWC3_GLOBALS_REGS_END		0xc6ff
+#define DWC3_DEVICE_REGS_START		0xc700
+#define DWC3_DEVICE_REGS_END		0xcbff
+#define DWC3_OTG_REGS_START		0xcc00
+#define DWC3_OTG_REGS_END		0xccff
+
 /* Global Registers */
 #define DWC3_GSBUSCFG0		0xc100
 #define DWC3_GSBUSCFG1		0xc104
@@ -139,8 +153,9 @@
 /* OTG Registers */
 #define DWC3_OCFG		0xcc00
 #define DWC3_OCTL		0xcc04
-#define DWC3_OEVTEN		0xcc08
-#define DWC3_OSTS		0xcc0C
+#define DWC3_OEVT		0xcc08
+#define DWC3_OEVTEN		0xcc0c
+#define DWC3_OSTS		0xcc10
 
 /* Bit fields */
 
@@ -172,6 +187,7 @@
 /* Global USB3 PIPE Control Register */
 #define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
 #define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
+#define DWC3_GUSB3PIPECTL_DELAY_P1P2P3 (7 << 19)
 
 /* Global TX Fifo Size Register */
 #define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff)
@@ -182,6 +198,9 @@
 #define DWC3_GHWPARAMS1_EN_PWROPT_NO	0
 #define DWC3_GHWPARAMS1_EN_PWROPT_CLK	1
 
+/* Global HWPARAMS6 Register */
+#define DWC3_GHWPARAMS6_SRP_SUPPORT	(1 << 10)
+
 /* Device Configuration Register */
 #define DWC3_DCFG_DEVADDR(addr)	((addr) << 3)
 #define DWC3_DCFG_DEVADDR_MASK	DWC3_DCFG_DEVADDR(0x7f)
@@ -300,6 +319,37 @@
 #define DWC3_DEPCMD_TYPE_BULK		2
 #define DWC3_DEPCMD_TYPE_INTR		3
 
+/* OTG Events Register */
+#define DWC3_OEVT_DEVICEMODE			(1 << 31)
+#define DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT		(1 << 24)
+#define DWC3_OEVTEN_OTGADEVBHOSTENDEVNT		(1 << 20)
+#define DWC3_OEVTEN_OTGADEVHOSTEVNT		(1 << 19)
+#define DWC3_OEVTEN_OTGADEVHNPCHNGEVNT		(1 << 18)
+#define DWC3_OEVTEN_OTGADEVSRPDETEVNT		(1 << 17)
+#define DWC3_OEVTEN_OTGADEVSESSENDDETEVNT	(1 << 16)
+#define DWC3_OEVTEN_OTGBDEVBHOSTENDEVNT		(1 << 11)
+#define DWC3_OEVTEN_OTGBDEVHNPCHNGEVNT		(1 << 10)
+#define DWC3_OEVTEN_OTGBDEVSESSVLDDETEVNT	(1 << 9)
+#define DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT		(1 << 8)
+
+/* OTG OSTS register */
+#define DWC3_OTG_OSTS_OTGSTATE_SHIFT	(8)
+#define DWC3_OTG_OSTS_OTGSTATE		(0xF << DWC3_OTG_OSTS_OTGSTATE_SHIFT)
+#define DWC3_OTG_OSTS_PERIPHERALSTATE	(1 << 4)
+#define DWC3_OTG_OSTS_XHCIPRTPOWER	(1 << 3)
+#define DWC3_OTG_OSTS_BSESVALID		(1 << 2)
+#define DWC3_OTG_OSTS_VBUSVALID		(1 << 1)
+#define DWC3_OTG_OSTS_CONIDSTS		(1 << 0)
+
+/* OTG OSTS register */
+#define DWC3_OTG_OCTL_PERIMODE		(1 << 6)
+#define DWC3_OTG_OCTL_PRTPWRCTL		(1 << 5)
+#define DWC3_OTG_OCTL_HNPREQ		(1 << 4)
+#define DWC3_OTG_OCTL_SESREQ		(1 << 3)
+#define DWC3_OTG_OCTL_TERMSELDLPULSE	(1 << 2)
+#define DWC3_OTG_OCTL_DEVSETHNPEN	(1 << 1)
+#define DWC3_OTG_OCTL_HSTSETHNPEN	(1 << 0)
+
 /* Structures */
 
 struct dwc3_trb;
@@ -582,8 +632,9 @@
 	spinlock_t		lock;
 	struct device		*dev;
 
+	struct dwc3_otg		*dotg;
 	struct platform_device	*xhci;
-	struct resource		*res;
+	struct resource		xhci_resources[DWC3_XHCI_RESOURCES_NUM];
 
 	struct dwc3_event_buffer **ev_buffs;
 	struct dwc3_ep		*eps[DWC3_ENDPOINTS_NUM];
@@ -594,8 +645,6 @@
 	void __iomem		*regs;
 	size_t			regs_size;
 
-	int			irq;
-
 	u32			num_event_buffers;
 	u32			u1u2;
 	u32			maximum_speed;
@@ -609,6 +658,7 @@
 #define DWC3_REVISION_185A	0x5533185a
 #define DWC3_REVISION_188A	0x5533188a
 #define DWC3_REVISION_190A	0x5533190a
+#define DWC3_REVISION_230A	0x5533230a
 
 	unsigned		is_selfpowered:1;
 	unsigned		three_stage_setup:1;
@@ -633,6 +683,12 @@
 
 	u8			test_mode;
 	u8			test_mode_nr;
+
+	/* Indicate if the gadget was powered by the otg driver */
+	bool			vbus_active;
+
+	/* Indicate if software connect was issued by the usb_gadget_driver */
+	bool			softconnect;
 };
 
 /* -------------------------------------------------------------------------- */
@@ -772,6 +828,9 @@
 void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
 int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
 
+int dwc3_otg_init(struct dwc3 *dwc);
+void dwc3_otg_exit(struct dwc3 *dwc);
+
 int dwc3_host_init(struct dwc3 *dwc);
 void dwc3_host_exit(struct dwc3 *dwc);
 
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 5a79cae..d216f17 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -17,6 +17,7 @@
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
 #include <linux/ioport.h>
+#include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -30,6 +31,7 @@
 
 #include <mach/rpm-regulator.h>
 
+#include "dwc3_otg.h"
 #include "core.h"
 #include "gadget.h"
 
@@ -87,6 +89,16 @@
 #define DBM_TRB_DATA_SRC	0x40000000
 #define DBM_TRB_DMA		0x20000000
 #define DBM_TRB_EP_NUM(ep)	(ep<<24)
+/**
+ *  USB QSCRATCH Hardware registers
+ *
+ */
+#define QSCRATCH_REG_OFFSET	(0x000F8800)
+#define CHARGING_DET_CTRL_REG	(QSCRATCH_REG_OFFSET + 0x18)
+#define CHARGING_DET_OUTPUT_REG	(QSCRATCH_REG_OFFSET + 0x1C)
+#define ALT_INTERRUPT_EN_REG	(QSCRATCH_REG_OFFSET + 0x20)
+#define HS_PHY_IRQ_STAT_REG	(QSCRATCH_REG_OFFSET + 0x24)
+
 
 struct dwc3_msm_req_complete {
 	struct list_head list_item;
@@ -104,6 +116,7 @@
 	u8 ep_num_mapping[DBM_MAX_EPS];
 	const struct usb_ep_ops *original_ep_ops[DWC3_ENDPOINTS_NUM];
 	struct list_head req_complete_list;
+	struct clk		*core_clk;
 	struct regulator	*hsusb_3p3;
 	struct regulator	*hsusb_1p8;
 	struct regulator	*hsusb_vddcx;
@@ -111,6 +124,11 @@
 	struct regulator	*ssusb_vddcx;
 	enum usb_vdd_type	ss_vdd_type;
 	enum usb_vdd_type	hs_vdd_type;
+	struct dwc3_charger	charger;
+	struct usb_phy		*otg_xceiv;
+	struct delayed_work	chg_work;
+	enum usb_chg_state	chg_state;
+	u8			dcd_retries;
 };
 
 #define USB_HSPHY_3P3_VOL_MIN		3050000 /* uV */
@@ -150,6 +168,7 @@
 };
 
 static struct dwc3_msm *context;
+static u64 dwc3_msm_dma_mask = DMA_BIT_MASK(64);
 
 /**
  *
@@ -221,6 +240,34 @@
 }
 
 /**
+ * Write register and read back masked value to confirm it is written
+ *
+ * @base - DWC3 base virtual address.
+ * @offset - register offset.
+ * @mask - register bitmask specifying what should be updated
+ * @val - value to write.
+ *
+ */
+static inline void dwc3_msm_write_readback(void *base, u32 offset,
+					    const u32 mask, u32 val)
+{
+	u32 write_val, tmp = ioread32(base + offset);
+
+	tmp &= ~mask;		/* retain other bits */
+	write_val = tmp | val;
+
+	iowrite32(write_val, base + offset);
+
+	/* Read back to see if val was written */
+	tmp = ioread32(base + offset);
+	tmp &= mask;		/* clear other bits */
+
+	if (tmp != val)
+		dev_err(context->dev, "%s: write: %x to QSCRATCH: %x FAILED\n",
+						__func__, val, offset);
+}
+
+/**
  * Return DBM EP number which is not already configured.
  *
  */
@@ -996,6 +1043,184 @@
 	return rc < 0 ? rc : 0;
 }
 
+static void dwc3_chg_enable_secondary_det(struct dwc3_msm *mdwc)
+{
+	u32 chg_ctrl;
+
+	/* Turn off VDP_SRC */
+	dwc3_msm_write_reg(mdwc->base, CHARGING_DET_CTRL_REG, 0x0);
+	msleep(20);
+
+	/* Before proceeding make sure VDP_SRC is OFF */
+	chg_ctrl = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_CTRL_REG);
+	if (chg_ctrl & 0x3F)
+		dev_err(mdwc->dev, "%s Unable to reset chg_det block: %x\n",
+						 __func__, chg_ctrl);
+	/*
+	 * Configure DM as current source, DP as current sink
+	 * and enable battery charging comparators.
+	 */
+	dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x3F, 0x34);
+}
+
+static bool dwc3_chg_det_check_output(struct dwc3_msm *mdwc)
+{
+	u32 chg_det;
+	bool ret = false;
+
+	chg_det = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_OUTPUT_REG);
+	ret = chg_det & 1;
+
+	return ret;
+}
+
+static void dwc3_chg_enable_primary_det(struct dwc3_msm *mdwc)
+{
+	/*
+	 * Configure DP as current source, DM as current sink
+	 * and enable battery charging comparators.
+	 */
+	dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x3F, 0x30);
+}
+
+static inline bool dwc3_chg_check_dcd(struct dwc3_msm *mdwc)
+{
+	u32 chg_state;
+	bool ret = false;
+
+	chg_state = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_OUTPUT_REG);
+	ret = chg_state & 2;
+
+	return ret;
+}
+
+static inline void dwc3_chg_disable_dcd(struct dwc3_msm *mdwc)
+{
+	dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x3F, 0x0);
+}
+
+static inline void dwc3_chg_enable_dcd(struct dwc3_msm *mdwc)
+{
+	/* Data contact detection enable, DCDENB */
+	dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x3F, 0x2);
+}
+
+static void dwc3_chg_block_reset(struct dwc3_msm *mdwc)
+{
+	u32 chg_ctrl;
+
+	/* Clear charger detecting control bits */
+	dwc3_msm_write_reg(mdwc->base, CHARGING_DET_CTRL_REG, 0x0);
+
+	/* Clear alt interrupt latch and enable bits */
+	dwc3_msm_write_reg(mdwc->base, HS_PHY_IRQ_STAT_REG, 0xFFF);
+	dwc3_msm_write_reg(mdwc->base, ALT_INTERRUPT_EN_REG, 0x0);
+
+	udelay(100);
+
+	/* Before proceeding make sure charger block is RESET */
+	chg_ctrl = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_CTRL_REG);
+	if (chg_ctrl & 0x3F)
+		dev_err(mdwc->dev, "%s Unable to reset chg_det block: %x\n",
+						 __func__, chg_ctrl);
+}
+
+static const char *chg_to_string(enum dwc3_chg_type chg_type)
+{
+	switch (chg_type) {
+	case USB_SDP_CHARGER:		return "USB_SDP_CHARGER";
+	case USB_DCP_CHARGER:		return "USB_DCP_CHARGER";
+	case USB_CDP_CHARGER:		return "USB_CDP_CHARGER";
+	default:			return "INVALID_CHARGER";
+	}
+}
+
+#define DWC3_CHG_DCD_POLL_TIME		(100 * HZ/1000) /* 100 msec */
+#define DWC3_CHG_DCD_MAX_RETRIES	6 /* Tdcd_tmout = 6 * 100 msec */
+#define DWC3_CHG_PRIMARY_DET_TIME	(50 * HZ/1000) /* TVDPSRC_ON */
+#define DWC3_CHG_SECONDARY_DET_TIME	(50 * HZ/1000) /* TVDMSRC_ON */
+
+static void dwc3_chg_detect_work(struct work_struct *w)
+{
+	struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm, chg_work.work);
+	bool is_dcd = false, tmout, vout;
+	unsigned long delay;
+
+	dev_dbg(mdwc->dev, "chg detection work\n");
+	switch (mdwc->chg_state) {
+	case USB_CHG_STATE_UNDEFINED:
+		dwc3_chg_block_reset(mdwc);
+		dwc3_chg_enable_dcd(mdwc);
+		mdwc->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
+		mdwc->dcd_retries = 0;
+		delay = DWC3_CHG_DCD_POLL_TIME;
+		break;
+	case USB_CHG_STATE_WAIT_FOR_DCD:
+		is_dcd = dwc3_chg_check_dcd(mdwc);
+		tmout = ++mdwc->dcd_retries == DWC3_CHG_DCD_MAX_RETRIES;
+		if (is_dcd || tmout) {
+			dwc3_chg_disable_dcd(mdwc);
+			dwc3_chg_enable_primary_det(mdwc);
+			delay = DWC3_CHG_PRIMARY_DET_TIME;
+			mdwc->chg_state = USB_CHG_STATE_DCD_DONE;
+		} else {
+			delay = DWC3_CHG_DCD_POLL_TIME;
+		}
+		break;
+	case USB_CHG_STATE_DCD_DONE:
+		vout = dwc3_chg_det_check_output(mdwc);
+		if (vout) {
+			dwc3_chg_enable_secondary_det(mdwc);
+			delay = DWC3_CHG_SECONDARY_DET_TIME;
+			mdwc->chg_state = USB_CHG_STATE_PRIMARY_DONE;
+		} else {
+			mdwc->charger.chg_type = USB_SDP_CHARGER;
+			mdwc->chg_state = USB_CHG_STATE_DETECTED;
+			delay = 0;
+		}
+		break;
+	case USB_CHG_STATE_PRIMARY_DONE:
+		vout = dwc3_chg_det_check_output(mdwc);
+		if (vout)
+			mdwc->charger.chg_type = USB_DCP_CHARGER;
+		else
+			mdwc->charger.chg_type = USB_CDP_CHARGER;
+		mdwc->chg_state = USB_CHG_STATE_SECONDARY_DONE;
+		/* fall through */
+	case USB_CHG_STATE_SECONDARY_DONE:
+		mdwc->chg_state = USB_CHG_STATE_DETECTED;
+		/* fall through */
+	case USB_CHG_STATE_DETECTED:
+		dwc3_chg_block_reset(mdwc);
+		dev_dbg(mdwc->dev, "chg_type = %s\n",
+			chg_to_string(mdwc->charger.chg_type));
+		mdwc->charger.notify_detection_complete(mdwc->otg_xceiv->otg,
+								&mdwc->charger);
+		return;
+	default:
+		return;
+	}
+
+	queue_delayed_work(system_nrt_wq, &mdwc->chg_work, delay);
+}
+
+static void dwc3_start_chg_det(struct dwc3_charger *charger, bool start)
+{
+	struct dwc3_msm *mdwc = context;
+
+	if (start == false) {
+		cancel_delayed_work_sync(&mdwc->chg_work);
+		mdwc->chg_state = USB_CHG_STATE_UNDEFINED;
+		charger->chg_type = DWC3_INVALID_CHARGER;
+		return;
+	}
+
+	mdwc->chg_state = USB_CHG_STATE_UNDEFINED;
+	charger->chg_type = DWC3_INVALID_CHARGER;
+	queue_delayed_work(system_nrt_wq, &mdwc->chg_work, 0);
+}
+
+
 static int __devinit dwc3_msm_probe(struct platform_device *pdev)
 {
 	struct device_node *node = pdev->dev.of_node;
@@ -1015,6 +1240,19 @@
 	msm->dev = &pdev->dev;
 
 	INIT_LIST_HEAD(&msm->req_complete_list);
+	INIT_DELAYED_WORK(&msm->chg_work, dwc3_chg_detect_work);
+
+	/*
+	 * DWC3 Core requires its CORE CLK (aka master / bus clk) to
+	 * run at 125Mhz in SSUSB mode and >60MHZ for HSUSB mode.
+	 */
+	msm->core_clk = devm_clk_get(&pdev->dev, "core_clk");
+	if (IS_ERR(msm->core_clk)) {
+		dev_err(&pdev->dev, "failed to get core_clk\n");
+		return PTR_ERR(msm->core_clk);
+	}
+	clk_set_rate(msm->core_clk, 125000000);
+	clk_prepare_enable(msm->core_clk);
 
 	/* SS PHY */
 	msm->ss_vdd_type = VDDCX_CORNER;
@@ -1024,7 +1262,8 @@
 							"SSUSB_VDDCX");
 		if (IS_ERR(msm->ssusb_vddcx)) {
 			dev_err(&pdev->dev, "unable to get ssusb vddcx\n");
-			return PTR_ERR(msm->ssusb_vddcx);
+			ret = PTR_ERR(msm->ssusb_vddcx);
+			goto disable_core_clk;
 		}
 		msm->ss_vdd_type = VDDCX;
 		dev_dbg(&pdev->dev, "ss_vdd_type: VDDCX\n");
@@ -1033,7 +1272,7 @@
 	ret = dwc3_ssusb_config_vddcx(1);
 	if (ret) {
 		dev_err(&pdev->dev, "ssusb vddcx configuration failed\n");
-		return ret;
+		goto disable_core_clk;
 	}
 
 	ret = regulator_enable(context->ssusb_vddcx);
@@ -1115,10 +1354,9 @@
 		goto disable_hs_ldo;
 	}
 
-	dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask);
-
 	dwc3->dev.parent = &pdev->dev;
-	dwc3->dev.dma_mask = pdev->dev.dma_mask;
+	dwc3->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+	dwc3->dev.dma_mask = &dwc3_msm_dma_mask;
 	dwc3->dev.dma_parms = pdev->dev.dma_parms;
 	msm->resource_size = resource_size(res);
 	msm->dwc3 = dwc3;
@@ -1155,8 +1393,24 @@
 	/* Reset the DBM */
 	dwc3_msm_dbm_soft_reset();
 
+	msm->otg_xceiv = usb_get_transceiver();
+	if (msm->otg_xceiv) {
+		msm->charger.start_detection = dwc3_start_chg_det;
+		ret = dwc3_set_charger(msm->otg_xceiv->otg, &msm->charger);
+		if (ret || !msm->charger.notify_detection_complete) {
+			dev_err(&pdev->dev, "failed to register charger: %d\n",
+									ret);
+			goto put_xcvr;
+		}
+	} else {
+		dev_err(&pdev->dev, "%s: No OTG transceiver found\n", __func__);
+	}
+
 	return 0;
 
+put_xcvr:
+	usb_put_transceiver(msm->otg_xceiv);
+	platform_device_del(dwc3);
 put_pdev:
 	platform_device_put(dwc3);
 disable_hs_ldo:
@@ -1175,6 +1429,8 @@
 	regulator_disable(context->ssusb_vddcx);
 unconfig_ss_vddcx:
 	dwc3_ssusb_config_vddcx(0);
+disable_core_clk:
+	clk_disable_unprepare(msm->core_clk);
 
 	return ret;
 }
@@ -1183,6 +1439,10 @@
 {
 	struct dwc3_msm	*msm = platform_get_drvdata(pdev);
 
+	if (msm->otg_xceiv) {
+		dwc3_start_chg_det(&msm->charger, false);
+		usb_put_transceiver(msm->otg_xceiv);
+	}
 	platform_device_unregister(msm->dwc3);
 
 	dwc3_hsusb_ldo_enable(0);
@@ -1193,6 +1453,7 @@
 	dwc3_ssusb_ldo_init(0);
 	regulator_disable(msm->ssusb_vddcx);
 	dwc3_ssusb_config_vddcx(0);
+	clk_disable_unprepare(msm->core_clk);
 
 	return 0;
 }
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index d7d9c0e..a5c77ad 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -49,7 +49,6 @@
 #include <linux/of.h>
 
 #include "core.h"
-#include "io.h"
 
 /*
  * All these registers belong to OMAP's Wrapper around the
@@ -143,6 +142,17 @@
 	u32			dma_status:1;
 };
 
+static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset)
+{
+	return readl_relaxed(base + offset);
+}
+
+static inline void dwc3_omap_writel(void __iomem *base, u32 offset, u32 value)
+{
+	writel_relaxed(value, base + offset);
+}
+
+
 static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
 {
 	struct dwc3_omap	*omap = _omap;
@@ -150,7 +160,7 @@
 
 	spin_lock(&omap->lock);
 
-	reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_1);
+	reg = dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_1);
 
 	if (reg & USBOTGSS_IRQ1_DMADISABLECLR) {
 		dev_dbg(omap->dev, "DMA Disable was Cleared\n");
@@ -184,10 +194,10 @@
 	if (reg & USBOTGSS_IRQ1_IDPULLUP_FALL)
 		dev_dbg(omap->dev, "IDPULLUP Fall\n");
 
-	dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_1, reg);
+	dwc3_omap_writel(omap->base, USBOTGSS_IRQSTATUS_1, reg);
 
-	reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_0);
-	dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_0, reg);
+	reg = dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_0);
+	dwc3_omap_writel(omap->base, USBOTGSS_IRQSTATUS_0, reg);
 
 	spin_unlock(&omap->lock);
 
@@ -270,7 +280,7 @@
 	omap->base	= base;
 	omap->dwc3	= dwc3;
 
-	reg = dwc3_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
+	reg = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
 
 	utmi_mode = of_get_property(node, "utmi-mode", &size);
 	if (utmi_mode && size == sizeof(*utmi_mode)) {
@@ -293,10 +303,10 @@
 		}
 	}
 
-	dwc3_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
+	dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
 
 	/* check the DMA Status */
-	reg = dwc3_readl(omap->base, USBOTGSS_SYSCONFIG);
+	reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
 	omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
 
 	/* Set No-Idle and No-Standby */
@@ -306,7 +316,7 @@
 	reg |= (USBOTGSS_SYSCONFIG_STANDBYMODE(USBOTGSS_STANDBYMODE_NO_STANDBY)
 		| USBOTGSS_SYSCONFIG_IDLEMODE(USBOTGSS_IDLEMODE_NO_IDLE));
 
-	dwc3_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
+	dwc3_omap_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
 
 	ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0,
 			"dwc3-omap", omap);
@@ -318,7 +328,7 @@
 
 	/* enable all IRQs */
 	reg = USBOTGSS_IRQO_COREIRQ_ST;
-	dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
+	dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
 
 	reg = (USBOTGSS_IRQ1_OEVT |
 			USBOTGSS_IRQ1_DRVVBUS_RISE |
@@ -330,7 +340,7 @@
 			USBOTGSS_IRQ1_DISCHRGVBUS_FALL |
 			USBOTGSS_IRQ1_IDPULLUP_FALL);
 
-	dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
+	dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
 
 	ret = platform_device_add_resources(dwc3, pdev->resource,
 			pdev->num_resources);
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
new file mode 100644
index 0000000..5df030a
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -0,0 +1,664 @@
+/**
+ * dwc3_otg.c - DesignWare USB3 DRD Controller OTG
+ *
+ * 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/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/platform_device.h>
+
+#include "core.h"
+#include "dwc3_otg.h"
+#include "io.h"
+#include "xhci.h"
+
+
+/**
+ * dwc3_otg_set_host_regs - reset dwc3 otg registers to host operation.
+ *
+ * This function sets the OTG registers to work in A-Device host mode.
+ * This function should be called just before entering to A-Device mode.
+ *
+ * @w: Pointer to the dwc3 otg workqueue.
+ */
+static void dwc3_otg_set_host_regs(struct dwc3_otg *dotg)
+{
+	u32 octl;
+
+	/* Set OCTL[6](PeriMode) to 0 (host) */
+	octl = dwc3_readl(dotg->regs, DWC3_OCTL);
+	octl &= ~DWC3_OTG_OCTL_PERIMODE;
+	dwc3_writel(dotg->regs, DWC3_OCTL, octl);
+
+	/*
+	 * TODO: add more OTG registers writes for HOST mode here,
+	 * see figure 12-10 A-device flow in dwc3 Synopsis spec
+	 */
+}
+
+/**
+ * dwc3_otg_set_peripheral_regs - reset dwc3 otg registers to peripheral operation.
+ *
+ * This function sets the OTG registers to work in B-Device peripheral mode.
+ * This function should be called just before entering to B-Device mode.
+ *
+ * @w: Pointer to the dwc3 otg workqueue.
+ */
+static void dwc3_otg_set_peripheral_regs(struct dwc3_otg *dotg)
+{
+	u32 octl;
+
+	/* Set OCTL[6](PeriMode) to 1 (peripheral) */
+	octl = dwc3_readl(dotg->regs, DWC3_OCTL);
+	octl |= DWC3_OTG_OCTL_PERIMODE;
+	dwc3_writel(dotg->regs, DWC3_OCTL, octl);
+
+	/*
+	 * TODO: add more OTG registers writes for PERIPHERAL mode here,
+	 * see figure 12-19 B-device flow in dwc3 Synopsis spec
+	 */
+}
+
+/**
+ * dwc3_otg_start_host -  helper function for starting/stoping the host controller driver.
+ *
+ * @otg: Pointer to the otg_transceiver structure.
+ * @on: start / stop the host controller driver.
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+static int dwc3_otg_start_host(struct usb_otg *otg, int on)
+{
+	struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+	struct usb_hcd *hcd;
+	struct xhci_hcd *xhci;
+	int ret = 0;
+
+	if (!otg->host)
+		return -EINVAL;
+
+	hcd = bus_to_hcd(otg->host);
+	xhci = hcd_to_xhci(hcd);
+	if (on) {
+		dev_dbg(otg->phy->dev, "%s: turn on host %s\n",
+					__func__, otg->host->bus_name);
+		dwc3_otg_set_host_regs(dotg);
+
+		/*
+		 * This should be revisited for more testing post-silicon.
+		 * In worst case we may need to disconnect the root hub
+		 * before stopping the controller so that it does not
+		 * interfere with runtime pm/system pm.
+		 * We can also consider registering and unregistering xhci
+		 * platform device. It is almost similar to add_hcd and
+		 * remove_hcd, But we may not use standard set_host method
+		 * anymore.
+		 */
+		ret = hcd->driver->start(hcd);
+		if (ret) {
+			dev_err(otg->phy->dev,
+				"%s: failed to start primary hcd, ret=%d\n",
+				__func__, ret);
+			return ret;
+		}
+
+		ret = xhci->shared_hcd->driver->start(xhci->shared_hcd);
+		if (ret) {
+			dev_err(otg->phy->dev,
+				"%s: failed to start secondary hcd, ret=%d\n",
+				__func__, ret);
+			return ret;
+		}
+	} else {
+		dev_dbg(otg->phy->dev, "%s: turn off host %s\n",
+					__func__, otg->host->bus_name);
+		hcd->driver->stop(hcd);
+	}
+
+	return 0;
+}
+
+/**
+ * dwc3_otg_set_host -  bind/unbind the host controller driver.
+ *
+ * @otg: Pointer to the otg_transceiver structure.
+ * @host: Pointer to the usb_bus structure.
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+static int dwc3_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
+{
+	struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+
+	if (host) {
+		dev_dbg(otg->phy->dev, "%s: set host %s\n",
+					__func__, host->bus_name);
+		otg->host = host;
+
+		/*
+		 * Only after both peripheral and host are set then check
+		 * OTG sm. This prevents unnecessary activation of the sm
+		 * in case the ID is high.
+		 */
+		if (otg->gadget)
+			schedule_work(&dotg->sm_work);
+	} else {
+		if (otg->phy->state == OTG_STATE_A_HOST) {
+			dwc3_otg_start_host(otg, 0);
+			otg->host = NULL;
+			otg->phy->state = OTG_STATE_UNDEFINED;
+			schedule_work(&dotg->sm_work);
+		} else {
+			otg->host = NULL;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * dwc3_otg_start_peripheral -  bind/unbind the peripheral controller.
+ *
+ * @otg: Pointer to the otg_transceiver structure.
+ * @gadget: pointer to the usb_gadget structure.
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+static int dwc3_otg_start_peripheral(struct usb_otg *otg, int on)
+{
+	struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+
+	if (!otg->gadget)
+		return -EINVAL;
+
+	if (on) {
+		dev_dbg(otg->phy->dev, "%s: turn on gadget %s\n",
+					__func__, otg->gadget->name);
+		dwc3_otg_set_peripheral_regs(dotg);
+		usb_gadget_vbus_connect(otg->gadget);
+	} else {
+		dev_dbg(otg->phy->dev, "%s: turn off gadget %s\n",
+					__func__, otg->gadget->name);
+		usb_gadget_vbus_disconnect(otg->gadget);
+	}
+
+	return 0;
+}
+
+/**
+ * dwc3_otg_set_peripheral -  bind/unbind the peripheral controller driver.
+ *
+ * @otg: Pointer to the otg_transceiver structure.
+ * @gadget: pointer to the usb_gadget structure.
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+static int dwc3_otg_set_peripheral(struct usb_otg *otg,
+				struct usb_gadget *gadget)
+{
+	struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+
+	if (gadget) {
+		dev_dbg(otg->phy->dev, "%s: set gadget %s\n",
+					__func__, gadget->name);
+		otg->gadget = gadget;
+
+		/*
+		 * Only after both peripheral and host are set then check
+		 * OTG sm. This prevents unnecessary activation of the sm
+		 * in case the ID is grounded.
+		 */
+		if (otg->host)
+			schedule_work(&dotg->sm_work);
+	} else {
+		if (otg->phy->state == OTG_STATE_B_PERIPHERAL) {
+			dwc3_otg_start_peripheral(otg, 0);
+			otg->gadget = NULL;
+			otg->phy->state = OTG_STATE_UNDEFINED;
+			schedule_work(&dotg->sm_work);
+		} else {
+			otg->gadget = NULL;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * dwc3_ext_chg_det_done - callback to handle charger detection completion
+ * @otg: Pointer to the otg transceiver structure
+ * @charger: Pointer to the external charger structure
+ *
+ * Returns 0 on success
+ */
+static void dwc3_ext_chg_det_done(struct usb_otg *otg, struct dwc3_charger *chg)
+{
+	struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+
+	/*
+	 * Ignore chg_detection notification if BSV has gone off by this time.
+	 * STOP chg_det as part of !BSV handling would reset the chg_det flags
+	 */
+	if (test_bit(B_SESS_VLD, &dotg->inputs))
+		schedule_work(&dotg->sm_work);
+}
+
+/**
+ * dwc3_set_charger - bind/unbind external charger driver
+ * @otg: Pointer to the otg transceiver structure
+ * @charger: Pointer to the external charger structure
+ *
+ * Returns 0 on success
+ */
+int dwc3_set_charger(struct usb_otg *otg, struct dwc3_charger *charger)
+{
+	struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+
+	dotg->charger = charger;
+	if (charger)
+		charger->notify_detection_complete = dwc3_ext_chg_det_done;
+
+	return 0;
+}
+
+/* IRQs which OTG driver is interested in handling */
+#define DWC3_OEVT_MASK		(DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT | \
+				 DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT)
+
+/**
+ * dwc3_otg_interrupt - interrupt handler for dwc3 otg events.
+ * @_dotg: Pointer to out controller context structure
+ *
+ * Returns IRQ_HANDLED on success otherwise IRQ_NONE.
+ */
+static irqreturn_t dwc3_otg_interrupt(int irq, void *_dotg)
+{
+	struct dwc3_otg *dotg = (struct dwc3_otg *)_dotg;
+	u32 osts, oevt_reg;
+	int ret = IRQ_NONE;
+	int handled_irqs = 0;
+
+	oevt_reg = dwc3_readl(dotg->regs, DWC3_OEVT);
+
+	if (!(oevt_reg & DWC3_OEVT_MASK))
+		return IRQ_NONE;
+
+	osts = dwc3_readl(dotg->regs, DWC3_OSTS);
+
+	if ((oevt_reg & DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT) ||
+	    (oevt_reg & DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT)) {
+		/*
+		 * ID sts has changed, set inputs later, in the workqueue
+		 * function, switch from A to B or from B to A.
+		 */
+
+		if (osts & DWC3_OTG_OSTS_CONIDSTS)
+			set_bit(ID, &dotg->inputs);
+		else
+			clear_bit(ID, &dotg->inputs);
+
+		if (osts & DWC3_OTG_OSTS_BSESVALID)
+			set_bit(B_SESS_VLD, &dotg->inputs);
+		else
+			clear_bit(B_SESS_VLD, &dotg->inputs);
+
+		schedule_work(&dotg->sm_work);
+
+		handled_irqs |= (oevt_reg & DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT) ?
+				DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT : 0;
+		handled_irqs |= (oevt_reg & DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT) ?
+				DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT : 0;
+
+		ret = IRQ_HANDLED;
+
+		/* Clear the interrupts we handled */
+		dwc3_writel(dotg->regs, DWC3_OEVT, handled_irqs);
+	}
+
+	return ret;
+}
+
+/**
+ * dwc3_otg_init_sm - initialize OTG statemachine input
+ * @dotg: Pointer to the dwc3_otg structure
+ *
+ */
+void dwc3_otg_init_sm(struct dwc3_otg *dotg)
+{
+	u32 osts = dwc3_readl(dotg->regs, DWC3_OSTS);
+	struct usb_phy *phy = dotg->otg.phy;
+
+	/*
+	 * TODO: If using external notifications then wait here till initial
+	 * state is reported
+	 */
+
+	dev_dbg(phy->dev, "Initialize OTG inputs, osts: 0x%x\n", osts);
+
+	if (osts & DWC3_OTG_OSTS_CONIDSTS)
+		set_bit(ID, &dotg->inputs);
+	else
+		clear_bit(ID, &dotg->inputs);
+
+	if (osts & DWC3_OTG_OSTS_BSESVALID)
+		set_bit(B_SESS_VLD, &dotg->inputs);
+	else
+		clear_bit(B_SESS_VLD, &dotg->inputs);
+}
+
+/**
+ * dwc3_otg_sm_work - workqueue function.
+ *
+ * @w: Pointer to the dwc3 otg workqueue
+ *
+ * NOTE: After any change in phy->state,
+ * we must reschdule the state machine.
+ */
+static void dwc3_otg_sm_work(struct work_struct *w)
+{
+	struct dwc3_otg *dotg = container_of(w, struct dwc3_otg, sm_work);
+	struct usb_phy *phy = dotg->otg.phy;
+	struct dwc3_charger *charger = dotg->charger;
+	bool work = 0;
+
+	dev_dbg(phy->dev, "%s state\n", otg_state_string(phy->state));
+
+	/* Check OTG state */
+	switch (phy->state) {
+	case OTG_STATE_UNDEFINED:
+		dwc3_otg_init_sm(dotg);
+		/* Switch to A or B-Device according to ID / BSV */
+		if (!test_bit(ID, &dotg->inputs) && phy->otg->host) {
+			dev_dbg(phy->dev, "!id\n");
+			phy->state = OTG_STATE_A_IDLE;
+			work = 1;
+		} else if (test_bit(B_SESS_VLD, &dotg->inputs)) {
+			dev_dbg(phy->dev, "b_sess_vld\n");
+			phy->state = OTG_STATE_B_IDLE;
+			work = 1;
+		} else {
+			phy->state = OTG_STATE_B_IDLE;
+			/* TODO: Enter low power state */
+		}
+		break;
+
+	case OTG_STATE_B_IDLE:
+		if (!test_bit(ID, &dotg->inputs) && phy->otg->host) {
+			dev_dbg(phy->dev, "!id\n");
+			phy->state = OTG_STATE_A_IDLE;
+			work = 1;
+			if (charger) {
+				if (charger->chg_type == DWC3_INVALID_CHARGER)
+					charger->start_detection(dotg->charger,
+									false);
+				else
+					charger->chg_type =
+							DWC3_INVALID_CHARGER;
+			}
+		} else if (test_bit(B_SESS_VLD, &dotg->inputs)) {
+			dev_dbg(phy->dev, "b_sess_vld\n");
+			if (charger) {
+				/* Has charger been detected? If no detect it */
+				switch (charger->chg_type) {
+				case DWC3_DCP_CHARGER:
+					/* TODO: initiate LPM */
+					break;
+				case DWC3_CDP_CHARGER:
+					dwc3_otg_start_peripheral(&dotg->otg,
+									1);
+					phy->state = OTG_STATE_B_PERIPHERAL;
+					work = 1;
+					break;
+				case DWC3_SDP_CHARGER:
+					dwc3_otg_start_peripheral(&dotg->otg,
+									1);
+					phy->state = OTG_STATE_B_PERIPHERAL;
+					work = 1;
+					break;
+				default:
+					dev_dbg(phy->dev, "chg_det started\n");
+					charger->start_detection(charger, true);
+					break;
+				}
+			} else {
+				/* no charger registered, start peripheral */
+				if (dwc3_otg_start_peripheral(&dotg->otg, 1)) {
+					/*
+					 * Probably set_peripheral not called
+					 * yet. We will re-try as soon as it
+					 * will be called
+					 */
+					dev_err(phy->dev,
+						"unable to start B-device\n");
+					phy->state = OTG_STATE_UNDEFINED;
+					return;
+				}
+			}
+		} else {
+			if (charger) {
+				if (charger->chg_type == DWC3_INVALID_CHARGER)
+					charger->start_detection(dotg->charger,
+									false);
+				else
+					charger->chg_type =
+							DWC3_INVALID_CHARGER;
+			}
+			/* TODO: Enter low power state */
+		}
+		break;
+
+	case OTG_STATE_B_PERIPHERAL:
+		if (!test_bit(B_SESS_VLD, &dotg->inputs) ||
+				!test_bit(ID, &dotg->inputs)) {
+			dev_dbg(phy->dev, "!id || !bsv\n");
+			dwc3_otg_start_peripheral(&dotg->otg, 0);
+			phy->state = OTG_STATE_B_IDLE;
+			if (charger)
+				charger->chg_type = DWC3_INVALID_CHARGER;
+			work = 1;
+		}
+		break;
+
+	case OTG_STATE_A_IDLE:
+		/* Switch to A-Device*/
+		if (test_bit(ID, &dotg->inputs)) {
+			dev_dbg(phy->dev, "id\n");
+			phy->state = OTG_STATE_B_IDLE;
+			work = 1;
+		} else {
+			 if (dwc3_otg_start_host(&dotg->otg, 1)) {
+				/*
+				 * Probably set_host was not called yet.
+				 * We will re-try as soon as it will be called
+				 */
+				dev_dbg(phy->dev,
+					"unable to start A-device\n");
+				phy->state = OTG_STATE_UNDEFINED;
+				return;
+			}
+			phy->state = OTG_STATE_A_HOST;
+		}
+		break;
+
+	case OTG_STATE_A_HOST:
+		if (test_bit(ID, &dotg->inputs)) {
+			dev_dbg(phy->dev, "id\n");
+			dwc3_otg_start_host(&dotg->otg, 0);
+			phy->state = OTG_STATE_B_IDLE;
+			work = 1;
+		}
+		break;
+
+	default:
+		dev_err(phy->dev, "%s: invalid otg-state\n", __func__);
+
+	}
+
+	if (work)
+		schedule_work(&dotg->sm_work);
+}
+
+
+/**
+ * dwc3_otg_reset - reset dwc3 otg registers.
+ *
+ * @w: Pointer to the dwc3 otg workqueue
+ */
+static void dwc3_otg_reset(struct dwc3_otg *dotg)
+{
+	/*
+	 * OCFG[2] - OTG-Version = 1
+	 * OCFG[1] - HNPCap = 0
+	 * OCFG[0] - SRPCap = 0
+	 */
+	dwc3_writel(dotg->regs, DWC3_OCFG, 0x4);
+
+	/*
+	 * OCTL[6] - PeriMode = 1
+	 * OCTL[5] - PrtPwrCtl = 0
+	 * OCTL[4] - HNPReq = 0
+	 * OCTL[3] - SesReq = 0
+	 * OCTL[2] - TermSelDLPulse = 0
+	 * OCTL[1] - DevSetHNPEn = 0
+	 * OCTL[0] - HstSetHNPEn = 0
+	 */
+	dwc3_writel(dotg->regs, DWC3_OCTL, 0x40);
+
+	/* Clear all otg events (interrupts) indications  */
+	dwc3_writel(dotg->regs, DWC3_OEVT, 0xFFFF);
+
+	/* Enable ID/BSV StsChngEn event*/
+	dwc3_writel(dotg->regs, DWC3_OEVTEN,
+			DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT |
+			DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT);
+}
+
+/**
+ * dwc3_otg_init - Initializes otg related registers
+ * @dwc: Pointer to out controller context structure
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+int dwc3_otg_init(struct dwc3 *dwc)
+{
+	u32	reg;
+	int ret = 0;
+	struct dwc3_otg *dotg;
+
+	dev_dbg(dwc->dev, "dwc3_otg_init\n");
+
+	/*
+	 * GHWPARAMS6[10] bit is SRPSupport.
+	 * This bit also reflects DWC_USB3_EN_OTG
+	 */
+	reg = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
+	if (!(reg & DWC3_GHWPARAMS6_SRP_SUPPORT)) {
+		/*
+		 * No OTG support in the HW core.
+		 * We return 0 to indicate no error, since this is acceptable
+		 * situation, just continue probe the dwc3 driver without otg.
+		 */
+		dev_dbg(dwc->dev, "dwc3_otg address space is not supported\n");
+		return 0;
+	}
+
+	/* Allocate and init otg instance */
+	dotg = kzalloc(sizeof(struct dwc3_otg), GFP_KERNEL);
+	if (!dotg) {
+		dev_err(dwc->dev, "unable to allocate dwc3_otg\n");
+		return -ENOMEM;
+	}
+
+	dotg->irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+	if (dotg->irq < 0) {
+		dev_err(dwc->dev, "%s: missing IRQ\n", __func__);
+		ret = -ENODEV;
+		goto err1;
+	}
+
+	dotg->regs = dwc->regs;
+
+	dotg->otg.set_peripheral = dwc3_otg_set_peripheral;
+	dotg->otg.set_host = dwc3_otg_set_host;
+
+	/* This reference is used by dwc3 modules for checking otg existance */
+	dwc->dotg = dotg;
+
+	dotg->otg.phy = kzalloc(sizeof(struct usb_phy), GFP_KERNEL);
+	if (!dotg->otg.phy) {
+		dev_err(dwc->dev, "unable to allocate dwc3_otg.phy\n");
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	dotg->otg.phy->otg = &dotg->otg;
+	dotg->otg.phy->dev = dwc->dev;
+
+	ret = usb_set_transceiver(dotg->otg.phy);
+	if (ret) {
+		dev_err(dotg->otg.phy->dev,
+			"%s: failed to set transceiver, already exists\n",
+			__func__);
+		goto err2;
+	}
+
+	dwc3_otg_reset(dotg);
+
+	dotg->otg.phy->state = OTG_STATE_UNDEFINED;
+
+	INIT_WORK(&dotg->sm_work, dwc3_otg_sm_work);
+
+	ret = request_irq(dotg->irq, dwc3_otg_interrupt, IRQF_SHARED,
+				"dwc3_otg", dotg);
+	if (ret) {
+		dev_err(dotg->otg.phy->dev, "failed to request irq #%d --> %d\n",
+				dotg->irq, ret);
+		goto err3;
+	}
+
+	return 0;
+
+err3:
+	cancel_work_sync(&dotg->sm_work);
+	usb_set_transceiver(NULL);
+err2:
+	kfree(dotg->otg.phy);
+err1:
+	dwc->dotg = NULL;
+	kfree(dotg);
+
+	return ret;
+}
+
+/**
+ * dwc3_otg_exit
+ * @dwc: Pointer to out controller context structure
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+void dwc3_otg_exit(struct dwc3 *dwc)
+{
+	struct dwc3_otg *dotg = dwc->dotg;
+
+	/* dotg is null when GHWPARAMS6[10]=SRPSupport=0, see dwc3_otg_init */
+	if (dotg) {
+		if (dotg->charger)
+			dotg->charger->start_detection(dotg->charger, false);
+		cancel_work_sync(&dotg->sm_work);
+		usb_set_transceiver(NULL);
+		free_irq(dotg->irq, dotg);
+		kfree(dotg->otg.phy);
+		kfree(dotg);
+		dwc->dotg = NULL;
+	}
+}
diff --git a/drivers/usb/dwc3/dwc3_otg.h b/drivers/usb/dwc3/dwc3_otg.h
new file mode 100644
index 0000000..0d8b61b
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3_otg.h
@@ -0,0 +1,76 @@
+/**
+ * dwc3_otg.h - DesignWare USB3 DRD Controller OTG
+ *
+ * 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 __LINUX_USB_DWC3_OTG_H
+#define __LINUX_USB_DWC3_OTG_H
+
+#include <linux/workqueue.h>
+
+#include <linux/usb/otg.h>
+
+struct dwc3_charger;
+
+/**
+ * struct dwc3_otg: OTG driver data. Shared by HCD and DCD.
+ * @otg: USB OTG Transceiver structure.
+ * @irq: IRQ number assigned for HSUSB controller.
+ * @regs: ioremapped register base address.
+ * @sm_work: OTG state machine work.
+ * @charger: DWC3 external charger detector
+ * @inputs: OTG state machine inputs
+ */
+struct dwc3_otg {
+	struct usb_otg otg;
+	int irq;
+	void __iomem *regs;
+	struct work_struct sm_work;
+	struct dwc3_charger *charger;
+#define ID		0
+#define B_SESS_VLD	1
+	unsigned long inputs;
+};
+
+/**
+ * USB charger types
+ *
+ * DWC3_INVALID_CHARGER	Invalid USB charger.
+ * DWC3_SDP_CHARGER	Standard downstream port. Refers to a downstream port
+ *                      on USB compliant host/hub.
+ * DWC3_DCP_CHARGER	Dedicated charger port (AC charger/ Wall charger).
+ * DWC3_CDP_CHARGER	Charging downstream port. Enumeration can happen and
+ *                      IDEV_CHG_MAX can be drawn irrespective of USB state.
+ */
+enum dwc3_chg_type {
+	DWC3_INVALID_CHARGER = 0,
+	DWC3_SDP_CHARGER,
+	DWC3_DCP_CHARGER,
+	DWC3_CDP_CHARGER,
+};
+
+struct dwc3_charger {
+	enum dwc3_chg_type	chg_type;
+
+	/* start/stop charger detection, provided by external charger module */
+	void	(*start_detection)(struct dwc3_charger *charger, bool start);
+
+	/* to notify OTG about charger detection completion, provided by OTG */
+	void	(*notify_detection_complete)(struct usb_otg *otg,
+						struct dwc3_charger *charger);
+};
+
+/* for external charger driver */
+extern int dwc3_set_charger(struct usb_otg *otg, struct dwc3_charger *charger);
+
+#endif /* __LINUX_USB_DWC3_OTG_H */
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index a988c43..060144f 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -49,6 +49,7 @@
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
 
 #include "core.h"
 #include "gadget.h"
@@ -1326,7 +1327,59 @@
 	is_on = !!is_on;
 
 	spin_lock_irqsave(&dwc->lock, flags);
+
+	dwc->softconnect = is_on;
+
+	if ((dwc->dotg && !dwc->vbus_active) ||
+		!dwc->gadget_driver) {
+
+		spin_unlock_irqrestore(&dwc->lock, flags);
+
+		/*
+		 * Need to wait for vbus_session(on) from otg driver or to
+		 * the udc_start.
+		 */
+		return 0;
+	}
+
 	dwc3_gadget_run_stop(dwc, is_on);
+
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return 0;
+}
+
+static int dwc3_gadget_vbus_session(struct usb_gadget *_gadget, int is_active)
+{
+	struct dwc3 *dwc = gadget_to_dwc(_gadget);
+	unsigned long flags;
+
+	if (!dwc->dotg)
+		return -EPERM;
+
+	is_active = !!is_active;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+
+	/* Mark that the vbus was powered */
+	dwc->vbus_active = is_active;
+
+	/*
+	 * Check if upper level usb_gadget_driver was already registerd with
+	 * this udc controller driver (if dwc3_gadget_start was called)
+	 */
+	if (dwc->gadget_driver && dwc->softconnect) {
+		if (dwc->vbus_active) {
+			/*
+			 * Both vbus was activated by otg and pullup was
+			 * signaled by the gadget driver.
+			 */
+			dwc3_gadget_run_stop(dwc, 1);
+		} else {
+			dwc3_gadget_run_stop(dwc, 0);
+		}
+	}
+
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
 	return 0;
@@ -1417,6 +1470,7 @@
 	.get_frame		= dwc3_gadget_get_frame,
 	.wakeup			= dwc3_gadget_wakeup,
 	.set_selfpowered	= dwc3_gadget_set_selfpowered,
+	.vbus_session		= dwc3_gadget_vbus_session,
 	.pullup			= dwc3_gadget_pullup,
 	.udc_start		= dwc3_gadget_start,
 	.udc_stop		= dwc3_gadget_stop,
@@ -2153,6 +2207,33 @@
 		break;
 	case DWC3_DEVICE_EVENT_OVERFLOW:
 		dev_vdbg(dwc->dev, "Overflow\n");
+		/*
+		 * Controllers prior to 2.30a revision has a bug where
+		 * Overflow Event may overwrite an unacknowledged event
+		 * in the event buffer.  The severity of the issue depends
+		 * on the overwritten event type.  Add a warning message
+		 * saying that an event is overwritten.
+		 *
+		 * TODO: In future we may need to see if we can re-enumerate
+		 * with host.
+		 */
+		if (dwc->revision < DWC3_REVISION_230A)
+			dev_warn(dwc->dev, "Unacknowledged event overwritten\n");
+		break;
+	case DWC3_DEVICE_EVENT_VENDOR_DEV_TEST_LMP:
+		/*
+		 * Controllers prior to 2.30a revision has a bug, due to which
+		 * a vendor device test LMP event can not be filtered.  But
+		 * this event is not handled in the current code.  This is a
+		 * special event and 8 bytes of data will follow the event.
+		 * Handling this event is tricky when event buffer is almost
+		 * full. Moreover this event will not occur in normal scenario
+		 * and can only happen with special hosts in testing scenarios.
+		 * Add a warning message to indicate that this event is received
+		 * which means that event buffer might have corrupted.
+		 */
+		if (dwc->revision < DWC3_REVISION_230A)
+			dev_warn(dwc->dev, "Vendor Device Test LMP Received\n");
 		break;
 	default:
 		dev_dbg(dwc->dev, "UNKNOWN IRQ %d\n", event->type);
@@ -2314,8 +2395,7 @@
 	}
 
 	/* Enable all but Start and End of Frame IRQs */
-	reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
-			DWC3_DEVTEN_EVNTOVERFLOWEN |
+	reg = (DWC3_DEVTEN_EVNTOVERFLOWEN |
 			DWC3_DEVTEN_CMDCMPLTEN |
 			DWC3_DEVTEN_ERRTICERREN |
 			DWC3_DEVTEN_WKUPEVTEN |
@@ -2338,6 +2418,15 @@
 		goto err7;
 	}
 
+	if (dwc->dotg) {
+		/* dwc3 otg driver is active (DRD mode + SRPSupport=1) */
+		ret = otg_set_peripheral(&dwc->dotg->otg, &dwc->gadget);
+		if (ret) {
+			dev_err(dwc->dev, "failed to set peripheral to otg\n");
+			goto err7;
+		}
+	}
+
 	return 0;
 
 err7:
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index b108d18..099708b 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -38,20 +38,13 @@
 #include <linux/platform_device.h>
 
 #include "core.h"
-
-static struct resource generic_resources[] = {
-	{
-		.flags = IORESOURCE_IRQ,
-	},
-	{
-		.flags = IORESOURCE_MEM,
-	},
-};
+#include "xhci.h"
 
 int dwc3_host_init(struct dwc3 *dwc)
 {
 	struct platform_device	*xhci;
 	int			ret;
+	struct xhci_plat_data	pdata;
 
 	xhci = platform_device_alloc("xhci-hcd", -1);
 	if (!xhci) {
@@ -67,15 +60,19 @@
 	xhci->dev.dma_parms	= dwc->dev->dma_parms;
 
 	dwc->xhci = xhci;
+	pdata.vendor = ((dwc->revision & DWC3_GSNPSID_MASK) >>
+			__ffs(DWC3_GSNPSID_MASK) & DWC3_GSNPSREV_MASK);
+	pdata.revision = dwc->revision & DWC3_GSNPSREV_MASK;
 
-	/* setup resources */
-	generic_resources[0].start = dwc->irq;
+	ret = platform_device_add_data(xhci, (const void *) &pdata,
+			sizeof(struct xhci_plat_data));
+	if (ret) {
+		dev_err(dwc->dev, "couldn't add pdata to xHCI device\n");
+		goto err1;
+	}
 
-	generic_resources[1].start = dwc->res->start;
-	generic_resources[1].end = dwc->res->start + 0x7fff;
-
-	ret = platform_device_add_resources(xhci, generic_resources,
-			ARRAY_SIZE(generic_resources));
+	ret = platform_device_add_resources(xhci, dwc->xhci_resources,
+						DWC3_XHCI_RESOURCES_NUM);
 	if (ret) {
 		dev_err(dwc->dev, "couldn't add resources to xHCI device\n");
 		goto err1;
diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h
index 071d561..90de7a4 100644
--- a/drivers/usb/dwc3/io.h
+++ b/drivers/usb/dwc3/io.h
@@ -41,14 +41,26 @@
 
 #include <linux/io.h>
 
+#include "core.h"
+
 static inline u32 dwc3_readl(void __iomem *base, u32 offset)
 {
-	return readl(base + offset);
+	/*
+	 * We requested the mem region starting from the Globals address
+	 * space, see dwc3_probe in core.c.
+	 * However, the offsets are given starting from xHCI address space.
+	 */
+	return readl_relaxed(base + (offset - DWC3_GLOBALS_REGS_START));
 }
 
 static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
 {
-	writel(value, base + offset);
+	/*
+	 * We requested the mem region starting from the Globals address
+	 * space, see dwc3_probe in core.c.
+	 * However, the offsets are given starting from xHCI address space.
+	 */
+	writel_relaxed(value, base + (offset - DWC3_GLOBALS_REGS_START));
 }
 
 #endif /* __DRIVERS_USB_DWC3_IO_H */
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 95f11c1..87b307c 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -854,6 +854,16 @@
 	  Say "y" to link the driver statically, or "m" to build
 	  a dynamically linked module called "g_mass_storage".
 
+config USB_GADGET_TARGET
+	tristate "USB Gadget Target Fabric Module"
+	depends on TARGET_CORE
+	help
+	  This fabric is an USB gadget. Two USB protocols are supported that is
+	  BBB or BOT (Bulk Only Transport) and UAS (USB Attached SCSI). BOT is
+	  advertised on alternative interface 0 (primary) and UAS is on
+	  alternative interface 1. Both protocols can work on USB2.0 and USB3.0.
+	  UAS utilizes the USB 3.0 feature called streams support.
+
 config USB_G_SERIAL
 	tristate "Serial Gadget (with CDC ACM and CDC OBEX support)"
 	help
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index c646c9f..b8f5149 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -54,6 +54,7 @@
 g_webcam-y			:= webcam.o
 g_ncm-y				:= ncm.o
 g_acm_ms-y			:= acm_ms.o
+g_tcm_usb_gadget-y		:= tcm_usb_gadget.o
 g_android-y			:= android.o
 
 obj-$(CONFIG_USB_ZERO)		+= g_zero.o
@@ -74,4 +75,5 @@
 obj-$(CONFIG_USB_G_WEBCAM)	+= g_webcam.o
 obj-$(CONFIG_USB_G_NCM)		+= g_ncm.o
 obj-$(CONFIG_USB_G_ACM_MS)	+= g_acm_ms.o
+obj-$(CONFIG_USB_GADGET_TARGET)	+= tcm_usb_gadget.o
 obj-$(CONFIG_USB_G_ANDROID)	+= g_android.o
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 90a3b1e..b5a7291 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -1438,7 +1438,6 @@
 
 	sscanf(buff, "%d", &enabled);
 	if (enabled && !dev->enabled) {
-		cdev->next_string_id = 0;
 		/*
 		 * Update values in composite driver's copy of
 		 * device descriptor.
@@ -1546,7 +1545,8 @@
 {									\
 	if (size >= sizeof(buffer))					\
 		return -EINVAL;						\
-	strlcpy(buffer, strim((char *) buf), sizeof(buffer));		\
+	strlcpy(buffer, buf, sizeof(buffer));				\
+	strim(buffer);							\
 	return size;							\
 }									\
 static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, field ## _show, field ## _store);
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index 1cbaa8e..e3c1216 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -56,7 +56,7 @@
 
 	if (_udc_ctxt.wake_irq && _udc_ctxt.wake_irq_state) {
 		disable_irq_wake(_udc_ctxt.wake_irq);
-		disable_irq(_udc_ctxt.wake_irq);
+		disable_irq_nosync(_udc_ctxt.wake_irq);
 		_udc_ctxt.wake_irq_state = false;
 	}
 }
@@ -134,7 +134,7 @@
 	dev_dbg(&pdev->dev, "_udc_ctxt.gpio_irq = %d and irq = %d\n",
 			_udc_ctxt.wake_gpio, wake_irq);
 	ret = request_irq(wake_irq, ci13xxx_msm_resume_irq,
-		IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "usb resume", NULL);
+		IRQF_TRIGGER_RISING | IRQF_ONESHOT, "usb resume", NULL);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "could not register USB_RESUME IRQ.\n");
 		goto gpio_free;
diff --git a/drivers/usb/gadget/ci13xxx_msm_hsic.c b/drivers/usb/gadget/ci13xxx_msm_hsic.c
index 30b45eb..f353b07 100644
--- a/drivers/usb/gadget/ci13xxx_msm_hsic.c
+++ b/drivers/usb/gadget/ci13xxx_msm_hsic.c
@@ -381,7 +381,7 @@
 	 */
 	mb();
 
-	if (!mhsic->pdata->keep_core_clk_on_suspend_workaround) {
+	if (!mhsic->pdata->core_clk_always_on_workaround) {
 		clk_disable(mhsic->iface_clk);
 		clk_disable(mhsic->core_clk);
 	}
@@ -438,7 +438,7 @@
 		dev_err(mhsic->dev, "%s failed to vote for TCXO %d\n",
 				__func__, ret);
 
-	if (!mhsic->pdata->keep_core_clk_on_suspend_workaround) {
+	if (!mhsic->pdata->core_clk_always_on_workaround) {
 		clk_enable(mhsic->iface_clk);
 		clk_enable(mhsic->core_clk);
 	}
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index 41a1777..6883b78 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -795,6 +795,7 @@
 		spin_unlock(&mbim->lock);
 		mbim_clear_queues(mbim);
 		mbim_reset_function_queue(mbim);
+		spin_lock(&mbim->lock);
 		break;
 	default:
 		pr_err("Unknown event %02x --> %d\n",
@@ -1450,8 +1451,6 @@
 
 	mbim->cdev = c->cdev;
 
-	spin_lock_init(&mbim->lock);
-
 	mbim_reset_values(mbim);
 
 	mbim->function.name = "usb_mbim";
@@ -1615,6 +1614,7 @@
 	pr_debug("Exit(%d)", count);
 
 	return count;
+
 }
 
 static int mbim_open(struct inode *ip, struct file *fp)
diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c
new file mode 100644
index 0000000..c46439c
--- /dev/null
+++ b/drivers/usb/gadget/tcm_usb_gadget.c
@@ -0,0 +1,2480 @@
+/* Target based USB-Gadget
+ *
+ * UAS protocol handling, target callbacks, configfs handling,
+ * BBB (USB Mass Storage Class Bulk-Only (BBB) and Transport protocol handling.
+ *
+ * Author: Sebastian Andrzej Siewior <bigeasy at linutronix dot de>
+ * License: GPLv2 as published by FSF.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/configfs.h>
+#include <linux/ctype.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/composite.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/storage.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_tcq.h>
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+#include <target/target_core_fabric_configfs.h>
+#include <target/target_core_configfs.h>
+#include <target/configfs_macros.h>
+#include <asm/unaligned.h>
+
+#include "usbstring.c"
+#include "epautoconf.c"
+#include "config.c"
+#include "composite.c"
+
+#include "tcm_usb_gadget.h"
+
+static struct target_fabric_configfs *usbg_fabric_configfs;
+
+static inline struct f_uas *to_f_uas(struct usb_function *f)
+{
+	return container_of(f, struct f_uas, function);
+}
+
+static void usbg_cmd_release(struct kref *);
+
+static inline void usbg_cleanup_cmd(struct usbg_cmd *cmd)
+{
+	kref_put(&cmd->ref, usbg_cmd_release);
+}
+
+/* Start bot.c code */
+
+static int bot_enqueue_cmd_cbw(struct f_uas *fu)
+{
+	int ret;
+
+	if (fu->flags & USBG_BOT_CMD_PEND)
+		return 0;
+
+	ret = usb_ep_queue(fu->ep_out, fu->cmd.req, GFP_ATOMIC);
+	if (!ret)
+		fu->flags |= USBG_BOT_CMD_PEND;
+	return ret;
+}
+
+static void bot_status_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct usbg_cmd *cmd = req->context;
+	struct f_uas *fu = cmd->fu;
+
+	usbg_cleanup_cmd(cmd);
+	if (req->status < 0) {
+		pr_err("ERR %s(%d)\n", __func__, __LINE__);
+		return;
+	}
+
+	/* CSW completed, wait for next CBW */
+	bot_enqueue_cmd_cbw(fu);
+}
+
+static void bot_enqueue_sense_code(struct f_uas *fu, struct usbg_cmd *cmd)
+{
+	struct bulk_cs_wrap *csw = &fu->bot_status.csw;
+	int ret;
+	u8 *sense;
+	unsigned int csw_stat;
+
+	csw_stat = cmd->csw_code;
+
+	/*
+	 * We can't send SENSE as a response. So we take ASC & ASCQ from our
+	 * sense buffer and queue it and hope the host sends a REQUEST_SENSE
+	 * command where it learns why we failed.
+	 */
+	sense = cmd->sense_iu.sense;
+
+	csw->Tag = cmd->bot_tag;
+	csw->Status = csw_stat;
+	fu->bot_status.req->context = cmd;
+	ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_ATOMIC);
+	if (ret)
+		pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret);
+}
+
+static void bot_err_compl(struct usb_ep *ep, struct usb_request *req)
+{
+	struct usbg_cmd *cmd = req->context;
+	struct f_uas *fu = cmd->fu;
+
+	if (req->status < 0)
+		pr_err("ERR %s(%d)\n", __func__, __LINE__);
+
+	if (cmd->data_len) {
+		if (cmd->data_len > ep->maxpacket) {
+			req->length = ep->maxpacket;
+			cmd->data_len -= ep->maxpacket;
+		} else {
+			req->length = cmd->data_len;
+			cmd->data_len = 0;
+		}
+
+		usb_ep_queue(ep, req, GFP_ATOMIC);
+		return ;
+	}
+	bot_enqueue_sense_code(fu, cmd);
+}
+
+static void bot_send_bad_status(struct usbg_cmd *cmd)
+{
+	struct f_uas *fu = cmd->fu;
+	struct bulk_cs_wrap *csw = &fu->bot_status.csw;
+	struct usb_request *req;
+	struct usb_ep *ep;
+
+	csw->Residue = cpu_to_le32(cmd->data_len);
+
+	if (cmd->data_len) {
+		if (cmd->is_read) {
+			ep = fu->ep_in;
+			req = fu->bot_req_in;
+		} else {
+			ep = fu->ep_out;
+			req = fu->bot_req_out;
+		}
+
+		if (cmd->data_len > fu->ep_in->maxpacket) {
+			req->length = ep->maxpacket;
+			cmd->data_len -= ep->maxpacket;
+		} else {
+			req->length = cmd->data_len;
+			cmd->data_len = 0;
+		}
+		req->complete = bot_err_compl;
+		req->context = cmd;
+		req->buf = fu->cmd.buf;
+		usb_ep_queue(ep, req, GFP_KERNEL);
+	} else {
+		bot_enqueue_sense_code(fu, cmd);
+	}
+}
+
+static int bot_send_status(struct usbg_cmd *cmd, bool moved_data)
+{
+	struct f_uas *fu = cmd->fu;
+	struct bulk_cs_wrap *csw = &fu->bot_status.csw;
+	int ret;
+
+	if (cmd->se_cmd.scsi_status == SAM_STAT_GOOD) {
+		if (!moved_data && cmd->data_len) {
+			/*
+			 * the host wants to move data, we don't. Fill / empty
+			 * the pipe and then send the csw with reside set.
+			 */
+			cmd->csw_code = US_BULK_STAT_OK;
+			bot_send_bad_status(cmd);
+			return 0;
+		}
+
+		csw->Tag = cmd->bot_tag;
+		csw->Residue = cpu_to_le32(0);
+		csw->Status = US_BULK_STAT_OK;
+		fu->bot_status.req->context = cmd;
+
+		ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_KERNEL);
+		if (ret)
+			pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret);
+	} else {
+		cmd->csw_code = US_BULK_STAT_FAIL;
+		bot_send_bad_status(cmd);
+	}
+	return 0;
+}
+
+/*
+ * Called after command (no data transfer) or after the write (to device)
+ * operation is completed
+ */
+static int bot_send_status_response(struct usbg_cmd *cmd)
+{
+	bool moved_data = false;
+
+	if (!cmd->is_read)
+		moved_data = true;
+	return bot_send_status(cmd, moved_data);
+}
+
+/* Read request completed, now we have to send the CSW */
+static void bot_read_compl(struct usb_ep *ep, struct usb_request *req)
+{
+	struct usbg_cmd *cmd = req->context;
+
+	if (req->status < 0)
+		pr_err("ERR %s(%d)\n", __func__, __LINE__);
+
+	bot_send_status(cmd, true);
+}
+
+static int bot_send_read_response(struct usbg_cmd *cmd)
+{
+	struct f_uas *fu = cmd->fu;
+	struct se_cmd *se_cmd = &cmd->se_cmd;
+	struct usb_gadget *gadget = fuas_to_gadget(fu);
+	int ret;
+
+	if (!cmd->data_len) {
+		cmd->csw_code = US_BULK_STAT_PHASE;
+		bot_send_bad_status(cmd);
+		return 0;
+	}
+
+	if (!gadget->sg_supported) {
+		cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
+		if (!cmd->data_buf)
+			return -ENOMEM;
+
+		sg_copy_to_buffer(se_cmd->t_data_sg,
+				se_cmd->t_data_nents,
+				cmd->data_buf,
+				se_cmd->data_length);
+
+		fu->bot_req_in->buf = cmd->data_buf;
+	} else {
+		fu->bot_req_in->buf = NULL;
+		fu->bot_req_in->num_sgs = se_cmd->t_data_nents;
+		fu->bot_req_in->sg = se_cmd->t_data_sg;
+	}
+
+	fu->bot_req_in->complete = bot_read_compl;
+	fu->bot_req_in->length = se_cmd->data_length;
+	fu->bot_req_in->context = cmd;
+	ret = usb_ep_queue(fu->ep_in, fu->bot_req_in, GFP_ATOMIC);
+	if (ret)
+		pr_err("%s(%d)\n", __func__, __LINE__);
+	return 0;
+}
+
+static void usbg_data_write_cmpl(struct usb_ep *, struct usb_request *);
+static int usbg_prepare_w_request(struct usbg_cmd *, struct usb_request *);
+
+static int bot_send_write_request(struct usbg_cmd *cmd)
+{
+	struct f_uas *fu = cmd->fu;
+	struct se_cmd *se_cmd = &cmd->se_cmd;
+	struct usb_gadget *gadget = fuas_to_gadget(fu);
+	int ret;
+
+	init_completion(&cmd->write_complete);
+	cmd->fu = fu;
+
+	if (!cmd->data_len) {
+		cmd->csw_code = US_BULK_STAT_PHASE;
+		return -EINVAL;
+	}
+
+	if (!gadget->sg_supported) {
+		cmd->data_buf = kmalloc(se_cmd->data_length, GFP_KERNEL);
+		if (!cmd->data_buf)
+			return -ENOMEM;
+
+		fu->bot_req_out->buf = cmd->data_buf;
+	} else {
+		fu->bot_req_out->buf = NULL;
+		fu->bot_req_out->num_sgs = se_cmd->t_data_nents;
+		fu->bot_req_out->sg = se_cmd->t_data_sg;
+	}
+
+	fu->bot_req_out->complete = usbg_data_write_cmpl;
+	fu->bot_req_out->length = se_cmd->data_length;
+	fu->bot_req_out->context = cmd;
+
+	ret = usbg_prepare_w_request(cmd, fu->bot_req_out);
+	if (ret)
+		goto cleanup;
+	ret = usb_ep_queue(fu->ep_out, fu->bot_req_out, GFP_KERNEL);
+	if (ret)
+		pr_err("%s(%d)\n", __func__, __LINE__);
+
+	wait_for_completion(&cmd->write_complete);
+	transport_generic_process_write(se_cmd);
+cleanup:
+	return ret;
+}
+
+static int bot_submit_command(struct f_uas *, void *, unsigned int);
+
+static void bot_cmd_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct f_uas *fu = req->context;
+	int ret;
+
+	fu->flags &= ~USBG_BOT_CMD_PEND;
+
+	if (req->status < 0)
+		return;
+
+	ret = bot_submit_command(fu, req->buf, req->actual);
+	if (ret)
+		pr_err("%s(%d): %d\n", __func__, __LINE__, ret);
+}
+
+static int bot_prepare_reqs(struct f_uas *fu)
+{
+	int ret;
+
+	fu->bot_req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
+	if (!fu->bot_req_in)
+		goto err;
+
+	fu->bot_req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
+	if (!fu->bot_req_out)
+		goto err_out;
+
+	fu->cmd.req = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
+	if (!fu->cmd.req)
+		goto err_cmd;
+
+	fu->bot_status.req = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
+	if (!fu->bot_status.req)
+		goto err_sts;
+
+	fu->bot_status.req->buf = &fu->bot_status.csw;
+	fu->bot_status.req->length = US_BULK_CS_WRAP_LEN;
+	fu->bot_status.req->complete = bot_status_complete;
+	fu->bot_status.csw.Signature = cpu_to_le32(US_BULK_CS_SIGN);
+
+	fu->cmd.buf = kmalloc(fu->ep_out->maxpacket, GFP_KERNEL);
+	if (!fu->cmd.buf)
+		goto err_buf;
+
+	fu->cmd.req->complete = bot_cmd_complete;
+	fu->cmd.req->buf = fu->cmd.buf;
+	fu->cmd.req->length = fu->ep_out->maxpacket;
+	fu->cmd.req->context = fu;
+
+	ret = bot_enqueue_cmd_cbw(fu);
+	if (ret)
+		goto err_queue;
+	return 0;
+err_queue:
+	kfree(fu->cmd.buf);
+	fu->cmd.buf = NULL;
+err_buf:
+	usb_ep_free_request(fu->ep_in, fu->bot_status.req);
+err_sts:
+	usb_ep_free_request(fu->ep_out, fu->cmd.req);
+	fu->cmd.req = NULL;
+err_cmd:
+	usb_ep_free_request(fu->ep_out, fu->bot_req_out);
+	fu->bot_req_out = NULL;
+err_out:
+	usb_ep_free_request(fu->ep_in, fu->bot_req_in);
+	fu->bot_req_in = NULL;
+err:
+	pr_err("BOT: endpoint setup failed\n");
+	return -ENOMEM;
+}
+
+void bot_cleanup_old_alt(struct f_uas *fu)
+{
+	if (!(fu->flags & USBG_ENABLED))
+		return;
+
+	usb_ep_disable(fu->ep_in);
+	usb_ep_disable(fu->ep_out);
+
+	if (!fu->bot_req_in)
+		return;
+
+	usb_ep_free_request(fu->ep_in, fu->bot_req_in);
+	usb_ep_free_request(fu->ep_out, fu->bot_req_out);
+	usb_ep_free_request(fu->ep_out, fu->cmd.req);
+	usb_ep_free_request(fu->ep_out, fu->bot_status.req);
+
+	kfree(fu->cmd.buf);
+
+	fu->bot_req_in = NULL;
+	fu->bot_req_out = NULL;
+	fu->cmd.req = NULL;
+	fu->bot_status.req = NULL;
+	fu->cmd.buf = NULL;
+}
+
+static void bot_set_alt(struct f_uas *fu)
+{
+	struct usb_function *f = &fu->function;
+	struct usb_gadget *gadget = f->config->cdev->gadget;
+	int ret;
+
+	fu->flags = USBG_IS_BOT;
+
+	config_ep_by_speed(gadget, f, fu->ep_in);
+	ret = usb_ep_enable(fu->ep_in);
+	if (ret)
+		goto err_b_in;
+
+	config_ep_by_speed(gadget, f, fu->ep_out);
+	ret = usb_ep_enable(fu->ep_out);
+	if (ret)
+		goto err_b_out;
+
+	ret = bot_prepare_reqs(fu);
+	if (ret)
+		goto err_wq;
+	fu->flags |= USBG_ENABLED;
+	pr_info("Using the BOT protocol\n");
+	return;
+err_wq:
+	usb_ep_disable(fu->ep_out);
+err_b_out:
+	usb_ep_disable(fu->ep_in);
+err_b_in:
+	fu->flags = USBG_IS_BOT;
+}
+
+static int usbg_bot_setup(struct usb_function *f,
+		const struct usb_ctrlrequest *ctrl)
+{
+	struct f_uas *fu = to_f_uas(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
+	u16 w_value = le16_to_cpu(ctrl->wValue);
+	u16 w_length = le16_to_cpu(ctrl->wLength);
+	int luns;
+	u8 *ret_lun;
+
+	switch (ctrl->bRequest) {
+	case US_BULK_GET_MAX_LUN:
+		if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_CLASS |
+					USB_RECIP_INTERFACE))
+			return -ENOTSUPP;
+
+		if (w_length < 1)
+			return -EINVAL;
+		if (w_value != 0)
+			return -EINVAL;
+		luns = atomic_read(&fu->tpg->tpg_port_count);
+		if (!luns) {
+			pr_err("No LUNs configured?\n");
+			return -EINVAL;
+		}
+		/*
+		 * If 4 LUNs are present we return 3 i.e. LUN 0..3 can be
+		 * accessed. The upper limit is 0xf
+		 */
+		luns--;
+		if (luns > 0xf) {
+			pr_info_once("Limiting the number of luns to 16\n");
+			luns = 0xf;
+		}
+		ret_lun = cdev->req->buf;
+		*ret_lun = luns;
+		cdev->req->length = 1;
+		return usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
+		break;
+
+	case US_BULK_RESET_REQUEST:
+		/* XXX maybe we should remove previous requests for IN + OUT */
+		bot_enqueue_cmd_cbw(fu);
+		return 0;
+		break;
+	};
+	return -ENOTSUPP;
+}
+
+/* Start uas.c code */
+
+static void uasp_cleanup_one_stream(struct f_uas *fu, struct uas_stream *stream)
+{
+	/* We have either all three allocated or none */
+	if (!stream->req_in)
+		return;
+
+	usb_ep_free_request(fu->ep_in, stream->req_in);
+	usb_ep_free_request(fu->ep_out, stream->req_out);
+	usb_ep_free_request(fu->ep_status, stream->req_status);
+
+	stream->req_in = NULL;
+	stream->req_out = NULL;
+	stream->req_status = NULL;
+}
+
+static void uasp_free_cmdreq(struct f_uas *fu)
+{
+	usb_ep_free_request(fu->ep_cmd, fu->cmd.req);
+	kfree(fu->cmd.buf);
+	fu->cmd.req = NULL;
+	fu->cmd.buf = NULL;
+}
+
+static void uasp_cleanup_old_alt(struct f_uas *fu)
+{
+	int i;
+
+	if (!(fu->flags & USBG_ENABLED))
+		return;
+
+	usb_ep_disable(fu->ep_in);
+	usb_ep_disable(fu->ep_out);
+	usb_ep_disable(fu->ep_status);
+	usb_ep_disable(fu->ep_cmd);
+
+	for (i = 0; i < UASP_SS_EP_COMP_NUM_STREAMS; i++)
+		uasp_cleanup_one_stream(fu, &fu->stream[i]);
+	uasp_free_cmdreq(fu);
+}
+
+static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req);
+
+static int uasp_prepare_r_request(struct usbg_cmd *cmd)
+{
+	struct se_cmd *se_cmd = &cmd->se_cmd;
+	struct f_uas *fu = cmd->fu;
+	struct usb_gadget *gadget = fuas_to_gadget(fu);
+	struct uas_stream *stream = cmd->stream;
+
+	if (!gadget->sg_supported) {
+		cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
+		if (!cmd->data_buf)
+			return -ENOMEM;
+
+		sg_copy_to_buffer(se_cmd->t_data_sg,
+				se_cmd->t_data_nents,
+				cmd->data_buf,
+				se_cmd->data_length);
+
+		stream->req_in->buf = cmd->data_buf;
+	} else {
+		stream->req_in->buf = NULL;
+		stream->req_in->num_sgs = se_cmd->t_data_nents;
+		stream->req_in->sg = se_cmd->t_data_sg;
+	}
+
+	stream->req_in->complete = uasp_status_data_cmpl;
+	stream->req_in->length = se_cmd->data_length;
+	stream->req_in->context = cmd;
+
+	cmd->state = UASP_SEND_STATUS;
+	return 0;
+}
+
+static void uasp_prepare_status(struct usbg_cmd *cmd)
+{
+	struct se_cmd *se_cmd = &cmd->se_cmd;
+	struct sense_iu *iu = &cmd->sense_iu;
+	struct uas_stream *stream = cmd->stream;
+
+	cmd->state = UASP_QUEUE_COMMAND;
+	iu->iu_id = IU_ID_STATUS;
+	iu->tag = cpu_to_be16(cmd->tag);
+
+	/*
+	 * iu->status_qual = cpu_to_be16(STATUS QUALIFIER SAM-4. Where R U?);
+	 */
+	iu->len = cpu_to_be16(se_cmd->scsi_sense_length);
+	iu->status = se_cmd->scsi_status;
+	stream->req_status->context = cmd;
+	stream->req_status->length = se_cmd->scsi_sense_length + 16;
+	stream->req_status->buf = iu;
+	stream->req_status->complete = uasp_status_data_cmpl;
+}
+
+static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req)
+{
+	struct usbg_cmd *cmd = req->context;
+	struct uas_stream *stream = cmd->stream;
+	struct f_uas *fu = cmd->fu;
+	int ret;
+
+	if (req->status < 0)
+		goto cleanup;
+
+	switch (cmd->state) {
+	case UASP_SEND_DATA:
+		ret = uasp_prepare_r_request(cmd);
+		if (ret)
+			goto cleanup;
+		ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC);
+		if (ret)
+			pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+		break;
+
+	case UASP_RECEIVE_DATA:
+		ret = usbg_prepare_w_request(cmd, stream->req_out);
+		if (ret)
+			goto cleanup;
+		ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC);
+		if (ret)
+			pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+		break;
+
+	case UASP_SEND_STATUS:
+		uasp_prepare_status(cmd);
+		ret = usb_ep_queue(fu->ep_status, stream->req_status,
+				GFP_ATOMIC);
+		if (ret)
+			pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+		break;
+
+	case UASP_QUEUE_COMMAND:
+		usbg_cleanup_cmd(cmd);
+		usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
+		break;
+
+	default:
+		BUG();
+	};
+	return;
+
+cleanup:
+	usbg_cleanup_cmd(cmd);
+}
+
+static int uasp_send_status_response(struct usbg_cmd *cmd)
+{
+	struct f_uas *fu = cmd->fu;
+	struct uas_stream *stream = cmd->stream;
+	struct sense_iu *iu = &cmd->sense_iu;
+
+	iu->tag = cpu_to_be16(cmd->tag);
+	stream->req_status->complete = uasp_status_data_cmpl;
+	stream->req_status->context = cmd;
+	cmd->fu = fu;
+	uasp_prepare_status(cmd);
+	return usb_ep_queue(fu->ep_status, stream->req_status, GFP_ATOMIC);
+}
+
+static int uasp_send_read_response(struct usbg_cmd *cmd)
+{
+	struct f_uas *fu = cmd->fu;
+	struct uas_stream *stream = cmd->stream;
+	struct sense_iu *iu = &cmd->sense_iu;
+	int ret;
+
+	cmd->fu = fu;
+
+	iu->tag = cpu_to_be16(cmd->tag);
+	if (fu->flags & USBG_USE_STREAMS) {
+
+		ret = uasp_prepare_r_request(cmd);
+		if (ret)
+			goto out;
+		ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC);
+		if (ret) {
+			pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+			kfree(cmd->data_buf);
+			cmd->data_buf = NULL;
+		}
+
+	} else {
+
+		iu->iu_id = IU_ID_READ_READY;
+		iu->tag = cpu_to_be16(cmd->tag);
+
+		stream->req_status->complete = uasp_status_data_cmpl;
+		stream->req_status->context = cmd;
+
+		cmd->state = UASP_SEND_DATA;
+		stream->req_status->buf = iu;
+		stream->req_status->length = sizeof(struct iu);
+
+		ret = usb_ep_queue(fu->ep_status, stream->req_status,
+				GFP_ATOMIC);
+		if (ret)
+			pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+	}
+out:
+	return ret;
+}
+
+static int uasp_send_write_request(struct usbg_cmd *cmd)
+{
+	struct f_uas *fu = cmd->fu;
+	struct se_cmd *se_cmd = &cmd->se_cmd;
+	struct uas_stream *stream = cmd->stream;
+	struct sense_iu *iu = &cmd->sense_iu;
+	int ret;
+
+	init_completion(&cmd->write_complete);
+	cmd->fu = fu;
+
+	iu->tag = cpu_to_be16(cmd->tag);
+
+	if (fu->flags & USBG_USE_STREAMS) {
+
+		ret = usbg_prepare_w_request(cmd, stream->req_out);
+		if (ret)
+			goto cleanup;
+		ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC);
+		if (ret)
+			pr_err("%s(%d)\n", __func__, __LINE__);
+
+	} else {
+
+		iu->iu_id = IU_ID_WRITE_READY;
+		iu->tag = cpu_to_be16(cmd->tag);
+
+		stream->req_status->complete = uasp_status_data_cmpl;
+		stream->req_status->context = cmd;
+
+		cmd->state = UASP_RECEIVE_DATA;
+		stream->req_status->buf = iu;
+		stream->req_status->length = sizeof(struct iu);
+
+		ret = usb_ep_queue(fu->ep_status, stream->req_status,
+				GFP_ATOMIC);
+		if (ret)
+			pr_err("%s(%d)\n", __func__, __LINE__);
+	}
+
+	wait_for_completion(&cmd->write_complete);
+	transport_generic_process_write(se_cmd);
+cleanup:
+	return ret;
+}
+
+static int usbg_submit_command(struct f_uas *, void *, unsigned int);
+
+static void uasp_cmd_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct f_uas *fu = req->context;
+	int ret;
+
+	if (req->status < 0)
+		return;
+
+	ret = usbg_submit_command(fu, req->buf, req->actual);
+	/*
+	 * Once we tune for performance enqueue the command req here again so
+	 * we can receive a second command while we processing this one. Pay
+	 * attention to properly sync STAUS endpoint with DATA IN + OUT so you
+	 * don't break HS.
+	 */
+	if (!ret)
+		return;
+	usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
+}
+
+static int uasp_alloc_stream_res(struct f_uas *fu, struct uas_stream *stream)
+{
+	stream->req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
+	if (!stream->req_in)
+		goto out;
+
+	stream->req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
+	if (!stream->req_out)
+		goto err_out;
+
+	stream->req_status = usb_ep_alloc_request(fu->ep_status, GFP_KERNEL);
+	if (!stream->req_status)
+		goto err_sts;
+
+	return 0;
+err_sts:
+	usb_ep_free_request(fu->ep_status, stream->req_status);
+	stream->req_status = NULL;
+err_out:
+	usb_ep_free_request(fu->ep_out, stream->req_out);
+	stream->req_out = NULL;
+out:
+	return -ENOMEM;
+}
+
+static int uasp_alloc_cmd(struct f_uas *fu)
+{
+	fu->cmd.req = usb_ep_alloc_request(fu->ep_cmd, GFP_KERNEL);
+	if (!fu->cmd.req)
+		goto err;
+
+	fu->cmd.buf = kmalloc(fu->ep_cmd->maxpacket, GFP_KERNEL);
+	if (!fu->cmd.buf)
+		goto err_buf;
+
+	fu->cmd.req->complete = uasp_cmd_complete;
+	fu->cmd.req->buf = fu->cmd.buf;
+	fu->cmd.req->length = fu->ep_cmd->maxpacket;
+	fu->cmd.req->context = fu;
+	return 0;
+
+err_buf:
+	usb_ep_free_request(fu->ep_cmd, fu->cmd.req);
+err:
+	return -ENOMEM;
+}
+
+static void uasp_setup_stream_res(struct f_uas *fu, int max_streams)
+{
+	int i;
+
+	for (i = 0; i < max_streams; i++) {
+		struct uas_stream *s = &fu->stream[i];
+
+		s->req_in->stream_id = i + 1;
+		s->req_out->stream_id = i + 1;
+		s->req_status->stream_id = i + 1;
+	}
+}
+
+static int uasp_prepare_reqs(struct f_uas *fu)
+{
+	int ret;
+	int i;
+	int max_streams;
+
+	if (fu->flags & USBG_USE_STREAMS)
+		max_streams = UASP_SS_EP_COMP_NUM_STREAMS;
+	else
+		max_streams = 1;
+
+	for (i = 0; i < max_streams; i++) {
+		ret = uasp_alloc_stream_res(fu, &fu->stream[i]);
+		if (ret)
+			goto err_cleanup;
+	}
+
+	ret = uasp_alloc_cmd(fu);
+	if (ret)
+		goto err_free_stream;
+	uasp_setup_stream_res(fu, max_streams);
+
+	ret = usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
+	if (ret)
+		goto err_free_stream;
+
+	return 0;
+
+err_free_stream:
+	uasp_free_cmdreq(fu);
+
+err_cleanup:
+	if (i) {
+		do {
+			uasp_cleanup_one_stream(fu, &fu->stream[i - 1]);
+			i--;
+		} while (i);
+	}
+	pr_err("UASP: endpoint setup failed\n");
+	return ret;
+}
+
+static void uasp_set_alt(struct f_uas *fu)
+{
+	struct usb_function *f = &fu->function;
+	struct usb_gadget *gadget = f->config->cdev->gadget;
+	int ret;
+
+	fu->flags = USBG_IS_UAS;
+
+	if (gadget->speed == USB_SPEED_SUPER)
+		fu->flags |= USBG_USE_STREAMS;
+
+	config_ep_by_speed(gadget, f, fu->ep_in);
+	ret = usb_ep_enable(fu->ep_in);
+	if (ret)
+		goto err_b_in;
+
+	config_ep_by_speed(gadget, f, fu->ep_out);
+	ret = usb_ep_enable(fu->ep_out);
+	if (ret)
+		goto err_b_out;
+
+	config_ep_by_speed(gadget, f, fu->ep_cmd);
+	ret = usb_ep_enable(fu->ep_cmd);
+	if (ret)
+		goto err_cmd;
+	config_ep_by_speed(gadget, f, fu->ep_status);
+	ret = usb_ep_enable(fu->ep_status);
+	if (ret)
+		goto err_status;
+
+	ret = uasp_prepare_reqs(fu);
+	if (ret)
+		goto err_wq;
+	fu->flags |= USBG_ENABLED;
+
+	pr_info("Using the UAS protocol\n");
+	return;
+err_wq:
+	usb_ep_disable(fu->ep_status);
+err_status:
+	usb_ep_disable(fu->ep_cmd);
+err_cmd:
+	usb_ep_disable(fu->ep_out);
+err_b_out:
+	usb_ep_disable(fu->ep_in);
+err_b_in:
+	fu->flags = 0;
+}
+
+static int get_cmd_dir(const unsigned char *cdb)
+{
+	int ret;
+
+	switch (cdb[0]) {
+	case READ_6:
+	case READ_10:
+	case READ_12:
+	case READ_16:
+	case INQUIRY:
+	case MODE_SENSE:
+	case MODE_SENSE_10:
+	case SERVICE_ACTION_IN:
+	case MAINTENANCE_IN:
+	case PERSISTENT_RESERVE_IN:
+	case SECURITY_PROTOCOL_IN:
+	case ACCESS_CONTROL_IN:
+	case REPORT_LUNS:
+	case READ_BLOCK_LIMITS:
+	case READ_POSITION:
+	case READ_CAPACITY:
+	case READ_TOC:
+	case READ_FORMAT_CAPACITIES:
+	case REQUEST_SENSE:
+		ret = DMA_FROM_DEVICE;
+		break;
+
+	case WRITE_6:
+	case WRITE_10:
+	case WRITE_12:
+	case WRITE_16:
+	case MODE_SELECT:
+	case MODE_SELECT_10:
+	case WRITE_VERIFY:
+	case WRITE_VERIFY_12:
+	case PERSISTENT_RESERVE_OUT:
+	case MAINTENANCE_OUT:
+	case SECURITY_PROTOCOL_OUT:
+	case ACCESS_CONTROL_OUT:
+		ret = DMA_TO_DEVICE;
+		break;
+	case ALLOW_MEDIUM_REMOVAL:
+	case TEST_UNIT_READY:
+	case SYNCHRONIZE_CACHE:
+	case START_STOP:
+	case ERASE:
+	case REZERO_UNIT:
+	case SEEK_10:
+	case SPACE:
+	case VERIFY:
+	case WRITE_FILEMARKS:
+		ret = DMA_NONE;
+		break;
+	default:
+		pr_warn("target: Unknown data direction for SCSI Opcode "
+				"0x%02x\n", cdb[0]);
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static void usbg_data_write_cmpl(struct usb_ep *ep, struct usb_request *req)
+{
+	struct usbg_cmd *cmd = req->context;
+	struct se_cmd *se_cmd = &cmd->se_cmd;
+
+	if (req->status < 0) {
+		pr_err("%s() state %d transfer failed\n", __func__, cmd->state);
+		goto cleanup;
+	}
+
+	if (req->num_sgs == 0) {
+		sg_copy_from_buffer(se_cmd->t_data_sg,
+				se_cmd->t_data_nents,
+				cmd->data_buf,
+				se_cmd->data_length);
+	}
+
+	complete(&cmd->write_complete);
+	return;
+
+cleanup:
+	usbg_cleanup_cmd(cmd);
+}
+
+static int usbg_prepare_w_request(struct usbg_cmd *cmd, struct usb_request *req)
+{
+	struct se_cmd *se_cmd = &cmd->se_cmd;
+	struct f_uas *fu = cmd->fu;
+	struct usb_gadget *gadget = fuas_to_gadget(fu);
+
+	if (!gadget->sg_supported) {
+		cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
+		if (!cmd->data_buf)
+			return -ENOMEM;
+
+		req->buf = cmd->data_buf;
+	} else {
+		req->buf = NULL;
+		req->num_sgs = se_cmd->t_data_nents;
+		req->sg = se_cmd->t_data_sg;
+	}
+
+	req->complete = usbg_data_write_cmpl;
+	req->length = se_cmd->data_length;
+	req->context = cmd;
+	return 0;
+}
+
+static int usbg_send_status_response(struct se_cmd *se_cmd)
+{
+	struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+			se_cmd);
+	struct f_uas *fu = cmd->fu;
+
+	if (fu->flags & USBG_IS_BOT)
+		return bot_send_status_response(cmd);
+	else
+		return uasp_send_status_response(cmd);
+}
+
+static int usbg_send_write_request(struct se_cmd *se_cmd)
+{
+	struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+			se_cmd);
+	struct f_uas *fu = cmd->fu;
+
+	if (fu->flags & USBG_IS_BOT)
+		return bot_send_write_request(cmd);
+	else
+		return uasp_send_write_request(cmd);
+}
+
+static int usbg_send_read_response(struct se_cmd *se_cmd)
+{
+	struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+			se_cmd);
+	struct f_uas *fu = cmd->fu;
+
+	if (fu->flags & USBG_IS_BOT)
+		return bot_send_read_response(cmd);
+	else
+		return uasp_send_read_response(cmd);
+}
+
+static void usbg_cmd_work(struct work_struct *work)
+{
+	struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work);
+	struct se_cmd *se_cmd;
+	struct tcm_usbg_nexus *tv_nexus;
+	struct usbg_tpg *tpg;
+	int dir;
+
+	se_cmd = &cmd->se_cmd;
+	tpg = cmd->fu->tpg;
+	tv_nexus = tpg->tpg_nexus;
+	dir = get_cmd_dir(cmd->cmd_buf);
+	if (dir < 0) {
+		transport_init_se_cmd(se_cmd,
+				tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
+				tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
+				cmd->prio_attr, cmd->sense_iu.sense);
+
+		transport_send_check_condition_and_sense(se_cmd,
+				TCM_UNSUPPORTED_SCSI_OPCODE, 1);
+		usbg_cleanup_cmd(cmd);
+		return;
+	}
+
+	target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
+			cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
+			0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE);
+}
+
+static int usbg_submit_command(struct f_uas *fu,
+		void *cmdbuf, unsigned int len)
+{
+	struct command_iu *cmd_iu = cmdbuf;
+	struct usbg_cmd *cmd;
+	struct usbg_tpg *tpg;
+	struct se_cmd *se_cmd;
+	struct tcm_usbg_nexus *tv_nexus;
+	u32 cmd_len;
+	int ret;
+
+	if (cmd_iu->iu_id != IU_ID_COMMAND) {
+		pr_err("Unsupported type %d\n", cmd_iu->iu_id);
+		return -EINVAL;
+	}
+
+	cmd = kzalloc(sizeof *cmd, GFP_ATOMIC);
+	if (!cmd)
+		return -ENOMEM;
+
+	cmd->fu = fu;
+
+	/* XXX until I figure out why I can't free in on complete */
+	kref_init(&cmd->ref);
+	kref_get(&cmd->ref);
+
+	tpg = fu->tpg;
+	cmd_len = (cmd_iu->len & ~0x3) + 16;
+	if (cmd_len > USBG_MAX_CMD)
+		goto err;
+
+	memcpy(cmd->cmd_buf, cmd_iu->cdb, cmd_len);
+
+	cmd->tag = be16_to_cpup(&cmd_iu->tag);
+	if (fu->flags & USBG_USE_STREAMS) {
+		if (cmd->tag > UASP_SS_EP_COMP_NUM_STREAMS)
+			goto err;
+		if (!cmd->tag)
+			cmd->stream = &fu->stream[0];
+		else
+			cmd->stream = &fu->stream[cmd->tag - 1];
+	} else {
+		cmd->stream = &fu->stream[0];
+	}
+
+	tv_nexus = tpg->tpg_nexus;
+	if (!tv_nexus) {
+		pr_err("Missing nexus, ignoring command\n");
+		goto err;
+	}
+
+	switch (cmd_iu->prio_attr & 0x7) {
+	case UAS_HEAD_TAG:
+		cmd->prio_attr = MSG_HEAD_TAG;
+		break;
+	case UAS_ORDERED_TAG:
+		cmd->prio_attr = MSG_ORDERED_TAG;
+		break;
+	case UAS_ACA:
+		cmd->prio_attr = MSG_ACA_TAG;
+		break;
+	default:
+		pr_debug_once("Unsupported prio_attr: %02x.\n",
+				cmd_iu->prio_attr);
+	case UAS_SIMPLE_TAG:
+		cmd->prio_attr = MSG_SIMPLE_TAG;
+		break;
+	}
+
+	se_cmd = &cmd->se_cmd;
+	cmd->unpacked_lun = scsilun_to_int(&cmd_iu->lun);
+
+	INIT_WORK(&cmd->work, usbg_cmd_work);
+	ret = queue_work(tpg->workqueue, &cmd->work);
+	if (ret < 0)
+		goto err;
+
+	return 0;
+err:
+	kfree(cmd);
+	return -EINVAL;
+}
+
+static void bot_cmd_work(struct work_struct *work)
+{
+	struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work);
+	struct se_cmd *se_cmd;
+	struct tcm_usbg_nexus *tv_nexus;
+	struct usbg_tpg *tpg;
+	int dir;
+
+	se_cmd = &cmd->se_cmd;
+	tpg = cmd->fu->tpg;
+	tv_nexus = tpg->tpg_nexus;
+	dir = get_cmd_dir(cmd->cmd_buf);
+	if (dir < 0) {
+		transport_init_se_cmd(se_cmd,
+				tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
+				tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
+				cmd->prio_attr, cmd->sense_iu.sense);
+
+		transport_send_check_condition_and_sense(se_cmd,
+				TCM_UNSUPPORTED_SCSI_OPCODE, 1);
+		usbg_cleanup_cmd(cmd);
+		return;
+	}
+
+	target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
+			cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
+			cmd->data_len, cmd->prio_attr, dir, 0);
+}
+
+static int bot_submit_command(struct f_uas *fu,
+		void *cmdbuf, unsigned int len)
+{
+	struct bulk_cb_wrap *cbw = cmdbuf;
+	struct usbg_cmd *cmd;
+	struct usbg_tpg *tpg;
+	struct se_cmd *se_cmd;
+	struct tcm_usbg_nexus *tv_nexus;
+	u32 cmd_len;
+	int ret;
+
+	if (cbw->Signature != cpu_to_le32(US_BULK_CB_SIGN)) {
+		pr_err("Wrong signature on CBW\n");
+		return -EINVAL;
+	}
+	if (len != 31) {
+		pr_err("Wrong length for CBW\n");
+		return -EINVAL;
+	}
+
+	cmd_len = cbw->Length;
+	if (cmd_len < 1 || cmd_len > 16)
+		return -EINVAL;
+
+	cmd = kzalloc(sizeof *cmd, GFP_ATOMIC);
+	if (!cmd)
+		return -ENOMEM;
+
+	cmd->fu = fu;
+
+	/* XXX until I figure out why I can't free in on complete */
+	kref_init(&cmd->ref);
+	kref_get(&cmd->ref);
+
+	tpg = fu->tpg;
+
+	memcpy(cmd->cmd_buf, cbw->CDB, cmd_len);
+
+	cmd->bot_tag = cbw->Tag;
+
+	tv_nexus = tpg->tpg_nexus;
+	if (!tv_nexus) {
+		pr_err("Missing nexus, ignoring command\n");
+		goto err;
+	}
+
+	cmd->prio_attr = MSG_SIMPLE_TAG;
+	se_cmd = &cmd->se_cmd;
+	cmd->unpacked_lun = cbw->Lun;
+	cmd->is_read = cbw->Flags & US_BULK_FLAG_IN ? 1 : 0;
+	cmd->data_len = le32_to_cpu(cbw->DataTransferLength);
+
+	INIT_WORK(&cmd->work, bot_cmd_work);
+	ret = queue_work(tpg->workqueue, &cmd->work);
+	if (ret < 0)
+		goto err;
+
+	return 0;
+err:
+	kfree(cmd);
+	return -EINVAL;
+}
+
+/* Start fabric.c code */
+
+static int usbg_check_true(struct se_portal_group *se_tpg)
+{
+	return 1;
+}
+
+static int usbg_check_false(struct se_portal_group *se_tpg)
+{
+	return 0;
+}
+
+static char *usbg_get_fabric_name(void)
+{
+	return "usb_gadget";
+}
+
+static u8 usbg_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+{
+	struct usbg_tpg *tpg = container_of(se_tpg,
+				struct usbg_tpg, se_tpg);
+	struct usbg_tport *tport = tpg->tport;
+	u8 proto_id;
+
+	switch (tport->tport_proto_id) {
+	case SCSI_PROTOCOL_SAS:
+	default:
+		proto_id = sas_get_fabric_proto_ident(se_tpg);
+		break;
+	}
+
+	return proto_id;
+}
+
+static char *usbg_get_fabric_wwn(struct se_portal_group *se_tpg)
+{
+	struct usbg_tpg *tpg = container_of(se_tpg,
+				struct usbg_tpg, se_tpg);
+	struct usbg_tport *tport = tpg->tport;
+
+	return &tport->tport_name[0];
+}
+
+static u16 usbg_get_tag(struct se_portal_group *se_tpg)
+{
+	struct usbg_tpg *tpg = container_of(se_tpg,
+				struct usbg_tpg, se_tpg);
+	return tpg->tport_tpgt;
+}
+
+static u32 usbg_get_default_depth(struct se_portal_group *se_tpg)
+{
+	return 1;
+}
+
+static u32 usbg_get_pr_transport_id(
+	struct se_portal_group *se_tpg,
+	struct se_node_acl *se_nacl,
+	struct t10_pr_registration *pr_reg,
+	int *format_code,
+	unsigned char *buf)
+{
+	struct usbg_tpg *tpg = container_of(se_tpg,
+				struct usbg_tpg, se_tpg);
+	struct usbg_tport *tport = tpg->tport;
+	int ret = 0;
+
+	switch (tport->tport_proto_id) {
+	case SCSI_PROTOCOL_SAS:
+	default:
+		ret = sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
+					format_code, buf);
+		break;
+	}
+
+	return ret;
+}
+
+static u32 usbg_get_pr_transport_id_len(
+	struct se_portal_group *se_tpg,
+	struct se_node_acl *se_nacl,
+	struct t10_pr_registration *pr_reg,
+	int *format_code)
+{
+	struct usbg_tpg *tpg = container_of(se_tpg,
+				struct usbg_tpg, se_tpg);
+	struct usbg_tport *tport = tpg->tport;
+	int ret = 0;
+
+	switch (tport->tport_proto_id) {
+	case SCSI_PROTOCOL_SAS:
+	default:
+		ret = sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
+					format_code);
+		break;
+	}
+
+	return ret;
+}
+
+static char *usbg_parse_pr_out_transport_id(
+	struct se_portal_group *se_tpg,
+	const char *buf,
+	u32 *out_tid_len,
+	char **port_nexus_ptr)
+{
+	struct usbg_tpg *tpg = container_of(se_tpg,
+				struct usbg_tpg, se_tpg);
+	struct usbg_tport *tport = tpg->tport;
+	char *tid = NULL;
+
+	switch (tport->tport_proto_id) {
+	case SCSI_PROTOCOL_SAS:
+	default:
+		tid = sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
+					port_nexus_ptr);
+	}
+
+	return tid;
+}
+
+static struct se_node_acl *usbg_alloc_fabric_acl(struct se_portal_group *se_tpg)
+{
+	struct usbg_nacl *nacl;
+
+	nacl = kzalloc(sizeof(struct usbg_nacl), GFP_KERNEL);
+	if (!nacl) {
+		printk(KERN_ERR "Unable to alocate struct usbg_nacl\n");
+		return NULL;
+	}
+
+	return &nacl->se_node_acl;
+}
+
+static void usbg_release_fabric_acl(
+	struct se_portal_group *se_tpg,
+	struct se_node_acl *se_nacl)
+{
+	struct usbg_nacl *nacl = container_of(se_nacl,
+			struct usbg_nacl, se_node_acl);
+	kfree(nacl);
+}
+
+static u32 usbg_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+	return 1;
+}
+
+static int usbg_new_cmd(struct se_cmd *se_cmd)
+{
+	struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+			se_cmd);
+	int ret;
+
+	ret = target_setup_cmd_from_cdb(se_cmd, cmd->cmd_buf);
+	if (ret)
+		return ret;
+
+	return transport_generic_map_mem_to_cmd(se_cmd, NULL, 0, NULL, 0);
+}
+
+static void usbg_cmd_release(struct kref *ref)
+{
+	struct usbg_cmd *cmd = container_of(ref, struct usbg_cmd,
+			ref);
+
+	transport_generic_free_cmd(&cmd->se_cmd, 0);
+}
+
+static void usbg_release_cmd(struct se_cmd *se_cmd)
+{
+	struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+			se_cmd);
+	kfree(cmd->data_buf);
+	kfree(cmd);
+	return;
+}
+
+static int usbg_shutdown_session(struct se_session *se_sess)
+{
+	return 0;
+}
+
+static void usbg_close_session(struct se_session *se_sess)
+{
+	return;
+}
+
+static u32 usbg_sess_get_index(struct se_session *se_sess)
+{
+	return 0;
+}
+
+/*
+ * XXX Error recovery: return != 0 if we expect writes. Dunno when that could be
+ */
+static int usbg_write_pending_status(struct se_cmd *se_cmd)
+{
+	return 0;
+}
+
+static void usbg_set_default_node_attrs(struct se_node_acl *nacl)
+{
+	return;
+}
+
+static u32 usbg_get_task_tag(struct se_cmd *se_cmd)
+{
+	struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+			se_cmd);
+	struct f_uas *fu = cmd->fu;
+
+	if (fu->flags & USBG_IS_BOT)
+		return le32_to_cpu(cmd->bot_tag);
+	else
+		return cmd->tag;
+}
+
+static int usbg_get_cmd_state(struct se_cmd *se_cmd)
+{
+	return 0;
+}
+
+static int usbg_queue_tm_rsp(struct se_cmd *se_cmd)
+{
+	return 0;
+}
+
+static u16 usbg_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)
+{
+	return 0;
+}
+
+static u16 usbg_get_fabric_sense_len(void)
+{
+	return 0;
+}
+
+static const char *usbg_check_wwn(const char *name)
+{
+	const char *n;
+	unsigned int len;
+
+	n = strstr(name, "naa.");
+	if (!n)
+		return NULL;
+	n += 4;
+	len = strlen(n);
+	if (len == 0 || len > USBG_NAMELEN - 1)
+		return NULL;
+	return n;
+}
+
+static struct se_node_acl *usbg_make_nodeacl(
+	struct se_portal_group *se_tpg,
+	struct config_group *group,
+	const char *name)
+{
+	struct se_node_acl *se_nacl, *se_nacl_new;
+	struct usbg_nacl *nacl;
+	u64 wwpn = 0;
+	u32 nexus_depth;
+	const char *wnn_name;
+
+	wnn_name = usbg_check_wwn(name);
+	if (!wnn_name)
+		return ERR_PTR(-EINVAL);
+	se_nacl_new = usbg_alloc_fabric_acl(se_tpg);
+	if (!(se_nacl_new))
+		return ERR_PTR(-ENOMEM);
+
+	nexus_depth = 1;
+	/*
+	 * se_nacl_new may be released by core_tpg_add_initiator_node_acl()
+	 * when converting a NodeACL from demo mode -> explict
+	 */
+	se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new,
+				name, nexus_depth);
+	if (IS_ERR(se_nacl)) {
+		usbg_release_fabric_acl(se_tpg, se_nacl_new);
+		return se_nacl;
+	}
+	/*
+	 * Locate our struct usbg_nacl and set the FC Nport WWPN
+	 */
+	nacl = container_of(se_nacl, struct usbg_nacl, se_node_acl);
+	nacl->iport_wwpn = wwpn;
+	snprintf(nacl->iport_name, sizeof(nacl->iport_name), "%s", name);
+	return se_nacl;
+}
+
+static void usbg_drop_nodeacl(struct se_node_acl *se_acl)
+{
+	struct usbg_nacl *nacl = container_of(se_acl,
+				struct usbg_nacl, se_node_acl);
+	core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1);
+	kfree(nacl);
+}
+
+struct usbg_tpg *the_only_tpg_I_currently_have;
+
+static struct se_portal_group *usbg_make_tpg(
+	struct se_wwn *wwn,
+	struct config_group *group,
+	const char *name)
+{
+	struct usbg_tport *tport = container_of(wwn, struct usbg_tport,
+			tport_wwn);
+	struct usbg_tpg *tpg;
+	unsigned long tpgt;
+	int ret;
+
+	if (strstr(name, "tpgt_") != name)
+		return ERR_PTR(-EINVAL);
+	if (kstrtoul(name + 5, 0, &tpgt) || tpgt > UINT_MAX)
+		return ERR_PTR(-EINVAL);
+	if (the_only_tpg_I_currently_have) {
+		pr_err("Until the gadget framework can't handle multiple\n");
+		pr_err("gadgets, you can't do this here.\n");
+		return ERR_PTR(-EBUSY);
+	}
+
+	tpg = kzalloc(sizeof(struct usbg_tpg), GFP_KERNEL);
+	if (!tpg) {
+		printk(KERN_ERR "Unable to allocate struct usbg_tpg");
+		return ERR_PTR(-ENOMEM);
+	}
+	mutex_init(&tpg->tpg_mutex);
+	atomic_set(&tpg->tpg_port_count, 0);
+	tpg->workqueue = alloc_workqueue("tcm_usb_gadget", 0, 1);
+	if (!tpg->workqueue) {
+		kfree(tpg);
+		return NULL;
+	}
+
+	tpg->tport = tport;
+	tpg->tport_tpgt = tpgt;
+
+	ret = core_tpg_register(&usbg_fabric_configfs->tf_ops, wwn,
+				&tpg->se_tpg, tpg,
+				TRANSPORT_TPG_TYPE_NORMAL);
+	if (ret < 0) {
+		destroy_workqueue(tpg->workqueue);
+		kfree(tpg);
+		return NULL;
+	}
+	the_only_tpg_I_currently_have = tpg;
+	return &tpg->se_tpg;
+}
+
+static void usbg_drop_tpg(struct se_portal_group *se_tpg)
+{
+	struct usbg_tpg *tpg = container_of(se_tpg,
+				struct usbg_tpg, se_tpg);
+
+	core_tpg_deregister(se_tpg);
+	destroy_workqueue(tpg->workqueue);
+	kfree(tpg);
+	the_only_tpg_I_currently_have = NULL;
+}
+
+static struct se_wwn *usbg_make_tport(
+	struct target_fabric_configfs *tf,
+	struct config_group *group,
+	const char *name)
+{
+	struct usbg_tport *tport;
+	const char *wnn_name;
+	u64 wwpn = 0;
+
+	wnn_name = usbg_check_wwn(name);
+	if (!wnn_name)
+		return ERR_PTR(-EINVAL);
+
+	tport = kzalloc(sizeof(struct usbg_tport), GFP_KERNEL);
+	if (!(tport)) {
+		printk(KERN_ERR "Unable to allocate struct usbg_tport");
+		return ERR_PTR(-ENOMEM);
+	}
+	tport->tport_wwpn = wwpn;
+	snprintf(tport->tport_name, sizeof(tport->tport_name), wnn_name);
+	return &tport->tport_wwn;
+}
+
+static void usbg_drop_tport(struct se_wwn *wwn)
+{
+	struct usbg_tport *tport = container_of(wwn,
+				struct usbg_tport, tport_wwn);
+	kfree(tport);
+}
+
+/*
+ * If somebody feels like dropping the version property, go ahead.
+ */
+static ssize_t usbg_wwn_show_attr_version(
+	struct target_fabric_configfs *tf,
+	char *page)
+{
+	return sprintf(page, "usb-gadget fabric module\n");
+}
+TF_WWN_ATTR_RO(usbg, version);
+
+static struct configfs_attribute *usbg_wwn_attrs[] = {
+	&usbg_wwn_version.attr,
+	NULL,
+};
+
+static ssize_t tcm_usbg_tpg_show_enable(
+		struct se_portal_group *se_tpg,
+		char *page)
+{
+	struct usbg_tpg  *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+
+	return snprintf(page, PAGE_SIZE, "%u\n", tpg->gadget_connect);
+}
+
+static int usbg_attach(struct usbg_tpg *);
+static void usbg_detach(struct usbg_tpg *);
+
+static ssize_t tcm_usbg_tpg_store_enable(
+		struct se_portal_group *se_tpg,
+		const char *page,
+		size_t count)
+{
+	struct usbg_tpg  *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+	unsigned long op;
+	ssize_t ret;
+
+	ret = kstrtoul(page, 0, &op);
+	if (ret < 0)
+		return -EINVAL;
+	if (op > 1)
+		return -EINVAL;
+
+	if (op && tpg->gadget_connect)
+		goto out;
+	if (!op && !tpg->gadget_connect)
+		goto out;
+
+	if (op) {
+		ret = usbg_attach(tpg);
+		if (ret)
+			goto out;
+	} else {
+		usbg_detach(tpg);
+	}
+	tpg->gadget_connect = op;
+out:
+	return count;
+}
+TF_TPG_BASE_ATTR(tcm_usbg, enable, S_IRUGO | S_IWUSR);
+
+static ssize_t tcm_usbg_tpg_show_nexus(
+		struct se_portal_group *se_tpg,
+		char *page)
+{
+	struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+	struct tcm_usbg_nexus *tv_nexus;
+	ssize_t ret;
+
+	mutex_lock(&tpg->tpg_mutex);
+	tv_nexus = tpg->tpg_nexus;
+	if (!tv_nexus) {
+		ret = -ENODEV;
+		goto out;
+	}
+	ret = snprintf(page, PAGE_SIZE, "%s\n",
+			tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
+out:
+	mutex_unlock(&tpg->tpg_mutex);
+	return ret;
+}
+
+static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name)
+{
+	struct se_portal_group *se_tpg;
+	struct tcm_usbg_nexus *tv_nexus;
+	int ret;
+
+	mutex_lock(&tpg->tpg_mutex);
+	if (tpg->tpg_nexus) {
+		ret = -EEXIST;
+		pr_debug("tpg->tpg_nexus already exists\n");
+		goto err_unlock;
+	}
+	se_tpg = &tpg->se_tpg;
+
+	ret = -ENOMEM;
+	tv_nexus = kzalloc(sizeof(*tv_nexus), GFP_KERNEL);
+	if (!tv_nexus) {
+		pr_err("Unable to allocate struct tcm_vhost_nexus\n");
+		goto err_unlock;
+	}
+	tv_nexus->tvn_se_sess = transport_init_session();
+	if (IS_ERR(tv_nexus->tvn_se_sess))
+		goto err_free;
+
+	/*
+	 * Since we are running in 'demo mode' this call with generate a
+	 * struct se_node_acl for the tcm_vhost struct se_portal_group with
+	 * the SCSI Initiator port name of the passed configfs group 'name'.
+	 */
+	tv_nexus->tvn_se_sess->se_node_acl = core_tpg_check_initiator_node_acl(
+			se_tpg, name);
+	if (!tv_nexus->tvn_se_sess->se_node_acl) {
+		pr_debug("core_tpg_check_initiator_node_acl() failed"
+				" for %s\n", name);
+		goto err_session;
+	}
+	/*
+	 * Now register the TCM vHost virtual I_T Nexus as active with the
+	 * call to __transport_register_session()
+	 */
+	__transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
+			tv_nexus->tvn_se_sess, tv_nexus);
+	tpg->tpg_nexus = tv_nexus;
+	mutex_unlock(&tpg->tpg_mutex);
+	return 0;
+
+err_session:
+	transport_free_session(tv_nexus->tvn_se_sess);
+err_free:
+	kfree(tv_nexus);
+err_unlock:
+	mutex_unlock(&tpg->tpg_mutex);
+	return ret;
+}
+
+static int tcm_usbg_drop_nexus(struct usbg_tpg *tpg)
+{
+	struct se_session *se_sess;
+	struct tcm_usbg_nexus *tv_nexus;
+	int ret = -ENODEV;
+
+	mutex_lock(&tpg->tpg_mutex);
+	tv_nexus = tpg->tpg_nexus;
+	if (!tv_nexus)
+		goto out;
+
+	se_sess = tv_nexus->tvn_se_sess;
+	if (!se_sess)
+		goto out;
+
+	if (atomic_read(&tpg->tpg_port_count)) {
+		ret = -EPERM;
+		pr_err("Unable to remove Host I_T Nexus with"
+				" active TPG port count: %d\n",
+				atomic_read(&tpg->tpg_port_count));
+		goto out;
+	}
+
+	pr_debug("Removing I_T Nexus to Initiator Port: %s\n",
+			tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
+	/*
+	 * Release the SCSI I_T Nexus to the emulated vHost Target Port
+	 */
+	transport_deregister_session(tv_nexus->tvn_se_sess);
+	tpg->tpg_nexus = NULL;
+
+	kfree(tv_nexus);
+out:
+	mutex_unlock(&tpg->tpg_mutex);
+	return 0;
+}
+
+static ssize_t tcm_usbg_tpg_store_nexus(
+		struct se_portal_group *se_tpg,
+		const char *page,
+		size_t count)
+{
+	struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+	unsigned char i_port[USBG_NAMELEN], *ptr;
+	int ret;
+
+	if (!strncmp(page, "NULL", 4)) {
+		ret = tcm_usbg_drop_nexus(tpg);
+		return (!ret) ? count : ret;
+	}
+	if (strlen(page) > USBG_NAMELEN) {
+		pr_err("Emulated NAA Sas Address: %s, exceeds"
+				" max: %d\n", page, USBG_NAMELEN);
+		return -EINVAL;
+	}
+	snprintf(i_port, USBG_NAMELEN, "%s", page);
+
+	ptr = strstr(i_port, "naa.");
+	if (!ptr) {
+		pr_err("Missing 'naa.' prefix\n");
+		return -EINVAL;
+	}
+
+	if (i_port[strlen(i_port) - 1] == '\n')
+		i_port[strlen(i_port) - 1] = '\0';
+
+	ret = tcm_usbg_make_nexus(tpg, &i_port[4]);
+	if (ret < 0)
+		return ret;
+	return count;
+}
+TF_TPG_BASE_ATTR(tcm_usbg, nexus, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *usbg_base_attrs[] = {
+	&tcm_usbg_tpg_enable.attr,
+	&tcm_usbg_tpg_nexus.attr,
+	NULL,
+};
+
+static int usbg_port_link(struct se_portal_group *se_tpg, struct se_lun *lun)
+{
+	struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+
+	atomic_inc(&tpg->tpg_port_count);
+	smp_mb__after_atomic_inc();
+	return 0;
+}
+
+static void usbg_port_unlink(struct se_portal_group *se_tpg,
+		struct se_lun *se_lun)
+{
+	struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+
+	atomic_dec(&tpg->tpg_port_count);
+	smp_mb__after_atomic_dec();
+}
+
+static int usbg_check_stop_free(struct se_cmd *se_cmd)
+{
+	struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+			se_cmd);
+
+	kref_put(&cmd->ref, usbg_cmd_release);
+	return 1;
+}
+
+static struct target_core_fabric_ops usbg_ops = {
+	.get_fabric_name		= usbg_get_fabric_name,
+	.get_fabric_proto_ident		= usbg_get_fabric_proto_ident,
+	.tpg_get_wwn			= usbg_get_fabric_wwn,
+	.tpg_get_tag			= usbg_get_tag,
+	.tpg_get_default_depth		= usbg_get_default_depth,
+	.tpg_get_pr_transport_id	= usbg_get_pr_transport_id,
+	.tpg_get_pr_transport_id_len	= usbg_get_pr_transport_id_len,
+	.tpg_parse_pr_out_transport_id	= usbg_parse_pr_out_transport_id,
+	.tpg_check_demo_mode		= usbg_check_true,
+	.tpg_check_demo_mode_cache	= usbg_check_false,
+	.tpg_check_demo_mode_write_protect = usbg_check_false,
+	.tpg_check_prod_mode_write_protect = usbg_check_false,
+	.tpg_alloc_fabric_acl		= usbg_alloc_fabric_acl,
+	.tpg_release_fabric_acl		= usbg_release_fabric_acl,
+	.tpg_get_inst_index		= usbg_tpg_get_inst_index,
+	.new_cmd_map			= usbg_new_cmd,
+	.release_cmd			= usbg_release_cmd,
+	.shutdown_session		= usbg_shutdown_session,
+	.close_session			= usbg_close_session,
+	.sess_get_index			= usbg_sess_get_index,
+	.sess_get_initiator_sid		= NULL,
+	.write_pending			= usbg_send_write_request,
+	.write_pending_status		= usbg_write_pending_status,
+	.set_default_node_attributes	= usbg_set_default_node_attrs,
+	.get_task_tag			= usbg_get_task_tag,
+	.get_cmd_state			= usbg_get_cmd_state,
+	.queue_data_in			= usbg_send_read_response,
+	.queue_status			= usbg_send_status_response,
+	.queue_tm_rsp			= usbg_queue_tm_rsp,
+	.get_fabric_sense_len		= usbg_get_fabric_sense_len,
+	.set_fabric_sense_len		= usbg_set_fabric_sense_len,
+	.check_stop_free		= usbg_check_stop_free,
+
+	.fabric_make_wwn		= usbg_make_tport,
+	.fabric_drop_wwn		= usbg_drop_tport,
+	.fabric_make_tpg		= usbg_make_tpg,
+	.fabric_drop_tpg		= usbg_drop_tpg,
+	.fabric_post_link		= usbg_port_link,
+	.fabric_pre_unlink		= usbg_port_unlink,
+	.fabric_make_np			= NULL,
+	.fabric_drop_np			= NULL,
+	.fabric_make_nodeacl		= usbg_make_nodeacl,
+	.fabric_drop_nodeacl		= usbg_drop_nodeacl,
+};
+
+static int usbg_register_configfs(void)
+{
+	struct target_fabric_configfs *fabric;
+	int ret;
+
+	fabric = target_fabric_configfs_init(THIS_MODULE, "usb_gadget");
+	if (IS_ERR(fabric)) {
+		printk(KERN_ERR "target_fabric_configfs_init() failed\n");
+		return PTR_ERR(fabric);
+	}
+
+	fabric->tf_ops = usbg_ops;
+	TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = usbg_wwn_attrs;
+	TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = usbg_base_attrs;
+	TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL;
+	ret = target_fabric_configfs_register(fabric);
+	if (ret < 0) {
+		printk(KERN_ERR "target_fabric_configfs_register() failed"
+				" for usb-gadget\n");
+		return ret;
+	}
+	usbg_fabric_configfs = fabric;
+	return 0;
+};
+
+static void usbg_deregister_configfs(void)
+{
+	if (!(usbg_fabric_configfs))
+		return;
+
+	target_fabric_configfs_deregister(usbg_fabric_configfs);
+	usbg_fabric_configfs = NULL;
+};
+
+/* Start gadget.c code */
+
+static struct usb_interface_descriptor bot_intf_desc = {
+	.bLength =              sizeof(bot_intf_desc),
+	.bDescriptorType =      USB_DT_INTERFACE,
+	.bAlternateSetting =	0,
+	.bNumEndpoints =        2,
+	.bAlternateSetting =	USB_G_ALT_INT_BBB,
+	.bInterfaceClass =      USB_CLASS_MASS_STORAGE,
+	.bInterfaceSubClass =   USB_SC_SCSI,
+	.bInterfaceProtocol =   USB_PR_BULK,
+	.iInterface =           USB_G_STR_INT_UAS,
+};
+
+static struct usb_interface_descriptor uasp_intf_desc = {
+	.bLength =		sizeof(uasp_intf_desc),
+	.bDescriptorType =	USB_DT_INTERFACE,
+	.bNumEndpoints =	4,
+	.bAlternateSetting =	USB_G_ALT_INT_UAS,
+	.bInterfaceClass =	USB_CLASS_MASS_STORAGE,
+	.bInterfaceSubClass =	USB_SC_SCSI,
+	.bInterfaceProtocol =	USB_PR_UAS,
+	.iInterface =		USB_G_STR_INT_BBB,
+};
+
+static struct usb_endpoint_descriptor uasp_bi_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_bi_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_bi_pipe_desc = {
+	.bLength =		sizeof(uasp_bi_pipe_desc),
+	.bDescriptorType =	USB_DT_PIPE_USAGE,
+	.bPipeID =		DATA_IN_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_bi_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_bi_ep_comp_desc = {
+	.bLength =		sizeof(uasp_bi_ep_comp_desc),
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+	.bMaxBurst =		0,
+	.bmAttributes =		UASP_SS_EP_COMP_LOG_STREAMS,
+	.wBytesPerInterval =	0,
+};
+
+static struct usb_ss_ep_comp_descriptor bot_bi_ep_comp_desc = {
+	.bLength =		sizeof(bot_bi_ep_comp_desc),
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+	.bMaxBurst =		0,
+};
+
+static struct usb_endpoint_descriptor uasp_bo_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_bo_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_bo_pipe_desc = {
+	.bLength =		sizeof(uasp_bo_pipe_desc),
+	.bDescriptorType =	USB_DT_PIPE_USAGE,
+	.bPipeID =		DATA_OUT_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_bo_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(0x400),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_bo_ep_comp_desc = {
+	.bLength =		sizeof(uasp_bo_ep_comp_desc),
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+	.bmAttributes =		UASP_SS_EP_COMP_LOG_STREAMS,
+};
+
+static struct usb_ss_ep_comp_descriptor bot_bo_ep_comp_desc = {
+	.bLength =		sizeof(bot_bo_ep_comp_desc),
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+};
+
+static struct usb_endpoint_descriptor uasp_status_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_status_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_status_pipe_desc = {
+	.bLength =		sizeof(uasp_status_pipe_desc),
+	.bDescriptorType =	USB_DT_PIPE_USAGE,
+	.bPipeID =		STATUS_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_status_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_status_in_ep_comp_desc = {
+	.bLength =		sizeof(uasp_status_in_ep_comp_desc),
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+	.bmAttributes =		UASP_SS_EP_COMP_LOG_STREAMS,
+};
+
+static struct usb_endpoint_descriptor uasp_cmd_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_cmd_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_cmd_pipe_desc = {
+	.bLength =		sizeof(uasp_cmd_pipe_desc),
+	.bDescriptorType =	USB_DT_PIPE_USAGE,
+	.bPipeID =		CMD_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_cmd_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_cmd_comp_desc = {
+	.bLength =		sizeof(uasp_cmd_comp_desc),
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+};
+
+static struct usb_descriptor_header *uasp_fs_function_desc[] = {
+	(struct usb_descriptor_header *) &bot_intf_desc,
+	(struct usb_descriptor_header *) &uasp_fs_bi_desc,
+	(struct usb_descriptor_header *) &uasp_fs_bo_desc,
+
+	(struct usb_descriptor_header *) &uasp_intf_desc,
+	(struct usb_descriptor_header *) &uasp_fs_bi_desc,
+	(struct usb_descriptor_header *) &uasp_bi_pipe_desc,
+	(struct usb_descriptor_header *) &uasp_fs_bo_desc,
+	(struct usb_descriptor_header *) &uasp_bo_pipe_desc,
+	(struct usb_descriptor_header *) &uasp_fs_status_desc,
+	(struct usb_descriptor_header *) &uasp_status_pipe_desc,
+	(struct usb_descriptor_header *) &uasp_fs_cmd_desc,
+	(struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
+};
+
+static struct usb_descriptor_header *uasp_hs_function_desc[] = {
+	(struct usb_descriptor_header *) &bot_intf_desc,
+	(struct usb_descriptor_header *) &uasp_bi_desc,
+	(struct usb_descriptor_header *) &uasp_bo_desc,
+
+	(struct usb_descriptor_header *) &uasp_intf_desc,
+	(struct usb_descriptor_header *) &uasp_bi_desc,
+	(struct usb_descriptor_header *) &uasp_bi_pipe_desc,
+	(struct usb_descriptor_header *) &uasp_bo_desc,
+	(struct usb_descriptor_header *) &uasp_bo_pipe_desc,
+	(struct usb_descriptor_header *) &uasp_status_desc,
+	(struct usb_descriptor_header *) &uasp_status_pipe_desc,
+	(struct usb_descriptor_header *) &uasp_cmd_desc,
+	(struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
+	NULL,
+};
+
+static struct usb_descriptor_header *uasp_ss_function_desc[] = {
+	(struct usb_descriptor_header *) &bot_intf_desc,
+	(struct usb_descriptor_header *) &uasp_ss_bi_desc,
+	(struct usb_descriptor_header *) &bot_bi_ep_comp_desc,
+	(struct usb_descriptor_header *) &uasp_ss_bo_desc,
+	(struct usb_descriptor_header *) &bot_bo_ep_comp_desc,
+
+	(struct usb_descriptor_header *) &uasp_intf_desc,
+	(struct usb_descriptor_header *) &uasp_ss_bi_desc,
+	(struct usb_descriptor_header *) &uasp_bi_ep_comp_desc,
+	(struct usb_descriptor_header *) &uasp_bi_pipe_desc,
+	(struct usb_descriptor_header *) &uasp_ss_bo_desc,
+	(struct usb_descriptor_header *) &uasp_bo_ep_comp_desc,
+	(struct usb_descriptor_header *) &uasp_bo_pipe_desc,
+	(struct usb_descriptor_header *) &uasp_ss_status_desc,
+	(struct usb_descriptor_header *) &uasp_status_in_ep_comp_desc,
+	(struct usb_descriptor_header *) &uasp_status_pipe_desc,
+	(struct usb_descriptor_header *) &uasp_ss_cmd_desc,
+	(struct usb_descriptor_header *) &uasp_cmd_comp_desc,
+	(struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
+	NULL,
+};
+
+#define UAS_VENDOR_ID	0x0525	/* NetChip */
+#define UAS_PRODUCT_ID	0xa4a5	/* Linux-USB File-backed Storage Gadget */
+
+static struct usb_device_descriptor usbg_device_desc = {
+	.bLength =		sizeof(usbg_device_desc),
+	.bDescriptorType =	USB_DT_DEVICE,
+	.bcdUSB =		cpu_to_le16(0x0200),
+	.bDeviceClass =		USB_CLASS_PER_INTERFACE,
+	.idVendor =		cpu_to_le16(UAS_VENDOR_ID),
+	.idProduct =		cpu_to_le16(UAS_PRODUCT_ID),
+	.iManufacturer =	USB_G_STR_MANUFACTOR,
+	.iProduct =		USB_G_STR_PRODUCT,
+	.iSerialNumber =	USB_G_STR_SERIAL,
+
+	.bNumConfigurations =   1,
+};
+
+static struct usb_string	usbg_us_strings[] = {
+	{ USB_G_STR_MANUFACTOR,	"Target Manufactor"},
+	{ USB_G_STR_PRODUCT,	"Target Product"},
+	{ USB_G_STR_SERIAL,	"000000000001"},
+	{ USB_G_STR_CONFIG,	"default config"},
+	{ USB_G_STR_INT_UAS,	"USB Attached SCSI"},
+	{ USB_G_STR_INT_BBB,	"Bulk Only Transport"},
+	{ },
+};
+
+static struct usb_gadget_strings usbg_stringtab = {
+	.language = 0x0409,
+	.strings = usbg_us_strings,
+};
+
+static struct usb_gadget_strings *usbg_strings[] = {
+	&usbg_stringtab,
+	NULL,
+};
+
+static int guas_unbind(struct usb_composite_dev *cdev)
+{
+	return 0;
+}
+
+static struct usb_configuration usbg_config_driver = {
+	.label                  = "Linux Target",
+	.bConfigurationValue    = 1,
+	.iConfiguration		= USB_G_STR_CONFIG,
+	.bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
+};
+
+static void give_back_ep(struct usb_ep **pep)
+{
+	struct usb_ep *ep = *pep;
+	if (!ep)
+		return;
+	ep->driver_data = NULL;
+}
+
+static int usbg_bind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct f_uas		*fu = to_f_uas(f);
+	struct usb_gadget	*gadget = c->cdev->gadget;
+	struct usb_ep		*ep;
+	int			iface;
+
+	iface = usb_interface_id(c, f);
+	if (iface < 0)
+		return iface;
+
+	bot_intf_desc.bInterfaceNumber = iface;
+	uasp_intf_desc.bInterfaceNumber = iface;
+	fu->iface = iface;
+	ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bi_desc,
+			&uasp_bi_ep_comp_desc);
+	if (!ep)
+		goto ep_fail;
+
+	ep->driver_data = fu;
+	fu->ep_in = ep;
+
+	ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bo_desc,
+			&uasp_bo_ep_comp_desc);
+	if (!ep)
+		goto ep_fail;
+	ep->driver_data = fu;
+	fu->ep_out = ep;
+
+	ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_status_desc,
+			&uasp_status_in_ep_comp_desc);
+	if (!ep)
+		goto ep_fail;
+	ep->driver_data = fu;
+	fu->ep_status = ep;
+
+	ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_cmd_desc,
+			&uasp_cmd_comp_desc);
+	if (!ep)
+		goto ep_fail;
+	ep->driver_data = fu;
+	fu->ep_cmd = ep;
+
+	/* Assume endpoint addresses are the same for both speeds */
+	uasp_bi_desc.bEndpointAddress =	uasp_ss_bi_desc.bEndpointAddress;
+	uasp_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress;
+	uasp_status_desc.bEndpointAddress =
+		uasp_ss_status_desc.bEndpointAddress;
+	uasp_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
+
+	uasp_fs_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress;
+	uasp_fs_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress;
+	uasp_fs_status_desc.bEndpointAddress =
+		uasp_ss_status_desc.bEndpointAddress;
+	uasp_fs_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
+
+	return 0;
+ep_fail:
+	pr_err("Can't claim all required eps\n");
+
+	give_back_ep(&fu->ep_in);
+	give_back_ep(&fu->ep_out);
+	give_back_ep(&fu->ep_status);
+	give_back_ep(&fu->ep_cmd);
+	return -ENOTSUPP;
+}
+
+static void usbg_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct f_uas *fu = to_f_uas(f);
+
+	kfree(fu);
+}
+
+struct guas_setup_wq {
+	struct work_struct work;
+	struct f_uas *fu;
+	unsigned int alt;
+};
+
+static void usbg_delayed_set_alt(struct work_struct *wq)
+{
+	struct guas_setup_wq *work = container_of(wq, struct guas_setup_wq,
+			work);
+	struct f_uas *fu = work->fu;
+	int alt = work->alt;
+
+	kfree(work);
+
+	if (fu->flags & USBG_IS_BOT)
+		bot_cleanup_old_alt(fu);
+	if (fu->flags & USBG_IS_UAS)
+		uasp_cleanup_old_alt(fu);
+
+	if (alt == USB_G_ALT_INT_BBB)
+		bot_set_alt(fu);
+	else if (alt == USB_G_ALT_INT_UAS)
+		uasp_set_alt(fu);
+	usb_composite_setup_continue(fu->function.config->cdev);
+}
+
+static int usbg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+	struct f_uas *fu = to_f_uas(f);
+
+	if ((alt == USB_G_ALT_INT_BBB) || (alt == USB_G_ALT_INT_UAS)) {
+		struct guas_setup_wq *work;
+
+		work = kmalloc(sizeof(*work), GFP_ATOMIC);
+		if (!work)
+			return -ENOMEM;
+		INIT_WORK(&work->work, usbg_delayed_set_alt);
+		work->fu = fu;
+		work->alt = alt;
+		schedule_work(&work->work);
+		return USB_GADGET_DELAYED_STATUS;
+	}
+	return -EOPNOTSUPP;
+}
+
+static void usbg_disable(struct usb_function *f)
+{
+	struct f_uas *fu = to_f_uas(f);
+
+	if (fu->flags & USBG_IS_UAS)
+		uasp_cleanup_old_alt(fu);
+	else if (fu->flags & USBG_IS_BOT)
+		bot_cleanup_old_alt(fu);
+	fu->flags = 0;
+}
+
+static int usbg_setup(struct usb_function *f,
+		const struct usb_ctrlrequest *ctrl)
+{
+	struct f_uas *fu = to_f_uas(f);
+
+	if (!(fu->flags & USBG_IS_BOT))
+		return -EOPNOTSUPP;
+
+	return usbg_bot_setup(f, ctrl);
+}
+
+static int usbg_cfg_bind(struct usb_configuration *c)
+{
+	struct f_uas *fu;
+	int ret;
+
+	fu = kzalloc(sizeof(*fu), GFP_KERNEL);
+	if (!fu)
+		return -ENOMEM;
+	fu->function.name = "Target Function";
+	fu->function.descriptors = uasp_fs_function_desc;
+	fu->function.hs_descriptors = uasp_hs_function_desc;
+	fu->function.ss_descriptors = uasp_ss_function_desc;
+	fu->function.bind = usbg_bind;
+	fu->function.unbind = usbg_unbind;
+	fu->function.set_alt = usbg_set_alt;
+	fu->function.setup = usbg_setup;
+	fu->function.disable = usbg_disable;
+	fu->tpg = the_only_tpg_I_currently_have;
+
+	ret = usb_add_function(c, &fu->function);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	kfree(fu);
+	return ret;
+}
+
+static int usb_target_bind(struct usb_composite_dev *cdev)
+{
+	int ret;
+
+	ret = usb_add_config(cdev, &usbg_config_driver,
+			usbg_cfg_bind);
+	return 0;
+}
+
+static struct usb_composite_driver usbg_driver = {
+	.name           = "g_target",
+	.dev            = &usbg_device_desc,
+	.strings        = usbg_strings,
+	.max_speed      = USB_SPEED_SUPER,
+	.unbind         = guas_unbind,
+};
+
+static int usbg_attach(struct usbg_tpg *tpg)
+{
+	return usb_composite_probe(&usbg_driver, usb_target_bind);
+}
+
+static void usbg_detach(struct usbg_tpg *tpg)
+{
+	usb_composite_unregister(&usbg_driver);
+}
+
+static int __init usb_target_gadget_init(void)
+{
+	int ret;
+
+	ret = usbg_register_configfs();
+	return ret;
+}
+module_init(usb_target_gadget_init);
+
+static void __exit usb_target_gadget_exit(void)
+{
+	usbg_deregister_configfs();
+}
+module_exit(usb_target_gadget_exit);
+
+MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
+MODULE_DESCRIPTION("usb-gadget fabric");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/gadget/tcm_usb_gadget.h b/drivers/usb/gadget/tcm_usb_gadget.h
new file mode 100644
index 0000000..bb18999
--- /dev/null
+++ b/drivers/usb/gadget/tcm_usb_gadget.h
@@ -0,0 +1,146 @@
+#ifndef __TARGET_USB_GADGET_H__
+#define __TARGET_USB_GADGET_H__
+
+#include <linux/kref.h>
+/* #include <linux/usb/uas.h> */
+#include <linux/usb/composite.h>
+#include <linux/usb/uas.h>
+#include <linux/usb/storage.h>
+#include <scsi/scsi.h>
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+
+#define USBG_NAMELEN 32
+
+#define fuas_to_gadget(f)	(f->function.config->cdev->gadget)
+#define UASP_SS_EP_COMP_LOG_STREAMS 4
+#define UASP_SS_EP_COMP_NUM_STREAMS (1 << UASP_SS_EP_COMP_LOG_STREAMS)
+
+#define USB_G_STR_MANUFACTOR    1
+#define USB_G_STR_PRODUCT       2
+#define USB_G_STR_SERIAL        3
+#define USB_G_STR_CONFIG        4
+#define USB_G_STR_INT_UAS       5
+#define USB_G_STR_INT_BBB       6
+
+#define USB_G_ALT_INT_BBB       0
+#define USB_G_ALT_INT_UAS       1
+
+struct usbg_nacl {
+	/* Binary World Wide unique Port Name for SAS Initiator port */
+	u64 iport_wwpn;
+	/* ASCII formatted WWPN for Sas Initiator port */
+	char iport_name[USBG_NAMELEN];
+	/* Returned by usbg_make_nodeacl() */
+	struct se_node_acl se_node_acl;
+};
+
+struct tcm_usbg_nexus {
+	struct se_session *tvn_se_sess;
+};
+
+struct usbg_tpg {
+	struct mutex tpg_mutex;
+	/* SAS port target portal group tag for TCM */
+	u16 tport_tpgt;
+	/* Pointer back to usbg_tport */
+	struct usbg_tport *tport;
+	struct workqueue_struct *workqueue;
+	/* Returned by usbg_make_tpg() */
+	struct se_portal_group se_tpg;
+	u32 gadget_connect;
+	struct tcm_usbg_nexus *tpg_nexus;
+	atomic_t tpg_port_count;
+};
+
+struct usbg_tport {
+	/* SCSI protocol the tport is providing */
+	u8 tport_proto_id;
+	/* Binary World Wide unique Port Name for SAS Target port */
+	u64 tport_wwpn;
+	/* ASCII formatted WWPN for SAS Target port */
+	char tport_name[USBG_NAMELEN];
+	/* Returned by usbg_make_tport() */
+	struct se_wwn tport_wwn;
+};
+
+enum uas_state {
+	UASP_SEND_DATA,
+	UASP_RECEIVE_DATA,
+	UASP_SEND_STATUS,
+	UASP_QUEUE_COMMAND,
+};
+
+#define USBG_MAX_CMD    64
+struct usbg_cmd {
+	/* common */
+	u8 cmd_buf[USBG_MAX_CMD];
+	u32 data_len;
+	struct work_struct work;
+	int unpacked_lun;
+	struct se_cmd se_cmd;
+	void *data_buf; /* used if no sg support available */
+	struct f_uas *fu;
+	struct completion write_complete;
+	struct kref ref;
+
+	/* UAS only */
+	u16 tag;
+	u16 prio_attr;
+	struct sense_iu sense_iu;
+	enum uas_state state;
+	struct uas_stream *stream;
+
+	/* BOT only */
+	__le32 bot_tag;
+	unsigned int csw_code;
+	unsigned is_read:1;
+
+};
+
+struct uas_stream {
+	struct usb_request	*req_in;
+	struct usb_request	*req_out;
+	struct usb_request	*req_status;
+};
+
+struct usbg_cdb {
+	struct usb_request	*req;
+	void			*buf;
+};
+
+struct bot_status {
+	struct usb_request	*req;
+	struct bulk_cs_wrap	csw;
+};
+
+struct f_uas {
+	struct usbg_tpg		*tpg;
+	struct usb_function	function;
+	u16			iface;
+
+	u32			flags;
+#define USBG_ENABLED		(1 << 0)
+#define USBG_IS_UAS		(1 << 1)
+#define USBG_USE_STREAMS	(1 << 2)
+#define USBG_IS_BOT		(1 << 3)
+#define USBG_BOT_CMD_PEND	(1 << 4)
+
+	struct usbg_cdb		cmd;
+	struct usb_ep		*ep_in;
+	struct usb_ep		*ep_out;
+
+	/* UAS */
+	struct usb_ep		*ep_status;
+	struct usb_ep		*ep_cmd;
+	struct uas_stream	stream[UASP_SS_EP_COMP_NUM_STREAMS];
+
+	/* BOT */
+	struct bot_status	bot_status;
+	struct usb_request	*bot_req_in;
+	struct usb_request	*bot_req_out;
+};
+
+extern struct usbg_tpg *the_only_tpg_I_currently_have;
+
+#endif
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 673ad12..78ece8d 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -343,6 +343,8 @@
 
 	/* Write 1 to disable the port */
 	xhci_writel(xhci, port_status | PORT_PE, addr);
+	if (xhci->quirks & XHCI_PORTSC_DELAY)
+		ndelay(100);
 	port_status = xhci_readl(xhci, addr);
 	xhci_dbg(xhci, "disable port, actual port %d status  = 0x%x\n",
 			wIndex, port_status);
@@ -389,6 +391,8 @@
 	}
 	/* Change bits are all write 1 to clear */
 	xhci_writel(xhci, port_status | status, addr);
+	if (xhci->quirks & XHCI_PORTSC_DELAY)
+		ndelay(100);
 	port_status = xhci_readl(xhci, addr);
 	xhci_dbg(xhci, "clear port %s change, actual port %d status  = 0x%x\n",
 			port_change_bit, wIndex, port_status);
@@ -420,6 +424,8 @@
 	temp &= ~PORT_PLS_MASK;
 	temp |= PORT_LINK_STROBE | link_state;
 	xhci_writel(xhci, temp, port_array[port_id]);
+	if (xhci->quirks & XHCI_PORTSC_DELAY)
+		ndelay(100);
 }
 
 void xhci_set_remote_wake_mask(struct xhci_hcd *xhci,
@@ -446,6 +452,8 @@
 		temp &= ~PORT_WKOC_E;
 
 	xhci_writel(xhci, temp, port_array[port_id]);
+	if (xhci->quirks & XHCI_PORTSC_DELAY)
+		ndelay(100);
 }
 
 /* Test and clear port RWC bit */
@@ -459,6 +467,8 @@
 		temp = xhci_port_state_to_neutral(temp);
 		temp |= port_bit;
 		xhci_writel(xhci, temp, port_array[port_id]);
+		if (xhci->quirks & XHCI_PORTSC_DELAY)
+			ndelay(100);
 	}
 }
 
@@ -721,6 +731,8 @@
 			 */
 			xhci_writel(xhci, temp | PORT_POWER,
 					port_array[wIndex]);
+			if (xhci->quirks & XHCI_PORTSC_DELAY)
+				ndelay(100);
 
 			temp = xhci_readl(xhci, port_array[wIndex]);
 			xhci_dbg(xhci, "set port power, actual port %d status  = 0x%x\n", wIndex, temp);
@@ -728,6 +740,8 @@
 		case USB_PORT_FEAT_RESET:
 			temp = (temp | PORT_RESET);
 			xhci_writel(xhci, temp, port_array[wIndex]);
+			if (xhci->quirks & XHCI_PORTSC_DELAY)
+				ndelay(100);
 
 			temp = xhci_readl(xhci, port_array[wIndex]);
 			xhci_dbg(xhci, "set port reset, actual port %d status  = 0x%x\n", wIndex, temp);
@@ -743,6 +757,8 @@
 		case USB_PORT_FEAT_BH_PORT_RESET:
 			temp |= PORT_WR;
 			xhci_writel(xhci, temp, port_array[wIndex]);
+			if (xhci->quirks & XHCI_PORTSC_DELAY)
+				ndelay(100);
 
 			temp = xhci_readl(xhci, port_array[wIndex]);
 			break;
@@ -936,8 +952,11 @@
 			t2 &= ~PORT_WAKE_BITS;
 
 		t1 = xhci_port_state_to_neutral(t1);
-		if (t1 != t2)
+		if (t1 != t2) {
 			xhci_writel(xhci, t2, port_array[port_index]);
+			if (xhci->quirks & XHCI_PORTSC_DELAY)
+				ndelay(100);
+		}
 
 		if (hcd->speed != HCD_USB3) {
 			/* enable remote wake up for USB 2.0 */
@@ -951,6 +970,8 @@
 			tmp = xhci_readl(xhci, addr);
 			tmp |= PORT_RWE;
 			xhci_writel(xhci, tmp, addr);
+			if (xhci->quirks & XHCI_PORTSC_DELAY)
+				ndelay(100);
 		}
 	}
 	hcd->state = HC_STATE_SUSPENDED;
@@ -1028,8 +1049,11 @@
 					xhci, port_index + 1);
 			if (slot_id)
 				xhci_ring_device(xhci, slot_id);
-		} else
+		} else {
 			xhci_writel(xhci, temp, port_array[port_index]);
+			if (xhci->quirks & XHCI_PORTSC_DELAY)
+				ndelay(100);
+		}
 
 		if (hcd->speed != HCD_USB3) {
 			/* disable remote wake up for USB 2.0 */
@@ -1043,6 +1067,8 @@
 			tmp = xhci_readl(xhci, addr);
 			tmp &= ~PORT_RWE;
 			xhci_writel(xhci, tmp, addr);
+			if (xhci->quirks & XHCI_PORTSC_DELAY)
+				ndelay(100);
 		}
 	}
 
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 689bc18..8467dc0 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -14,17 +14,30 @@
 #include <linux/platform_device.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/usb/otg.h>
 
 #include "xhci.h"
 
+#define SYNOPSIS_DWC3_VENDOR	0x5533
+
+static struct usb_phy *phy;
+
 static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
 {
+	struct xhci_plat_data *pdata = dev->platform_data;
+
 	/*
 	 * As of now platform drivers don't provide MSI support so we ensure
 	 * here that the generic code does not try to make a pci_dev from our
 	 * dev struct in order to setup MSI
 	 */
 	xhci->quirks |= XHCI_BROKEN_MSI;
+
+	if (!pdata)
+		return;
+	else if (pdata->vendor == SYNOPSIS_DWC3_VENDOR &&
+			pdata->revision < 0x230A)
+		xhci->quirks |= XHCI_PORTSC_DELAY;
 }
 
 /* called during probe() after chip reset completes */
@@ -149,6 +162,19 @@
 	if (ret)
 		goto put_usb3_hcd;
 
+	phy = usb_get_transceiver();
+	if (phy && phy->otg) {
+		dev_dbg(&pdev->dev, "%s otg support available\n", __func__);
+		hcd->driver->stop(hcd);
+		ret = otg_set_host(phy->otg, &hcd->self);
+		if (ret) {
+			dev_err(&pdev->dev, "%s otg_set_host failed\n",
+				__func__);
+			usb_put_transceiver(phy);
+			goto put_usb3_hcd;
+		}
+	}
+
 	return 0;
 
 put_usb3_hcd:
@@ -182,6 +208,11 @@
 	usb_put_hcd(hcd);
 	kfree(xhci);
 
+	if (phy && phy->otg) {
+		otg_set_host(phy->otg, NULL);
+		usb_put_transceiver(phy);
+	}
+
 	return 0;
 }
 
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 36641a7..2c26998 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -318,16 +318,6 @@
 	return;
 }
 
-static void xhci_msix_sync_irqs(struct xhci_hcd *xhci)
-{
-	int i;
-
-	if (xhci->msix_entries) {
-		for (i = 0; i < xhci->msix_count; i++)
-			synchronize_irq(xhci->msix_entries[i].vector);
-	}
-}
-
 static int xhci_try_enable_msi(struct usb_hcd *hcd)
 {
 	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
@@ -383,11 +373,7 @@
 {
 }
 
-static void xhci_msix_sync_irqs(struct xhci_hcd *xhci)
-{
-}
-
-#endif
+#endif /* CONFIG_PCI */
 
 /*
  * Initialize memory for HCD and xHC (one-time init).
@@ -513,6 +499,13 @@
 
 	xhci_dbg(xhci, "xhci_run\n");
 
+	xhci_dbg(xhci, "Calling HCD init\n");
+	/* Initialize HCD and host controller data structures. */
+	ret = xhci_init(hcd);
+	if (ret)
+		return ret;
+	xhci_dbg(xhci, "Called HCD init\n");
+
 	ret = xhci_try_enable_msi(hcd);
 	if (ret)
 		return ret;
@@ -661,6 +654,23 @@
 }
 
 #ifdef CONFIG_PM
+
+#ifdef CONFIG_PCI
+static void xhci_msix_sync_irqs(struct xhci_hcd *xhci)
+{
+	int i;
+
+	if (xhci->msix_entries) {
+		for (i = 0; i < xhci->msix_count; i++)
+			synchronize_irq(xhci->msix_entries[i].vector);
+	}
+}
+#else
+static void xhci_msix_sync_irqs(struct xhci_hcd *xhci)
+{
+}
+#endif /* CONFIG_PCI */
+
 static void xhci_save_registers(struct xhci_hcd *xhci)
 {
 	xhci->s3.command = xhci_readl(xhci, &xhci->op_regs->command);
@@ -3712,6 +3722,8 @@
 	hird = xhci_calculate_hird_besl(xhci, udev);
 	temp = PORT_L1DS(udev->slot_id) | PORT_HIRD(hird);
 	xhci_writel(xhci, temp, pm_addr);
+	if (xhci->quirks & XHCI_PORTSC_DELAY)
+		ndelay(100);
 
 	/* Set port link state to U2(L1) */
 	addr = port_array[port_num];
@@ -3789,6 +3801,7 @@
 	unsigned int	port_num;
 	unsigned long	flags;
 	int		hird;
+	bool		delay;
 
 	if (hcd->speed == HCD_USB3 || !xhci->hw_lpm_support ||
 			!udev->lpm_capable)
@@ -3801,6 +3814,9 @@
 	if (udev->usb2_hw_lpm_capable != 1)
 		return -EPERM;
 
+	if (xhci->quirks & XHCI_PORTSC_DELAY)
+		delay = true;
+
 	spin_lock_irqsave(&xhci->lock, flags);
 
 	port_array = xhci->usb2_ports;
@@ -3817,12 +3833,18 @@
 		temp &= ~PORT_HIRD_MASK;
 		temp |= PORT_HIRD(hird) | PORT_RWE;
 		xhci_writel(xhci, temp, pm_addr);
+		if (delay)
+			ndelay(100);
 		temp = xhci_readl(xhci, pm_addr);
 		temp |= PORT_HLE;
 		xhci_writel(xhci, temp, pm_addr);
+		if (delay)
+			ndelay(100);
 	} else {
 		temp &= ~(PORT_HLE | PORT_RWE | PORT_HIRD_MASK);
 		xhci_writel(xhci, temp, pm_addr);
+		if (delay)
+			ndelay(100);
 	}
 
 	spin_unlock_irqrestore(&xhci->lock, flags);
@@ -4043,12 +4065,6 @@
 		dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32));
 	}
 
-	xhci_dbg(xhci, "Calling HCD init\n");
-	/* Initialize HCD and host controller data structures. */
-	retval = xhci_init(hcd);
-	if (retval)
-		goto error;
-	xhci_dbg(xhci, "Called HCD init\n");
 	return 0;
 error:
 	kfree(xhci);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 3d69c4b..127b0e9 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1479,6 +1479,21 @@
 #define XHCI_RESET_ON_RESUME	(1 << 7)
 #define	XHCI_SW_BW_CHECKING	(1 << 8)
 #define XHCI_AMD_0x96_HOST	(1 << 9)
+/*
+ * In Synopsis DWC3 controller, PORTSC register access involves multiple clock
+ * domains. When the software does a PORTSC write, handshakes are needed
+ * across these clock domains. This results in long access times, especially
+ * for USB 2.0 ports. In order to solve this issue, when the PORTSC write
+ * operations happen on the system bus, the command is latched and system bus
+ * is released immediately. However, the real PORTSC write access will take
+ * some time internally to complete. If the software quickly does a read to the
+ * PORTSC, some fields (port status change related fields like OCC, etc.) may
+ * not have correct value due to the current way of handling these bits.
+ *
+ * The workaround is to give some delay (5 mac2_clk -> UTMI clock = 60 MHz ->
+ * (16.66 ns x 5 = 84ns) ~100ns after writing to the PORTSC register.
+ */
+#define XHCI_PORTSC_DELAY	(1 << 10)
 	unsigned int		num_active_eps;
 	unsigned int		limit_active_eps;
 	/* There are two roothubs to keep track of bus suspend info for */
@@ -1667,6 +1682,11 @@
 static inline void xhci_unregister_pci(void) {}
 #endif
 
+struct xhci_plat_data {
+	unsigned vendor;
+	unsigned revision;
+};
+
 #if defined(CONFIG_USB_XHCI_PLATFORM) \
 	|| defined(CONFIG_USB_XHCI_PLATFORM_MODULE)
 int xhci_register_plat(void);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index c0f9346..dedad53 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -827,8 +827,10 @@
 
 	/* Ensure that above operation is completed before turning off clocks */
 	mb();
-	clk_disable_unprepare(motg->pclk);
-	clk_disable_unprepare(motg->core_clk);
+	if (!motg->pdata->core_clk_always_on_workaround) {
+		clk_disable_unprepare(motg->pclk);
+		clk_disable_unprepare(motg->core_clk);
+	}
 
 	/* usb phy no more require TCXO clock, hence vote for TCXO disable */
 	if (!host_bus_suspend) {
@@ -891,9 +893,10 @@
 		motg->lpm_flags &= ~XO_SHUTDOWN;
 	}
 
-	clk_prepare_enable(motg->core_clk);
-
-	clk_prepare_enable(motg->pclk);
+	if (!motg->pdata->core_clk_always_on_workaround) {
+		clk_prepare_enable(motg->core_clk);
+		clk_prepare_enable(motg->pclk);
+	}
 
 	if (motg->lpm_flags & PHY_PWR_COLLAPSED) {
 		msm_hsusb_ldo_enable(motg, 1);
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 55d2b3e..cad6e02 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -914,6 +914,7 @@
 		goto error;
 	}
 
+	mutex_lock(&mgmt->mdp_do_hist_mutex);
 	mutex_lock(&mgmt->mdp_hist_mutex);
 	if (mgmt->mdp_is_hist_start == TRUE) {
 		pr_err("%s histogram already started\n", __func__);
@@ -933,6 +934,7 @@
 
 error_lock:
 	mutex_unlock(&mgmt->mdp_hist_mutex);
+	mutex_unlock(&mgmt->mdp_do_hist_mutex);
 error:
 	return ret;
 }
@@ -949,6 +951,7 @@
 		goto error;
 	}
 
+	mutex_lock(&mgmt->mdp_do_hist_mutex);
 	mutex_lock(&mgmt->mdp_hist_mutex);
 	if (mgmt->mdp_is_hist_start == FALSE) {
 		pr_err("%s histogram already stopped\n", __func__);
@@ -969,10 +972,12 @@
 
 	mutex_unlock(&mgmt->mdp_hist_mutex);
 	cancel_work_sync(&mgmt->mdp_histogram_worker);
+	mutex_unlock(&mgmt->mdp_do_hist_mutex);
 	return ret;
 
 error_lock:
 	mutex_unlock(&mgmt->mdp_hist_mutex);
+	mutex_unlock(&mgmt->mdp_do_hist_mutex);
 error:
 	return ret;
 }
@@ -1178,11 +1183,13 @@
 	return ret;
 }
 
+#define MDP_HISTOGRAM_TIMEOUT_MS	84 /*5 Frames*/
 static int mdp_do_histogram(struct fb_info *info,
 					struct mdp_histogram_data *hist)
 {
 	struct mdp_hist_mgmt *mgmt = NULL;
 	int ret = 0;
+	unsigned long timeout = (MDP_HISTOGRAM_TIMEOUT_MS * HZ) / 1000;
 
 	ret = mdp_histogram_block2mgmt(hist->block, &mgmt);
 	if (ret) {
@@ -1227,9 +1234,17 @@
 	mgmt->hist = hist;
 	mutex_unlock(&mgmt->mdp_hist_mutex);
 
-	if (wait_for_completion_killable(&mgmt->mdp_hist_comp)) {
-		pr_err("%s(): histogram bin collection killed", __func__);
-		ret = -EINVAL;
+	ret = wait_for_completion_killable_timeout(&mgmt->mdp_hist_comp,
+								timeout);
+	if (ret <= 0) {
+		if (!ret) {
+			mgmt->hist = NULL;
+			ret = -ETIMEDOUT;
+			pr_debug("%s: bin collection timedout", __func__);
+		} else {
+			mgmt->hist = NULL;
+			pr_debug("%s: bin collection interrupted", __func__);
+		}
 		goto error;
 	}
 
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 2a15506..b3ec39e 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -126,7 +126,7 @@
 	pr_debug("mixer %u, pipe %u, plane %u\n", pipe->mixer_num,
 		pipe->pipe_ndx, plane);
 	if (ion_map_iommu(display_iclient, *srcp_ihdl,
-		DISPLAY_DOMAIN, GEN_POOL, SZ_4K, 0, start,
+		DISPLAY_READ_DOMAIN, GEN_POOL, SZ_4K, 0, start,
 		len, 0, ION_IOMMU_UNMAP_DELAYED)) {
 		ion_free(display_iclient, *srcp_ihdl);
 		pr_err("ion_map_iommu() failed\n");
@@ -140,7 +140,7 @@
 		if (iom_pipe_info->prev_ihdl[plane]) {
 			ion_unmap_iommu(display_iclient,
 				iom_pipe_info->prev_ihdl[plane],
-				DISPLAY_DOMAIN, GEN_POOL);
+				DISPLAY_READ_DOMAIN, GEN_POOL);
 			ion_free(display_iclient,
 				iom_pipe_info->prev_ihdl[plane]);
 			pr_debug("Previous: mixer %u, pipe %u, plane %u, "
@@ -175,7 +175,7 @@
 					iom_pipe_info->prev_ihdl[i]);
 				ion_unmap_iommu(display_iclient,
 					iom_pipe_info->prev_ihdl[i],
-					DISPLAY_DOMAIN, GEN_POOL);
+					DISPLAY_READ_DOMAIN, GEN_POOL);
 				ion_free(display_iclient,
 					iom_pipe_info->prev_ihdl[i]);
 				iom_pipe_info->prev_ihdl[i] = NULL;
@@ -191,7 +191,7 @@
 						iom_pipe_info->ihdl[i]);
 					ion_unmap_iommu(display_iclient,
 						iom_pipe_info->ihdl[i],
-						DISPLAY_DOMAIN, GEN_POOL);
+						DISPLAY_READ_DOMAIN, GEN_POOL);
 					ion_free(display_iclient,
 						iom_pipe_info->ihdl[i]);
 					iom_pipe_info->ihdl[i] = NULL;
@@ -3180,25 +3180,25 @@
 	char *name;
 	int  domain;
 } msm_iommu_ctx_names[] = {
-	/* Display */
+	/* Display read*/
 	{
 		.name = "mdp_port0_cb0",
-		.domain = DISPLAY_DOMAIN,
+		.domain = DISPLAY_READ_DOMAIN,
 	},
-	/* Display */
+	/* Display read*/
 	{
 		.name = "mdp_port0_cb1",
-		.domain = DISPLAY_DOMAIN,
+		.domain = DISPLAY_WRITE_DOMAIN,
 	},
-	/* Display */
+	/* Display write */
 	{
 		.name = "mdp_port1_cb0",
-		.domain = DISPLAY_DOMAIN,
+		.domain = DISPLAY_READ_DOMAIN,
 	},
-	/* Display */
+	/* Display write */
 	{
 		.name = "mdp_port1_cb1",
-		.domain = DISPLAY_DOMAIN,
+		.domain = DISPLAY_WRITE_DOMAIN,
 	},
 };
 
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index fe31f93..9174bc5 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -239,15 +239,8 @@
 
 	mdp_footswitch_ctrl(TRUE);
 	mdp4_overlay_panel_mode(MDP4_MIXER1, MDP4_PANEL_DTV);
-
-	/* Allocate dtv_pipe at dtv_on*/
-	if (dtv_pipe == NULL) {
-		if (mdp4_overlay_dtv_set(mfd, NULL)) {
-			pr_warn("%s: dtv_pipe is NULL, dtv_set failed\n",
-				__func__);
-			return -EINVAL;
-		}
-	}
+	if (dtv_pipe != NULL)
+		ret = mdp4_dtv_start(mfd);
 
 	ret = panel_next_on(pdev);
 	if (ret != 0)
@@ -708,6 +701,14 @@
 		return;
 	}
 	mutex_lock(&mfd->dma->ov_mutex);
+	if (dtv_pipe == NULL) {
+		if (mdp4_overlay_dtv_set(mfd, NULL)) {
+			pr_warn("%s: dtv_pipe == NULL\n", __func__);
+			mutex_unlock(&mfd->dma->ov_mutex);
+			return;
+		}
+	}
+
 	pipe = dtv_pipe;
 
 	if (hdmi_prim_display && (pipe->pipe_used == 0 ||
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index f192b12..cce8ea4 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -2591,11 +2591,20 @@
 		buf->ihdl = ion_alloc(mfd->iclient, buffer_size, SZ_4K,
 			mfd->mem_hid);
 		if (!IS_ERR_OR_NULL(buf->ihdl)) {
-			if (ion_map_iommu(mfd->iclient, buf->ihdl,
-				DISPLAY_DOMAIN, GEN_POOL, SZ_4K, 0, &addr,
-				&len, 0, 0)) {
-				pr_err("ion_map_iommu() failed\n");
-				return -ENOMEM;
+			if (mfd->mem_hid & ION_SECURE) {
+				if (ion_phys(mfd->iclient, buf->ihdl,
+					&addr, (unsigned *)&len)) {
+					pr_err("%s:%d: ion_phys map failed\n",
+						 __func__, __LINE__);
+					return -ENOMEM;
+				}
+			} else {
+				if (ion_map_iommu(mfd->iclient, buf->ihdl,
+					DISPLAY_WRITE_DOMAIN, GEN_POOL, SZ_4K,
+					0, &addr, &len, 0, 0)) {
+					pr_err("ion_map_iommu() failed\n");
+					return -ENOMEM;
+				}
 			}
 		} else {
 			pr_err("%s:%d: ion_alloc failed\n", __func__,
@@ -2629,8 +2638,9 @@
 
 	if (!IS_ERR_OR_NULL(mfd->iclient)) {
 		if (!IS_ERR_OR_NULL(buf->ihdl)) {
-			ion_unmap_iommu(mfd->iclient, buf->ihdl,
-				DISPLAY_DOMAIN, GEN_POOL);
+			if (!(mfd->mem_hid & ION_SECURE))
+				ion_unmap_iommu(mfd->iclient, buf->ihdl,
+					DISPLAY_WRITE_DOMAIN, GEN_POOL);
 			ion_free(mfd->iclient, buf->ihdl);
 			pr_debug("%s:%d free writeback imem\n", __func__,
 				__LINE__);
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
index 2a61f07..780e0c6 100644
--- a/drivers/video/msm/mdss/Makefile
+++ b/drivers/video/msm/mdss/Makefile
@@ -1,5 +1,8 @@
 mdss-mdp-objs := mdss_mdp.o mdss_mdp_ctl.o mdss_mdp_pipe.o mdss_mdp_util.o
+mdss-mdp-objs += mdss_mdp_pp.o
+mdss-mdp-objs += mdss_mdp_intf_video.o
 mdss-mdp-objs += mdss_mdp_intf_writeback.o
+mdss-mdp-objs += mdss_mdp_rotator.o
 mdss-mdp-objs += mdss_mdp_overlay.o
 obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp.o
 obj-$(CONFIG_FB_MSM_MDSS) += mdss_fb.o
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
index aaf6690..a58c3e6 100644
--- a/drivers/video/msm/mdss/mdss.h
+++ b/drivers/video/msm/mdss/mdss.h
@@ -23,13 +23,20 @@
 
 extern unsigned char *mdss_reg_base;
 
+enum mdss_mdp_clk_type {
+	MDSS_CLK_AHB,
+	MDSS_CLK_AXI,
+	MDSS_CLK_MDP_SRC,
+	MDSS_CLK_MDP_CORE,
+	MDSS_CLK_MDP_LUT,
+	MDSS_CLK_MDP_VSYNC,
+	MDSS_MAX_CLK
+};
+
 struct mdss_res_type {
 	u32 rev;
 	u32 mdp_rev;
-	struct clk *mdp_clk;
-	struct clk *mdp_pclk;
-	struct clk *mdp_lut_clk;
-	struct clk *vsync_clk;
+	struct clk *mdp_clk[MDSS_MAX_CLK];
 	struct regulator *fs;
 
 	struct workqueue_struct *clk_ctrl_wq;
@@ -40,6 +47,8 @@
 	u32 irq_ena;
 	u32 irq_buzy;
 
+	u32 mdp_irq_mask;
+
 	u32 clk_ena;
 	u32 suspend;
 	u32 timeout;
@@ -60,4 +69,22 @@
 	u32 *mixer_type_map;
 };
 extern struct mdss_res_type *mdss_res;
+
+enum mdss_hw_index {
+	MDSS_HW_MDP,
+	MDSS_HW_DSI0,
+	MDSS_HW_DSI1,
+	MDSS_HW_HDMI,
+	MDSS_HW_EDP,
+	MDSS_MAX_HW_BLK
+};
+
+struct mdss_hw {
+	u32 hw_ndx;
+	irqreturn_t (*irq_handler)(int irq, void *ptr);
+};
+
+void mdss_enable_irq(struct mdss_hw *hw);
+void mdss_disable_irq(struct mdss_hw *hw);
+void mdss_disable_irq_nosync(struct mdss_hw *hw);
 #endif /* MDSS_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index d1847c3..41e0c18 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -39,14 +39,13 @@
 #include <mach/board.h>
 #include <mach/clk.h>
 #include <mach/hardware.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
 
 #include "mdss.h"
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
 
-/* 1.15 mdp clk factor */
-#define MDP_CLK_FACTOR(rate) (((rate) * 23) / 20)
-
 unsigned char *mdss_reg_base;
 
 struct mdss_res_type *mdss_res;
@@ -75,45 +74,261 @@
 	MDSS_MDP_MIXER_TYPE_WRITEBACK,
 };
 
-irqreturn_t mdss_irq_handler(int mdss_irq, void *ptr)
+#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val) \
+	{ \
+		.src = MSM_BUS_MASTER_MDP_PORT0,	\
+		.dst = MSM_BUS_SLAVE_EBI_CH0,		\
+		.ab = (ab_val),				\
+		.ib = (ib_val),				\
+	}
+
+#define MDP_BUS_VECTOR_ENTRY_NDX(n) \
+		MDP_BUS_VECTOR_ENTRY((n) * 100000000, (n) * 200000000)
+
+static struct msm_bus_vectors mdp_bus_vectors[] = {
+	MDP_BUS_VECTOR_ENTRY_NDX(0),
+	MDP_BUS_VECTOR_ENTRY_NDX(1),
+	MDP_BUS_VECTOR_ENTRY_NDX(2),
+	MDP_BUS_VECTOR_ENTRY_NDX(3),
+	MDP_BUS_VECTOR_ENTRY_NDX(4),
+	MDP_BUS_VECTOR_ENTRY_NDX(5),
+	MDP_BUS_VECTOR_ENTRY_NDX(6),
+	MDP_BUS_VECTOR_ENTRY_NDX(7),
+	MDP_BUS_VECTOR_ENTRY_NDX(8),
+	MDP_BUS_VECTOR_ENTRY_NDX(9),
+	MDP_BUS_VECTOR_ENTRY_NDX(10),
+	MDP_BUS_VECTOR_ENTRY(200000000, 200000000)
+};
+static struct msm_bus_paths mdp_bus_usecases[ARRAY_SIZE(mdp_bus_vectors)];
+static struct msm_bus_scale_pdata mdp_bus_scale_table = {
+	.usecase = mdp_bus_usecases,
+	.num_usecases = ARRAY_SIZE(mdp_bus_usecases),
+	.name = "mdss_mdp",
+};
+
+struct mdss_hw mdss_mdp_hw = {
+	.hw_ndx = MDSS_HW_MDP,
+	.irq_handler = mdss_mdp_isr,
+};
+
+static DEFINE_SPINLOCK(mdss_lock);
+struct mdss_hw *mdss_irq_handlers[MDSS_MAX_HW_BLK];
+
+static inline int mdss_irq_dispatch(u32 hw_ndx, int irq, void *ptr)
+{
+	struct mdss_hw *hw;
+
+	spin_lock(&mdss_lock);
+	hw = mdss_irq_handlers[hw_ndx];
+	spin_unlock(&mdss_lock);
+	if (hw)
+		return hw->irq_handler(irq, ptr);
+
+	return -ENODEV;
+}
+
+static irqreturn_t mdss_irq_handler(int irq, void *ptr)
 {
 	u32 intr = MDSS_MDP_REG_READ(MDSS_REG_HW_INTR_STATUS);
 
 	mdss_res->irq_buzy = true;
 
 	if (intr & MDSS_INTR_MDP)
-		mdss_mdp_isr(mdss_irq, ptr);
+		mdss_irq_dispatch(MDSS_HW_MDP, irq, ptr);
+
+	if (intr & MDSS_INTR_DSI0)
+		mdss_irq_dispatch(MDSS_HW_DSI0, irq, ptr);
+
+	if (intr & MDSS_INTR_DSI1)
+		mdss_irq_dispatch(MDSS_HW_DSI1, irq, ptr);
+
+	if (intr & MDSS_INTR_EDP)
+		mdss_irq_dispatch(MDSS_HW_EDP, irq, ptr);
+
+	if (intr & MDSS_INTR_HDMI)
+		mdss_irq_dispatch(MDSS_HW_HDMI, irq, ptr);
 
 	mdss_res->irq_buzy = false;
 
 	return IRQ_HANDLED;
 }
 
+
+void mdss_enable_irq(struct mdss_hw *hw)
+{
+	unsigned long irq_flags;
+	u32 ndx_bit;
+
+	if (hw->hw_ndx >= MDSS_MAX_HW_BLK)
+		return;
+
+	ndx_bit = BIT(hw->hw_ndx);
+
+	pr_debug("Enable HW=%d irq ena=%d mask=%x\n", hw->hw_ndx,
+			mdss_res->irq_ena, mdss_res->irq_mask);
+
+	spin_lock_irqsave(&mdss_lock, irq_flags);
+	if (mdss_res->irq_mask & ndx_bit) {
+		pr_debug("MDSS HW ndx=%d is already set, mask=%x\n",
+				hw->hw_ndx, mdss_res->irq_mask);
+	} else {
+		mdss_irq_handlers[hw->hw_ndx] = hw;
+		mdss_res->irq_mask |= ndx_bit;
+		if (!mdss_res->irq_ena) {
+			mdss_res->irq_ena = true;
+			enable_irq(mdss_res->irq);
+		}
+	}
+	spin_unlock_irqrestore(&mdss_lock, irq_flags);
+}
+EXPORT_SYMBOL(mdss_enable_irq);
+
+void mdss_disable_irq(struct mdss_hw *hw)
+{
+	unsigned long irq_flags;
+	u32 ndx_bit;
+
+	if (hw->hw_ndx >= MDSS_MAX_HW_BLK)
+		return;
+
+	ndx_bit = BIT(hw->hw_ndx);
+
+	pr_debug("Disable HW=%d irq ena=%d mask=%x\n", hw->hw_ndx,
+			mdss_res->irq_ena, mdss_res->irq_mask);
+
+	spin_lock_irqsave(&mdss_lock, irq_flags);
+	if (!(mdss_res->irq_mask & ndx_bit)) {
+		pr_warn("MDSS HW ndx=%d is NOT set, mask=%x\n",
+			hw->hw_ndx, mdss_res->mdp_irq_mask);
+	} else {
+		mdss_irq_handlers[hw->hw_ndx] = NULL;
+		mdss_res->irq_mask &= ~ndx_bit;
+		if (mdss_res->irq_mask == 0) {
+			mdss_res->irq_ena = false;
+			disable_irq(mdss_res->irq);
+		}
+	}
+	spin_unlock_irqrestore(&mdss_lock, irq_flags);
+}
+EXPORT_SYMBOL(mdss_disable_irq);
+
+void mdss_disable_irq_nosync(struct mdss_hw *hw)
+{
+	u32 ndx_bit;
+
+	if (hw->hw_ndx >= MDSS_MAX_HW_BLK)
+		return;
+
+	ndx_bit = BIT(hw->hw_ndx);
+
+	pr_debug("Disable HW=%d irq ena=%d mask=%x\n", hw->hw_ndx,
+			mdss_res->irq_ena, mdss_res->irq_mask);
+
+	spin_lock(&mdss_lock);
+	if (!(mdss_res->irq_mask & ndx_bit)) {
+		pr_warn("MDSS HW ndx=%d is NOT set, mask=%x\n",
+			hw->hw_ndx, mdss_res->mdp_irq_mask);
+	} else {
+		mdss_irq_handlers[hw->hw_ndx] = NULL;
+		mdss_res->irq_mask &= ~ndx_bit;
+		if (mdss_res->irq_mask == 0) {
+			mdss_res->irq_ena = false;
+			disable_irq_nosync(mdss_res->irq);
+		}
+	}
+	spin_unlock(&mdss_lock);
+}
+EXPORT_SYMBOL(mdss_disable_irq_nosync);
+
+static int mdss_mdp_bus_scale_register(void)
+{
+	if (!mdss_res->bus_hdl) {
+		struct msm_bus_scale_pdata *bus_pdata = &mdp_bus_scale_table;
+		int i;
+
+		for (i = 0; i < bus_pdata->num_usecases; i++) {
+			mdp_bus_usecases[i].num_paths = 1;
+			mdp_bus_usecases[i].vectors = &mdp_bus_vectors[i];
+		}
+
+		mdss_res->bus_hdl = msm_bus_scale_register_client(bus_pdata);
+		if (!mdss_res->bus_hdl) {
+			pr_err("not able to get bus scale\n");
+			return -ENOMEM;
+		}
+
+		pr_debug("register bus_hdl=%x\n", mdss_res->bus_hdl);
+	}
+	return 0;
+}
+
+static void mdss_mdp_bus_scale_unregister(void)
+{
+	pr_debug("unregister bus_hdl=%x\n", mdss_res->bus_hdl);
+
+	if (mdss_res->bus_hdl)
+		msm_bus_scale_unregister_client(mdss_res->bus_hdl);
+}
+
+int mdss_mdp_bus_scale_set_min_quota(u32 quota)
+{
+	struct msm_bus_scale_pdata *bus_pdata = &mdp_bus_scale_table;
+	struct msm_bus_vectors *vect = NULL;
+	int lvl;
+
+	if (mdss_res->bus_hdl < 1) {
+		pr_err("invalid bus handle %d\n", mdss_res->bus_hdl);
+		return -EINVAL;
+	}
+
+	for (lvl = 0; lvl < bus_pdata->num_usecases; lvl++) {
+		if (bus_pdata->usecase[lvl].num_paths) {
+			vect = &bus_pdata->usecase[lvl].vectors[0];
+			if (vect->ab >= quota) {
+				pr_debug("lvl=%d quota=%u ab=%u\n", lvl, quota,
+						vect->ab);
+				break;
+			}
+		}
+	}
+
+	if (lvl == bus_pdata->num_usecases) {
+		pr_warn("cannot match quota=%u try with max level\n", quota);
+		lvl--;
+	}
+
+	return msm_bus_scale_client_update_request(mdss_res->bus_hdl, lvl);
+}
+
+static inline u32 mdss_mdp_irq_mask(u32 intr_type, u32 intf_num)
+{
+	if (intr_type == MDSS_MDP_IRQ_INTF_UNDER_RUN ||
+	    intr_type == MDSS_MDP_IRQ_INTF_VSYNC)
+		intf_num = (intf_num - MDSS_MDP_INTF0) * 2;
+	return 1 << (intr_type + intf_num);
+}
+
 int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num)
 {
 	u32 irq;
 	unsigned long irq_flags;
 	int ret = 0;
 
-	if (intr_type == MDSS_MDP_IRQ_INTF_UNDER_RUN ||
-	    intr_type == MDSS_MDP_IRQ_INTF_VSYNC)
-		intf_num = intf_num << 1;
-
-	irq =  BIT(intr_type + intf_num);
+	irq = mdss_mdp_irq_mask(intr_type, intf_num);
 
 	spin_lock_irqsave(&mdp_lock, irq_flags);
-	if (mdss_res->irq_mask & irq) {
-		pr_warn("MDSS IRQ-0x%x is already set, mask=%x irq=%d\n",
-			irq, mdss_res->irq_mask, mdss_res->irq_ena);
+	if (mdss_res->mdp_irq_mask & irq) {
+		pr_warn("MDSS MDP IRQ-0x%x is already set, mask=%x\n",
+				irq, mdss_res->mdp_irq_mask);
 		ret = -EBUSY;
 	} else {
-		mdss_res->irq_mask |= irq;
+		pr_debug("MDP IRQ mask old=%x new=%x\n",
+				mdss_res->mdp_irq_mask, irq);
+		mdss_res->mdp_irq_mask |= irq;
 		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_CLEAR, irq);
-		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN, mdss_res->irq_mask);
-		if (!mdss_res->irq_ena) {
-			mdss_res->irq_ena = true;
-			enable_irq(mdss_res->irq);
-		}
+		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN,
+				mdss_res->mdp_irq_mask);
+		mdss_enable_irq(&mdss_mdp_hw);
 	}
 	spin_unlock_irqrestore(&mdp_lock, irq_flags);
 
@@ -125,24 +340,17 @@
 	u32 irq;
 	unsigned long irq_flags;
 
-
-	if (intr_type == MDSS_MDP_IRQ_INTF_UNDER_RUN ||
-	    intr_type == MDSS_MDP_IRQ_INTF_VSYNC)
-		intf_num = intf_num << 1;
-
-	irq = BIT(intr_type + intf_num);
+	irq = mdss_mdp_irq_mask(intr_type, intf_num);
 
 	spin_lock_irqsave(&mdp_lock, irq_flags);
-	if (!(mdss_res->irq_mask & irq)) {
-		pr_warn("MDSS IRQ-%x is NOT set, mask=%x irq=%d\n",
-			irq, mdss_res->irq_mask, mdss_res->irq_ena);
+	if (!(mdss_res->mdp_irq_mask & irq)) {
+		pr_warn("MDSS MDP IRQ-%x is NOT set, mask=%x\n",
+				irq, mdss_res->mdp_irq_mask);
 	} else {
-		mdss_res->irq_mask &= ~irq;
-		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN, mdss_res->irq_mask);
-		if (!mdss_res->irq_mask) {
-			mdss_res->irq_ena = false;
-			disable_irq(mdss_res->irq);
-		}
+		mdss_res->mdp_irq_mask &= ~irq;
+		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN,
+				mdss_res->mdp_irq_mask);
+		mdss_disable_irq(&mdss_mdp_hw);
 	}
 	spin_unlock_irqrestore(&mdp_lock, irq_flags);
 }
@@ -151,34 +359,114 @@
 {
 	u32 irq;
 
-	if (intr_type == MDSS_MDP_IRQ_INTF_UNDER_RUN ||
-	    intr_type == MDSS_MDP_IRQ_INTF_VSYNC)
-		intf_num = intf_num << 1;
-
-	irq = BIT(intr_type + intf_num);
+	irq = mdss_mdp_irq_mask(intr_type, intf_num);
 
 	spin_lock(&mdp_lock);
-	if (!(mdss_res->irq_mask & irq)) {
-		pr_warn("MDSS IRQ-%x is NOT set, mask=%x irq=%d\n",
-			irq, mdss_res->irq_mask, mdss_res->irq_ena);
+	if (!(mdss_res->mdp_irq_mask & irq)) {
+		pr_warn("MDSS MDP IRQ-%x is NOT set, mask=%x\n",
+				irq, mdss_res->mdp_irq_mask);
 	} else {
-		mdss_res->irq_mask &= ~irq;
-		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN, mdss_res->irq_mask);
-		if (!mdss_res->irq_mask) {
-			mdss_res->irq_ena = false;
-			disable_irq_nosync(mdss_res->irq);
-		}
+		mdss_res->mdp_irq_mask &= ~irq;
+		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN,
+				mdss_res->mdp_irq_mask);
+		mdss_disable_irq_nosync(&mdss_mdp_hw);
 	}
 	spin_unlock(&mdp_lock);
 }
 
+static inline struct clk *mdss_mdp_get_clk(u32 clk_idx)
+{
+	if (clk_idx < MDSS_MAX_CLK)
+		return mdss_res->mdp_clk[clk_idx];
+	return NULL;
+}
+
+static int mdss_mdp_clk_update(u32 clk_idx, u32 enable)
+{
+	int ret = -ENODEV;
+	struct clk *clk = mdss_mdp_get_clk(clk_idx);
+
+	if (clk) {
+		pr_debug("clk=%d en=%d\n", clk_idx, enable);
+		if (enable) {
+			ret = clk_prepare_enable(clk);
+		} else {
+			clk_disable_unprepare(clk);
+			ret = 0;
+		}
+	}
+	return ret;
+}
+
+int mdss_mdp_vsync_clk_enable(int enable)
+{
+	int ret = 0;
+	pr_debug("clk enable=%d\n", enable);
+	mutex_lock(&mdp_clk_lock);
+	if (mdss_res->vsync_ena != enable) {
+		mdss_res->vsync_ena = enable;
+		ret = mdss_mdp_clk_update(MDSS_CLK_MDP_VSYNC, enable);
+	}
+	mutex_unlock(&mdp_clk_lock);
+	return ret;
+}
+
+void mdss_mdp_set_clk_rate(unsigned long min_clk_rate)
+{
+	unsigned long clk_rate;
+	struct clk *clk = mdss_mdp_get_clk(MDSS_CLK_MDP_SRC);
+	if (clk) {
+		mutex_lock(&mdp_clk_lock);
+		clk_rate = clk_round_rate(clk, min_clk_rate);
+		if (IS_ERR_VALUE(clk_rate)) {
+			pr_err("unable to round rate err=%ld\n", clk_rate);
+		} else if (clk_rate != clk_get_rate(clk)) {
+			if (IS_ERR_VALUE(clk_set_rate(clk, clk_rate)))
+				pr_err("clk_set_rate failed\n");
+			else
+				pr_debug("mdp clk rate=%lu\n", clk_rate);
+		}
+		mutex_unlock(&mdp_clk_lock);
+	}
+}
+
+unsigned long mdss_mdp_get_clk_rate(u32 clk_idx)
+{
+	unsigned long clk_rate = 0;
+	struct clk *clk = mdss_mdp_get_clk(clk_idx);
+	mutex_lock(&mdp_clk_lock);
+	if (clk)
+		clk_rate = clk_get_rate(clk);
+	mutex_unlock(&mdp_clk_lock);
+
+	return clk_rate;
+}
+
 static void mdss_mdp_clk_ctrl_update(int enable)
 {
 	if (mdss_res->clk_ena == enable)
 		return;
 
 	pr_debug("MDP CLKS %s\n", (enable ? "Enable" : "Disable"));
+
+	mutex_lock(&mdp_clk_lock);
 	mdss_res->clk_ena = enable;
+	mb();
+
+	mdss_mdp_clk_update(MDSS_CLK_AHB, enable);
+	mdss_mdp_clk_update(MDSS_CLK_AXI, enable);
+
+	mdss_mdp_clk_update(MDSS_CLK_MDP_CORE, enable);
+	mdss_mdp_clk_update(MDSS_CLK_MDP_LUT, enable);
+	if (mdss_res->vsync_ena)
+		mdss_mdp_clk_update(MDSS_CLK_MDP_VSYNC, enable);
+
+	mutex_unlock(&mdp_clk_lock);
+}
+
+static void mdss_mdp_clk_ctrl_workqueue_handler(struct work_struct *work)
+{
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 }
 
 void mdss_mdp_clk_ctrl(int enable, int isr)
@@ -233,14 +521,30 @@
 	}
 }
 
-static void mdss_mdp_clk_ctrl_workqueue_handler(struct work_struct *work)
+static inline int mdss_mdp_irq_clk_register(struct platform_device *pdev,
+					    char *clk_name, int clk_idx)
 {
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	struct clk *tmp;
+	if (clk_idx >= MDSS_MAX_CLK) {
+		pr_err("invalid clk index %d\n", clk_idx);
+		return -EINVAL;
+	}
+
+
+	tmp = clk_get(&pdev->dev, clk_name);
+	if (IS_ERR(tmp)) {
+		pr_err("unable to get clk: %s\n", clk_name);
+		return PTR_ERR(tmp);
+	}
+
+	mdss_res->mdp_clk[clk_idx] = tmp;
+	return 0;
 }
 
-static int mdss_mdp_irq_clk_setup(void)
+static int mdss_mdp_irq_clk_setup(struct platform_device *pdev)
 {
 	int ret;
+	int i;
 
 	ret = request_irq(mdss_res->irq, mdss_irq_handler, IRQF_DISABLED,
 			  "MDSS", 0);
@@ -250,15 +554,38 @@
 	}
 	disable_irq(mdss_res->irq);
 
-	mdss_res->fs = regulator_get(NULL, "fs_mdp");
-	if (IS_ERR(mdss_res->fs))
+	mdss_res->fs = regulator_get(NULL, "gdsc_mdss");
+	if (IS_ERR_OR_NULL(mdss_res->fs)) {
 		mdss_res->fs = NULL;
-	else {
-		regulator_enable(mdss_res->fs);
-		mdss_res->fs_ena = true;
+		pr_err("unable to get gdsc_mdss regulator\n");
+		goto error;
 	}
+	regulator_enable(mdss_res->fs);
+
+	if (mdss_mdp_irq_clk_register(pdev, "bus_clk", MDSS_CLK_AXI) ||
+	    mdss_mdp_irq_clk_register(pdev, "iface_clk", MDSS_CLK_AHB) ||
+	    mdss_mdp_irq_clk_register(pdev, "core_clk_src", MDSS_CLK_MDP_SRC) ||
+	    mdss_mdp_irq_clk_register(pdev, "core_clk", MDSS_CLK_MDP_CORE) ||
+	    mdss_mdp_irq_clk_register(pdev, "lut_clk", MDSS_CLK_MDP_LUT) ||
+	    mdss_mdp_irq_clk_register(pdev, "vsync_clk", MDSS_CLK_MDP_VSYNC))
+		goto error;
+
+	mdss_mdp_set_clk_rate(MDP_CLK_DEFAULT_RATE);
+	pr_debug("mdp clk rate=%ld\n", mdss_mdp_get_clk_rate(MDSS_CLK_MDP_SRC));
 
 	return 0;
+error:
+	for (i = 0; i < MDSS_MAX_CLK; i++) {
+		if (mdss_res->mdp_clk[i])
+			clk_put(mdss_res->mdp_clk[i]);
+	}
+	if (mdss_res->fs)
+		regulator_put(mdss_res->fs);
+	if (mdss_res->irq)
+		free_irq(mdss_res->irq, 0);
+
+	return -EINVAL;
+
 }
 
 static struct msm_panel_common_pdata *mdss_mdp_populate_pdata(
@@ -272,11 +599,11 @@
 	return pdata;
 }
 
-static u32 mdss_mdp_res_init(void)
+static u32 mdss_mdp_res_init(struct platform_device *pdev)
 {
 	u32 rc;
 
-	rc = mdss_mdp_irq_clk_setup();
+	rc = mdss_mdp_irq_clk_setup(pdev);
 	if (rc)
 		return rc;
 
@@ -365,12 +692,12 @@
 		goto probe_done;
 	}
 
-	rc = mdss_mdp_res_init();
+	rc = mdss_mdp_res_init(pdev);
 	if (rc) {
 		pr_err("unable to initialize mdss mdp resources\n");
 		goto probe_done;
 	}
-
+	rc = mdss_mdp_bus_scale_register();
 probe_done:
 	if (IS_ERR_VALUE(rc)) {
 		if (mdss_res) {
@@ -448,6 +775,7 @@
 		regulator_put(mdss_res->fs);
 	iounmap(mdss_reg_base);
 	pm_runtime_disable(&pdev->dev);
+	mdss_mdp_bus_scale_unregister();
 	return 0;
 }
 
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index c65d5a7..2cdd9f6 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -93,9 +93,18 @@
 	MDSS_MDP_BLOCK_MAX
 };
 
+enum mdss_mdp_csc_type {
+	MDSS_MDP_CSC_RGB2RGB,
+	MDSS_MDP_CSC_YUV2RGB,
+	MDSS_MDP_CSC_RGB2YUV,
+	MDSS_MDP_CSC_YUV2YUV,
+	MDSS_MDP_MAX_CSC
+};
+
 struct mdss_mdp_ctl {
 	u32 num;
 	u32 ref_cnt;
+	int power_on;
 
 	u32 intf_num;
 	u32 intf_type;
@@ -109,6 +118,8 @@
 	u16 height;
 	u32 dst_format;
 
+	u32 bus_quota;
+
 	struct msm_fb_data_type *mfd;
 	struct mdss_mdp_mixer *mixer_left;
 	struct mdss_mdp_mixer *mixer_right;
@@ -133,6 +144,8 @@
 	u8 cursor_enabled;
 	u8 rotator_mode;
 
+	u32 bus_quota;
+
 	struct mdss_mdp_ctl *ctl;
 	struct mdss_mdp_pipe *stage_pipe[MDSS_MDP_MAX_STAGE];
 };
@@ -218,6 +231,7 @@
 	struct mdss_mdp_format_params *src_fmt;
 	struct mdss_mdp_plane_sizes src_planes;
 
+	u32 bus_quota;
 	u8 mixer_stage;
 	u8 is_fg;
 	u8 alpha;
@@ -253,17 +267,22 @@
 int mdss_mdp_set_intr_callback(u32 intr_type, u32 intf_num,
 			       void (*fnc_ptr)(void *), void *arg);
 
+int mdss_mdp_bus_scale_set_min_quota(u32 quota);
+void mdss_mdp_set_clk_rate(unsigned long min_clk_rate);
 unsigned long mdss_mdp_get_clk_rate(u32 clk_idx);
 int mdss_mdp_vsync_clk_enable(int enable);
 void mdss_mdp_clk_ctrl(int enable, int isr);
 void mdss_mdp_footswitch_ctrl(int on);
 
 int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd);
+int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl);
 int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl);
 
 int mdss_mdp_ctl_on(struct msm_fb_data_type *mfd);
 int mdss_mdp_ctl_off(struct msm_fb_data_type *mfd);
 
+struct mdss_mdp_mixer *mdss_mdp_wb_mixer_alloc(int rotator);
+int mdss_mdp_wb_mixer_destroy(struct mdss_mdp_mixer *mixer);
 struct mdss_mdp_mixer *mdss_mdp_mixer_get(struct mdss_mdp_ctl *ctl, int mux);
 struct mdss_mdp_pipe *mdss_mdp_mixer_stage_pipe(struct mdss_mdp_ctl *ctl,
 						int mux, int stage);
@@ -271,6 +290,9 @@
 int mdss_mdp_mixer_pipe_unstage(struct mdss_mdp_pipe *pipe);
 int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg);
 
+int mdss_mdp_csc_setup(u32 block, u32 blk_idx, u32 tbl_idx, u32 csc_type);
+int mdss_mdp_dspp_setup(struct mdss_mdp_ctl *ctl, struct mdss_mdp_mixer *mixer);
+
 struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_pnum(u32 pnum);
 struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_locked(u32 type);
 struct mdss_mdp_pipe *mdss_mdp_pipe_get_locked(u32 ndx);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index d89347e..c80527d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -20,10 +20,127 @@
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
 
+enum {
+	MDSS_MDP_BUS_UPDATE_SKIP,
+	MDSS_MDP_BUS_UPDATE_EARLY,
+	MDSS_MDP_BUS_UPDATE_LATE,
+};
+
 static DEFINE_MUTEX(mdss_mdp_ctl_lock);
 static struct mdss_mdp_ctl mdss_mdp_ctl_list[MDSS_MDP_MAX_CTL];
 static struct mdss_mdp_mixer mdss_mdp_mixer_list[MDSS_MDP_MAX_LAYERMIXER];
 
+static int mdss_mdp_ctl_update_clk_rate(void)
+{
+	struct mdss_mdp_ctl *ctl;
+	int cnum;
+	unsigned long clk_rate = MDP_CLK_DEFAULT_RATE;
+
+	mutex_lock(&mdss_mdp_ctl_lock);
+	for (cnum = 0; cnum < MDSS_MDP_MAX_CTL; cnum++) {
+		ctl = &mdss_mdp_ctl_list[cnum];
+		if (ctl->power_on && ctl->mfd) {
+			unsigned long tmp;
+			pr_debug("ctl=%d pclk_rate=%u\n", ctl->num,
+					ctl->mfd->panel_info.clk_rate);
+			tmp = (ctl->mfd->panel_info.clk_rate * 23) / 20;
+			if (tmp > clk_rate)
+				clk_rate = tmp;
+		}
+	}
+	mdss_mdp_set_clk_rate(clk_rate);
+	mutex_unlock(&mdss_mdp_ctl_lock);
+
+	return 0;
+}
+
+static int mdss_mdp_ctl_update_bus_scale(void)
+{
+	struct mdss_mdp_ctl *ctl;
+	int cnum;
+	u32 bus_quota = 0;
+
+	mutex_lock(&mdss_mdp_ctl_lock);
+	for (cnum = 0; cnum < MDSS_MDP_MAX_CTL; cnum++) {
+		ctl = &mdss_mdp_ctl_list[cnum];
+		if (ctl->power_on)
+			bus_quota += ctl->bus_quota;
+	}
+	mdss_mdp_bus_scale_set_min_quota(bus_quota);
+	mutex_unlock(&mdss_mdp_ctl_lock);
+
+	return 0;
+}
+
+static void mdss_mdp_bus_update_pipe_quota(struct mdss_mdp_pipe *pipe)
+{
+	u32 quota;
+
+	quota = pipe->img_width * pipe->img_height * 60 * pipe->src_fmt->bpp;
+	quota *= 5 / 4; /* 1.25 factor */
+
+	pr_debug("pipe=%d quota old=%u new=%u\n", pipe->num,
+		   pipe->bus_quota, quota);
+	pipe->bus_quota = quota;
+}
+
+static int mdss_mdp_bus_update_mixer_quota(struct mdss_mdp_mixer *mixer)
+{
+	struct mdss_mdp_pipe *pipe;
+	u32 quota, stage;
+
+	if (!mixer)
+		return 0;
+
+	quota = 0;
+	for (stage = 0; stage < MDSS_MDP_MAX_STAGE; stage++) {
+		pipe = mixer->stage_pipe[stage];
+		if (pipe == NULL)
+			continue;
+
+		quota += pipe->bus_quota;
+	}
+
+	pr_debug("mixer=%d quota old=%u new=%u\n", mixer->num,
+		   mixer->bus_quota, quota);
+
+	if (quota != mixer->bus_quota) {
+		mixer->bus_quota = quota;
+		return 1;
+	}
+
+	return 0;
+}
+
+static int mdss_mdp_bus_update_ctl_quota(struct mdss_mdp_ctl *ctl)
+{
+	int ret = MDSS_MDP_BUS_UPDATE_SKIP;
+
+	if (mdss_mdp_bus_update_mixer_quota(ctl->mixer_left) ||
+			mdss_mdp_bus_update_mixer_quota(ctl->mixer_right)) {
+		u32 quota = 0;
+
+		if (ctl->mixer_left)
+			quota += ctl->mixer_left->bus_quota;
+		if (ctl->mixer_right)
+			quota += ctl->mixer_right->bus_quota;
+
+		pr_debug("ctl=%d quota old=%u new=%u\n",
+			   ctl->num, ctl->bus_quota, quota);
+
+		if (quota != ctl->bus_quota) {
+			if (quota > ctl->bus_quota)
+				ret = MDSS_MDP_BUS_UPDATE_EARLY;
+			else
+				ret = MDSS_MDP_BUS_UPDATE_LATE;
+
+			ctl->bus_quota = quota;
+		}
+	}
+
+	return ret;
+}
+
 static struct mdss_mdp_ctl *mdss_mdp_ctl_alloc(void)
 {
 	struct mdss_mdp_ctl *ctl = NULL;
@@ -110,6 +227,71 @@
 	return 0;
 }
 
+struct mdss_mdp_mixer *mdss_mdp_wb_mixer_alloc(int rotator)
+{
+	struct mdss_mdp_ctl *ctl = NULL;
+	struct mdss_mdp_mixer *mixer = NULL;
+
+	ctl = mdss_mdp_ctl_alloc();
+
+	if (!ctl)
+		return NULL;
+
+	mixer = mdss_mdp_mixer_alloc(MDSS_MDP_MIXER_TYPE_WRITEBACK);
+	if (!mixer)
+		goto error;
+
+	mixer->rotator_mode = rotator;
+
+	switch (mixer->num) {
+	case MDSS_MDP_LAYERMIXER3:
+		ctl->opmode = (rotator ? MDSS_MDP_CTL_OP_ROT0_MODE :
+			       MDSS_MDP_CTL_OP_WB0_MODE);
+		break;
+	case MDSS_MDP_LAYERMIXER4:
+		ctl->opmode = (rotator ? MDSS_MDP_CTL_OP_ROT1_MODE :
+			       MDSS_MDP_CTL_OP_WB1_MODE);
+		break;
+	default:
+		pr_err("invalid layer mixer=%d\n", mixer->num);
+		goto error;
+	}
+
+	ctl->mixer_left = mixer;
+	mixer->ctl = ctl;
+
+	ctl->start_fnc = mdss_mdp_writeback_start;
+
+	if (ctl->start_fnc)
+		ctl->start_fnc(ctl);
+
+	return mixer;
+error:
+	if (mixer)
+		mdss_mdp_mixer_free(mixer);
+	if (ctl)
+		mdss_mdp_ctl_free(ctl);
+
+	return NULL;
+}
+
+int mdss_mdp_wb_mixer_destroy(struct mdss_mdp_mixer *mixer)
+{
+	struct mdss_mdp_ctl *ctl;
+
+	ctl = mixer->ctl;
+
+	pr_debug("destroy ctl=%d mixer=%d\n", ctl->num, mixer->num);
+
+	if (ctl->stop_fnc)
+		ctl->stop_fnc(ctl);
+
+	mdss_mdp_mixer_free(mixer);
+	mdss_mdp_ctl_free(ctl);
+
+	return 0;
+}
+
 static int mdss_mdp_ctl_init(struct msm_fb_data_type *mfd)
 {
 	struct mdss_mdp_ctl *ctl;
@@ -166,6 +348,27 @@
 	}
 
 	switch (mfd->panel_info.type) {
+	case EDP_PANEL:
+		ctl->intf_num = MDSS_MDP_INTF0;
+		ctl->intf_type = MDSS_INTF_EDP;
+		ctl->opmode = MDSS_MDP_CTL_OP_VIDEO_MODE;
+		ctl->start_fnc = mdss_mdp_video_start;
+		break;
+	case MIPI_VIDEO_PANEL:
+		if (mfd->panel_info.pdest == DISPLAY_1)
+			ctl->intf_num = MDSS_MDP_INTF1;
+		else
+			ctl->intf_num = MDSS_MDP_INTF2;
+		ctl->intf_type = MDSS_INTF_DSI;
+		ctl->opmode = MDSS_MDP_CTL_OP_VIDEO_MODE;
+		ctl->start_fnc = mdss_mdp_video_start;
+		break;
+	case DTV_PANEL:
+		ctl->intf_num = MDSS_MDP_INTF3;
+		ctl->intf_type = MDSS_INTF_HDMI;
+		ctl->opmode = MDSS_MDP_CTL_OP_VIDEO_MODE;
+		ctl->start_fnc = mdss_mdp_video_start;
+		break;
 	case WRITEBACK_PANEL:
 		ctl->intf_num = MDSS_MDP_NO_INTF;
 		ctl->opmode = MDSS_MDP_CTL_OP_WFD_MODE;
@@ -237,6 +440,10 @@
 	ctl = mfd->ctl;
 
 	mutex_lock(&ctl->lock);
+
+	ctl->power_on = true;
+	mdss_mdp_ctl_update_clk_rate();
+
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 	if (ctl->start_fnc)
 		ret = ctl->start_fnc(ctl);
@@ -255,7 +462,7 @@
 	mixer->params_changed++;
 
 	temp = MDSS_MDP_REG_READ(MDSS_MDP_REG_DISP_INTF_SEL);
-	temp |= (ctl->intf_type << (ctl->intf_num * 8));
+	temp |= (ctl->intf_type << ((ctl->intf_num - MDSS_MDP_INTF0) * 8));
 	MDSS_MDP_REG_WRITE(MDSS_MDP_REG_DISP_INTF_SEL, temp);
 
 	outsize = (mixer->height << 16) | mixer->width;
@@ -308,6 +515,8 @@
 	pr_debug("ctl_num=%d\n", mfd->ctl->num);
 
 	mutex_lock(&ctl->lock);
+	ctl->power_on = false;
+
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 	if (ctl->stop_fnc)
 		ret = ctl->stop_fnc(ctl);
@@ -321,6 +530,10 @@
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 
 	ctl->play_cnt = 0;
+
+	mdss_mdp_ctl_update_bus_scale();
+	mdss_mdp_ctl_update_clk_rate();
+
 	mutex_unlock(&ctl->lock);
 
 	mdss_mdp_pipe_release_all(mfd);
@@ -328,7 +541,6 @@
 	if (!mfd->ref_cnt)
 		mdss_mdp_ctl_destroy(mfd);
 
-
 	return ret;
 }
 
@@ -493,6 +705,7 @@
 	if (params_changed) {
 		mixer->params_changed++;
 		mixer->stage_pipe[pipe->mixer_stage] = pipe;
+		mdss_mdp_bus_update_pipe_quota(pipe);
 	}
 
 	if (pipe->type == MDSS_MDP_PIPE_TYPE_DMA)
@@ -537,6 +750,9 @@
 {
 	mixer->params_changed = 0;
 
+	if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF)
+		mdss_mdp_dspp_setup(mixer->ctl, mixer);
+
 	/* skip mixer setup for rotator */
 	if (!mixer->rotator_mode)
 		mdss_mdp_mixer_setup(mixer->ctl, mixer);
@@ -548,6 +764,7 @@
 {
 	int mixer1_changed, mixer2_changed;
 	int ret = 0;
+	int bus_update = MDSS_MDP_BUS_UPDATE_SKIP;
 
 	if (!ctl) {
 		pr_err("display function not set\n");
@@ -564,6 +781,8 @@
 
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 	if (mixer1_changed || mixer2_changed) {
+		bus_update = mdss_mdp_bus_update_ctl_quota(ctl);
+
 		if (ctl->prepare_fnc)
 			ret = ctl->prepare_fnc(ctl, arg);
 		if (ret) {
@@ -571,6 +790,9 @@
 			goto done;
 		}
 
+		if (bus_update == MDSS_MDP_BUS_UPDATE_EARLY)
+			mdss_mdp_ctl_update_bus_scale();
+
 		if (mixer1_changed)
 			mdss_mdp_mixer_update(ctl->mixer_left);
 		if (mixer2_changed)
@@ -591,6 +813,9 @@
 
 	ctl->play_cnt++;
 
+	if (bus_update == MDSS_MDP_BUS_UPDATE_LATE)
+		mdss_mdp_ctl_update_bus_scale();
+
 done:
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
new file mode 100644
index 0000000..21ef290
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -0,0 +1,319 @@
+/* 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.
+ *
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include "mdss_fb.h"
+#include "mdss_mdp.h"
+
+/* intf timing settings */
+struct intf_timing_params {
+	u32 width;
+	u32 height;
+	u32 xres;
+	u32 yres;
+
+	u32 h_back_porch;
+	u32 h_front_porch;
+	u32 v_back_porch;
+	u32 v_front_porch;
+	u32 hsync_pulse_width;
+	u32 vsync_pulse_width;
+
+	u32 border_clr;
+	u32 underflow_clr;
+	u32 hsync_skew;
+};
+
+#define MAX_SESSIONS 3
+struct mdss_mdp_video_ctx {
+	u32 ctl_num;
+	u32 pp_num;
+	u8 ref_cnt;
+
+	u8 timegen_en;
+	struct completion pp_comp;
+	struct completion vsync_comp;
+};
+
+struct mdss_mdp_video_ctx mdss_mdp_video_ctx_list[MAX_SESSIONS];
+
+static int mdss_mdp_video_timegen_setup(struct mdss_mdp_ctl *ctl,
+					struct intf_timing_params *p)
+{
+	u32 hsync_period, vsync_period;
+	u32 hsync_start_x, hsync_end_x, display_v_start, display_v_end;
+	u32 active_h_start, active_h_end, active_v_start, active_v_end;
+	u32 display_hctl, active_hctl, hsync_ctl, polarity_ctl;
+	int off;
+
+	off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
+
+	hsync_period = p->hsync_pulse_width + p->h_back_porch +
+			p->width + p->h_front_porch;
+	vsync_period = p->vsync_pulse_width + p->v_back_porch +
+			p->height + p->v_front_porch;
+
+	display_v_start = ((p->vsync_pulse_width + p->v_back_porch) *
+			hsync_period) + p->hsync_skew;
+	display_v_end = ((vsync_period - p->v_front_porch) * hsync_period) +
+			p->hsync_skew - 1;
+
+	if (ctl->intf_type == MDSS_INTF_EDP) {
+		display_v_start += p->hsync_pulse_width + p->h_back_porch;
+		display_v_end -= p->h_front_porch;
+	}
+
+	hsync_start_x = p->h_back_porch + p->hsync_pulse_width;
+	hsync_end_x = hsync_period - p->h_front_porch - 1;
+
+	if (p->width != p->xres) {
+		active_h_start = hsync_start_x;
+		active_h_end = active_h_start + p->xres - 1;
+	} else {
+		active_h_start = 0;
+		active_h_end = 0;
+	}
+
+	if (p->height != p->yres) {
+		active_v_start = display_v_start;
+		active_v_end = active_v_start + (p->yres * hsync_period) - 1;
+	} else {
+		active_v_start = 0;
+		active_v_end = 0;
+	}
+
+
+	if (active_h_end) {
+		active_hctl = (active_h_end << 16) | active_h_start;
+		active_hctl |= BIT(31);	/* ACTIVE_H_ENABLE */
+	} else {
+		active_hctl = 0;
+	}
+
+	if (active_v_end)
+		active_v_start |= BIT(31); /* ACTIVE_V_ENABLE */
+
+	hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width;
+	display_hctl = (hsync_end_x << 16) | hsync_start_x;
+	polarity_ctl = (0 << 2) |	/* DEN Polarity */
+		       (0 << 1) |      /* VSYNC Polarity */
+		       (0);	       /* HSYNC Polarity */
+
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_HSYNC_CTL, hsync_ctl);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0,
+			   vsync_period * hsync_period);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_VSYNC_PULSE_WIDTH_F0,
+			   p->vsync_pulse_width * hsync_period);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_DISPLAY_HCTL,
+			   display_hctl);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_DISPLAY_V_START_F0,
+			   display_v_start);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_DISPLAY_V_END_F0,
+			   display_v_end);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_ACTIVE_HCTL, active_hctl);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_ACTIVE_V_START_F0,
+			   active_v_start);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_ACTIVE_V_END_F0,
+			   active_v_end);
+
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_BORDER_COLOR,
+			   p->border_clr);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_UNDERFLOW_COLOR,
+			   p->underflow_clr);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_HSYNC_SKEW,
+			   p->hsync_skew);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_POLARITY_CTL,
+			   polarity_ctl);
+
+	return 0;
+}
+
+static int mdss_mdp_video_stop(struct mdss_mdp_ctl *ctl)
+{
+	struct mdss_mdp_video_ctx *ctx;
+	int off;
+
+	pr_debug("stop ctl=%d\n", ctl->num);
+
+	ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
+	if (!ctx) {
+		pr_err("invalid ctx for ctl=%d\n", ctl->num);
+		return -ENODEV;
+	}
+
+	if (ctx->timegen_en) {
+		off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
+		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 0);
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+		ctx->timegen_en = false;
+	}
+
+	memset(ctx, 0, sizeof(*ctx));
+
+	return 0;
+}
+
+static void mdss_mdp_video_pp_intr_done(void *arg)
+{
+	struct mdss_mdp_video_ctx *ctx;
+
+	ctx = (struct mdss_mdp_video_ctx *) arg;
+	if (!ctx) {
+		pr_err("invalid ctx\n");
+		return;
+	}
+
+	pr_debug("intr mixer=%d\n", ctx->pp_num);
+
+	complete(&ctx->pp_comp);
+}
+
+static void mdss_mdp_video_vsync_intr_done(void *arg)
+{
+	struct mdss_mdp_video_ctx *ctx;
+
+	ctx = (struct mdss_mdp_video_ctx *) arg;
+	if (!ctx) {
+		pr_err("invalid ctx\n");
+		return;
+	}
+
+	pr_debug("intr ctl=%d\n", ctx->ctl_num);
+
+	complete(&ctx->vsync_comp);
+}
+
+static int mdss_mdp_video_prepare(struct mdss_mdp_ctl *ctl, void *arg)
+{
+	struct mdss_mdp_video_ctx *ctx;
+
+	ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
+	if (!ctx) {
+		pr_err("invalid ctx\n");
+		return -ENODEV;
+	}
+
+	if (ctx->timegen_en) {
+		u32 intr_type = MDSS_MDP_IRQ_PING_PONG_COMP;
+
+		pr_debug("waiting for ping pong %d done\n", ctx->pp_num);
+		mdss_mdp_set_intr_callback(intr_type, ctx->pp_num,
+					   mdss_mdp_video_pp_intr_done, ctx);
+		mdss_mdp_irq_enable(intr_type, ctx->pp_num);
+
+		wait_for_completion_interruptible(&ctx->pp_comp);
+		mdss_mdp_irq_disable(intr_type, ctx->pp_num);
+	}
+
+	return 0;
+}
+
+static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg)
+{
+	struct mdss_mdp_video_ctx *ctx;
+	u32 intr_type = MDSS_MDP_IRQ_INTF_VSYNC;
+
+	pr_debug("kickoff ctl=%d\n", ctl->num);
+
+	ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
+	if (!ctx) {
+		pr_err("invalid ctx\n");
+		return -ENODEV;
+	}
+	mdss_mdp_set_intr_callback(intr_type, ctl->intf_num,
+				   mdss_mdp_video_vsync_intr_done, ctx);
+	mdss_mdp_irq_enable(intr_type, ctl->intf_num);
+
+	if (!ctx->timegen_en) {
+		int off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
+
+		pr_debug("enabling timing gen for intf=%d\n", ctl->intf_num);
+
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 1);
+		ctx->timegen_en = true;
+		wmb();
+	}
+
+	wait_for_completion_interruptible(&ctx->vsync_comp);
+	mdss_mdp_irq_disable(intr_type, ctl->intf_num);
+
+	return 0;
+}
+
+int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl)
+{
+	struct msm_fb_data_type *mfd;
+	struct mdss_panel_info *pinfo;
+	struct mdss_mdp_video_ctx *ctx;
+	struct mdss_mdp_mixer *mixer;
+	struct intf_timing_params itp = {0};
+	struct fb_info *fbi;
+	int i;
+
+	mfd = ctl->mfd;
+	fbi = mfd->fbi;
+	pinfo = &mfd->panel_info;
+	mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT);
+
+	if (!mixer) {
+		pr_err("mixer not setup correctly\n");
+		return -ENODEV;
+	}
+
+	pr_debug("start ctl=%u\n", ctl->num);
+
+	for (i = 0; i < MAX_SESSIONS; i++) {
+		ctx = &mdss_mdp_video_ctx_list[i];
+		if (ctx->ref_cnt == 0) {
+			ctx->ref_cnt++;
+			break;
+		}
+	}
+	if (i == MAX_SESSIONS) {
+		pr_err("too many sessions\n");
+		return -ENOMEM;
+	}
+	ctl->priv_data = ctx;
+	ctx->ctl_num = ctl->num;
+	ctx->pp_num = mixer->num;
+	init_completion(&ctx->pp_comp);
+	init_completion(&ctx->vsync_comp);
+
+	itp.width = pinfo->xres + pinfo->lcdc.xres_pad;
+	itp.height = pinfo->yres + pinfo->lcdc.yres_pad;
+	itp.border_clr = pinfo->lcdc.border_clr;
+	itp.underflow_clr = pinfo->lcdc.underflow_clr;
+	itp.hsync_skew = pinfo->lcdc.hsync_skew;
+
+	itp.xres = fbi->var.xres;
+	itp.yres = fbi->var.yres;
+	itp.h_back_porch = fbi->var.left_margin;
+	itp.h_front_porch = fbi->var.right_margin;
+	itp.v_back_porch = fbi->var.upper_margin;
+	itp.v_front_porch = fbi->var.lower_margin;
+	itp.hsync_pulse_width = fbi->var.hsync_len;
+	itp.vsync_pulse_width = fbi->var.vsync_len;
+
+	if (mdss_mdp_video_timegen_setup(ctl, &itp)) {
+		pr_err("unable to get timing parameters\n");
+		return -EINVAL;
+	}
+
+	ctl->stop_fnc = mdss_mdp_video_stop;
+	ctl->prepare_fnc = mdss_mdp_video_prepare;
+	ctl->display_fnc = mdss_mdp_video_display;
+
+	return 0;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index 99d4b4c..c1bc58a 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -15,6 +15,7 @@
 
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
+#include "mdss_mdp_rotator.h"
 
 #define ROT_BLK_SIZE	128
 
@@ -193,6 +194,35 @@
 	return 0;
 }
 
+static int mdss_mdp_writeback_rot_setup(struct mdss_mdp_ctl *ctl,
+					struct mdss_mdp_writeback_ctx *ctx,
+					struct mdss_mdp_rotator_session *rot)
+{
+	pr_debug("rotator wb_num=%d\n", ctx->wb_num);
+
+	ctx->opmode = BIT(6); /* ROT EN */
+	if (ROT_BLK_SIZE == 128)
+		ctx->opmode |= BIT(4); /* block size 128 */
+
+	ctx->opmode |= rot->bwc_mode;
+
+	ctx->width = rot->src_rect.w;
+	ctx->height = rot->src_rect.h;
+
+	ctx->format = rot->format;
+
+	ctx->rot90 = !!(rot->rotations & MDP_ROT_90);
+	if (ctx->rot90) {
+		ctx->opmode |= BIT(5); /* ROT 90 */
+		swap(ctx->width, ctx->height);
+	}
+
+	if (mdss_mdp_writeback_format_setup(ctx))
+		return -EINVAL;
+
+	return 0;
+}
+
 static int mdss_mdp_writeback_stop(struct mdss_mdp_ctl *ctl)
 {
 	struct mdss_mdp_writeback_ctx *ctx;
@@ -208,6 +238,27 @@
 	return 0;
 }
 
+static int mdss_mdp_writeback_prepare(struct mdss_mdp_ctl *ctl, void *arg)
+{
+	struct mdss_mdp_writeback_ctx *ctx;
+	ctx = (struct mdss_mdp_writeback_ctx *) ctl->priv_data;
+	if (!ctx)
+		return -ENODEV;
+
+	if (ctx->type == MDSS_MDP_WRITEBACK_TYPE_ROTATOR) {
+		struct mdss_mdp_rotator_session *rot;
+		rot = (struct mdss_mdp_rotator_session *) arg;
+		if (!rot) {
+			pr_err("unable to retrieve rot session ctl=%d\n",
+			       ctl->num);
+			return -ENODEV;
+		}
+		mdss_mdp_writeback_rot_setup(ctl, ctx, rot);
+	}
+
+	return 0;
+}
+
 static void mdss_mdp_writeback_intr_done(void *arg)
 {
 	struct mdss_mdp_writeback_ctx *ctx;
@@ -229,6 +280,7 @@
 static int mdss_mdp_writeback_display(struct mdss_mdp_ctl *ctl, void *arg)
 {
 	struct mdss_mdp_writeback_ctx *ctx;
+	struct mdss_mdp_rotator_session *rot = NULL;
 	struct mdss_mdp_data *wb_data;
 	u32 flush_bits;
 	int ret;
@@ -237,7 +289,17 @@
 	if (!ctx)
 		return -ENODEV;
 
-	wb_data = &ctx->wb_data;
+	if (ctx->type == MDSS_MDP_WRITEBACK_TYPE_ROTATOR) {
+		rot = (struct mdss_mdp_rotator_session *) arg;
+		if (!rot) {
+			pr_err("unable to retrieve rot session ctl=%d\n",
+			       ctl->num);
+			return -ENODEV;
+		}
+		wb_data = rot->dst_data;
+	} else {
+		wb_data = &ctx->wb_data;
+	}
 
 	ret = mdss_mdp_writeback_addr_setup(ctx, wb_data);
 	if (ret) {
@@ -257,8 +319,16 @@
 	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
 	wmb();
 
-	pr_debug("writeback kickoff wb_num=%d\n", ctx->wb_num);
-	wait_for_completion_interruptible(&ctx->comp);
+	if (rot) {
+		pr_debug("rotator kickoff wb_num=%d\n", ctx->wb_num);
+		mutex_lock(&rot->lock);
+		rot->comp = &ctx->comp;
+		rot->busy = 1;
+		mutex_unlock(&rot->lock);
+	} else {
+		pr_debug("writeback kickoff wb_num=%d\n", ctx->wb_num);
+		wait_for_completion_interruptible(&ctx->comp);
+	}
 
 	return 0;
 }
@@ -290,6 +360,8 @@
 
 	if (ctx->type == MDSS_MDP_WRITEBACK_TYPE_WFD)
 		ret = mdss_mdp_writeback_wfd_setup(ctl, ctx);
+	else if (ctx->type == MDSS_MDP_WRITEBACK_TYPE_ROTATOR)
+		ctl->prepare_fnc = mdss_mdp_writeback_prepare;
 	else /* line mode not supported */
 		return -ENOSYS;
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index bd4a974..f1b158d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -21,6 +21,7 @@
 
 #include "mdss_fb.h"
 #include "mdss_mdp.h"
+#include "mdss_mdp_rotator.h"
 
 #define CHECK_BOUNDS(offset, size, max_size) \
 	(((size) > (max_size)) || ((offset) > ((max_size) - (size))))
@@ -85,28 +86,30 @@
 		dst_h = req->dst_rect.h;
 	}
 
-	if ((req->src_rect.w * MAX_UPSCALE_RATIO) < dst_w) {
-		pr_err("too much upscaling Width %d->%d\n",
-		       req->src_rect.w, req->dst_rect.w);
-		return -EINVAL;
-	}
+	if (!(req->flags & MDSS_MDP_ROT_ONLY)) {
+		if ((req->src_rect.w * MAX_UPSCALE_RATIO) < dst_w) {
+			pr_err("too much upscaling Width %d->%d\n",
+			       req->src_rect.w, req->dst_rect.w);
+			return -EINVAL;
+		}
 
-	if ((req->src_rect.h * MAX_UPSCALE_RATIO) < dst_h) {
-		pr_err("too much upscaling. Height %d->%d\n",
-		       req->src_rect.h, req->dst_rect.h);
-		return -EINVAL;
-	}
+		if ((req->src_rect.h * MAX_UPSCALE_RATIO) < dst_h) {
+			pr_err("too much upscaling. Height %d->%d\n",
+			       req->src_rect.h, req->dst_rect.h);
+			return -EINVAL;
+		}
 
-	if (req->src_rect.w > (dst_w * MAX_DOWNSCALE_RATIO)) {
-		pr_err("too much downscaling. Width %d->%d\n",
-		       req->src_rect.w, req->dst_rect.w);
-		return -EINVAL;
-	}
+		if (req->src_rect.w > (dst_w * MAX_DOWNSCALE_RATIO)) {
+			pr_err("too much downscaling. Width %d->%d\n",
+			       req->src_rect.w, req->dst_rect.w);
+			return -EINVAL;
+		}
 
-	if (req->src_rect.h > (dst_h * MAX_DOWNSCALE_RATIO)) {
-		pr_err("too much downscaling. Height %d->%d\n",
-		       req->src_rect.h, req->dst_rect.h);
-		return -EINVAL;
+		if (req->src_rect.h > (dst_h * MAX_DOWNSCALE_RATIO)) {
+			pr_err("too much downscaling. Height %d->%d\n",
+			       req->src_rect.h, req->dst_rect.h);
+			return -EINVAL;
+		}
 	}
 
 	if (fmt->is_yuv) {
@@ -141,6 +144,61 @@
 	return 0;
 }
 
+static int mdss_mdp_overlay_rotator_setup(struct msm_fb_data_type *mfd,
+					  struct mdp_overlay *req)
+{
+	struct mdss_mdp_rotator_session *rot;
+	struct mdss_mdp_format_params *fmt;
+	int ret = 0;
+
+	pr_debug("rot ctl=%u req id=%x\n", mfd->ctl->num, req->id);
+
+	fmt = mdss_mdp_get_format_params(req->src.format);
+	if (!fmt) {
+		pr_err("invalid rot format %d\n", req->src.format);
+		return -EINVAL;
+	}
+
+	ret = mdss_mdp_overlay_req_check(mfd, req, fmt);
+	if (ret)
+		return ret;
+
+	if (req->id == MSMFB_NEW_REQUEST) {
+		rot = mdss_mdp_rotator_session_alloc();
+
+		if (!rot) {
+			pr_err("unable to allocate rotator session\n");
+			return -ENOMEM;
+		}
+	} else if (req->id & MDSS_MDP_ROT_SESSION_MASK) {
+		rot = mdss_mdp_rotator_session_get(req->id);
+
+		if (!rot) {
+			pr_err("rotator session=%x not found\n", req->id);
+			return -ENODEV;
+		}
+	} else {
+		pr_err("invalid rotator session id=%x\n", req->id);
+		return -EINVAL;
+	}
+
+	rot->rotations = req->flags & (MDP_ROT_90 | MDP_FLIP_LR | MDP_FLIP_UD);
+
+	rot->format = fmt->format;
+	rot->img_width = req->src.width;
+	rot->img_height = req->src.height;
+	rot->src_rect.x = req->src_rect.x;
+	rot->src_rect.y = req->src_rect.y;
+	rot->src_rect.w = req->src_rect.w;
+	rot->src_rect.h = req->src_rect.h;
+
+	rot->params_changed++;
+
+	req->id = rot->session_id;
+
+	return ret;
+}
+
 static int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd,
 				       struct mdp_overlay *req,
 				       struct mdss_mdp_pipe **ppipe)
@@ -256,14 +314,19 @@
 				struct mdp_overlay *req)
 {
 	int ret;
-	struct mdss_mdp_pipe *pipe;
 
-	/* userspace zorder start with stage 0 */
-	req->z_order += MDSS_MDP_STAGE_0;
+	if (req->flags & MDSS_MDP_ROT_ONLY) {
+		ret = mdss_mdp_overlay_rotator_setup(mfd, req);
+	} else {
+		struct mdss_mdp_pipe *pipe;
 
-	ret = mdss_mdp_overlay_pipe_setup(mfd, req, &pipe);
+		/* userspace zorder start with stage 0 */
+		req->z_order += MDSS_MDP_STAGE_0;
 
-	req->z_order -= MDSS_MDP_STAGE_0;
+		ret = mdss_mdp_overlay_pipe_setup(mfd, req, &pipe);
+
+		req->z_order -= MDSS_MDP_STAGE_0;
+	}
 
 	return ret;
 }
@@ -280,6 +343,19 @@
 
 	pr_debug("unset ndx=%x\n", ndx);
 
+	if (ndx & MDSS_MDP_ROT_SESSION_MASK) {
+		struct mdss_mdp_rotator_session *rot;
+		rot = mdss_mdp_rotator_session_get(ndx);
+		if (rot) {
+			mdss_mdp_rotator_finish(rot);
+		} else {
+			pr_warn("unknown session id=%x\n", ndx);
+			ret = -ENODEV;
+		}
+
+		return ret;
+	}
+
 	for (i = 0; unset_ndx != ndx && i < MDSS_MDP_MAX_SSPP; i++) {
 		pipe_ndx = BIT(i);
 		if (pipe_ndx & ndx) {
@@ -319,6 +395,28 @@
 	return ret;
 }
 
+static int mdss_mdp_overlay_rotate(struct msmfb_overlay_data *req,
+				   struct mdss_mdp_data *src_data,
+				   struct mdss_mdp_data *dst_data)
+{
+	struct mdss_mdp_rotator_session *rot;
+	int ret;
+
+	rot = mdss_mdp_rotator_session_get(req->id);
+	if (!rot) {
+		pr_err("invalid session id=%x\n", req->id);
+		return -ENODEV;
+	}
+
+	ret = mdss_mdp_rotator_queue(rot, src_data, dst_data);
+	if (ret) {
+		pr_err("rotator queue error session id=%x\n", req->id);
+		return ret;
+	}
+
+	return 0;
+}
+
 static int mdss_mdp_overlay_queue(struct msmfb_overlay_data *req,
 				  struct mdss_mdp_data *src_data)
 {
@@ -364,7 +462,23 @@
 	}
 	src_data.num_planes = 1;
 
-	ret = mdss_mdp_overlay_queue(req, &src_data);
+	if (req->id & MDSS_MDP_ROT_SESSION_MASK) {
+		struct mdss_mdp_data dst_data;
+		memset(&dst_data, 0, sizeof(dst_data));
+
+		mdss_mdp_get_img(mfd->iclient, &req->dst_data, &dst_data.p[0]);
+		if (dst_data.p[0].len == 0) {
+			pr_err("dst data pmem error\n");
+			return -ENOMEM;
+		}
+		dst_data.num_planes = 1;
+
+		ret = mdss_mdp_overlay_rotate(req, &src_data, &dst_data);
+
+		mdss_mdp_put_img(&dst_data.p[0]);
+	} else {
+		ret = mdss_mdp_overlay_queue(req, &src_data);
+	}
 
 	mdss_mdp_put_img(&src_data.p[0]);
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index b52cff5..52f4324 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -581,6 +581,11 @@
 			  (1 << 18) |	/* SRC_DATA=YCBCR */
 			  (1 << 17);	/* CSC_1_EN */
 
+	/* only need to program once */
+	if (pipe->play_cnt == 0) {
+		mdss_mdp_csc_setup(MDSS_MDP_BLOCK_SSPP, pipe->num, 1,
+				   MDSS_MDP_CSC_YUV2RGB);
+	}
 	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_VIG_OP_MODE, opmode);
 
 	return 0;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
new file mode 100644
index 0000000..db840a8
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -0,0 +1,175 @@
+/* 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.
+ *
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include "mdss_mdp.h"
+
+struct mdp_csc_cfg mdp_csc_convert[MDSS_MDP_MAX_CSC] = {
+	[MDSS_MDP_CSC_RGB2RGB] = {
+		0,
+		{
+			0x0200, 0x0000, 0x0000,
+			0x0000, 0x0200, 0x0000,
+			0x0000, 0x0000, 0x0200,
+		},
+		{ 0x0, 0x0, 0x0,},
+		{ 0x0, 0x0, 0x0,},
+		{ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
+		{ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
+	},
+	[MDSS_MDP_CSC_YUV2RGB] = {
+		0,
+		{
+			0x0254, 0x0000, 0x0331,
+			0x0254, 0xff37, 0xfe60,
+			0x0254, 0x0409, 0x0000,
+		},
+		{ 0xfff0, 0xff80, 0xff80,},
+		{ 0x0, 0x0, 0x0,},
+		{ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
+		{ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
+	},
+	[MDSS_MDP_CSC_RGB2YUV] = {
+		0,
+		{
+			0x0083, 0x0102, 0x0032,
+			0x1fb5, 0x1f6c, 0x00e1,
+			0x00e1, 0x1f45, 0x1fdc
+		},
+		{ 0x0, 0x0, 0x0,},
+		{ 0x0010, 0x0080, 0x0080,},
+		{ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
+		{ 0x0010, 0x00eb, 0x0010, 0x00f0, 0x0010, 0x00f0,},
+	},
+	[MDSS_MDP_CSC_YUV2YUV] = {
+		0,
+		{
+			0x0200, 0x0000, 0x0000,
+			0x0000, 0x0200, 0x0000,
+			0x0000, 0x0000, 0x0200,
+		},
+		{ 0x0, 0x0, 0x0,},
+		{ 0x0, 0x0, 0x0,},
+		{ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
+		{ 0x0, 0xff, 0x0, 0xff, 0x0, 0xff,},
+	},
+};
+
+#define CSC_MV_OFF	0x0
+#define CSC_BV_OFF	0x2C
+#define CSC_LV_OFF	0x14
+#define CSC_POST_OFF	0xC
+
+static int mdss_mdp_csc_setup_data(u32 block, u32 blk_idx, u32 tbl_idx,
+				   struct mdp_csc_cfg *data)
+{
+	int i, ret = 0;
+	u32 *off, base, val = 0;
+
+	if (data == NULL) {
+		pr_err("no csc matrix specified\n");
+		return -EINVAL;
+	}
+
+	switch (block) {
+	case MDSS_MDP_BLOCK_SSPP:
+		if (blk_idx < MDSS_MDP_SSPP_RGB0) {
+			base = MDSS_MDP_REG_SSPP_OFFSET(blk_idx);
+			if (tbl_idx == 1)
+				base += MDSS_MDP_REG_VIG_CSC_1_BASE;
+			else
+				base += MDSS_MDP_REG_VIG_CSC_0_BASE;
+		} else {
+			ret = -EINVAL;
+		}
+		break;
+	case MDSS_MDP_BLOCK_WB:
+		if (blk_idx < MDSS_MDP_MAX_WRITEBACK) {
+			base = MDSS_MDP_REG_WB_OFFSET(blk_idx) +
+			       MDSS_MDP_REG_WB_CSC_BASE;
+		} else {
+			ret = -EINVAL;
+		}
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	if (ret != 0) {
+		pr_err("unsupported block id for csc\n");
+		return ret;
+	}
+
+	off = (u32 *) (base + CSC_MV_OFF);
+	for (i = 0; i < 9; i++) {
+		if (i & 0x1) {
+			val |= data->csc_mv[i] << 16;
+			MDSS_MDP_REG_WRITE(off, val);
+			off++;
+		} else {
+			val = data->csc_mv[i];
+		}
+	}
+	MDSS_MDP_REG_WRITE(off, val); /* COEFF_33 */
+
+	off = (u32 *) (base + CSC_BV_OFF);
+	for (i = 0; i < 3; i++) {
+		MDSS_MDP_REG_WRITE(off, data->csc_pre_bv[i]);
+		MDSS_MDP_REG_WRITE((u32 *)(((u32)off) + CSC_POST_OFF),
+				   data->csc_post_bv[i]);
+		off++;
+	}
+
+	off = (u32 *) (base + CSC_LV_OFF);
+	for (i = 0; i < 6; i += 2) {
+		val = (data->csc_pre_lv[i] << 8) | data->csc_pre_lv[i+1];
+		MDSS_MDP_REG_WRITE(off, val);
+
+		val = (data->csc_post_lv[i] << 8) | data->csc_post_lv[i+1];
+		MDSS_MDP_REG_WRITE((u32 *)(((u32)off) + CSC_POST_OFF), val);
+		off++;
+	}
+
+	return ret;
+}
+
+int mdss_mdp_csc_setup(u32 block, u32 blk_idx, u32 tbl_idx, u32 csc_type)
+{
+	struct mdp_csc_cfg *data;
+
+	if (csc_type >= MDSS_MDP_MAX_CSC) {
+		pr_err("invalid csc matrix index %d\n", csc_type);
+		return -ERANGE;
+	}
+
+	pr_debug("csc type=%d blk=%d idx=%d tbl=%d\n", csc_type,
+		 block, blk_idx, tbl_idx);
+
+	data = &mdp_csc_convert[csc_type];
+	return mdss_mdp_csc_setup_data(block, blk_idx, tbl_idx, data);
+}
+
+int mdss_mdp_dspp_setup(struct mdss_mdp_ctl *ctl, struct mdss_mdp_mixer *mixer)
+{
+	int dspp_num;
+
+	if (!ctl || !mixer)
+		return -EINVAL;
+
+	dspp_num = mixer->num;
+
+	ctl->flush_bits |= BIT(13 + dspp_num);	/* DSPP */
+
+	return 0;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
new file mode 100644
index 0000000..628b7f5
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -0,0 +1,228 @@
+/* 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.
+ *
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+
+#include "mdss_mdp.h"
+#include "mdss_mdp_rotator.h"
+
+#define MAX_ROTATOR_SESSIONS 8
+
+static DEFINE_MUTEX(rotator_lock);
+static struct mdss_mdp_rotator_session rotator_session[MAX_ROTATOR_SESSIONS];
+static LIST_HEAD(rotator_queue);
+
+struct mdss_mdp_rotator_session *mdss_mdp_rotator_session_alloc(void)
+{
+	struct mdss_mdp_rotator_session *rot;
+	int i;
+
+	mutex_lock(&rotator_lock);
+	for (i = 0; i < MAX_ROTATOR_SESSIONS; i++) {
+		rot = &rotator_session[i];
+		if (rot->ref_cnt == 0) {
+			rot->ref_cnt++;
+			rot->session_id = i | MDSS_MDP_ROT_SESSION_MASK;
+			mutex_init(&rot->lock);
+			break;
+		}
+	}
+	mutex_unlock(&rotator_lock);
+	if (i == MAX_ROTATOR_SESSIONS) {
+		pr_err("max rotator sessions reached\n");
+		return NULL;
+	}
+
+	return rot;
+}
+
+struct mdss_mdp_rotator_session *mdss_mdp_rotator_session_get(u32 session_id)
+{
+	struct mdss_mdp_rotator_session *rot;
+	u32 ndx;
+
+	ndx = session_id & ~MDSS_MDP_ROT_SESSION_MASK;
+	if (ndx < MAX_ROTATOR_SESSIONS) {
+		rot = &rotator_session[ndx];
+		if (rot->ref_cnt && rot->session_id == session_id)
+			return rot;
+	}
+	return NULL;
+}
+
+static int mdss_mdp_rotator_busy_wait(struct mdss_mdp_rotator_session *rot)
+{
+	mutex_lock(&rot->lock);
+	if (rot->busy) {
+		pr_debug("waiting for rot=%d to complete\n", rot->pipe->num);
+		wait_for_completion_interruptible(rot->comp);
+		rot->busy = 0;
+	}
+	mutex_unlock(&rot->lock);
+
+	return 0;
+}
+
+static struct mdss_mdp_pipe *mdss_mdp_rotator_pipe_alloc(void)
+{
+	struct mdss_mdp_mixer *mixer;
+	struct mdss_mdp_pipe *pipe = NULL;
+	int pnum;
+
+	mixer = mdss_mdp_wb_mixer_alloc(1);
+	if (!mixer)
+		return NULL;
+
+	switch (mixer->num) {
+	case MDSS_MDP_LAYERMIXER3:
+		pnum = MDSS_MDP_SSPP_DMA0;
+		break;
+	case MDSS_MDP_LAYERMIXER4:
+		pnum = MDSS_MDP_SSPP_DMA1;
+		break;
+	default:
+		goto done;
+	}
+
+	pipe = mdss_mdp_pipe_alloc_pnum(pnum);
+
+	if (pipe)
+		pipe->mixer = mixer;
+done:
+	if (!pipe)
+		mdss_mdp_wb_mixer_destroy(mixer);
+
+	return pipe;
+}
+
+static int mdss_mdp_rotator_pipe_dequeue(struct mdss_mdp_rotator_session *rot)
+{
+	if (rot->pipe) {
+		pr_debug("reusing existing session=%d\n", rot->pipe->num);
+		mdss_mdp_rotator_busy_wait(rot);
+		list_move_tail(&rot->head, &rotator_queue);
+	} else {
+		struct mdss_mdp_rotator_session *tmp;
+
+		rot->params_changed++;
+		rot->pipe = mdss_mdp_rotator_pipe_alloc();
+		if (rot->pipe) {
+			pr_debug("use new rotator pipe=%d\n", rot->pipe->num);
+
+			rot->pipe->mixer_stage = MDSS_MDP_STAGE_UNUSED;
+			list_add_tail(&rot->head, &rotator_queue);
+		} else if (!list_empty(&rotator_queue)) {
+			tmp = list_first_entry(&rotator_queue,
+					       struct mdss_mdp_rotator_session,
+					       head);
+
+			pr_debug("wait for rotator pipe=%d\n", tmp->pipe->num);
+			mdss_mdp_rotator_busy_wait(tmp);
+			rot->pipe = tmp->pipe;
+			tmp->pipe = NULL;
+
+			list_del(&tmp->head);
+			list_add_tail(&rot->head, &rotator_queue);
+		} else {
+			pr_err("no available rotator pipes\n");
+			return -EBUSY;
+		}
+	}
+
+	return 0;
+}
+
+int mdss_mdp_rotator_queue(struct mdss_mdp_rotator_session *rot,
+			   struct mdss_mdp_data *src_data,
+			   struct mdss_mdp_data *dst_data)
+{
+	struct mdss_mdp_pipe *rot_pipe;
+	struct mdss_mdp_ctl *ctl;
+	int ret;
+
+	if (!rot)
+		return -ENODEV;
+
+	mutex_lock(&rotator_lock);
+	ret = mdss_mdp_rotator_pipe_dequeue(rot);
+	if (ret) {
+		pr_err("unable to acquire rotator\n");
+		goto done;
+	}
+
+	rot_pipe = rot->pipe;
+
+	pr_debug("queue rotator pnum=%d\n", rot_pipe->num);
+
+	ctl = rot_pipe->mixer->ctl;
+
+	if (rot->params_changed) {
+		rot->params_changed = 0;
+		rot_pipe->flags = rot->rotations;
+		rot_pipe->src_fmt = mdss_mdp_get_format_params(rot->format);
+		rot_pipe->img_width = rot->img_width;
+		rot_pipe->img_height = rot->img_height;
+		rot_pipe->src = rot->src_rect;
+		rot_pipe->bwc_mode = rot->bwc_mode;
+		rot_pipe->params_changed++;
+	}
+
+	rot->dst_data = dst_data;
+
+	ret = mdss_mdp_pipe_queue_data(rot->pipe, src_data);
+	if (ret) {
+		pr_err("unable to queue rot data\n");
+		goto done;
+	}
+
+	ret = mdss_mdp_display_commit(ctl, rot);
+
+done:
+	mutex_unlock(&rotator_lock);
+
+	if (!rot->no_wait)
+		mdss_mdp_rotator_busy_wait(rot);
+
+	return ret;
+}
+
+int mdss_mdp_rotator_finish(struct mdss_mdp_rotator_session *rot)
+{
+	struct mdss_mdp_pipe *rot_pipe;
+
+	if (!rot)
+		return -ENODEV;
+
+	pr_debug("finish rot id=%x\n", rot->session_id);
+
+	mutex_lock(&rotator_lock);
+	rot_pipe = rot->pipe;
+	if (rot_pipe) {
+		mdss_mdp_rotator_busy_wait(rot);
+		list_del(&rot->head);
+	}
+	memset(rot, 0, sizeof(*rot));
+	if (rot_pipe) {
+		struct mdss_mdp_mixer *mixer = rot_pipe->mixer;
+		mdss_mdp_pipe_destroy(rot_pipe);
+		mdss_mdp_wb_mixer_destroy(mixer);
+	}
+	mutex_unlock(&rotator_lock);
+
+	return 0;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.h b/drivers/video/msm/mdss/mdss_mdp_rotator.h
new file mode 100644
index 0000000..8940c46
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.h
@@ -0,0 +1,55 @@
+/* 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 MDSS_MDP_ROTATOR_H
+#define MDSS_MDP_ROTATOR_H
+
+#include <linux/types.h>
+
+#include "mdss_mdp.h"
+
+#define MDSS_MDP_ROT_SESSION_MASK	0x80000000
+
+struct mdss_mdp_rotator_session {
+	u32 session_id;
+	u32 ref_cnt;
+	u32 params_changed;
+
+	u32 format;
+	u32 rotations;
+
+	u16 img_width;
+	u16 img_height;
+	struct mdss_mdp_img_rect src_rect;
+
+	u32 bwc_mode;
+	struct mdss_mdp_pipe *pipe;
+	struct mdss_mdp_data *dst_data;
+
+	struct mutex lock;
+	u8 busy;
+	u8 no_wait;
+	struct completion *comp;
+
+	struct list_head head;
+};
+
+struct mdss_mdp_rotator_session *mdss_mdp_rotator_session_alloc(void);
+struct mdss_mdp_rotator_session *mdss_mdp_rotator_session_get(u32 session_id);
+
+int mdss_mdp_rotator_queue(struct mdss_mdp_rotator_session *rot,
+			   struct mdss_mdp_data *src_data,
+			   struct mdss_mdp_data *dst_data);
+int mdss_mdp_rotator_finish(struct mdss_mdp_rotator_session *rot);
+int mdss_mdp_rotator_ctl_busy_wait(struct mdss_mdp_ctl *ctl);
+
+#endif /* MDSS_MDP_ROTATOR_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index 25c9ac4..2e86806 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -10,7 +10,6 @@
  * GNU General Public License for more details.
  *
  */
-
 #define pr_fmt(fmt)	"%s: " fmt, __func__
 
 #include <linux/android_pmem.h>
@@ -53,7 +52,7 @@
 	int index = -1;
 	switch (intr_type) {
 	case MDSS_MDP_IRQ_INTF_VSYNC:
-		index = MDP_INTR_VSYNC_INTF_0 + intf_num;
+		index = MDP_INTR_VSYNC_INTF_0 + (intf_num - MDSS_MDP_INTF0);
 		break;
 	case MDSS_MDP_IRQ_PING_PONG_COMP:
 		index = MDP_INTR_PING_PONG_0 + intf_num;
@@ -116,11 +115,12 @@
 
 
 	isr = MDSS_MDP_REG_READ(MDSS_MDP_REG_INTR_STATUS);
+
+	pr_debug("isr=%x\n", isr);
+
 	if (isr == 0)
 		goto done;
 
-	pr_devel("isr=%x\n", isr);
-
 	mask = MDSS_MDP_REG_READ(MDSS_MDP_REG_INTR_EN);
 	MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_CLEAR, isr);
 
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 81a6e50..18ee3e6 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -1326,7 +1326,7 @@
 	fbi->fix.smem_start = (unsigned long)fbram_phys;
 
 	msm_iommu_map_contig_buffer(fbi->fix.smem_start,
-					DISPLAY_DOMAIN,
+					DISPLAY_READ_DOMAIN,
 					GEN_POOL,
 					fbi->fix.smem_len,
 					SZ_4K,
@@ -1334,7 +1334,7 @@
 					&(mfd->display_iova));
 
 	msm_iommu_map_contig_buffer(fbi->fix.smem_start,
-					ROTATOR_DOMAIN,
+					ROTATOR_SRC_DOMAIN,
 					GEN_POOL,
 					fbi->fix.smem_len,
 					SZ_4K,
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
index 45430e8..a5171f0 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
@@ -590,6 +590,12 @@
 			__func__, dev_ctxt);
 		return false;
 	}
+	if (dev_ctxt->turbo_mode_set &&
+			(req_perf_lvl < RESTRK_1080P_TURBO_PERF_LEVEL)) {
+		VCDRES_MSG_MED("%s(): TURBO MODE!!\n", __func__);
+		return true;
+	}
+
 	VCDRES_MSG_LOW("%s(), req_perf_lvl = %d", __func__, req_perf_lvl);
 
 	if (resource_context.vidc_platform_data->disable_turbo
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
index 2b534f1..96e729d 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
@@ -759,6 +759,7 @@
 	client = dev_ctxt->cctxt_list_head;
 	dev_ctxt->cctxt_list_head = cctxt;
 	cctxt->next = client;
+	dev_ctxt->turbo_mode_set = 0;
 
 	*clnt_cctxt = cctxt;
 
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c
index 80e03ba..33b2300 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c
@@ -312,6 +312,7 @@
 		return false;
 	}
 	dev_ctxt->curr_perf_lvl = RESTRK_1080P_TURBO_PERF_LEVEL;
+	vcd_update_decoder_perf_level(dev_ctxt, RESTRK_1080P_TURBO_PERF_LEVEL);
 #endif
 	return rc;
 }
diff --git a/include/linux/input/mpu3050.h b/include/linux/input/mpu3050.h
new file mode 100644
index 0000000..6006abb
--- /dev/null
+++ b/include/linux/input/mpu3050.h
@@ -0,0 +1,31 @@
+/*
+ * 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 __MPU3050_H__
+#define __MPU3050_H__
+
+struct mpu3050_gyro_platform_data {
+	int poll_interval;
+	int min_interval;
+
+	int (*init)(void);
+	void (*exit)(void);
+	int (*power_on)(void);
+	int (*power_off)(void);
+
+	int gpio_int;
+	int gpio_fsync;
+};
+
+#endif /* __MPU3050_H__ */
diff --git a/include/linux/ion.h b/include/linux/ion.h
index d9443ff..fca5517 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -86,6 +86,14 @@
 	FIXED_HIGH,
 };
 
+enum cp_mem_usage {
+	VIDEO_BITSTREAM = 0x1,
+	VIDEO_PIXEL = 0x2,
+	VIDEO_NONPIXEL = 0x3,
+	MAX_USAGE = 0x4,
+	UNKNOWN = 0x7FFFFFFF,
+};
+
 /**
  * Flag to use when allocating to indicate that a heap is secure.
  */
@@ -482,22 +490,28 @@
  *
  * @client - a client that has allocated from the heap heap_id
  * @heap_id - heap id to secure.
+ * @version - version of content protection
+ * @data - extra data needed for protection
  *
  * Secure a heap
  * Returns 0 on success
  */
-int ion_secure_heap(struct ion_device *dev, int heap_id);
+int ion_secure_heap(struct ion_device *dev, int heap_id, int version,
+			void *data);
 
 /**
  * ion_unsecure_heap - un-secure a heap
  *
  * @client - a client that has allocated from the heap heap_id
  * @heap_id - heap id to un-secure.
+ * @version - version of content protection
+ * @data - extra data needed for protection
  *
  * Un-secure a heap
  * Returns 0 on success
  */
-int ion_unsecure_heap(struct ion_device *dev, int heap_id);
+int ion_unsecure_heap(struct ion_device *dev, int heap_id, int version,
+			void *data);
 
 /**
  * msm_ion_secure_heap - secure a heap. Wrapper around ion_secure_heap.
@@ -520,6 +534,30 @@
 int msm_ion_unsecure_heap(int heap_id);
 
 /**
+ * msm_ion_secure_heap_2_0 - secure a heap using 2.0 APIs
+ *  Wrapper around ion_secure_heap.
+ *
+ * @heap_id - heap id to secure.
+ * @usage - usage hint to TZ
+ *
+ * Secure a heap
+ * Returns 0 on success
+ */
+int msm_ion_secure_heap_2_0(int heap_id, enum cp_mem_usage usage);
+
+/**
+ * msm_ion_unsecure_heap - unsecure a heap secured with 3.0 APIs.
+ * Wrapper around ion_unsecure_heap.
+ *
+ * @heap_id - heap id to secure.
+ * @usage - usage hint to TZ
+ *
+ * Un-secure a heap
+ * Returns 0 on success
+ */
+int msm_ion_unsecure_heap_2_0(int heap_id, enum cp_mem_usage usage);
+
+/**
  * msm_ion_do_cache_op - do cache operations.
  *
  * @client - pointer to ION client.
@@ -627,13 +665,15 @@
 	return;
 }
 
-static inline int ion_secure_heap(struct ion_device *dev, int heap_id)
+static inline int ion_secure_heap(struct ion_device *dev, int heap_id,
+					int version, void *data)
 {
 	return -ENODEV;
 
 }
 
-static inline int ion_unsecure_heap(struct ion_device *dev, int heap_id)
+static inline int ion_unsecure_heap(struct ion_device *dev, int heap_id,
+					int version, void *data)
 {
 	return -ENODEV;
 }
@@ -649,6 +689,17 @@
 	return -ENODEV;
 }
 
+static inline int msm_ion_secure_heap_2_0(int heap_id, enum cp_mem_usage usage)
+{
+	return -ENODEV;
+}
+
+static inline int msm_ion_unsecure_heap_2_0(int heap_id,
+					enum cp_mem_usage usage)
+{
+	return -ENODEV;
+}
+
 static inline int msm_ion_do_cache_op(struct ion_client *client,
 			struct ion_handle *handle, void *vaddr,
 			unsigned long len, unsigned int cmd)
diff --git a/include/linux/mfd/pm8xxx/pm8038.h b/include/linux/mfd/pm8xxx/pm8038.h
index 90557b9..682abc8 100644
--- a/include/linux/mfd/pm8xxx/pm8038.h
+++ b/include/linux/mfd/pm8xxx/pm8038.h
@@ -33,6 +33,7 @@
 #include <linux/leds-pm8xxx.h>
 #include <linux/mfd/pm8xxx/ccadc.h>
 #include <linux/mfd/pm8xxx/spk.h>
+#include <linux/mfd/pm8xxx/tm.h>
 
 #define PM8038_CORE_DEV_NAME "pm8038-core"
 
@@ -64,6 +65,9 @@
 
 #define PM8038_RESOUT_IRQ		PM8038_IRQ_BLOCK_BIT(6, 4)
 
+#define PM8038_OVERTEMP_IRQ		PM8038_IRQ_BLOCK_BIT(4, 2)
+#define PM8038_TEMPSTAT_IRQ		PM8038_IRQ_BLOCK_BIT(6, 7)
+
 struct pm8038_platform_data {
 	int					irq_base;
 	struct pm8xxx_gpio_platform_data	*gpio_pdata;
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 8b6351f..19728fe 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -120,6 +120,7 @@
 	NUM_HSIC_PARAM,
 };
 
+#define MDSS_MDP_ROT_ONLY		0x80
 #define MDSS_MDP_RIGHT_MIXER		0x100
 
 /* mdp_blit_req flag values */
@@ -249,6 +250,7 @@
 	uint32_t version_key;
 	struct msmfb_data plane1_data;
 	struct msmfb_data plane2_data;
+	struct msmfb_data dst_data;
 };
 
 struct msmfb_img {
diff --git a/include/linux/msm_thermal.h b/include/linux/msm_thermal.h
new file mode 100644
index 0000000..fe9be89
--- /dev/null
+++ b/include/linux/msm_thermal.h
@@ -0,0 +1,34 @@
+/*
+ * 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 __MSM_THERMAL_H
+#define __MSM_THERMAL_H
+
+struct msm_thermal_data {
+	uint32_t sensor_id;
+	uint32_t poll_ms;
+	uint32_t limit_temp;
+	uint32_t temp_hysteresis;
+	uint32_t limit_freq;
+};
+
+#ifdef CONFIG_THERMAL_MONITOR
+extern int msm_thermal_init(struct msm_thermal_data *pdata);
+#else
+static inline int msm_thermal_init(struct msm_thermal_data *pdata)
+{
+	return -ENOSYS;
+}
+#endif
+
+#endif /*__MSM_THERMAL_H*/
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 22d4997..9da1999 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -24,6 +24,7 @@
 #include <linux/usb/otg.h>
 #include <linux/wakelock.h>
 #include <linux/pm_qos.h>
+#include <linux/hrtimer.h>
 
 /*
  * The following are bit fields describing the usb_request.udc_priv word.
@@ -191,6 +192,8 @@
  * @enable_lpm_on_suspend: Enable the USB core to go into Low
  *              Power Mode, when USB bus is suspended but cable
  *              is connected.
+ * @core_clk_always_on_workaround: Don't disable core_clk when
+ *              USB enters LPM.
  * @bus_scale_table: parameters for bus bandwidth requirements
  */
 struct msm_otg_platform_data {
@@ -207,6 +210,7 @@
 	bool disable_reset_on_disconnect;
 	bool enable_dcd;
 	bool enable_lpm_on_dev_suspend;
+	bool core_clk_always_on_workaround;
 	struct msm_bus_scale_pdata *bus_scale_table;
 };
 
@@ -365,8 +369,14 @@
 	unsigned int dock_connect_irq;
 };
 
+/**
+ * struct msm_hsic_peripheral_platform_data: HSIC peripheral
+ * platform data.
+ * @core_clk_always_on_workaround: Don't disable core_clk when
+ *                                 HSIC enters LPM.
+ */
 struct msm_hsic_peripheral_platform_data {
-	bool keep_core_clk_on_suspend_workaround;
+	bool core_clk_always_on_workaround;
 };
 
 struct usb_bam_pipe_connect {
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index f18fafd..63ebdea 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -2295,11 +2295,11 @@
 #define V4L2_EVENT_FRAME_SYNC			4
 #define V4L2_EVENT_PRIVATE_START		0x08000000
 
-#define V4L2_EVENT_MSM_VIDC_START	{ V4L2_EVENT_PRIVATE_START + 0x00001000}
-#define V4L2_EVENT_MSM_VIDC_FLUSH_DONE	{V4L2_EVENT_PRIVATE_START + 1}
+#define V4L2_EVENT_MSM_VIDC_START	(V4L2_EVENT_PRIVATE_START + 0x00001000)
+#define V4L2_EVENT_MSM_VIDC_FLUSH_DONE	(V4L2_EVENT_PRIVATE_START + 1)
 #define V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED	\
-		{V4L2_EVENT_PRIVATE_START + 2}
-#define V4L2_EVENT_MSM_VIDC_CLOSE_DONE	{V4L2_EVENT_PRIVATE_START + 3}
+		(V4L2_EVENT_PRIVATE_START + 2)
+#define V4L2_EVENT_MSM_VIDC_CLOSE_DONE	(V4L2_EVENT_PRIVATE_START + 3)
 
 /* Payload for V4L2_EVENT_VSYNC */
 struct v4l2_event_vsync {
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 0c9b274..320ac8b 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -1594,4 +1594,66 @@
 	uint32_t len;
 };
 
+enum msm_camss_irq_idx {
+	CAMERA_SS_IRQ_0,
+	CAMERA_SS_IRQ_1,
+	CAMERA_SS_IRQ_2,
+	CAMERA_SS_IRQ_3,
+	CAMERA_SS_IRQ_4,
+	CAMERA_SS_IRQ_5,
+	CAMERA_SS_IRQ_6,
+	CAMERA_SS_IRQ_7,
+	CAMERA_SS_IRQ_8,
+	CAMERA_SS_IRQ_9,
+	CAMERA_SS_IRQ_10,
+	CAMERA_SS_IRQ_11,
+	CAMERA_SS_IRQ_12,
+	CAMERA_SS_IRQ_MAX
+};
+
+enum msm_cam_hw_idx {
+	MSM_CAM_HW_MICRO,
+	MSM_CAM_HW_CCI,
+	MSM_CAM_HW_CSI0,
+	MSM_CAM_HW_CSI1,
+	MSM_CAM_HW_CSI2,
+	MSM_CAM_HW_CSI3,
+	MSM_CAM_HW_ISPIF,
+	MSM_CAM_HW_CPP,
+	MSM_CAM_HW_VFE0,
+	MSM_CAM_HW_VFE1,
+	MSM_CAM_HW_JPEG0,
+	MSM_CAM_HW_JPEG1,
+	MSM_CAM_HW_JPEG2,
+	MSM_CAM_HW_MAX
+};
+
+struct msm_camera_irq_cfg {
+	/* Bit mask of all the camera hardwares that needs to
+	 * be composited into a single IRQ to the MSM.
+	 * Current usage: (may be updated based on hw changes)
+	 * Bits 31:13 - Reserved.
+	 * Bits 12:0
+	 * 12 - MSM_CAM_HW_JPEG2
+	 * 11 - MSM_CAM_HW_JPEG1
+	 * 10 - MSM_CAM_HW_JPEG0
+	 *  9 - MSM_CAM_HW_VFE1
+	 *  8 - MSM_CAM_HW_VFE0
+	 *  7 - MSM_CAM_HW_CPP
+	 *  6 - MSM_CAM_HW_ISPIF
+	 *  5 - MSM_CAM_HW_CSI3
+	 *  4 - MSM_CAM_HW_CSI2
+	 *  3 - MSM_CAM_HW_CSI1
+	 *  2 - MSM_CAM_HW_CSI0
+	 *  1 - MSM_CAM_HW_CCI
+	 *  0 - MSM_CAM_HW_MICRO
+	 */
+	uint32_t cam_hw_mask;
+	uint8_t  irq_idx;
+	uint8_t  num_hwcore;
+};
+
+#define MSM_IRQROUTER_CFG_COMPIRQ \
+	_IOWR('V', BASE_VIDIOC_PRIVATE, void __user *)
+
 #endif /* __LINUX_MSM_CAMERA_H */
diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h
index cb728a0..333d0df 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -327,5 +327,10 @@
 #define VFE_OUTPUTS_JPEG_AND_THUMB	BIT(9)
 #define VFE_OUTPUTS_THUMB_AND_JPEG	BIT(10)
 
+struct msm_frame_info {
+	uint32_t image_mode;
+	uint32_t path;
+};
+
 #endif /*__MSM_ISP_H__*/
 
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index ec8d73e..431dedf 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -1176,6 +1176,7 @@
 } __attribute__((packed));
 
 #define ADM_CMD_CONNECT_AFE_PORT 0x00010320
+#define ADM_CMD_DISCONNECT_AFE_PORT 0x00010321
 
 struct adm_cmd_connect_afe_port {
 	struct apr_hdr     hdr;
diff --git a/include/sound/q6adm.h b/include/sound/q6adm.h
index 29fb606..56594d4 100644
--- a/include/sound/q6adm.h
+++ b/include/sound/q6adm.h
@@ -41,6 +41,7 @@
 				unsigned int *port_id, int copp_id);
 
 int adm_connect_afe_port(int mode, int session_id, int port_id);
+int adm_disconnect_afe_port(int mode, int session_id, int port_id);
 
 #ifdef CONFIG_RTAC
 int adm_get_copp_id(int port_id);
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 4676a02..17fef15 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -241,7 +241,7 @@
 	struct snd_soc_dai_driver *driver;
 
 	/* DAI runtime info */
-	unsigned int capture_active:1;		/* stream is in use */
+	unsigned int capture_active;		/* stream is in use */
 	unsigned int playback_active:1;		/* stream is in use */
 	unsigned int symmetric_rates:1;
 	struct snd_pcm_runtime *runtime;
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index aaccc5f..372c60d 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -234,6 +234,7 @@
 enum target_sc_flags_table {
 	TARGET_SCF_BIDI_OP		= 0x01,
 	TARGET_SCF_ACK_KREF		= 0x02,
+	TARGET_SCF_UNKNOWN_SIZE		= 0x04,
 };
 
 /* fabric independent task management function values */
@@ -538,6 +539,7 @@
 	/* Used to signal cmd->se_tfo->check_release_cmd() usage per cmd */
 	unsigned		check_release:1;
 	unsigned		cmd_wait_set:1;
+	unsigned		unknown_data_length:1;
 	/* See se_cmd_flags_table */
 	u32			se_cmd_flags;
 	u32			se_ordered_id;
diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h
index 10c6908..f27f575 100644
--- a/include/target/target_core_fabric.h
+++ b/include/target/target_core_fabric.h
@@ -112,7 +112,7 @@
 void	transport_init_se_cmd(struct se_cmd *, struct target_core_fabric_ops *,
 		struct se_session *, u32, int, int, unsigned char *);
 int	transport_lookup_cmd_lun(struct se_cmd *, u32);
-int	transport_generic_allocate_tasks(struct se_cmd *, unsigned char *);
+int	target_setup_cmd_from_cdb(struct se_cmd *, unsigned char *);
 void	target_submit_cmd(struct se_cmd *, struct se_session *, unsigned char *,
 		unsigned char *, u32, u32, int, int, int);
 int	target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index 4193e12..be31953 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -1930,6 +1930,20 @@
 
 };
 
+static const struct snd_soc_dapm_route audio_i2s_map[] = {
+	{"RX_I2S_CLK", NULL, "CP"},
+	{"RX_I2S_CLK", NULL, "CDC_CONN"},
+	{"SLIM RX1", NULL, "RX_I2S_CLK"},
+	{"SLIM RX2", NULL, "RX_I2S_CLK"},
+	{"SLIM RX3", NULL, "RX_I2S_CLK"},
+	{"SLIM RX4", NULL, "RX_I2S_CLK"},
+
+	{"SLIM TX1", NULL, "TX_I2S_CLK"},
+	{"SLIM TX2", NULL, "TX_I2S_CLK"},
+	{"SLIM TX3", NULL, "TX_I2S_CLK"},
+	{"SLIM TX4", NULL, "TX_I2S_CLK"},
+};
+
 static const struct snd_soc_dapm_route audio_map[] = {
 	/* Earpiece (RX MIX1) */
 	{"EAR", NULL, "EAR PA"},
@@ -2618,9 +2632,9 @@
 			}
 			snd_soc_update_bits(codec, SITAR_A_CDC_CLK_TX_I2S_CTL,
 						0x03, tx_fs_rate);
+		} else {
+			sitar->dai[dai->id - 1].rate   = params_rate(params);
 		}
-	} else {
-		sitar->dai[dai->id - 1].rate   = params_rate(params);
 	}
 
 	/**
@@ -2665,9 +2679,9 @@
 			}
 			snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_I2S_CTL,
 						0x03, (rx_fs_rate >> 0x05));
+		} else {
+			sitar->dai[dai->id - 1].rate   = params_rate(params);
 		}
-	} else {
-		sitar->dai[dai->id - 1].rate   = params_rate(params);
 	}
 
 	return 0;
@@ -2714,6 +2728,37 @@
 	},
 };
 
+static struct snd_soc_dai_driver sitar_i2s_dai[] = {
+	{
+		.name = "sitar_i2s_rx1",
+		.id = AIF1_PB,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.rates = WCD9304_RATES,
+			.formats = SITAR_FORMATS,
+			.rate_max = 192000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &sitar_dai_ops,
+	},
+	{
+		.name = "sitar_i2s_tx1",
+		.id = AIF1_CAP,
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.rates = WCD9304_RATES,
+			.formats = SITAR_FORMATS,
+			.rate_max = 192000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &sitar_dai_ops,
+	},
+};
+
 static int sitar_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
@@ -4638,11 +4683,16 @@
 				sitar_1_1_reg_defaults[i].val);
 
 }
+
+static const struct sitar_reg_mask_val sitar_i2c_codec_reg_init_val[] = {
+	{WCD9XXX_A_CHIP_CTL, 0x1, 0x1},
+};
+
 static const struct sitar_reg_mask_val sitar_codec_reg_init_val[] = {
 	/* Initialize current threshold to 350MA
 	* number of wait and run cycles to 4096
 	*/
-	{SITAR_A_RX_HPH_OCP_CTL, 0xF8, 0x60},
+	{SITAR_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
 	{SITAR_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
 
 	{SITAR_A_QFUSE_CTL, 0xFF, 0x03},
@@ -4679,6 +4729,15 @@
 	{SITAR_A_CDC_CLK_MCLK_CTL, 0x01, 0x01},
 };
 
+static void sitar_i2c_codec_init_reg(struct snd_soc_codec *codec)
+{
+	u32 i;
+	for (i = 0; i < ARRAY_SIZE(sitar_i2c_codec_reg_init_val); i++)
+		snd_soc_update_bits(codec, sitar_i2c_codec_reg_init_val[i].reg,
+			sitar_i2c_codec_reg_init_val[i].mask,
+			sitar_i2c_codec_reg_init_val[i].val);
+}
+
 static void sitar_codec_init_reg(struct snd_soc_codec *codec)
 {
 	u32 i;
@@ -4734,6 +4793,9 @@
 	sitar->pdata = dev_get_platdata(codec->dev->parent);
 	sitar_update_reg_defaults(codec);
 	sitar_codec_init_reg(codec);
+	sitar->intf_type = wcd9xxx_get_intf_type();
+	if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C)
+		sitar_i2c_codec_init_reg(codec);
 
 	ret = sitar_handle_pdata(sitar);
 	if (IS_ERR_VALUE(ret)) {
@@ -4745,6 +4807,12 @@
 		ARRAY_SIZE(sitar_snd_controls));
 	snd_soc_dapm_new_controls(dapm, sitar_dapm_widgets,
 		ARRAY_SIZE(sitar_dapm_widgets));
+	if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+		snd_soc_dapm_new_controls(dapm, sitar_dapm_i2s_widgets,
+			ARRAY_SIZE(sitar_dapm_i2s_widgets));
+		snd_soc_dapm_add_routes(dapm, audio_i2s_map,
+		ARRAY_SIZE(audio_i2s_map));
+	}
 	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
 	sitar_version = snd_soc_read(codec, WCD9XXX_A_CHIP_VERSION);
@@ -4972,8 +5040,12 @@
 		S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
 
 #endif
-	ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sitar,
+	if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+		ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sitar,
 			sitar_dai, ARRAY_SIZE(sitar_dai));
+	else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
+		ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sitar,
+			sitar_i2s_dai, ARRAY_SIZE(sitar_i2s_dai));
 	return ret;
 }
 static int __devexit sitar_remove(struct platform_device *pdev)
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 7eefe97..e85e9f5 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -4256,7 +4256,8 @@
 				continue;
 			if (!strncmp(w->sname,
 				tabla_dai[j].playback.stream_name, 13)) {
-				--tabla_p->dai[j].ch_act;
+				if (tabla_p->dai[j].ch_act)
+					--tabla_p->dai[j].ch_act;
 				break;
 			}
 		}
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index a7fd38b..2da5c6a 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -18,6 +18,8 @@
 #include <linux/gpio.h>
 #include <linux/mfd/pm8xxx/pm8921.h>
 #include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/slimbus/slimbus.h>
 #include <sound/core.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
@@ -1417,6 +1419,19 @@
 	return 0;
 }
 
+static int msm_slimbus_1_startup(struct snd_pcm_substream *substream)
+{
+	struct slim_controller *slim = slim_busnum_to_ctrl(1);
+
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+
+	if (slim != NULL)
+		pm_runtime_get_sync(slim->dev.parent);
+
+	return 0;
+}
+
 static void msm_auxpcm_shutdown(struct snd_pcm_substream *substream)
 {
 
@@ -1433,6 +1448,19 @@
 		rtd->dai_link->cpu_dai_name, rtd->dai_link->codec_dai_name);
 }
 
+static void msm_slimbus_1_shutdown(struct snd_pcm_substream *substream)
+{
+	struct slim_controller *slim = slim_busnum_to_ctrl(1);
+
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+
+	if (slim != NULL) {
+		pm_runtime_mark_last_busy(slim->dev.parent);
+		pm_runtime_put(slim->dev.parent);
+	}
+}
+
 static struct snd_soc_ops msm_be_ops = {
 	.startup = msm_startup,
 	.hw_params = msm_hw_params,
@@ -1445,9 +1473,9 @@
 };
 
 static struct snd_soc_ops msm_slimbus_1_be_ops = {
-	.startup = msm_startup,
+	.startup = msm_slimbus_1_startup,
 	.hw_params = msm_slimbus_1_hw_params,
-	.shutdown = msm_shutdown,
+	.shutdown = msm_slimbus_1_shutdown,
 };
 
 static struct snd_soc_ops msm_slimbus_3_be_ops = {
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index 8061b06..d4045e1 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -103,7 +103,6 @@
 			break;
 		} else
 			atomic_set(&prtd->pending_buffer, 0);
-
 		if (runtime->status->hw_ptr >= runtime->control->appl_ptr)
 			break;
 		buf = prtd->audio_client->port[IN].buf;
@@ -261,7 +260,8 @@
 			compr->info.codec_param.codec.bit_rate/8;
 		wma_pro_cfg.block_align = compr->info.codec_param.codec.align;
 		wma_pro_cfg.valid_bits_per_sample =
-		compr->info.codec_param.codec.options.wma.bits_per_sample;
+			compr->info.codec_param.codec\
+				.options.wma.bits_per_sample;
 		wma_pro_cfg.ch_mask =
 			compr->info.codec_param.codec.options.wma.channelmask;
 		wma_pro_cfg.encode_opt =
@@ -297,7 +297,7 @@
 				SND_AUDIOCODEC_AC3_PASS_THROUGH) {
 			msm_pcm_routing_reg_psthr_stream(
 				soc_prtd->dai_link->be_id,
-				prtd->session_id, substream->stream);
+				prtd->session_id, substream->stream, 1);
 		}
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
@@ -307,6 +307,12 @@
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 		pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
+		if (compr->info.codec_param.codec.id ==
+				SND_AUDIOCODEC_AC3_PASS_THROUGH) {
+			msm_pcm_routing_reg_psthr_stream(
+				soc_prtd->dai_link->be_id,
+				prtd->session_id, substream->stream, 0);
+		}
 		atomic_set(&prtd->start, 0);
 		break;
 	case SNDRV_PCM_TRIGGER_SUSPEND:
@@ -452,9 +458,11 @@
 	compressed_audio.prtd = NULL;
 	q6asm_audio_client_buf_free_contiguous(dir,
 				prtd->audio_client);
-
-	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
-	SNDRV_PCM_STREAM_PLAYBACK);
+	if (!(compr->info.codec_param.codec.id ==
+			SND_AUDIOCODEC_AC3_PASS_THROUGH))
+		msm_pcm_routing_dereg_phy_stream(
+			soc_prtd->dai_link->be_id,
+			SNDRV_PCM_STREAM_PLAYBACK);
 	q6asm_audio_client_free(prtd->audio_client);
 	kfree(prtd);
 	return 0;
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 6e190b2..56e83d5 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -426,6 +426,30 @@
 		.ops = &msm_fe_dai_ops,
 		.name = "SEC_I2S_RX_HOSTLESS",
 	},
+	{
+		.playback = {
+			.stream_name = "SGLTE Playback",
+			.aif_name = "SGLTE_DL",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min =     8000,
+			.rate_max =     48000,
+		},
+		.capture = {
+			.stream_name = "SGLTE Capture",
+			.aif_name = "SGLTE_UL",
+			.rates = SNDRV_PCM_RATE_8000_48000,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.channels_min = 1,
+			.channels_max = 2,
+			.rate_min =     8000,
+			.rate_max =     48000,
+		},
+		.ops = &msm_fe_dai_ops,
+		.name = "SGLTE",
+	},
 };
 
 static __devinit int msm_fe_dai_dev_probe(struct platform_device *pdev)
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 4e1ce52..cc51a0f6 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -48,6 +48,7 @@
 
 static int fm_switch_enable;
 static int fm_pcmrx_switch_enable;
+static int srs_alsa_ctrl_ever_called;
 
 #define INT_RX_VOL_MAX_STEPS 0x2000
 #define INT_RX_VOL_GAIN 0x2000
@@ -120,6 +121,12 @@
 
 static void srs_send_params(int port_id, unsigned int techs,
 		int param_block_idx) {
+
+	/* only send commands to dsp if srs alsa ctrl was used
+	   at least one time */
+	if (!srs_alsa_ctrl_ever_called)
+		return;
+
 	pr_debug("SRS %s: called, port_id = %d, techs flags = %u,"
 			" paramblockidx %d", __func__, port_id, techs,
 			param_block_idx);
@@ -237,7 +244,7 @@
 }
 
 void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,
-					int stream_type)
+					int stream_type, int enable)
 {
 	int i, session_type, path_type, port_type;
 	u32 mode = 0;
@@ -267,8 +274,13 @@
 		   (msm_bedais[i].active) &&
 		   (test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
 			mode = afe_get_port_type(msm_bedais[i].port_id);
-			adm_connect_afe_port(mode, dspst_id,
+			if (enable)
+				adm_connect_afe_port(mode, dspst_id,
 					    msm_bedais[i].port_id);
+			else
+				adm_disconnect_afe_port(mode, dspst_id,
+						msm_bedais[i].port_id);
+
 			break;
 		}
 	}
@@ -328,6 +340,8 @@
 
 			payload.copp_ids[payload.num_copps++] =
 				msm_bedais[i].port_id;
+			srs_port_id = msm_bedais[i].port_id;
+			srs_send_params(srs_port_id, 1, 0);
 		}
 	}
 	if (payload.num_copps)
@@ -436,6 +450,8 @@
 
 			msm_pcm_routing_build_matrix(val,
 				fe_dai_map[val][session_type], path_type);
+			srs_port_id = msm_bedais[reg].port_id;
+			srs_send_params(srs_port_id, 1, 0);
 		}
 	} else {
 		if (test_bit(val, &msm_bedais[reg].fe_sessions) &&
@@ -505,6 +521,8 @@
 		session_id = voc_get_session_id(VOICE_SESSION_NAME);
 	else if (val == MSM_FRONTEND_DAI_VOLTE)
 		session_id = voc_get_session_id(VOLTE_SESSION_NAME);
+	else if (val == MSM_FRONTEND_DAI_SGLTE)
+		session_id = voc_get_session_id(SGLTE_SESSION_NAME);
 	else
 		session_id = voc_get_session_id(VOIP_SESSION_NAME);
 
@@ -811,6 +829,8 @@
 	unsigned int techs = 0;
 	unsigned short offset, value, max, index;
 
+	srs_alsa_ctrl_ever_called = 1;
+
 	max = sizeof(msm_srs_trumedia_params) >> 1;
 	index = (unsigned short)((ucontrol->value.integer.value[0] &
 			SRS_PARAM_INDEX_MASK) >> 31);
@@ -1303,6 +1323,9 @@
 	SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_PRI_I2S_RX,
 	MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_PRI_I2S_RX,
+	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new sec_i2s_rx_voice_mixer_controls[] = {
@@ -1315,6 +1338,9 @@
 	SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SEC_I2S_RX,
 	MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_SEC_I2S_RX,
+	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new slimbus_rx_voice_mixer_controls[] = {
@@ -1327,6 +1353,9 @@
 	SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
 	MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
+	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new bt_sco_rx_voice_mixer_controls[] = {
@@ -1342,6 +1371,9 @@
 	SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
 	MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
+	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new mi2s_rx_voice_mixer_controls[] = {
@@ -1354,6 +1386,9 @@
 	SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_MI2S_RX,
 	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
 	msm_routing_put_voice_stub_mixer),
+	SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_MI2S_RX,
+	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new afe_pcm_rx_voice_mixer_controls[] = {
@@ -1369,6 +1404,9 @@
 	SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_AFE_PCM_RX,
 	MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_AFE_PCM_RX,
+	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new aux_pcm_rx_voice_mixer_controls[] = {
@@ -1384,6 +1422,9 @@
 	SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_AUXPCM_RX,
 	MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_AUXPCM_RX,
+	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new sec_aux_pcm_rx_voice_mixer_controls[] = {
@@ -1396,6 +1437,9 @@
 	SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
 	MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
 	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new hdmi_rx_voice_mixer_controls[] = {
@@ -1411,6 +1455,9 @@
 	SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_HDMI_RX,
 	MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
 	msm_routing_put_voice_stub_mixer),
+	SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_HDMI_RX,
+	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
 };
 
 static const struct snd_kcontrol_new stub_rx_mixer_controls[] = {
@@ -1476,6 +1523,29 @@
 	msm_routing_put_voice_mixer),
 };
 
+static const struct snd_kcontrol_new tx_sglte_mixer_controls[] = {
+	SOC_SINGLE_EXT("PRI_TX_SGLTE", MSM_BACKEND_DAI_PRI_I2S_TX,
+	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("MI2S_TX_SGLTE", MSM_BACKEND_DAI_MI2S_TX,
+	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("SLIM_0_TX_SGLTE", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_SGLTE",
+	MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_SGLTE, 1, 0,
+	msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("AFE_PCM_TX_SGLTE", MSM_BACKEND_DAI_AFE_PCM_TX,
+	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("AUX_PCM_TX_SGLTE", MSM_BACKEND_DAI_AUXPCM_TX,
+	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+	SOC_SINGLE_EXT("SEC_AUX_PCM_TX_SGLTE", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+	MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+	msm_routing_put_voice_mixer),
+};
 static const struct snd_kcontrol_new tx_voip_mixer_controls[] = {
 	SOC_SINGLE_EXT("PRI_TX_Voip", MSM_BACKEND_DAI_PRI_I2S_TX,
 	MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
@@ -1878,6 +1948,8 @@
 	SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("VoLTE_DL", "VoLTE Playback", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("VoLTE_UL", "VoLTE Capture", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_IN("SGLTE_DL", "SGLTE Playback", 0, 0, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("SGLTE_UL", "SGLTE Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("VOIP_UL", "VoIP Capture", 0, 0, 0, 0),
 	SND_SOC_DAPM_AIF_IN("SLIM0_DL_HL", "SLIMBUS0_HOSTLESS Playback",
 		0, 0, 0, 0),
@@ -2025,6 +2097,9 @@
 	SND_SOC_DAPM_MIXER("VoLTE_Tx Mixer",
 				SND_SOC_NOPM, 0, 0, tx_volte_mixer_controls,
 				ARRAY_SIZE(tx_volte_mixer_controls)),
+	SND_SOC_DAPM_MIXER("SGLTE_Tx Mixer",
+				SND_SOC_NOPM, 0, 0, tx_sglte_mixer_controls,
+				ARRAY_SIZE(tx_sglte_mixer_controls)),
 	SND_SOC_DAPM_MIXER("INTERNAL_BT_SCO_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
 	int_bt_sco_rx_mixer_controls, ARRAY_SIZE(int_bt_sco_rx_mixer_controls)),
 	SND_SOC_DAPM_MIXER("INTERNAL_FM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -2175,41 +2250,49 @@
 
 	{"PRI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
 	{"PRI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+	{"PRI_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
 	{"PRI_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"PRI_I2S_RX", NULL, "PRI_RX_Voice Mixer"},
 
 	{"SEC_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
 	{"SEC_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+	{"SEC_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
 	{"SEC_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"SEC_I2S_RX", NULL, "SEC_RX_Voice Mixer"},
 
 	{"SLIM_0_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
 	{"SLIM_0_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+	{"SLIM_0_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
 	{"SLIM_0_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"SLIMBUS_0_RX", NULL, "SLIM_0_RX_Voice Mixer"},
 
 	{"INTERNAL_BT_SCO_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
 	{"INTERNAL_BT_SCO_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+	{"INTERNAL_BT_SCO_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
 	{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX_Voice Mixer"},
 
 	{"AFE_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
 	{"AFE_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+	{"AFE_PCM_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
 	{"AFE_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"PCM_RX", NULL, "AFE_PCM_RX_Voice Mixer"},
 
 	{"AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
 	{"AUX_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+	{"AUX_PCM_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
 	{"AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"AUX_PCM_RX", NULL, "AUX_PCM_RX_Voice Mixer"},
 
 	{"SEC_AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
 	{"SEC_AUX_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+	{"SEC_AUX_PCM_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
 	{"SEC_AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"SEC_AUX_PCM_RX", NULL, "SEC_AUX_PCM_RX_Voice Mixer"},
 
 	{"HDMI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
 	{"HDMI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+	{"HDMI_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
 	{"HDMI_RX_Voice Mixer", "Voip", "VOIP_DL"},
 	{"HDMI", NULL, "HDMI_RX_Voice Mixer"},
 	{"HDMI", NULL, "HDMI_DL_HL"},
@@ -2229,6 +2312,14 @@
 	{"VoLTE_Tx Mixer", "AUX_PCM_TX_VoLTE", "AUX_PCM_TX"},
 	{"VoLTE_Tx Mixer", "SEC_AUX_PCM_TX_VoLTE", "SEC_AUX_PCM_TX"},
 	{"VoLTE_UL", NULL, "VoLTE_Tx Mixer"},
+	{"SGLTE_Tx Mixer", "PRI_TX_SGLTE", "PRI_I2S_TX"},
+	{"SGLTE_Tx Mixer", "MI2S_TX_SGLTE", "MI2S_TX"},
+	{"SGLTE_Tx Mixer", "SLIM_0_TX_SGLTE", "SLIMBUS_0_TX"},
+	{"SGLTE_Tx Mixer", "INTERNAL_BT_SCO_TX_SGLTE", "INT_BT_SCO_TX"},
+	{"SGLTE_Tx Mixer", "AFE_PCM_TX_SGLTE", "PCM_TX"},
+	{"SGLTE_Tx Mixer", "AUX_PCM_TX_SGLTE", "AUX_PCM_TX"},
+	{"SGLTE_Tx Mixer", "SEC_AUX_PCM_TX_SGLTE", "SEC_AUX_PCM_TX"},
+	{"SGLTE_UL", NULL, "SGLTE_Tx Mixer"},
 	{"Voip_Tx Mixer", "PRI_TX_Voip", "PRI_I2S_TX"},
 	{"Voip_Tx Mixer", "MI2S_TX_Voip", "MI2S_TX"},
 	{"Voip_Tx Mixer", "SLIM_0_TX_Voip", "SLIMBUS_0_TX"},
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index d1230ad..45dbf40 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -66,6 +66,7 @@
 	MSM_FRONTEND_DAI_AFE_TX,
 	MSM_FRONTEND_DAI_VOICE_STUB,
 	MSM_FRONTEND_DAI_VOLTE,
+	MSM_FRONTEND_DAI_SGLTE,
 	MSM_FRONTEND_DAI_MAX,
 };
 
@@ -113,7 +114,7 @@
 void msm_pcm_routing_reg_phy_stream(int fedai_id, int dspst_id,
 	int stream_type);
 void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,
-		int stream_type);
+		int stream_type, int enable);
 
 void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type);
 
diff --git a/sound/soc/msm/msm-pcm-voice.c b/sound/soc/msm/msm-pcm-voice.c
index 7bdb4f0..633973e 100644
--- a/sound/soc/msm/msm-pcm-voice.c
+++ b/sound/soc/msm/msm-pcm-voice.c
@@ -59,6 +59,14 @@
 		return false;
 }
 
+static int is_sglte(struct msm_voice *psglte)
+{
+	if (psglte == &voice_info[SGLTE_SESSION_INDEX])
+		return true;
+	else
+		return false;
+}
+
 static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
@@ -93,6 +101,10 @@
 		voice = &voice_info[VOLTE_SESSION_INDEX];
 		pr_debug("%s: Open VoLTE Substream Id=%s\n",
 				__func__, substream->pcm->id);
+	} else if (!strncmp("SGLTE", substream->pcm->id, 5)) {
+		voice = &voice_info[SGLTE_SESSION_INDEX];
+		pr_debug("%s: Open SGLTE Substream Id=%s\n",
+				__func__, substream->pcm->id);
 	} else {
 		voice = &voice_info[VOICE_SESSION_INDEX];
 		pr_debug("%s: Open VOICE Substream Id=%s\n",
@@ -162,6 +174,8 @@
 		pr_debug("end voice call\n");
 		if (is_volte(prtd))
 			session_id = voc_get_session_id(VOLTE_SESSION_NAME);
+		else if (is_sglte(prtd))
+			session_id = voc_get_session_id(SGLTE_SESSION_NAME);
 		else
 			session_id = voc_get_session_id(VOICE_SESSION_NAME);
 		voc_end_voice_call(session_id);
@@ -187,6 +201,8 @@
 	if (prtd->playback_start && prtd->capture_start) {
 		if (is_volte(prtd))
 			session_id = voc_get_session_id(VOLTE_SESSION_NAME);
+		else if (is_sglte(prtd))
+			session_id = voc_get_session_id(SGLTE_SESSION_NAME);
 		else
 			session_id = voc_get_session_id(VOICE_SESSION_NAME);
 		voc_start_voice_call(session_id);
@@ -217,6 +233,8 @@
 	pr_debug("%s: cmd = %d\n", __func__, cmd);
 	if (is_volte(prtd))
 		session_id = voc_get_session_id(VOLTE_SESSION_NAME);
+	else if (is_sglte(prtd))
+		session_id = voc_get_session_id(SGLTE_SESSION_NAME);
 	else
 		session_id = voc_get_session_id(VOICE_SESSION_NAME);
 
@@ -290,6 +308,23 @@
 	return 0;
 }
 
+static int msm_sglte_volume_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 0;
+	return 0;
+}
+
+static int msm_sglte_volume_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int volume = ucontrol->value.integer.value[0];
+	pr_debug("%s: volume: %d\n", __func__, volume);
+	voc_set_rx_vol_index(voc_get_session_id(SGLTE_SESSION_NAME),
+						RX_PATH, volume);
+	return 0;
+}
+
 static int msm_voice_mute_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -328,6 +363,25 @@
 	return 0;
 }
 
+static int msm_sglte_mute_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = 0;
+	return 0;
+}
+
+static int msm_sglte_mute_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int mute = ucontrol->value.integer.value[0];
+
+	pr_debug("%s: mute=%d\n", __func__, mute);
+
+	voc_set_tx_mute(voc_get_session_id(SGLTE_SESSION_NAME), TX_PATH, mute);
+
+	return 0;
+}
+
 static int msm_voice_rx_device_mute_get(struct snd_kcontrol *kcontrol,
 					struct snd_ctl_elem_value *ucontrol)
 {
@@ -368,6 +422,26 @@
 	return 0;
 }
 
+static int msm_sglte_rx_device_mute_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] =
+		voc_get_rx_device_mute(voc_get_session_id(SGLTE_SESSION_NAME));
+	return 0;
+}
+
+static int msm_sglte_rx_device_mute_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	int mute = ucontrol->value.integer.value[0];
+
+	pr_debug("%s: mute=%d\n", __func__, mute);
+
+	voc_set_rx_device_mute(voc_get_session_id(SGLTE_SESSION_NAME), mute);
+
+	return 0;
+}
+
 static const char const *tty_mode[] = {"OFF", "HCO", "VCO", "FULL"};
 static const struct soc_enum msm_tty_mode_enum[] = {
 		SOC_ENUM_SINGLE_EXT(4, tty_mode),
@@ -481,6 +555,13 @@
 				msm_volte_mute_get, msm_volte_mute_put),
 	SOC_SINGLE_EXT("VoLTE Rx Volume", SND_SOC_NOPM, 0, 5, 0,
 				msm_volte_volume_get, msm_volte_volume_put),
+	SOC_SINGLE_EXT("SGLTE Rx Device Mute", SND_SOC_NOPM, 0, 1, 0,
+				msm_sglte_rx_device_mute_get,
+				msm_sglte_rx_device_mute_put),
+	SOC_SINGLE_EXT("SGLTE Tx Mute", SND_SOC_NOPM, 0, 1, 0,
+				msm_sglte_mute_get, msm_sglte_mute_put),
+	SOC_SINGLE_EXT("SGLTE Rx Volume", SND_SOC_NOPM, 0, 5, 0,
+				msm_sglte_volume_get, msm_sglte_volume_put),
 };
 
 static struct snd_pcm_ops msm_pcm_ops = {
@@ -543,6 +624,7 @@
 	memset(&voice_info, 0, sizeof(voice_info));
 	mutex_init(&voice_info[VOICE_SESSION_INDEX].lock);
 	mutex_init(&voice_info[VOLTE_SESSION_INDEX].lock);
+	mutex_init(&voice_info[SGLTE_SESSION_INDEX].lock);
 
 	return platform_driver_register(&msm_pcm_driver);
 }
diff --git a/sound/soc/msm/msm-pcm-voice.h b/sound/soc/msm/msm-pcm-voice.h
index aa00577..41aca89 100644
--- a/sound/soc/msm/msm-pcm-voice.h
+++ b/sound/soc/msm/msm-pcm-voice.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
@@ -16,6 +16,7 @@
 enum {
 	VOICE_SESSION_INDEX,
 	VOLTE_SESSION_INDEX,
+	SGLTE_SESSION_INDEX,
 	VOICE_SESSION_INDEX_MAX,
 };
 
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index 98cfa6d..2c44b46 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -1321,6 +1321,21 @@
 		.codec_name = "snd-soc-dummy",
 		.be_id = MSM_FRONTEND_DAI_VOLTE,
 	},
+	{
+		.name = "SGLTE",
+		.stream_name = "SGLTE",
+		.cpu_dai_name   = "SGLTE",
+		.platform_name  = "msm-pcm-voice",
+		.dynamic = 1,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+					SND_SOC_DPCM_TRIGGER_POST},
+		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,/* this dainlink has playback support */
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.be_id = MSM_FRONTEND_DAI_SGLTE,
+	},
 	/* Backend BT/FM DAI Links */
 	{
 		.name = LPASS_BE_INT_BT_SCO_RX,
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index bf6f743..bc57ef3 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -278,6 +278,7 @@
 			case ADM_CMD_MEMORY_UNMAP_REGIONS:
 			case ADM_CMD_MATRIX_MAP_ROUTINGS:
 			case ADM_CMD_CONNECT_AFE_PORT:
+			case ADM_CMD_DISCONNECT_AFE_PORT:
 				atomic_set(&this_adm.copp_stat[index], 1);
 				wake_up(&this_adm.wait);
 				break;
@@ -523,6 +524,76 @@
 	return ret;
 }
 
+int adm_disconnect_afe_port(int mode, int session_id, int port_id)
+{
+	struct adm_cmd_connect_afe_port	cmd;
+	int ret = 0;
+	int index;
+
+	pr_debug("%s: port %d session id:%d mode:%d\n", __func__,
+				port_id, session_id, mode);
+
+	port_id = afe_convert_virtual_to_portid(port_id);
+
+	if (afe_validate_port(port_id) < 0) {
+		pr_err("%s port idi[%d] is invalid\n", __func__, port_id);
+		return -ENODEV;
+	}
+	if (this_adm.apr == NULL) {
+		this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
+						0xFFFFFFFF, &this_adm);
+		if (this_adm.apr == NULL) {
+			pr_err("%s: Unable to register ADM\n", __func__);
+			ret = -ENODEV;
+			return ret;
+		}
+		rtac_set_adm_handle(this_adm.apr);
+	}
+	index = afe_get_port_index(port_id);
+	pr_debug("%s: Port ID %d, index %d\n", __func__, port_id, index);
+
+	cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+			APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cmd.hdr.pkt_size = sizeof(cmd);
+	cmd.hdr.src_svc = APR_SVC_ADM;
+	cmd.hdr.src_domain = APR_DOMAIN_APPS;
+	cmd.hdr.src_port = port_id;
+	cmd.hdr.dest_svc = APR_SVC_ADM;
+	cmd.hdr.dest_domain = APR_DOMAIN_ADSP;
+	cmd.hdr.dest_port = port_id;
+	cmd.hdr.token = port_id;
+	cmd.hdr.opcode = ADM_CMD_DISCONNECT_AFE_PORT;
+
+	cmd.mode = mode;
+	cmd.session_id = session_id;
+	cmd.afe_port_id = port_id;
+
+	atomic_set(&this_adm.copp_stat[index], 0);
+	ret = apr_send_pkt(this_adm.apr, (uint32_t *)&cmd);
+	if (ret < 0) {
+		pr_err("%s:ADM enable for port %d failed\n",
+					__func__, port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	/* Wait for the callback with copp id */
+	ret = wait_event_timeout(this_adm.wait,
+		atomic_read(&this_adm.copp_stat[index]),
+		msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s ADM connect AFE failed for port %d\n", __func__,
+							port_id);
+		ret = -EINVAL;
+		goto fail_cmd;
+	}
+	atomic_dec(&this_adm.copp_cnt[index]);
+	return 0;
+
+fail_cmd:
+
+	return ret;
+}
+
 int adm_open(int port_id, int path, int rate, int channel_mode, int topology)
 {
 	struct adm_copp_open_command	open;
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index 0c30dc9..f66a01c 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -34,6 +34,7 @@
 #define VOC_PATH_PASSIVE 0
 #define VOC_PATH_FULL 1
 #define VOC_PATH_VOLTE_PASSIVE 2
+#define VOC_PATH_SGLTE_PASSIVE 3
 
 /* CVP CAL Size: 245760 = 240 * 1024 */
 #define CVP_CAL_SIZE 245760
@@ -149,6 +150,9 @@
 		else if (!strncmp(name, "VoLTE session", 13))
 			session_id =
 			common.voice[VOC_PATH_VOLTE_PASSIVE].session_id;
+		else if (!strncmp(name, "SGLTE session", 13))
+			session_id =
+			common.voice[VOC_PATH_SGLTE_PASSIVE].session_id;
 		else
 			session_id = common.voice[VOC_PATH_FULL].session_id;
 
@@ -189,6 +193,11 @@
 	return (session_id == common.voice[VOC_PATH_VOLTE_PASSIVE].session_id);
 }
 
+static bool is_sglte_session(u16 session_id)
+{
+	return (session_id == common.voice[VOC_PATH_SGLTE_PASSIVE].session_id);
+}
+
 static int voice_apr_register(void)
 {
 	pr_debug("%s\n", __func__);
@@ -275,8 +284,10 @@
 		pr_err("%s: apr_mvm is NULL.\n", __func__);
 		return -EINVAL;
 	}
-	pr_debug("%s: VoLTE command to MVM\n", __func__);
-	if (is_volte_session(v->session_id)) {
+	pr_debug("%s: VoLTE/SGLTE command to MVM\n", __func__);
+	if (is_volte_session(v->session_id) ||
+			is_sglte_session(v->session_id)) {
+
 		mvm_handle = voice_get_mvm_handle(v);
 		mvm_voice_ctl_cmd.hdr.hdr_field = APR_HDR_FIELD(
 						APR_MSG_TYPE_SEQ_CMD,
@@ -350,7 +361,8 @@
 
 	if (!mvm_handle) {
 		if (is_voice_session(v->session_id) ||
-				is_volte_session(v->session_id)) {
+				is_volte_session(v->session_id) ||
+				is_sglte_session(v->session_id)) {
 			mvm_session_cmd.hdr.hdr_field = APR_HDR_FIELD(
 						APR_MSG_TYPE_SEQ_CMD,
 						APR_HDR_LEN(APR_HDR_SIZE),
@@ -369,11 +381,15 @@
 			if (is_volte_session(v->session_id)) {
 				strlcpy(mvm_session_cmd.mvm_session.name,
 				"default volte voice",
+				sizeof(mvm_session_cmd.mvm_session.name) - 1);
+			} else if (is_sglte_session(v->session_id)) {
+				strlcpy(mvm_session_cmd.mvm_session.name,
+				"default modem voice2",
 				sizeof(mvm_session_cmd.mvm_session.name));
 			} else {
-			strlcpy(mvm_session_cmd.mvm_session.name,
+				strlcpy(mvm_session_cmd.mvm_session.name,
 				"default modem voice",
-				sizeof(mvm_session_cmd.mvm_session.name));
+				sizeof(mvm_session_cmd.mvm_session.name) - 1);
 			}
 
 			v->mvm_state = CMD_STATUS_FAIL;
@@ -432,7 +448,8 @@
 	/* send cmd to create cvs session */
 	if (!cvs_handle) {
 		if (is_voice_session(v->session_id) ||
-			is_volte_session(v->session_id)) {
+			is_volte_session(v->session_id) ||
+			is_sglte_session(v->session_id)) {
 			pr_debug("%s: creating CVS passive session\n",
 				 __func__);
 
@@ -452,11 +469,15 @@
 			if (is_volte_session(v->session_id)) {
 				strlcpy(mvm_session_cmd.mvm_session.name,
 				"default volte voice",
-				sizeof(mvm_session_cmd.mvm_session.name));
-			} else {
-			strlcpy(cvs_session_cmd.cvs_session.name,
-				"default modem voice",
+				sizeof(mvm_session_cmd.mvm_session.name) - 1);
+			} else if (is_sglte_session(v->session_id)) {
+				strlcpy(cvs_session_cmd.cvs_session.name,
+				"default modem voice2",
 				sizeof(cvs_session_cmd.cvs_session.name));
+			} else {
+				strlcpy(cvs_session_cmd.cvs_session.name,
+				"default modem voice",
+				sizeof(cvs_session_cmd.cvs_session.name) - 1);
 			}
 			v->cvs_state = CMD_STATUS_FAIL;
 
diff --git a/sound/soc/msm/qdsp6/q6voice.h b/sound/soc/msm/qdsp6/q6voice.h
index 88ab0d5..468aba8 100644
--- a/sound/soc/msm/qdsp6/q6voice.h
+++ b/sound/soc/msm/qdsp6/q6voice.h
@@ -16,7 +16,7 @@
 #include <linux/ion.h>
 
 #define MAX_VOC_PKT_SIZE 642
-#define SESSION_NAME_LEN 20
+#define SESSION_NAME_LEN 21
 
 #define VOC_REC_UPLINK		0x00
 #define VOC_REC_DOWNLINK	0x01
@@ -918,7 +918,7 @@
 	void *buf;
 };
 
-#define MAX_VOC_SESSIONS 3
+#define MAX_VOC_SESSIONS 4
 #define SESSION_ID_BASE 0xFFF0
 
 struct common_data {
@@ -990,6 +990,7 @@
 #define VOICE_SESSION_NAME "Voice session"
 #define VOIP_SESSION_NAME "VoIP session"
 #define VOLTE_SESSION_NAME "VoLTE session"
+#define SGLTE_SESSION_NAME "SGLTE session"
 uint16_t voc_get_session_id(char *name);
 
 int voc_start_playback(uint32_t set);
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 3a9fbe1..fd3fe6a 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -236,11 +236,24 @@
 	}
 
 	if (codec_dai->driver->ops->startup) {
-		ret = codec_dai->driver->ops->startup(substream, codec_dai);
-		if (ret < 0) {
-			printk(KERN_ERR "asoc: can't open codec %s\n",
-				codec_dai->name);
-			goto codec_dai_err;
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			ret = codec_dai->driver->ops->startup(substream,
+								codec_dai);
+			if (ret < 0) {
+				printk(KERN_ERR "asoc: can't open codec %s\n",
+					codec_dai->name);
+				goto codec_dai_err;
+			}
+		} else {
+			if (!codec_dai->capture_active) {
+				ret = codec_dai->driver->ops->startup(substream,
+								codec_dai);
+				if (ret < 0) {
+					printk(KERN_ERR "can't open codec %s\n",
+						codec_dai->name);
+					goto codec_dai_err;
+				}
+			}
 		}
 	}
 
@@ -456,8 +469,15 @@
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		snd_soc_dai_digital_mute(codec_dai, 1);
 
-	if (cpu_dai->driver->ops->shutdown)
-		cpu_dai->driver->ops->shutdown(substream, cpu_dai);
+	if (cpu_dai->driver->ops->shutdown) {
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			codec_dai->driver->ops->shutdown(substream, codec_dai);
+		} else {
+			if (!codec_dai->capture_active)
+				codec_dai->driver->ops->shutdown(substream,
+								codec_dai);
+		}
+	}
 
 	if (codec_dai->driver->ops->shutdown)
 		codec_dai->driver->ops->shutdown(substream, codec_dai);
@@ -485,7 +505,8 @@
 		}
 	} else {
 		/* capture streams can be powered down now */
-		snd_soc_dapm_stream_event(rtd,
+		if (!codec_dai->capture_active)
+			snd_soc_dapm_stream_event(rtd,
 			codec_dai->driver->capture.stream_name,
 			SND_SOC_DAPM_STREAM_STOP);
 	}
@@ -557,11 +578,12 @@
 		snd_soc_dapm_stream_event(rtd,
 					  codec_dai->driver->playback.stream_name,
 					  SND_SOC_DAPM_STREAM_START);
-	else
-		snd_soc_dapm_stream_event(rtd,
+	else {
+		if (codec_dai->capture_active == 1)
+			snd_soc_dapm_stream_event(rtd,
 					  codec_dai->driver->capture.stream_name,
 					  SND_SOC_DAPM_STREAM_START);
-
+	}
 	snd_soc_dai_digital_mute(codec_dai, 0);
 
 out:
@@ -594,11 +616,24 @@
 	}
 
 	if (codec_dai->driver->ops->hw_params) {
-		ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai);
-		if (ret < 0) {
-			printk(KERN_ERR "asoc: can't set codec %s hw params\n",
-				codec_dai->name);
-			goto codec_err;
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			ret = codec_dai->driver->ops->hw_params(substream,
+							params, codec_dai);
+			if (ret < 0) {
+				printk(KERN_ERR "not set codec %s hw params\n",
+					codec_dai->name);
+				goto codec_err;
+			}
+		} else {
+			if (codec_dai->capture_active == 1) {
+				ret = codec_dai->driver->ops->hw_params(
+						substream, params, codec_dai);
+				if (ret < 0) {
+					printk(KERN_ERR "fail: %s hw params\n",
+						codec_dai->name);
+					goto codec_err;
+				}
+			}
 		}
 	}
 
@@ -706,9 +741,19 @@
 	int ret;
 
 	if (codec_dai->driver->ops->trigger) {
-		ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai);
-		if (ret < 0)
-			return ret;
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			ret = codec_dai->driver->ops->trigger(substream,
+						cmd, codec_dai);
+			if (ret < 0)
+				return ret;
+		} else {
+			if (codec_dai->capture_active == 1) {
+				ret = codec_dai->driver->ops->trigger(
+						substream, cmd, codec_dai);
+				if (ret < 0)
+					return ret;
+			}
+		}
 	}
 
 	if (platform->driver->ops && platform->driver->ops->trigger) {
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 1fcf1bb..28e5548 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -30,6 +30,17 @@
 	return __value(parse_events_text + 1, 16, PE_RAW);
 }
 
+static int sh_raw(void)
+{
+	return __value(parse_events_text + 2, 16, PE_SH_RAW);
+}
+
+static int fab_raw(void)
+{
+	return __value(parse_events_text + 2, 16, PE_FAB_RAW);
+}
+
+
 static int str(int token)
 {
 	parse_events_lval.str = strdup(parse_events_text);
@@ -107,6 +118,8 @@
 
 mem:			{ return PE_PREFIX_MEM; }
 r{num_raw_hex}		{ return raw(); }
+rs{num_raw_hex}		{ return sh_raw(); }
+rm{num_raw_hex}		{ return fab_raw(); }
 {num_dec}		{ return value(10); }
 {num_hex}		{ return value(16); }
 
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index d9637da..07b292d 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -24,7 +24,7 @@
 
 %}
 
-%token PE_VALUE PE_VALUE_SYM PE_RAW PE_TERM
+%token PE_VALUE PE_VALUE_SYM PE_RAW PE_SH_RAW PE_FAB_RAW PE_TERM
 %token PE_NAME
 %token PE_MODIFIER_EVENT PE_MODIFIER_BP
 %token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT
@@ -33,6 +33,8 @@
 %type <num> PE_VALUE
 %type <num> PE_VALUE_SYM
 %type <num> PE_RAW
+%type <num> PE_SH_RAW
+%type <num> PE_FAB_RAW
 %type <num> PE_TERM
 %type <str> PE_NAME
 %type <str> PE_NAME_CACHE_TYPE
@@ -77,7 +79,9 @@
 	   event_legacy_mem |
 	   event_legacy_tracepoint sep_dc |
 	   event_legacy_numeric sep_dc |
-	   event_legacy_raw sep_dc
+	   event_legacy_raw sep_dc |
+	   event_legacy_shared_raw sep_dc |
+	   event_legacy_fabric_raw sep_dc
 
 event_pmu:
 PE_NAME '/' event_config '/'
@@ -149,6 +153,18 @@
 	ABORT_ON(parse_events_add_numeric(list_event, idx, PERF_TYPE_RAW, $1, NULL));
 }
 
+event_legacy_shared_raw:
+PE_SH_RAW
+{
+	ABORT_ON(parse_events_add_numeric(list_event, idx, 6, $1, NULL));
+}
+
+event_legacy_fabric_raw:
+PE_FAB_RAW
+{
+	ABORT_ON(parse_events_add_numeric(list_event, idx, 7, $1, NULL));
+}
+
 event_config:
 event_config ',' event_term
 {