Merge "msm: footswitch-8x60: Correct 8064 bus port IDs for video encoder/decoder" into msm-3.0
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index de314ea..88ad1a9 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -651,6 +651,26 @@
 	}
 }
 
+static int cpu_has_active_perf(void)
+{
+	int idx;
+	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+
+	if (!armpmu)
+		return 0;
+
+	for (idx = 0; idx <= armpmu->num_events; ++idx) {
+		struct perf_event *event = cpuc->events[idx];
+
+		if (event)
+			/*Even one event's existence is good enough.*/
+			return 1;
+
+	}
+
+	return 0;
+}
+
 static struct pmu pmu = {
 	.pmu_enable	= armpmu_enable,
 	.pmu_disable	= armpmu_disable,
@@ -676,16 +696,18 @@
 {
 	switch (cmd) {
 	case CPU_PM_ENTER:
-		armpmu_update_counters();
-		perf_pmu_disable(&pmu);
+		if (cpu_has_active_perf()) {
+			armpmu_update_counters();
+			perf_pmu_disable(&pmu);
+		}
 		break;
 
 	case CPU_PM_ENTER_FAILED:
 	case CPU_PM_EXIT:
-		if (armpmu && armpmu->reset)
+		if (cpu_has_active_perf() && armpmu->reset) {
 			armpmu->reset(NULL);
-		perf_pmu_enable(&pmu);
-
+			perf_pmu_enable(&pmu);
+		}
 		break;
 	}
 
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 0d25c89..99a3ed2 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -1970,6 +1970,7 @@
 	&apq8064_etm_device,
 	&apq_cpudai_slim_4_rx,
 	&apq_cpudai_slim_4_tx,
+	&msm8960_gemini_device,
 };
 
 static struct platform_device *sim_devices[] __initdata = {
diff --git a/arch/arm/mach-msm/board-8930-gpu.c b/arch/arm/mach-msm/board-8930-gpu.c
index 7c8c64f..5ee480a 100644
--- a/arch/arm/mach-msm/board-8930-gpu.c
+++ b/arch/arm/mach-msm/board-8930-gpu.c
@@ -115,7 +115,7 @@
 static struct kgsl_device_platform_data kgsl_3d0_pdata = {
 	.pwrlevel = {
 		{
-			.gpu_freq = 450000000,
+			.gpu_freq = 400000000,
 			.bus_freq = 3,
 			.io_fraction = 0,
 		},
diff --git a/arch/arm/mach-msm/board-8960-gpiomux.c b/arch/arm/mach-msm/board-8960-gpiomux.c
index 9bf80ed..8b5c693 100644
--- a/arch/arm/mach-msm/board-8960-gpiomux.c
+++ b/arch/arm/mach-msm/board-8960-gpiomux.c
@@ -256,6 +256,7 @@
 	.pull = GPIOMUX_PULL_DOWN,
 };
 
+#if defined(CONFIG_FB_MSM_HDMI_MHL_8334) || defined(CONFIG_FB_MSM_HDMI_MHL_9244)
 static struct gpiomux_setting hdmi_active_3_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_2MA,
@@ -270,6 +271,7 @@
 	.dir = GPIOMUX_OUT_HIGH,
 };
 #endif
+#endif
 
 #if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
 static struct msm_gpiomux_config msm8960_ethernet_configs[] = {
@@ -690,6 +692,7 @@
 			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
 		},
 	},
+#ifdef CONFIG_FB_MSM_HDMI_MHL_9244
 		{
 		.gpio = 15,
 		.settings = {
@@ -704,6 +707,23 @@
 			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
 		},
 	},
+#endif
+#ifdef CONFIG_FB_MSM_HDMI_MHL_8334
+		{
+		.gpio = 4,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_3_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 15,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &hdmi_active_4_cfg,
+			[GPIOMUX_SUSPENDED] = &hdmi_suspend_cfg,
+		},
+	},
+#endif /* CONFIG_FB_MSM_HDMI_MHL */
 };
 #endif
 
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 6ed174c..c294919 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -110,6 +110,9 @@
 #define KS8851_IRQ_GPIO		90
 #define HAP_SHIFT_LVL_OE_GPIO	47
 
+#define MHL_GPIO_INT            4
+#define MHL_GPIO_RESET          15
+
 #if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
 
 struct sx150x_platform_data msm8960_sx150x_data[] = {
@@ -2273,11 +2276,76 @@
 	},
 };
 
+#ifdef CONFIG_FB_MSM_HDMI_MHL_8334
+static void mhl_sii_reset_gpio(int on)
+{
+	gpio_set_value(MHL_GPIO_RESET, on);
+	return;
+}
+
+/*
+ * Request for GPIO allocations
+ * Set appropriate GPIO directions
+ */
+static int mhl_sii_gpio_setup(int on)
+{
+	int ret;
+
+	if (on) {
+		ret = gpio_request(MHL_GPIO_RESET, "W_RST#");
+		if (ret < 0) {
+			pr_err("GPIO RESET request failed: %d\n", ret);
+			return -EBUSY;
+		}
+		ret = gpio_direction_output(MHL_GPIO_RESET, 1);
+		if (ret < 0) {
+			pr_err("SET GPIO RESET direction failed: %d\n", ret);
+			gpio_free(MHL_GPIO_RESET);
+			return -EBUSY;
+		}
+		ret = gpio_request(MHL_GPIO_INT, "W_INT");
+		if (ret < 0) {
+			pr_err("GPIO INT request failed: %d\n", ret);
+			gpio_free(MHL_GPIO_RESET);
+			return -EBUSY;
+		}
+		ret = gpio_direction_input(MHL_GPIO_INT);
+		if (ret < 0) {
+			pr_err("SET GPIO INTR direction failed: %d\n", ret);
+			gpio_free(MHL_GPIO_RESET);
+			gpio_free(MHL_GPIO_INT);
+			return -EBUSY;
+		}
+	} else {
+		gpio_free(MHL_GPIO_RESET);
+		gpio_free(MHL_GPIO_INT);
+	}
+
+	return 0;
+}
+
+static struct msm_mhl_platform_data mhl_platform_data = {
+	.irq = MSM_GPIO_TO_INT(4),
+	.gpio_setup = mhl_sii_gpio_setup,
+	.reset_pin = mhl_sii_reset_gpio,
+};
+#endif
+
 static struct i2c_board_info sii_device_info[] __initdata = {
 	{
+#ifdef CONFIG_FB_MSM_HDMI_MHL_8334
+		/*
+		 * keeps SI 8334 as the default
+		 * MHL TX
+		 */
+		I2C_BOARD_INFO("sii8334", 0x39),
+		.platform_data = &mhl_platform_data,
+#endif
+#ifdef CONFIG_FB_MSM_HDMI_MHL_9244
 		I2C_BOARD_INFO("Sil-9244", 0x39),
-		.flags = I2C_CLIENT_WAKE,
 		.irq = MSM_GPIO_TO_INT(15),
+#endif /* CONFIG_MSM_HDMI_MHL */
+		.flags = I2C_CLIENT_WAKE,
 	},
 };
 
@@ -2902,7 +2970,7 @@
 		ARRAY_SIZE(mxt_device_info),
 	},
 	{
-		I2C_FFA | I2C_LIQUID,
+		I2C_SURF | I2C_FFA | I2C_LIQUID,
 		MSM_8960_GSBI10_QUP_I2C_BUS_ID,
 		sii_device_info,
 		ARRAY_SIZE(sii_device_info),
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index 28f5e7f..55c5fd9 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -380,6 +380,7 @@
 }
 
 static struct clk_lookup msm_clocks_dummy[] = {
+	CLK_DUMMY("xo",		XO_CLK,		NULL,	OFF),
 	CLK_DUMMY("core_clk",	BLSP2_UART_CLK,	"msm_serial_hsl.0",	OFF),
 	CLK_DUMMY("iface_clk",	BLSP2_UART_CLK,	"msm_serial_hsl.0",	OFF),
 	CLK_DUMMY("core_clk",	SDC1_CLK,	NULL,			OFF),
diff --git a/arch/arm/mach-msm/cache_erp.c b/arch/arm/mach-msm/cache_erp.c
index 1eb229a..9a721e4 100644
--- a/arch/arm/mach-msm/cache_erp.c
+++ b/arch/arm/mach-msm/cache_erp.c
@@ -28,6 +28,9 @@
 #define CESR_TLBMH		BIT(16)
 #define CESR_I_MASK		0x000000CC
 
+/* Print a message for everything but TLB MH events */
+#define CESR_PRINT_MASK		0x000000FF
+
 #define L2ESR_IND_ADDR		0x204
 #define L2ESYNR0_IND_ADDR	0x208
 #define L2ESYNR1_IND_ADDR	0x209
@@ -190,9 +193,12 @@
 	struct msm_l1_err_stats *l1_stats = dev_id;
 	unsigned int cesr = read_cesr();
 	unsigned int i_cesynr, d_cesynr;
+	int print_regs = cesr & CESR_PRINT_MASK;
 
-	pr_alert("L1 Error detected on CPU %d!\n", smp_processor_id());
-	pr_alert("\tCESR    = 0x%08x\n", cesr);
+	if (print_regs) {
+		pr_alert("L1 Error detected on CPU %d!\n", smp_processor_id());
+		pr_alert("\tCESR    = 0x%08x\n", cesr);
+	}
 
 	if (cesr & CESR_DCTPE) {
 		pr_alert("D-cache tag parity error\n");
@@ -225,7 +231,7 @@
 	}
 
 	if (cesr & CESR_TLBMH) {
-		pr_alert("TLB multi-hit error\n");
+		asm ("mcr p15, 0, r0, c8, c7, 0");
 		l1_stats->tlbmh++;
 	}
 
@@ -250,7 +256,8 @@
 	/* Clear the interrupt bits we processed */
 	write_cesr(cesr);
 
-	ERP_L1_ERR("L1 cache / TLB error detected");
+	if (print_regs)
+		ERP_L1_ERR("L1 cache error detected");
 
 	return IRQ_HANDLED;
 }
diff --git a/arch/arm/mach-msm/clock-7x30.c b/arch/arm/mach-msm/clock-7x30.c
index 5951734..d124ba6 100644
--- a/arch/arm/mach-msm/clock-7x30.c
+++ b/arch/arm/mach-msm/clock-7x30.c
@@ -2800,8 +2800,8 @@
 	OWN(APPS1,  6, "iface_clk",	grp_2d_p_clk,	"kgsl-2d0.0"),
 	OWN(APPS1,  6, "iface_clk",	grp_2d_p_clk,	"footswitch-pcom.0"),
 	OWN(APPS1, 31, "hdmi_clk",	hdmi_clk,	"dtv.0"),
-	OWN(APPS1,  0, "jpeg_clk",	jpeg_clk,	NULL),
-	OWN(APPS1,  0, "jpeg_pclk",	jpeg_p_clk,	NULL),
+	OWN(APPS1,  0, "jpeg_clk",	jpeg_clk,	"msm_gemini.0"),
+	OWN(APPS1,  0, "jpeg_pclk",	jpeg_p_clk,	"msm_gemini.0"),
 	OWN(APPS1, 23, "lpa_codec_clk", lpa_codec_clk,	NULL),
 	OWN(APPS1, 23, "lpa_core_clk",	lpa_core_clk,	NULL),
 	OWN(APPS1, 23, "lpa_pclk",	lpa_p_clk,	NULL),
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 0ebaaab..3f7206f 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -5047,8 +5047,8 @@
 	CLK_LOOKUP("vcap_npl_clk",      vcap_npl_clk.c,         ""),
 	CLK_LOOKUP("vcap_npl_clk",      vcap_npl_clk.c,         "msm_vcap.0"),
 	CLK_LOOKUP("bus_clk",		ijpeg_axi_clk.c, "footswitch-8x60.3"),
-	CLK_LOOKUP("mem_clk",		imem_axi_clk.c,		""),
-	CLK_LOOKUP("ijpeg_clk",         ijpeg_clk.c,            ""),
+	CLK_LOOKUP("imem_clk",		imem_axi_clk.c,		"msm_gemini.0"),
+	CLK_LOOKUP("ijpeg_clk",         ijpeg_clk.c,    "msm_gemini.0"),
 	CLK_LOOKUP("core_clk",		ijpeg_clk.c,	"footswitch-8x60.3"),
 	CLK_LOOKUP("core_clk",		jpegd_clk.c,		""),
 	CLK_LOOKUP("core_clk",		mdp_clk.c,		"mdp.0"),
@@ -5093,7 +5093,7 @@
 	CLK_LOOKUP("iface_clk",		gfx3d_p_clk.c,	"footswitch-8x60.2"),
 	CLK_LOOKUP("master_iface_clk",	hdmi_m_p_clk.c,		"hdmi_msm.1"),
 	CLK_LOOKUP("slave_iface_clk",	hdmi_s_p_clk.c,		"hdmi_msm.1"),
-	CLK_LOOKUP("ijpeg_pclk",	ijpeg_p_clk.c,		""),
+	CLK_LOOKUP("ijpeg_pclk",	ijpeg_p_clk.c,		"msm_gemini.0"),
 	CLK_LOOKUP("iface_clk",		ijpeg_p_clk.c,	"footswitch-8x60.3"),
 	CLK_LOOKUP("iface_clk",		jpegd_p_clk.c,		""),
 	CLK_LOOKUP("mem_iface_clk",	imem_p_clk.c,	"kgsl-3d0.0"),
@@ -5349,8 +5349,8 @@
 	CLK_LOOKUP("core_clk",		gfx3d_clk.c,	"kgsl-3d0.0"),
 	CLK_LOOKUP("core_clk",		gfx3d_clk.c,	"footswitch-8x60.2"),
 	CLK_LOOKUP("bus_clk",		ijpeg_axi_clk.c, "footswitch-8x60.3"),
-	CLK_LOOKUP("imem_clk",		imem_axi_clk.c,		NULL),
-	CLK_LOOKUP("ijpeg_clk",         ijpeg_clk.c,            NULL),
+	CLK_LOOKUP("imem_clk",		imem_axi_clk.c,		"msm_gemini.0"),
+	CLK_LOOKUP("ijpeg_clk",     ijpeg_clk.c,    "msm_gemini.0"),
 	CLK_LOOKUP("core_clk",		ijpeg_clk.c,	"footswitch-8x60.3"),
 	CLK_LOOKUP("core_clk",		jpegd_clk.c,		""),
 	CLK_LOOKUP("core_clk",		mdp_clk.c,		"mdp.0"),
@@ -5402,7 +5402,7 @@
 	CLK_LOOKUP("iface_clk",		gfx3d_p_clk.c,	"footswitch-8x60.2"),
 	CLK_LOOKUP("master_iface_clk",	hdmi_m_p_clk.c,	"hdmi_msm.1"),
 	CLK_LOOKUP("slave_iface_clk",	hdmi_s_p_clk.c,	"hdmi_msm.1"),
-	CLK_LOOKUP("ijpeg_pclk",	ijpeg_p_clk.c,		NULL),
+	CLK_LOOKUP("ijpeg_pclk",	ijpeg_p_clk.c,		"msm_gemini.0"),
 	CLK_LOOKUP("iface_clk",		ijpeg_p_clk.c,	"footswitch-8x60.3"),
 	CLK_LOOKUP("iface_clk",		jpegd_p_clk.c,		""),
 	CLK_LOOKUP("mem_iface_clk",	imem_p_clk.c,	"kgsl-3d0.0"),
@@ -5638,8 +5638,8 @@
 	CLK_LOOKUP("bus_clk",
 			    gfx3d_axi_clk_8930.c, "footswitch-8x60.2"),
 	CLK_LOOKUP("bus_clk",		ijpeg_axi_clk.c, "footswitch-8x60.3"),
-	CLK_LOOKUP("imem_clk",		imem_axi_clk.c,		NULL),
-	CLK_LOOKUP("ijpeg_clk",         ijpeg_clk.c,            NULL),
+	CLK_LOOKUP("imem_clk",		imem_axi_clk.c,		"msm_gemini.0"),
+	CLK_LOOKUP("ijpeg_clk",         ijpeg_clk.c,    "msm_gemini.0"),
 	CLK_LOOKUP("core_clk",		ijpeg_clk.c,	"footswitch-8x60.3"),
 	CLK_LOOKUP("core_clk",		mdp_clk.c,		"mdp.0"),
 	CLK_LOOKUP("core_clk",		mdp_clk.c,	"footswitch-8x60.4"),
@@ -5682,7 +5682,7 @@
 	CLK_LOOKUP("iface_clk",		gfx3d_p_clk.c,	"footswitch-8x60.2"),
 	CLK_LOOKUP("master_iface_clk",	hdmi_m_p_clk.c,	"hdmi_msm.1"),
 	CLK_LOOKUP("slave_iface_clk",	hdmi_s_p_clk.c,	"hdmi_msm.1"),
-	CLK_LOOKUP("ijpeg_pclk",	ijpeg_p_clk.c,		NULL),
+	CLK_LOOKUP("ijpeg_pclk",	ijpeg_p_clk.c,		"msm_gemini.0"),
 	CLK_LOOKUP("iface_clk",		ijpeg_p_clk.c,	"footswitch-8x60.3"),
 	CLK_LOOKUP("mem_iface_clk",	imem_p_clk.c,	"kgsl-3d0.0"),
 	CLK_LOOKUP("iface_clk",		mdp_p_clk.c,		"mdp.0"),
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index a1bbf53..2bfadf6 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -3613,7 +3613,7 @@
 	CLK_LOOKUP("core_clk",		gfx2d1_clk.c,	"footswitch-8x60.1"),
 	CLK_LOOKUP("core_clk",		gfx3d_clk.c,	"kgsl-3d0.0"),
 	CLK_LOOKUP("core_clk",		gfx3d_clk.c,	"footswitch-8x60.2"),
-	CLK_LOOKUP("ijpeg_clk",		ijpeg_clk.c,		NULL),
+	CLK_LOOKUP("ijpeg_clk",		ijpeg_clk.c,		"msm_gemini.0"),
 	CLK_LOOKUP("core_clk",		ijpeg_clk.c,	"footswitch-8x60.3"),
 	CLK_LOOKUP("core_clk",		jpegd_clk.c,		NULL),
 	CLK_LOOKUP("core_clk",		mdp_clk.c,		"mdp.0"),
@@ -3666,7 +3666,7 @@
 	CLK_LOOKUP("iface_clk",		gfx3d_p_clk.c,	"footswitch-8x60.2"),
 	CLK_LOOKUP("master_iface_clk",	hdmi_m_p_clk.c,	"hdmi_msm.1"),
 	CLK_LOOKUP("slave_iface_clk",	hdmi_s_p_clk.c,	"hdmi_msm.1"),
-	CLK_LOOKUP("ijpeg_pclk",	ijpeg_p_clk.c,		NULL),
+	CLK_LOOKUP("ijpeg_pclk",	ijpeg_p_clk.c,		"msm_gemini.0"),
 	CLK_LOOKUP("iface_clk",		ijpeg_p_clk.c,	"footswitch-8x60.3"),
 	CLK_LOOKUP("iface_clk",		jpegd_p_clk.c,		NULL),
 	CLK_LOOKUP("mem_iface_clk",	imem_p_clk.c,	"kgsl-3d0.0"),
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
index e83f17a..5022811 100644
--- a/arch/arm/mach-msm/clock-pll.c
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -45,9 +45,11 @@
 
 static DEFINE_SPINLOCK(pll_reg_lock);
 
+#define ENABLE_WAIT_MAX_LOOPS 200
+
 int pll_vote_clk_enable(struct clk *clk)
 {
-	u32 ena;
+	u32 ena, count;
 	unsigned long flags;
 	struct pll_vote_clk *pll = to_pll_vote_clk(clk);
 
@@ -57,11 +59,22 @@
 	writel_relaxed(ena, PLL_EN_REG(pll));
 	spin_unlock_irqrestore(&pll_reg_lock, flags);
 
-	/* Wait until PLL is enabled */
-	while ((readl_relaxed(PLL_STATUS_REG(pll)) & pll->status_mask) == 0)
-		cpu_relax();
+	/*
+	 * Use a memory barrier since some PLL status registers are
+	 * not within the same 1K segment as the voting registers.
+	 */
+	mb();
 
-	return 0;
+	/* Wait for pll to enable. */
+	for (count = ENABLE_WAIT_MAX_LOOPS; count > 0; count--) {
+		if (readl_relaxed(pll->status_reg) & pll->status_mask)
+			return 0;
+		udelay(1);
+	}
+
+	WARN("PLL %s didn't enable after voting for it!\n", clk->dbg_name);
+
+	return -ETIMEDOUT;
 }
 
 void pll_vote_clk_disable(struct clk *clk)
diff --git a/arch/arm/mach-msm/cpuidle.c b/arch/arm/mach-msm/cpuidle.c
index 4ba3f95..b68fdc1 100644
--- a/arch/arm/mach-msm/cpuidle.c
+++ b/arch/arm/mach-msm/cpuidle.c
@@ -30,28 +30,40 @@
 	{0, 0, "C0", "WFI",
 		MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
 
-	{0, 1, "C1", "STANDALONE_POWER_COLLAPSE",
+	{0, 1, "C1", "RETENTION",
+		MSM_PM_SLEEP_MODE_RETENTION},
+
+	{0, 2, "C2", "STANDALONE_POWER_COLLAPSE",
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
 
-	{0, 2, "C2", "POWER_COLLAPSE",
+	{0, 3, "C3", "POWER_COLLAPSE",
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE},
 
 	{1, 0, "C0", "WFI",
 		MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
 
-	{1, 1, "C1", "STANDALONE_POWER_COLLAPSE",
+	{1, 1, "C1", "RETENTION",
+		MSM_PM_SLEEP_MODE_RETENTION},
+
+	{1, 2, "C2", "STANDALONE_POWER_COLLAPSE",
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
 
 	{2, 0, "C0", "WFI",
 		MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
 
-	{2, 1, "C1", "STANDALONE_POWER_COLLAPSE",
+	{2, 1, "C1", "RETENTION",
+		MSM_PM_SLEEP_MODE_RETENTION},
+
+	{2, 2, "C2", "STANDALONE_POWER_COLLAPSE",
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
 
 	{3, 0, "C0", "WFI",
 		MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
 
-	{3, 1, "C1", "STANDALONE_POWER_COLLAPSE",
+	{3, 1, "C1", "RETENTION",
+		MSM_PM_SLEEP_MODE_RETENTION},
+
+	{3, 2, "C2", "STANDALONE_POWER_COLLAPSE",
 		MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
 };
 
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 36cdd86..c46c493 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -475,6 +475,12 @@
 	bool (*check_hdcp_hw_support)(void);
 };
 
+struct msm_mhl_platform_data {
+	int irq;
+	int (*gpio_setup)(int on);
+	void (*reset_pin)(int on);
+};
+
 struct msm_i2c_platform_data {
 	int clk_freq;
 	uint32_t rmutex;
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index e6a0175..04cfa71 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -638,8 +638,6 @@
 };
 
 int msm_camio_enable(struct platform_device *dev);
-int msm_camio_jpeg_clk_enable(void);
-int msm_camio_jpeg_clk_disable(void);
 int msm_camio_vpe_clk_enable(uint32_t);
 int msm_camio_vpe_clk_disable(void);
 
diff --git a/arch/arm/mach-msm/include/mach/iommu_domains.h b/arch/arm/mach-msm/include/mach/iommu_domains.h
index c17795a..74e1115 100644
--- a/arch/arm/mach-msm/include/mach/iommu_domains.h
+++ b/arch/arm/mach-msm/include/mach/iommu_domains.h
@@ -42,10 +42,6 @@
 			unsigned int partition_no,
 			unsigned long size);
 
-extern unsigned long msm_subsystem_get_domain_no(int subsys_id);
-
-extern unsigned long msm_subsystem_get_partition_no(int subsys_id);
-
 extern int msm_use_iommu(void);
 
 extern int msm_iommu_map_extra(struct iommu_domain *domain,
@@ -69,16 +65,6 @@
 			unsigned int partition_no,
 			unsigned long size) { return; }
 
-static inline unsigned long msm_subsystem_get_domain_no(int subsys_id)
-{
-	return 0xFFFFFFFF;
-}
-
-static inline unsigned long msm_subsystem_get_partition_no(int subsys_id)
-{
-	return 0xFFFFFFFF;
-}
-
 static inline int msm_use_iommu(void)
 {
 	return 0;
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index 1959f5d..dbc1389 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -227,40 +227,6 @@
 		return NULL;
 }
 
-static unsigned long subsystem_to_domain_tbl[] = {
-	VIDEO_DOMAIN,
-	VIDEO_DOMAIN,
-	CAMERA_DOMAIN,
-	DISPLAY_DOMAIN,
-	ROTATOR_DOMAIN,
-	0xFFFFFFFF
-};
-
-unsigned long msm_subsystem_get_domain_no(int subsys_id)
-{
-	if (subsys_id > INVALID_SUBSYS_ID && subsys_id <= MAX_SUBSYSTEM_ID &&
-	    subsys_id < ARRAY_SIZE(subsystem_to_domain_tbl))
-		return subsystem_to_domain_tbl[subsys_id];
-	else
-		return subsystem_to_domain_tbl[MAX_SUBSYSTEM_ID];
-}
-
-unsigned long msm_subsystem_get_partition_no(int subsys_id)
-{
-	switch (subsys_id) {
-	case MSM_SUBSYSTEM_VIDEO_FWARE:
-		return VIDEO_FIRMWARE_POOL;
-	case MSM_SUBSYSTEM_VIDEO:
-		return VIDEO_MAIN_POOL;
-	case MSM_SUBSYSTEM_CAMERA:
-	case MSM_SUBSYSTEM_DISPLAY:
-	case MSM_SUBSYSTEM_ROTATOR:
-		return GEN_POOL;
-	default:
-		return 0xFFFFFFFF;
-	}
-}
-
 unsigned long msm_allocate_iova_address(unsigned int iommu_domain,
 					unsigned int partition_no,
 					unsigned long size,
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
index a90be23..462543e 100644
--- a/arch/arm/mach-msm/ipc_router.h
+++ b/arch/arm/mach-msm/ipc_router.h
@@ -138,7 +138,7 @@
 struct msm_ipc_sock {
 	struct sock sk;
 	struct msm_ipc_port *port;
-	void *default_pil;
+	void *modem_pil;
 };
 
 enum write_data_type {
@@ -206,15 +206,4 @@
 int msm_ipc_router_init_sockets(void);
 void msm_ipc_router_exit_sockets(void);
 
-#if defined CONFIG_MSM_IPC_ROUTER_SMD_XPRT
-extern void *msm_ipc_load_default_node(void);
-
-extern void msm_ipc_unload_default_node(void *pil);
-#else
-static inline void *msm_ipc_load_default_node(void)
-{ return NULL; }
-
-static inline void msm_ipc_unload_default_node(void *pil) { }
-#endif
-
 #endif
diff --git a/arch/arm/mach-msm/ipc_router_smd_xprt.c b/arch/arm/mach-msm/ipc_router_smd_xprt.c
index 307b6ae..0cde393 100644
--- a/arch/arm/mach-msm/ipc_router_smd_xprt.c
+++ b/arch/arm/mach-msm/ipc_router_smd_xprt.c
@@ -19,7 +19,6 @@
 #include <linux/types.h>
 
 #include <mach/msm_smd.h>
-#include <mach/peripheral-loader.h>
 
 #include "ipc_router.h"
 #include "smd_private.h"
@@ -443,31 +442,6 @@
 	return 0;
 }
 
-void *msm_ipc_load_default_node(void)
-{
-	void *pil = NULL;
-	const char *peripheral;
-
-	peripheral = smd_edge_to_subsystem(SMD_APPS_MODEM);
-	if (peripheral && !strncmp(peripheral, "modem", 6)) {
-		pil = pil_get(peripheral);
-		if (IS_ERR(pil)) {
-			pr_err("%s: Failed to load %s\n",
-				__func__, peripheral);
-			pil = NULL;
-		}
-	}
-	return pil;
-}
-EXPORT_SYMBOL(msm_ipc_load_default_node);
-
-void msm_ipc_unload_default_node(void *pil)
-{
-	if (pil)
-		pil_put(pil);
-}
-EXPORT_SYMBOL(msm_ipc_unload_default_node);
-
 static struct platform_driver msm_ipc_router_smd_remote_driver[] = {
 	{
 		.probe		= msm_ipc_router_smd_remote_probe,
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index d1ed538..6e8c99e 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -26,15 +26,58 @@
 
 #include <net/sock.h>
 
+#include <mach/peripheral-loader.h>
+#include <mach/socinfo.h>
+
 #include "ipc_router.h"
 
 #define msm_ipc_sk(sk) ((struct msm_ipc_sock *)(sk))
 #define msm_ipc_sk_port(sk) ((struct msm_ipc_port *)(msm_ipc_sk(sk)->port))
+#define MODEM_LOAD_TIMEOUT (10 * HZ)
 
 static int sockets_enabled;
 static struct proto msm_ipc_proto;
 static const struct proto_ops msm_ipc_proto_ops;
 
+static void msm_ipc_router_unload_modem(void *pil)
+{
+	if (pil)
+		pil_put(pil);
+}
+
+static void *msm_ipc_router_load_modem(void)
+{
+	void *pil = NULL;
+	int rc;
+
+	/* Load GNSS for Standalone 8064 but not for Fusion 3 */
+	if (cpu_is_apq8064()) {
+		if (socinfo_get_platform_subtype() == 0x0)
+			pil = pil_get("gss");
+	} else {
+		pil = pil_get("modem");
+	}
+
+	if (IS_ERR(pil) || !pil) {
+		pr_debug("%s: modem load failed\n", __func__);
+		pil = NULL;
+	} else {
+		rc = wait_for_completion_interruptible_timeout(
+						&msm_ipc_remote_router_up,
+						MODEM_LOAD_TIMEOUT);
+		if (!rc)
+			rc = -ETIMEDOUT;
+		if (rc < 0) {
+			pr_err("%s: wait for remote router failed %d\n",
+				__func__, rc);
+			msm_ipc_router_unload_modem(pil);
+			pil = NULL;
+		}
+	}
+
+	return pil;
+}
+
 static struct sk_buff_head *msm_ipc_router_build_msg(unsigned int num_sect,
 					  struct iovec const *msg_sect,
 					  size_t total_len)
@@ -201,9 +244,9 @@
 	sock_init_data(sock, sk);
 	sk->sk_rcvtimeo = DEFAULT_RCV_TIMEO;
 
-	pil = msm_ipc_load_default_node();
+	pil = msm_ipc_router_load_modem();
 	msm_ipc_sk(sk)->port = port_ptr;
-	msm_ipc_sk(sk)->default_pil = pil;
+	msm_ipc_sk(sk)->modem_pil = pil;
 
 	return 0;
 }
@@ -452,12 +495,12 @@
 {
 	struct sock *sk = sock->sk;
 	struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
-	void *pil = msm_ipc_sk(sk)->default_pil;
+	void *pil = msm_ipc_sk(sk)->modem_pil;
 	int ret;
 
 	lock_sock(sk);
 	ret = msm_ipc_router_close_port(port_ptr);
-	msm_ipc_unload_default_node(pil);
+	msm_ipc_router_unload_modem(pil);
 	release_sock(sk);
 	sock_put(sk);
 	sock->sk = NULL;
diff --git a/arch/arm/mach-msm/pil-q6v5.c b/arch/arm/mach-msm/pil-q6v5.c
new file mode 100644
index 0000000..cd58a4c
--- /dev/null
+++ b/arch/arm/mach-msm/pil-q6v5.c
@@ -0,0 +1,199 @@
+/*
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/elf.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+
+#include "peripheral-loader.h"
+#include "pil-q6v5.h"
+
+/* Register Offsets */
+#define QDSP6SS_RESET			0x014
+#define QDSP6SS_GFMUX_CTL		0x020
+#define QDSP6SS_PWR_CTL			0x030
+
+/* QDSP6SS_RESET */
+#define Q6SS_CORE_ARES			BIT(1)
+#define Q6SS_ETM_ISDB_ARES		BIT(3)
+#define Q6SS_STOP_CORE			BIT(4)
+
+/* QDSP6SS_GFMUX_CTL */
+#define Q6SS_CLK_ENA			BIT(1)
+
+/* QDSP6SS_PWR_CTL */
+#define Q6SS_L2DATA_SLP_NRET_N		BIT(0)
+#define Q6SS_L2TAG_SLP_NRET_N		BIT(16)
+#define Q6SS_ETB_SLP_NRET_N		BIT(17)
+#define Q6SS_L2DATA_STBY_N		BIT(18)
+#define Q6SS_SLP_RET_N			BIT(19)
+#define Q6SS_CLAMP_IO			BIT(20)
+#define QDSS_BHS_ON			BIT(21)
+
+int pil_q6v5_make_proxy_votes(struct pil_desc *pil)
+{
+	int ret;
+	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+
+	ret = clk_prepare_enable(drv->xo);
+	if (ret) {
+		dev_err(pil->dev, "Failed to enable XO\n");
+		return ret;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(pil_q6v5_make_proxy_votes);
+
+void pil_q6v5_remove_proxy_votes(struct pil_desc *pil)
+{
+	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+	clk_disable_unprepare(drv->xo);
+}
+EXPORT_SYMBOL(pil_q6v5_remove_proxy_votes);
+
+int pil_q6v5_init_image(struct pil_desc *pil, const u8 *metadata,
+			       size_t size)
+{
+	const struct elf32_hdr *ehdr = (struct elf32_hdr *)metadata;
+	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+	drv->start_addr = ehdr->e_entry;
+	return 0;
+}
+EXPORT_SYMBOL(pil_q6v5_init_image);
+
+void pil_q6v5_shutdown(struct pil_desc *pil)
+{
+	u32 val;
+	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+
+	/* Turn off core clock */
+	val = readl_relaxed(drv->reg_base + QDSP6SS_GFMUX_CTL);
+	val &= ~Q6SS_CLK_ENA;
+	writel_relaxed(val, drv->reg_base + QDSP6SS_GFMUX_CTL);
+
+	/* Clamp IO */
+	val = readl_relaxed(drv->reg_base + QDSP6SS_PWR_CTL);
+	val |= Q6SS_CLAMP_IO;
+	writel_relaxed(val, drv->reg_base + QDSP6SS_PWR_CTL);
+
+	/* Turn off Q6 memories */
+	val &= ~(Q6SS_L2DATA_SLP_NRET_N | Q6SS_SLP_RET_N |
+		 Q6SS_L2TAG_SLP_NRET_N | Q6SS_ETB_SLP_NRET_N |
+		 Q6SS_L2DATA_STBY_N);
+	writel_relaxed(Q6SS_CLAMP_IO, drv->reg_base + QDSP6SS_PWR_CTL);
+
+	/* Assert Q6 resets */
+	val = readl_relaxed(drv->reg_base + QDSP6SS_RESET);
+	val = (Q6SS_CORE_ARES | Q6SS_ETM_ISDB_ARES);
+	writel_relaxed(val, drv->reg_base + QDSP6SS_RESET);
+
+	/* Kill power at block headswitch (affects LPASS only) */
+	val = readl_relaxed(drv->reg_base + QDSP6SS_PWR_CTL);
+	val &= ~QDSS_BHS_ON;
+	writel_relaxed(val, drv->reg_base + QDSP6SS_PWR_CTL);
+}
+EXPORT_SYMBOL(pil_q6v5_shutdown);
+
+int pil_q6v5_reset(struct pil_desc *pil)
+{
+	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+	u32 val;
+
+	/* Assert resets, stop core */
+	val = readl_relaxed(drv->reg_base + QDSP6SS_RESET);
+	val |= (Q6SS_CORE_ARES | Q6SS_ETM_ISDB_ARES | Q6SS_STOP_CORE);
+	writel_relaxed(val, drv->reg_base + QDSP6SS_RESET);
+
+	/* Enable power block headswitch (only affects LPASS) */
+	val = readl_relaxed(drv->reg_base + QDSP6SS_PWR_CTL);
+	val |= QDSS_BHS_ON;
+	writel_relaxed(val, drv->reg_base + QDSP6SS_PWR_CTL);
+
+	/* Turn on memories */
+	val = readl_relaxed(drv->reg_base + QDSP6SS_PWR_CTL);
+	val |= Q6SS_L2DATA_SLP_NRET_N | Q6SS_SLP_RET_N |
+	       Q6SS_L2TAG_SLP_NRET_N | Q6SS_ETB_SLP_NRET_N |
+	       Q6SS_L2DATA_STBY_N;
+	writel_relaxed(val, drv->reg_base + QDSP6SS_PWR_CTL);
+
+	/* Remove IO clamp */
+	val &= ~Q6SS_CLAMP_IO;
+	writel_relaxed(val, drv->reg_base + QDSP6SS_PWR_CTL);
+
+	/* Bring core out of reset */
+	val = Q6SS_STOP_CORE;
+	writel_relaxed(val, drv->reg_base + QDSP6SS_RESET);
+
+	/* Turn on core clock */
+	val = readl_relaxed(drv->reg_base + QDSP6SS_GFMUX_CTL);
+	val |= Q6SS_CLK_ENA;
+	writel_relaxed(val, drv->reg_base + QDSP6SS_GFMUX_CTL);
+
+	/* Start core execution */
+	val = readl_relaxed(drv->reg_base + QDSP6SS_RESET);
+	val &= ~Q6SS_STOP_CORE;
+	writel_relaxed(val, drv->reg_base + QDSP6SS_RESET);
+
+	return 0;
+}
+EXPORT_SYMBOL(pil_q6v5_reset);
+
+struct pil_desc __devinit *pil_q6v5_init(struct platform_device *pdev)
+{
+	struct q6v5_data *drv;
+	struct resource *res;
+	struct pil_desc *desc;
+	int ret;
+
+	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+	if (!drv)
+		return ERR_PTR(-ENOMEM);
+	platform_set_drvdata(pdev, drv);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return ERR_PTR(-EINVAL);
+	drv->reg_base = devm_ioremap(&pdev->dev, res->start,
+				     resource_size(res));
+	if (!drv->reg_base)
+		return ERR_PTR(-ENOMEM);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	drv->clk_base = devm_ioremap(&pdev->dev, res->start,
+				     resource_size(res));
+	if (!drv->clk_base)
+		return ERR_PTR(-ENOMEM);
+
+	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+	if (!desc)
+		return ERR_PTR(-ENOMEM);
+
+	ret = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
+				      &desc->name);
+	if (ret)
+		return ERR_PTR(ret);
+
+	drv->xo = devm_clk_get(&pdev->dev, "xo");
+	if (IS_ERR(drv->xo))
+		return ERR_CAST(drv->xo);
+
+	desc->dev = &pdev->dev;
+
+	return desc;
+}
+EXPORT_SYMBOL(pil_q6v5_init);
diff --git a/arch/arm/mach-msm/pil-q6v5.h b/arch/arm/mach-msm/pil-q6v5.h
new file mode 100644
index 0000000..23471d1
--- /dev/null
+++ b/arch/arm/mach-msm/pil-q6v5.h
@@ -0,0 +1,42 @@
+/*
+ * 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_PIL_Q6V5_H
+#define __MSM_PIL_Q6V5_H
+
+struct regulator;
+struct clk;
+struct pil_device;
+struct pil_desc;
+struct platform_device;
+
+struct q6v5_data {
+	void __iomem *reg_base;
+	void __iomem *clk_base;
+	void __iomem *rmb_base;
+	unsigned long start_addr;
+	struct regulator *vreg;
+	bool vreg_enabled;
+	int self_auth;
+	struct clk *xo;
+	struct pil_device *pil;
+};
+
+int pil_q6v5_make_proxy_votes(struct pil_desc *pil);
+void pil_q6v5_remove_proxy_votes(struct pil_desc *pil);
+int pil_q6v5_init_image(struct pil_desc *pil, const u8 *metadata,
+			size_t size);
+void pil_q6v5_shutdown(struct pil_desc *pil);
+int pil_q6v5_reset(struct pil_desc *pil);
+struct pil_desc *pil_q6v5_init(struct platform_device *pdev);
+
+#endif
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 2b0cc18..43e7032 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -105,6 +105,7 @@
 static char *msm_pm_sleep_mode_labels[MSM_PM_SLEEP_MODE_NR] = {
 	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = "power_collapse",
 	[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT] = "wfi",
+	[MSM_PM_SLEEP_MODE_RETENTION] = "retention",
 	[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE] =
 		"standalone_power_collapse",
 };
@@ -324,6 +325,7 @@
 enum msm_pm_time_stats_id {
 	MSM_PM_STAT_REQUESTED_IDLE,
 	MSM_PM_STAT_IDLE_WFI,
+	MSM_PM_STAT_RETENTION,
 	MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
 	MSM_PM_STAT_IDLE_POWER_COLLAPSE,
 	MSM_PM_STAT_SUSPEND,
@@ -617,6 +619,19 @@
 	msm_arch_idle();
 }
 
+
+static void msm_pm_retention(void)
+{
+	int ret = 0;
+
+	msm_pm_config_hw_before_swfi();
+	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_RETENTION, false);
+	WARN_ON(ret);
+	msm_arch_idle();
+	ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
+	WARN_ON(ret);
+}
+
 #ifdef CONFIG_CACHE_L2X0
 static inline bool msm_pm_l2x0_power_collapse(void)
 {
@@ -810,6 +825,11 @@
 			}
 			/* fall through */
 
+		case MSM_PM_SLEEP_MODE_RETENTION:
+			if (!allow)
+				break;
+			/* fall through */
+
 		case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
 			if (!allow)
 				break;
@@ -884,6 +904,13 @@
 #endif
 		break;
 
+	case MSM_PM_SLEEP_MODE_RETENTION:
+		msm_pm_retention();
+#ifdef CONFIG_MSM_IDLE_STATS
+		exit_stat = MSM_PM_STAT_RETENTION;
+#endif
+		break;
+
 	case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
 		msm_pm_power_collapse_standalone(true);
 #ifdef CONFIG_MSM_IDLE_STATS
@@ -982,6 +1009,10 @@
 		per_cpu(msm_pm_last_slp_mode, cpu)
 			= MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE;
 		msm_pm_power_collapse_standalone(false);
+	} else if (allow[MSM_PM_SLEEP_MODE_RETENTION]) {
+		per_cpu(msm_pm_last_slp_mode, cpu)
+			= MSM_PM_SLEEP_MODE_RETENTION;
+		msm_pm_retention();
 	} else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
 		per_cpu(msm_pm_last_slp_mode, cpu)
 			= MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE;
@@ -1108,6 +1139,10 @@
 		if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
 			pr_info("%s: standalone power collapse\n", __func__);
 		msm_pm_power_collapse_standalone(false);
+	} else if (allow[MSM_PM_SLEEP_MODE_RETENTION]) {
+		if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
+			pr_info("%s: retention\n", __func__);
+		msm_pm_retention();
 	} else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
 		if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
 			pr_info("%s: swfi\n", __func__);
@@ -1195,6 +1230,10 @@
 		stats[MSM_PM_STAT_IDLE_WFI].first_bucket_time =
 			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
 
+		stats[MSM_PM_STAT_RETENTION].name = "retention";
+		stats[MSM_PM_STAT_RETENTION].first_bucket_time =
+			CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
+
 		stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].name =
 			"idle-standalone-power-collapse";
 		stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].
diff --git a/arch/arm/mach-msm/pm-data.c b/arch/arm/mach-msm/pm-data.c
index d7001d7..6f4743f 100644
--- a/arch/arm/mach-msm/pm-data.c
+++ b/arch/arm/mach-msm/pm-data.c
@@ -28,6 +28,13 @@
 		.suspend_enabled = 0,
 	},
 
+	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_RETENTION)] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 0,
+		.suspend_enabled = 0,
+	},
+
 	[MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
 		.idle_supported = 1,
 		.suspend_supported = 1,
@@ -49,6 +56,13 @@
 		.suspend_enabled = 0,
 	},
 
+	[MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_RETENTION)] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 0,
+		.suspend_enabled = 0,
+	},
+
 	[MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
 		.idle_supported = 1,
 		.suspend_supported = 0,
@@ -70,6 +84,13 @@
 		.suspend_enabled = 0,
 	},
 
+	[MSM_PM_MODE(2, MSM_PM_SLEEP_MODE_RETENTION)] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 0,
+		.suspend_enabled = 0,
+	},
+
 	[MSM_PM_MODE(2, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
 		.idle_supported = 1,
 		.suspend_supported = 0,
@@ -91,6 +112,13 @@
 		.suspend_enabled = 0,
 	},
 
+	[MSM_PM_MODE(3, MSM_PM_SLEEP_MODE_RETENTION)] = {
+		.idle_supported = 1,
+		.suspend_supported = 1,
+		.idle_enabled = 0,
+		.suspend_enabled = 0,
+	},
+
 	[MSM_PM_MODE(3, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
 		.idle_supported = 1,
 		.suspend_supported = 0,
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index 7ef3c34..09494a0 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -44,13 +44,14 @@
 };
 
 enum msm_pm_sleep_mode {
-	MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND,
-	MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
-	MSM_PM_SLEEP_MODE_APPS_SLEEP,
-	MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT,
-	MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
-	MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN,
-	MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
+	MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT = 0,
+	MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT = 1,
+	MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE = 2,
+	MSM_PM_SLEEP_MODE_POWER_COLLAPSE = 3,
+	MSM_PM_SLEEP_MODE_APPS_SLEEP = 4,
+	MSM_PM_SLEEP_MODE_RETENTION = MSM_PM_SLEEP_MODE_APPS_SLEEP,
+	MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND = 5,
+	MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN = 6,
 	MSM_PM_SLEEP_MODE_NR
 };
 
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index 48e0135..ba3129d8 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -946,8 +946,15 @@
 
 	ac = audio->ac;
 	/* Offset with  appropriate meta */
-	param.paddr = buf_node->paddr + sizeof(struct dec_meta_in);
-	param.len = buf_node->buf.data_len - sizeof(struct dec_meta_in);
+	if (audio->feedback) {
+		/* Non Tunnel mode */
+		param.paddr = buf_node->paddr + sizeof(struct dec_meta_in);
+		param.len = buf_node->buf.data_len - sizeof(struct dec_meta_in);
+	} else {
+		/* Tunnel mode */
+		param.paddr = buf_node->paddr;
+		param.len = buf_node->buf.data_len;
+	}
 	param.msw_ts = buf_node->meta_info.meta_in.ntimestamp.highpart;
 	param.lsw_ts = buf_node->meta_info.meta_in.ntimestamp.lowpart;
 	/* If no meta_info enaled, indicate no time stamp valid */
diff --git a/arch/arm/mach-msm/subsystem_map.c b/arch/arm/mach-msm/subsystem_map.c
index b5ff244..d6a17e6 100644
--- a/arch/arm/mach-msm/subsystem_map.c
+++ b/arch/arm/mach-msm/subsystem_map.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -34,6 +34,15 @@
 static struct rb_root phys_root;
 DEFINE_MUTEX(msm_buffer_mutex);
 
+static unsigned long subsystem_to_domain_tbl[] = {
+	VIDEO_DOMAIN,
+	VIDEO_DOMAIN,
+	CAMERA_DOMAIN,
+	DISPLAY_DOMAIN,
+	ROTATOR_DOMAIN,
+	0xFFFFFFFF
+};
+
 static struct msm_buffer_node *find_buffer(void *key)
 {
 	struct rb_root *root = &buffer_root;
@@ -208,6 +217,31 @@
 	return 0;
 }
 
+static unsigned long msm_subsystem_get_domain_no(int subsys_id)
+{
+	if (subsys_id > INVALID_SUBSYS_ID && subsys_id <= MAX_SUBSYSTEM_ID &&
+	    subsys_id < ARRAY_SIZE(subsystem_to_domain_tbl))
+		return subsystem_to_domain_tbl[subsys_id];
+	else
+		return subsystem_to_domain_tbl[MAX_SUBSYSTEM_ID];
+}
+
+static unsigned long msm_subsystem_get_partition_no(int subsys_id)
+{
+	switch (subsys_id) {
+	case MSM_SUBSYSTEM_VIDEO_FWARE:
+		return VIDEO_FIRMWARE_POOL;
+	case MSM_SUBSYSTEM_VIDEO:
+		return VIDEO_MAIN_POOL;
+	case MSM_SUBSYSTEM_CAMERA:
+	case MSM_SUBSYSTEM_DISPLAY:
+	case MSM_SUBSYSTEM_ROTATOR:
+		return GEN_POOL;
+	default:
+		return 0xFFFFFFFF;
+	}
+}
+
 phys_addr_t msm_subsystem_check_iova_mapping(int subsys_id, unsigned long iova)
 {
 	struct iommu_domain *subsys_domain;
diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c
index 47bc750..865fcc2 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -1303,15 +1303,15 @@
 			msm_rotator_dev->img_info[first_free_index];
 		*(msm_rotator_dev->img_info[first_free_index]) = info;
 		msm_rotator_dev->fd_info[first_free_index] = fd_info;
-
-		if (copy_to_user((void __user *)arg, &info, sizeof(info)))
-			rc = -EFAULT;
 	} else if (s == MAX_SESSIONS) {
 		dev_dbg(msm_rotator_dev->device, "%s: all sessions in use\n",
 			__func__);
 		rc = -EBUSY;
 	}
 
+	if (rc == 0 && copy_to_user((void __user *)arg, &info, sizeof(info)))
+		rc = -EFAULT;
+
 rotator_start_exit:
 	mutex_unlock(&msm_rotator_dev->rotator_lock);
 
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 0cec423..6823a5a 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -484,7 +484,7 @@
 	valid_handle = ion_handle_validate(client, handle);
 	if (!valid_handle) {
 		mutex_unlock(&client->lock);
-		WARN("%s: invalid handle passed to free.\n", __func__);
+		WARN(1, "%s: invalid handle passed to free.\n", __func__);
 		return;
 	}
 	ion_handle_put(handle);
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 7e84692..5faff24 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -122,6 +122,40 @@
 }
 
 /**
+ * kgsl_cancel_events_ctxt - Cancel all events for a context
+ * @device - KGSL device for the events to cancel
+ * @ctxt - context whose events we want to cancel
+ *
+ */
+static void kgsl_cancel_events_ctxt(struct kgsl_device *device,
+	struct kgsl_context *context)
+{
+	struct kgsl_event *event, *event_tmp;
+	unsigned int id, cur;
+
+	cur = device->ftbl->readtimestamp(device, context,
+			KGSL_TIMESTAMP_RETIRED);
+	id = context->id;
+
+	list_for_each_entry_safe(event, event_tmp, &device->events, list) {
+		if (event->context != context)
+			continue;
+
+		/*
+		 * "cancel" the events by calling their callback.
+		 * Currently, events are used for lock and memory
+		 * management, so if the process is dying the right
+		 * thing to do is release or free.
+		 */
+		if (event->func)
+			event->func(device, event->priv, id, cur);
+
+		list_del(&event->list);
+		kfree(event);
+	}
+}
+
+/**
  * kgsl_cancel_events - Cancel all events for a process
  * @device - KGSL device for the events to cancel
  * @owner - driver instance that owns the events to cancel
@@ -1240,6 +1274,8 @@
 		goto done;
 	}
 
+	kgsl_cancel_events_ctxt(dev_priv->device, context);
+
 	if (dev_priv->device->ftbl->drawctxt_destroy)
 		dev_priv->device->ftbl->drawctxt_destroy(dev_priv->device,
 			context);
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 7eb5ee9..8077323e 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -36,7 +36,8 @@
 {
 	int i;
 	/* For IOMMU only unmap the global structures to global pt */
-	if ((KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type) &&
+	if ((KGSL_MMU_TYPE_NONE != kgsl_mmu_type) &&
+		(KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type) &&
 		(KGSL_MMU_GLOBAL_PT !=  pt->name))
 		return 0;
 	for (i = 0; i < KGSL_DEVICE_MAX; i++) {
@@ -47,6 +48,36 @@
 	return 0;
 }
 
+
+static int kgsl_setup_pt(struct kgsl_pagetable *pt)
+{
+	int i = 0;
+	int status = 0;
+
+	/* 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))
+		return 0;
+	for (i = 0; i < KGSL_DEVICE_MAX; i++) {
+		struct kgsl_device *device = kgsl_driver.devp[i];
+		if (device) {
+			status = device->ftbl->setup_pt(device, pt);
+			if (status)
+				goto error_pt;
+		}
+	}
+	return status;
+error_pt:
+	while (i >= 0) {
+		struct kgsl_device *device = kgsl_driver.devp[i];
+		if (device)
+			device->ftbl->cleanup_pt(device, pt);
+		i--;
+	}
+	return status;
+}
+
 static void kgsl_destroy_pagetable(struct kref *kref)
 {
 	struct kgsl_pagetable *pagetable = container_of(kref,
@@ -340,9 +371,15 @@
 	mmu->device = device;
 
 	if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type) {
-		dev_info(device->dev, "|%s| MMU type set for device is "
-			"NOMMU\n", __func__);
-		return 0;
+		int status = 0;
+		status = kgsl_allocate_contiguous(&mmu->setstate_memory, 64);
+		if (!status) {
+			kgsl_sharedmem_set(&mmu->setstate_memory, 0, 0,
+					mmu->setstate_memory.size);
+			dev_info(device->dev, "|%s| MMU type set for device is "
+				"NOMMU\n", __func__);
+		}
+		return status;
 	} else if (KGSL_MMU_TYPE_GPU == kgsl_mmu_type)
 		mmu->mmu_ops = &gpummu_ops;
 	else if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type)
@@ -358,6 +395,9 @@
 
 	if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE) {
 		kgsl_regwrite(device, MH_MMU_CONFIG, 0);
+		/* Setup gpuaddr of global mappings */
+		if (!mmu->setstate_memory.gpuaddr)
+			kgsl_setup_pt(NULL);
 		return 0;
 	} else {
 		return mmu->mmu_ops->mmu_start(device);
@@ -385,34 +425,6 @@
 }
 EXPORT_SYMBOL(kgsl_mh_intrcallback);
 
-static int kgsl_setup_pt(struct kgsl_pagetable *pt)
-{
-	int i = 0;
-	int status = 0;
-
-	/* For IOMMU only map the global structures to global pt */
-	if ((KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type) &&
-		(KGSL_MMU_GLOBAL_PT !=  pt->name))
-		return 0;
-	for (i = 0; i < KGSL_DEVICE_MAX; i++) {
-		struct kgsl_device *device = kgsl_driver.devp[i];
-		if (device) {
-			status = device->ftbl->setup_pt(device, pt);
-			if (status)
-				goto error_pt;
-		}
-	}
-	return status;
-error_pt:
-	while (i >= 0) {
-		struct kgsl_device *device = kgsl_driver.devp[i];
-		if (device)
-			device->ftbl->cleanup_pt(device, pt);
-		i--;
-	}
-	return status;
-}
-
 static struct kgsl_pagetable *kgsl_mmu_createpagetableobject(
 				unsigned int name)
 {
@@ -589,7 +601,14 @@
 
 	if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE) {
 		if (memdesc->sglen == 1) {
-			memdesc->gpuaddr = sg_phys(memdesc->sg);
+			memdesc->gpuaddr = sg_dma_address(memdesc->sg);
+			if (!memdesc->gpuaddr)
+				memdesc->gpuaddr = sg_phys(memdesc->sg);
+			if (!memdesc->gpuaddr) {
+				KGSL_CORE_ERR("Unable to get a valid physical "
+					"address for memdesc\n");
+				return -EINVAL;
+			}
 			return 0;
 		} else {
 			KGSL_CORE_ERR("Memory is not contigious "
@@ -741,9 +760,10 @@
 {
 	struct kgsl_mmu *mmu = &device->mmu;
 
-	if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE)
+	if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE) {
+		kgsl_sharedmem_free(&mmu->setstate_memory);
 		return 0;
-	else
+	} else
 		return mmu->mmu_ops->mmu_close(device);
 }
 EXPORT_SYMBOL(kgsl_mmu_close);
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 3dea4e9..4fd6e49 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -3,10 +3,10 @@
 CFLAGS_REMOVE_msm_vfe8x.o = -Wframe-larger-than=1024
 endif
 
+EXTRA_CFLAGS += -Idrivers/media/video/msm/io
 obj-$(CONFIG_MSM_CAMERA) += io/
 ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
   EXTRA_CFLAGS += -Idrivers/media/video/msm/csi
-  EXTRA_CFLAGS += -Idrivers/media/video/msm/io
   EXTRA_CFLAGS += -Idrivers/media/video/msm/sensors
   obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o msm_mctl_pp.o
   obj-$(CONFIG_MSM_CAMERA) += sensors/ actuators/ csi/
diff --git a/drivers/media/video/msm/gemini/msm_gemini_platform.c b/drivers/media/video/msm/gemini/msm_gemini_platform.c
index ee0ff2f..fb5b035 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_platform.c
+++ b/drivers/media/video/msm/gemini/msm_gemini_platform.c
@@ -20,6 +20,7 @@
 #include <mach/msm_subsystem_map.h>
 
 #include "msm_gemini_platform.h"
+#include "msm_gemini_sync.h"
 #include "msm_gemini_common.h"
 #include "msm_gemini_hw.h"
 
@@ -80,6 +81,20 @@
 	return 0;
 }
 
+static struct msm_cam_clk_info gemini_8x_clk_info[] = {
+	{"ijpeg_clk", 228571000},
+	{"ijpeg_pclk", -1},
+};
+
+static struct msm_cam_clk_info gemini_7x_clk_info[] = {
+	{"jpeg_clk", 153600000},
+	{"jpeg_pclk", -1},
+};
+
+static struct msm_cam_clk_info gemini_imem_clk_info[] = {
+	{"imem_clk", -1},
+};
+
 int msm_gemini_platform_init(struct platform_device *pdev,
 	struct resource **mem,
 	void **base,
@@ -91,6 +106,8 @@
 	int gemini_irq;
 	struct resource *gemini_mem, *gemini_io, *gemini_irq_res;
 	void *gemini_base;
+	struct msm_gemini_device *pgmn_dev =
+		(struct msm_gemini_device *) context;
 
 	gemini_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!gemini_mem) {
@@ -119,10 +136,43 @@
 		goto fail1;
 	}
 
-	rc = msm_camio_jpeg_clk_enable();
-	if (rc) {
-		GMN_PR_ERR("%s: clk failed rc = %d\n", __func__, rc);
-		goto fail2;
+	pgmn_dev->hw_version = GEMINI_8X60;
+	rc = msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_8x_clk_info,
+	 pgmn_dev->gemini_clk, ARRAY_SIZE(gemini_8x_clk_info), 1);
+	if (rc < 0) {
+		pgmn_dev->hw_version = GEMINI_7X;
+		rc = msm_cam_clk_enable(&pgmn_dev->pdev->dev,
+			gemini_7x_clk_info, pgmn_dev->gemini_clk,
+			ARRAY_SIZE(gemini_7x_clk_info), 1);
+		if (rc < 0) {
+			GMN_PR_ERR("%s: clk failed rc = %d\n", __func__, rc);
+			goto fail2;
+		}
+	} else {
+		rc = msm_cam_clk_enable(&pgmn_dev->pdev->dev,
+				gemini_imem_clk_info, &pgmn_dev->gemini_clk[2],
+				ARRAY_SIZE(gemini_imem_clk_info), 1);
+		if (!rc)
+			pgmn_dev->hw_version = GEMINI_8960;
+	}
+
+	if (pgmn_dev->hw_version != GEMINI_7X) {
+		if (pgmn_dev->gemini_fs == NULL) {
+			pgmn_dev->gemini_fs =
+				regulator_get(&pgmn_dev->pdev->dev, "fs_ijpeg");
+			if (IS_ERR(pgmn_dev->gemini_fs)) {
+				pr_err("%s: Regulator FS_ijpeg get failed %ld\n",
+					__func__, PTR_ERR(pgmn_dev->gemini_fs));
+				pgmn_dev->gemini_fs = NULL;
+				goto gemini_fs_failed;
+			} else if (regulator_enable(pgmn_dev->gemini_fs)) {
+				pr_err("%s: Regulator FS_ijpeg enable failed\n",
+								__func__);
+				regulator_put(pgmn_dev->gemini_fs);
+				pgmn_dev->gemini_fs = NULL;
+				goto gemini_fs_failed;
+			}
+		}
 	}
 
 	msm_gemini_hw_init(gemini_base, resource_size(gemini_mem));
@@ -146,7 +196,21 @@
 	return rc;
 
 fail3:
-	msm_camio_jpeg_clk_disable();
+	if (pgmn_dev->hw_version != GEMINI_7X) {
+		regulator_disable(pgmn_dev->gemini_fs);
+		regulator_put(pgmn_dev->gemini_fs);
+		pgmn_dev->gemini_fs = NULL;
+	}
+gemini_fs_failed:
+	if (pgmn_dev->hw_version == GEMINI_8960)
+		msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_imem_clk_info,
+		 &pgmn_dev->gemini_clk[2], ARRAY_SIZE(gemini_imem_clk_info), 0);
+	if (pgmn_dev->hw_version != GEMINI_7X)
+		msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_8x_clk_info,
+		pgmn_dev->gemini_clk, ARRAY_SIZE(gemini_8x_clk_info), 0);
+	else
+		msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_7x_clk_info,
+		pgmn_dev->gemini_clk, ARRAY_SIZE(gemini_7x_clk_info), 0);
 fail2:
 	iounmap(gemini_base);
 fail1:
@@ -158,10 +222,28 @@
 int msm_gemini_platform_release(struct resource *mem, void *base, int irq,
 	void *context)
 {
-	int result;
+	int result = 0;
+	struct msm_gemini_device *pgmn_dev =
+		(struct msm_gemini_device *) context;
 
 	free_irq(irq, context);
-	result = msm_camio_jpeg_clk_disable();
+
+	if (pgmn_dev->hw_version != GEMINI_7X) {
+		regulator_disable(pgmn_dev->gemini_fs);
+		regulator_put(pgmn_dev->gemini_fs);
+		pgmn_dev->gemini_fs = NULL;
+	}
+
+	if (pgmn_dev->hw_version == GEMINI_8960)
+		msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_imem_clk_info,
+		 &pgmn_dev->gemini_clk[2], ARRAY_SIZE(gemini_imem_clk_info), 0);
+	if (pgmn_dev->hw_version != GEMINI_7X)
+		msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_8x_clk_info,
+		pgmn_dev->gemini_clk, ARRAY_SIZE(gemini_8x_clk_info), 0);
+	else
+		msm_cam_clk_enable(&pgmn_dev->pdev->dev, gemini_7x_clk_info,
+		pgmn_dev->gemini_clk, ARRAY_SIZE(gemini_7x_clk_info), 0);
+
 	iounmap(base);
 	release_mem_region(mem->start, resource_size(mem));
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
diff --git a/drivers/media/video/msm/gemini/msm_gemini_sync.h b/drivers/media/video/msm/gemini/msm_gemini_sync.h
index a47e766..1c6726d 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_sync.h
+++ b/drivers/media/video/msm/gemini/msm_gemini_sync.h
@@ -21,6 +21,10 @@
 #include <media/v4l2-subdev.h>
 #include "msm_gemini_core.h"
 
+#define GEMINI_7X 0x1
+#define GEMINI_8X60 (0x1 << 1)
+#define GEMINI_8960 (0x1 << 2)
+
 struct msm_gemini_q {
 	char const	*name;
 	struct list_head  q;
@@ -39,6 +43,9 @@
 	struct resource        *mem;
 	int                     irq;
 	void                   *base;
+	struct clk *gemini_clk[3];
+	struct regulator *gemini_fs;
+	uint32_t hw_version;
 
 	struct device *device;
 	struct cdev   cdev;
diff --git a/drivers/media/video/msm/io/msm_io_8960.c b/drivers/media/video/msm/io/msm_io_8960.c
index 1ab4223..f9c454a 100644
--- a/drivers/media/video/msm/io/msm_io_8960.c
+++ b/drivers/media/video/msm/io/msm_io_8960.c
@@ -27,141 +27,11 @@
 
 #define BUFF_SIZE_128 128
 
-static struct clk *camio_jpeg_clk;
-static struct clk *camio_jpeg_pclk;
-static struct clk *camio_imem_clk;
-static struct regulator *fs_ijpeg;
-
-int msm_camio_clk_enable(enum msm_camio_clk_type clktype)
-{
-	int rc = 0;
-	struct clk *clk = NULL;
-
-	switch (clktype) {
-	case CAMIO_JPEG_CLK:
-		camio_jpeg_clk =
-		clk = clk_get(NULL, "ijpeg_clk");
-		clk_set_rate(clk, 228571000);
-		break;
-
-	case CAMIO_JPEG_PCLK:
-		camio_jpeg_pclk =
-		clk = clk_get(NULL, "ijpeg_pclk");
-		break;
-
-	case CAMIO_IMEM_CLK:
-		camio_imem_clk =
-		clk = clk_get(NULL, "imem_clk");
-		break;
-
-	default:
-		break;
-	}
-
-	if (!IS_ERR(clk))
-		rc = clk_enable(clk);
-	else
-		rc = PTR_ERR(clk);
-
-	if (rc < 0)
-		pr_err("%s(%d) failed %d\n", __func__, clktype, rc);
-
-	return rc;
-}
-
-int msm_camio_clk_disable(enum msm_camio_clk_type clktype)
-{
-	int rc = 0;
-	struct clk *clk = NULL;
-
-	switch (clktype) {
-	case CAMIO_JPEG_CLK:
-		clk = camio_jpeg_clk;
-		break;
-
-	case CAMIO_JPEG_PCLK:
-		clk = camio_jpeg_pclk;
-		break;
-
-	case CAMIO_IMEM_CLK:
-		clk = camio_imem_clk;
-		break;
-
-	default:
-		break;
-	}
-
-	if (!IS_ERR(clk)) {
-		clk_disable(clk);
-		clk_put(clk);
-	} else
-		rc = PTR_ERR(clk);
-
-	if (rc < 0)
-		pr_err("%s(%d) failed %d\n", __func__, clktype, rc);
-
-	return rc;
-}
-
 void msm_camio_clk_rate_set_2(struct clk *clk, int rate)
 {
 	clk_set_rate(clk, rate);
 }
 
-int msm_camio_jpeg_clk_disable(void)
-{
-	int rc = 0;
-	rc = msm_camio_clk_disable(CAMIO_JPEG_PCLK);
-	if (rc < 0)
-		return rc;
-	rc = msm_camio_clk_disable(CAMIO_JPEG_CLK);
-	if (rc < 0)
-		return rc;
-	rc = msm_camio_clk_disable(CAMIO_IMEM_CLK);
-	if (rc < 0)
-		return rc;
-
-	if (fs_ijpeg) {
-		rc = regulator_disable(fs_ijpeg);
-		if (rc < 0) {
-			pr_err("%s: Regulator disable failed %d\n",
-						__func__, rc);
-			return rc;
-		}
-		regulator_put(fs_ijpeg);
-	}
-	CDBG("%s: exit %d\n", __func__, rc);
-	return rc;
-}
-
-int msm_camio_jpeg_clk_enable(void)
-{
-	int rc = 0;
-	fs_ijpeg = regulator_get(NULL, "fs_ijpeg");
-	if (IS_ERR(fs_ijpeg)) {
-		pr_err("%s: Regulator FS_IJPEG get failed %ld\n",
-			__func__, PTR_ERR(fs_ijpeg));
-		fs_ijpeg = NULL;
-	} else if (regulator_enable(fs_ijpeg)) {
-		pr_err("%s: Regulator FS_IJPEG enable failed\n", __func__);
-		regulator_put(fs_ijpeg);
-	}
-
-	rc = msm_camio_clk_enable(CAMIO_JPEG_CLK);
-	if (rc < 0)
-		return rc;
-	rc = msm_camio_clk_enable(CAMIO_JPEG_PCLK);
-	if (rc < 0)
-		return rc;
-
-	rc = msm_camio_clk_enable(CAMIO_IMEM_CLK);
-	if (rc < 0)
-		return rc;
-
-	CDBG("%s: exit %d\n", __func__, rc);
-	return rc;
-}
-
 void msm_camio_bus_scale_cfg(struct msm_bus_scale_pdata *cam_bus_scale_table,
 		enum msm_bus_perf_setting perf_setting)
 {
diff --git a/drivers/media/video/msm/io/msm_io_8x60.c b/drivers/media/video/msm/io/msm_io_8x60.c
index 4e8dc25..baa1245 100644
--- a/drivers/media/video/msm/io/msm_io_8x60.c
+++ b/drivers/media/video/msm/io/msm_io_8x60.c
@@ -85,12 +85,9 @@
 static struct clk *camio_csi0_pclk;
 static struct clk *camio_csi1_pclk;
 static struct clk *camio_vfe_pclk;
-static struct clk *camio_jpeg_clk;
-static struct clk *camio_jpeg_pclk;
 static struct clk *camio_vpe_clk;
 static struct clk *camio_vpe_pclk;
 static struct regulator *fs_vfe;
-static struct regulator *fs_ijpeg;
 static struct regulator *fs_vpe;
 static struct regulator *ldo15;
 static struct regulator *lvs0;
@@ -254,17 +251,6 @@
 		clk = clk_get(&camio_dev->dev, "csi_pclk");
 		break;
 
-	case CAMIO_JPEG_CLK:
-		camio_jpeg_clk =
-		clk = clk_get(NULL, "ijpeg_clk");
-		msm_camio_clk_rate_set_2(clk, 228571000);
-		break;
-
-	case CAMIO_JPEG_PCLK:
-		camio_jpeg_pclk =
-		clk = clk_get(NULL, "ijpeg_pclk");
-		break;
-
 	case CAMIO_VPE_CLK:
 		camio_vpe_clk =
 		clk = clk_get(NULL, "vpe_clk");
@@ -334,14 +320,6 @@
 		clk = camio_csi1_pclk;
 		break;
 
-	case CAMIO_JPEG_CLK:
-		clk = camio_jpeg_clk;
-		break;
-
-	case CAMIO_JPEG_PCLK:
-		clk = camio_jpeg_pclk;
-		break;
-
 	case CAMIO_VPE_CLK:
 		clk = camio_vpe_clk;
 		break;
@@ -393,47 +371,6 @@
 	return IRQ_HANDLED;
 }
 
-int msm_camio_jpeg_clk_disable(void)
-{
-	int rc = 0;
-	if (fs_ijpeg) {
-		rc = regulator_disable(fs_ijpeg);
-		if (rc < 0) {
-			CDBG("%s: Regulator disable failed %d\n", __func__, rc);
-			return rc;
-		}
-		regulator_put(fs_ijpeg);
-	}
-	rc = msm_camio_clk_disable(CAMIO_JPEG_PCLK);
-	if (rc < 0)
-		return rc;
-	rc = msm_camio_clk_disable(CAMIO_JPEG_CLK);
-	CDBG("%s: exit %d\n", __func__, rc);
-	return rc;
-}
-
-int msm_camio_jpeg_clk_enable(void)
-{
-	int rc = 0;
-	rc = msm_camio_clk_enable(CAMIO_JPEG_CLK);
-	if (rc < 0)
-		return rc;
-	rc = msm_camio_clk_enable(CAMIO_JPEG_PCLK);
-	if (rc < 0)
-		return rc;
-	fs_ijpeg = regulator_get(NULL, "fs_ijpeg");
-	if (IS_ERR(fs_ijpeg)) {
-		CDBG("%s: Regulator FS_IJPEG get failed %ld\n", __func__,
-			PTR_ERR(fs_ijpeg));
-		fs_ijpeg = NULL;
-	} else if (regulator_enable(fs_ijpeg)) {
-		CDBG("%s: Regulator FS_IJPEG enable failed\n", __func__);
-		regulator_put(fs_ijpeg);
-	}
-	CDBG("%s: exit %d\n", __func__, rc);
-	return rc;
-}
-
 int msm_camio_vpe_clk_disable(void)
 {
 	int rc = 0;
diff --git a/drivers/media/video/msm/io/msm_io_vfe31.c b/drivers/media/video/msm/io/msm_io_vfe31.c
index 7f3b7ae..24bba59 100644
--- a/drivers/media/video/msm/io/msm_io_vfe31.c
+++ b/drivers/media/video/msm/io/msm_io_vfe31.c
@@ -108,8 +108,6 @@
 static struct clk *camio_csi_clk;
 static struct clk *camio_csi_pclk;
 static struct clk *camio_csi_vfe_clk;
-static struct clk *camio_jpeg_clk;
-static struct clk *camio_jpeg_pclk;
 static struct clk *camio_vpe_clk;
 static struct regulator *fs_vpe;
 static struct msm_camera_io_ext camio_ext;
@@ -117,7 +115,6 @@
 static struct resource *camifpadio, *csiio;
 void __iomem *camifpadbase, *csibase;
 static uint32_t vpe_clk_rate;
-static uint32_t jpeg_clk_rate;
 
 static struct regulator_bulk_data regs[] = {
 	{ .supply = "gp2",  .min_uV = 2600000, .max_uV = 2600000 },
@@ -239,16 +236,6 @@
 		clk = clk_get(NULL, "csi_pclk");
 		break;
 
-	case CAMIO_JPEG_CLK:
-		camio_jpeg_clk =
-		clk = clk_get(NULL, "jpeg_clk");
-		jpeg_clk_rate = clk_round_rate(clk, 144000000);
-		clk_set_rate(clk, jpeg_clk_rate);
-		break;
-	case CAMIO_JPEG_PCLK:
-		camio_jpeg_pclk =
-		clk = clk_get(NULL, "jpeg_pclk");
-		break;
 	case CAMIO_VPE_CLK:
 		camio_vpe_clk =
 		clk = clk_get(NULL, "vpe_clk");
@@ -308,12 +295,6 @@
 	case CAMIO_CSI0_PCLK:
 		clk = camio_csi_pclk;
 		break;
-	case CAMIO_JPEG_CLK:
-		clk = camio_jpeg_clk;
-		break;
-	case CAMIO_JPEG_PCLK:
-		clk = camio_jpeg_pclk;
-		break;
 	case CAMIO_VPE_CLK:
 		clk = camio_vpe_clk;
 		break;
@@ -356,22 +337,6 @@
 	return IRQ_HANDLED;
 }
 
-int msm_camio_jpeg_clk_disable(void)
-{
-	msm_camio_clk_disable(CAMIO_JPEG_CLK);
-	msm_camio_clk_disable(CAMIO_JPEG_PCLK);
-	/* Need to add the code for remove PM QOS requirement */
-	return 0;
-}
-
-
-int msm_camio_jpeg_clk_enable(void)
-{
-	msm_camio_clk_enable(CAMIO_JPEG_CLK);
-	msm_camio_clk_enable(CAMIO_JPEG_PCLK);
-	return 0;
-}
-
 int msm_camio_vpe_clk_disable(void)
 {
 	msm_camio_clk_disable(CAMIO_VPE_CLK);
diff --git a/drivers/media/video/msm/io/msm_io_vfe31_v4l2.c b/drivers/media/video/msm/io/msm_io_vfe31_v4l2.c
index 451cb5a..a1270ea 100644
--- a/drivers/media/video/msm/io/msm_io_vfe31_v4l2.c
+++ b/drivers/media/video/msm/io/msm_io_vfe31_v4l2.c
@@ -33,12 +33,9 @@
 
 #define BUFF_SIZE_128 128
 
-static struct clk *camio_jpeg_clk;
 static struct clk *camio_vfe_clk;
-static struct clk *camio_jpeg_pclk;
 static struct clk *camio_vpe_clk;
 static struct clk *camio_vpe_pclk;
-static struct regulator *fs_ijpeg;
 static struct regulator *fs_vpe;
 
 static int vpe_clk_rate;
@@ -49,19 +46,6 @@
 	struct clk *clk = NULL;
 
 	switch (clktype) {
-	case CAMIO_JPEG_CLK:
-		camio_jpeg_clk =
-		clk = clk_get(NULL, "ijpeg_clk");
-		rc = clk_set_rate(clk, 228571000);
-		if (rc < 0)
-			rc = clk_set_rate(clk, 153600000);
-		break;
-
-	case CAMIO_JPEG_PCLK:
-		camio_jpeg_pclk =
-		clk = clk_get(NULL, "ijpeg_pclk");
-		break;
-
 	case CAMIO_VPE_CLK:
 		camio_vpe_clk =
 		clk = clk_get(NULL, "vpe_clk");
@@ -93,14 +77,6 @@
 	struct clk *clk = NULL;
 
 	switch (clktype) {
-	case CAMIO_JPEG_CLK:
-		clk = camio_jpeg_clk;
-		break;
-
-	case CAMIO_JPEG_PCLK:
-		clk = camio_jpeg_pclk;
-		break;
-
 	case CAMIO_VPE_CLK:
 		clk = camio_vpe_clk;
 		break;
@@ -138,47 +114,6 @@
 	clk_set_rate(clk, rate);
 }
 
-int msm_camio_jpeg_clk_disable(void)
-{
-	int rc = 0;
-	if (fs_ijpeg) {
-		rc = regulator_disable(fs_ijpeg);
-		if (rc < 0) {
-			CDBG("%s: Regulator disable failed %d\n", __func__, rc);
-			return rc;
-		}
-		regulator_put(fs_ijpeg);
-	}
-	rc = msm_camio_clk_disable(CAMIO_JPEG_PCLK);
-	if (rc < 0)
-		return rc;
-	rc = msm_camio_clk_disable(CAMIO_JPEG_CLK);
-	CDBG("%s: exit %d\n", __func__, rc);
-	return rc;
-}
-
-int msm_camio_jpeg_clk_enable(void)
-{
-	int rc = 0;
-	rc = msm_camio_clk_enable(CAMIO_JPEG_CLK);
-	if (rc < 0)
-		return rc;
-	rc = msm_camio_clk_enable(CAMIO_JPEG_PCLK);
-	if (rc < 0)
-		return rc;
-	fs_ijpeg = regulator_get(NULL, "fs_ijpeg");
-	if (IS_ERR(fs_ijpeg)) {
-		CDBG("%s: Regulator FS_IJPEG get failed %ld\n", __func__,
-			PTR_ERR(fs_ijpeg));
-		fs_ijpeg = NULL;
-	} else if (regulator_enable(fs_ijpeg)) {
-		CDBG("%s: Regulator FS_IJPEG enable failed\n", __func__);
-		regulator_put(fs_ijpeg);
-	}
-	CDBG("%s: exit %d\n", __func__, rc);
-	return rc;
-}
-
 int msm_camio_vpe_clk_disable(void)
 {
 	int rc = 0;
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index 6443250..670d0f8 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -154,7 +154,10 @@
 				unsigned int *nplanes, unsigned long sizes[],
 				void *alloc_ctxs[])
 {
-	*nbuffers = 3;
+	*nbuffers += 2;
+	if (*nbuffers > VIDEO_MAX_FRAME)
+		return -EINVAL;
+
 	*nplanes = 1;
 	return 0;
 }
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index e1a6ffd..318c319 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -4082,21 +4082,22 @@
 };
 #endif
 
-void msmsdcc_print_regs(const char *name, void __iomem *base,
-			unsigned int no_of_regs)
+static void msmsdcc_print_regs(const char *name, void __iomem *base,
+			       u32 phys_base, unsigned int no_of_regs)
 {
 	unsigned int i;
 
 	if (!base)
 		return;
-	pr_info("===== %s: Register Dumps @base=0x%x =====\n",
-		name, (u32)base);
+
+	pr_info("===== %s: Register Dumps @phys_base=0x%x, @virt_base=0x%x"
+		" =====\n", name, phys_base, (u32)base);
 	for (i = 0; i < no_of_regs; i = i + 4) {
-		pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x.\n", i*4,
-				(u32)readl_relaxed(base + i*4),
-				(u32)readl_relaxed(base + ((i+1)*4)),
-				(u32)readl_relaxed(base + ((i+2)*4)),
-				(u32)readl_relaxed(base + ((i+3)*4)));
+		pr_info("Reg=0x%.2x: 0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x\n", i*4,
+			(u32)readl_relaxed(base + i*4),
+			(u32)readl_relaxed(base + ((i+1)*4)),
+			(u32)readl_relaxed(base + ((i+2)*4)),
+			(u32)readl_relaxed(base + ((i+3)*4)));
 	}
 }
 
@@ -4104,17 +4105,17 @@
 {
 	/* Dump current state of SDCC clocks, power and irq */
 	pr_info("%s: SDCC PWR is %s\n", mmc_hostname(host->mmc),
-			(host->pwr ? "ON" : "OFF"));
+		(host->pwr ? "ON" : "OFF"));
 	pr_info("%s: SDCC clks are %s, MCLK rate=%d\n",
-			mmc_hostname(host->mmc),
-			(host->clks_on ? "ON" : "OFF"),
-			(u32)clk_get_rate(host->clk));
+		mmc_hostname(host->mmc), (host->clks_on ? "ON" : "OFF"),
+		(u32)clk_get_rate(host->clk));
 	pr_info("%s: SDCC irq is %s\n", mmc_hostname(host->mmc),
 		(host->sdcc_irq_disabled ? "disabled" : "enabled"));
 
 	/* Now dump SDCC registers. Don't print FIFO registers */
 	if (host->clks_on)
-		msmsdcc_print_regs("SDCC-CORE", host->base, 28);
+		msmsdcc_print_regs("SDCC-CORE", host->base,
+				   host->core_memres->start, 28);
 
 	if (host->curr.data) {
 		if (!msmsdcc_is_dma_possible(host, host->curr.data))
@@ -4123,22 +4124,27 @@
 			pr_info("%s: ADM mode: busy=%d, chnl=%d, crci=%d\n",
 				mmc_hostname(host->mmc), host->dma.busy,
 				host->dma.channel, host->dma.crci);
-		else if (host->is_sps_mode)
+		else if (host->is_sps_mode) {
+			if (host->sps.busy)
+				msmsdcc_print_regs("SDCC-DML", host->dml_base,
+						   host->dml_memres->start,
+						   16);
 			pr_info("%s: SPS mode: busy=%d\n",
 				mmc_hostname(host->mmc), host->sps.busy);
+		}
 
 		pr_info("%s: xfer_size=%d, data_xfered=%d, xfer_remain=%d\n",
 			mmc_hostname(host->mmc), host->curr.xfer_size,
 			host->curr.data_xfered, host->curr.xfer_remain);
-		pr_info("%s: got_dataend=%d, prog_enable=%d,"
-			" wait_for_auto_prog_done=%d,"
-			" got_auto_prog_done=%d\n",
-			mmc_hostname(host->mmc), host->curr.got_dataend,
-			host->prog_enable, host->curr.wait_for_auto_prog_done,
-			host->curr.got_auto_prog_done);
 	}
 
+	pr_info("%s: got_dataend=%d, prog_enable=%d,"
+		" wait_for_auto_prog_done=%d, got_auto_prog_done=%d\n",
+		mmc_hostname(host->mmc), host->curr.got_dataend,
+		host->prog_enable, host->curr.wait_for_auto_prog_done,
+		host->curr.got_auto_prog_done);
 }
+
 static void msmsdcc_req_tout_timer_hdlr(unsigned long data)
 {
 	struct msmsdcc_host *host = (struct msmsdcc_host *)data;
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index ce748f5..aa1a589 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -78,9 +78,13 @@
 /**
  * struct pm8921_bms_chip -
  * @bms_output_lock:	lock to prevent concurrent bms reads
- * @bms_100_lock:	lock to prevent concurrent updates to values that force
- *			100% charge
  *
+ * @last_ocv_uv_mutex:	mutex to protect simultaneous invocations of calculate
+ *			state of charge, note that last_ocv_uv could be
+ *			changed as soc is adjusted. This mutex protects
+ *			simultaneous updates of last_ocv_uv as well. This mutex
+ *			also protects changes to *_at_100 variables used in
+ *			faking 100% SOC.
  */
 struct pm8921_bms_chip {
 	struct device		*dev;
@@ -111,7 +115,6 @@
 	unsigned int		pmic_bms_irq[PM_BMS_MAX_INTS];
 	DECLARE_BITMAP(enabled_irqs, PM_BMS_MAX_INTS);
 	struct mutex		bms_output_lock;
-	spinlock_t		bms_100_lock;
 	struct single_row_lut	*adjusted_fcc_temp_lut;
 	unsigned int		charging_began;
 	unsigned int		start_percent;
@@ -127,6 +130,8 @@
 	int			amux_2_trim_delta;
 	uint16_t		prev_last_good_ocv_raw;
 	unsigned int		rconn_mohm;
+	struct mutex		last_ocv_uv_mutex;
+	int			last_ocv_uv;
 };
 
 static struct pm8921_bms_chip *the_chip;
@@ -144,7 +149,6 @@
 module_param(last_charge_increase, int, 0644);
 
 static int last_rbatt = -EINVAL;
-static int last_ocv_uv = -EINVAL;
 static int last_soc = -EINVAL;
 static int last_real_fcc_mah = -EINVAL;
 static int last_real_fcc_batt_temp = -EINVAL;
@@ -163,7 +167,6 @@
 };
 
 module_param_cb(last_rbatt, &bms_param_ops, &last_rbatt, 0644);
-module_param_cb(last_ocv_uv, &bms_param_ops, &last_ocv_uv, 0644);
 module_param_cb(last_soc, &bms_param_ops, &last_soc, 0644);
 
 /*
@@ -957,16 +960,28 @@
 		adjust_pon_ocv_raw(chip, raw);
 		convert_vbatt_raw_to_uv(chip, usb_chg,
 			raw->last_good_ocv_raw, &raw->last_good_ocv_uv);
-		last_ocv_uv = raw->last_good_ocv_uv;
+		chip->last_ocv_uv = raw->last_good_ocv_uv;
 	} else if (chip->prev_last_good_ocv_raw != raw->last_good_ocv_raw) {
 		chip->prev_last_good_ocv_raw = raw->last_good_ocv_raw;
 		convert_vbatt_raw_to_uv(chip, usb_chg,
 			raw->last_good_ocv_raw, &raw->last_good_ocv_uv);
-		last_ocv_uv = raw->last_good_ocv_uv;
+		chip->last_ocv_uv = raw->last_good_ocv_uv;
 	} else {
-		raw->last_good_ocv_uv = last_ocv_uv;
+		raw->last_good_ocv_uv = chip->last_ocv_uv;
 	}
 
+	/* fake a high OCV if we are just done charging */
+	if (chip->ocv_reading_at_100 != raw->last_good_ocv_raw) {
+		chip->ocv_reading_at_100 = 0;
+		chip->cc_reading_at_100 = 0;
+	} else {
+		/*
+		 * force 100% ocv by selecting the highest voltage the
+		 * battery could ever reach
+		 */
+		raw->last_good_ocv_uv = chip->max_voltage_uv;
+		chip->last_ocv_uv = chip->max_voltage_uv;
+	}
 	pr_debug("0p625 = %duV\n", chip->xoadc_v0625);
 	pr_debug("1p25 = %duV\n", chip->xoadc_v125);
 	pr_debug("last_good_ocv_raw= 0x%x, last_good_ocv_uv= %duV\n",
@@ -1120,7 +1135,7 @@
 
 	cc_voltage_uv = cc;
 	cc_voltage_uv -= chip->cc_reading_at_100;
-	pr_debug("cc = %d. after subtracting %d cc = %lld\n",
+	pr_debug("cc = %d. after subtracting 0x%x cc = %lld\n",
 					cc, chip->cc_reading_at_100,
 					cc_voltage_uv);
 	cc_voltage_uv = cc_to_microvolt(chip, cc_voltage_uv);
@@ -1156,25 +1171,7 @@
 {
 	int  ocv, pc;
 
-	/* calculate remainging charge */
-	ocv = 0;
-	if (chip->ocv_reading_at_100 != raw->last_good_ocv_raw) {
-		chip->ocv_reading_at_100 = 0;
-		chip->cc_reading_at_100 = 0;
-		ocv = raw->last_good_ocv_uv;
-	} else {
-		/*
-		 * force 100% ocv by selecting the highest voltage the
-		 * battery could every reach
-		 */
-		ocv = chip->max_voltage_uv;
-	}
-
-	if (ocv == 0) {
-		ocv = last_ocv_uv;
-		pr_debug("ocv not available using last_ocv_uv=%d\n", ocv);
-	}
-
+	ocv = raw->last_good_ocv_uv;
 	pc = calculate_pc(chip, ocv, batt_temp, chargecycles);
 	pr_debug("ocv = %d pc = %d\n", ocv, pc);
 	return (fcc_uah * pc) / 100;
@@ -1189,7 +1186,6 @@
 						int *cc_uah,
 						int *rbatt)
 {
-	unsigned long flags;
 	int soc_rbatt;
 
 	*fcc_uah = calculate_fcc_uah(chip, batt_temp, chargecycles);
@@ -1197,7 +1193,6 @@
 					*fcc_uah, batt_temp, chargecycles);
 
 
-	spin_lock_irqsave(&chip->bms_100_lock, flags);
 	/* calculate remainging charge */
 	*remaining_charge_uah = calculate_remaining_charge_uah(chip, raw,
 					*fcc_uah, batt_temp, chargecycles);
@@ -1205,11 +1200,10 @@
 
 	/* calculate cc micro_volt_hour */
 	calculate_cc_uah(chip, raw->cc, cc_uah);
-	pr_debug("cc_uah = %duAh raw->cc = %x cc = %lld after subtracting %d\n",
+	pr_debug("cc_uah = %duAh raw->cc = %x cc = %lld after subtracting %x\n",
 				*cc_uah, raw->cc,
 				(int64_t)raw->cc - chip->cc_reading_at_100,
 				chip->cc_reading_at_100);
-	spin_unlock_irqrestore(&chip->bms_100_lock, flags);
 
 	soc_rbatt = ((*remaining_charge_uah - *cc_uah) * 100) / *fcc_uah;
 	if (soc_rbatt < 0)
@@ -1245,6 +1239,108 @@
 			real_fcc_uah, remaining_charge_uah, cc_uah, fcc_uah);
 	return real_fcc_uah;
 }
+
+static int bound_soc(int soc)
+{
+	soc = max(0, soc);
+	soc = min(100, soc);
+	return soc;
+}
+
+static int last_soc_est = -EINVAL;
+static int adjust_soc(struct pm8921_bms_chip *chip, int soc, int batt_temp,
+		int rbatt , int fcc_uah, int uuc_uah, int cc_uah)
+{
+	int ibat_ua = 0, vbat_uv = 0;
+	int ocv_est_uv = 0, soc_est = 0, pc_est = 0, pc = 0;
+	int delta_ocv_uv = 0;
+	int n = 0;
+	int rc_new_uah = 0;
+	int pc_new = 0;
+	int soc_new = 0;
+	int m = 0;
+
+	pm8921_bms_get_simultaneous_battery_voltage_and_current(&ibat_ua,
+		&vbat_uv);
+
+	if (ibat_ua < 0)
+		goto out;
+	ocv_est_uv = vbat_uv + (ibat_ua * rbatt)/1000;
+	pc_est = calculate_pc(chip, ocv_est_uv, batt_temp, last_chargecycles);
+	soc_est = div_s64((s64)fcc_uah * pc_est - uuc_uah*100,
+						(s64)fcc_uah - uuc_uah);
+	soc_est = bound_soc(soc_est);
+
+	/*
+	 * do not adjust if soc_est is between 45 and 25 OR soc_est is
+	 * same as what bms calculated
+	 */
+	if (is_between(45, 25, soc_est) || soc_est == soc)
+		goto out;
+
+	if (last_soc_est == -EINVAL)
+		last_soc_est = soc;
+
+	n = min(200, max(1 , soc + soc_est + last_soc_est));
+	/* remember the last soc_est in last_soc_est */
+	last_soc_est = soc_est;
+
+	pc = calculate_pc(chip, chip->last_ocv_uv,
+				batt_temp, last_chargecycles);
+	if (pc > 0) {
+		pc_new = calculate_pc(chip, chip->last_ocv_uv - (++m * 1000),
+						batt_temp, last_chargecycles);
+		while (pc_new == pc) {
+			/* start taking 10mV steps */
+			m = m + 10;
+			pc_new = calculate_pc(chip,
+						chip->last_ocv_uv - (m * 1000),
+						batt_temp, last_chargecycles);
+		}
+	} else {
+		/*
+		 * pc is already at the lowest point,
+		 * assume 1 millivolt translates to 1% pc
+		 */
+		pc = 1;
+		pc_new = 0;
+		m = 1;
+	}
+
+	delta_ocv_uv = div_s64((soc - soc_est) * (s64)m * 1000,
+							n * (pc - pc_new));
+	chip->last_ocv_uv -= delta_ocv_uv;
+
+	if (chip->last_ocv_uv >= chip->max_voltage_uv)
+		chip->last_ocv_uv = chip->max_voltage_uv;
+
+	/* calculate the soc based on this new ocv */
+	pc_new = calculate_pc(chip, chip->last_ocv_uv,
+						batt_temp, last_chargecycles);
+	rc_new_uah = (fcc_uah * pc_new) / 100;
+	soc_new = (rc_new_uah - cc_uah - uuc_uah)*100 / (fcc_uah - uuc_uah);
+	soc_new = bound_soc(soc_new);
+
+	/*
+	 * if soc_new is ZERO force it higher so that phone doesnt report soc=0
+	 * soc = 0 should happen only when soc_est == 0
+	 */
+	if (soc_new == 0 && soc_est != 0)
+		soc_new = 1;
+
+	soc = soc_new;
+
+out:
+	pr_debug("ibat_ua = %d, vbat_uv = %d, ocv_est_uv = %d, pc_est = %d, "
+		"soc_est = %d, n = %d, delta_ocv_uv = %d, last_ocv_uv = %d, "
+		"pc_new = %d, soc_new = %d\n",
+		ibat_ua, vbat_uv, ocv_est_uv, pc_est,
+		soc_est, n, delta_ocv_uv, chip->last_ocv_uv,
+		pc_new, soc_new);
+
+	return soc;
+}
+
 /*
  * Remaining Usable Charge = remaining_charge (charge at ocv instance)
  *				- coloumb counter charge
@@ -1257,7 +1353,6 @@
 {
 	int remaining_usable_charge_uah, fcc_uah, unusable_charge_uah;
 	int remaining_charge_uah, soc;
-	int update_userspace = 1;
 	int cc_uah;
 	int rbatt;
 
@@ -1302,30 +1397,31 @@
 		pr_err("for bad rem_usb_chg last_ocv_uv = %d"
 				"chargecycles = %d, batt_temp = %d"
 				"fcc = %d soc =%d\n",
-				last_ocv_uv, chargecycles, batt_temp,
+				chip->last_ocv_uv, chargecycles, batt_temp,
 				fcc_uah, soc);
-		update_userspace = 0;
 		soc = 0;
 	}
 
-	if (last_soc == -EINVAL || soc <= last_soc) {
-		last_soc = update_userspace ? soc : last_soc;
-		return soc;
-	}
+	soc = adjust_soc(chip, soc, batt_temp, rbatt,
+					fcc_uah, unusable_charge_uah, cc_uah);
 
-	/*
-	 * soc > last_soc
-	 * the device must be charging for reporting a higher soc, if not ignore
-	 * this soc and continue reporting the last_soc
-	 */
-	if (the_chip->start_percent != -EINVAL) {
+	if (last_soc == -EINVAL || soc <= last_soc) {
 		last_soc = soc;
 	} else {
-		pr_debug("soc = %d reporting last_soc = %d\n", soc, last_soc);
-		soc = last_soc;
+		/*
+		 * soc > last_soc
+		 * the device must be charging for reporting a higher soc, if
+		 * not ignore this soc and continue reporting the last_soc
+		 */
+		if (the_chip->start_percent != -EINVAL)
+			last_soc = soc;
+		else
+			pr_debug("soc = %d reporting last_soc = %d\n", soc,
+								last_soc);
 	}
 
-	return soc;
+	pr_debug("Reported SOC = %u%%\n", last_soc);
+	return last_soc;
 }
 #define MIN_DELTA_625_UV	1000
 static void calib_hkadc(struct pm8921_bms_chip *chip)
@@ -1452,6 +1548,7 @@
 	int batt_temp, rc;
 	struct pm8xxx_adc_chan_result result;
 	struct pm8921_soc_params raw;
+	int soc;
 
 	if (!the_chip) {
 		pr_err("called before initialization\n");
@@ -1468,10 +1565,13 @@
 						result.measurement);
 	batt_temp = (int)result.physical;
 
+	mutex_lock(&the_chip->last_ocv_uv_mutex);
 	read_soc_params_raw(the_chip, &raw);
 
-	return calculate_state_of_charge(the_chip, &raw,
+	soc = calculate_state_of_charge(the_chip, &raw,
 					batt_temp, last_chargecycles);
+	mutex_unlock(&the_chip->last_ocv_uv_mutex);
+	return soc;
 }
 EXPORT_SYMBOL_GPL(pm8921_bms_get_percent_charge);
 
@@ -1501,6 +1601,8 @@
 						result.measurement);
 	batt_temp = (int)result.physical;
 
+	mutex_lock(&the_chip->last_ocv_uv_mutex);
+
 	read_soc_params_raw(the_chip, &raw);
 
 	calculate_soc_params(the_chip, &raw, batt_temp, last_chargecycles,
@@ -1509,6 +1611,8 @@
 						&remaining_charge_uah,
 						&cc_uah,
 						&rbatt);
+	mutex_unlock(&the_chip->last_ocv_uv_mutex);
+
 	return rbatt;
 }
 EXPORT_SYMBOL_GPL(pm8921_bms_get_rbatt);
@@ -1556,10 +1660,13 @@
 						result.measurement);
 	batt_temp = (int)result.physical;
 
+	mutex_lock(&the_chip->last_ocv_uv_mutex);
 	read_soc_params_raw(the_chip, &raw);
 
 	the_chip->start_percent = calculate_state_of_charge(the_chip, &raw,
 					batt_temp, last_chargecycles);
+	mutex_unlock(&the_chip->last_ocv_uv_mutex);
+
 	bms_start_percent = the_chip->start_percent;
 	bms_start_ocv_uv = raw.last_good_ocv_uv;
 	calculate_cc_uah(the_chip, raw.cc, &bms_start_cc_uah);
@@ -1590,13 +1697,16 @@
 						result.measurement);
 	batt_temp = (int)result.physical;
 
+	mutex_lock(&the_chip->last_ocv_uv_mutex);
+
 	read_soc_params_raw(the_chip, &raw);
 
 	calculate_cc_uah(the_chip, raw.cc, &bms_end_cc_uah);
 
+	bms_end_ocv_uv = raw.last_good_ocv_uv;
+
 	if (is_battery_full
 		&& the_chip->start_percent <= MIN_START_PERCENT_FOR_LEARNING) {
-		unsigned long flags;
 		int fcc_uah, new_fcc_uah, delta_fcc_uah;
 
 		new_fcc_uah = calculate_real_fcc_uah(the_chip, &raw,
@@ -1627,20 +1737,24 @@
 		last_real_fcc_batt_temp = batt_temp;
 		readjust_fcc_table();
 
-		spin_lock_irqsave(&the_chip->bms_100_lock, flags);
+	}
+
+	if (is_battery_full) {
 		the_chip->ocv_reading_at_100 = raw.last_good_ocv_raw;
 		the_chip->cc_reading_at_100 = raw.cc;
-		spin_unlock_irqrestore(&the_chip->bms_100_lock, flags);
-		pr_debug("EOC ocv_reading = 0x%x cc = %d\n",
+
+		the_chip->last_ocv_uv = the_chip->max_voltage_uv;
+		raw.last_good_ocv_uv = the_chip->max_voltage_uv;
+		pr_debug("EOC ocv_reading = 0x%x cc = 0x%x\n",
 				the_chip->ocv_reading_at_100,
 				the_chip->cc_reading_at_100);
 	}
 
 	the_chip->end_percent = calculate_state_of_charge(the_chip, &raw,
 					batt_temp, last_chargecycles);
+	mutex_unlock(&the_chip->last_ocv_uv_mutex);
 
 	bms_end_percent = the_chip->end_percent;
-	bms_end_ocv_uv = raw.last_good_ocv_uv;
 
 	if (the_chip->end_percent > the_chip->start_percent) {
 		last_charge_increase +=
@@ -1804,6 +1918,8 @@
 					chip->batt_temp_channel, rc);
 	}
 	chip->batt_temp_suspend = (int)result.physical;
+
+	mutex_lock(&chip->last_ocv_uv_mutex);
 	read_soc_params_raw(chip, &raw);
 
 	fcc_uah = calculate_fcc_uah(chip,
@@ -1818,12 +1934,14 @@
 
 	/* calculate cc micro_volt_hour */
 	calculate_cc_uah(chip, raw.cc, &cc_uah);
-	pr_debug("cc_uah = %duAh raw->cc = %x cc = %lld after subtracting %d\n",
+	pr_debug("cc_uah = %duAh raw->cc = %x cc = %lld after subtracting %x\n",
 				cc_uah, raw.cc,
 				(int64_t)raw.cc - chip->cc_reading_at_100,
 				chip->cc_reading_at_100);
 	chip->soc_rbatt_suspend = ((remaining_charge_uah - cc_uah) * 100)
 						/ fcc_uah;
+	mutex_unlock(&chip->last_ocv_uv_mutex);
+
 	return 0;
 }
 
@@ -1911,9 +2029,9 @@
 			pr_err("failed to read adc based ocv_uv rc = %d\n", rc);
 			ocv_uv = DEFAULT_OCV_MICROVOLTS;
 		}
-		last_ocv_uv = ocv_uv;
 	}
-	pr_debug("ocv_uv = %d last_ocv_uv = %d\n", ocv_uv, last_ocv_uv);
+	chip->last_ocv_uv = ocv_uv;
+	pr_debug("ocv_uv = %d last_ocv_uv = %d\n", ocv_uv, chip->last_ocv_uv);
 }
 
 static int64_t read_battery_id(struct pm8921_bms_chip *chip)
@@ -2314,8 +2432,9 @@
 		pr_err("Cannot allocate pm_bms_chip\n");
 		return -ENOMEM;
 	}
+
 	mutex_init(&chip->bms_output_lock);
-	spin_lock_init(&chip->bms_100_lock);
+	mutex_init(&chip->last_ocv_uv_mutex);
 	chip->dev = &pdev->dev;
 	chip->r_sense = pdata->r_sense;
 	chip->i_test = pdata->i_test;
@@ -2387,7 +2506,7 @@
 	get_battery_uvolts(chip, &vbatt);
 	pr_info("OK battery_capacity_at_boot=%d volt = %d ocv = %d\n",
 				pm8921_bms_get_percent_charge(),
-				vbatt, last_ocv_uv);
+				vbatt, chip->last_ocv_uv);
 	return 0;
 
 free_irqs:
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index cc008ab..24da4d1 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -1978,6 +1978,9 @@
 				slc1 = ctrl->sched.chc1[coeff1];
 			}
 		}
+		/* Leave some slots for messaging space */
+		if (opensl1[1] == 0 && opensl1[0] == 0)
+			return -EXFULL;
 		if (opensl1[1] > opensl1[0]) {
 			int temp = opensl1[0];
 			opensl1[0] = opensl1[1];
@@ -2180,6 +2183,9 @@
 				slc1 = ctrl->sched.chc1[coeff1];
 			}
 		}
+		/* Leave some slots for messaging space */
+		if (opensl3[1] == 0 && opensl3[0] == 0)
+			return -EXFULL;
 		/* swap 1st and 2nd bucket if 2nd bucket has more open slots */
 		if (opensl3[1] > opensl3[0]) {
 			int temp = opensl3[0];
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index e2d77e9..69e0546 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -1155,6 +1155,22 @@
 	return xfrs_grped;
 }
 
+static inline void write_force_cs(struct msm_spi *dd, bool set_flag)
+{
+	u32 spi_ioc;
+	u32 spi_ioc_orig;
+
+	spi_ioc = readl_relaxed(dd->base + SPI_IO_CONTROL);
+	spi_ioc_orig = spi_ioc;
+	if (set_flag)
+		spi_ioc |= SPI_IO_C_FORCE_CS;
+	else
+		spi_ioc &= ~SPI_IO_C_FORCE_CS;
+
+	if (spi_ioc != spi_ioc_orig)
+		writel_relaxed(spi_ioc, dd->base + SPI_IO_CONTROL);
+}
+
 static void msm_spi_process_message(struct msm_spi *dd)
 {
 	int xfrs_grped = 0;
@@ -1178,11 +1194,10 @@
 	}
 
 	if (dd->qup_ver) {
+		write_force_cs(dd, 0);
 		list_for_each_entry(dd->cur_transfer,
 				&dd->cur_msg->transfers,
 				transfer_list) {
-			u32 spi_ioc;
-			u32 spi_ioc_orig;
 			struct spi_transfer *t = dd->cur_transfer;
 			struct spi_transfer *nxt;
 
@@ -1191,18 +1206,10 @@
 						struct spi_transfer,
 						transfer_list);
 
-				spi_ioc = readl_relaxed(dd->base +
-							SPI_IO_CONTROL);
-				spi_ioc_orig = spi_ioc;
 				if (t->cs_change == nxt->cs_change)
-					spi_ioc |= SPI_IO_C_FORCE_CS;
+					write_force_cs(dd, 1);
 				else
-					spi_ioc &= ~SPI_IO_C_FORCE_CS;
-
-				if (spi_ioc != spi_ioc_orig) {
-					writel_relaxed(spi_ioc,
-						dd->base + SPI_IO_CONTROL);
-				}
+					write_force_cs(dd, 0);
 			}
 
 			dd->cur_msg_len = dd->cur_transfer->len;
diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig
index 578e339..b8d1df8 100644
--- a/drivers/video/msm/Kconfig
+++ b/drivers/video/msm/Kconfig
@@ -802,9 +802,18 @@
 	  Support for HDMI CEC Feature
 	  Choose to enable CEC
 
-config FB_MSM_HDMI_MHL
+config FB_MSM_HDMI_MHL_9244
 	depends on FB_MSM_HDMI_MSM_PANEL
-	bool 'HDMI to MHL support'
+	bool 'SI_MHL 9244 support'
+	default n
+	---help---
+	  Support the HDMI to MHL conversion.
+	  MHL (Mobile High-Definition Link) technology
+	  uses USB connector to output HDMI content
+
+config FB_MSM_HDMI_MHL_8334
+	depends on FB_MSM_HDMI_MSM_PANEL
+	bool 'SI_MHL 8334 support '
 	default n
 	---help---
 	  Support the HDMI to MHL conversion.
diff --git a/drivers/video/msm/Makefile b/drivers/video/msm/Makefile
index 5a72ad4..b2ecb08 100644
--- a/drivers/video/msm/Makefile
+++ b/drivers/video/msm/Makefile
@@ -171,6 +171,11 @@
 
 obj-$(CONFIG_FB_MSM_TVOUT) += tvout_msm.o
 
+ccflags-y := -I$(src)/mhl
+obj-$(CONFIG_FB_MSM_HDMI_MHL_8334) += mhl-8334.o
+mhl-8334-objs  += mhl/mhl_8334.o
+mhl-8334-objs  += mhl/mhl_i2c_utils.o
+
 obj-$(CONFIG_FB_MSM_EXTMDDI_SVGA) += mddi_ext_lcd.o
 
 obj-$(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) += mdp4_wfd_writeback_panel.o
diff --git a/drivers/video/msm/mhl/mhl_8334.c b/drivers/video/msm/mhl/mhl_8334.c
new file mode 100644
index 0000000..43280a5
--- /dev/null
+++ b/drivers/video/msm/mhl/mhl_8334.c
@@ -0,0 +1,849 @@
+/* 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/types.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <mach/msm_hdmi_audio.h>
+#include <mach/clk.h>
+#include <mach/msm_iomap.h>
+#include <mach/socinfo.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+#include "msm_fb.h"
+#include "external_common.h"
+#include "mhl_8334.h"
+#include "mhl_i2c_utils.h"
+
+#define DEBUG
+
+
+static struct i2c_device_id mhl_sii_i2c_id[] = {
+	{ MHL_DRIVER_NAME, 0 },
+	{ }
+};
+
+struct mhl_msm_state_t *mhl_msm_state;
+spinlock_t mhl_state_lock;
+
+static int mhl_i2c_probe(struct i2c_client *client,\
+	const struct i2c_device_id *id);
+static int mhl_i2c_remove(struct i2c_client *client);
+static void force_usb_switch_open(void);
+static void release_usb_switch_open(void);
+static void switch_mode(enum mhl_st_type to_mode);
+static irqreturn_t mhl_tx_isr(int irq, void *dev_id);
+
+static struct i2c_driver mhl_sii_i2c_driver = {
+	.driver = {
+		.name = MHL_DRIVER_NAME,
+		.owner = THIS_MODULE,
+	},
+	.probe = mhl_i2c_probe,
+	/*.remove =  __exit_p(mhl_i2c_remove),*/
+	.remove =  mhl_i2c_remove,
+	.id_table = mhl_sii_i2c_id,
+};
+
+bool mhl_is_connected(void)
+{
+	return true;
+}
+
+static void cbus_reset(void)
+{
+	uint8_t i;
+
+	/*
+	 * REG_SRST
+	 */
+	mhl_i2c_reg_modify(TX_PAGE_3, 0x0000, BIT3, BIT3);
+	msleep(20);
+	mhl_i2c_reg_modify(TX_PAGE_3, 0x0000, BIT3, 0x00);
+	/*
+	 * REG_INTR1 and REG_INTR4
+	 */
+	mhl_i2c_reg_write(TX_PAGE_L0, 0x0075, BIT6 | BIT5);
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0022,
+		BIT0 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6);
+	/* REG5 */
+	if (mhl_msm_state->chip_rev_id < 1)
+		mhl_i2c_reg_write(TX_PAGE_3, 0x0024, BIT3 | BIT4);
+	else
+		/*REG5 Mask disabled due to auto FIFO reset ??*/
+		mhl_i2c_reg_write(TX_PAGE_3, 0x0024, 0x00);
+
+	/* Unmask CBUS1 Intrs */
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0009,
+		BIT2 | BIT3 | BIT4 | BIT5 | BIT6);
+
+	/* Unmask CBUS2 Intrs */
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x001F, BIT2 | BIT3);
+
+	for (i = 0; i < 4; i++) {
+		/*
+		 * Enable WRITE_STAT interrupt for writes to
+		 * all 4 MSC Status registers.
+		 */
+		mhl_i2c_reg_write(TX_PAGE_CBUS, (0xE0 + i), 0xFF);
+
+		/*
+		 * Enable SET_INT interrupt for writes to
+		 * all 4 MSC Interrupt registers.
+		 */
+		mhl_i2c_reg_write(TX_PAGE_CBUS, (0xF0 + i), 0xFF);
+	}
+}
+
+static void init_cbus_regs(void)
+{
+	uint8_t		regval;
+
+	/* Increase DDC translation layer timer*/
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0007, 0xF2);
+	/* Drive High Time */
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0036, 0x03);
+	/* Use programmed timing */
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0039, 0x30);
+	/* CBUS Drive Strength */
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0040, 0x03);
+	/*
+	 * Write initial default settings
+	 * to devcap regs: default settings
+	 */
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_DEV_STATE,
+		DEVCAP_VAL_DEV_STATE);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_MHL_VERSION,
+		DEVCAP_VAL_MHL_VERSION);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_DEV_CAT,
+		DEVCAP_VAL_DEV_CAT);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_ADOPTER_ID_H,
+		DEVCAP_VAL_ADOPTER_ID_H);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_ADOPTER_ID_L,
+		DEVCAP_VAL_ADOPTER_ID_L);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_VID_LINK_MODE,
+		DEVCAP_VAL_VID_LINK_MODE);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_AUD_LINK_MODE,
+		DEVCAP_VAL_AUD_LINK_MODE);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_VIDEO_TYPE,
+		DEVCAP_VAL_VIDEO_TYPE);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_LOG_DEV_MAP,
+		DEVCAP_VAL_LOG_DEV_MAP);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_BANDWIDTH,
+		DEVCAP_VAL_BANDWIDTH);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_FEATURE_FLAG,
+		DEVCAP_VAL_FEATURE_FLAG);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_DEVICE_ID_H,
+		DEVCAP_VAL_DEVICE_ID_H);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_DEVICE_ID_L,
+		DEVCAP_VAL_DEVICE_ID_L);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_SCRATCHPAD_SIZE,
+		DEVCAP_VAL_SCRATCHPAD_SIZE);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_INT_STAT_SIZE,
+		DEVCAP_VAL_INT_STAT_SIZE);
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0080 | DEVCAP_OFFSET_RESERVED,
+		DEVCAP_VAL_RESERVED);
+
+	/* Make bits 2,3 (initiator timeout) to 1,1
+	 * for register CBUS_LINK_CONTROL_2
+	 * REG_CBUS_LINK_CONTROL_2
+	 */
+	regval = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x0031);
+	regval = (regval | 0x0C);
+	/* REG_CBUS_LINK_CONTROL_2 */
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0031, regval);
+	 /* REG_MSC_TIMEOUT_LIMIT */
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0022, 0x0F);
+	/* REG_CBUS_LINK_CONTROL_1 */
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x0030, 0x01);
+	/* disallow vendor specific commands */
+	mhl_i2c_reg_modify(TX_PAGE_CBUS, 0x002E, BIT4, BIT4);
+}
+
+/*
+ * Configure the initial reg settings
+ */
+static void mhl_init_reg_settings(void)
+{
+
+	/*
+	 * ============================================
+	 * POWER UP
+	 * ============================================
+	 */
+
+	/* Power up 1.2V core */
+	mhl_i2c_reg_write(TX_PAGE_L1, 0x003D, 0x3F);
+	/* Enable Tx PLL Clock */
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0011, 0x01);
+	/* Enable Tx Clock Path and Equalizer */
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0012, 0x11);
+	/* Tx Source Termination ON */
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0030, 0x10);
+	/* Enable 1X MHL Clock output */
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0035, 0xAC);
+	/* Tx Differential Driver Config */
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0031, 0x3C);
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0033, 0xD9);
+	/* PLL Bandwidth Control */
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0037, 0x02);
+	/*
+	 * ============================================
+	 * Analog PLL Control
+	 * ============================================
+	 */
+	/* Enable Rx PLL clock */
+	mhl_i2c_reg_write(TX_PAGE_L0, 0x0080, 0x00);
+	mhl_i2c_reg_write(TX_PAGE_L0, 0x00F8, 0x0C);
+	mhl_i2c_reg_write(TX_PAGE_L0, 0x0085, 0x02);
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0000, 0x00);
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0013, 0x60);
+	/* PLL Cal ref sel */
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0017, 0x03);
+	/* VCO Cal */
+	mhl_i2c_reg_write(TX_PAGE_2, 0x001A, 0x20);
+	/* Auto EQ */
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0022, 0xE0);
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0023, 0xC0);
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0024, 0xA0);
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0025, 0x80);
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0026, 0x60);
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0027, 0x40);
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0028, 0x20);
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0029, 0x00);
+	/* Rx PLL Bandwidth 4MHz */
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0031, 0x0A);
+	/* Rx PLL Bandwidth value from I2C */
+	mhl_i2c_reg_write(TX_PAGE_2, 0x0045, 0x06);
+	mhl_i2c_reg_write(TX_PAGE_2, 0x004B, 0x06);
+	/* Manual zone control */
+	mhl_i2c_reg_write(TX_PAGE_2, 0x004C, 0xE0);
+	/* PLL Mode value */
+	mhl_i2c_reg_write(TX_PAGE_2, 0x004D, 0x00);
+	mhl_i2c_reg_write(TX_PAGE_L0, 0x0008, 0x35);
+	/*
+	 * Discovery Control and Status regs
+	 * Setting De-glitch time to 50 ms (default)
+	 * Switch Control Disabled
+	 */
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0011, 0xAD);
+	/* 1.8V CBUS VTH */
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0014, 0x55);
+	/* RGND and single Discovery attempt */
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0015, 0x11);
+	/* Ignore VBUS */
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0017, 0x82);
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0018, 0x24);
+	/* Pull-up resistance off for IDLE state */
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0013, 0x84);
+	/* Enable CBUS Discovery */
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0010, 0x27);
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0016, 0x20);
+	/* MHL CBUS Discovery - immediate comm.  */
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0012, 0x86);
+	/* Do not force HPD to 0 during wake-up from D3 */
+	if (mhl_msm_state->cur_state != POWER_STATE_D3) {
+		mhl_i2c_reg_modify(TX_PAGE_3, 0x0020,
+			       BIT5 | BIT4, BIT4);
+	}
+	/* Enable Auto Soft RESET */
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0000, 0x084);
+	/* HDMI Transcode mode enable */
+	mhl_i2c_reg_write(TX_PAGE_L0, 0x000D, 0x1C);
+
+	cbus_reset();
+	init_cbus_regs();
+}
+
+static int mhl_chip_init(void)
+{
+	/* Read the chip rev ID */
+	mhl_msm_state->chip_rev_id = mhl_i2c_reg_read(TX_PAGE_L0, 0x04);
+	pr_debug("MHL: chip rev ID read=[%x]\n", mhl_msm_state->chip_rev_id);
+
+	/* Reset the TX chip */
+	mhl_msm_state->mhl_data->reset_pin(0);
+	msleep(20);
+	mhl_msm_state->mhl_data->reset_pin(1);
+	/* MHL spec requires a 100 ms wait here.  */
+	msleep(100);
+
+	mhl_init_reg_settings();
+
+	/*
+	 * Power down the chip to the
+	 * D3 - a low power standby mode
+	 * cable impedance measurement logic is operational
+	 */
+	switch_mode(POWER_STATE_D3);
+	return 0;
+}
+
+/*
+ * I2C probe
+ */
+static int mhl_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	int ret;
+	mhl_msm_state->mhl_data = kzalloc(sizeof(struct msm_mhl_platform_data),
+		GFP_KERNEL);
+	if (!(mhl_msm_state->mhl_data)) {
+		ret = -ENOMEM;
+		goto probe_exit;
+	}
+	pr_debug("Inside probe\n");
+	mhl_msm_state->i2c_client = client;
+
+	spin_lock_init(&mhl_state_lock);
+
+	i2c_set_clientdata(client, mhl_msm_state);
+	mhl_msm_state->mhl_data = client->dev.platform_data;
+
+	/* Init GPIO stuff here */
+	ret = mhl_msm_state->mhl_data->gpio_setup(1);
+	if (ret == -1) {
+		pr_err("MHL: mhl_gpio_init has failed\n");
+		ret = -ENODEV;
+		goto probe_exit;
+	}
+	return 0;
+
+probe_exit:
+	if (mhl_msm_state->mhl_data) {
+		/* free the gpios */
+		mhl_msm_state->mhl_data->gpio_setup(0);
+		kfree(mhl_msm_state->mhl_data);
+		mhl_msm_state->mhl_data = NULL;
+	}
+	return ret;
+}
+
+static int mhl_i2c_remove(struct i2c_client *client)
+{
+	pr_debug("inside i2c remove\n");
+	mhl_msm_state->mhl_data->gpio_setup(0);
+	kfree(mhl_msm_state->mhl_data);
+	return 0;
+}
+
+static int __init mhl_msm_init(void)
+{
+	int32_t     ret;
+
+	mhl_msm_state = kzalloc(sizeof(struct mhl_msm_state_t), GFP_KERNEL);
+	if (!mhl_msm_state) {
+		pr_err("mhl_msm_init FAILED: out of memory\n");
+		ret = -ENOMEM;
+		goto init_exit;
+	}
+
+	mhl_msm_state->i2c_client = NULL;
+	ret = i2c_add_driver(&mhl_sii_i2c_driver);
+	if (ret) {
+		pr_err("MHL: I2C driver add failed: %d\n", ret);
+		ret = -ENODEV;
+		goto init_exit;
+	} else {
+		if (mhl_msm_state->i2c_client == NULL) {
+			pr_err("JSR: I2C driver add failed\n");
+			ret = -ENODEV;
+			goto init_exit;
+		}
+		pr_debug("MHL: I2C driver added\n");
+	}
+
+	/* Request IRQ stuff here */
+	pr_debug("MHL: mhl_msm_state->mhl_data->irq=[%d]\n",
+		mhl_msm_state->mhl_data->irq);
+	ret = request_threaded_irq(mhl_msm_state->mhl_data->irq, NULL,
+				   &mhl_tx_isr,
+				 IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+				 "mhl_tx_isr", mhl_msm_state);
+	if (ret != 0) {
+		pr_err("request_threaded_irq failed, status: %d\n",
+			ret);
+		ret = -EACCES; /* Error code???? */
+		goto init_exit;
+	}
+
+	mhl_msm_state->cur_state = POWER_STATE_D0_MHL;
+
+	/* MHL SII 8334 chip specific init */
+	mhl_chip_init();
+	return 0;
+
+init_exit:
+	pr_err("Exiting from the init with err\n");
+	i2c_del_driver(&mhl_sii_i2c_driver);
+	if (!mhl_msm_state) {
+		kfree(mhl_msm_state);
+		mhl_msm_state = NULL;
+	 }
+	 return ret;
+}
+
+static void switch_mode(enum mhl_st_type to_mode)
+{
+	unsigned long flags;
+
+	switch (to_mode) {
+	case POWER_STATE_D0_NO_MHL:
+		break;
+	case POWER_STATE_D0_MHL:
+		mhl_init_reg_settings();
+
+		/* REG_DISC_CTRL1 */
+		mhl_i2c_reg_modify(TX_PAGE_3, 0x0010, BIT1, 0);
+
+		/*
+		 * TPI_DEVICE_POWER_STATE_CTRL_REG
+		 * TX_POWER_STATE_MASK = BIT1 | BIT0
+		 */
+		mhl_i2c_reg_modify(TX_PAGE_TPI, 0x001E, BIT1 | BIT0, 0x00);
+		break;
+	case POWER_STATE_D3:
+		if (mhl_msm_state->cur_state != POWER_STATE_D3) {
+			/* Force HPD to 0 when not in MHL mode.  */
+			mhl_i2c_reg_modify(TX_PAGE_3, 0x0020,
+				BIT5 | BIT4, BIT4);
+
+			/*
+			 * Change TMDS termination to high impedance
+			 * on disconnection.
+			 */
+			mhl_i2c_reg_write(TX_PAGE_3, 0x0030, 0xD0);
+			mhl_i2c_reg_modify(TX_PAGE_L1, 0x003D,
+				BIT1 | BIT0, BIT0);
+			spin_lock_irqsave(&mhl_state_lock, flags);
+			mhl_msm_state->cur_state = POWER_STATE_D3;
+			spin_unlock_irqrestore(&mhl_state_lock, flags);
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static void mhl_drive_hpd(uint8_t to_state)
+{
+	pr_debug("%s: To state=[0x%x]\n", __func__, to_state);
+	if (to_state == HPD_UP) {
+		/*
+		 * Drive HPD to UP state
+		 *
+		 * The below two reg configs combined
+		 * enable TMDS output.
+		 */
+
+		/* Enable TMDS on TMDS_CCTRL */
+		mhl_i2c_reg_modify(TX_PAGE_L0, 0x0080, BIT4, BIT4);
+
+		/*
+		 * Set HPD_OUT_OVR_EN = HPD State
+		 * EDID read and Un-force HPD (from low)
+		 * propogate to src let HPD float by clearing
+		 * HPD OUT OVRRD EN
+		 */
+		mhl_i2c_reg_modify(TX_PAGE_3, 0x0020, BIT4, 0x00);
+	} else {
+		/*
+		 * Drive HPD to DOWN state
+		 * Disable TMDS Output on REG_TMDS_CCTRL
+		 * Enable/Disable TMDS output (MHL TMDS output only)
+		 */
+		mhl_i2c_reg_modify(TX_PAGE_L0, 0x0080, BIT4, 0x00);
+	}
+	return;
+}
+
+static void mhl_msm_connection(void)
+{
+	uint8_t val;
+	unsigned long flags;
+
+	pr_err("%s: cur state = [0x%x]\n", __func__, mhl_msm_state->cur_state);
+
+	if (mhl_msm_state->cur_state == POWER_STATE_D0_MHL) {
+		/* Already in D0 - MHL power state */
+		return;
+	}
+	spin_lock_irqsave(&mhl_state_lock, flags);
+	mhl_msm_state->cur_state = POWER_STATE_D0_MHL;
+	spin_unlock_irqrestore(&mhl_state_lock, flags);
+
+	mhl_i2c_reg_write(TX_PAGE_3, 0x30, 0x10);
+
+	mhl_i2c_reg_write(TX_PAGE_CBUS, 0x07, 0xF2);
+
+	/*
+	 * Keep the discovery enabled. Need RGND interrupt
+	 * Possibly chip disables discovery after MHL_EST??
+	 * Need to re-enable here
+	 */
+	val = mhl_i2c_reg_read(TX_PAGE_3, 0x10);
+	mhl_i2c_reg_write(TX_PAGE_3, 0x10, val | BIT(0));
+
+	return;
+}
+
+static void mhl_msm_disconnection(void)
+{
+	uint8_t reg;
+
+	/* Clear interrupts - REG INTR4 */
+	reg = mhl_i2c_reg_read(TX_PAGE_3, 0x0021);
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0021, reg);
+	/*
+	 * MHL TX CTL1
+	 * Disabling Tx termination
+	 */
+	mhl_i2c_reg_write(TX_PAGE_3, 0x30, 0xD0);
+	/*
+	 * MSC REQUESTOR ABORT REASON
+	 * Clear CBUS_HPD status
+	 */
+	mhl_i2c_reg_modify(TX_PAGE_CBUS, 0x000D, BIT6, 0x00);
+	/* Change HPD line to drive it low */
+	mhl_drive_hpd(HPD_DOWN);
+	/* switch power state to D3 */
+	switch_mode(POWER_STATE_D3);
+	return;
+}
+
+/*
+ * If hardware detected a change in impedence and raised an INTR
+ * We check the range of this impedence to infer if the connected
+ * device is MHL or USB and take appropriate actions.
+ */
+static void mhl_msm_read_rgnd_int(void)
+{
+	uint8_t rgnd_imp;
+
+	/*
+	 * DISC STATUS REG 2
+	 * 1:0 RGND
+	 * 00  - open (USB)
+	 * 01  - 2 kOHM (USB)
+	 * 10  - 1 kOHM ***(MHL)**** It's range 800 - 1200 OHM from MHL spec
+	 * 11  - short (USB)
+	 */
+	rgnd_imp = mhl_i2c_reg_read(TX_PAGE_3, 0x001C);
+	pr_debug("Imp Range read = %02X\n", (int)rgnd_imp);
+
+
+	if (0x02 == rgnd_imp) {
+		pr_debug("MHL: MHL DEVICE!!!\n");
+		/*
+		 * Handling the MHL event in driver
+		 */
+		mhl_i2c_reg_modify(TX_PAGE_3, 0x0018, BIT0, BIT0);
+	} else {
+		pr_debug("MHL: NON-MHL DEVICE!!!\n");
+		mhl_i2c_reg_modify(TX_PAGE_3, 0x0018, BIT3, BIT3);
+	}
+}
+
+static void force_usb_switch_open(void)
+{
+	/*DISABLE_DISCOVERY*/
+	mhl_i2c_reg_modify(TX_PAGE_3, 0x0010, BIT0, 0);
+	/* Force USB ID switch to open*/
+	mhl_i2c_reg_modify(TX_PAGE_3, 0x0015, BIT6, BIT6);
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0012, 0x86);
+	/* Force HPD to 0 when not in Mobile HD mode. */
+	mhl_i2c_reg_modify(TX_PAGE_3, 0x0020, BIT5 | BIT4, BIT4);
+}
+
+static void release_usb_switch_open(void)
+{
+	msleep(50);
+	mhl_i2c_reg_modify(TX_PAGE_3, 0x0015, BIT6, 0x00);
+	mhl_i2c_reg_modify(TX_PAGE_3, 0x0010, BIT0, BIT0);
+}
+
+static void int_4_isr(void)
+{
+	uint8_t status;
+
+	/* INTR_STATUS4 */
+	status = mhl_i2c_reg_read(TX_PAGE_3, 0x0021);
+
+	/*
+	 * When I2C is inoperational (D3) and
+	 * a previous interrupt brought us here,
+	 * do nothing.
+	 */
+	pr_debug("MHL: MRR Interrupt status is = %02X\n", (int) status);
+	if (0xFF != status) {
+		if ((status & BIT0) && (mhl_msm_state->chip_rev_id < 1)) {
+			uint8_t tmds_cstat;
+			uint8_t mhl_fifo_status;
+
+			/* TMDS CSTAT */
+			tmds_cstat = mhl_i2c_reg_read(TX_PAGE_3, 0x0040);
+
+			pr_debug("TMDS CSTAT: 0x%02x\n", tmds_cstat);
+
+			if (tmds_cstat & 0x02) {
+				mhl_fifo_status = mhl_i2c_reg_read(TX_PAGE_3,
+					0x0023);
+				pr_debug("MHL FIFO status: 0x%02x\n",
+					mhl_fifo_status);
+				if (mhl_fifo_status & 0x0C) {
+					mhl_i2c_reg_write(TX_PAGE_3, 0x0023,
+						0x0C);
+
+					pr_debug("Apply MHL FIFO Reset\n");
+					mhl_i2c_reg_write(TX_PAGE_3, 0x0000,
+						0x94);
+					mhl_i2c_reg_write(TX_PAGE_3, 0x0000,
+						0x84);
+				}
+			}
+		}
+
+		if (status & BIT1)
+			pr_err("MHL: INT4 BIT1 is set\n");
+
+		/* MHL_EST interrupt */
+		if (status & BIT2) {
+			pr_err("MHL: Calling mhl_msm_connection() from ISR\n");
+			mhl_msm_connection();
+			pr_err("MHL Connect  Drv: INT4 Status = %02X\n",
+				(int) status);
+		} else if (status & BIT3) {
+			pr_err("MHL: uUSB-A type device detected.\n");
+			mhl_i2c_reg_write(TX_PAGE_3, 0x001C, 0x80);
+			switch_mode(POWER_STATE_D3);
+		}
+
+		if (status & BIT5) {
+			mhl_msm_disconnection();
+			pr_err("MHL Disconnect Drv: INT4 Status = %02X\n",
+				(int)status);
+		}
+
+		if ((mhl_msm_state->cur_state != POWER_STATE_D0_MHL) &&\
+			(status & BIT6)) {
+			/* RGND READY Intr */
+			switch_mode(POWER_STATE_D0_MHL);
+			mhl_msm_read_rgnd_int();
+		}
+
+		/* Can't succeed at these in D3 */
+		if (mhl_msm_state->cur_state != POWER_STATE_D3) {
+			/* CBUS Lockout interrupt? */
+			/*
+			 * Hardware detection mechanism figures that
+			 * CBUS line is latched and raises this intr
+			 * where we force usb switch open and release
+			 */
+			if (status & BIT4) {
+				force_usb_switch_open();
+				release_usb_switch_open();
+			}
+		}
+	}
+	pr_debug("MHL END  Drv: INT4 Status = %02X\n", (int) status);
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0021, status);
+
+	return;
+}
+
+static void int_5_isr(void)
+{
+	uint8_t intr_5_stat;
+
+	/*
+	 * Clear INT 5 ??
+	 * Probably need to revisit this later
+	 * INTR5 is related to FIFO underflow/overflow reset
+	 * which is handled in 8334 by auto FIFO reset
+	 */
+	intr_5_stat = mhl_i2c_reg_read(TX_PAGE_3, 0x0023);
+	mhl_i2c_reg_write(TX_PAGE_3, 0x0023, intr_5_stat);
+}
+
+
+static void int_1_isr(void)
+{
+	/* This ISR mainly handles the HPD status changes */
+	uint8_t intr_1_stat;
+	uint8_t cbus_stat;
+
+	/* INTR STATUS 1 */
+	intr_1_stat = mhl_i2c_reg_read(TX_PAGE_L0, 0x0071);
+
+	if (intr_1_stat) {
+		/* Clear interrupts */
+		mhl_i2c_reg_write(TX_PAGE_L0, 0x0071, intr_1_stat);
+		if (BIT6 & intr_1_stat) {
+			/*
+			 * HPD status change event is pending
+			 * Read CBUS HPD status for this info
+			 */
+
+			/* MSC REQ ABRT REASON */
+			cbus_stat = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x0D);
+			if (BIT6 & cbus_stat)
+				mhl_drive_hpd(HPD_UP);
+		}
+	}
+	return;
+}
+
+/*
+ * RCP, RAP messages - mandatory for compliance
+ *
+ */
+static void mhl_cbus_isr(void)
+{
+	uint8_t regval;
+	int req_done = FALSE;
+	uint8_t sub_cmd;
+	uint8_t cmd_data;
+	int msc_msg_recved = FALSE;
+	int rc = -1;
+
+	regval  = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x08);
+	if (regval == 0xff)
+		return;
+
+	/* clear all interrupts that were raised even if we did not process */
+	if (regval)
+		mhl_i2c_reg_write(TX_PAGE_CBUS, 0x08, regval);
+
+	pr_err("%s: CBUS_INT = %02x\n", __func__, regval);
+
+	/* MSC_MSG (RCP/RAP) */
+	if (regval & BIT(3)) {
+		sub_cmd = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x18);
+		cmd_data = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x19);
+		msc_msg_recved = TRUE;
+	}
+
+	/* MSC_REQ_DONE */
+	if (regval & BIT(4))
+		req_done = TRUE;
+
+	/* Now look for interrupts on CBUS_MSC_INT2 */
+	regval  = mhl_i2c_reg_read(TX_PAGE_CBUS, 0x1E);
+
+	/* clear all interrupts that were raised */
+	/* even if we did not process */
+	if (regval)
+		mhl_i2c_reg_write(TX_PAGE_CBUS, 0x1E, regval);
+
+	pr_err("%s: CBUS_MSC_INT2 = %02x\n", __func__, regval);
+
+	/* received SET_INT */
+	if (regval & BIT(2)) {
+		uint8_t intr;
+		intr = mhl_i2c_reg_read(TX_PAGE_CBUS, 0xA0);
+		pr_debug("%s: MHL_INT_0 = %02x\n", __func__, intr);
+		intr = mhl_i2c_reg_read(TX_PAGE_CBUS, 0xA1);
+		pr_debug("%s: MHL_INT_1 = %02x\n", __func__, intr);
+		mhl_i2c_reg_write(TX_PAGE_CBUS, 0xA0, 0xFF);
+		mhl_i2c_reg_write(TX_PAGE_CBUS, 0xA1, 0xFF);
+		mhl_i2c_reg_write(TX_PAGE_CBUS, 0xA2, 0xFF);
+		mhl_i2c_reg_write(TX_PAGE_CBUS, 0xA3, 0xFF);
+	}
+
+	/* received WRITE_STAT */
+	if (regval & BIT(3)) {
+		uint8_t stat;
+		stat = mhl_i2c_reg_read(TX_PAGE_CBUS, 0xB0);
+		pr_err("%s: MHL_STATUS_0 = %02x\n", __func__, stat);
+		stat = mhl_i2c_reg_read(TX_PAGE_CBUS, 0xB1);
+		pr_err("%s: MHL_STATUS_1 = %02x\n", __func__, stat);
+
+		mhl_i2c_reg_write(TX_PAGE_CBUS, 0xB0, 0xFF);
+		mhl_i2c_reg_write(TX_PAGE_CBUS, 0xB1, 0xFF);
+		mhl_i2c_reg_write(TX_PAGE_CBUS, 0xB2, 0xFF);
+		mhl_i2c_reg_write(TX_PAGE_CBUS, 0xB3, 0xFF);
+	}
+
+	/* received MSC_MSG */
+	if (msc_msg_recved) {
+		/*mhl msc recv msc msg*/
+		if (rc)
+			pr_err("MHL: mhl msc recv msc msg failed(%d)!\n", rc);
+	}
+
+	return;
+}
+
+static irqreturn_t mhl_tx_isr(int irq, void *dev_id)
+{
+	/*
+	 * Check discovery interrupt
+	 * if not yet connected
+	 */
+	pr_debug("MHL: Current POWER state is [0x%x]\n",
+		mhl_msm_state->cur_state);
+	/*
+	 * Check RGND, MHL_EST, CBUS_LOCKOUT, SCDT
+	 * interrupts. In D3, we get only RGND
+	 */
+	int_4_isr();
+
+	pr_debug("MHL: Current POWER state is [0x%x]\n",
+		mhl_msm_state->cur_state);
+	if (mhl_msm_state->cur_state == POWER_STATE_D0_MHL) {
+		/*
+		 * If int_4_isr() didn't move the tx to D3
+		 * on disconnect, continue to check other
+		 * interrupt sources.
+		 */
+		int_5_isr();
+
+		/*
+		 * Check for any peer messages for DCAP_CHG etc
+		 * Dispatch to have the CBUS module working only
+		 * once connected.
+		 */
+		mhl_cbus_isr();
+		int_1_isr();
+	}
+	return IRQ_HANDLED;
+}
+
+static void __exit mhl_msm_exit(void)
+{
+	pr_warn("MHL: Exiting, Bye\n");
+	/*
+	 * Delete driver if i2c client structure is NULL
+	 */
+	i2c_del_driver(&mhl_sii_i2c_driver);
+	if (!mhl_msm_state) {
+		kfree(mhl_msm_state);
+		mhl_msm_state = NULL;
+	 }
+}
+
+module_init(mhl_msm_init);
+module_exit(mhl_msm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MHL SII 8334 TX driver");
diff --git a/drivers/video/msm/mhl/mhl_8334.h b/drivers/video/msm/mhl/mhl_8334.h
new file mode 100644
index 0000000..c1d9030
--- /dev/null
+++ b/drivers/video/msm/mhl/mhl_8334.h
@@ -0,0 +1,74 @@
+/* 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 __MHL_MSM_H__
+#define __MHL_MSM_H__
+
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <mach/board.h>
+
+#include "mhl_devcap.h"
+#include "mhl_defs.h"
+
+#define GPIO_MHL_RESET       15
+#define GPIO_MHL_INT         4
+
+#define MHL_DEVICE_NAME "sii8334"
+#define MHL_DRIVER_NAME "sii8334"
+
+#define HPD_UP               1
+#define HPD_DOWN             0
+
+struct mhl_msm_state_t {
+	struct i2c_client *i2c_client;
+	struct i2c_driver *i2c_driver;
+	uint8_t      cur_state;
+	uint8_t chip_rev_id;
+	struct msm_mhl_platform_data *mhl_data;
+};
+
+enum {
+	TX_PAGE_TPI          = 0x00,
+	TX_PAGE_L0           = 0x01,
+	TX_PAGE_L1           = 0x02,
+	TX_PAGE_2            = 0x03,
+	TX_PAGE_3            = 0x04,
+	TX_PAGE_CBUS         = 0x05,
+	TX_PAGE_DDC_EDID     = 0x06,
+	TX_PAGE_DDC_SEGM     = 0x07,
+};
+
+enum mhl_st_type {
+	POWER_STATE_D0_NO_MHL = 0,
+	POWER_STATE_D0_MHL    = 2,
+	POWER_STATE_D3        = 3,
+};
+
+enum {
+	DEV_PAGE_TPI_0      = (0x72),
+	DEV_PAGE_TX_L0_0    = (0x72),
+	DEV_PAGE_TPI_1      = (0x76),
+	DEV_PAGE_TX_L0_1    = (0x76),
+	DEV_PAGE_TX_L1_0    = (0x7A),
+	DEV_PAGE_TX_L1_1    = (0x7E),
+	DEV_PAGE_TX_2_0     = (0x92),
+	DEV_PAGE_TX_2_1     = (0x96),
+	DEV_PAGE_TX_3_0	    = (0x9A),
+	DEV_PAGE_TX_3_1	    = (0x9E),
+	DEV_PAGE_CBUS       = (0xC8),
+	DEV_PAGE_DDC_EDID   = (0xA0),
+	DEV_PAGE_DDC_SEGM   = (0x60),
+};
+
+#endif /* __MHL_MSM_H__ */
diff --git a/drivers/video/msm/mhl/mhl_defs.h b/drivers/video/msm/mhl/mhl_defs.h
new file mode 100644
index 0000000..094874e
--- /dev/null
+++ b/drivers/video/msm/mhl/mhl_defs.h
@@ -0,0 +1,222 @@
+/* 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 __MHL_SPEC_DEFS_H__
+#define __MHL_SPEC_DEFS_H__
+
+enum DevCapOffset_e {
+	DEVCAP_OFFSET_DEV_STATE         = 0x00,
+	DEVCAP_OFFSET_MHL_VERSION	= 0x01,
+	DEVCAP_OFFSET_DEV_CAT           = 0x02,
+	DEVCAP_OFFSET_ADOPTER_ID_H      = 0x03,
+	DEVCAP_OFFSET_ADOPTER_ID_L      = 0x04,
+	DEVCAP_OFFSET_VID_LINK_MODE     = 0x05,
+	DEVCAP_OFFSET_AUD_LINK_MODE     = 0x06,
+	DEVCAP_OFFSET_VIDEO_TYPE        = 0x07,
+	DEVCAP_OFFSET_LOG_DEV_MAP       = 0x08,
+	DEVCAP_OFFSET_BANDWIDTH         = 0x09,
+	DEVCAP_OFFSET_FEATURE_FLAG      = 0x0A,
+	DEVCAP_OFFSET_DEVICE_ID_H       = 0x0B,
+	DEVCAP_OFFSET_DEVICE_ID_L       = 0x0C,
+	DEVCAP_OFFSET_SCRATCHPAD_SIZE   = 0x0D,
+	DEVCAP_OFFSET_INT_STAT_SIZE     = 0x0E,
+	DEVCAP_OFFSET_RESERVED          = 0x0F,
+	/* this one must be last */
+	DEVCAP_SIZE
+};
+
+#ifndef __MHL_MSM_8334_REGS_H__
+#define __MHL_MSM_8334_REGS_H__
+
+#define BIT0                    0x01
+#define BIT1                    0x02
+#define BIT2                    0x04
+#define BIT3                    0x08
+#define BIT4                    0x10
+#define BIT5                    0x20
+#define BIT6                    0x40
+#define BIT7                    0x80
+
+#define LOW                     0
+#define HIGH                    1
+
+#define MAX_PAGES               8
+#endif
+
+
+/* Version that this chip supports*/
+/* bits 4..7 */
+#define	MHL_VER_MAJOR           (0x01 << 4)
+/* bits 0..3 */
+#define	MHL_VER_MINOR		0x01
+#define MHL_VERSION		(MHL_VER_MAJOR | MHL_VER_MINOR)
+
+/*Device Category*/
+#define	MHL_DEV_CATEGORY_OFFSET		DEVCAP_OFFSET_DEV_CAT
+#define	MHL_DEV_CATEGORY_POW_BIT	(BIT4)
+
+#define	MHL_DEV_CAT_SOURCE		0x02
+
+/*Video Link Mode*/
+#define	MHL_DEV_VID_LINK_SUPPRGB444		0x01
+#define	MHL_DEV_VID_LINK_SUPPYCBCR444		0x02
+#define	MHL_DEV_VID_LINK_SUPPYCBCR422		0x04
+#define	MHL_DEV_VID_LINK_SUPP_PPIXEL		0x08
+#define	MHL_DEV_VID_LINK_SUPP_ISLANDS		0x10
+
+/*Audio Link Mode Support*/
+#define	MHL_DEV_AUD_LINK_2CH				0x01
+#define	MHL_DEV_AUD_LINK_8CH				0x02
+
+
+/*Feature Flag in the devcap*/
+#define	MHL_DEV_FEATURE_FLAG_OFFSET		DEVCAP_OFFSET_FEATURE_FLAG
+/* Dongles have freedom to not support RCP */
+#define	MHL_FEATURE_RCP_SUPPORT				BIT0
+/* Dongles have freedom to not support RAP */
+#define	MHL_FEATURE_RAP_SUPPORT				BIT1
+/* Dongles have freedom to not support SCRATCHPAD */
+#define	MHL_FEATURE_SP_SUPPORT				BIT2
+
+/*Logical Dev Map*/
+#define	MHL_DEV_LD_DISPLAY					(0x01 << 0)
+#define	MHL_DEV_LD_VIDEO					(0x01 << 1)
+#define	MHL_DEV_LD_AUDIO					(0x01 << 2)
+#define	MHL_DEV_LD_MEDIA					(0x01 << 3)
+#define	MHL_DEV_LD_TUNER					(0x01 << 4)
+#define	MHL_DEV_LD_RECORD					(0x01 << 5)
+#define	MHL_DEV_LD_SPEAKER					(0x01 << 6)
+#define	MHL_DEV_LD_GUI						(0x01 << 7)
+
+/*Bandwidth*/
+/* 225 MHz */
+#define	MHL_BANDWIDTH_LIMIT					22
+
+
+#define MHL_STATUS_REG_CONNECTED_RDY        0x30
+#define MHL_STATUS_REG_LINK_MODE            0x31
+
+#define	MHL_STATUS_DCAP_RDY					BIT0
+
+#define MHL_STATUS_CLK_MODE_MASK            0x07
+#define MHL_STATUS_CLK_MODE_PACKED_PIXEL    0x02
+#define MHL_STATUS_CLK_MODE_NORMAL          0x03
+#define MHL_STATUS_PATH_EN_MASK             0x08
+#define MHL_STATUS_PATH_ENABLED             0x08
+#define MHL_STATUS_PATH_DISABLED            0x00
+#define MHL_STATUS_MUTED_MASK               0x10
+
+#define MHL_RCHANGE_INT                     0x20
+#define MHL_DCHANGE_INT                     0x21
+
+#define	MHL_INT_DCAP_CHG					BIT0
+#define MHL_INT_DSCR_CHG                    BIT1
+#define MHL_INT_REQ_WRT                     BIT2
+#define MHL_INT_GRT_WRT                     BIT3
+
+/* On INTR_1 the EDID_CHG is located at BIT 0*/
+#define	MHL_INT_EDID_CHG					BIT1
+
+/* This contains one nibble each - max offset */
+#define		MHL_INT_AND_STATUS_SIZE			0x33
+#define		MHL_SCRATCHPAD_SIZE			16
+/* manually define highest number */
+#define		MHL_MAX_BUFFER_SIZE			MHL_SCRATCHPAD_SIZE
+
+
+
+enum {
+	/* RCP sub-command  */
+	MHL_MSC_MSG_RCP             = 0x10,
+	/* RCP Acknowledge sub-command  */
+	MHL_MSC_MSG_RCPK            = 0x11,
+	/* RCP Error sub-command  */
+	MHL_MSC_MSG_RCPE            = 0x12,
+	/* Mode Change Warning sub-command  */
+	MHL_MSC_MSG_RAP             = 0x20,
+	/* MCW Acknowledge sub-command  */
+	MHL_MSC_MSG_RAPK            = 0x21,
+};
+
+#define	RCPE_NO_ERROR				0x00
+#define	RCPE_INEEFECTIVE_KEY_CODE	0x01
+#define	RCPE_BUSY					0x02
+/* MHL spec related defines*/
+enum {
+	/* Command or Data byte acknowledge */
+	MHL_ACK						= 0x33,
+	/* Command or Data byte not acknowledge */
+	MHL_NACK					= 0x34,
+	/* Transaction abort */
+	MHL_ABORT					= 0x35,
+	/* 0xE0 - Write one status register strip top bit */
+	MHL_WRITE_STAT				= 0x60 | 0x80,
+	/* Write one interrupt register */
+	MHL_SET_INT					= 0x60,
+	/* Read one register */
+	MHL_READ_DEVCAP				= 0x61,
+	/* Read CBUS revision level from follower */
+	MHL_GET_STATE				= 0x62,
+	/* Read vendor ID value from follower. */
+	MHL_GET_VENDOR_ID			= 0x63,
+	/* Set Hot Plug Detect in follower */
+	MHL_SET_HPD					= 0x64,
+	/* Clear Hot Plug Detect in follower */
+	MHL_CLR_HPD					= 0x65,
+	/* Set Capture ID for downstream device. */
+	MHL_SET_CAP_ID				= 0x66,
+	/* Get Capture ID from downstream device. */
+	MHL_GET_CAP_ID				= 0x67,
+	/* VS command to send RCP sub-commands */
+	MHL_MSC_MSG					= 0x68,
+	/* Get Vendor-Specific command error code. */
+	MHL_GET_SC1_ERRORCODE		= 0x69,
+	/* Get DDC channel command error code. */
+	MHL_GET_DDC_ERRORCODE		= 0x6A,
+	/* Get MSC command error code. */
+	MHL_GET_MSC_ERRORCODE		= 0x6B,
+	/* Write 1-16 bytes to responder's scratchpad. */
+	MHL_WRITE_BURST				= 0x6C,
+	/* Get channel 3 command error code. */
+	MHL_GET_SC3_ERRORCODE		= 0x6D,
+};
+
+/* Turn content streaming ON. */
+#define	MHL_RAP_CONTENT_ON		0x10
+/* Turn content streaming OFF. */
+#define	MHL_RAP_CONTENT_OFF		0x11
+
+/*
+ *
+ * MHL Timings applicable to this driver.
+ *
+ */
+/* 100 - 1000 milliseconds. Per MHL 1.0 Specs */
+#define	T_SRC_VBUS_CBUS_TO_STABLE	(200)
+/* 20 milliseconds. Per MHL 1.0 Specs */
+#define	T_SRC_WAKE_PULSE_WIDTH_1	(20)
+/* 60 milliseconds. Per MHL 1.0 Specs */
+#define	T_SRC_WAKE_PULSE_WIDTH_2	(60)
+
+/* 100 - 1000 milliseconds. Per MHL 1.0 Specs */
+#define	T_SRC_WAKE_TO_DISCOVER		(500)
+
+#define T_SRC_VBUS_CBUS_T0_STABLE	(500)
+
+/* Allow RSEN to stay low this much before reacting.*/
+#define	T_SRC_RSEN_DEGLITCH			(100)
+
+/* Wait this much after connection before reacting to RSEN (300-500ms)*/
+/* Per specs between 300 to 500 ms*/
+#define	T_SRC_RXSENSE_CHK			(400)
+
+#endif /* __MHL_SPEC_DEFS_H__ */
diff --git a/drivers/video/msm/mhl/mhl_devcap.h b/drivers/video/msm/mhl/mhl_devcap.h
new file mode 100644
index 0000000..6d01daf
--- /dev/null
+++ b/drivers/video/msm/mhl/mhl_devcap.h
@@ -0,0 +1,45 @@
+/* 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 __MHL_DEVCAP_H__
+#define __MHL_DEVCAP_H__
+
+#define SILICON_IMAGE_ADOPTER_ID 322
+#define TRANSCODER_DEVICE_ID 0x8334
+
+#define MHL_DEV_LD_AUDIO (0x01 << 2)
+#define MHL_DEV_LD_VIDEO (0x01 << 1)
+#define MHL_DEV_LD_MEDIA (0x01 << 3)
+#define MHL_DEV_LD_GUI (0x01 << 7)
+#define	MHL_LOGICAL_DEVICE_MAP		(MHL_DEV_LD_AUDIO |\
+	MHL_DEV_LD_VIDEO | MHL_DEV_LD_MEDIA | MHL_DEV_LD_GUI)
+
+#define DEVCAP_VAL_DEV_STATE       0
+#define DEVCAP_VAL_MHL_VERSION     MHL_VERSION
+#define DEVCAP_VAL_DEV_CAT         (MHL_DEV_CAT_SOURCE |\
+	MHL_DEV_CATEGORY_POW_BIT)
+#define DEVCAP_VAL_ADOPTER_ID_H    (uint8_t)(SILICON_IMAGE_ADOPTER_ID >>   8)
+#define DEVCAP_VAL_ADOPTER_ID_L    (uint8_t)(SILICON_IMAGE_ADOPTER_ID & 0xFF)
+#define DEVCAP_VAL_VID_LINK_MODE   MHL_DEV_VID_LINK_SUPPRGB444
+#define DEVCAP_VAL_AUD_LINK_MODE   MHL_DEV_AUD_LINK_2CH
+#define DEVCAP_VAL_VIDEO_TYPE      0
+#define DEVCAP_VAL_LOG_DEV_MAP     MHL_LOGICAL_DEVICE_MAP
+#define DEVCAP_VAL_BANDWIDTH       0
+#define DEVCAP_VAL_FEATURE_FLAG    (MHL_FEATURE_RCP_SUPPORT |\
+	MHL_FEATURE_RAP_SUPPORT | MHL_FEATURE_SP_SUPPORT)
+#define DEVCAP_VAL_DEVICE_ID_H     (uint8_t)(TRANSCODER_DEVICE_ID >>   8)
+#define DEVCAP_VAL_DEVICE_ID_L     (uint8_t)(TRANSCODER_DEVICE_ID & 0xFF)
+#define DEVCAP_VAL_SCRATCHPAD_SIZE MHL_SCRATCHPAD_SIZE
+#define DEVCAP_VAL_INT_STAT_SIZE   MHL_INT_AND_STATUS_SIZE
+#define DEVCAP_VAL_RESERVED        0
+
+#endif /* __MHL_DEVCAP_H__ */
diff --git a/drivers/video/msm/mhl/mhl_i2c_utils.c b/drivers/video/msm/mhl/mhl_i2c_utils.c
new file mode 100644
index 0000000..596af2e
--- /dev/null
+++ b/drivers/video/msm/mhl/mhl_i2c_utils.c
@@ -0,0 +1,107 @@
+/* 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/i2c.h>
+
+#include "mhl_i2c_utils.h"
+#include "mhl_8334.h"
+
+#define DEBUG
+
+uint8_t slave_addrs[MAX_PAGES] = {
+	DEV_PAGE_TPI_0    ,
+	DEV_PAGE_TX_L0_0  ,
+	DEV_PAGE_TX_L1_0  ,
+	DEV_PAGE_TX_2_0   ,
+	DEV_PAGE_TX_3_0   ,
+	DEV_PAGE_CBUS     ,
+	DEV_PAGE_DDC_EDID ,
+	DEV_PAGE_DDC_SEGM ,
+};
+
+int mhl_i2c_reg_read(uint8_t slave_addr_index, uint8_t reg_offset)
+{
+	struct i2c_msg msgs[2];
+	uint8_t buffer = 0;
+	int ret = -1;
+
+	pr_debug("MRR: Reading from slave_addr_index=[%x] and offset=[%x]\n",
+		slave_addr_index, reg_offset);
+	pr_debug("MRR: Addr slave_addr_index=[%x]\n",
+		slave_addrs[slave_addr_index]);
+
+	/* Slave addr */
+	msgs[0].addr = slave_addrs[slave_addr_index] >> 1;
+	msgs[1].addr = slave_addrs[slave_addr_index] >> 1;
+
+	/* Write Command */
+	msgs[0].flags = 0;
+	msgs[1].flags = I2C_M_RD;
+
+	/* Register offset for the next transaction */
+	msgs[0].buf = &reg_offset;
+	msgs[1].buf = &buffer;
+
+	/* Offset is 1 Byte long */
+	msgs[0].len = 1;
+	msgs[1].len = 1;
+
+	ret = i2c_transfer(mhl_msm_state->i2c_client->adapter, msgs, 2);
+	if (ret < 1) {
+		pr_err("I2C READ FAILED=[%d]\n", ret);
+		return -EACCES;
+	}
+	pr_err("Buffer is [%x]\n", buffer);
+	return buffer;
+}
+
+
+int mhl_i2c_reg_write(uint8_t slave_addr_index, uint8_t reg_offset,
+	uint8_t value)
+{
+	return mhl_i2c_reg_write_cmds(slave_addr_index, reg_offset, &value, 1);
+}
+
+int mhl_i2c_reg_write_cmds(uint8_t slave_addr_index, uint8_t reg_offset,
+	uint8_t *value, uint16_t count)
+{
+	struct i2c_msg msgs[1];
+	uint8_t data[2];
+	int status = -EACCES;
+
+	msgs[0].addr = slave_addrs[slave_addr_index] >> 1;
+	msgs[0].flags = 0;
+	msgs[0].len = 2;
+	msgs[0].buf = data;
+	data[0] = reg_offset;
+	data[1] = *value;
+
+	status = i2c_transfer(mhl_msm_state->i2c_client->adapter, msgs, 1);
+	if (status < 1) {
+		pr_err("I2C WRITE FAILED=[%d]\n", status);
+		return -EACCES;
+	}
+
+	return status;
+}
+
+void mhl_i2c_reg_modify(uint8_t slave_addr_index, uint8_t reg_offset,
+	uint8_t mask, uint8_t val)
+{
+	uint8_t temp;
+
+	temp = mhl_i2c_reg_read(slave_addr_index, reg_offset);
+	temp &= (~mask);
+	temp |= (mask & val);
+	mhl_i2c_reg_write(slave_addr_index, reg_offset, temp);
+}
+
diff --git a/drivers/video/msm/mhl/mhl_i2c_utils.h b/drivers/video/msm/mhl/mhl_i2c_utils.h
new file mode 100644
index 0000000..76498d4
--- /dev/null
+++ b/drivers/video/msm/mhl/mhl_i2c_utils.h
@@ -0,0 +1,39 @@
+/* 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 __MHL_I2C_UTILS_H__
+#define __MHL_I2C_UTILS_H__
+
+#include <linux/i2c.h>
+#include <linux/types.h>
+
+#include "mhl_defs.h"
+
+/*
+ * I2C command to the adapter to append
+ * the buffer from next msg to this one.
+ */
+#define I2C_M_APPND_NXT_WR          0x0002
+
+extern uint8_t slave_addrs[MAX_PAGES];
+extern struct mhl_msm_state_t *mhl_msm_state;
+
+int mhl_i2c_reg_read(uint8_t slave_addr_index, uint8_t reg_offset);
+int mhl_i2c_reg_write(uint8_t slave_addr_index, uint8_t reg_offset,
+	uint8_t value);
+int mhl_i2c_reg_write_cmds(uint8_t slave_addr_index, uint8_t reg_offset,
+	uint8_t *value, uint16_t count);
+void mhl_i2c_reg_modify(uint8_t slave_addr_index, uint8_t reg_offset,
+	uint8_t mask, uint8_t val);
+
+#endif /* __MHL_I2C_UTILS_H__ */
diff --git a/drivers/video/msm/mhl_api.h b/drivers/video/msm/mhl_api.h
index 627f802..a4364ea 100644
--- a/drivers/video/msm/mhl_api.h
+++ b/drivers/video/msm/mhl_api.h
@@ -14,7 +14,7 @@
 #ifndef __MHL_API_H__
 #define __MHL_API_H__
 
-#ifdef CONFIG_FB_MSM_HDMI_MHL
+#ifdef CONFIG_FB_MSM_HDMI_MHL_8334
 bool mhl_is_connected(void);
 #else
 static bool mhl_is_connected(void)
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
index b720800..62f0976 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
@@ -1000,7 +1000,8 @@
 			(decoder->frame_size.scan_lines ==
 			decoder->client_frame_size.scan_lines) &&
 			(decoder->frame_size.stride ==
-			decoder->client_frame_size.stride))
+			decoder->client_frame_size.stride) &&
+			decoder->progressive_only)
 				need_reconfig = false;
 	}
 	return need_reconfig;
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
index 86e9ff6..0d5ba9c 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
@@ -342,6 +342,7 @@
 static u32 vcd_flush_in_eos(struct vcd_clnt_ctxt *cctxt,
 	u32 mode)
 {
+	u32 rc = VCD_S_SUCCESS;
 	VCD_MSG_LOW("vcd_flush_in_eos:");
 
 	if (mode > VCD_FLUSH_ALL || !mode) {
@@ -351,10 +352,18 @@
 	}
 
 	VCD_MSG_MED("Flush mode requested %d", mode);
+	if (!(cctxt->status.frame_submitted) &&
+		(!cctxt->decoding)) {
+		rc = vcd_flush_buffers(cctxt, mode);
+		if (!VCD_FAILED(rc)) {
+			VCD_MSG_HIGH("All buffers are flushed");
+			cctxt->status.mask |= (mode & VCD_FLUSH_ALL);
+			vcd_send_flush_done(cctxt, VCD_S_SUCCESS);
+		}
+	} else
+		cctxt->status.mask |= (mode & VCD_FLUSH_ALL);
 
-	cctxt->status.mask |= (mode & VCD_FLUSH_ALL);
-
-	return VCD_S_SUCCESS;
+	return rc;
 }
 
 static u32 vcd_flush_in_invalid(struct vcd_clnt_ctxt *cctxt,
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index e7cc68e..1dae562 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1031,6 +1031,55 @@
  *	%NL80211_CMD_SET_BEACON to provide extra IEs (e.g., WPS/P2P IE) into
  *	(Re)Association Response frames when the driver (or firmware) replies to
  *	(Re)Association Request frames.
+ * @NL80211_ATTR_STA_WME: Nested attribute containing the wme configuration
+ *      of the station, see &enum nl80211_sta_wme_attr.
+ * @NL80211_ATTR_SUPPORT_AP_UAPSD: the device supports uapsd when working
+ *      as AP.
+ *
+ * @NL80211_ATTR_ROAM_SUPPORT: Indicates whether the firmware is capable of
+ *      roaming to another AP in the same ESS if the signal lever is low.
+ *
+ * @NL80211_ATTR_PMKSA_CANDIDATE: Nested attribute containing the PMKSA caching
+ *      candidate information, see &enum nl80211_pmksa_candidate_attr.
+ *
+ * @NL80211_ATTR_TX_NO_CCK_RATE: Indicates whether to use CCK rate or not
+ *      for management frames transmission. In order to avoid p2p probe/action
+ *      frames are being transmitted at CCK rate in 2GHz band, the user space
+ *      applications use this attribute.
+ *      This attribute is used with %NL80211_CMD_TRIGGER_SCAN and
+ *      %NL80211_CMD_FRAME commands.
+ *
+ * @NL80211_ATTR_TDLS_ACTION: Low level TDLS action code (e.g. link setup
+ *      request, link setup confirm, link teardown, etc.). Values are
+ *      described in the TDLS (802.11z) specification.
+ * @NL80211_ATTR_TDLS_DIALOG_TOKEN: Non-zero token for uniquely identifying a
+ *      TDLS conversation between two devices.
+ * @NL80211_ATTR_TDLS_OPERATION: High level TDLS operation; see
+ *      &enum nl80211_tdls_operation, represented as a u8.
+ * @NL80211_ATTR_TDLS_SUPPORT: A flag indicating the device can operate
+ *      as a TDLS peer sta.
+ * @NL80211_ATTR_TDLS_EXTERNAL_SETUP: The TDLS discovery/setup and teardown
+ *      procedures should be performed by sending TDLS packets via
+ *      %NL80211_CMD_TDLS_MGMT. Otherwise %NL80211_CMD_TDLS_OPER should be
+ *      used for asking the driver to perform a TDLS operation.
+ *
+ * @NL80211_ATTR_DEVICE_AP_SME: This u32 attribute may be listed for devices
+ *      that have AP support to indicate that they have the AP SME integrated
+ *      with support for the features listed in this attribute, see
+ *      &enum nl80211_ap_sme_features.
+ *
+ * @NL80211_ATTR_DONT_WAIT_FOR_ACK: Used with %NL80211_CMD_FRAME, this tells
+ *      the driver to not wait for an acknowledgement. Note that due to this,
+ *      it will also not give a status callback nor return a cookie. This is
+ *      mostly useful for probe responses to save airtime.
+ *
+ * @NL80211_ATTR_FEATURE_FLAGS: This u32 attribute contains flags from
+ *      &enum nl80211_feature_flags and is advertised in wiphy information.
+ * @NL80211_ATTR_PROBE_RESP_OFFLOAD: Indicates that the HW responds to probe
+ *
+ *      requests while operating in AP-mode.
+ *      This attribute holds a bitmap of the supported protocols for
+ *      offloading (see &enum nl80211_probe_resp_offload_support_attr).
  *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -1254,6 +1303,19 @@
 
 	NL80211_ATTR_TX_NO_CCK_RATE,
 
+	NL80211_ATTR_TDLS_ACTION,
+	NL80211_ATTR_TDLS_DIALOG_TOKEN,
+	NL80211_ATTR_TDLS_OPERATION,
+	NL80211_ATTR_TDLS_SUPPORT,
+	NL80211_ATTR_TDLS_EXTERNAL_SETUP,
+	NL80211_ATTR_DEVICE_AP_SME,
+
+	NL80211_ATTR_DONT_WAIT_FOR_ACK,
+
+	NL80211_ATTR_FEATURE_FLAGS,
+
+	NL80211_ATTR_PROBE_RESP_OFFLOAD,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -2436,4 +2498,35 @@
 	NL80211_HIDDEN_SSID_ZERO_CONTENTS
 };
 
+/*
+ * enum nl80211_ap_sme_features - device-integrated AP features
+ * Reserved for future use, no bits are defined in
+ * NL80211_ATTR_DEVICE_AP_SME yet.
+enum nl80211_ap_sme_features {
+};
+ */
+
+/**
+ * enum nl80211_probe_resp_offload_support_attr - optional supported
+ *     protocols for probe-response offloading by the driver/FW.
+ *     To be used with the %NL80211_ATTR_PROBE_RESP_OFFLOAD attribute.
+ *     Each enum value represents a bit in the bitmap of supported
+ *     protocols. Typically a subset of probe-requests belonging to a
+ *     supported protocol will be excluded from offload and uploaded
+ *     to the host.
+ *
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS: Support for WPS ver. 1
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2: Support for WPS ver. 2
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P: Support for P2P
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U: Support for 802.11u
+ */
+
+enum nl80211_probe_resp_offload_support_attr {
+	NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS =        1<<0,
+	NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 =       1<<1,
+	NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P =        1<<2,
+	NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U =     1<<3,
+};
+
+
 #endif /* __LINUX_NL80211_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 4898ea2..53c7196 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1584,6 +1584,21 @@
  * @WIPHY_FLAG_MESH_AUTH: The device supports mesh authentication by routing
  *	auth frames to userspace. See @NL80211_MESH_SETUP_USERSPACE_AUTH.
  * @WIPHY_FLAG_SUPPORTS_SCHED_SCAN: The device supports scheduled scans.
+ * @WIPHY_FLAG_SUPPORTS_FW_ROAM: The device supports roaming feature in the
+ *     firmware.
+ * @WIPHY_FLAG_AP_UAPSD: The device supports uapsd on AP.
+ * @WIPHY_FLAG_SUPPORTS_TDLS: The device supports TDLS (802.11z) operation.
+ * @WIPHY_FLAG_TDLS_EXTERNAL_SETUP: The device does not handle TDLS (802.11z)
+ *     link setup/discovery operations internally. Setup, discovery and
+ *     teardown packets should be sent through the @NL80211_CMD_TDLS_MGMT
+ *     command. When this flag is not set, @NL80211_CMD_TDLS_OPER should be
+ *     used for asking the driver/firmware to perform a TDLS operation.
+ * @WIPHY_FLAG_HAVE_AP_SME: device integrates AP SME
+ * @WIPHY_FLAG_REPORTS_OBSS: the device will report beacons from other BSSes
+ *      when there are virtual interfaces in AP mode by calling
+ *      cfg80211_report_obss_beacon().
+ * @WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD: When operating as an AP, the device
+ *      responds to probe-requests in hardware.
  */
 enum wiphy_flags {
 	WIPHY_FLAG_CUSTOM_REGULATORY		= BIT(0),
@@ -1598,6 +1613,13 @@
 	WIPHY_FLAG_MESH_AUTH			= BIT(10),
 	WIPHY_FLAG_SUPPORTS_SCHED_SCAN		= BIT(11),
 	WIPHY_FLAG_ENFORCE_COMBINATIONS		= BIT(12),
+	WIPHY_FLAG_SUPPORTS_FW_ROAM             = BIT(13),
+	WIPHY_FLAG_AP_UAPSD                     = BIT(14),
+	WIPHY_FLAG_SUPPORTS_TDLS                = BIT(15),
+	WIPHY_FLAG_TDLS_EXTERNAL_SETUP          = BIT(16),
+	WIPHY_FLAG_HAVE_AP_SME                  = BIT(17),
+	WIPHY_FLAG_REPORTS_OBSS                 = BIT(18),
+	WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD        = BIT(19),
 };
 
 /**
@@ -1788,6 +1810,7 @@
  *	may request, if implemented.
  *
  * @wowlan: WoWLAN support information
+ * @ap_sme_capa: AP SME capabilities, flags from &enum nl80211_ap_sme_features.
  */
 struct wiphy {
 	/* assign these fields before you register the wiphy */
@@ -1811,6 +1834,8 @@
 
 	u32 flags;
 
+	u32 ap_sme_capa;
+
 	enum cfg80211_signal_type signal_type;
 
 	int bss_priv_size;
@@ -1838,6 +1863,13 @@
 	u32 available_antennas_tx;
 	u32 available_antennas_rx;
 
+	/*
+	* Bitmap of supported protocols for probe response offloading
+	* see &enum nl80211_probe_resp_offload_support_attr. Only valid
+	* when the wiphy flag @WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD is set.
+	*/
+	u32 probe_resp_offload;
+
 	/* If multiple wiphys are registered and you're handed e.g.
 	 * a regular netdev with assigned ieee80211_ptr, you won't
 	 * know whether it points to a wiphy your driver has registered
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index f71d743..782ee8d 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -992,6 +992,7 @@
 		struct asm_qcelp13_read_cfg qcelp13;
 		struct asm_sbc_read_cfg     sbc;
 		struct asm_amrwb_read_cfg   amrwb;
+		struct asm_multi_channel_pcm_fmt_blk      mpcm;
 	} __attribute__((packed)) cfg;
 };
 
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index c3d4bd5..aec4171 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -238,6 +238,9 @@
 int q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
 			uint32_t rate, uint32_t channels);
 
+int q6asm_enc_cfg_blk_multi_ch_pcm(struct audio_client *ac,
+			uint32_t rate, uint32_t channels);
+
 int q6asm_enable_sbrps(struct audio_client *ac,
 			uint32_t sbr_ps);
 
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 8d52423..f51b006 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -815,6 +815,7 @@
 	struct mutex mutex;
 	struct mutex dapm_mutex;
 	struct mutex dsp_mutex;
+	spinlock_t dsp_spinlock;
 
 	bool instantiated;
 
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 880dbe2..e921d00 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -488,6 +488,10 @@
 	int i;
 	u16 ifmodes = wiphy->interface_modes;
 
+	if (WARN_ON(wiphy->ap_sme_capa &&
+		!(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME)))
+		return -EINVAL;
+
 	if (WARN_ON(wiphy->addresses && !wiphy->n_addresses))
 		return -EINVAL;
 
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index bf6915b..e6457ff 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -718,6 +718,10 @@
 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
 		    dev->wiphy.available_antennas_rx);
 
+	if (dev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD)
+		NLA_PUT_U32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD,
+			dev->wiphy.probe_resp_offload);
+
 	if ((dev->wiphy.available_antennas_tx ||
 	     dev->wiphy.available_antennas_rx) && dev->ops->get_antenna) {
 		u32 tx_ant = 0, rx_ant = 0;
@@ -954,6 +958,10 @@
 	if (nl80211_put_iface_combinations(&dev->wiphy, msg))
 		goto nla_put_failure;
 
+	if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME)
+		NLA_PUT_U32(msg, NL80211_ATTR_DEVICE_AP_SME,
+			dev->wiphy.ap_sme_capa);
+
 	return genlmsg_end(msg, hdr);
 
  nla_put_failure:
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 14d9adf..4c9cef9 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -62,7 +62,7 @@
 			.rates = SNDRV_PCM_RATE_8000_48000,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 			.channels_min = 1,
-			.channels_max = 2,
+			.channels_max = 4,
 			.rate_min =     8000,
 			.rate_max =	48000,
 		},
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index b0cfd34..a53dd44 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -1007,7 +1007,7 @@
 		SNDRV_PCM_RATE_16000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
 		.channels_min = 1,
-		.channels_max = 2,
+		.channels_max = 4,
 		.rate_min =     8000,
 		.rate_max =	48000,
 	},
diff --git a/sound/soc/msm/msm-pcm-q6.c b/sound/soc/msm/msm-pcm-q6.c
index dd194d6..4686386 100644
--- a/sound/soc/msm/msm-pcm-q6.c
+++ b/sound/soc/msm/msm-pcm-q6.c
@@ -55,7 +55,7 @@
 	.rate_min =             8000,
 	.rate_max =             48000,
 	.channels_min =         1,
-	.channels_max =         2,
+	.channels_max =         4,
 	.buffer_bytes_max =     CAPTURE_NUM_PERIODS * CAPTURE_PERIOD_SIZE,
 	.period_bytes_min =	CAPTURE_PERIOD_SIZE,
 	.period_bytes_max =     CAPTURE_PERIOD_SIZE,
@@ -248,8 +248,14 @@
 
 	pr_debug("Samp_rate = %d\n", prtd->samp_rate);
 	pr_debug("Channel = %d\n", prtd->channel_mode);
-	ret = q6asm_enc_cfg_blk_pcm(prtd->audio_client, prtd->samp_rate,
-					prtd->channel_mode);
+	if (prtd->channel_mode > 2) {
+		ret = q6asm_enc_cfg_blk_multi_ch_pcm(prtd->audio_client,
+		prtd->samp_rate, prtd->channel_mode);
+	} else {
+		ret = q6asm_enc_cfg_blk_pcm(prtd->audio_client,
+		prtd->samp_rate, prtd->channel_mode);
+	}
+
 	if (ret < 0)
 		pr_debug("%s: cmd cfg pcm was block failed", __func__);
 
@@ -331,13 +337,6 @@
 	/* Capture path */
 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
 		runtime->hw = msm_pcm_hardware_capture;
-		ret = q6asm_open_read(prtd->audio_client, FORMAT_LINEAR_PCM);
-		if (ret < 0) {
-			pr_err("%s: pcm in open failed\n", __func__);
-			q6asm_audio_client_free(prtd->audio_client);
-			kfree(prtd);
-			return -ENOMEM;
-		}
 	}
 
 	pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
@@ -622,12 +621,28 @@
 	struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
 	struct audio_buffer *buf;
 	int dir, ret;
+	int format = FORMAT_LINEAR_PCM;
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		dir = IN;
 	else
 		dir = OUT;
 
+	/*capture path*/
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		if (params_channels(params) > 2)
+			format = FORMAT_MULTI_CHANNEL_LINEAR_PCM;
+		pr_debug("%s format = :0x%x\n", __func__, format);
+
+		ret = q6asm_open_read(prtd->audio_client, format);
+		if (ret < 0) {
+			pr_err("%s: q6asm_open_read failed\n", __func__);
+			q6asm_audio_client_free(prtd->audio_client);
+			kfree(prtd);
+			return -ENOMEM;
+		}
+	}
+
 	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
 			prtd->audio_client,
 			runtime->hw.period_bytes_min,
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index c58bdf5..18f95f6 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -1842,8 +1842,9 @@
 		if (fe_dai_map[i][session_type] != INVALID_SESSION) {
 
 			channels = bedai->channel;
-			if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) &&
-				(channels > 2))
+			if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+				substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+				&& (channels > 2))
 				adm_multi_ch_copp_open(bedai->port_id,
 				path_type,
 				bedai->sample_rate,
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index e254cce..9dad1bb 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -520,9 +520,6 @@
 	}
 	codec_clk = clk_get(cpu_dai->dev, "osr_clk");
 
-	sitar_hs_detect(codec, &hs_jack, &button_jack, sitar_mbhc_cal,
-			SITAR_MICBIAS2, msm8930_enable_codec_ext_clk, 0,
-			SITAR_EXT_CLK_RATE);
 	return 0;
 }
 
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index bc5c007..3745b17 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -489,6 +489,11 @@
 		} else if (channel_mode == 2) {
 			open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
 			open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
+		} else if (channel_mode == 4) {
+			open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
+			open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
+			open.dev_channel_mapping[2] = PCM_CHANNEL_RB;
+			open.dev_channel_mapping[3] = PCM_CHANNEL_LB;
 		} else if (channel_mode == 6) {
 			open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
 			open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index c7ebd2c..f3a2383 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -1228,6 +1228,10 @@
 		open.uMode = STREAM_PRIORITY_HIGH;
 		open.format = LINEAR_PCM;
 		break;
+	case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
+		open.uMode = STREAM_PRIORITY_HIGH;
+		open.format = MULTI_CHANNEL_PCM;
+		break;
 	case FORMAT_MPEG4_AAC:
 		open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
 		open.format = MPEG4_AAC;
@@ -1664,6 +1668,56 @@
 	return -EINVAL;
 }
 
+int q6asm_enc_cfg_blk_multi_ch_pcm(struct audio_client *ac,
+			uint32_t rate, uint32_t channels)
+{
+	struct asm_stream_cmd_encdec_cfg_blk  enc_cfg;
+
+	int rc = 0;
+
+	pr_debug("%s: Session %d, rate = %d, channels = %d\n", __func__,
+			 ac->session, rate, channels);
+
+	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+
+	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+	enc_cfg.param_id = ASM_ENCDEC_CFG_BLK_ID;
+	enc_cfg.param_size = sizeof(struct asm_encode_cfg_blk);
+	enc_cfg.enc_blk.frames_per_buf = 1;
+	enc_cfg.enc_blk.format_id = MULTI_CHANNEL_PCM;
+	enc_cfg.enc_blk.cfg_size =
+		sizeof(struct asm_multi_channel_pcm_fmt_blk);
+	enc_cfg.enc_blk.cfg.mpcm.num_channels = channels;
+	enc_cfg.enc_blk.cfg.mpcm.bits_per_sample = 16;
+	enc_cfg.enc_blk.cfg.mpcm.sample_rate = rate;
+	enc_cfg.enc_blk.cfg.mpcm.is_signed = 1;
+	enc_cfg.enc_blk.cfg.mpcm.is_interleaved = 1;
+	enc_cfg.enc_blk.cfg.mpcm.channel_mapping[0] = PCM_CHANNEL_FL;
+	enc_cfg.enc_blk.cfg.mpcm.channel_mapping[1] = PCM_CHANNEL_FR;
+	enc_cfg.enc_blk.cfg.mpcm.channel_mapping[2] = PCM_CHANNEL_RB;
+	enc_cfg.enc_blk.cfg.mpcm.channel_mapping[3] = PCM_CHANNEL_LB;
+	enc_cfg.enc_blk.cfg.mpcm.channel_mapping[4] = 0;
+	enc_cfg.enc_blk.cfg.mpcm.channel_mapping[5] = 0;
+	enc_cfg.enc_blk.cfg.mpcm.channel_mapping[6] = 0;
+	enc_cfg.enc_blk.cfg.mpcm.channel_mapping[7] = 0;
+
+	rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+	if (rc < 0) {
+		pr_err("Comamnd open failed\n");
+		rc = -EINVAL;
+		goto fail_cmd;
+	}
+	rc = wait_event_timeout(ac->cmd_wait,
+			(atomic_read(&ac->cmd_state) == 0), 5*HZ);
+	if (!rc) {
+		pr_err("timeout opcode[0x%x] ", enc_cfg.hdr.opcode);
+		goto fail_cmd;
+	}
+	return 0;
+fail_cmd:
+	return -EINVAL;
+}
+
 int q6asm_enable_sbrps(struct audio_client *ac,
 			uint32_t sbr_ps_enable)
 {
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 0068c2a..f47b0d3 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3812,6 +3812,7 @@
 	mutex_init(&card->mutex);
 	mutex_init(&card->dapm_mutex);
 	mutex_init(&card->dsp_mutex);
+	spin_lock_init(&card->dsp_spinlock);
 
 	mutex_lock(&client_mutex);
 	list_add(&card->list, &card_list);
diff --git a/sound/soc/soc-dsp.c b/sound/soc/soc-dsp.c
index 6d4f178..1fb5585 100644
--- a/sound/soc/soc-dsp.c
+++ b/sound/soc/soc-dsp.c
@@ -635,10 +635,15 @@
 {
 	struct snd_soc_dsp_params *dsp_params;
 	int ret = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&fe->card->dsp_spinlock, flags);
 
 	if ((cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE) ||
-				(cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH))
+				(cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH)) {
+		spin_unlock_irqrestore(&fe->card->dsp_spinlock, flags);
 		return ret;
+	}
 
 	list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
 
@@ -687,10 +692,14 @@
 			}
 			break;
 		}
-		if (ret < 0)
+
+		if (ret < 0) {
+			spin_unlock_irqrestore(&fe->card->dsp_spinlock, flags);
 			return ret;
+		}
 	}
 
+	spin_unlock_irqrestore(&fe->card->dsp_spinlock, flags);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(soc_dsp_be_dai_trigger);