Merge "msm: clock-local: Combine _rcg_clk_set_rate() with rcg_clk_set_rate()" into msm-3.0
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index 00ff580..fc1d81a 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -295,6 +295,7 @@
 CONFIG_MMC_MSM_CARD_HW_DETECTION=y
 CONFIG_MMC_MSM_SDC3_SUPPORT=y
 CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT=y
+CONFIG_LEDS_GPIO=y
 CONFIG_LEDS_MSM_PDM=y
 CONFIG_SWITCH=y
 CONFIG_SWITCH_GPIO=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index da8b9df..bf4011f 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -291,6 +291,7 @@
 CONFIG_THERMAL=y
 CONFIG_THERMAL_TSENS8960=y
 CONFIG_THERMAL_PM8XXX=y
+CONFIG_THERMAL_MONITOR=y
 CONFIG_MFD_PM8921_CORE=y
 CONFIG_MFD_PM8821_CORE=y
 CONFIG_MFD_PM8038_CORE=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 10b55dc..6248c98 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -292,6 +292,7 @@
 CONFIG_THERMAL=y
 CONFIG_THERMAL_TSENS8960=y
 CONFIG_THERMAL_PM8XXX=y
+CONFIG_THERMAL_MONITOR=y
 CONFIG_MFD_PM8921_CORE=y
 CONFIG_MFD_PM8821_CORE=y
 CONFIG_MFD_PM8038_CORE=y
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 0b7e230..69675e1 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -242,7 +242,7 @@
 obj-$(CONFIG_ARCH_APQ8064) += devices-8960.o devices-8064.o
 board-8960-all-objs += board-8960.o board-8960-camera.o board-8960-display.o board-8960-pmic.o board-8960-storage.o board-8960-gpiomux.o
 board-8930-all-objs += board-8930.o board-8930-camera.o board-8930-display.o board-8930-pmic.o board-8930-storage.o board-8930-gpiomux.o devices-8930.o
-board-8064-all-objs += board-8064.o board-8064-pmic.o board-8064-storage.o board-8064-gpiomux.o
+board-8064-all-objs += board-8064.o board-8064-pmic.o board-8064-storage.o board-8064-gpiomux.o board-8064-camera.o
 obj-$(CONFIG_MACH_MSM8960_SIM) += board-8960-all.o board-8960-regulator.o
 obj-$(CONFIG_MACH_MSM8960_RUMI3) += board-8960-all.o board-8960-regulator.o
 obj-$(CONFIG_MACH_MSM8960_CDP) += board-8960-all.o board-8960-regulator.o
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index 9082b07..408f77b 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -68,7 +68,8 @@
 #define STBY_KHZ		1
 
 #define HFPLL_NOMINAL_VDD	1050000
-#define HFPLL_LOW_VDD		 850000
+#define HFPLL_LOW_VDD_8960	 850000
+#define HFPLL_LOW_VDD		 945000
 #define HFPLL_LOW_VDD_PLL_L_MAX	0x28
 
 #define SECCLKAGD		BIT(4)
@@ -200,6 +201,9 @@
 			.vreg[VREG_DIG]  = { "krait0_dig", 1150000,
 					     RPM_VREG_VOTER1,
 					     RPM_VREG_ID_PM8921_S3 },
+			.vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
+					     RPM_VREG_VOTER1,
+					     RPM_VREG_ID_PM8921_LVS7 },
 		},
 	[CPU1] = {
 			.hfpll_base      = MSM_HFPLL_BASE + 0x240,
@@ -212,6 +216,9 @@
 			.vreg[VREG_DIG]  = { "krait0_dig", 1150000,
 					     RPM_VREG_VOTER2,
 					     RPM_VREG_ID_PM8921_S3 },
+			.vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
+					     RPM_VREG_VOTER2,
+					     RPM_VREG_ID_PM8921_LVS7 },
 		},
 	[CPU2] = {
 			.hfpll_base      = MSM_HFPLL_BASE + 0x280,
@@ -224,6 +231,9 @@
 			.vreg[VREG_DIG]  = { "krait0_dig", 1150000,
 					     RPM_VREG_VOTER4,
 					     RPM_VREG_ID_PM8921_S3 },
+			.vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
+					     RPM_VREG_VOTER4,
+					     RPM_VREG_ID_PM8921_LVS7 },
 		},
 	[CPU3] = {
 			.hfpll_base      = MSM_HFPLL_BASE + 0x2C0,
@@ -236,15 +246,20 @@
 			.vreg[VREG_DIG]  = { "krait0_dig", 1150000,
 					     RPM_VREG_VOTER5,
 					     RPM_VREG_ID_PM8921_S3 },
+			.vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
+					     RPM_VREG_VOTER5,
+					     RPM_VREG_ID_PM8921_LVS7 },
 		},
 	[L2] = {
 			.hfpll_base   = MSM_HFPLL_BASE    + 0x300,
 			.aux_clk_sel  = MSM_APCS_GCC_BASE + 0x028,
 			.l2cpmr_iaddr = L2CPMR_IADDR,
+			.vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
+					     RPM_VREG_VOTER6,
+					     RPM_VREG_ID_PM8921_LVS7 },
 		},
 };
 
-/*TODO: Update the rpm vreg id when the rpm driver is ready */
 static struct scalable scalable_8930[] = {
 	[CPU0] = {
 			.hfpll_base      = MSM_HFPLL_BASE + 0x200,
@@ -253,16 +268,13 @@
 			.vreg[VREG_CORE] = { "krait0",     1300000 },
 			.vreg[VREG_MEM]  = { "krait0_mem", 1150000,
 					     RPM_VREG_VOTER1,
-					     RPM_VREG_ID_PM8921_L24 },
+					     RPM_VREG_ID_PM8038_L24 },
 			.vreg[VREG_DIG]  = { "krait0_dig", 1150000,
 					     RPM_VREG_VOTER1,
-					     RPM_VREG_ID_PM8921_S3 },
-			.vreg[VREG_HFPLL_A] = { "hfpll", 2100000,
-					     RPM_VREG_VOTER1,
-					     RPM_VREG_ID_PM8921_S8 },
+					     RPM_VREG_ID_PM8038_S1 },
 			.vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
 					     RPM_VREG_VOTER1,
-					     RPM_VREG_ID_PM8921_L23 },
+					     RPM_VREG_ID_PM8038_L23 },
 		},
 	[CPU1] = {
 			.hfpll_base      = MSM_HFPLL_BASE + 0x300,
@@ -271,27 +283,21 @@
 			.vreg[VREG_CORE] = { "krait1",     1300000 },
 			.vreg[VREG_MEM]  = { "krait0_mem", 1150000,
 					     RPM_VREG_VOTER2,
-					     RPM_VREG_ID_PM8921_L24 },
+					     RPM_VREG_ID_PM8038_L24 },
 			.vreg[VREG_DIG]  = { "krait0_dig", 1150000,
 					     RPM_VREG_VOTER2,
-					     RPM_VREG_ID_PM8921_S3 },
-			.vreg[VREG_HFPLL_A] = { "hfpll", 2100000,
-					     RPM_VREG_VOTER2,
-					     RPM_VREG_ID_PM8921_S8 },
+					     RPM_VREG_ID_PM8038_S1 },
 			.vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
 					     RPM_VREG_VOTER2,
-					     RPM_VREG_ID_PM8921_L23 },
+					     RPM_VREG_ID_PM8038_L23 },
 		},
 	[L2] = {
 			.hfpll_base   = MSM_HFPLL_BASE    + 0x400,
 			.aux_clk_sel  = MSM_APCS_GCC_BASE + 0x028,
 			.l2cpmr_iaddr = L2CPMR_IADDR,
-			.vreg[VREG_HFPLL_A] = { "hfpll", 2100000,
-					     RPM_VREG_VOTER6,
-					     RPM_VREG_ID_PM8921_S8 },
 			.vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
 					     RPM_VREG_VOTER6,
-					     RPM_VREG_ID_PM8921_L23 },
+					     RPM_VREG_ID_PM8038_L23 },
 		},
 };
 
@@ -304,16 +310,13 @@
 			.vreg[VREG_CORE] = { "krait0",     1300000 },
 			.vreg[VREG_MEM]  = { "krait0_mem", 1150000,
 					     RPM_VREG_VOTER1,
-					     RPM_VREG_ID_PM8921_L24 },
+					     RPM_VREG_ID_PM8038_L24 },
 			.vreg[VREG_DIG]  = { "krait0_dig", 1150000,
 					     RPM_VREG_VOTER1,
-					     RPM_VREG_ID_PM8921_S3 },
-			.vreg[VREG_HFPLL_A] = { "hfpll", 2100000,
-					     RPM_VREG_VOTER1,
-					     RPM_VREG_ID_PM8921_S8 },
+					     RPM_VREG_ID_PM8038_S1 },
 			.vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
 					     RPM_VREG_VOTER1,
-					     RPM_VREG_ID_PM8921_L23 },
+					     RPM_VREG_ID_PM8038_L23 },
 		},
 	[CPU1] = {
 			.hfpll_base      = MSM_HFPLL_BASE + 0x300,
@@ -322,27 +325,21 @@
 			.vreg[VREG_CORE] = { "krait1",     1300000 },
 			.vreg[VREG_MEM]  = { "krait0_mem", 1150000,
 					     RPM_VREG_VOTER2,
-					     RPM_VREG_ID_PM8921_L24 },
+					     RPM_VREG_ID_PM8038_L24 },
 			.vreg[VREG_DIG]  = { "krait0_dig", 1150000,
 					     RPM_VREG_VOTER2,
-					     RPM_VREG_ID_PM8921_S3 },
-			.vreg[VREG_HFPLL_A] = { "hfpll", 2100000,
-					     RPM_VREG_VOTER2,
-					     RPM_VREG_ID_PM8921_S8 },
+					     RPM_VREG_ID_PM8038_S1 },
 			.vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
 					     RPM_VREG_VOTER2,
-					     RPM_VREG_ID_PM8921_L23 },
+					     RPM_VREG_ID_PM8038_L23 },
 		},
 	[L2] = {
 			.hfpll_base   = MSM_HFPLL_BASE    + 0x400,
 			.aux_clk_sel  = MSM_APCS_GCC_BASE + 0x028,
 			.l2cpmr_iaddr = L2CPMR_IADDR,
-			.vreg[VREG_HFPLL_A] = { "hfpll", 2100000,
-					     RPM_VREG_VOTER6,
-					     RPM_VREG_ID_PM8921_S8 },
 			.vreg[VREG_HFPLL_B] = { "hfpll", 1800000,
 					     RPM_VREG_VOTER6,
-					     RPM_VREG_ID_PM8921_L23 },
+					     RPM_VREG_ID_PM8038_L23 },
 		},
 };
 
@@ -741,12 +738,14 @@
 {
 	int rc;
 
-	rc = rpm_vreg_set_voltage(sc->vreg[VREG_HFPLL_A].rpm_vreg_id,
-			sc->vreg[VREG_HFPLL_A].rpm_vreg_voter, 2100000,
-			sc->vreg[VREG_HFPLL_A].max_vdd, 0);
-	if (rc)
-		pr_err("%s regulator enable failed (%d)\n",
-			sc->vreg[VREG_HFPLL_A].name, rc);
+	if (cpu_is_msm8960()) {
+		rc = rpm_vreg_set_voltage(sc->vreg[VREG_HFPLL_A].rpm_vreg_id,
+				sc->vreg[VREG_HFPLL_A].rpm_vreg_voter, 2100000,
+				sc->vreg[VREG_HFPLL_A].max_vdd, 0);
+		if (rc)
+			pr_err("%s regulator enable failed (%d)\n",
+				sc->vreg[VREG_HFPLL_A].name, rc);
+	}
 	rc = rpm_vreg_set_voltage(sc->vreg[VREG_HFPLL_B].rpm_vreg_id,
 			sc->vreg[VREG_HFPLL_B].rpm_vreg_voter, 1800000,
 			sc->vreg[VREG_HFPLL_B].max_vdd, 0);
@@ -792,12 +791,15 @@
 	if (rc)
 		pr_err("%s regulator enable failed (%d)\n",
 			sc->vreg[VREG_HFPLL_B].name, rc);
-	rc = rpm_vreg_set_voltage(sc->vreg[VREG_HFPLL_A].rpm_vreg_id,
-			sc->vreg[VREG_HFPLL_A].rpm_vreg_voter, 0,
-			0, 0);
-	if (rc)
-		pr_err("%s regulator enable failed (%d)\n",
-			sc->vreg[VREG_HFPLL_A].name, rc);
+
+	if (cpu_is_msm8960()) {
+		rc = rpm_vreg_set_voltage(sc->vreg[VREG_HFPLL_A].rpm_vreg_id,
+				sc->vreg[VREG_HFPLL_A].rpm_vreg_voter, 0,
+				0, 0);
+		if (rc)
+			pr_err("%s regulator enable failed (%d)\n",
+				sc->vreg[VREG_HFPLL_A].name, rc);
+	}
 }
 
 /* Program the HFPLL rate. Assumes HFPLL is already disabled. */
@@ -1022,9 +1024,12 @@
 		pll_vdd_dig = 0;
 	else if (tgt->l2_level->speed.pll_l_val > HFPLL_LOW_VDD_PLL_L_MAX)
 		pll_vdd_dig = HFPLL_NOMINAL_VDD;
-	else
-		pll_vdd_dig = HFPLL_LOW_VDD;
-
+	else {
+		if (cpu_is_msm8960())
+			pll_vdd_dig = HFPLL_LOW_VDD_8960;
+		else
+			pll_vdd_dig = HFPLL_LOW_VDD;
+	}
 	return max(tgt->l2_level->vdd_dig, pll_vdd_dig);
 }
 
@@ -1036,9 +1041,12 @@
 		pll_vdd_core = 0;
 	else if (tgt->speed.pll_l_val > HFPLL_LOW_VDD_PLL_L_MAX)
 		pll_vdd_core = HFPLL_NOMINAL_VDD;
-	else
-		pll_vdd_core = HFPLL_LOW_VDD;
-
+	else {
+		if (cpu_is_msm8960())
+			pll_vdd_core = HFPLL_LOW_VDD_8960;
+		else
+			pll_vdd_core = HFPLL_LOW_VDD;
+	}
 	return max(tgt->vdd_core, pll_vdd_core);
 }
 
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
new file mode 100644
index 0000000..f30f0bf
--- /dev/null
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -0,0 +1,375 @@
+/* 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 <asm/mach-types.h>
+#include <linux/i2c.h>
+#include <mach/board.h>
+#include <mach/msm_bus_board.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+
+#include "devices.h"
+#include "board-8064.h"
+
+static struct gpiomux_setting cam_settings[] = {
+	{
+		.func = GPIOMUX_FUNC_GPIO, /*suspend*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_DOWN,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_1, /*active 1*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_GPIO, /*active 2*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_1, /*active 3*/
+		.drv = GPIOMUX_DRV_8MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_5, /*active 4*/
+		.drv = GPIOMUX_DRV_8MA,
+		.pull = GPIOMUX_PULL_UP,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_6, /*active 5*/
+		.drv = GPIOMUX_DRV_8MA,
+		.pull = GPIOMUX_PULL_UP,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_2, /*active 6*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_UP,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_3, /*active 7*/
+		.drv = GPIOMUX_DRV_8MA,
+		.pull = GPIOMUX_PULL_UP,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_GPIO, /*i2c suspend*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_KEEPER,
+	},
+
+};
+
+
+static struct msm_gpiomux_config apq8064_cam_common_configs[] = {
+	{
+		.gpio = 2,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[2],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+	{
+		.gpio = 3,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[1],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+	{
+		.gpio = 4,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[1],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+	{
+		.gpio = 5,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[1],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+	{
+		.gpio = 76,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[2],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+	{
+		.gpio = 107,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[2],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
+		},
+	},
+};
+
+static struct msm_gpiomux_config apq8064_cam_2d_configs[] = {
+	{
+		.gpio = 10,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &cam_settings[8],
+		},
+	},
+	{
+		.gpio = 11,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &cam_settings[8],
+		},
+	},
+	{
+		.gpio = 12,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &cam_settings[8],
+		},
+	},
+	{
+		.gpio = 13,
+		.settings = {
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &cam_settings[8],
+		},
+	},
+};
+
+#ifdef CONFIG_MSM_CAMERA
+
+static uint16_t msm_cam_gpio_2d_tbl[] = {
+	5, /*CAMIF_MCLK*/
+	10, /*CAMIF_I2C_DATA*/
+	11, /*CAMIF_I2C_CLK*/
+};
+
+static struct msm_camera_gpio_conf gpio_conf = {
+	.cam_gpiomux_conf_tbl = apq8064_cam_2d_configs,
+	.cam_gpiomux_conf_tbl_size = ARRAY_SIZE(apq8064_cam_2d_configs),
+	.cam_gpio_tbl = msm_cam_gpio_2d_tbl,
+	.cam_gpio_tbl_size = ARRAY_SIZE(msm_cam_gpio_2d_tbl),
+};
+
+static struct msm_bus_vectors cam_init_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+static struct msm_bus_vectors cam_preview_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 27648000,
+		.ib  = 110592000,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+static struct msm_bus_vectors cam_video_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 140451840,
+		.ib  = 561807360,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 206807040,
+		.ib  = 488816640,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+};
+
+static struct msm_bus_vectors cam_snapshot_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 274423680,
+		.ib  = 1097694720,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 540000000,
+		.ib  = 1350000000,
+	},
+};
+
+static struct msm_bus_vectors cam_zsl_vectors[] = {
+	{
+		.src = MSM_BUS_MASTER_VFE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 302071680,
+		.ib  = 1208286720,
+	},
+	{
+		.src = MSM_BUS_MASTER_VPE,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 0,
+		.ib  = 0,
+	},
+	{
+		.src = MSM_BUS_MASTER_JPEG_ENC,
+		.dst = MSM_BUS_SLAVE_EBI_CH0,
+		.ab  = 540000000,
+		.ib  = 1350000000,
+	},
+};
+
+static struct msm_bus_paths cam_bus_client_config[] = {
+	{
+		ARRAY_SIZE(cam_init_vectors),
+		cam_init_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_preview_vectors),
+		cam_preview_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_video_vectors),
+		cam_video_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_snapshot_vectors),
+		cam_snapshot_vectors,
+	},
+	{
+		ARRAY_SIZE(cam_zsl_vectors),
+		cam_zsl_vectors,
+	},
+};
+
+static struct msm_bus_scale_pdata cam_bus_client_pdata = {
+		cam_bus_client_config,
+		ARRAY_SIZE(cam_bus_client_config),
+		.name = "msm_camera",
+};
+
+static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
+	{
+		.ioclk.mclk_clk_rate = 24000000,
+		.ioclk.vfe_clk_rate  = 228570000,
+		.csid_core = 0,
+		.cam_bus_scale_table = &cam_bus_client_pdata,
+	},
+	{
+		.ioclk.mclk_clk_rate = 24000000,
+		.ioclk.vfe_clk_rate  = 228570000,
+		.csid_core = 1,
+		.cam_bus_scale_table = &cam_bus_client_pdata,
+	},
+};
+
+#ifdef CONFIG_IMX074
+static struct msm_camera_sensor_flash_data flash_imx074 = {
+	.flash_type	= MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_imx074 = {
+	.mount_angle	= 90,
+	.sensor_reset	= 107,
+	.sensor_pwd	= 85,
+	.vcm_pwd	= 0,
+	.vcm_enable	= 1,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_imx074_data = {
+	.sensor_name	= "imx074",
+	.pdata	= &msm_camera_csi_device_data[0],
+	.flash_data	= &flash_imx074,
+	.sensor_platform_info = &sensor_board_info_imx074,
+	.gpio_conf = &gpio_conf,
+	.csi_if	= 1,
+	.camera_type = BACK_CAMERA_2D,
+};
+#endif
+
+void __init apq8064_init_cam(void)
+{
+	msm_gpiomux_install(apq8064_cam_common_configs,
+			ARRAY_SIZE(apq8064_cam_common_configs));
+
+	platform_device_register(&msm8960_device_csiphy0);
+	platform_device_register(&msm8960_device_csiphy1);
+	platform_device_register(&msm8960_device_csid0);
+	platform_device_register(&msm8960_device_csid1);
+	platform_device_register(&msm8960_device_ispif);
+	platform_device_register(&msm8960_device_vfe);
+	platform_device_register(&msm8960_device_vpe);
+}
+
+#ifdef CONFIG_I2C
+static struct i2c_board_info apq8064_camera_i2c_boardinfo[] = {
+#ifdef CONFIG_IMX074
+	{
+	I2C_BOARD_INFO("imx074", 0x1A),
+	.platform_data = &msm_camera_sensor_imx074_data,
+	},
+#endif
+};
+
+struct msm_camera_board_info apq8064_camera_board_info = {
+	.board_info = apq8064_camera_i2c_boardinfo,
+	.num_i2c_board_info = ARRAY_SIZE(apq8064_camera_i2c_boardinfo),
+};
+#endif
+#endif
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index ee1c91a..275614b 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -59,6 +59,7 @@
 #include "mpm.h"
 #include "rpm_resources.h"
 #include "pm-boot.h"
+#include "devices-msm8x60.h"
 
 #define MSM_PMEM_ADSP_SIZE         0x7800000
 #define MSM_PMEM_AUDIO_SIZE        0x2B4000
@@ -69,7 +70,7 @@
 #endif
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-#define MSM_PMEM_KERNEL_EBI1_SIZE  0xB0C000
+#define MSM_PMEM_KERNEL_EBI1_SIZE  0x280000
 #define MSM_ION_SF_SIZE		MSM_PMEM_SIZE
 #define MSM_ION_MM_FW_SIZE	0x200000 /* (2MB) */
 #define MSM_ION_MM_SIZE		MSM_PMEM_ADSP_SIZE
@@ -1068,6 +1069,7 @@
 	&msm_bus_8064_mm_fabric,
 	&msm_bus_8064_sys_fpb,
 	&msm_bus_8064_cpss_fpb,
+	&msm_device_vidc,
 };
 
 static struct platform_device *sim_devices[] __initdata = {
diff --git a/arch/arm/mach-msm/board-8064.h b/arch/arm/mach-msm/board-8064.h
index 98f453b..1634b05 100644
--- a/arch/arm/mach-msm/board-8064.h
+++ b/arch/arm/mach-msm/board-8064.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -44,4 +44,7 @@
 void apq8064_init_mmc(void);
 void apq8064_init_gpiomux(void);
 void apq8064_init_pmic(void);
+extern struct msm_camera_board_info apq8064_camera_board_info;
+void apq8064_init_cam(void);
+#define APQ_8064_GSBI4_QUP_I2C_BUS_ID 4
 #endif
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index 23c94c4..b7400d1 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -26,15 +26,7 @@
 #include <mach/ion.h>
 
 #include "devices.h"
-
-/* TODO: Remove this once PM8038 physically becomes
- * available.
- */
-#ifndef MSM8930_PHASE_2
-#include "board-8960.h"
-#else
 #include "board-8930.h"
-#endif
 
 #ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
 #define MSM_FB_PRIM_BUF_SIZE (1376 * 768 * 4 * 3) /* 4 bpp x 3 pages */
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator.c
index 989fde3..c652238 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator.c
@@ -110,6 +110,9 @@
 	REGULATOR_SUPPLY("dsi_vddio",		"mipi_dsi.1"),
 	REGULATOR_SUPPLY("hdmi_avdd",		"hdmi_msm.0"),
 	REGULATOR_SUPPLY("hdmi_vcc",		"hdmi_msm.0"),
+	REGULATOR_SUPPLY("pll_vdd",		"pil_riva"),
+	REGULATOR_SUPPLY("pll_vdd",		"pil_qdsp6v4.1"),
+	REGULATOR_SUPPLY("pll_vdd",		"pil_qdsp6v4.2"),
 };
 VREG_CONSUMERS(L24) = {
 	REGULATOR_SUPPLY("8038_l24",		NULL),
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
index eee6d09..dee1e98 100644
--- a/arch/arm/mach-msm/board-8930-storage.c
+++ b/arch/arm/mach-msm/board-8930-storage.c
@@ -23,14 +23,7 @@
 #include <mach/gpiomux.h>
 #include "devices.h"
 
-/* TODO: Remove this once PM8038 physically becomes
- * available.
- */
-#ifndef MSM8930_PHASE_2
-#include "board-8960.h"
-#else
 #include "board-8930.h"
-#endif
 
 /* MSM8960 has 5 SDCC controllers */
 enum sdcc_controllers {
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 75d0fb2..69ea6ee 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -126,7 +126,7 @@
 
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-#define MSM_PMEM_KERNEL_EBI1_SIZE  0xB0C000
+#define MSM_PMEM_KERNEL_EBI1_SIZE  0x280000
 #define MSM_ION_SF_SIZE		MSM_PMEM_SIZE
 #define MSM_ION_MM_FW_SIZE	0x200000 /* (2MB) */
 #define MSM_ION_MM_SIZE		MSM_PMEM_ADSP_SIZE
diff --git a/arch/arm/mach-msm/board-8930.h b/arch/arm/mach-msm/board-8930.h
index 1feb5b8..cefaff5 100644
--- a/arch/arm/mach-msm/board-8930.h
+++ b/arch/arm/mach-msm/board-8930.h
@@ -13,6 +13,8 @@
 #ifndef __ARCH_ARM_MACH_MSM_BOARD_MSM8930_H
 #define __ARCH_ARM_MACH_MSM_BOARD_MSM8930_H
 
+#define MSM8930_PHASE_2
+
 #include <linux/regulator/gpio-regulator.h>
 #include <linux/mfd/pm8xxx/pm8038.h>
 #include <linux/i2c.h>
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index f36c3a1..5520bf9 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -110,6 +110,9 @@
 	REGULATOR_SUPPLY("8921_l23",		NULL),
 	REGULATOR_SUPPLY("dsi_vddio",		"mipi_dsi.1"),
 	REGULATOR_SUPPLY("hdmi_avdd",		"hdmi_msm.0"),
+	REGULATOR_SUPPLY("pll_vdd",		"pil_riva"),
+	REGULATOR_SUPPLY("pll_vdd",		"pil_qdsp6v4.1"),
+	REGULATOR_SUPPLY("pll_vdd",		"pil_qdsp6v4.2"),
 };
 VREG_CONSUMERS(L24) = {
 	REGULATOR_SUPPLY("8921_l24",		NULL),
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index a0a540f..6683f90 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -139,7 +139,7 @@
 #define MSM_LIQUID_PMEM_SIZE 0x4000000 /* 64 Mbytes */
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-#define MSM_PMEM_KERNEL_EBI1_SIZE  0xB0C000
+#define MSM_PMEM_KERNEL_EBI1_SIZE  0x280000
 #define MSM_ION_SF_SIZE		MSM_PMEM_SIZE
 #define MSM_ION_MM_FW_SIZE	0x200000 /* (2MB) */
 #define MSM_ION_MM_SIZE		MSM_PMEM_ADSP_SIZE
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index bd570cf..d54ebc5 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -797,6 +797,7 @@
 
 #ifdef CONFIG_MSM_SSBI
 static struct msm_ssbi_platform_data msm7x30_ssbi_pm8058_pdata = {
+	.rsl_id = "D:PMIC_SSBI",
 	.controller_type = MSM_SBI_CTRL_SSBI2,
 	.slave	= {
 		.name			= "pm8058-core",
@@ -2143,10 +2144,10 @@
 
 
 static struct msm_ts_platform_data msm_ts_data = {
-	.min_x          = 0,
-	.max_x          = 4096,
-	.min_y          = 0,
-	.max_y          = 4096,
+	.min_x          = 284,
+	.max_x          = 3801,
+	.min_y          = 155,
+	.max_y          = 3929,
 	.min_press      = 0,
 	.max_press      = 255,
 	.inv_x          = 4096,
@@ -6348,6 +6349,10 @@
 static struct tsc2007_platform_data tsc2007_ts_data = {
 	.model = 2007,
 	.x_plate_ohms = 300,
+	.min_x		= 210,
+	.max_x		= 3832,
+	.min_y		= 150,
+	.max_y		= 3936,
 	.irq_flags    = IRQF_TRIGGER_LOW,
 	.init_platform_hw = tsc2007_init,
 	.exit_platform_hw = tsc2007_exit,
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index a4f1b32..5cb022e 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -2703,9 +2703,10 @@
 #define MSM_ION_MM_SIZE		0x3600000 /* (54MB) */
 #define MSM_ION_MFC_SIZE	SZ_8K
 #define MSM_ION_WB_SIZE		0x600000 /* 6MB */
+#define MSM_ION_AUDIO_SIZE	MSM_PMEM_AUDIO_SIZE
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-#define MSM_ION_HEAP_NUM	7
+#define MSM_ION_HEAP_NUM	8
 #else
 #define MSM_ION_HEAP_NUM	1
 #endif
@@ -5334,6 +5335,14 @@
 			.memory_type = ION_EBI_TYPE,
 			.extra_data = (void *) &cp_wb_ion_pdata,
 		},
+		{
+			.id	= ION_AUDIO_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.name	= ION_AUDIO_HEAP_NAME,
+			.size	= MSM_ION_AUDIO_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *)&co_ion_pdata,
+		},
 #endif
 	}
 };
@@ -5382,6 +5391,7 @@
 	msm8x60_reserve_table[MEMTYPE_SMI].size += MSM_ION_MFC_SIZE;
 	msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_CAMERA_SIZE;
 	msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_WB_SIZE;
+	msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_AUDIO_SIZE;
 #endif
 }
 
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index a21abb8..1f2a5ec 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -793,10 +793,75 @@
 				__func__, rc);
 }
 
+/* 8625 keypad device information */
+static unsigned int kp_row_gpios_8625[] = {31};
+static unsigned int kp_col_gpios_8625[] = {36, 37};
+
+static const unsigned short keymap_8625[] = {
+	KEY_VOLUMEUP,
+	KEY_VOLUMEDOWN,
+};
+
+static struct gpio_event_matrix_info kp_matrix_info_8625 = {
+	.info.func      = gpio_event_matrix_func,
+	.keymap         = keymap_8625,
+	.output_gpios   = kp_row_gpios_8625,
+	.input_gpios    = kp_col_gpios_8625,
+	.noutputs       = ARRAY_SIZE(kp_row_gpios_8625),
+	.ninputs        = ARRAY_SIZE(kp_col_gpios_8625),
+	.settle_time.tv_nsec = 40 * NSEC_PER_USEC,
+	.poll_time.tv_nsec = 20 * NSEC_PER_MSEC,
+	.flags          = GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE |
+			  GPIOKPF_PRINT_UNMAPPED_KEYS,
+};
+
+static struct gpio_event_info *kp_info_8625[] = {
+	&kp_matrix_info_8625.info,
+};
+static struct gpio_event_platform_data kp_pdata_8625 = {
+	.name           = "8625_kp",
+	.info           = kp_info_8625,
+	.info_count     = ARRAY_SIZE(kp_info_8625)
+};
+
+static struct platform_device kp_pdev_8625 = {
+	.name   = GPIO_EVENT_DEV_NAME,
+	.id     = -1,
+	.dev    = {
+		.platform_data  = &kp_pdata_8625,
+	},
+};
+
+#define LED_RED_GPIO_8625 49
+#define LED_GREEN_GPIO_8625 34
+
+static struct gpio_led gpio_leds_config_8625[] = {
+	{
+		.name = "green",
+		.gpio = LED_GREEN_GPIO_8625,
+	},
+	{
+		.name = "red",
+		.gpio = LED_RED_GPIO_8625,
+	},
+};
+
+static struct gpio_led_platform_data gpio_leds_pdata_8625 = {
+	.num_leds = ARRAY_SIZE(gpio_leds_config_8625),
+	.leds = gpio_leds_config_8625,
+};
+
+static struct platform_device gpio_leds_8625 = {
+	.name          = "leds-gpio",
+	.id            = -1,
+	.dev           = {
+		.platform_data = &gpio_leds_pdata_8625,
+	},
+};
+
 static void msm7627a_add_io_devices(void)
 {
-	if (machine_is_msm7627a_evb())
-		return;
+	int rc;
 
 #if defined(CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C) || \
 	defined(CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C_MODULE)
@@ -810,6 +875,30 @@
 	msm_init_pmic_vibrator();
 #endif
 
+	/* keypad */
+	if (machine_is_msm7627a_evb())
+		platform_device_register(&kp_pdev_8625);
+
+	/* leds */
+	if (machine_is_msm7627a_evb()) {
+		rc = gpio_tlmm_config(GPIO_CFG(LED_RED_GPIO_8625, 0,
+				GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
+				GPIO_CFG_16MA), GPIO_CFG_ENABLE);
+		if (rc) {
+			pr_err("%s: gpio_tlmm_config for %d failed\n",
+				__func__, LED_RED_GPIO_8625);
+		}
+
+		rc = gpio_tlmm_config(GPIO_CFG(LED_GREEN_GPIO_8625, 0,
+				GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
+				GPIO_CFG_16MA), GPIO_CFG_ENABLE);
+		if (rc) {
+			pr_err("%s: gpio_tlmm_config for %d failed\n",
+				__func__, LED_GREEN_GPIO_8625);
+		}
+
+		platform_device_register(&gpio_leds_8625);
+	}
 }
 
 #define UART1DM_RX_GPIO		45
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 8e8a966..afd3612d 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -363,6 +363,8 @@
 };
 #define PLL_RATE(l, m, n, v, d, i) { l, m, n, v, (d>>1), i }
 
+static int rpm_vreg_id_vdd_dig;
+
 enum vdd_dig_levels {
 	VDD_DIG_NONE,
 	VDD_DIG_LOW,
@@ -378,8 +380,7 @@
 		[VDD_DIG_NOMINAL] = 1050000,
 		[VDD_DIG_HIGH]    = 1150000
 	};
-
-	return rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S3, RPM_VREG_VOTER3,
+	return rpm_vreg_set_voltage(rpm_vreg_id_vdd_dig, RPM_VREG_VOTER3,
 				    vdd_uv[level], 1150000, 1);
 }
 
@@ -405,28 +406,41 @@
 
 static int set_vdd_l23(struct clk_vdd_class *vdd_class, int level)
 {
-	int rc;
-
-	if (level == VDD_L23_OFF) {
-		rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
-				RPM_VREG_VOTER3, 0, 0, 1);
-		if (rc)
-			return rc;
-		rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
-				RPM_VREG_VOTER3, 0, 0, 1);
-		if (rc)
-			rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
-				RPM_VREG_VOTER3, 1800000, 1800000, 1);
-	} else {
-		rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
-				RPM_VREG_VOTER3, 2200000, 2200000, 1);
-		if (rc)
-			return rc;
-		rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
-				RPM_VREG_VOTER3, 1800000, 1800000, 1);
-		if (rc)
-			rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
-				RPM_VREG_VOTER3, 0, 0, 1);
+	int rc = 0;
+	if (cpu_is_msm8960()) {
+		if (level == VDD_L23_OFF) {
+			rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
+					RPM_VREG_VOTER3, 0, 0, 1);
+			if (rc)
+				return rc;
+			rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
+					RPM_VREG_VOTER3, 0, 0, 1);
+			if (rc)
+				rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
+					RPM_VREG_VOTER3, 1800000, 1800000, 1);
+		} else {
+			rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
+					RPM_VREG_VOTER3, 2200000, 2200000, 1);
+			if (rc)
+				return rc;
+			rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
+					RPM_VREG_VOTER3, 1800000, 1800000, 1);
+			if (rc)
+				rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
+						RPM_VREG_VOTER3, 0, 0, 1);
+		}
+	} else if (cpu_is_msm8930() || cpu_is_msm8627()) {
+		if (level == VDD_L23_OFF) {
+			rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8038_L23,
+					RPM_VREG_VOTER3, 0, 0, 1);
+			if (rc)
+				return rc;
+		} else {
+			rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8038_L23,
+					RPM_VREG_VOTER3, 1800000, 1800000, 1);
+			if (rc)
+				return rc;
+		}
 	}
 
 	return rc;
@@ -4799,6 +4813,8 @@
 
 static struct clk_lookup msm_clocks_8064[] = {
 	CLK_LOOKUP("cxo",		cxo_clk.c,		NULL),
+	CLK_LOOKUP("cxo",		cxo_clk.c,		"wcnss_wlan.0"),
+	CLK_LOOKUP("cxo",		cxo_clk.c,		"pil_riva"),
 	CLK_LOOKUP("pll2",		pll2_clk.c,		NULL),
 	CLK_LOOKUP("pll8",		pll8_clk.c,		NULL),
 	CLK_LOOKUP("pll4",		pll4_clk.c,		NULL),
@@ -5036,6 +5052,8 @@
 
 static struct clk_lookup msm_clocks_8960_v1[] __initdata = {
 	CLK_LOOKUP("cxo",		cxo_clk.c,		NULL),
+	CLK_LOOKUP("cxo",		cxo_clk.c,		"wcnss_wlan.0"),
+	CLK_LOOKUP("cxo",		cxo_clk.c,		"pil_riva"),
 	CLK_LOOKUP("pll2",		pll2_clk.c,		NULL),
 	CLK_LOOKUP("pll8",		pll8_clk.c,		NULL),
 	CLK_LOOKUP("pll4",		pll4_clk.c,		NULL),
@@ -5641,6 +5659,13 @@
 {
 	size_t num_lookups = ARRAY_SIZE(msm_clocks_8960_v1);
 
+	if (cpu_is_msm8960() || cpu_is_apq8064())
+		rpm_vreg_id_vdd_dig = RPM_VREG_ID_PM8921_S3;
+	else if (cpu_is_msm8930() || cpu_is_msm8627())
+		rpm_vreg_id_vdd_dig = RPM_VREG_ID_PM8038_S1;
+	else
+		BUG();
+
 	xo_pxo = msm_xo_get(MSM_XO_PXO, "clock-8960");
 	if (IS_ERR(xo_pxo)) {
 		pr_err("%s: msm_xo_get(PXO) failed.\n", __func__);
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index f5d066d..d463c41 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -1537,6 +1537,7 @@
 };
 
 struct platform_device *msm_footswitch_devices[] = {
+	FS_8X60(FS_MDP,    "fs_mdp"),
 	FS_8X60(FS_ROT,    "fs_rot"),
 	FS_8X60(FS_IJPEG,  "fs_ijpeg"),
 	FS_8X60(FS_VFE,    "fs_vfe"),
diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
index 660884c..631d520 100644
--- a/arch/arm/mach-msm/idle-v7.S
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -49,7 +49,9 @@
 #if (NR_CPUS >= 2)
 	mrc	p15, 0, r1, c0, c0, 5	/* MPIDR */
 	ands	r1, r1, #15		/* What CPU am I */
-	addne	r0, r0, #CPU_SAVED_STATE_SIZE
+	mov	r2, #CPU_SAVED_STATE_SIZE
+	mul	r1, r1, r2
+	add	r0, r0, r1
 #endif
 
 	stmia   r0!, {r4-r14}
@@ -149,15 +151,18 @@
 	mov     r1, #'A'
 	str     r1, [r0, #0x00C]
 #endif
-	ldr     r1, =saved_state_end
+	ldr     r1, =saved_state
 	ldr     r2, =msm_pm_collapse_exit
 	adr     r3, msm_pm_collapse_exit
 	add     r1, r1, r3
 	sub     r1, r1, r2
+	add	r1, r1, #CPU_SAVED_STATE_SIZE
 #if (NR_CPUS >= 2)
 	mrc	p15, 0, r2, c0, c0, 5	/* MPIDR */
 	ands	r2, r2, #15		/* What CPU am I */
-	subeq	r1, r1, #CPU_SAVED_STATE_SIZE
+	mov	r3, #CPU_SAVED_STATE_SIZE
+	mul	r2, r2, r3
+	add	r1, r1, r2
 #endif
 
 #ifdef CONFIG_MSM_CPU_AVS
@@ -268,11 +273,7 @@
 	.long	0x0
 
 saved_state:
-#if (NR_CPUS >= 2)
-	.space	CPU_SAVED_STATE_SIZE * 2 /* This code only supports 2 cores */
-#else
-	.space	CPU_SAVED_STATE_SIZE
-#endif
+	.space	CPU_SAVED_STATE_SIZE * NR_CPUS
 saved_state_end:
 
 msm_pm_boot_vector:
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index 8961c79..1abfd7b 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -87,6 +87,8 @@
 	VFE_MSG_V32_START_RECORDING,
 	VFE_MSG_V32_CAPTURE,
 	VFE_MSG_OUTPUT_IRQ,
+	VFE_MSG_V2X_PREVIEW,
+	VFE_MSG_V2X_CAPTURE,
 };
 
 enum vpe_resp_msg {
diff --git a/arch/arm/mach-msm/pil-q6v4.c b/arch/arm/mach-msm/pil-q6v4.c
index d8ebab5..cdbfc48 100644
--- a/arch/arm/mach-msm/pil-q6v4.c
+++ b/arch/arm/mach-msm/pil-q6v4.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
@@ -19,6 +19,7 @@
 #include <linux/elf.h>
 #include <linux/delay.h>
 #include <linux/err.h>
+#include <linux/workqueue.h>
 
 #include <mach/msm_bus.h>
 #include <mach/msm_iomap.h>
@@ -68,9 +69,10 @@
 	void __iomem *modem_base;
 	unsigned long start_addr;
 	struct regulator *vreg;
+	struct regulator *pll_supply;
 	bool vreg_enabled;
 	struct msm_xo_voter *xo;
-	struct timer_list xo_timer;
+	struct delayed_work work;
 };
 
 static int pil_q6v4_init_image(struct pil_desc *pil, const u8 *metadata,
@@ -87,27 +89,32 @@
 	return 0;
 }
 
-static void pil_q6v4_make_xo_proxy_votes(struct device *dev)
+static void pil_q6v4_make_proxy_votes(struct device *dev)
 {
 	struct q6v4_data *drv = dev_get_drvdata(dev);
+	int ret;
 
 	msm_xo_mode_vote(drv->xo, MSM_XO_MODE_ON);
-	mod_timer(&drv->xo_timer, jiffies+msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
+	if (drv->pll_supply) {
+		ret = regulator_enable(drv->pll_supply);
+		if (ret)
+			dev_err(dev, "failed to enable pll supply\n");
+	}
+	schedule_delayed_work(&drv->work, msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
 }
 
-static void pil_q6v4_remove_xo_proxy_votes(unsigned long data)
+static void pil_q6v4_remove_proxy_votes(struct work_struct *work)
 {
-	struct q6v4_data *drv = (struct q6v4_data *)data;
-
+	struct q6v4_data *drv = container_of(work, struct q6v4_data, work.work);
+	if (drv->pll_supply)
+		regulator_disable(drv->pll_supply);
 	msm_xo_mode_vote(drv->xo, MSM_XO_MODE_OFF);
 }
 
-static void pil_q6v4_remove_xo_proxy_votes_now(struct device *dev)
+static void pil_q6v4_remove_proxy_votes_now(struct device *dev)
 {
 	struct q6v4_data *drv = dev_get_drvdata(dev);
-
-	if (del_timer(&drv->xo_timer))
-		pil_q6v4_remove_xo_proxy_votes((unsigned long)drv);
+	flush_delayed_work(&drv->work);
 }
 
 static int pil_q6v4_power_up(struct device *dev)
@@ -184,7 +191,7 @@
 	const struct q6v4_data *drv = dev_get_drvdata(pil->dev);
 	const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
 
-	pil_q6v4_make_xo_proxy_votes(pil->dev);
+	pil_q6v4_make_proxy_votes(pil->dev);
 
 	err = pil_q6v4_power_up(pil->dev);
 	if (err)
@@ -300,7 +307,7 @@
 		drv->vreg_enabled = false;
 	}
 
-	pil_q6v4_remove_xo_proxy_votes_now(pil->dev);
+	pil_q6v4_remove_proxy_votes_now(pil->dev);
 
 	return 0;
 }
@@ -324,7 +331,7 @@
 	const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
 	int err;
 
-	pil_q6v4_make_xo_proxy_votes(pil->dev);
+	pil_q6v4_make_proxy_votes(pil->dev);
 
 	err = pil_q6v4_power_up(pil->dev);
 	if (err)
@@ -355,7 +362,7 @@
 		drv->vreg_enabled = false;
 	}
 
-	pil_q6v4_remove_xo_proxy_votes_now(pil->dev);
+	pil_q6v4_remove_proxy_votes_now(pil->dev);
 
 	return ret;
 }
@@ -373,6 +380,7 @@
 	struct q6v4_data *drv;
 	struct resource *res;
 	struct pil_desc *desc;
+	int ret;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res)
@@ -396,9 +404,26 @@
 	}
 
 	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
-	if (!drv)
+	if (!desc)
 		return -ENOMEM;
 
+	drv->pll_supply = regulator_get(&pdev->dev, "pll_vdd");
+	if (IS_ERR(drv->pll_supply)) {
+		drv->pll_supply = NULL;
+	} else {
+		ret = regulator_set_voltage(drv->pll_supply, 1800000, 1800000);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to set pll voltage\n");
+			goto err;
+		}
+
+		ret = regulator_set_optimum_mode(drv->pll_supply, 100000);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "failed to set pll optimum mode\n");
+			goto err;
+		}
+	}
+
 	desc->name = pdata->name;
 	desc->depends_on = pdata->depends;
 	desc->dev = &pdev->dev;
@@ -412,26 +437,39 @@
 	}
 
 	drv->vreg = regulator_get(&pdev->dev, "core_vdd");
-	if (IS_ERR(drv->vreg))
-		return PTR_ERR(drv->vreg);
-
-	setup_timer(&drv->xo_timer, pil_q6v4_remove_xo_proxy_votes,
-		    (unsigned long)drv);
-	drv->xo = msm_xo_get(pdata->xo_id, pdata->name);
-	if (IS_ERR(drv->xo))
-		return PTR_ERR(drv->xo);
-
-	if (msm_pil_register(desc)) {
-		regulator_put(drv->vreg);
-		return -EINVAL;
+	if (IS_ERR(drv->vreg)) {
+		ret = PTR_ERR(drv->vreg);
+		goto err;
 	}
+
+	drv->xo = msm_xo_get(pdata->xo_id, pdata->name);
+	if (IS_ERR(drv->xo)) {
+		ret = PTR_ERR(drv->xo);
+		goto err_xo;
+	}
+	INIT_DELAYED_WORK(&drv->work, pil_q6v4_remove_proxy_votes);
+
+	ret = msm_pil_register(desc);
+	if (ret)
+		goto err_pil;
 	return 0;
+err_pil:
+	cancel_delayed_work_sync(&drv->work);
+	msm_xo_put(drv->xo);
+err_xo:
+	regulator_put(drv->vreg);
+err:
+	regulator_put(drv->pll_supply);
+	return ret;
 }
 
 static int __devexit pil_q6v4_driver_exit(struct platform_device *pdev)
 {
 	struct q6v4_data *drv = platform_get_drvdata(pdev);
+	cancel_delayed_work_sync(&drv->work);
+	msm_xo_put(drv->xo);
 	regulator_put(drv->vreg);
+	regulator_put(drv->pll_supply);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index 6848c59..7e78a15 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -18,9 +18,11 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/workqueue.h>
+#include <linux/clk.h>
 
 #include <mach/msm_iomap.h>
-#include <mach/msm_xo.h>
 
 #include "peripheral-loader.h"
 #include "scm-pas.h"
@@ -80,38 +82,40 @@
 struct riva_data {
 	void __iomem *base;
 	unsigned long start_addr;
-	struct msm_xo_voter *xo;
-	struct timer_list xo_timer;
+	struct clk *xo;
+	bool use_cxo;
+	struct delayed_work work;
+	struct regulator *pll_supply;
 };
 
-static void pil_riva_make_xo_proxy_votes(struct device *dev)
+static void pil_riva_make_proxy_votes(struct device *dev)
 {
 	struct riva_data *drv = dev_get_drvdata(dev);
+	int ret;
 
-	msm_xo_mode_vote(drv->xo, MSM_XO_MODE_ON);
-	mod_timer(&drv->xo_timer, jiffies+msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
+	if (drv->use_cxo) {
+		ret = clk_prepare_enable(drv->xo);
+		if (ret)
+			dev_err(dev, "failed to enable xo\n");
+	}
+	ret = regulator_enable(drv->pll_supply);
+	if (ret)
+		dev_err(dev, "failed to enable pll supply\n");
+	schedule_delayed_work(&drv->work, msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
 }
 
-static void pil_riva_remove_xo_proxy_votes(unsigned long data)
+static void pil_riva_remove_proxy_votes(struct work_struct *work)
 {
-	struct riva_data *drv = (struct riva_data *)data;
-
-	msm_xo_mode_vote(drv->xo, MSM_XO_MODE_OFF);
+	struct riva_data *drv = container_of(work, struct riva_data, work.work);
+	regulator_disable(drv->pll_supply);
+	if (drv->use_cxo)
+		clk_disable_unprepare(drv->xo);
 }
 
-static void pil_riva_remove_xo_proxy_votes_now(struct device *dev)
+static void pil_riva_remove_proxy_votes_now(struct device *dev)
 {
 	struct riva_data *drv = dev_get_drvdata(dev);
-
-	if (del_timer(&drv->xo_timer))
-		pil_riva_remove_xo_proxy_votes((unsigned long)drv);
-}
-
-static bool cxo_is_needed(struct riva_data *drv)
-{
-	u32 reg = readl_relaxed(drv->base + RIVA_PMU_CFG);
-	return (reg & RIVA_PMU_CFG_IRIS_XO_MODE)
-		!= RIVA_PMU_CFG_IRIS_XO_MODE_48;
+	flush_delayed_work(&drv->work);
 }
 
 static int nop_verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
@@ -128,30 +132,38 @@
 	return 0;
 }
 
+static bool cxo_is_needed(struct riva_data *drv)
+{
+	u32 reg = readl_relaxed(drv->base + RIVA_PMU_CFG);
+	return (reg & RIVA_PMU_CFG_IRIS_XO_MODE)
+		!= RIVA_PMU_CFG_IRIS_XO_MODE_48;
+}
+
 static int pil_riva_reset(struct pil_desc *pil)
 {
 	u32 reg, sel;
-	bool use_cxo;
 	struct riva_data *drv = dev_get_drvdata(pil->dev);
 	void __iomem *base = drv->base;
 	unsigned long start_addr = drv->start_addr;
+	int ret;
 
+	ret = clk_prepare_enable(drv->xo);
+	if (ret)
+		return ret;
 	/* Enable A2XB bridge */
 	reg = readl_relaxed(base + RIVA_PMU_A2XB_CFG);
 	reg |= RIVA_PMU_A2XB_CFG_EN;
 	writel_relaxed(reg, base + RIVA_PMU_A2XB_CFG);
 
-	/* Proxy-vote for CXO if it's needed */
-	use_cxo = cxo_is_needed(drv);
-	if (use_cxo)
-		pil_riva_make_xo_proxy_votes(pil->dev);
+	drv->use_cxo = cxo_is_needed(drv);
+	pil_riva_make_proxy_votes(pil->dev);
 
 	/* Program PLL 13 to 960 MHz */
 	reg = readl_relaxed(RIVA_PLL_MODE);
 	reg &= ~(PLL_MODE_BYPASSNL | PLL_MODE_OUTCTRL | PLL_MODE_RESET_N);
 	writel_relaxed(reg, RIVA_PLL_MODE);
 
-	if (use_cxo)
+	if (drv->use_cxo)
 		writel_relaxed(0x40000C00 | 50, RIVA_PLL_L_VAL);
 	else
 		writel_relaxed(0x40000C00 | 40, RIVA_PLL_L_VAL);
@@ -161,7 +173,7 @@
 
 	reg = readl_relaxed(RIVA_PLL_MODE);
 	reg &= ~(PLL_MODE_REF_XO_SEL);
-	reg |= use_cxo ? PLL_MODE_REF_XO_SEL_CXO : PLL_MODE_REF_XO_SEL_RF;
+	reg |= drv->use_cxo ? PLL_MODE_REF_XO_SEL_CXO : PLL_MODE_REF_XO_SEL_RF;
 	writel_relaxed(reg, RIVA_PLL_MODE);
 
 	/* Enable PLL 13 */
@@ -226,6 +238,7 @@
 	/* Take cCPU out of reset */
 	reg |= RIVA_PMU_OVRD_VAL_CCPU_RESET;
 	writel_relaxed(reg, base + RIVA_PMU_OVRD_VAL);
+	clk_disable_unprepare(drv->xo);
 
 	return 0;
 }
@@ -234,7 +247,11 @@
 {
 	struct riva_data *drv = dev_get_drvdata(pil->dev);
 	u32 reg;
+	int ret;
 
+	ret = clk_prepare_enable(drv->xo);
+	if (ret)
+		return ret;
 	/* Put cCPU and cCPU clock into reset */
 	reg = readl_relaxed(drv->base + RIVA_PMU_OVRD_VAL);
 	reg &= ~(RIVA_PMU_OVRD_VAL_CCPU_RESET | RIVA_PMU_OVRD_VAL_CCPU_CLK);
@@ -253,7 +270,8 @@
 	writel_relaxed(0, RIVA_RESET);
 	mb();
 
-	pil_riva_remove_xo_proxy_votes_now(pil->dev);
+	clk_disable_unprepare(drv->xo);
+	pil_riva_remove_proxy_votes_now(pil->dev);
 
 	return 0;
 }
@@ -274,19 +292,29 @@
 static int pil_riva_reset_trusted(struct pil_desc *pil)
 {
 	struct riva_data *drv = dev_get_drvdata(pil->dev);
+	int ret;
 
-	/* Proxy-vote for CXO if it's needed */
-	if (cxo_is_needed(drv))
-		pil_riva_make_xo_proxy_votes(pil->dev);
-
-	return pas_auth_and_reset(PAS_RIVA);
+	ret = clk_prepare_enable(drv->xo);
+	if (ret)
+		return ret;
+	/* Proxy-vote for resources RIVA needs */
+	pil_riva_make_proxy_votes(pil->dev);
+	ret = pas_auth_and_reset(PAS_RIVA);
+	clk_disable_unprepare(drv->xo);
+	return ret;
 }
 
 static int pil_riva_shutdown_trusted(struct pil_desc *pil)
 {
-	int ret = pas_shutdown(PAS_RIVA);
+	int ret;
+	struct riva_data *drv = dev_get_drvdata(pil->dev);
 
-	pil_riva_remove_xo_proxy_votes_now(pil->dev);
+	ret = clk_prepare_enable(drv->xo);
+	if (ret)
+		return ret;
+	ret = pas_shutdown(PAS_RIVA);
+	pil_riva_remove_proxy_votes_now(pil->dev);
+	clk_disable_unprepare(drv->xo);
 
 	return ret;
 }
@@ -303,6 +331,7 @@
 	struct riva_data *drv;
 	struct resource *res;
 	struct pil_desc *desc;
+	int ret;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res)
@@ -321,6 +350,23 @@
 	if (!desc)
 		return -ENOMEM;
 
+	drv->pll_supply = regulator_get(&pdev->dev, "pll_vdd");
+	if (IS_ERR(drv->pll_supply)) {
+		dev_err(&pdev->dev, "failed to get pll supply\n");
+		return PTR_ERR(drv->pll_supply);
+	}
+	ret = regulator_set_voltage(drv->pll_supply, 1800000, 1800000);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to set pll supply voltage\n");
+		goto err;
+	}
+
+	ret = regulator_set_optimum_mode(drv->pll_supply, 100000);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to set pll supply optimum mode\n");
+		goto err;
+	}
+
 	desc->name = "wcnss";
 	desc->dev = &pdev->dev;
 
@@ -332,17 +378,31 @@
 		dev_info(&pdev->dev, "using non-secure boot\n");
 	}
 
-	setup_timer(&drv->xo_timer, pil_riva_remove_xo_proxy_votes,
-		    (unsigned long)drv);
-	drv->xo = msm_xo_get(MSM_XO_CXO, desc->name);
-	if (IS_ERR(drv->xo))
-		return PTR_ERR(drv->xo);
+	drv->xo = clk_get(&pdev->dev, "cxo");
+	if (IS_ERR(drv->xo)) {
+		ret = PTR_ERR(drv->xo);
+		goto err;
+	}
+	INIT_DELAYED_WORK(&drv->work, pil_riva_remove_proxy_votes);
 
-	return msm_pil_register(desc);
+	ret = msm_pil_register(desc);
+	if (ret)
+		goto err_register;
+	return 0;
+err_register:
+	cancel_delayed_work_sync(&drv->work);
+	clk_put(drv->xo);
+err:
+	regulator_put(drv->pll_supply);
+	return ret;
 }
 
 static int __devexit pil_riva_remove(struct platform_device *pdev)
 {
+	struct riva_data *drv = platform_get_drvdata(pdev);
+	cancel_delayed_work_sync(&drv->work);
+	clk_put(drv->xo);
+	regulator_put(drv->pll_supply);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/qdsp5/adsp_info.c b/arch/arm/mach-msm/qdsp5/adsp_info.c
index 62e385d..dea52bb 100644
--- a/arch/arm/mach-msm/qdsp5/adsp_info.c
+++ b/arch/arm/mach-msm/qdsp5/adsp_info.c
@@ -1,6 +1,6 @@
 /* arch/arm/mach-msm/adsp_info.c
  *
- * Copyright (c) 2008-2009, 2011 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2009, 2011-2012 Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -89,7 +89,7 @@
 	QDSP_MODULE(RMTASK, NULL, 0, NULL, NULL),
 #if !defined(CONFIG_ARCH_MSM7X30)
 	QDSP_MODULE(AUDRECTASK, NULL, 0, NULL, NULL),
-	QDSP_MODULE(VFETASK, "vfe_clk", 0, adsp_vfe_verify_cmd,
+	QDSP_MODULE(VFETASK, NULL, 0, adsp_vfe_verify_cmd,
 		adsp_vfe_patch_event),
 	QDSP_MODULE(QCAMTASK, NULL, 0, NULL, NULL),
 	QDSP_MODULE(LPMTASK, NULL, 0, adsp_lpm_verify_cmd, NULL),
diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile
index 908b63d..7b8f3e6 100644
--- a/drivers/gpu/msm/Makefile
+++ b/drivers/gpu/msm/Makefile
@@ -8,7 +8,8 @@
 	kgsl_pwrscale.o \
 	kgsl_mmu.o \
 	kgsl_gpummu.o \
-	kgsl_iommu.o
+	kgsl_iommu.o \
+	kgsl_snapshot.o
 
 msm_kgsl_core-$(CONFIG_DEBUG_FS) += kgsl_debugfs.o
 msm_kgsl_core-$(CONFIG_MSM_KGSL_CFF_DUMP) += kgsl_cffdump.o
@@ -20,8 +21,10 @@
 	adreno_ringbuffer.o \
 	adreno_drawctxt.o \
 	adreno_postmortem.o \
+	adreno_snapshot.o \
 	adreno_a2xx.o \
 	adreno_a2xx_trace.o \
+	adreno_a2xx_snapshot.o \
 	adreno.o
 
 msm_adreno-$(CONFIG_DEBUG_FS) += adreno_debugfs.o
diff --git a/drivers/gpu/msm/a2xx_reg.h b/drivers/gpu/msm/a2xx_reg.h
index 5ffdea1..50b2745 100644
--- a/drivers/gpu/msm/a2xx_reg.h
+++ b/drivers/gpu/msm/a2xx_reg.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2002,2007-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -416,4 +416,37 @@
 #define REG_A225_GRAS_UCP5W              0x2357
 #define REG_A225_GRAS_UCP_ENABLED        0x2360
 
+/* Debug registers used by snapshot */
+#define REG_PA_SU_DEBUG_CNTL            0x0C80
+#define REG_PA_SU_DEBUG_DATA            0x0C81
+#define REG_RB_DEBUG_CNTL               0x0F26
+#define REG_RB_DEBUG_DATA               0x0F27
+#define REG_PC_DEBUG_CNTL               0x0C38
+#define REG_PC_DEBUG_DATA               0x0C39
+#define REG_GRAS_DEBUG_CNTL             0x0C80
+#define REG_GRAS_DEBUG_DATA             0x0C81
+#define REG_SQ_DEBUG_MISC               0x0D05
+#define REG_SQ_DEBUG_INPUT_FSM          0x0DAE
+#define REG_SQ_DEBUG_CONST_MGR_FSM      0x0DAF
+#define REG_SQ_DEBUG_EXP_ALLOC          0x0DB3
+#define REG_SQ_DEBUG_FSM_ALU_0          0x0DB1
+#define REG_SQ_DEBUG_FSM_ALU_1          0x0DB2
+#define REG_SQ_DEBUG_PTR_BUFF           0x0DB4
+#define REG_SQ_DEBUG_GPR_VTX            0x0DB5
+#define REG_SQ_DEBUG_GPR_PIX            0x0DB6
+#define REG_SQ_DEBUG_TB_STATUS_SEL      0x0DB7
+#define REG_SQ_DEBUG_VTX_TB_0           0x0DB8
+#define REG_SQ_DEBUG_VTX_TB_1           0x0DB9
+#define REG_SQ_DEBUG_VTX_TB_STATE_MEM   0x0DBB
+#define REG_SQ_DEBUG_TP_FSM             0x0DB0
+#define REG_SQ_DEBUG_VTX_TB_STATUS_REG  0x0DBA
+#define REG_SQ_DEBUG_PIX_TB_0           0x0DBC
+#define REG_SQ_DEBUG_PIX_TB_STATUS_REG_0 0x0DBD
+#define REG_SQ_DEBUG_PIX_TB_STATUS_REG_1 0x0DBE
+#define REG_SQ_DEBUG_PIX_TB_STATUS_REG_2 0x0DBF
+#define REG_SQ_DEBUG_PIX_TB_STATUS_REG_3 0x0DC0
+#define REG_SQ_DEBUG_PIX_TB_STATE_MEM   0x0DC1
+#define REG_SQ_DEBUG_MISC_0             0x2309
+#define REG_SQ_DEBUG_MISC_1             0x230A
+
 #endif /* __A200_REG_H */
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 03e447b..ce76a8f 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -728,8 +728,21 @@
 	} else {
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_DUMP_AND_RECOVER);
 		INIT_COMPLETION(device->recovery_gate);
-		/* Detected a hang - trigger an automatic dump */
+		/* Detected a hang */
+
+
+		/*
+		 * Trigger an automatic dump of the state to
+		 * the console
+		 */
 		adreno_postmortem_dump(device, 0);
+
+		/*
+		 * Make a GPU snapshot.  For now, do it after the PM dump so we
+		 * can at least be sure the PM dump will work as it always has
+		 */
+		kgsl_device_snapshot(device, 1);
+
 		result = adreno_recover_hang(device);
 		if (result)
 			kgsl_pwrctrl_set_state(device, KGSL_STATE_HUNG);
@@ -1094,7 +1107,8 @@
 			* get an interrupt */
 			cmds[0] = cp_type3_packet(CP_NOP, 1);
 			cmds[1] = 0;
-			adreno_ringbuffer_issuecmds(device, 0, &cmds[0], 2);
+			adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
+				&cmds[0], 2);
 		}
 		mutex_unlock(&device->mutex);
 	}
@@ -1341,6 +1355,7 @@
 	.power_stats = adreno_power_stats,
 	.irqctrl = adreno_irqctrl,
 	.gpuid = adreno_gpuid,
+	.snapshot = adreno_snapshot,
 	/* Optional functions */
 	.setstate = adreno_setstate,
 	.drawctxt_create = adreno_drawctxt_create,
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index a3d2c00..bdba624 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -24,6 +24,7 @@
 		KGSL_CONTAINER_OF(device, struct adreno_device, dev)
 
 /* Flags to control command packet settings */
+#define KGSL_CMD_FLAGS_NONE             0x00000000
 #define KGSL_CMD_FLAGS_PMODE		0x00000001
 #define KGSL_CMD_FLAGS_NO_TS_CMP	0x00000002
 #define KGSL_CMD_FLAGS_NOT_KERNEL_CMD	0x00000004
@@ -84,6 +85,7 @@
 	void (*ctxt_restore)(struct adreno_device *, struct adreno_context *);
 	irqreturn_t (*irq_handler)(struct adreno_device *);
 	void (*irq_control)(struct adreno_device *, int);
+	void * (*snapshot)(struct adreno_device *, void *, int *, int);
 };
 
 extern struct adreno_gpudev adreno_a2xx_gpudev;
@@ -108,6 +110,9 @@
 uint8_t *adreno_convertaddr(struct kgsl_device *device,
 	unsigned int pt_base, unsigned int gpuaddr, unsigned int size);
 
+void *adreno_snapshot(struct kgsl_device *device, void *snapshot, int *remain,
+		int hang);
+
 static inline int adreno_is_a200(struct adreno_device *adreno_dev)
 {
 	return (adreno_dev->gpurev == ADRENO_REV_A200);
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index 16402c3..cf9a60a 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1405,7 +1405,8 @@
 		"active context flags %08x\n", context->flags);
 
 	/* save registers and constants. */
-	adreno_ringbuffer_issuecmds(device, 0, context->reg_save, 3);
+	adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
+		context->reg_save, 3);
 
 	if (context->flags & CTXT_FLAGS_SHADER_SAVE) {
 		/* save shader partitioning and instructions. */
@@ -1415,7 +1416,7 @@
 		/* fixup shader partitioning parameter for
 		 *  SET_SHADER_BASES.
 		 */
-		adreno_ringbuffer_issuecmds(device, 0,
+		adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
 			context->shader_fixup, 3);
 
 		context->flags |= CTXT_FLAGS_SHADER_RESTORE;
@@ -1430,7 +1431,7 @@
 			context->context_gmem_shadow.gmem_save, 3);
 
 		/* Restore TP0_CHICKEN */
-		adreno_ringbuffer_issuecmds(device, 0,
+		adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
 			context->chicken_restore, 3);
 
 		context->flags |= CTXT_FLAGS_GMEM_RESTORE;
@@ -1481,7 +1482,7 @@
 	cmds[3] = device->memstore.gpuaddr +
 		KGSL_DEVICE_MEMSTORE_OFFSET(current_context);
 	cmds[4] = (unsigned int) context;
-	adreno_ringbuffer_issuecmds(device, 0, cmds, 5);
+	adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE, cmds, 5);
 	kgsl_mmu_setstate(device, context->pagetable);
 
 #ifndef CONFIG_MSM_KGSL_CFF_DUMP_NO_CONTEXT_MEM_DUMP
@@ -1498,26 +1499,27 @@
 			context->context_gmem_shadow.gmem_restore, 3);
 
 		/* Restore TP0_CHICKEN */
-		adreno_ringbuffer_issuecmds(device, 0,
+		adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
 			context->chicken_restore, 3);
 
 		context->flags &= ~CTXT_FLAGS_GMEM_RESTORE;
 	}
 
 	/* restore registers and constants. */
-	adreno_ringbuffer_issuecmds(device, 0,
+	adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
 		context->reg_restore, 3);
 
 	/* restore shader instructions & partitioning. */
 	if (context->flags & CTXT_FLAGS_SHADER_RESTORE) {
-		adreno_ringbuffer_issuecmds(device, 0,
+		adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
 			context->shader_restore, 3);
 	}
 
 	if (adreno_is_a20x(adreno_dev)) {
 		cmds[0] = cp_type3_packet(CP_SET_BIN_BASE_OFFSET, 1);
 		cmds[1] = context->bin_base_offset;
-		adreno_ringbuffer_issuecmds(device, 0, cmds, 2);
+		adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
+			cmds, 2);
 	}
 }
 
@@ -1704,6 +1706,10 @@
 	wmb();
 }
 
+/* Defined in adreno_a2xx_snapshot.c */
+void *a2xx_snapshot(struct adreno_device *adreno_dev, void *snapshot,
+	int *remain, int hang);
+
 struct adreno_gpudev adreno_a2xx_gpudev = {
 	.ctxt_gpustate_shadow = a2xx_ctxt_gpustate_shadow,
 	.ctxt_gmem_shadow = a2xx_ctxt_gmem_shadow,
@@ -1711,4 +1717,5 @@
 	.ctxt_restore = a2xx_ctxt_restore,
 	.irq_handler = a2xx_irq_handler,
 	.irq_control = a2xx_irq_control,
+	.snapshot = a2xx_snapshot,
 };
diff --git a/drivers/gpu/msm/adreno_a2xx_snapshot.c b/drivers/gpu/msm/adreno_a2xx_snapshot.c
new file mode 100644
index 0000000..30d692b
--- /dev/null
+++ b/drivers/gpu/msm/adreno_a2xx_snapshot.c
@@ -0,0 +1,356 @@
+/* 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 "kgsl.h"
+#include "adreno.h"
+#include "kgsl_snapshot.h"
+
+#define DEBUG_SECTION_SZ(_dwords) (((_dwords) * sizeof(unsigned int)) \
+		+ sizeof(struct kgsl_snapshot_debug))
+
+/* Dump the SX debug registers into a GPU snapshot debug section */
+
+#define SXDEBUG_COUNT 0x1B
+
+static int a2xx_snapshot_sxdebug(struct kgsl_device *device, void *snapshot,
+	int remain, void *priv)
+{
+	struct kgsl_snapshot_debug *header = snapshot;
+	unsigned int *data = snapshot + sizeof(*header);
+	int i;
+
+	if (remain < DEBUG_SECTION_SZ(SXDEBUG_COUNT)) {
+		SNAPSHOT_ERR_NOMEM(device, "SX DEBUG");
+		return 0;
+	}
+
+	header->type = SNAPSHOT_DEBUG_SX;
+	header->size = SXDEBUG_COUNT;
+
+	for (i = 0; i < SXDEBUG_COUNT; i++) {
+		adreno_regwrite(device, REG_RBBM_DEBUG_CNTL, 0x1B00 | i);
+		adreno_regread(device, REG_RBBM_DEBUG_OUT, &data[i]);
+	}
+
+	adreno_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
+
+	return DEBUG_SECTION_SZ(SXDEBUG_COUNT);
+}
+
+#define CPDEBUG_COUNT 0x20
+
+static int a2xx_snapshot_cpdebug(struct kgsl_device *device, void *snapshot,
+	int remain, void *priv)
+{
+	struct kgsl_snapshot_debug *header = snapshot;
+	unsigned int *data = snapshot + sizeof(*header);
+	int i;
+
+	if (remain < DEBUG_SECTION_SZ(CPDEBUG_COUNT)) {
+		SNAPSHOT_ERR_NOMEM(device, "CP DEBUG");
+		return 0;
+	}
+
+	header->type = SNAPSHOT_DEBUG_CP;
+	header->size = CPDEBUG_COUNT;
+
+	for (i = 0; i < CPDEBUG_COUNT; i++) {
+		adreno_regwrite(device, REG_RBBM_DEBUG_CNTL, 0x1628);
+		adreno_regread(device, REG_RBBM_DEBUG_OUT, &data[i]);
+	}
+
+	adreno_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
+
+	return DEBUG_SECTION_SZ(CPDEBUG_COUNT);
+}
+
+/*
+ * The contents of the SQ debug sections are dword pairs:
+ * [register offset]:[value]
+ * This macro writes both dwords for the given register
+ */
+
+#define SQ_DEBUG_WRITE(_device, _reg, _data, _offset) \
+	do { _data[(_offset)++] = (_reg); \
+	adreno_regread(_device, (_reg), &_data[(_offset)++]); } while (0)
+
+#define SQ_DEBUG_BANK_SIZE 23
+
+static int a2xx_snapshot_sqdebug(struct kgsl_device *device, void *snapshot,
+	int remain, void *priv)
+{
+	struct kgsl_snapshot_debug *header = snapshot;
+	unsigned int *data = snapshot + sizeof(*header);
+	int i, offset = 0;
+	int size = SQ_DEBUG_BANK_SIZE * 2 * 2;
+
+	if (remain < DEBUG_SECTION_SZ(size)) {
+		SNAPSHOT_ERR_NOMEM(device, "SQ Debug");
+		return 0;
+	}
+
+	header->type = SNAPSHOT_DEBUG_SQ;
+	header->size = size;
+
+	for (i = 0; i < 2; i++) {
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_CONST_MGR_FSM+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_EXP_ALLOC+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_FSM_ALU_0+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_FSM_ALU_1+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_GPR_PIX+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_GPR_VTX+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_INPUT_FSM+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_MISC+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_MISC_0+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_MISC_1+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_0+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATE_MEM+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device,
+			REG_SQ_DEBUG_PIX_TB_STATUS_REG_0+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device,
+			REG_SQ_DEBUG_PIX_TB_STATUS_REG_1+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device,
+			REG_SQ_DEBUG_PIX_TB_STATUS_REG_2+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device,
+			REG_SQ_DEBUG_PIX_TB_STATUS_REG_3+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PTR_BUFF+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_TB_STATUS_SEL+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_TP_FSM+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_VTX_TB_0+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_VTX_TB_1+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_VTX_TB_STATE_MEM+i*0x1000,
+			data, offset);
+	}
+
+	return DEBUG_SECTION_SZ(size);
+}
+
+#define SQ_DEBUG_THREAD_SIZE 7
+
+static int a2xx_snapshot_sqthreaddebug(struct kgsl_device *device,
+	void *snapshot, int remain, void *priv)
+{
+	struct kgsl_snapshot_debug *header = snapshot;
+	unsigned int *data = snapshot + sizeof(*header);
+	int i, offset = 0;
+	int size = SQ_DEBUG_THREAD_SIZE * 2 * 16;
+
+	if (remain < DEBUG_SECTION_SZ(size)) {
+		SNAPSHOT_ERR_NOMEM(device, "SQ THREAD DEBUG");
+		return 0;
+	}
+
+	header->type = SNAPSHOT_DEBUG_SQTHREAD;
+	header->size = size;
+
+	for (i = 0; i < 16; i++) {
+		adreno_regwrite(device, REG_SQ_DEBUG_TB_STATUS_SEL,
+				i | (6<<4) | (i<<7) | (1<<11) | (1<<12)
+				| (i<<16) | (6<<20) | (i<<23));
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_VTX_TB_STATE_MEM,
+			 data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_VTX_TB_STATUS_REG,
+			 data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATE_MEM,
+			 data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATUS_REG_0,
+			 data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATUS_REG_1,
+			 data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATUS_REG_2,
+			 data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATUS_REG_3,
+			 data, offset);
+	}
+
+	return DEBUG_SECTION_SZ(size);
+}
+
+#define MIUDEBUG_COUNT 0x10
+
+static int a2xx_snapshot_miudebug(struct kgsl_device *device, void *snapshot,
+	int remain, void *priv)
+{
+	struct kgsl_snapshot_debug *header = snapshot;
+	unsigned int *data = snapshot + sizeof(*header);
+	int i;
+
+	if (remain < DEBUG_SECTION_SZ(MIUDEBUG_COUNT)) {
+		SNAPSHOT_ERR_NOMEM(device, "MIU DEBUG");
+		return 0;
+	}
+
+	header->type = SNAPSHOT_DEBUG_MIU;
+	header->size = MIUDEBUG_COUNT;
+
+	for (i = 0; i < MIUDEBUG_COUNT; i++) {
+		adreno_regwrite(device, REG_RBBM_DEBUG_CNTL, 0x1600 | i);
+		adreno_regread(device, REG_RBBM_DEBUG_OUT, &data[i]);
+	}
+
+	adreno_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
+
+	return DEBUG_SECTION_SZ(MIUDEBUG_COUNT);
+}
+
+/* Helper function to snapshot a section of indexed registers */
+
+static void *a2xx_snapshot_indexed_registers(struct kgsl_device *device,
+		void *snapshot, int *remain,
+		unsigned int index, unsigned int data, unsigned int start,
+		unsigned int count)
+{
+	struct kgsl_snapshot_indexed_registers iregs;
+	iregs.index = index;
+	iregs.data = data;
+	iregs.start = start;
+	iregs.count = count;
+
+	return kgsl_snapshot_add_section(device,
+		 KGSL_SNAPSHOT_SECTION_INDEXED_REGS, snapshot,
+		 remain, kgsl_snapshot_dump_indexed_regs, &iregs);
+}
+
+/* A2XX GPU snapshot function - this is where all of the A2XX specific
+ * bits and pieces are grabbed into the snapshot memory
+ */
+
+void *a2xx_snapshot(struct adreno_device *adreno_dev, void *snapshot,
+	int *remain, int hang)
+{
+	struct kgsl_device *device = &adreno_dev->dev;
+	struct kgsl_snapshot_registers regs;
+	unsigned int pmoverride;
+
+	/* Choose the register set to dump */
+
+	if (adreno_is_a20x(adreno_dev)) {
+		regs.regs = (unsigned int *) a200_registers;
+		regs.count = a200_registers_count;
+	} else {
+		regs.regs = (unsigned int *) a220_registers;
+		regs.count = a220_registers_count;
+	}
+
+	/* Master set of (non debug) registers */
+	snapshot = kgsl_snapshot_add_section(device,
+		KGSL_SNAPSHOT_SECTION_REGS, snapshot, remain,
+		kgsl_snapshot_dump_regs, &regs);
+
+	/* CP_STATE_DEBUG indexed registers */
+	snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+			remain, REG_CP_STATE_DEBUG_INDEX,
+			REG_CP_STATE_DEBUG_DATA, 0x0, 0x14);
+
+	/* CP_ME indexed registers */
+	snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+			remain, REG_CP_ME_CNTL, REG_CP_ME_STATUS,
+			64, 44);
+
+	/*
+	 * Need to temporarily turn off clock gating for the debug bus to
+	 * work
+	 */
+
+	adreno_regread(device, REG_RBBM_PM_OVERRIDE2, &pmoverride);
+	adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0xFF);
+
+	/* SX debug registers */
+	snapshot = kgsl_snapshot_add_section(device,
+			KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
+			a2xx_snapshot_sxdebug, NULL);
+
+	/* SU debug indexed registers (only for < 470) */
+	if (!adreno_is_a22x(adreno_dev))
+		snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+				remain, REG_PA_SU_DEBUG_CNTL,
+				REG_PA_SU_DEBUG_DATA,
+				0, 0x1B);
+
+	/* CP debug registers */
+	snapshot = kgsl_snapshot_add_section(device,
+			KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
+			a2xx_snapshot_cpdebug, NULL);
+
+	/* MH debug indexed registers */
+	snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+			remain, MH_DEBUG_CTRL, MH_DEBUG_DATA, 0x0, 0x40);
+
+	/* Leia only register sets */
+	if (adreno_is_a22x(adreno_dev)) {
+		/* RB DEBUG indexed regisers */
+		snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+			remain, REG_RB_DEBUG_CNTL, REG_RB_DEBUG_DATA, 0, 8);
+
+		/* RB DEBUG indexed registers bank 2 */
+		snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+			remain, REG_RB_DEBUG_CNTL, REG_RB_DEBUG_DATA + 0x1000,
+			0, 8);
+
+		/* PC_DEBUG indexed registers */
+		snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+			remain, REG_PC_DEBUG_CNTL, REG_PC_DEBUG_DATA, 0, 8);
+
+		/* GRAS_DEBUG indexed registers */
+		snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+			remain, REG_GRAS_DEBUG_CNTL, REG_GRAS_DEBUG_DATA, 0, 4);
+
+		/* MIU debug registers */
+		snapshot = kgsl_snapshot_add_section(device,
+			KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
+			a2xx_snapshot_miudebug, NULL);
+
+		/* SQ DEBUG debug registers */
+		snapshot = kgsl_snapshot_add_section(device,
+			KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
+			a2xx_snapshot_sqdebug, NULL);
+
+		/*
+		 * Reading SQ THREAD causes bad things to happen on a running
+		 * system, so only read it if the GPU is already hung
+		 */
+
+		if (hang) {
+			/* SQ THREAD debug registers */
+			snapshot = kgsl_snapshot_add_section(device,
+				KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
+				a2xx_snapshot_sqthreaddebug, NULL);
+		}
+	}
+
+	/* Reset the clock gating */
+	adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, pmoverride);
+
+	return snapshot;
+}
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
new file mode 100644
index 0000000..fb88a72
--- /dev/null
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -0,0 +1,332 @@
+/* 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 "kgsl.h"
+#include "kgsl_sharedmem.h"
+#include "kgsl_snapshot.h"
+
+#include "adreno.h"
+#include "adreno_pm4types.h"
+#include "a2xx_reg.h"
+
+/* Number of dwords of ringbuffer history to record */
+#define NUM_DWORDS_OF_RINGBUFFER_HISTORY 100
+
+/* Maintain a list of the objects we see during parsing */
+
+#define SNAPSHOT_OBJ_BUFSIZE 64
+
+#define SNAPSHOT_OBJ_TYPE_IB 0
+
+static struct kgsl_snapshot_obj {
+	int type;
+	uint32_t gpuaddr;
+	uint32_t ptbase;
+	void *ptr;
+	int dwords;
+} objbuf[SNAPSHOT_OBJ_BUFSIZE];
+
+/* Pointer to the next open entry in the object list */
+static int objbufptr;
+
+/* Push a new buffer object onto the list */
+static void push_object(struct kgsl_device *device, int type, uint32_t ptbase,
+	uint32_t gpuaddr, int dwords)
+{
+	int index;
+	void *ptr;
+
+	/* Go through the list and see that object has already been seen */
+	for (index = 0; index < objbufptr; index++) {
+		if (objbuf[index].gpuaddr == gpuaddr &&
+			objbuf[index].ptbase == ptbase)
+			return;
+	}
+
+	if (objbufptr == SNAPSHOT_OBJ_BUFSIZE) {
+		KGSL_DRV_ERR(device, "snapshot: too many snapshot objects\n");
+		return;
+	}
+
+	/*
+	 * adreno_convertaddr verifies that the IB size is valid - at least in
+	 * the context of it being smaller then the allocated memory space
+	 */
+	ptr = adreno_convertaddr(device, ptbase, gpuaddr, dwords << 2);
+
+	if (ptr == NULL) {
+		KGSL_DRV_ERR(device,
+			"snapshot: Can't find GPU address for %x\n", gpuaddr);
+		return;
+	}
+
+	/* Put it on the list of things to parse */
+	objbuf[objbufptr].type = type;
+	objbuf[objbufptr].gpuaddr = gpuaddr;
+	objbuf[objbufptr].ptbase = ptbase;
+	objbuf[objbufptr].dwords = dwords;
+	objbuf[objbufptr++].ptr = ptr;
+}
+
+/* Snapshot the istore memory */
+static int snapshot_istore(struct kgsl_device *device, void *snapshot,
+	int remain, void *priv)
+{
+	struct kgsl_snapshot_istore *header = snapshot;
+	unsigned int *data = snapshot + sizeof(*header);
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	int count, i;
+
+	count = adreno_dev->istore_size * ADRENO_ISTORE_WORDS;
+
+	if (remain < (count * 4) + sizeof(*header)) {
+		KGSL_DRV_ERR(device,
+			"snapshot: Not enough memory for the istore section");
+		return 0;
+	}
+
+	header->count = adreno_dev->istore_size;
+
+	for (i = 0; i < count; i++)
+		kgsl_regread(device, ADRENO_ISTORE_START + i, &data[i]);
+
+	return (count * 4) + sizeof(*header);
+}
+
+/* Snapshot the ringbuffer memory */
+static int snapshot_rb(struct kgsl_device *device, void *snapshot,
+	int remain, void *priv)
+{
+	struct kgsl_snapshot_rb *header = snapshot;
+	unsigned int *data = snapshot + sizeof(*header);
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+	unsigned int rbbase, ptbase, rptr, *rbptr;
+	int start, stop, index;
+	int numitems, size;
+
+	/* Get the GPU address of the ringbuffer */
+	kgsl_regread(device, REG_CP_RB_BASE, &rbbase);
+
+	/* Get the physical address of the MMU pagetable */
+	ptbase = kgsl_mmu_get_current_ptbase(device);
+
+	/* Get the current read pointers for the RB */
+	kgsl_regread(device, REG_CP_RB_RPTR, &rptr);
+
+	/* start the dump at the rptr minus some history */
+	start = (int) rptr - NUM_DWORDS_OF_RINGBUFFER_HISTORY;
+	if (start < 0)
+		start += rb->sizedwords;
+
+	/*
+	 * Stop the dump at the point where the software last wrote.  Don't use
+	 * the hardware value here on the chance that it didn't get properly
+	 * updated
+	 */
+
+	stop = (int) rb->wptr + 16;
+	if (stop > rb->sizedwords)
+		stop -= rb->sizedwords;
+
+	/* Set up the header for the section */
+
+	numitems = (stop > start) ? stop - start :
+		(rb->sizedwords - start) + stop;
+
+	size = (numitems << 2);
+
+	if (remain < size + sizeof(*header)) {
+		KGSL_DRV_ERR(device,
+			"snapshot: Not enough memory for the rb section");
+		return 0;
+	}
+
+	/* Write the sub-header for the section */
+	header->start = start;
+	header->end = stop;
+	header->wptr = rb->wptr;
+	header->rbsize = rb->sizedwords;
+	header->count = numitems;
+
+	index = start;
+	rbptr = rb->buffer_desc.hostptr;
+
+	/*
+	 * Loop through the RB, copying the data and looking for indirect
+	 * buffers and MMU pagetable changes
+	 */
+
+	while (index != rb->wptr) {
+		*data = rbptr[index];
+
+		if (rbptr[index] == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2))
+			push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
+				rbptr[index + 1], rbptr[index + 2]);
+
+		/*
+		 * FIXME: Handle upcoming MMU pagetable changes, but only
+		 * between the rptr and the wptr
+		 */
+
+		index = index + 1;
+
+		if (index == rb->sizedwords)
+			index = 0;
+
+		data++;
+	}
+
+	/* Dump 16 dwords past the wptr, but don't  bother interpeting it */
+
+	while (index != stop) {
+		*data = rbptr[index];
+		index = index + 1;
+
+		if (index == rb->sizedwords)
+			index = 0;
+
+		data++;
+	}
+
+	/* Return the size of the section */
+	return size + sizeof(*header);
+}
+
+/* Snapshot the memory for an indirect buffer */
+static int snapshot_ib(struct kgsl_device *device, void *snapshot,
+	int remain, void *priv)
+{
+	struct kgsl_snapshot_ib *header = snapshot;
+	struct kgsl_snapshot_obj *obj = priv;
+	unsigned int *src = obj->ptr;
+	unsigned int *dst = snapshot + sizeof(*header);
+	int i;
+
+	if (remain < (obj->dwords << 2) + sizeof(*header)) {
+		KGSL_DRV_ERR(device,
+			"snapshot: Not enough memory for the ib section");
+		return 0;
+	}
+
+	/* Write the sub-header for the section */
+	header->gpuaddr = obj->gpuaddr;
+	header->ptbase = obj->ptbase;
+	header->size = obj->dwords;
+
+	/* Write the contents of the ib */
+	for (i = 0; i < obj->dwords; i++) {
+		*dst = *src;
+		/* If another IB is discovered, then push it on the list too */
+
+		if (*src == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2)) {
+			push_object(device, SNAPSHOT_OBJ_TYPE_IB, obj->ptbase,
+				*(src + 1), *(src + 2));
+		}
+
+		src++;
+		dst++;
+	}
+
+	return (obj->dwords << 2) + sizeof(*header);
+}
+
+/* Dump another item on the current pending list */
+static void *dump_object(struct kgsl_device *device, int obj, void *snapshot,
+	int *remain)
+{
+	switch (objbuf[obj].type) {
+	case SNAPSHOT_OBJ_TYPE_IB:
+		snapshot = kgsl_snapshot_add_section(device,
+			KGSL_SNAPSHOT_SECTION_IB, snapshot, remain,
+			snapshot_ib, &objbuf[obj]);
+		break;
+	default:
+		KGSL_DRV_ERR(device,
+			"snapshot: Invalid snapshot object type: %d\n",
+			objbuf[obj].type);
+		break;
+	}
+
+	return snapshot;
+}
+
+/* adreno_snapshot - Snapshot the Adreno GPU state
+ * @device - KGSL device to snapshot
+ * @snapshot - Pointer to the start of memory to write into
+ * @remain - A pointer to how many bytes of memory are remaining in the snapshot
+ * @hang - set if this snapshot was automatically triggered by a GPU hang
+ * This is a hook function called by kgsl_snapshot to snapshot the
+ * Adreno specific information for the GPU snapshot.  In turn, this function
+ * calls the GPU specific snapshot function to get core specific information.
+ */
+
+void *adreno_snapshot(struct kgsl_device *device, void *snapshot, int *remain,
+		int hang)
+{
+	int i;
+	uint32_t ptbase, ibbase, ibsize;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+	/* Reset the list of objects */
+	objbufptr = 0;
+
+	/* Get the physical address of the MMU pagetable */
+	ptbase = kgsl_mmu_get_current_ptbase(device);
+
+	/* Dump the ringbuffer */
+	snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_RB,
+		snapshot, remain, snapshot_rb, NULL);
+
+	/*
+	 * Make sure that the IBs described in the CP registers are on the
+	 * list of objects
+	 */
+	kgsl_regread(device, REG_CP_IB1_BASE, &ibbase);
+	kgsl_regread(device, REG_CP_IB1_BUFSZ, &ibsize);
+
+	if (ibsize)
+		push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
+			ibbase, ibsize);
+
+	kgsl_regread(device, REG_CP_IB2_BASE, &ibbase);
+	kgsl_regread(device, REG_CP_IB2_BUFSZ, &ibsize);
+
+	if (ibsize)
+		push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
+			ibbase, ibsize);
+
+	/*
+	 * Go through the list of found objects and dump each one.  As the IBs
+	 * are parsed, more objects might be found, and objbufptr will increase
+	 */
+	for (i = 0; i < objbufptr; i++)
+		snapshot = dump_object(device, i, snapshot, remain);
+
+	/*
+	 * Only dump the istore on a hang - reading it on a running system
+	 * has a non 0 chance of hanging the GPU
+	 */
+
+	if (hang) {
+		snapshot = kgsl_snapshot_add_section(device,
+			KGSL_SNAPSHOT_SECTION_ISTORE, snapshot, remain,
+			snapshot_istore, NULL);
+	}
+
+	/* Add GPU specific sections - registers mainly, but other stuff too */
+	if (adreno_dev->gpudev->snapshot)
+		snapshot = adreno_dev->gpudev->snapshot(adreno_dev, snapshot,
+			remain, hang);
+
+	return snapshot;
+}
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index c6e78dd..1b6696b 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2097,6 +2097,8 @@
 	if (minor == KGSL_DEVICE_MAX)
 		return;
 
+	kgsl_device_snapshot_close(device);
+
 	kgsl_cffdump_close(device->id);
 	kgsl_pwrctrl_uninit_sysfs(device);
 
@@ -2199,6 +2201,9 @@
 
 	idr_init(&device->context_idr);
 
+	/* Initalize the snapshot engine */
+	kgsl_device_snapshot_init(device);
+
 	/* sysfs and debugfs initalization - failure here is non fatal */
 
 	/* Initialize logging */
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index f82b038..8ea5279 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -90,6 +90,8 @@
 		struct kgsl_power_stats *stats);
 	void (*irqctrl)(struct kgsl_device *device, int state);
 	unsigned int (*gpuid)(struct kgsl_device *device);
+	void * (*snapshot)(struct kgsl_device *device, void *snapshot,
+		int *remain, int hang);
 	/* Optional functions - these functions are not mandatory.  The
 	   driver will check that the function pointer is not NULL before
 	   calling the hook */
@@ -164,6 +166,15 @@
 	struct idr context_idr;
 	struct early_suspend display_off;
 
+	void *snapshot;		/* Pointer to the snapshot memory region */
+	int snapshot_maxsize;   /* Max size of the snapshot region */
+	int snapshot_size;      /* Current size of the snapshot region */
+	u32 snapshot_timestamp;	/* Timestamp of the last valid snapshot */
+	int snapshot_frozen;	/* 1 if the snapshot output is frozen until
+				   it gets read by the user.  This avoids
+				   losing the output on multiple hangs  */
+	struct kobject snapshot_kobj;
+
 	/* Logging levels */
 	int cmd_log;
 	int ctxt_log;
@@ -320,4 +331,8 @@
 
 const char *kgsl_pwrstate_to_str(unsigned int state);
 
+int kgsl_device_snapshot_init(struct kgsl_device *device);
+int kgsl_device_snapshot(struct kgsl_device *device, int hang);
+void kgsl_device_snapshot_close(struct kgsl_device *device);
+
 #endif  /* __KGSL_DEVICE_H */
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
new file mode 100644
index 0000000..72df148b
--- /dev/null
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -0,0 +1,484 @@
+/* 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/vmalloc.h>
+#include <linux/time.h>
+#include <linux/sysfs.h>
+#include <linux/utsname.h>
+#include <linux/sched.h>
+#include <linux/idr.h>
+
+#include "kgsl.h"
+#include "kgsl_log.h"
+#include "kgsl_device.h"
+#include "kgsl_sharedmem.h"
+#include "kgsl_snapshot.h"
+
+/* idr_for_each function to count the number of contexts */
+
+static int snapshot_context_count(int id, void *ptr, void *data)
+{
+	int *count = data;
+	*count = *count + 1;
+
+	return 0;
+}
+
+/*
+ * To simplify the iterator loop use a global pointer instead of trying
+ * to pass around double star references to the snapshot data
+ */
+
+static void *_ctxtptr;
+
+static int snapshot_context_info(int id, void *ptr, void *data)
+{
+	struct kgsl_snapshot_linux_context *header = _ctxtptr;
+	struct kgsl_context *context = ptr;
+	struct kgsl_device *device = context->dev_priv->device;
+
+	header->id = id;
+
+	/* Future-proof for per-context timestamps - for now, just
+	 * return the global timestamp for all contexts
+	 */
+
+	header->timestamp_queued = -1;
+	header->timestamp_retired = device->ftbl->readtimestamp(device,
+		KGSL_TIMESTAMP_RETIRED);
+
+	_ctxtptr += sizeof(struct kgsl_snapshot_linux_context);
+
+	return 0;
+}
+
+/* Snapshot the Linux specific information */
+static int snapshot_os(struct kgsl_device *device,
+	void *snapshot, int remain, void *priv)
+{
+	struct kgsl_snapshot_linux *header = snapshot;
+	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+	struct task_struct *task;
+	pid_t pid;
+	int hang = (int) priv;
+	int ctxtcount = 0;
+	int size = sizeof(*header);
+
+	/* Figure out how many active contexts there are - these will
+	 * be appended on the end of the structure */
+
+	idr_for_each(&device->context_idr, snapshot_context_count, &ctxtcount);
+
+	size += ctxtcount * sizeof(struct kgsl_snapshot_linux_context);
+
+	/* Make sure there is enough room for the data */
+	if (remain < size) {
+		SNAPSHOT_ERR_NOMEM(device, "OS");
+		return 0;
+	}
+
+	memset(header, 0, sizeof(*header));
+
+	header->osid = KGSL_SNAPSHOT_OS_LINUX;
+
+	header->state = hang ? SNAPSHOT_STATE_HUNG : SNAPSHOT_STATE_RUNNING;
+
+	/* Get the kernel build information */
+	strlcpy(header->release, utsname()->release, sizeof(header->release));
+	strlcpy(header->version, utsname()->version, sizeof(header->version));
+
+	/* Get the Unix time for the timestamp */
+	header->seconds = get_seconds();
+
+	/* Remember the power information */
+	header->power_flags = pwr->power_flags;
+	header->power_level = pwr->active_pwrlevel;
+	header->power_interval_timeout = pwr->interval_timeout;
+	header->grpclk = kgsl_get_clkrate(pwr->grp_clks[0]);
+	header->busclk = kgsl_get_clkrate(pwr->ebi1_clk);
+
+	/* Future proof for per-context timestamps */
+	header->current_context = -1;
+
+	/* Get the current PT base */
+	header->ptbase = kgsl_mmu_get_current_ptbase(device);
+	/* And the PID for the task leader */
+	pid = header->pid = kgsl_mmu_get_ptname_from_ptbase(header->ptbase);
+
+	task = find_task_by_vpid(pid);
+
+	if (task)
+		get_task_comm(header->comm, task);
+
+	header->ctxtcount = ctxtcount;
+
+	/* append information for each context */
+	_ctxtptr = snapshot + sizeof(*header);
+	idr_for_each(&device->context_idr, snapshot_context_info, NULL);
+
+	/* Return the size of the data segment */
+	return size;
+}
+/*
+ * kgsl_snapshot_dump_indexed_regs - helper function to dump indexed registers
+ * @device - the device to dump registers from
+ * @snapshot - pointer to the start of the region of memory for the snapshot
+ * @remain - a pointer to the number of bytes remaining in the snapshot
+ * @priv - A pointer to the kgsl_snapshot_indexed_registers data
+ *
+ * Given a indexed register cmd/data pair and a count, dump each indexed
+ * register
+ */
+
+int kgsl_snapshot_dump_indexed_regs(struct kgsl_device *device,
+	void *snapshot, int remain, void *priv)
+{
+	struct kgsl_snapshot_indexed_registers *iregs = priv;
+	struct kgsl_snapshot_indexed_regs *header = snapshot;
+	unsigned int *data = snapshot + sizeof(*header);
+	int i;
+
+	if (remain < (iregs->count * 4) + sizeof(*header)) {
+		SNAPSHOT_ERR_NOMEM(device, "INDEXED REGS");
+		return 0;
+	}
+
+	header->index_reg = iregs->index;
+	header->data_reg = iregs->data;
+	header->count = iregs->count;
+	header->start = iregs->start;
+
+	for (i = 0; i < iregs->count; i++) {
+		kgsl_regwrite(device, iregs->index, iregs->start + i);
+		kgsl_regread(device, iregs->data, &data[i]);
+	}
+
+	return (iregs->count * 4) + sizeof(*header);
+}
+EXPORT_SYMBOL(kgsl_snapshot_dump_indexed_regs);
+
+/*
+ * kgsl_snapshot_dump_regs - helper function to dump device registers
+ * @device - the device to dump registers from
+ * @snapshot - pointer to the start of the region of memory for the snapshot
+ * @remain - a pointer to the number of bytes remaining in the snapshot
+ * @priv - A pointer to the kgsl_snapshot_registers data
+ *
+ * Given an array of register ranges pairs (start,end [inclusive]), dump the
+ * registers into a snapshot register section.  The snapshot region stores a
+ * part of dwords for each register - the word address of the register, and
+ * the value.
+ */
+int kgsl_snapshot_dump_regs(struct kgsl_device *device, void *snapshot,
+	int remain, void *priv)
+{
+	struct kgsl_snapshot_regs *header = snapshot;
+	struct kgsl_snapshot_registers *regs = priv;
+	unsigned int *data = snapshot + sizeof(*header);
+	int count = 0, i, j;
+
+	/* Figure out how many registers we are going to dump */
+
+	for (i = 0; i < regs->count; i++) {
+		int start = regs->regs[i * 2];
+		int end = regs->regs[i * 2 + 1];
+
+		count += (end - start + 1);
+	}
+
+	if (remain < (count * 8) + sizeof(*header)) {
+		SNAPSHOT_ERR_NOMEM(device, "REGISTERS");
+		return 0;
+	}
+
+	for (i = 0; i < regs->count; i++) {
+		unsigned int start = regs->regs[i * 2];
+		unsigned int end = regs->regs[i * 2 + 1];
+
+		for (j = start; j <= end; j++) {
+			unsigned int val;
+
+			kgsl_regread(device, j, &val);
+			*data++ = j;
+			*data++ = val;
+		}
+	}
+
+	header->count = count;
+
+	/* Return the size of the section */
+	return (count * 8) + sizeof(*header);
+}
+EXPORT_SYMBOL(kgsl_snapshot_dump_regs);
+
+/*
+ * kgsl_snapshot - construct a device snapshot
+ * @device - device to snapshot
+ * @hang - set to 1 if the snapshot was triggered following a hnag
+ * Given a device, construct a binary snapshot dump of the current device state
+ * and store it in the device snapshot memory.
+ */
+int kgsl_device_snapshot(struct kgsl_device *device, int hang)
+{
+	struct kgsl_snapshot_header *header = device->snapshot;
+	int remain = device->snapshot_maxsize - sizeof(*header);
+	void *snapshot;
+
+	/*
+	 * The first hang is always the one we are interested in. To
+	 * avoid a subsequent hang blowing away the first, the snapshot
+	 * is frozen until it is dumped via sysfs.
+	 *
+	 * Note that triggered snapshots are always taken regardless
+	 * of the state and never frozen.
+	 */
+
+	if (hang && device->snapshot_frozen == 1)
+		return 0;
+
+	if (device->snapshot == NULL) {
+		KGSL_DRV_ERR(device,
+			"snapshot: No snapshot memory available\n");
+		return -ENOMEM;
+	}
+
+	if (remain < sizeof(*header)) {
+		KGSL_DRV_ERR(device,
+			"snapshot: Not enough memory for the header\n");
+		return -ENOMEM;
+	}
+
+	header->magic = SNAPSHOT_MAGIC;
+
+	header->gpuid = kgsl_gpuid(device);
+
+	/* Get a pointer to the first section (right after the header) */
+	snapshot = ((void *) device->snapshot) + sizeof(*header);
+
+	/* Build the Linux specific header */
+	snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_OS,
+		snapshot, &remain, snapshot_os, (void *) hang);
+
+	/* Get the device specific sections */
+	if (device->ftbl->snapshot)
+		snapshot = device->ftbl->snapshot(device, snapshot, &remain,
+			hang);
+
+	/* Add the empty end section to let the parser know we are done */
+	snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_END,
+		snapshot, &remain, NULL, NULL);
+
+	device->snapshot_timestamp = get_seconds();
+	device->snapshot_size = (int) (snapshot - device->snapshot);
+
+	/* Freeze the snapshot on a hang until it gets read */
+	device->snapshot_frozen = (hang) ? 1 : 0;
+
+	return 0;
+}
+EXPORT_SYMBOL(kgsl_device_snapshot);
+
+/* An attribute for showing snapshot details */
+struct kgsl_snapshot_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct kgsl_device *device, char *buf);
+	ssize_t (*store)(struct kgsl_device *device, const char *buf,
+		size_t count);
+};
+
+#define to_snapshot_attr(a) \
+container_of(a, struct kgsl_snapshot_attribute, attr)
+
+#define kobj_to_device(a) \
+container_of(a, struct kgsl_device, snapshot_kobj)
+
+/* Dump the sysfs binary data to the user */
+static ssize_t snapshot_show(struct file *filep, struct kobject *kobj,
+	struct bin_attribute *attr, char *buf, loff_t off,
+	size_t count)
+{
+	struct kgsl_device *device = kobj_to_device(kobj);
+
+	if (device == NULL)
+		return 0;
+
+	/* Return nothing if we haven't taken a snapshot yet */
+	if (device->snapshot_timestamp == 0)
+		return 0;
+
+	/* Get the mutex to keep things from changing while we are dumping */
+	mutex_lock(&device->mutex);
+
+	/*
+	 * Release the freeze on the snapshot the first time the buffer is read
+	 */
+
+	device->snapshot_frozen = 0;
+
+	if (off >= device->snapshot_size) {
+		count = 0;
+		goto exit;
+	}
+
+	if (off + count > device->snapshot_size)
+		count = device->snapshot_size - off;
+
+	memcpy(buf, device->snapshot + off, count);
+
+exit:
+	mutex_unlock(&device->mutex);
+	return count;
+}
+
+/* Show the timestamp of the last collected snapshot */
+static ssize_t timestamp_show(struct kgsl_device *device, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%x\n", device->snapshot_timestamp);
+}
+
+/* manually trigger a new snapshot to be collected */
+static ssize_t trigger_store(struct kgsl_device *device, const char *buf,
+	size_t count)
+{
+	if (device && count > 0) {
+		mutex_lock(&device->mutex);
+		kgsl_device_snapshot(device, 0);
+		mutex_unlock(&device->mutex);
+	}
+
+	return count;
+}
+
+static struct bin_attribute snapshot_attr = {
+	.attr.name = "dump",
+	.attr.mode = 0444,
+	.size = 0,
+	.read = snapshot_show
+};
+
+#define SNAPSHOT_ATTR(_name, _mode, _show, _store) \
+struct kgsl_snapshot_attribute attr_##_name = { \
+	.attr = { .name = __stringify(_name), .mode = _mode }, \
+	.show = _show, \
+	.store = _store, \
+}
+
+SNAPSHOT_ATTR(trigger, 0600, NULL, trigger_store);
+SNAPSHOT_ATTR(timestamp, 0444, timestamp_show, NULL);
+
+static void snapshot_sysfs_release(struct kobject *kobj)
+{
+}
+
+static ssize_t snapshot_sysfs_show(struct kobject *kobj,
+	struct attribute *attr, char *buf)
+{
+	struct kgsl_snapshot_attribute *pattr = to_snapshot_attr(attr);
+	struct kgsl_device *device = kobj_to_device(kobj);
+	ssize_t ret;
+
+	if (device && pattr->show)
+		ret = pattr->show(device, buf);
+	else
+		ret = -EIO;
+
+	return ret;
+}
+
+static ssize_t snapshot_sysfs_store(struct kobject *kobj,
+	struct attribute *attr, const char *buf, size_t count)
+{
+	struct kgsl_snapshot_attribute *pattr = to_snapshot_attr(attr);
+	struct kgsl_device *device = kobj_to_device(kobj);
+	ssize_t ret;
+
+	if (device && pattr->store)
+		ret = pattr->store(device, buf, count);
+	else
+		ret = -EIO;
+
+	return ret;
+}
+
+static const struct sysfs_ops snapshot_sysfs_ops = {
+	.show = snapshot_sysfs_show,
+	.store = snapshot_sysfs_store,
+};
+
+static struct kobj_type ktype_snapshot = {
+	.sysfs_ops = &snapshot_sysfs_ops,
+	.default_attrs = NULL,
+	.release = snapshot_sysfs_release,
+};
+
+/* kgsl_device_snapshot_init - Add resources for the device GPU snapshot
+ * @device - The device to initalize
+ *
+ * Allocate memory for a GPU snapshot for the specified device,
+ * and create the sysfs files to manage it
+ */
+
+int kgsl_device_snapshot_init(struct kgsl_device *device)
+{
+	int ret;
+
+	if (device->snapshot == NULL)
+		device->snapshot = vmalloc(KGSL_SNAPSHOT_MEMSIZE);
+
+	if (device->snapshot == NULL)
+		return -ENOMEM;
+
+	device->snapshot_maxsize = KGSL_SNAPSHOT_MEMSIZE;
+	device->snapshot_timestamp = 0;
+
+	ret = kobject_init_and_add(&device->snapshot_kobj, &ktype_snapshot,
+		&device->dev->kobj, "snapshot");
+	if (ret)
+		goto done;
+
+	ret = sysfs_create_bin_file(&device->snapshot_kobj, &snapshot_attr);
+	if (ret)
+		goto done;
+
+	ret  = sysfs_create_file(&device->snapshot_kobj, &attr_trigger.attr);
+	if (ret)
+		goto done;
+
+	ret  = sysfs_create_file(&device->snapshot_kobj, &attr_timestamp.attr);
+
+done:
+	return ret;
+}
+EXPORT_SYMBOL(kgsl_device_snapshot_init);
+
+/* kgsl_device_snapshot_close - Take down snapshot memory for a device
+ * @device - Pointer to the kgsl_device
+ *
+ * Remove the sysfs files and free the memory allocated for the GPU
+ * snapshot
+ */
+
+void kgsl_device_snapshot_close(struct kgsl_device *device)
+{
+	sysfs_remove_bin_file(&device->snapshot_kobj, &snapshot_attr);
+	sysfs_remove_file(&device->snapshot_kobj, &attr_trigger.attr);
+	sysfs_remove_file(&device->snapshot_kobj, &attr_timestamp.attr);
+
+	kobject_put(&device->snapshot_kobj);
+
+	vfree(device->snapshot);
+
+	device->snapshot = NULL;
+	device->snapshot_maxsize = 0;
+	device->snapshot_timestamp = 0;
+}
+EXPORT_SYMBOL(kgsl_device_snapshot_close);
diff --git a/drivers/gpu/msm/kgsl_snapshot.h b/drivers/gpu/msm/kgsl_snapshot.h
new file mode 100644
index 0000000..4fdc8a1
--- /dev/null
+++ b/drivers/gpu/msm/kgsl_snapshot.h
@@ -0,0 +1,259 @@
+/* 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 _KGSL_SNAPSHOT_H_
+#define _KGSL_SNAPSHOT_H_
+
+#include <linux/types.h>
+
+/* Snapshot header */
+
+#define SNAPSHOT_MAGIC 0x504D0001
+
+/* GPU ID scheme:
+ * [16:31] - core identifer (0x0002 for 2D or 0x0003 for 3D)
+ * [00:16] - GPU specific identifier
+ */
+
+struct kgsl_snapshot_header {
+	__u32 magic; /* Magic identifier */
+	__u32 gpuid; /* GPU ID - see above */
+} __packed;
+
+/* Section header */
+#define SNAPSHOT_SECTION_MAGIC 0xABCD
+
+struct kgsl_snapshot_section_header {
+	__u16 magic; /* Magic identifier */
+	__u16 id;    /* Type of section */
+	__u32 size;  /* Size of the section including this header */
+} __packed;
+
+/* Section identifiers */
+#define KGSL_SNAPSHOT_SECTION_OS           0x0101
+#define KGSL_SNAPSHOT_SECTION_REGS         0x0201
+#define KGSL_SNAPSHOT_SECTION_RB           0x0301
+#define KGSL_SNAPSHOT_SECTION_IB           0x0401
+#define KGSL_SNAPSHOT_SECTION_INDEXED_REGS 0x0501
+#define KGSL_SNAPSHOT_SECTION_ISTORE       0x0801
+#define KGSL_SNAPSHOT_SECTION_DEBUG        0x0901
+#define KGSL_SNAPSHOT_SECTION_END          0xFFFF
+
+/* OS sub-section header */
+#define KGSL_SNAPSHOT_OS_LINUX             0x0001
+
+/* Linux OS specific information */
+
+#define SNAPSHOT_STATE_HUNG 0
+#define SNAPSHOT_STATE_RUNNING 1
+
+struct kgsl_snapshot_linux {
+	int osid;                   /* subsection OS identifier */
+	int state;		    /* 1 if the thread is running, 0 for hung */
+	__u32 seconds;		    /* Unix timestamp for the snapshot */
+	__u32 power_flags;            /* Current power flags */
+	__u32 power_level;            /* Current power level */
+	__u32 power_interval_timeout; /* Power interval timeout */
+	__u32 grpclk;                 /* Current GP clock value */
+	__u32 busclk;		    /* Current busclk value */
+	__u32 ptbase;		    /* Current ptbase */
+	__u32 pid;		    /* PID of the process that owns the PT */
+	__u32 current_context;	    /* ID of the current context */
+	__u32 ctxtcount;	    /* Number of contexts appended to section */
+	unsigned char release[32];  /* kernel release */
+	unsigned char version[32];  /* kernel version */
+	unsigned char comm[16];	    /* Name of the process that owns the PT */
+} __packed;
+
+/*
+ * This structure contains a record of an active context.
+ * These are appended one after another in the OS section below
+ * the header above
+ */
+
+struct kgsl_snapshot_linux_context {
+	__u32 id;			/* The context ID */
+	__u32 timestamp_queued;		/* The last queued timestamp */
+	__u32 timestamp_retired;	/* The last timestamp retired by HW */
+};
+
+/* Ringbuffer sub-section header */
+struct kgsl_snapshot_rb {
+	int start;  /* dword at the start of the dump */
+	int end;    /* dword at the end of the dump */
+	int rbsize; /* Size (in dwords) of the ringbuffer */
+	int wptr;   /* Current index of the CPU write pointer */
+	int rptr;   /* Current index of the GPU read pointer */
+	int count;  /* Number of dwords in the dump */
+} __packed;
+
+/* Indirect buffer sub-section header */
+struct kgsl_snapshot_ib {
+	__u32 gpuaddr; /* GPU address of the the IB */
+	__u32 ptbase;  /* Base for the pagetable the GPU address is valid in */
+	int size;    /* Size of the IB */
+} __packed;
+
+/* Register sub-section header */
+struct kgsl_snapshot_regs {
+	__u32 count; /* Number of register pairs in the section */
+} __packed;
+
+/* Indexed register sub-section header */
+struct kgsl_snapshot_indexed_regs {
+	__u32 index_reg; /* Offset of the index register for this section */
+	__u32 data_reg;  /* Offset of the data register for this section */
+	int start;     /* Starting index */
+	int count;     /* Number of dwords in the data */
+} __packed;
+
+/* Istore sub-section header */
+struct kgsl_snapshot_istore {
+	int count;   /* Number of instructions in the istore */
+} __packed;
+
+/* Debug data sub-section header */
+
+#define SNAPSHOT_DEBUG_SX         1
+#define SNAPSHOT_DEBUG_CP         2
+#define SNAPSHOT_DEBUG_SQ         3
+#define SNAPSHOT_DEBUG_SQTHREAD   4
+#define SNAPSHOT_DEBUG_MIU        5
+
+struct kgsl_snapshot_debug {
+	int type;    /* Type identifier for the attached tata */
+	int size;   /* Size of the section in bytes */
+} __packed;
+
+#ifdef __KERNEL__
+
+/* Allocate 512K for each device snapshot */
+#define KGSL_SNAPSHOT_MEMSIZE (512 * 1024)
+
+struct kgsl_device;
+/*
+ * A helper macro to print out "not enough memory functions" - this
+ * makes it easy to standardize the messages as well as cut down on
+ * the number of strings in the binary
+ */
+
+#define SNAPSHOT_ERR_NOMEM(_d, _s) \
+	KGSL_DRV_ERR((_d), \
+	"snapshot: not enough snapshot memory for section %s\n", (_s))
+
+/*
+ * kgsl_snapshot_add_section - Add a new section to the GPU snapshot
+ * @device - the KGSL device being snapshotted
+ * @id - the section id
+ * @snapshot - pointer to the memory for the snapshot
+ * @remain - pointer to the number of bytes left in the snapshot region
+ * @func - Function pointer to fill the section
+ * @priv - Priv pointer to pass to the function
+ *
+ * Set up a KGSL snapshot header by filling the memory with the callback
+ * function and adding the standard section header
+ */
+
+static inline void *kgsl_snapshot_add_section(struct kgsl_device *device,
+	u16 id, void *snapshot, int *remain,
+	int (*func)(struct kgsl_device *, void *, int, void *), void *priv)
+{
+	struct kgsl_snapshot_section_header *header = snapshot;
+	void *data = snapshot + sizeof(*header);
+	int ret = 0;
+
+	/*
+	 * Sanity check to make sure there is enough for the header.  The
+	 * callback will check to make sure there is enough for the rest
+	 * of the data.  If there isn't enough room then don't advance the
+	 * pointer.
+	 */
+
+	if (*remain < sizeof(*header))
+		return snapshot;
+
+	/* It is legal to have no function (i.e. - make an empty section) */
+
+	if (func) {
+		ret = func(device, data, *remain, priv);
+
+		/*
+		 * If there wasn't enough room for the data then don't bother
+		 * setting up the header.
+		 */
+
+		if (ret == 0)
+			return snapshot;
+	}
+
+	header->magic = SNAPSHOT_SECTION_MAGIC;
+	header->id = id;
+	header->size = ret + sizeof(*header);
+
+	/* Decrement the room left in the snapshot region */
+	*remain -= header->size;
+	/* Advance the pointer to the end of the next function */
+	return snapshot + header->size;
+}
+
+/* A common helper function to dump a range of registers.  This will be used in
+ * the GPU specific devices like this:
+ *
+ * struct kgsl_snapshot_registers priv;
+ * priv.regs = registers_array;;
+ * priv.count = num_registers;
+ *
+ * kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS, snapshot,
+ *	remain, kgsl_snapshot_dump_regs, &priv).
+ *
+ * Pass in an array of register range pairs in the form of:
+ * start reg, stop reg
+ * All the registers between start and stop inclusive will be dumped
+ */
+
+struct kgsl_snapshot_registers {
+	unsigned int *regs;  /* Pointer to the array of register ranges */
+	int count;	     /* Number of entries in the array */
+};
+
+int kgsl_snapshot_dump_regs(struct kgsl_device *device, void *snapshot,
+	int remain, void *priv);
+
+/*
+ * A common helper function to dump a set of indexed registers. Use it
+ * like this:
+ *
+ * struct kgsl_snapshot_indexed_registers priv;
+ * priv.index = REG_INDEX;
+ * priv.data = REG_DATA;
+ * priv.count = num_registers
+ *
+ * kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_INDEXED_REGS,
+ *	snapshot, remain, kgsl_snapshot_dump_indexed_regs, &priv).
+ *
+ * The callback function will write an index from 0 to priv.count to
+ * the index register and read the data from the data register.
+ */
+
+struct kgsl_snapshot_indexed_registers {
+	unsigned int index; /* Offset of the index register */
+	unsigned int data;  /* Offset of the data register */
+	unsigned int start;	/* Index to start with */
+	unsigned int count; /* Number of values to read from the pair */
+};
+
+int kgsl_snapshot_dump_indexed_regs(struct kgsl_device *device,
+	void *snapshot, int remain, void *priv);
+
+#endif
+#endif
diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c
index ac76cde..fa6f4d9 100644
--- a/drivers/input/touchscreen/tsc2007.c
+++ b/drivers/input/touchscreen/tsc2007.c
@@ -81,6 +81,10 @@
 	u16			max_rt;
 	unsigned long		poll_delay;
 	unsigned long		poll_period;
+	u16			min_x;
+	u16			max_x;
+	u16			min_y;
+	u16			max_y;
 
 	bool			pendown;
 	int			irq;
@@ -396,6 +400,10 @@
 	ts->invert_y	      = pdata->invert_y;
 	ts->invert_z1	      = pdata->invert_z1;
 	ts->invert_z2	      = pdata->invert_z2;
+	ts->min_x	      = pdata->min_x ? pdata->min_x : 0;
+	ts->max_x	      = pdata->max_x ? pdata->max_x : MAX_12BIT;
+	ts->min_y	      = pdata->min_y ? pdata->min_y : 0;
+	ts->max_y	      = pdata->max_y ? pdata->max_y : MAX_12BIT;
 	ts->power_shutdown    = pdata->power_shutdown;
 
 	snprintf(ts->phys, sizeof(ts->phys),
@@ -408,8 +416,10 @@
 	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
 	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
 
-	input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, pdata->fuzzx, 0);
-	input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, pdata->fuzzy, 0);
+	input_set_abs_params(input_dev, ABS_X, ts->min_x,
+				ts->max_x, pdata->fuzzx, 0);
+	input_set_abs_params(input_dev, ABS_Y, ts->min_y,
+				ts->max_y, pdata->fuzzy, 0);
 	input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT,
 			pdata->fuzzz, 0);
 
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
index aa0e392..b1dc87e 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -62,7 +62,7 @@
 	  Omni Vision VGA YUV Sensor.
 config WEBCAM_OV9726
 	bool "Sensor OV9726 (VGA Bayer)"
-	depends on MSM_CAMERA && (ARCH_MSM8X60 || ARCH_MSM7X30 || ARCH_MSM7X27A) && !MSM_CAMERA_V4L2
+	depends on MSM_CAMERA && (ARCH_MSM8X60 || ARCH_MSM7X30 || ARCH_MSM7X27A)
 	default n
 	---help---
 	  Omni Vision VGA Bayer Sensor.
@@ -113,7 +113,7 @@
 
 config MT9E013
 	bool "Sensor mt9e013 module (BAYER 8M)"
-	depends on MSM_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60 || ARCH_MSM7X27A) && !MSM_CAMERA_V4L2
+	depends on MSM_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60 || ARCH_MSM7X27A)
 	default n
 	---help---
 	  Aptina 8M Bayer Sensor modules with Autofocus
@@ -149,6 +149,13 @@
 	  two mipi lanes, required for msm7x2xA platform.
 	  Say Y here if this is msm7x2xA variant platform.
 
+config DW9712_ACT
+	bool "Lens actuator dw9721"
+	depends on MSM_CAMERA && S5K4E1
+	---help---
+	  dw9721 lens actuator driver for S5K4E1.
+	  Say Y here if this is msm7627A variant platform.
+
 config MSM_CAMERA_FLASH_SC628A
 	bool "Qualcomm MSM camera sc628a flash support"
 	depends on MSM_CAMERA
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 5454763..b91449a 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -15,7 +15,11 @@
 obj-$(CONFIG_MSM_CAMERA) += msm_axi_qos.o gemini/
 obj-$(CONFIG_MSM_CAMERA_FLASH) += flash.o
 obj-$(CONFIG_ARCH_MSM_ARM11) += msm_vfe7x.o msm_io7x.o
-obj-$(CONFIG_ARCH_MSM7X27A) += msm_vfe7x27a.o msm_io_7x27a.o
+ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
+  obj-$(CONFIG_ARCH_MSM7X27A) += msm_vfe7x27a_v4l2.o msm_io_7x27a_v4l2.o
+else
+  obj-$(CONFIG_ARCH_MSM7X27A) += msm_vfe7x27a.o msm_io_7x27a.o
+endif
 obj-$(CONFIG_ARCH_MSM7X30) += msm_vfe31.o msm_io_vfe31.o msm_vpe1.o
 obj-$(CONFIG_ARCH_QSD8X50) += msm_vfe8x.o msm_vfe8x_proc.o msm_io8x.o
 obj-$(CONFIG_ARCH_MSM8X60) += msm_vfe31.o msm_io_8x60.o msm_vpe1.o
@@ -26,20 +30,20 @@
 obj-$(CONFIG_MSM_CAMERA_AF_FOXCONN) += mt9p012_fox.o
 obj-$(CONFIG_MSM_CAMERA_AF_BAM) += mt9p012_bam.o
 obj-$(CONFIG_MT9P012_KM) += mt9p012_km.o mt9p012_km_reg.o
-obj-$(CONFIG_MT9E013) += mt9e013.o mt9e013_reg.o
 obj-$(CONFIG_S5K3E2FX) += s5k3e2fx.o
-obj-$(CONFIG_S5K4E1) += s5k4e1.o s5k4e1_reg.o
 #FIXME: Merge the two ifeq causes VX6953 preview not coming up.
 ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
   obj-$(CONFIG_VX6953) += vx6953_v4l2.o vx6953_reg_v4l2.o
 else
   obj-$(CONFIG_VX6953) += vx6953.o vx6953_reg.o
   obj-$(CONFIG_IMX074) += imx074.o imx074_reg.o
+  obj-$(CONFIG_MT9E013) += mt9e013.o mt9e013_reg.o
+  obj-$(CONFIG_WEBCAM_OV9726) += ov9726.o ov9726_reg.o
+  obj-$(CONFIG_S5K4E1) += s5k4e1.o s5k4e1_reg.o
 endif
 obj-$(CONFIG_QS_S5K4E1) += qs_s5k4e1.o qs_s5k4e1_reg.o
 obj-$(CONFIG_VB6801) += vb6801.o
 obj-$(CONFIG_IMX072) += imx072.o imx072_reg.o
-obj-$(CONFIG_WEBCAM_OV9726) += ov9726.o ov9726_reg.o
 obj-$(CONFIG_WEBCAM_OV7692) += ov7692.o
 obj-$(CONFIG_WEBCAM_OV7692_QRD) += ov7692_qrd.o
 obj-$(CONFIG_OV5640) += ov5640.o
diff --git a/drivers/media/video/msm/actuators/Makefile b/drivers/media/video/msm/actuators/Makefile
index 4f4d5ee..f0a0c69 100644
--- a/drivers/media/video/msm/actuators/Makefile
+++ b/drivers/media/video/msm/actuators/Makefile
@@ -3,3 +3,4 @@
 EXTRA_CFLAGS += -Idrivers/media/video/msm/io
 obj-$(CONFIG_MSM_ACTUATOR) += msm_actuator.o
 obj-$(CONFIG_IMX074_ACT) += imx074_act.o
+obj-$(CONFIG_DW9712_ACT) += dw9712_act.o
diff --git a/drivers/media/video/msm/actuators/dw9712_act.c b/drivers/media/video/msm/actuators/dw9712_act.c
new file mode 100644
index 0000000..562290f
--- /dev/null
+++ b/drivers/media/video/msm/actuators/dw9712_act.c
@@ -0,0 +1,277 @@
+/* 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 "msm_actuator.h"
+#include "msm_camera_i2c.h"
+
+#define	DW9712_TOTAL_STEPS_NEAR_TO_FAR			32
+DEFINE_MUTEX(dw9712_act_mutex);
+static struct msm_actuator_ctrl_t dw9712_act_t;
+
+static struct region_params_t g_regions[] = {
+	/* step_bound[0] - macro side boundary
+	 * step_bound[1] - infinity side boundary
+	 */
+	/* Region 1 */
+	{
+		.step_bound = {DW9712_TOTAL_STEPS_NEAR_TO_FAR, 0},
+		.code_per_step = 2,
+	},
+};
+
+static uint16_t g_scenario[] = {
+	/* MOVE_NEAR and MOVE_FAR dir*/
+	DW9712_TOTAL_STEPS_NEAR_TO_FAR,
+};
+
+static int32_t dw9712_af_i2c_txdata(unsigned short saddr,
+				unsigned char *txdata, int length,
+				struct msm_actuator_ctrl_t *a_ctrl)
+{
+	struct i2c_msg msg[] = {
+		{
+			.addr = saddr,
+			.flags = 0,
+			.len = length,
+			.buf = txdata,
+		},
+	};
+	if (i2c_transfer(a_ctrl->i2c_client.client->adapter, msg, 1) < 0) {
+		pr_err("s5k4e1_af_i2c_txdata faild 0x%x\n", saddr);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int32_t dw9712_af_i2c_write_b_sensor(struct msm_actuator_ctrl_t *a_ctrl,
+			      uint8_t waddr, uint8_t bdata)
+{
+	int32_t rc = -EFAULT;
+	unsigned char buf[2];
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = waddr;
+	buf[1] = bdata;
+	rc = dw9712_af_i2c_txdata(a_ctrl->i2c_addr, buf, 2, a_ctrl);
+	if (rc < 0) {
+		pr_err("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+				waddr, bdata);
+	}
+	return rc;
+}
+
+static int32_t dw9712_wrapper_i2c_write(struct msm_actuator_ctrl_t *a_ctrl,
+	int16_t next_lens_position, void *params)
+{
+	uint8_t msb, lsb;
+
+	msb = (next_lens_position & 0xFF00) >> 8;
+	lsb = next_lens_position & 0xFF;
+	dw9712_af_i2c_write_b_sensor(a_ctrl, msb, lsb);
+
+	return 0;
+}
+
+int32_t msm_dw9712_act_move_focus(
+	struct msm_actuator_ctrl_t *a_ctrl,
+	int dir,
+	int32_t num_steps)
+{
+	int32_t rc = 0;
+	int8_t sign_dir = 0;
+	int16_t dest_step_pos = 0;
+	uint8_t code_val_msb, code_val_lsb;
+	uint16_t code_val;
+
+	LINFO("%s called, dir %d, num_steps %d\n",
+		__func__,
+		dir,
+		num_steps);
+
+	/* Determine sign direction */
+	if (dir == MOVE_NEAR)
+		sign_dir = 1;
+	else if (dir == MOVE_FAR)
+		sign_dir = -1;
+	else {
+		pr_err("Illegal focus direction\n");
+		rc = -EINVAL;
+		return rc;
+	}
+
+	/* Determine destination step position */
+	dest_step_pos = a_ctrl->curr_step_pos +
+		(sign_dir * num_steps);
+
+	if (dest_step_pos < 0)
+		dest_step_pos = 0;
+	else if (dest_step_pos > 1023)
+		dest_step_pos = 1023;
+
+	if (dest_step_pos == a_ctrl->curr_step_pos)
+		return rc;
+
+	code_val_msb = dest_step_pos >> 4;
+	code_val_lsb = (dest_step_pos & 0x000F) << 4;
+	code_val = (code_val_msb << 8) | (code_val_lsb);
+	rc = dw9712_wrapper_i2c_write(a_ctrl, code_val, NULL);
+	if (rc >= 0) {
+		rc = 0;
+		a_ctrl->curr_step_pos = dest_step_pos;
+	}
+	return 0;
+}
+
+static int32_t dw9712_set_default_focus(
+	struct msm_actuator_ctrl_t *a_ctrl)
+{
+	int32_t rc = 0;
+
+	if (!a_ctrl->step_position_table)
+		a_ctrl->func_tbl.actuator_init_table(a_ctrl);
+
+	if (a_ctrl->curr_step_pos != 0) {
+		rc = a_ctrl->func_tbl.actuator_move_focus(a_ctrl,
+				MOVE_FAR, a_ctrl->curr_step_pos);
+		a_ctrl->curr_step_pos = 0;
+	} else
+		rc = dw9712_wrapper_i2c_write(a_ctrl, 0x00, NULL);
+		if (rc >= 0)
+			rc = 0;
+	return rc;
+}
+
+static const struct i2c_device_id dw9712_act_i2c_id[] = {
+	{"dw9712_act", (kernel_ulong_t)&dw9712_act_t},
+	{ }
+};
+
+static int dw9712_act_config(void __user *argp)
+{
+	LINFO("%s called\n", __func__);
+	return (int) msm_actuator_config(&dw9712_act_t, argp);
+}
+
+static int dw9712_i2c_add_driver_table(void)
+{
+	LINFO("%s called\n", __func__);
+	return (int) msm_actuator_init_table(&dw9712_act_t);
+}
+
+static struct i2c_driver dw9712_act_i2c_driver = {
+	.id_table = dw9712_act_i2c_id,
+	.probe  = msm_actuator_i2c_probe,
+	.remove = __exit_p(dw9712_act_i2c_remove),
+	.driver = {
+		.name = "dw9712_act",
+	},
+};
+
+static int __init dw9712_i2c_add_driver(void)
+{
+	int rc = 0;
+
+	LINFO("%s called :%x\n", __func__, dw9712_act_t.i2c_addr);
+	rc = i2c_add_driver(dw9712_act_t.i2c_driver);
+	LINFO("%s called:%d %x\n", __func__, rc, dw9712_act_t.i2c_addr);
+	return rc;
+}
+
+static struct v4l2_subdev_core_ops dw9712_act_subdev_core_ops;
+
+static struct v4l2_subdev_ops dw9712_act_subdev_ops = {
+	.core = &dw9712_act_subdev_core_ops,
+};
+
+static int32_t dw9712_act_create_subdevice(
+	void *board_info,
+	void *sdev)
+{
+	int rc = 0;
+
+	struct msm_actuator_info *ptr;
+	LINFO("%s called\n", __func__);
+
+	ptr = board_info;
+	dw9712_act_t.vcm_pwd = ptr->vcm_pwd;
+	dw9712_act_t.vcm_enable = ptr->vcm_enable;
+	LINFO("vcm info: %x %x\n", dw9712_act_t.vcm_pwd,
+				dw9712_act_t.vcm_enable);
+	if (dw9712_act_t.vcm_enable) {
+		rc = gpio_request(dw9712_act_t.vcm_pwd, "dw9712_af");
+		if (!rc) {
+			LINFO("Enable VCM PWD\n");
+			gpio_direction_output(dw9712_act_t.vcm_pwd, 1);
+		}
+	}
+	return (int) msm_actuator_create_subdevice(&dw9712_act_t,
+		ptr->board_info,
+		(struct v4l2_subdev *)sdev);
+}
+
+static struct msm_actuator_ctrl_t dw9712_act_t = {
+	.i2c_driver = &dw9712_act_i2c_driver,
+	.i2c_addr = 0x8C,
+	.act_v4l2_subdev_ops = &dw9712_act_subdev_ops,
+	.actuator_ext_ctrl = {
+		.a_init_table = dw9712_i2c_add_driver_table,
+		.a_create_subdevice = dw9712_act_create_subdevice,
+		.a_config = dw9712_act_config,
+	},
+
+	.i2c_client = {
+		.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+	},
+
+	.set_info = {
+		.total_steps = DW9712_TOTAL_STEPS_NEAR_TO_FAR,
+	},
+
+	.curr_step_pos = 0,
+	.curr_region_index = 0,
+	.initial_code = 0x0,
+	.actuator_mutex = &dw9712_act_mutex,
+
+	.func_tbl = {
+		.actuator_init_table = msm_actuator_init_table,
+		.actuator_move_focus = msm_dw9712_act_move_focus,
+		.actuator_set_default_focus = dw9712_set_default_focus,
+		.actuator_i2c_write = dw9712_wrapper_i2c_write,
+	},
+
+	.get_info = {
+		.focal_length_num = 46,
+		.focal_length_den = 10,
+		.f_number_num = 265,
+		.f_number_den = 100,
+		.f_pix_num = 14,
+		.f_pix_den = 10,
+		.total_f_dist_num = 197681,
+		.total_f_dist_den = 1000,
+	},
+
+	/* Initialize scenario */
+	.ringing_scenario[MOVE_NEAR] = g_scenario,
+	.scenario_size[MOVE_NEAR] = ARRAY_SIZE(g_scenario),
+	.ringing_scenario[MOVE_FAR] = g_scenario,
+	.scenario_size[MOVE_FAR] = ARRAY_SIZE(g_scenario),
+
+	/* Initialize region params */
+	.region_params = g_regions,
+	.region_size = ARRAY_SIZE(g_regions),
+};
+
+subsys_initcall(dw9712_i2c_add_driver);
+MODULE_DESCRIPTION("DW9712 actuator");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/actuators/imx074_act.c b/drivers/media/video/msm/actuators/imx074_act.c
index e01d2c7..e4d340d4 100644
--- a/drivers/media/video/msm/actuators/imx074_act.c
+++ b/drivers/media/video/msm/actuators/imx074_act.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
@@ -186,13 +186,14 @@
 };
 
 static int32_t imx074_act_create_subdevice(
-	void *board_info,
+	void *act_info,
 	void *sdev)
 {
+	struct msm_actuator_info *info = (struct msm_actuator_info *)act_info;
 	LINFO("%s called\n", __func__);
 
 	return (int) msm_actuator_create_subdevice(&imx074_act_t,
-		(struct i2c_board_info const *)board_info,
+		(struct i2c_board_info const *)info->board_info,
 		(struct v4l2_subdev *)sdev);
 }
 
diff --git a/drivers/media/video/msm/actuators/msm_actuator.h b/drivers/media/video/msm/actuators/msm_actuator.h
index 6fad8dd..9c90282 100644
--- a/drivers/media/video/msm/actuators/msm_actuator.h
+++ b/drivers/media/video/msm/actuators/msm_actuator.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -14,6 +14,7 @@
 
 #include <linux/i2c.h>
 #include <mach/camera.h>
+#include <mach/gpio.h>
 #include <media/v4l2-subdev.h>
 #include <media/msm_camera.h>
 #include "msm_camera_i2c.h"
@@ -100,6 +101,8 @@
 	uint16_t region_size;
 	struct damping_t *damping[2];
 	void *user_data;
+	uint32_t vcm_pwd;
+	uint32_t vcm_enable;
 };
 
 int32_t msm_actuator_i2c_write_b_af(struct msm_actuator_ctrl_t *a_ctrl,
diff --git a/drivers/media/video/msm/csi/Makefile b/drivers/media/video/msm/csi/Makefile
index 3ce81af..6e8eb122 100644
--- a/drivers/media/video/msm/csi/Makefile
+++ b/drivers/media/video/msm/csi/Makefile
@@ -1,3 +1,4 @@
 GCC_VERSION      := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
 EXTRA_CFLAGS += -Idrivers/media/video/msm
 obj-$(CONFIG_ARCH_MSM8960) += msm_csiphy.o msm_csid.o msm_ispif.o
+obj-$(CONFIG_ARCH_MSM7X27A) += msm_csic.o
diff --git a/drivers/media/video/msm/csi/msm_csic.c b/drivers/media/video/msm/csi/msm_csic.c
new file mode 100644
index 0000000..476615d
--- /dev/null
+++ b/drivers/media/video/msm/csi/msm_csic.c
@@ -0,0 +1,430 @@
+/* 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/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <mach/board.h>
+#include <mach/camera.h>
+#include <media/msm_isp.h>
+#include "msm_csic.h"
+#include "msm.h"
+
+#define DBG_CSIC 0
+
+#define V4L2_IDENT_CSIC			50004
+/* MIPI	CSI controller registers */
+#define	MIPI_PHY_CONTROL		0x00000000
+#define	MIPI_PROTOCOL_CONTROL		0x00000004
+#define	MIPI_INTERRUPT_STATUS		0x00000008
+#define	MIPI_INTERRUPT_MASK		0x0000000C
+#define	MIPI_CAMERA_CNTL		0x00000024
+#define	MIPI_CALIBRATION_CONTROL	0x00000018
+#define	MIPI_PHY_D0_CONTROL2		0x00000038
+#define	MIPI_PHY_D1_CONTROL2		0x0000003C
+#define	MIPI_PHY_D2_CONTROL2		0x00000040
+#define	MIPI_PHY_D3_CONTROL2		0x00000044
+#define	MIPI_PHY_CL_CONTROL		0x00000048
+#define	MIPI_PHY_D0_CONTROL		0x00000034
+#define	MIPI_PHY_D1_CONTROL		0x00000020
+#define	MIPI_PHY_D2_CONTROL		0x0000002C
+#define	MIPI_PHY_D3_CONTROL		0x00000030
+#define	MIPI_PWR_CNTL			0x00000054
+
+/*
+ * MIPI_PROTOCOL_CONTROL register bits to enable/disable the features of
+ * CSI Rx Block
+ */
+
+/* DPCM scheme */
+#define	MIPI_PROTOCOL_CONTROL_DPCM_SCHEME_SHFT			0x1e
+/* SW_RST to issue a SW reset to the CSI core */
+#define	MIPI_PROTOCOL_CONTROL_SW_RST_BMSK			0x8000000
+/* To Capture Long packet Header Info in MIPI_PROTOCOL_STATUS register */
+#define	MIPI_PROTOCOL_CONTROL_LONG_PACKET_HEADER_CAPTURE_BMSK	0x200000
+/* Data format for unpacking purpose */
+#define	MIPI_PROTOCOL_CONTROL_DATA_FORMAT_SHFT			0x13
+/* Enable decoding of payload based on data type filed of packet hdr */
+#define	MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK			0x00000
+/* Enable error correction on packet headers */
+#define	MIPI_PROTOCOL_CONTROL_ECC_EN_BMSK			0x20000
+
+/*
+ * MIPI_CALIBRATION_CONTROL register contains control info for
+ * calibration impledence controller
+*/
+
+/* Enable bit for calibration pad */
+#define	MIPI_CALIBRATION_CONTROL_SWCAL_CAL_EN_SHFT		0x16
+/* With SWCAL_STRENGTH_OVERRIDE_EN, SW_CAL_EN and MANUAL_OVERRIDE_EN
+ * the hardware calibration circuitry associated with CAL_SW_HW_MODE
+ * is bypassed
+*/
+#define	MIPI_CALIBRATION_CONTROL_SWCAL_STRENGTH_OVERRIDE_EN_SHFT	0x15
+/* To indicate the Calibration process is in the control of HW/SW */
+#define	MIPI_CALIBRATION_CONTROL_CAL_SW_HW_MODE_SHFT		0x14
+/* When this is set the strength value of the data and clk lane impedence
+ * termination is updated with MANUAL_STRENGTH settings and calibration
+ * sensing logic is idle.
+*/
+#define	MIPI_CALIBRATION_CONTROL_MANUAL_OVERRIDE_EN_SHFT	0x7
+
+/* Data lane0 control */
+/* T-hs Settle count value  for Rx */
+#define	MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT			0x18
+/* Rx termination control */
+#define	MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT			0x10
+/* LP Rx enable */
+#define	MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT			0x4
+/*
+ * Enable for error in sync sequence
+ * 1 - one bit error in sync seq
+ * 0 - requires all 8 bit correct seq
+*/
+#define	MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT			0x3
+
+/* Comments are same as D0 */
+#define	MIPI_PHY_D1_CONTROL2_SETTLE_COUNT_SHFT			0x18
+#define	MIPI_PHY_D1_CONTROL2_HS_TERM_IMP_SHFT			0x10
+#define	MIPI_PHY_D1_CONTROL2_LP_REC_EN_SHFT			0x4
+#define	MIPI_PHY_D1_CONTROL2_ERR_SOT_HS_EN_SHFT			0x3
+
+/* Comments are same as D0 */
+#define	MIPI_PHY_D2_CONTROL2_SETTLE_COUNT_SHFT			0x18
+#define	MIPI_PHY_D2_CONTROL2_HS_TERM_IMP_SHFT			0x10
+#define	MIPI_PHY_D2_CONTROL2_LP_REC_EN_SHFT			0x4
+#define	MIPI_PHY_D2_CONTROL2_ERR_SOT_HS_EN_SHFT			0x3
+
+/* Comments are same as D0 */
+#define	MIPI_PHY_D3_CONTROL2_SETTLE_COUNT_SHFT			0x18
+#define	MIPI_PHY_D3_CONTROL2_HS_TERM_IMP_SHFT			0x10
+#define	MIPI_PHY_D3_CONTROL2_LP_REC_EN_SHFT			0x4
+#define	MIPI_PHY_D3_CONTROL2_ERR_SOT_HS_EN_SHFT			0x3
+
+/* PHY_CL_CTRL programs the parameters of clk lane of CSIRXPHY */
+/* HS Rx termination control */
+#define	MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT			0x18
+/* Start signal for T-hs delay */
+#define	MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT			0x2
+
+/* PHY DATA lane 0 control */
+/*
+ * HS RX equalizer strength control
+ * 00 - 0db 01 - 3db 10 - 5db 11 - 7db
+*/
+#define	MIPI_PHY_D0_CONTROL_HS_REC_EQ_SHFT			0x1c
+/* PHY DATA lane 1 control */
+/* Shutdown signal for MIPI clk phy line */
+#define	MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT		0x9
+/* Shutdown signal for MIPI data phy line */
+#define	MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT	0x8
+
+#define MSM_AXI_QOS_PREVIEW 200000
+#define MSM_AXI_QOS_SNAPSHOT 200000
+#define MSM_AXI_QOS_RECORDING 200000
+
+#define MIPI_PWR_CNTL_ENA	0x07
+#define MIPI_PWR_CNTL_DIS	0x0
+
+static int msm_csic_config(struct csic_cfg_params *cfg_params)
+{
+	int rc = 0;
+	uint32_t val = 0;
+	struct csic_device *csic_dev;
+	struct msm_camera_csi_params *csic_params;
+	void __iomem *csicbase;
+
+	csic_dev = v4l2_get_subdevdata(cfg_params->subdev);
+	csicbase = csic_dev->base;
+	csic_params = cfg_params->parms;
+
+	/* Enable error correction for DATA lane. Applies to all data lanes */
+	msm_io_w(0x4, csicbase + MIPI_PHY_CONTROL);
+
+	msm_io_w(MIPI_PROTOCOL_CONTROL_SW_RST_BMSK,
+		csicbase + MIPI_PROTOCOL_CONTROL);
+
+	val = MIPI_PROTOCOL_CONTROL_LONG_PACKET_HEADER_CAPTURE_BMSK |
+		MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK |
+		MIPI_PROTOCOL_CONTROL_ECC_EN_BMSK;
+	val |= (uint32_t)(csic_params->data_format) <<
+		MIPI_PROTOCOL_CONTROL_DATA_FORMAT_SHFT;
+	val |= csic_params->dpcm_scheme <<
+		MIPI_PROTOCOL_CONTROL_DPCM_SCHEME_SHFT;
+	CDBG("%s MIPI_PROTOCOL_CONTROL val=0x%x\n", __func__, val);
+	msm_io_w(val, csicbase + MIPI_PROTOCOL_CONTROL);
+
+	val = (0x1 << MIPI_CALIBRATION_CONTROL_SWCAL_CAL_EN_SHFT) |
+		(0x1 <<
+		MIPI_CALIBRATION_CONTROL_SWCAL_STRENGTH_OVERRIDE_EN_SHFT) |
+		(0x1 << MIPI_CALIBRATION_CONTROL_CAL_SW_HW_MODE_SHFT) |
+		(0x1 << MIPI_CALIBRATION_CONTROL_MANUAL_OVERRIDE_EN_SHFT);
+	CDBG("%s MIPI_CALIBRATION_CONTROL val=0x%x\n", __func__, val);
+	msm_io_w(val, csicbase + MIPI_CALIBRATION_CONTROL);
+
+	val = (csic_params->settle_cnt <<
+		MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) |
+		(0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) |
+		(0x1 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) |
+		(0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT);
+	CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
+	msm_io_w(val, csicbase + MIPI_PHY_D0_CONTROL2);
+	msm_io_w(val, csicbase + MIPI_PHY_D1_CONTROL2);
+	msm_io_w(val, csicbase + MIPI_PHY_D2_CONTROL2);
+	msm_io_w(val, csicbase + MIPI_PHY_D3_CONTROL2);
+
+
+	val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) |
+		(0x1 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT);
+	CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
+	msm_io_w(val, csicbase + MIPI_PHY_CL_CONTROL);
+
+	val = 0 << MIPI_PHY_D0_CONTROL_HS_REC_EQ_SHFT;
+	msm_io_w(val, csicbase + MIPI_PHY_D0_CONTROL);
+
+	val = (0x1 << MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT) |
+		(0x1 << MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT);
+	CDBG("%s MIPI_PHY_D1_CONTROL val=0x%x\n", __func__, val);
+	msm_io_w(val, csicbase + MIPI_PHY_D1_CONTROL);
+
+	msm_io_w(0x00000000, csicbase + MIPI_PHY_D2_CONTROL);
+	msm_io_w(0x00000000, csicbase + MIPI_PHY_D3_CONTROL);
+
+	/* program number of lanes and lane mapping */
+	switch (csic_params->lane_cnt) {
+	case 1:
+		msm_io_w(csic_params->lane_assign << 8 | 0x4,
+			csicbase + MIPI_CAMERA_CNTL);
+		break;
+	case 2:
+		msm_io_w(csic_params->lane_assign << 8 | 0x5,
+			csicbase + MIPI_CAMERA_CNTL);
+		break;
+	case 3:
+		msm_io_w(csic_params->lane_assign << 8 | 0x6,
+			csicbase + MIPI_CAMERA_CNTL);
+		break;
+	case 4:
+		msm_io_w(csic_params->lane_assign << 8 | 0x7,
+			csicbase + MIPI_CAMERA_CNTL);
+		break;
+	}
+
+	msm_io_w(0xFFFFF3FF, csicbase + MIPI_INTERRUPT_MASK);
+	/*clear IRQ bits - write 1 clears the status*/
+	msm_io_w(0xFFFFF3FF, csicbase + MIPI_INTERRUPT_STATUS);
+
+	return rc;
+}
+
+static irqreturn_t msm_csic_irq(int irq_num, void *data)
+{
+	uint32_t irq;
+	struct csic_device *csic_dev = data;
+
+	pr_info("msm_csic_irq: %x\n", (unsigned int)csic_dev->base);
+	irq = msm_io_r(csic_dev->base + MIPI_INTERRUPT_STATUS);
+	pr_info("%s MIPI_INTERRUPT_STATUS = 0x%x\n", __func__, irq);
+	msm_io_w(irq, csic_dev->base + MIPI_INTERRUPT_STATUS);
+
+	/* TODO: Needs to send this info to upper layers */
+	if ((irq >> 19) & 0x1)
+		pr_info("Unsupported packet format is received\n");
+	return IRQ_HANDLED;
+}
+
+static int msm_csic_subdev_g_chip_ident(struct v4l2_subdev *sd,
+			struct v4l2_dbg_chip_ident *chip)
+{
+	BUG_ON(!chip);
+	chip->ident = V4L2_IDENT_CSIC;
+	chip->revision = 0;
+	return 0;
+}
+
+static struct msm_cam_clk_info csic_clk_info[] = {
+	{"csi_clk", 400000000},
+	{"csi_vfe_clk", -1},
+	{"csi_pclk", -1},
+};
+
+static int msm_csic_init(struct v4l2_subdev *sd, uint32_t *csic_version)
+{
+	int rc = 0;
+	struct csic_device *csic_dev;
+	csic_dev = v4l2_get_subdevdata(sd);
+	if (csic_dev == NULL) {
+		rc = -ENOMEM;
+		return rc;
+	}
+
+	csic_dev->base = ioremap(csic_dev->mem->start,
+		resource_size(csic_dev->mem));
+	if (!csic_dev->base) {
+		rc = -ENOMEM;
+		return rc;
+	}
+
+	pr_info("msm_cam_clk_enable: enable csi_pclk, csi_clk, csi_vfe_clk\n");
+	rc = msm_cam_clk_enable(&csic_dev->pdev->dev, csic_clk_info,
+		csic_dev->csic_clk, ARRAY_SIZE(csic_clk_info), 1);
+	if (rc < 0) {
+		iounmap(csic_dev->base);
+		return rc;
+	}
+
+#if DBG_CSIC
+	enable_irq(csic_dev->irq->start);
+#endif
+
+	return 0;
+}
+
+static int msm_csic_release(struct v4l2_subdev *sd)
+{
+	struct csic_device *csic_dev;
+	csic_dev = v4l2_get_subdevdata(sd);
+
+#if DBG_CSIC
+	disable_irq(csic_dev->irq->start);
+#endif
+
+	pr_info("msm_cam_clk_enable: disble csi_pclk, csi_clk, csi_vfe_clk\n");
+	msm_cam_clk_enable(&csic_dev->pdev->dev, csic_clk_info,
+		csic_dev->csic_clk, ARRAY_SIZE(csic_clk_info), 0);
+
+	iounmap(csic_dev->base);
+	return 0;
+}
+
+static long msm_csic_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int cmd, void *arg)
+{
+	struct csic_cfg_params cfg_params;
+	switch (cmd) {
+	case VIDIOC_MSM_CSIC_CFG:
+		cfg_params.subdev = sd;
+		cfg_params.parms = arg;
+		return msm_csic_config((struct csic_cfg_params *)&cfg_params);
+	case VIDIOC_MSM_CSIC_INIT:
+		return msm_csic_init(sd, (uint32_t *)arg);
+	case VIDIOC_MSM_CSIC_RELEASE:
+		return msm_csic_release(sd);
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+
+static struct v4l2_subdev_core_ops msm_csic_subdev_core_ops = {
+	.g_chip_ident = &msm_csic_subdev_g_chip_ident,
+	.ioctl = &msm_csic_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_csic_subdev_ops = {
+	.core = &msm_csic_subdev_core_ops,
+};
+
+static int __devinit csic_probe(struct platform_device *pdev)
+{
+	struct csic_device *new_csic_dev;
+	int rc = 0;
+	CDBG("%s: device id = %d\n", __func__, pdev->id);
+	new_csic_dev = kzalloc(sizeof(struct csic_device), GFP_KERNEL);
+	if (!new_csic_dev) {
+		pr_err("%s: no enough memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	v4l2_subdev_init(&new_csic_dev->subdev, &msm_csic_subdev_ops);
+	v4l2_set_subdevdata(&new_csic_dev->subdev, new_csic_dev);
+	platform_set_drvdata(pdev, &new_csic_dev->subdev);
+	mutex_init(&new_csic_dev->mutex);
+
+	new_csic_dev->mem = platform_get_resource_byname(pdev,
+					IORESOURCE_MEM, "csic");
+	if (!new_csic_dev->mem) {
+		pr_err("%s: no mem resource?\n", __func__);
+		rc = -ENODEV;
+		goto csic_no_resource;
+	}
+	new_csic_dev->irq = platform_get_resource_byname(pdev,
+					IORESOURCE_IRQ, "csic");
+	if (!new_csic_dev->irq) {
+		pr_err("%s: no irq resource?\n", __func__);
+		rc = -ENODEV;
+		goto csic_no_resource;
+	}
+	new_csic_dev->io = request_mem_region(new_csic_dev->mem->start,
+		resource_size(new_csic_dev->mem), pdev->name);
+	if (!new_csic_dev->io) {
+		pr_err("%s: no valid mem region\n", __func__);
+		rc = -EBUSY;
+		goto csic_no_resource;
+	}
+
+	rc = request_irq(new_csic_dev->irq->start, msm_csic_irq,
+		IRQF_TRIGGER_RISING, "csic", new_csic_dev);
+	if (rc < 0) {
+		release_mem_region(new_csic_dev->mem->start,
+			resource_size(new_csic_dev->mem));
+		pr_err("%s: irq request fail\n", __func__);
+		rc = -EBUSY;
+		goto csic_no_resource;
+	}
+	disable_irq(new_csic_dev->irq->start);
+	pr_info("msm_cam_clk_enable: enable csi_pclk\n");
+	msm_cam_clk_enable(&pdev->dev, &csic_clk_info[2],
+				new_csic_dev->csic_clk, 1, 1);
+	new_csic_dev->base = ioremap(new_csic_dev->mem->start,
+		resource_size(new_csic_dev->mem));
+	if (!new_csic_dev->base) {
+		rc = -ENOMEM;
+		goto csic_no_resource;
+	}
+
+	msm_io_w(MIPI_PWR_CNTL_DIS, new_csic_dev->base + MIPI_PWR_CNTL_DIS);
+	pr_info("msm_cam_clk_enable: disable csi_pclk\n");
+	msm_cam_clk_enable(&pdev->dev, &csic_clk_info[2],
+					new_csic_dev->csic_clk, 1, 0);
+	iounmap(new_csic_dev->base);
+
+	new_csic_dev->pdev = pdev;
+	return 0;
+
+csic_no_resource:
+	mutex_destroy(&new_csic_dev->mutex);
+	kfree(new_csic_dev);
+	return 0;
+}
+
+static struct platform_driver csic_driver = {
+	.probe = csic_probe,
+	.driver = {
+		.name = MSM_CSIC_DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_csic_init_module(void)
+{
+	return platform_driver_register(&csic_driver);
+}
+
+static void __exit msm_csic_exit_module(void)
+{
+	platform_driver_unregister(&csic_driver);
+}
+
+module_init(msm_csic_init_module);
+module_exit(msm_csic_exit_module);
+MODULE_DESCRIPTION("MSM csic driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/csi/msm_csic.h b/drivers/media/video/msm/csi/msm_csic.h
new file mode 100644
index 0000000..08dde52
--- /dev/null
+++ b/drivers/media/video/msm/csi/msm_csic.h
@@ -0,0 +1,48 @@
+/* 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_CSIC_H
+#define MSM_CSIC_H
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <media/v4l2-subdev.h>
+
+struct csic_device {
+	struct platform_device *pdev;
+	struct v4l2_subdev subdev;
+	struct resource *mem;
+	struct resource *irq;
+	struct resource *io;
+	void __iomem *base;
+	struct mutex mutex;
+	uint32_t hw_version;
+
+	struct clk *csic_clk[5];
+};
+
+struct csic_cfg_params {
+	struct v4l2_subdev *subdev;
+	void *parms;
+};
+
+#define VIDIOC_MSM_CSIC_CFG \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct csic_cfg_params)
+
+#define VIDIOC_MSM_CSIC_INIT \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct v4l2_subdev*)
+
+#define VIDIOC_MSM_CSIC_RELEASE \
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct v4l2_subdev*)
+
+#endif
+
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 363e437..a9aa28b 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -1478,15 +1478,14 @@
 				__func__, rc);
 			return rc;
 		}
-		rc = v4l2_device_register_subdev(&pcam->v4l2_dev,
-					pcam->mctl.isp_sdev->sd_vpe);
-		if (rc < 0) {
-			mutex_unlock(&pcam->vid_lock);
-			pr_err("%s: vpe v4l2_device_register_subdev failed rc = %d\n",
-				__func__, rc);
-			return rc;
+		if (pcam->mctl.isp_sdev->sd_vpe) {
+			rc = v4l2_device_register_subdev(&pcam->v4l2_dev,
+						pcam->mctl.isp_sdev->sd_vpe);
+			if (rc < 0) {
+				mutex_unlock(&pcam->vid_lock);
+				return rc;
+			}
 		}
-
 		rc = msm_setup_v4l2_event_queue(&pcam_inst->eventHandle,
 							pcam->pvdev);
 		if (rc < 0) {
@@ -2395,7 +2394,7 @@
 		goto client_fail;
 
 	*actctrl = *a_ext_ctrl;
-	a_ext_ctrl->a_create_subdevice((void *)actuator_info->board_info,
+	a_ext_ctrl->a_create_subdevice((void *)actuator_info,
 				       (void *)act_sdev);
 	return rc;
 
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 5fc3e6a..cc2e8b4 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -43,6 +43,7 @@
 
 #define MSM_CSIPHY_DRV_NAME "msm_csiphy"
 #define MSM_CSID_DRV_NAME "msm_csid"
+#define MSM_CSIC_DRV_NAME "msm_csic"
 #define MSM_ISPIF_DRV_NAME "msm_ispif"
 #define MSM_VFE_DRV_NAME "msm_vfe"
 #define MSM_VPE_DRV_NAME "msm_vpe"
@@ -121,6 +122,8 @@
 	NOTIFY_PCLK_CHANGE, /* arg = pclk */
 	NOTIFY_CSIPHY_CFG, /* arg = msm_camera_csiphy_params */
 	NOTIFY_CSID_CFG, /* arg = msm_camera_csid_params */
+	NOTIFY_CSIC_CFG, /* arg = msm_camera_csic_params */
+	NOTIFY_VFE_BUF_FREE_EVT, /* arg = msm_camera_csic_params */
 	NOTIFY_INVALID
 };
 
@@ -225,6 +228,7 @@
 	struct msm_cam_config_dev *config_device;
 	struct v4l2_subdev *csiphy_sdev; /*csiphy sub device*/
 	struct v4l2_subdev *csid_sdev; /*csid sub device*/
+	struct v4l2_subdev *csic_sdev; /*csid sub device*/
 	struct v4l2_subdev *ispif_sdev; /* ispif sub device */
 	struct v4l2_subdev *act_sdev; /* actuator sub device */
 
diff --git a/drivers/media/video/msm/msm_io_7x27a_v4l2.c b/drivers/media/video/msm/msm_io_7x27a_v4l2.c
new file mode 100644
index 0000000..bee9f49
--- /dev/null
+++ b/drivers/media/video/msm/msm_io_7x27a_v4l2.c
@@ -0,0 +1,258 @@
+/* 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/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/pm_qos_params.h>
+#include <mach/board.h>
+#include <mach/camera.h>
+#include <mach/camera.h>
+#include <mach/clk.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+
+
+#define MSM_AXI_QOS_PREVIEW 200000
+#define MSM_AXI_QOS_SNAPSHOT 200000
+#define MSM_AXI_QOS_RECORDING 200000
+
+static struct clk *camio_cam_clk;
+static struct resource *clk_ctrl_mem;
+static struct msm_camera_io_clk camio_clk;
+void __iomem *appbase;
+
+void msm_io_w(u32 data, void __iomem *addr)
+{
+	CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
+	writel_relaxed((data), (addr));
+}
+
+u32 msm_io_r(void __iomem *addr)
+{
+	uint32_t data = readl_relaxed(addr);
+	CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
+	return data;
+}
+
+void msm_camio_clk_rate_set_2(struct clk *clk, int rate)
+{
+	clk_set_rate(clk, rate);
+}
+int msm_camio_clk_enable(enum msm_camio_clk_type clktype)
+{
+	int rc = 0;
+	struct clk *clk = NULL;
+
+	switch (clktype) {
+	case CAMIO_CAM_MCLK_CLK:
+		clk = clk_get(NULL, "cam_m_clk");
+		camio_cam_clk = clk;
+		msm_camio_clk_rate_set_2(clk, camio_clk.mclk_clk_rate);
+		break;
+	default:
+		break;
+	}
+
+	if (!IS_ERR(clk))
+		clk_enable(clk);
+	else
+		rc = -1;
+	return rc;
+}
+
+int msm_camio_clk_disable(enum msm_camio_clk_type clktype)
+{
+	int rc = 0;
+	struct clk *clk = NULL;
+
+	switch (clktype) {
+	case CAMIO_CAM_MCLK_CLK:
+		clk = camio_cam_clk;
+		break;
+	default:
+		break;
+	}
+
+	if (!IS_ERR(clk)) {
+		clk_disable(clk);
+		clk_put(clk);
+	} else
+		rc = -1;
+	return rc;
+}
+
+void msm_camio_clk_rate_set(int rate)
+{
+	struct clk *clk = camio_cam_clk;
+	clk_set_rate(clk, rate);
+}
+
+int msm_sensor_probe_on(struct device *dev)
+{
+	int rc = 0;
+	struct msm_camera_sensor_info *sinfo = dev->platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	camio_clk = camdev->ioclk;
+
+	rc = camdev->camera_gpio_on();
+	if (rc < 0)
+		return rc;
+
+	rc = msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK);
+	if (rc < 0)
+		camdev->camera_gpio_off();
+
+	return rc;
+}
+
+int msm_sensor_probe_off(struct device *dev)
+{
+	struct msm_camera_sensor_info *sinfo = dev->platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+
+	camdev->camera_gpio_off();
+	return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
+}
+
+void msm_camio_vfe_blk_reset(void)
+{
+	uint32_t val;
+
+	/* do apps reset */
+	val = readl_relaxed(appbase + 0x00000210);
+	val |= 0x1;
+	writel_relaxed(val, appbase + 0x00000210);
+	usleep_range(10000, 11000);
+
+	val = readl_relaxed(appbase + 0x00000210);
+	val &= ~0x1;
+	writel_relaxed(val, appbase + 0x00000210);
+	usleep_range(10000, 11000);
+
+	/* do axi reset */
+	val = readl_relaxed(appbase + 0x00000208);
+	val |= 0x1;
+	writel_relaxed(val, appbase + 0x00000208);
+	usleep_range(10000, 11000);
+
+	val = readl_relaxed(appbase + 0x00000208);
+	val &= ~0x1;
+	writel_relaxed(val, appbase + 0x00000208);
+	mb();
+	usleep_range(10000, 11000);
+}
+
+int msm_camio_probe_on(struct platform_device *pdev)
+{
+	int rc = 0;
+	const struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+	camio_clk = camdev->ioclk;
+
+	rc = camdev->camera_gpio_on();
+	if (rc < 0)
+		return rc;
+	return msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK);
+}
+
+int msm_camio_probe_off(struct platform_device *pdev)
+{
+	const struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+
+	camdev->camera_gpio_off();
+	return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
+}
+
+void msm_camio_set_perf_lvl(enum msm_bus_perf_setting perf_setting)
+{
+	switch (perf_setting) {
+	case S_INIT:
+		add_axi_qos();
+		break;
+	case S_PREVIEW:
+		update_axi_qos(MSM_AXI_QOS_PREVIEW);
+		break;
+	case S_VIDEO:
+		update_axi_qos(MSM_AXI_QOS_RECORDING);
+		break;
+	case S_CAPTURE:
+		update_axi_qos(MSM_AXI_QOS_SNAPSHOT);
+		break;
+	case S_DEFAULT:
+		update_axi_qos(PM_QOS_DEFAULT_VALUE);
+		break;
+	case S_EXIT:
+		release_axi_qos();
+		break;
+	default:
+		CDBG("%s: INVALID CASE\n", __func__);
+	}
+}
+
+static int __devinit clkctl_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+
+	clk_ctrl_mem = platform_get_resource_byname(pdev,
+					IORESOURCE_MEM, "clk_ctl");
+	if (!clk_ctrl_mem) {
+		pr_err("%s: no mem resource:3?\n", __func__);
+		return -ENODEV;
+	}
+
+	appbase = ioremap(clk_ctrl_mem->start,
+		resource_size(clk_ctrl_mem));
+	if (!appbase) {
+		pr_err("clkctl_probe: appbase:err\n");
+		rc = -ENOMEM;
+		goto ioremap_fail;
+	}
+	return 0;
+
+ioremap_fail:
+	msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
+	return rc;
+}
+
+static int clkctl_remove(struct platform_device *pdev)
+{
+	if (clk_ctrl_mem)
+		iounmap(clk_ctrl_mem);
+
+	return 0;
+}
+
+static struct platform_driver clkctl_driver = {
+	.probe  = clkctl_probe,
+	.remove = clkctl_remove,
+	.driver = {
+		.name = "msm_clk_ctl",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_clkctl_init_module(void)
+{
+	return platform_driver_register(&clkctl_driver);
+}
+
+static void __exit msm_clkctl_exit_module(void)
+{
+	platform_driver_unregister(&clkctl_driver);
+}
+
+module_init(msm_clkctl_init_module);
+module_exit(msm_clkctl_exit_module);
+MODULE_DESCRIPTION("CAM IO driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index 0a1516b..6a9d7c4 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.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
@@ -69,6 +69,20 @@
 	}
 }
 
+static int msm_isp_notify_VFE_BUF_FREE_EVT(struct v4l2_subdev *sd, void *arg)
+{
+	struct msm_vfe_cfg_cmd cfgcmd;
+	struct msm_camvfe_params vfe_params;
+	int rc;
+
+	cfgcmd.cmd_type = CMD_VFE_BUFFER_RELEASE;
+	cfgcmd.value = NULL;
+	vfe_params.vfe_cfg = &cfgcmd;
+	vfe_params.data = NULL;
+	rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params);
+	return 0;
+}
+
 static int msm_isp_notify_VFE_BUF_EVT(struct v4l2_subdev *sd, void *arg)
 {
 	int rc = -EINVAL;
@@ -89,6 +103,7 @@
 	switch (vdata->type) {
 	case VFE_MSG_V32_START:
 	case VFE_MSG_V32_START_RECORDING:
+	case VFE_MSG_V2X_PREVIEW:
 		D("%s Got V32_START_*: Getting ping addr id = %d",
 						__func__, vfe_id);
 		msm_mctl_reserve_free_buf(&pcam->mctl, vfe_id, &free_buf);
@@ -105,6 +120,7 @@
 		rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params);
 		break;
 	case VFE_MSG_V32_CAPTURE:
+	case VFE_MSG_V2X_CAPTURE:
 		pr_err("%s Got V32_CAPTURE: getting buffer for id = %d",
 						__func__, vfe_id);
 		msm_mctl_reserve_free_buf(&pcam->mctl, vfe_id, &free_buf);
@@ -161,6 +177,9 @@
 	if (notification == NOTIFY_VFE_BUF_EVT)
 		return msm_isp_notify_VFE_BUF_EVT(sd, arg);
 
+	if (notification == NOTIFY_VFE_BUF_FREE_EVT)
+		return msm_isp_notify_VFE_BUF_FREE_EVT(sd, arg);
+
 	isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl), GFP_ATOMIC);
 	if (!isp_event) {
 		pr_err("%s Insufficient memory. return", __func__);
@@ -376,6 +395,19 @@
 		axi_data.region = &region[0];
 		return msm_isp_subdev_ioctl(sd, &cfgcmd,
 							&axi_data);
+	case CMD_STATS_AEC_AWB_ENABLE:
+		axi_data.bufnum1 =
+			msm_pmem_region_lookup(&sync->pmem_stats,
+			MSM_PMEM_AEC_AWB, &region[0],
+			NUM_STAT_OUTPUT_BUFFERS);
+		if (!axi_data.bufnum1) {
+			pr_err("%s %d: pmem region lookup error\n",
+				__func__, __LINE__);
+			return -EINVAL;
+		}
+		axi_data.region = &region[0];
+		return msm_isp_subdev_ioctl(sd, &cfgcmd,
+							&axi_data);
 	case CMD_STATS_IHIST_ENABLE:
 		axi_data.bufnum1 =
 			msm_pmem_region_lookup(&sync->pmem_stats,
@@ -614,6 +646,8 @@
 			cfgcmd.cmd_type = CMD_STATS_RS_BUF_RELEASE;
 		else if (buf.type == STAT_CS)
 			cfgcmd.cmd_type = CMD_STATS_CS_BUF_RELEASE;
+		else if (buf.type == STAT_AEAW)
+			cfgcmd.cmd_type = CMD_STATS_BUF_RELEASE;
 
 		else {
 			pr_err("%s: invalid buf type %d\n",
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index e13dd62..e76b1d2 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -29,6 +29,7 @@
 
 #include "msm.h"
 #include "msm_csid.h"
+#include "msm_csic.h"
 #include "msm_csiphy.h"
 #include "msm_ispif.h"
 #include "msm_sensor.h"
@@ -92,6 +93,14 @@
 	.colorspace = V4L2_COLORSPACE_JPEG,
 	},
 	{
+	.name	   = "NV21BAYER",
+	.depth	  = 8,
+	.bitsperpxl = 8,
+	.fourcc	 = V4L2_PIX_FMT_NV21,
+	.pxlcode	= V4L2_MBUS_FMT_SGRBG10_1X10, /* Bayer sensor */
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	},
+	{
 	.name	   = "YU12BAYER",
 	.depth	  = 8,
 	.bitsperpxl = 8,
@@ -107,6 +116,14 @@
 	.pxlcode	= V4L2_MBUS_FMT_SBGGR10_1X10, /* Bayer sensor */
 	.colorspace = V4L2_COLORSPACE_JPEG,
 	},
+	{
+	.name	   = "RAWBAYER",
+	.depth	  = 10,
+	.bitsperpxl = 10,
+	.fourcc	 = V4L2_PIX_FMT_SBGGR10,
+	.pxlcode	= V4L2_MBUS_FMT_SGRBG10_1X10, /* Bayer sensor */
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	},
 
 };
 
@@ -225,6 +242,7 @@
 	case NOTIFY_VFE_MSG_OUT:
 	case NOTIFY_VFE_MSG_STATS:
 	case NOTIFY_VFE_BUF_EVT:
+	case NOTIFY_VFE_BUF_FREE_EVT:
 		if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_notify) {
 			rc = p_mctl->isp_sdev->isp_notify(
 				p_mctl->isp_sdev->sd, notification, arg);
@@ -248,6 +266,10 @@
 		rc = v4l2_subdev_call(p_mctl->csid_sdev,
 			core, ioctl, VIDIOC_MSM_CSID_CFG, arg);
 		break;
+	case NOTIFY_CSIC_CFG:
+		rc = v4l2_subdev_call(p_mctl->csic_sdev,
+			core, ioctl, VIDIOC_MSM_CSIC_CFG, arg);
+		break;
 	default:
 		break;
 	}
@@ -416,44 +438,70 @@
 	struct device *dev;
 	int rc = -ENODEV;
 
-	/* register csiphy subdev */
-	driver = driver_find(MSM_CSIPHY_DRV_NAME, &platform_bus_type);
-	if (!driver)
-		goto out;
+	struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(p_mctl->sensor_sdev);
+	struct msm_camera_sensor_info *sinfo =
+		(struct msm_camera_sensor_info *) s_ctrl->sensordata;
+	struct msm_camera_device_platform_data *pdata = sinfo->pdata;
 
-	dev = driver_find_device(driver, NULL, (void *)core_index,
+	if (pdata->is_csiphy) {
+		/* register csiphy subdev */
+		driver = driver_find(MSM_CSIPHY_DRV_NAME, &platform_bus_type);
+		if (!driver)
+			goto out;
+
+		dev = driver_find_device(driver, NULL, (void *)core_index,
 				msm_mctl_subdev_match_core);
-	if (!dev)
-		goto out_put_driver;
+		if (!dev)
+			goto out_put_driver;
 
-	p_mctl->csiphy_sdev = dev_get_drvdata(dev);
-	put_driver(driver);
+		p_mctl->csiphy_sdev = dev_get_drvdata(dev);
+		put_driver(driver);
+	}
 
-	/* register csid subdev */
-	driver = driver_find(MSM_CSID_DRV_NAME, &platform_bus_type);
-	if (!driver)
-		goto out;
+	if (pdata->is_csic) {
+		/* register csic subdev */
+		driver = driver_find(MSM_CSIC_DRV_NAME, &platform_bus_type);
+		if (!driver)
+			goto out;
 
-	dev = driver_find_device(driver, NULL, (void *)core_index,
+		dev = driver_find_device(driver, NULL, (void *)core_index,
 				msm_mctl_subdev_match_core);
-	if (!dev)
-		goto out_put_driver;
+		if (!dev)
+			goto out_put_driver;
 
-	p_mctl->csid_sdev = dev_get_drvdata(dev);
-	put_driver(driver);
+		p_mctl->csic_sdev = dev_get_drvdata(dev);
+		put_driver(driver);
+	}
 
-	/* register ispif subdev */
-	driver = driver_find(MSM_ISPIF_DRV_NAME, &platform_bus_type);
-	if (!driver)
-		goto out;
+	if (pdata->is_csid) {
+		/* register csid subdev */
+		driver = driver_find(MSM_CSID_DRV_NAME, &platform_bus_type);
+		if (!driver)
+			goto out;
 
-	dev = driver_find_device(driver, NULL, 0,
+		dev = driver_find_device(driver, NULL, (void *)core_index,
 				msm_mctl_subdev_match_core);
-	if (!dev)
-		goto out_put_driver;
+		if (!dev)
+			goto out_put_driver;
 
-	p_mctl->ispif_sdev = dev_get_drvdata(dev);
-	put_driver(driver);
+		p_mctl->csid_sdev = dev_get_drvdata(dev);
+		put_driver(driver);
+	}
+
+	if (pdata->is_ispif) {
+		/* register ispif subdev */
+		driver = driver_find(MSM_ISPIF_DRV_NAME, &platform_bus_type);
+		if (!driver)
+			goto out;
+
+		dev = driver_find_device(driver, NULL, 0,
+				msm_mctl_subdev_match_core);
+		if (!dev)
+			goto out_put_driver;
+
+		p_mctl->ispif_sdev = dev_get_drvdata(dev);
+		put_driver(driver);
+	}
 
 	/* register vfe subdev */
 	driver = driver_find(MSM_VFE_DRV_NAME, &platform_bus_type);
@@ -468,18 +516,20 @@
 	p_mctl->isp_sdev->sd = dev_get_drvdata(dev);
 	put_driver(driver);
 
-	/* register vfe subdev */
-	driver = driver_find(MSM_VPE_DRV_NAME, &platform_bus_type);
-	if (!driver)
-		goto out;
+	if (pdata->is_vpe) {
+		/* register vfe subdev */
+		driver = driver_find(MSM_VPE_DRV_NAME, &platform_bus_type);
+		if (!driver)
+			goto out;
 
-	dev = driver_find_device(driver, NULL, 0,
+		dev = driver_find_device(driver, NULL, 0,
 				msm_mctl_subdev_match_core);
-	if (!dev)
-		goto out_put_driver;
+		if (!dev)
+			goto out_put_driver;
 
-	p_mctl->isp_sdev->sd_vpe = dev_get_drvdata(dev);
-	put_driver(driver);
+		p_mctl->isp_sdev->sd_vpe = dev_get_drvdata(dev);
+		put_driver(driver);
+	}
 
 	rc = 0;
 	return rc;
@@ -522,20 +572,33 @@
 			goto msm_open_done;
 		}
 
-		rc = v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
-			VIDIOC_MSM_CSIPHY_INIT, NULL);
-		if (rc < 0) {
-			pr_err("%s: csiphy initialization failed %d\n",
+		if (camdev->is_csiphy) {
+			rc = v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
+				VIDIOC_MSM_CSIPHY_INIT, NULL);
+			if (rc < 0) {
+				pr_err("%s: csiphy initialization failed %d\n",
 				__func__, rc);
-			goto msm_open_done;
+				goto msm_open_done;
+			}
 		}
 
-		rc = v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl,
-			VIDIOC_MSM_CSID_INIT, &csid_version);
-		if (rc < 0) {
-			pr_err("%s: csid initialization failed %d\n",
+		if (camdev->is_csid) {
+			rc = v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl,
+				VIDIOC_MSM_CSID_INIT, &csid_version);
+			if (rc < 0) {
+				pr_err("%s: csid initialization failed %d\n",
 				__func__, rc);
-			goto msm_open_done;
+				goto msm_open_done;
+			}
+		}
+		if (camdev->is_csic) {
+			rc = v4l2_subdev_call(p_mctl->csic_sdev, core, ioctl,
+				VIDIOC_MSM_CSIC_INIT, &csid_version);
+			if (rc < 0) {
+				pr_err("%s: csic initialization failed %d\n",
+				__func__, rc);
+				goto msm_open_done;
+			}
 		}
 
 		/* ISP first*/
@@ -548,12 +611,14 @@
 			goto msm_open_done;
 		}
 
-		rc = v4l2_subdev_call(p_mctl->ispif_sdev, core, ioctl,
-			VIDIOC_MSM_ISPIF_INIT, &csid_version);
-		if (rc < 0) {
-			pr_err("%s: ispif initialization failed %d\n",
+		if (camdev->is_ispif) {
+			rc = v4l2_subdev_call(p_mctl->ispif_sdev, core, ioctl,
+				VIDIOC_MSM_ISPIF_INIT, &csid_version);
+			if (rc < 0) {
+				pr_err("%s: ispif initialization failed %d\n",
 				__func__, rc);
-			goto msm_open_done;
+				goto msm_open_done;
+			}
 		}
 
 		/* then sensor - move sub dev later*/
@@ -563,7 +628,6 @@
 			pr_err("%s: isp init failed: %d\n", __func__, rc);
 			goto msm_open_done;
 		}
-
 		if (sync->actctrl.a_power_up)
 			rc = sync->actctrl.a_power_up(
 				sync->sdata->actuator_info);
@@ -573,12 +637,13 @@
 			goto msm_open_done;
 		}
 
-		pm_qos_add_request(&p_mctl->pm_qos_req_list,
+		if (camdev->is_ispif) {
+			pm_qos_add_request(&p_mctl->pm_qos_req_list,
 					PM_QOS_CPU_DMA_LATENCY,
 					PM_QOS_DEFAULT_VALUE);
-		pm_qos_update_request(&p_mctl->pm_qos_req_list,
+			pm_qos_update_request(&p_mctl->pm_qos_req_list,
 					MSM_V4L2_SWFI_LATENCY);
-
+		}
 		sync->apps_id = apps_id;
 		sync->opencnt++;
 	}
@@ -591,28 +656,44 @@
 static int msm_mctl_release(struct msm_cam_media_controller *p_mctl)
 {
 	int rc = 0;
-	v4l2_subdev_call(p_mctl->ispif_sdev, core, ioctl,
-		VIDIOC_MSM_ISPIF_RELEASE, NULL);
+	struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(p_mctl->sensor_sdev);
+	struct msm_camera_sensor_info *sinfo =
+		(struct msm_camera_sensor_info *) s_ctrl->sensordata;
+	struct msm_camera_device_platform_data *camdev = sinfo->pdata;
+
+	if (camdev->is_ispif) {
+		v4l2_subdev_call(p_mctl->ispif_sdev, core, ioctl,
+			VIDIOC_MSM_ISPIF_RELEASE, NULL);
+	}
 
 	if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_release)
 		p_mctl->isp_sdev->isp_release(&p_mctl->sync);
 
-	v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl,
-		VIDIOC_MSM_CSID_RELEASE, NULL);
+	if (camdev->is_csid) {
+		v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl,
+			VIDIOC_MSM_CSID_RELEASE, NULL);
+	}
 
-	v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
-		VIDIOC_MSM_CSIPHY_RELEASE, NULL);
+	if (camdev->is_csic) {
+		v4l2_subdev_call(p_mctl->csic_sdev, core, ioctl,
+			VIDIOC_MSM_CSIC_RELEASE, NULL);
+	}
+
+	if (camdev->is_csiphy) {
+		v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
+			VIDIOC_MSM_CSIPHY_RELEASE, NULL);
+	}
 
 	if (p_mctl->sync.actctrl.a_power_down)
 		p_mctl->sync.actctrl.a_power_down(
 			p_mctl->sync.sdata->actuator_info);
 
 	v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 0);
-
-	pm_qos_update_request(&p_mctl->pm_qos_req_list,
+	if (camdev->is_ispif) {
+		pm_qos_update_request(&p_mctl->pm_qos_req_list,
 				PM_QOS_DEFAULT_VALUE);
-	pm_qos_remove_request(&p_mctl->pm_qos_req_list);
-
+		pm_qos_remove_request(&p_mctl->pm_qos_req_list);
+	}
 	wake_unlock(&p_mctl->sync.wake_lock);
 	return rc;
 }
diff --git a/drivers/media/video/msm/msm_mem.c b/drivers/media/video/msm/msm_mem.c
index b631981..0ba1c0f 100644
--- a/drivers/media/video/msm/msm_mem.c
+++ b/drivers/media/video/msm/msm_mem.c
@@ -220,6 +220,7 @@
 	case MSM_PMEM_CS:
 	case MSM_PMEM_IHIST:
 	case MSM_PMEM_SKIN:
+	case MSM_PMEM_AEC_AWB:
 		rc = msm_pmem_table_add(ptype, pinfo, client);
 		break;
 
@@ -246,6 +247,7 @@
 	case MSM_PMEM_CS:
 	case MSM_PMEM_IHIST:
 	case MSM_PMEM_SKIN:
+	case MSM_PMEM_AEC_AWB:
 		hlist_for_each_entry_safe(region, node, n,
 				ptype, list) {
 
diff --git a/drivers/media/video/msm/msm_vfe31.c b/drivers/media/video/msm/msm_vfe31.c
index 2b3732c..f1d70aa 100644
--- a/drivers/media/video/msm/msm_vfe31.c
+++ b/drivers/media/video/msm/msm_vfe31.c
@@ -3892,6 +3892,7 @@
 	spin_lock_init(&vfe31_ctrl->io_lock);
 	spin_lock_init(&vfe31_ctrl->update_ack_lock);
 	spin_lock_init(&vfe31_ctrl->tasklet_lock);
+	spin_lock_init(&vfe31_ctrl->xbar_lock);
 
 	INIT_LIST_HEAD(&vfe31_ctrl->tasklet_q);
 	vfe31_init_free_buf_queue();
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
new file mode 100644
index 0000000..638c51d
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
@@ -0,0 +1,1353 @@
+/* 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/msm_adsp.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/android_pmem.h>
+#include <linux/slab.h>
+#include <linux/pm_qos_params.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/msm_isp.h>
+#include <mach/msm_adsp.h>
+#include <mach/clk.h>
+#include <mach/camera.h>
+#include "msm_vfe7x27a_v4l2.h"
+#include "msm.h"
+
+/* ADSP Messages */
+#define MSG_RESET_ACK  0
+#define MSG_STOP_ACK  1
+#define MSG_SNAPSHOT  2
+#define MSG_ILLEGAL_COMMAND  3
+#define MSG_START_ACK  4
+#define MSG_UPDATE_ACK  5
+#define MSG_OUTPUT1  6
+#define MSG_OUTPUT2  7
+#define MSG_STATS_AF  8
+#define MSG_STATS_WE  9
+#define MSG_STATS_HISTOGRAM  10
+#define MSG_EPOCH1  11
+#define MSG_EPOCH2  12
+#define MSG_VFE_ERROR 13
+#define MSG_SYNC_TIMER1_DONE  14
+#define MSG_SYNC_TIMER2_DONE  15
+#define MSG_ASYNC_TIMER1_DONE  16
+#define MSG_ASYNC_TIMER2_DONE  17
+#define MSG_CAPTURE_COMPLETE  18
+#define MSG_TABLE_CMD_ACK  19
+#define MSG_EXP_TIMEOUT_ACK  20
+#define MSG_SOF  21
+#define MSG_OUTPUT_T  22
+#define MSG_OUTPUT_S  23
+
+#define VFE_ADSP_EVENT 0xFFFF
+#define SNAPSHOT_MASK_MODE 0x00000001
+#define MSM_AXI_QOS_PREVIEW	122000
+#define MSM_AXI_QOS_SNAPSHOT	192000
+
+
+#define QDSP_CMDQUEUE 25
+#define QDSP_SCALEQUEUE 26
+#define QDSP_TABLEQUEUE 27
+
+/* ADSP Scler queue Cmd IDs */
+#define VFE_SCALE_OUTPUT1_CONFIG  0
+#define VFE_SCALE_OUTPUT2_CONFIG  1
+#define VFE_SCALE_MAX  0xFFFFFFFF
+
+/* ADSP table queue Cmd IDs */
+#define VFE_AXI_INPUT_CONFIG  0
+#define VFE_AXI_OUTPUT_CONFIG  1
+#define VFE_RGB_GAMMA_CONFIG  2
+#define VFE_Y_GAMMA_CONFIG  3
+#define VFE_ROLL_OFF_CONFIG  4
+#define VFE_DEMOSAICv3_BPC_CFG  6
+#define VFE_DEMOSAICv3_ABF_CFG  7
+#define VFE_DEMOSAICv3_CFG  8
+#define VFE_MAX  0xFFFFFFFF
+
+/* ADSP cfg queue cmd IDs */
+#define VFE_RESET  0
+#define VFE_START  1
+#define VFE_STOP  2
+#define VFE_UPDATE  3
+#define VFE_CAMIF_CONFIG  4
+#define VFE_ACTIVE_REGION_CONFIG  5
+#define VFE_DEMOSAIC_CONFIG  6
+#define VFE_INPUT_FORMAT_CONFIG  7
+#define VFE_OUTPUT_CLAMP_CONFIG  8
+#define VFE_CHROMA_SUBSAMPLE_CONFIG  9
+#define VFE_BLACK_LEVEL_CONFIG  10
+#define VFE_WHITE_BALANCE_CONFIG  11
+#define VFE_COLOR_PROCESSING_CONFIG  12
+#define VFE_ADAPTIVE_FILTER_CONFIG  13
+#define VFE_FRAME_SKIP_CONFIG  14
+#define VFE_FOV_CROP  15
+#define VFE_STATS_AUTOFOCUS_CONFIG  16
+#define VFE_STATS_WB_EXP_CONFIG  17
+#define VFE_STATS_HISTOGRAM_CONFIG  18
+#define VFE_OUTPUT1_ACK  19
+#define VFE_OUTPUT2_ACK  20
+#define VFE_STATS_AUTOFOCUS_ACK  21
+#define VFE_STATS_WB_EXP_ACK  22
+#define VFE_EPOCH1_ACK  23
+#define VFE_EPOCH2_ACK  24
+#define VFE_UPDATE_CAMIF_FRAME_CONFIG  25
+#define VFE_SYNC_TIMER1_CONFIG  26
+#define VFE_SYNC_TIMER2_CONFIG  27
+#define VFE_ASYNC_TIMER1_START  28
+#define VFE_ASYNC_TIMER2_START  29
+#define VFE_STATS_AUTOFOCUS_UPDATE  30
+#define VFE_STATS_WB_EXP_UPDATE  31
+#define VFE_ROLL_OFF_UPDATE  33
+#define VFE_DEMOSAICv3_BPC_UPDATE  34
+#define VFE_TESTGEN_START  35
+#define VFE_STATS_MA  0xFFFFFFFF
+
+struct msg_id_map msgs_map[] = {
+	{MSG_RESET_ACK, MSG_ID_RESET_ACK},
+	{MSG_STOP_ACK, MSG_ID_STOP_ACK},
+	{MSG_SNAPSHOT, MSG_ID_SNAPSHOT_DONE},
+	{MSG_ILLEGAL_COMMAND, VFE_MAX},
+	{MSG_START_ACK, MSG_ID_START_ACK},
+	{MSG_UPDATE_ACK, MSG_ID_UPDATE_ACK},
+	{MSG_OUTPUT1, VFE_MAX},
+	{MSG_OUTPUT2, VFE_MAX},
+	{MSG_STATS_AF, MSG_ID_STATS_AF},
+	{MSG_STATS_WE, MSG_ID_STATS_AWB_AEC},
+	{MSG_STATS_HISTOGRAM, MSG_ID_STATS_IHIST},
+	{MSG_EPOCH1, MSG_ID_EPOCH1},
+	{MSG_EPOCH2, MSG_ID_EPOCH2},
+	{MSG_VFE_ERROR, MSG_ID_CAMIF_ERROR},
+	{MSG_SYNC_TIMER1_DONE, MSG_ID_SYNC_TIMER1_DONE},
+	{MSG_SYNC_TIMER2_DONE, MSG_ID_SYNC_TIMER2_DONE},
+	{MSG_ASYNC_TIMER1_DONE, MSG_ID_ASYNC_TIMER1_DONE},
+	{MSG_ASYNC_TIMER2_DONE, MSG_ID_ASYNC_TIMER2_DONE},
+	{MSG_CAPTURE_COMPLETE, MSG_CAPTURE_COMPLETE},
+	{MSG_TABLE_CMD_ACK, MSG_TABLE_CMD_ACK},
+	{MSG_EXP_TIMEOUT_ACK, MSG_EXP_TIMEOUT_ACK},
+	{MSG_SOF, MSG_ID_SOF_ACK},
+	{MSG_OUTPUT_T, MSG_ID_OUTPUT_T},
+	{MSG_OUTPUT_S, MSG_ID_OUTPUT_S},
+};
+
+struct cmd_id_map cmds_map[] = {
+	{VFE_CMD_DUMMY_0, VFE_MAX, VFE_MAX},
+	{VFE_CMD_SET_CLK, VFE_MAX, VFE_MAX},
+	{VFE_CMD_RESET, VFE_RESET, QDSP_CMDQUEUE,
+			"VFE_CMD_RESET", "VFE_RESET"},
+	{VFE_CMD_START, VFE_START, QDSP_CMDQUEUE,
+			"VFE_CMD_START", "VFE_START"},
+	{VFE_CMD_TEST_GEN_START, VFE_TESTGEN_START, QDSP_CMDQUEUE,
+		"VFE_CMD_TEST_GEN_START", "VFE_TESTGEN_START"},
+	{VFE_CMD_OPERATION_CFG, VFE_MAX , VFE_MAX},
+	{VFE_CMD_AXI_OUT_CFG, VFE_AXI_OUTPUT_CONFIG, QDSP_TABLEQUEUE,
+		"VFE_CMD_AXI_OUT_CFG", "VFE_AXI_OUTPUT_CONFIG"},
+	{VFE_CMD_CAMIF_CFG, VFE_CAMIF_CONFIG, QDSP_CMDQUEUE,
+			"VFE_CMD_CAMIF_CFG", "VFE_CAMIF_CONFIG"},
+	{VFE_CMD_AXI_INPUT_CFG, VFE_AXI_INPUT_CONFIG, QDSP_TABLEQUEUE,
+		"VFE_CMD_AXI_INPUT_CFG", "VFE_AXI_INPUT_CONFIG"},
+	{VFE_CMD_BLACK_LEVEL_CFG, VFE_BLACK_LEVEL_CONFIG, QDSP_CMDQUEUE,
+		"VFE_CMD_BLACK_LEVEL_CFG", "VFE_BLACK_LEVEL_CONFIG"},
+	{VFE_CMD_MESH_ROLL_OFF_CFG, VFE_ROLL_OFF_CONFIG, QDSP_TABLEQUEUE,
+		"VFE_CMD_MESH_ROLL_OFF_CFG", "VFE_ROLL_OFF_CONFIG"},
+	{VFE_CMD_DEMUX_CFG, VFE_INPUT_FORMAT_CONFIG, QDSP_CMDQUEUE,
+		"VFE_CMD_DEMUX_CFG", "VFE_INPUT_FORMAT_CONFIG"},
+	{VFE_CMD_FOV_CFG, VFE_FOV_CROP, QDSP_CMDQUEUE,
+		"VFE_CMD_FOV_CFG", "VFE_FOV_CROP"},
+	{VFE_CMD_MAIN_SCALER_CFG, VFE_MAX, VFE_MAX},
+	{VFE_CMD_WB_CFG, VFE_WHITE_BALANCE_CONFIG, QDSP_CMDQUEUE,
+		"VFE_CMD_WB_CFG", "VFE_WHITE_BALANCE_CONFIG"},
+	{VFE_CMD_COLOR_COR_CFG, VFE_MAX, VFE_MAX},
+	{VFE_CMD_RGB_G_CFG, VFE_RGB_GAMMA_CONFIG, QDSP_TABLEQUEUE,
+		"VFE_CMD_RGB_G_CFG", "VFE_RGB_GAMMA_CONFIG"},
+	{VFE_CMD_LA_CFG, VFE_MAX, VFE_MAX},
+	{VFE_CMD_CHROMA_EN_CFG, VFE_MAX, VFE_MAX},
+	{VFE_CMD_CHROMA_SUP_CFG, VFE_MAX, VFE_MAX},
+	{VFE_CMD_MCE_CFG, VFE_MAX, VFE_MAX},
+	{VFE_CMD_SK_ENHAN_CFG, VFE_MAX, VFE_MAX},
+	{VFE_CMD_ASF_CFG, VFE_ADAPTIVE_FILTER_CONFIG, QDSP_CMDQUEUE,
+		"VFE_CMD_ASF_CFG", "VFE_ADAPTIVE_FILTER_CONFIG"},
+	{VFE_CMD_S2Y_CFG, VFE_MAX, VFE_MAX},
+	{VFE_CMD_S2CbCr_CFG, VFE_MAX, VFE_MAX},
+	{VFE_CMD_CHROMA_SUBS_CFG, VFE_CHROMA_SUBSAMPLE_CONFIG, QDSP_CMDQUEUE,
+		"VFE_CMD_CHROMA_SUBS_CFG", "VFE_CHROMA_SUBSAMPLE_CONFIG"},
+	{VFE_CMD_OUT_CLAMP_CFG, VFE_OUTPUT_CLAMP_CONFIG, QDSP_CMDQUEUE,
+		"VFE_CMD_OUT_CLAMP_CFG", "VFE_OUTPUT_CLAMP_CONFIG"},
+	{VFE_CMD_FRAME_SKIP_CFG, VFE_FRAME_SKIP_CONFIG, QDSP_CMDQUEUE,
+		"VFE_CMD_FRAME_SKIP_CFG", "VFE_FRAME_SKIP_CONFIG"},
+	{VFE_CMD_DUMMY_1, VFE_MAX, VFE_MAX},
+	{VFE_CMD_DUMMY_2, VFE_MAX, VFE_MAX},
+	{VFE_CMD_DUMMY_3, VFE_MAX, VFE_MAX},
+	{VFE_CMD_UPDATE, VFE_UPDATE, QDSP_CMDQUEUE,
+		"VFE_CMD_UPDATE", "VFE_UPDATE"},
+	{VFE_CMD_BL_LVL_UPDATE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_DEMUX_UPDATE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_FOV_UPDATE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_MAIN_SCALER_UPDATE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_WB_UPDATE, VFE_WHITE_BALANCE_CONFIG, QDSP_CMDQUEUE,
+		"VFE_CMD_WB_UPDATE", "VFE_WHITE_BALANCE_CONFIG"},
+	{VFE_CMD_COLOR_COR_UPDATE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_RGB_G_UPDATE, VFE_RGB_GAMMA_CONFIG, QDSP_TABLEQUEUE,
+		"VFE_CMD_RGB_G_UPDATE", "VFE_RGB_GAMMA_CONFIG"},
+	{VFE_CMD_LA_UPDATE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_CHROMA_EN_UPDATE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_CHROMA_SUP_UPDATE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_MCE_UPDATE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_SK_ENHAN_UPDATE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_S2CbCr_UPDATE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_S2Y_UPDATE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_ASF_UPDATE, VFE_ADAPTIVE_FILTER_CONFIG, QDSP_CMDQUEUE,
+		"VFE_CMD_ASF_UPDATE", "VFE_ADAPTIVE_FILTER_CONFIG"},
+	{VFE_CMD_FRAME_SKIP_UPDATE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_CAMIF_FRAME_UPDATE, VFE_UPDATE_CAMIF_FRAME_CONFIG,
+		QDSP_CMDQUEUE, "VFE_CMD_CAMIF_FRAME_UPDATE",
+		"VFE_UPDATE_CAMIF_FRAME_CONFIG"},
+	{VFE_CMD_STATS_AF_UPDATE, VFE_STATS_AUTOFOCUS_UPDATE, QDSP_CMDQUEUE,
+		"VFE_CMD_STATS_AF_UPDATE", "VFE_STATS_AUTOFOCUS_UPDATE"},
+	{VFE_CMD_STATS_AE_UPDATE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STATS_AWB_UPDATE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STATS_RS_UPDATE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STATS_CS_UPDATE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STATS_SKIN_UPDATE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STATS_IHIST_UPDATE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_DUMMY_4, VFE_MAX, VFE_MAX},
+	{VFE_CMD_EPOCH1_ACK, VFE_EPOCH1_ACK, QDSP_CMDQUEUE,
+			"VFE_CMD_EPOCH1_ACK", "VFE_EPOCH1_ACK"},
+	{VFE_CMD_EPOCH2_ACK, VFE_EPOCH2_ACK, QDSP_CMDQUEUE,
+			"VFE_CMD_EPOCH2_ACK", "VFE_EPOCH2_ACK"},
+	{VFE_CMD_START_RECORDING, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STOP_RECORDING, VFE_MAX , VFE_MAX},
+	{VFE_CMD_DUMMY_5, VFE_MAX, VFE_MAX},
+	{VFE_CMD_DUMMY_6, VFE_MAX, VFE_MAX},
+	{VFE_CMD_CAPTURE, VFE_START, QDSP_CMDQUEUE,
+			"VFE_CMD_CAPTURE", "VFE_START"},
+	{VFE_CMD_DUMMY_7, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STOP, VFE_STOP, QDSP_CMDQUEUE, "VFE_CMD_STOP", "VFE_STOP"},
+	{VFE_CMD_GET_HW_VERSION, VFE_MAX, VFE_MAX},
+	{VFE_CMD_GET_FRAME_SKIP_COUNTS, VFE_MAX, VFE_MAX},
+	{VFE_CMD_OUTPUT1_BUFFER_ENQ, VFE_MAX, VFE_MAX},
+	{VFE_CMD_OUTPUT2_BUFFER_ENQ, VFE_MAX, VFE_MAX},
+	{VFE_CMD_OUTPUT3_BUFFER_ENQ, VFE_MAX, VFE_MAX},
+	{VFE_CMD_JPEG_OUT_BUF_ENQ, VFE_MAX, VFE_MAX},
+	{VFE_CMD_RAW_OUT_BUF_ENQ, VFE_MAX, VFE_MAX},
+	{VFE_CMD_RAW_IN_BUF_ENQ, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STATS_AF_ENQ, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STATS_AE_ENQ, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STATS_AWB_ENQ, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STATS_RS_ENQ, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STATS_CS_ENQ, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STATS_SKIN_ENQ, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STATS_IHIST_ENQ, VFE_MAX, VFE_MAX},
+	{VFE_CMD_DUMMY_8, VFE_MAX, VFE_MAX},
+	{VFE_CMD_JPEG_ENC_CFG, VFE_MAX, VFE_MAX},
+	{VFE_CMD_DUMMY_9, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STATS_AF_START, VFE_STATS_AUTOFOCUS_CONFIG, QDSP_CMDQUEUE,
+		"VFE_CMD_STATS_AF_START", "VFE_STATS_AUTOFOCUS_CONFIG"},
+	{VFE_CMD_STATS_AF_STOP, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STATS_AE_START, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STATS_AE_STOP, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STATS_AWB_START, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STATS_AWB_STOP, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STATS_RS_START, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STATS_RS_STOP, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STATS_CS_START, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STATS_CS_STOP, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STATS_SKIN_START, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STATS_SKIN_STOP, VFE_MAX, VFE_MAX},
+	{VFE_CMD_STATS_IHIST_START, VFE_STATS_HISTOGRAM_CONFIG, QDSP_CMDQUEUE,
+		"VFE_CMD_STATS_IHIST_START", "VFE_STATS_HISTOGRAM_CONFIG"},
+	{VFE_CMD_STATS_IHIST_STOP, VFE_MAX, VFE_MAX},
+	{VFE_CMD_DUMMY_10, VFE_MAX, VFE_MAX},
+	{VFE_CMD_SYNC_TIMER_SETTING, VFE_MAX, VFE_MAX},
+	{VFE_CMD_ASYNC_TIMER_SETTING, VFE_MAX, VFE_MAX},
+	{VFE_CMD_LIVESHOT, VFE_MAX, VFE_MAX},
+	{VFE_CMD_LA_SETUP, VFE_MAX, VFE_MAX},
+	{VFE_CMD_LINEARIZATION_CFG, VFE_MAX, VFE_MAX},
+	{VFE_CMD_DEMOSAICV3, VFE_DEMOSAICv3_CFG, QDSP_TABLEQUEUE,
+		"VFE_CMD_DEMOSAICV3", "VFE_DEMOSAICv3_CFG"},
+	{VFE_CMD_DEMOSAICV3_ABCC_CFG, VFE_MAX, VFE_MAX},
+	{VFE_CMD_DEMOSAICV3_DBCC_CFG, VFE_MAX, VFE_MAX},
+	{VFE_CMD_DEMOSAICV3_DBPC_CFG, VFE_DEMOSAICv3_BPC_CFG, QDSP_TABLEQUEUE,
+		"VFE_CMD_DEMOSAICV3_DBPC_CFG", "VFE_DEMOSAICv3_BPC_CFG"},
+	{VFE_CMD_DEMOSAICV3_ABF_CFG, VFE_DEMOSAICv3_ABF_CFG, QDSP_TABLEQUEUE,
+		"VFE_CMD_DEMOSAICV3_ABF_CFG", "VFE_DEMOSAICv3_ABF_CFG"},
+	{VFE_CMD_DEMOSAICV3_ABCC_UPDATE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_DEMOSAICV3_DBCC_UPDATE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_DEMOSAICV3_DBPC_UPDATE, VFE_DEMOSAICv3_BPC_UPDATE,
+		QDSP_CMDQUEUE, "VFE_CMD_DEMOSAICV3_DBPC_UPDATE",
+		"VFE_DEMOSAICv3_BPC_UPDATE"},
+	{VFE_CMD_XBAR_CFG, VFE_MAX, VFE_MAX},
+	{VFE_CMD_MODULE_CFG, VFE_MAX, VFE_MAX},
+	{VFE_CMD_ZSL, VFE_MAX, VFE_MAX},
+	{VFE_CMD_LINEARIZATION_UPDATE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_DEMOSAICV3_ABF_UPDATE, VFE_DEMOSAICv3_ABF_CFG,
+		QDSP_TABLEQUEUE, "VFE_CMD_DEMOSAICV3_ABF_UPDATE",
+		"VFE_DEMOSAICv3_ABF_CFG"},
+	{VFE_CMD_CLF_CFG, VFE_MAX, VFE_MAX},
+	{VFE_CMD_CLF_LUMA_UPDATE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_CLF_CHROMA_UPDATE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_PCA_ROLL_OFF_CFG, VFE_MAX, VFE_MAX},
+	{VFE_CMD_PCA_ROLL_OFF_UPDATE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_GET_REG_DUMP, VFE_MAX, VFE_MAX},
+	{VFE_CMD_GET_LINEARIZATON_TABLE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_GET_MESH_ROLLOFF_TABLE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_GET_PCA_ROLLOFF_TABLE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_GET_RGB_G_TABLE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_GET_LA_TABLE, VFE_MAX, VFE_MAX},
+	{VFE_CMD_DEMOSAICV3_UPDATE, VFE_DEMOSAICv3_CFG, QDSP_TABLEQUEUE,
+		"VFE_CMD_DEMOSAICV3_UPDATE", "VFE_DEMOSAICv3_CFG"},
+	{VFE_CMD_ACTIVE_REGION_CFG, VFE_ACTIVE_REGION_CONFIG, QDSP_CMDQUEUE,
+		"VFE_CMD_ACTIVE_REGION_CFG", "VFE_ACTIVE_REGION_CONFIG"},
+	{VFE_CMD_COLOR_PROCESSING_CONFIG, VFE_COLOR_PROCESSING_CONFIG,
+		QDSP_CMDQUEUE, "VFE_CMD_COLOR_PROCESSING_CONFIG",
+		"VFE_COLOR_PROCESSING_CONFIG"},
+	{VFE_CMD_STATS_WB_AEC_CONFIG, VFE_STATS_WB_EXP_CONFIG, QDSP_CMDQUEUE,
+		"VFE_CMD_STATS_WB_AEC_CONFIG", "VFE_STATS_WB_EXP_CONFIG"},
+	{VFE_CMD_STATS_WB_AEC_UPDATE, VFE_STATS_WB_EXP_UPDATE, QDSP_CMDQUEUE,
+		"VFE_CMD_STATS_WB_AEC_UPDATE", "VFE_STATS_WB_EXP_UPDATE"},
+	{VFE_CMD_Y_GAMMA_CONFIG, VFE_Y_GAMMA_CONFIG, QDSP_TABLEQUEUE,
+		"VFE_CMD_Y_GAMMA_CONFIG", "VFE_Y_GAMMA_CONFIG"},
+	{VFE_CMD_SCALE_OUTPUT1_CONFIG, VFE_SCALE_OUTPUT1_CONFIG,
+		QDSP_SCALEQUEUE, "VFE_CMD_SCALE_OUTPUT1_CONFIG",
+		"VFE_SCALE_OUTPUT1_CONFIG"},
+	{VFE_CMD_SCALE_OUTPUT2_CONFIG, VFE_SCALE_OUTPUT2_CONFIG,
+		QDSP_SCALEQUEUE, "VFE_CMD_SCALE_OUTPUT2_CONFIG",
+		"VFE_SCALE_OUTPUT2_CONFIG"},
+};
+
+
+static struct msm_adsp_module *qcam_mod;
+static struct msm_adsp_module *vfe_mod;
+static void *extdata;
+static uint32_t extlen;
+
+struct mutex vfe_lock;
+static void     *vfe_syncdata;
+static uint8_t vfestopped;
+
+static struct stop_event stopevent;
+
+static uint32_t op_mode;
+static uint32_t raw_mode;
+static struct vfe2x_ctrl_type *vfe2x_ctrl;
+
+static void vfe2x_send_isp_msg(
+	struct vfe2x_ctrl_type *vctrl,
+	uint32_t isp_msg_id)
+{
+	struct isp_msg_event isp_msg_evt;
+
+	isp_msg_evt.msg_id = isp_msg_id;
+	isp_msg_evt.sof_count = vfe2x_ctrl->vfeFrameId;
+	v4l2_subdev_notify(&vctrl->subdev,
+			NOTIFY_ISP_MSG_EVT,
+			(void *)&isp_msg_evt);
+}
+
+static void vfe_send_outmsg(struct v4l2_subdev *sd, uint8_t msgid,
+		uint32_t ch0_paddr, uint32_t ch1_paddr)
+{
+	struct isp_msg_output msg;
+
+	msg.output_id = msgid;
+	msg.buf.ch_paddr[0]     = ch0_paddr;
+	msg.buf.ch_paddr[1]     = ch1_paddr;
+	msg.frameCounter = vfe2x_ctrl->vfeFrameId;
+
+	v4l2_subdev_notify(&vfe2x_ctrl->subdev,
+			NOTIFY_VFE_MSG_OUT,
+			&msg);
+	return;
+}
+
+static void vfe_send_stats_msg(uint32_t buf_addr, uint32_t msg_id)
+{
+	struct isp_msg_stats msg_stats;
+
+	msg_stats.frameCounter = vfe2x_ctrl->vfeFrameId;
+	msg_stats.buffer       = buf_addr;
+	msg_stats.id           = msg_id;
+
+	v4l2_subdev_notify(&vfe2x_ctrl->subdev,
+				NOTIFY_VFE_MSG_STATS,
+				&msg_stats);
+}
+
+static void vfe_7x_ops(void *driver_data, unsigned id, size_t len,
+		void (*getevent)(void *ptr, size_t len))
+{
+	uint32_t evt_buf[3];
+	void *data;
+	struct buf_info *outch = NULL;
+	uint32_t y_phy, cbcr_phy;
+	struct table_cmd *table_pending = NULL;
+	unsigned long flags;
+	void   *cmd_data = NULL;
+	unsigned char buf[256];
+	struct msm_free_buf *free_buf = NULL;
+	struct vfe_outputack fack;
+
+	CDBG("%s:id=%d\n", __func__, id);
+
+	if (id != VFE_ADSP_EVENT) {
+		data = kzalloc(len, GFP_KERNEL);
+		if (!data) {
+			pr_err("%s: rp: cannot allocate buffer\n", __func__);
+			return;
+		}
+	}
+	if (id == VFE_ADSP_EVENT) {
+		/* event */
+		getevent(evt_buf, sizeof(evt_buf));
+		CDBG("%s:event:msg_id=%d\n", __func__, id);
+	} else {
+		/* messages */
+		getevent(data, len);
+		CDBG("%s:messages:msg_id=%d\n", __func__, id);
+
+		switch (id) {
+		case MSG_SNAPSHOT:
+			msm_camio_set_perf_lvl(S_PREVIEW);
+			vfe_7x_ops(driver_data, MSG_OUTPUT_S, len, getevent);
+			if (!raw_mode)
+				vfe_7x_ops(driver_data, MSG_OUTPUT_T,
+						len, getevent);
+			vfe2x_send_isp_msg(vfe2x_ctrl, MSG_ID_SNAPSHOT_DONE);
+			return;
+		case MSG_OUTPUT_S:
+			outch = &vfe2x_ctrl->snap;
+			y_phy = outch->ping.ch_paddr[0];
+			cbcr_phy = outch->ping.ch_paddr[1];
+			CDBG("MSG_OUTPUT_S: %x %x\n",
+				(unsigned int)y_phy, (unsigned int)cbcr_phy);
+			vfe_send_outmsg(&vfe2x_ctrl->subdev, MSG_ID_OUTPUT_S,
+							y_phy, cbcr_phy);
+			break;
+		case MSG_OUTPUT_T:
+			outch = &vfe2x_ctrl->thumb;
+			y_phy = outch->ping.ch_paddr[0];
+			cbcr_phy = outch->ping.ch_paddr[1];
+			CDBG("MSG_OUTPUT_T: %x %x\n",
+				(unsigned int)y_phy, (unsigned int)cbcr_phy);
+			vfe_send_outmsg(&vfe2x_ctrl->subdev, MSG_ID_OUTPUT_T,
+							y_phy, cbcr_phy);
+			break;
+		case MSG_OUTPUT1:
+		case MSG_OUTPUT2:
+			if (op_mode & SNAPSHOT_MASK_MODE) {
+				kfree(data);
+				return;
+			} else {
+				free_buf = vfe2x_check_free_buffer(
+					VFE_MSG_OUTPUT_IRQ,
+					VFE_MSG_OUTPUT_P);
+			      CDBG("free_buf = %x\n", (unsigned int) free_buf);
+			      if (free_buf) {
+					fack.header = VFE_OUTPUT2_ACK;
+
+					fack.output2newybufferaddress =
+						(void *)(free_buf->ch_paddr[0]);
+
+					fack.output2newcbcrbufferaddress =
+						(void *)(free_buf->ch_paddr[1]);
+
+					cmd_data = &fack;
+					len = sizeof(fack);
+					msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
+							cmd_data, len);
+			      } else {
+					fack.header = VFE_OUTPUT2_ACK;
+					fack.output2newybufferaddress =
+					(void *)
+				((struct vfe_endframe *)data)->y_address;
+					fack.output2newcbcrbufferaddress =
+					(void *)
+				((struct vfe_endframe *)data)->cbcr_address;
+					cmd_data = &fack;
+					len = sizeof(fack);
+					msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
+						cmd_data, len);
+				}
+			}
+			y_phy = ((struct vfe_endframe *)data)->y_address;
+			cbcr_phy = ((struct vfe_endframe *)data)->cbcr_address;
+
+
+			CDBG("vfe_7x_convert, y_phy = 0x%x, cbcr_phy = 0x%x\n",
+				 y_phy, cbcr_phy);
+
+			memcpy(((struct vfe_frame_extra *)extdata),
+				&((struct vfe_endframe *)data)->extra,
+				sizeof(struct vfe_frame_extra));
+
+			vfe2x_ctrl->vfeFrameId =
+				((struct vfe_frame_extra *)extdata)->frame_id;
+			vfe_send_outmsg(&vfe2x_ctrl->subdev,
+							MSG_ID_OUTPUT_P,
+							y_phy, cbcr_phy);
+			break;
+		case MSG_RESET_ACK:
+		case MSG_START_ACK:
+		case MSG_UPDATE_ACK:
+		case MSG_VFE_ERROR:
+		case MSG_SYNC_TIMER1_DONE:
+		case MSG_SYNC_TIMER2_DONE:
+			vfe2x_send_isp_msg(vfe2x_ctrl, msgs_map[id].isp_id);
+			if (id == MSG_START_ACK)
+				vfe2x_ctrl->vfe_started = 1;
+			break;
+		case MSG_SOF:
+			vfe2x_ctrl->vfeFrameId++;
+			if (vfe2x_ctrl->vfeFrameId == 0)
+				vfe2x_ctrl->vfeFrameId = 1; /* wrapped back */
+			vfe2x_send_isp_msg(vfe2x_ctrl, MSG_ID_SOF_ACK);
+			if (raw_mode)
+				vfe2x_send_isp_msg(vfe2x_ctrl,
+						MSG_ID_START_ACK);
+			break;
+		case MSG_STOP_ACK:
+			stopevent.state = 1;
+			vfe2x_ctrl->vfe_started = 0;
+			wake_up(&stopevent.wait);
+			vfe2x_send_isp_msg(vfe2x_ctrl, MSG_ID_STOP_ACK);
+			break;
+		case MSG_STATS_AF:
+		case MSG_STATS_WE:
+			vfe_send_stats_msg(*(uint32_t *)data,
+						msgs_map[id].isp_id);
+			break;
+		default:
+			vfe2x_send_isp_msg(vfe2x_ctrl, msgs_map[id].isp_id);
+			break;
+		}
+	}
+	if (MSG_TABLE_CMD_ACK == id) {
+		spin_lock_irqsave(&vfe2x_ctrl->table_lock, flags);
+		if (list_empty(&vfe2x_ctrl->table_q)) {
+			if (vfe2x_ctrl->start_pending) {
+				CDBG("Send START\n");
+				cmd_data = buf;
+				*(uint32_t *)cmd_data = VFE_START;
+				memcpy(((char *)cmd_data) + 4,
+					&vfe2x_ctrl->start_cmd,
+					sizeof(vfe2x_ctrl->start_cmd));
+				/* Send Start cmd here */
+				len  = sizeof(vfe2x_ctrl->start_cmd) + 4;
+				msm_adsp_write(vfe_mod, QDSP_CMDQUEUE,
+						cmd_data, len);
+				vfe2x_ctrl->start_pending = 0;
+			}
+			vfe2x_ctrl->tableack_pending = 0;
+			spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
+			return;
+		}
+		table_pending = list_first_entry(&vfe2x_ctrl->table_q,
+					struct table_cmd, list);
+		if (!table_pending) {
+			vfe2x_ctrl->tableack_pending = 0;
+			spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
+			return;
+		}
+		msm_adsp_write(vfe_mod, table_pending->queue,
+				table_pending->cmd, table_pending->size);
+		list_del(&table_pending->list);
+		kfree(table_pending->cmd);
+		vfe2x_ctrl->tableack_pending = 1;
+		spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
+	} else if (!vfe2x_ctrl->tableack_pending) {
+		if (!list_empty(&vfe2x_ctrl->table_q))
+			return;
+	}
+}
+
+static struct msm_adsp_ops vfe_7x_sync = {
+	.event = vfe_7x_ops,
+};
+
+static int vfe_7x_config_axi(int mode,
+	struct buf_info *ad, struct axiout *ao)
+{
+	unsigned long *bptr;
+	int    cnt;
+	int rc = 0;
+
+
+	if (mode == OUTPUT_1) {
+		ao->output1buffer1_y_phy = ad->ping.ch_paddr[0];
+		ao->output1buffer1_cbcr_phy = ad->ping.ch_paddr[1];
+		ao->output1buffer2_y_phy = ad->pong.ch_paddr[0];
+		ao->output1buffer2_cbcr_phy = ad->pong.ch_paddr[1];
+		bptr = &ao->output1buffer3_y_phy;
+		for (cnt = 0; cnt < 6; cnt++) {
+			*bptr = ad->pong.ch_paddr[0];
+			bptr++;
+			*bptr = ad->pong.ch_paddr[1];
+			bptr++;
+		}
+	}
+
+	if (mode == OUTPUT_2) {
+		ao->output2buffer1_y_phy = ad->ping.ch_paddr[0];
+		ao->output2buffer1_cbcr_phy = ad->ping.ch_paddr[1];
+		ao->output2buffer2_y_phy = ad->pong.ch_paddr[0];
+		ao->output2buffer2_cbcr_phy = ad->pong.ch_paddr[1];
+		ao->output2buffer3_y_phy = ad->free_buf.ch_paddr[0];
+		ao->output2buffer3_cbcr_phy = ad->free_buf.ch_paddr[1];
+		bptr = &ao->output2buffer4_y_phy;
+		for (cnt = 0; cnt < 5; cnt++) {
+			*bptr = ad->pong.ch_paddr[0];
+			bptr++;
+			*bptr = ad->pong.ch_paddr[1];
+			bptr++;
+		}
+	}
+
+	if (mode == OUTPUT_1_AND_2) {
+		if (raw_mode) {
+			ao->output2buffer1_y_phy = ad->ping.ch_paddr[0];
+			ao->output2buffer1_cbcr_phy = ad->ping.ch_paddr[0];
+			ao->output2buffer2_y_phy = ad->pong.ch_paddr[0];
+			ao->output2buffer2_cbcr_phy = ad->pong.ch_paddr[0];
+		} else {
+			ao->output2buffer1_y_phy = ad->ping.ch_paddr[0];
+			ao->output2buffer1_cbcr_phy = ad->ping.ch_paddr[1];
+			ao->output2buffer2_y_phy = ad->pong.ch_paddr[0];
+			ao->output2buffer2_cbcr_phy = ad->pong.ch_paddr[1];
+	}
+		bptr = &ao->output2buffer3_y_phy;
+		for (cnt = 0; cnt < 6; cnt++) {
+			*bptr = ad->pong.ch_paddr[0];
+			bptr++;
+			*bptr = ad->pong.ch_paddr[0];
+			bptr++;
+		}
+	}
+
+	return rc;
+}
+
+static void vfe2x_subdev_notify(int id, int path)
+{
+	struct msm_vfe_resp *rp;
+	unsigned long flags = 0;
+	spin_lock_irqsave(&vfe2x_ctrl->sd_notify_lock, flags);
+	rp = msm_isp_sync_alloc(sizeof(struct msm_vfe_resp), GFP_ATOMIC);
+	if (!rp) {
+		CDBG("rp: cannot allocate buffer\n");
+		return;
+	}
+	CDBG("vfe2x_subdev_notify : msgId = %d\n", id);
+	rp->evt_msg.type   = MSM_CAMERA_MSG;
+	rp->evt_msg.msg_id = path;
+	rp->type	   = id;
+	v4l2_subdev_notify(&vfe2x_ctrl->subdev, NOTIFY_VFE_BUF_EVT, rp);
+	spin_unlock_irqrestore(&vfe2x_ctrl->sd_notify_lock, flags);
+}
+
+static struct msm_free_buf *vfe2x_check_free_buffer(int id, int path)
+{
+	struct buf_info *outch = NULL;
+
+	vfe2x_subdev_notify(id, path);
+	if (op_mode & SNAPSHOT_MASK_MODE) {
+		if (path == VFE_MSG_OUTPUT_S)
+			outch = &vfe2x_ctrl->snap;
+		else if (path == VFE_MSG_OUTPUT_T)
+			outch = &vfe2x_ctrl->thumb;
+	} else {
+		if (path == VFE_MSG_OUTPUT_P)
+			outch = &vfe2x_ctrl->prev;
+	}
+	if (outch->free_buf.ch_paddr[0])
+		return &outch->free_buf;
+
+	return NULL;
+}
+
+static int vfe2x_configure_pingpong_buffers(int id, int path)
+{
+	struct buf_info *outch = NULL;
+	int rc = 0;
+
+	vfe2x_subdev_notify(id, path);
+
+	CDBG("Opmode = %d\n", op_mode);
+	if (op_mode & SNAPSHOT_MASK_MODE) {
+		if (path == VFE_MSG_OUTPUT_S)
+			outch = &vfe2x_ctrl->snap;
+		else if (path == VFE_MSG_OUTPUT_T)
+			outch = &vfe2x_ctrl->thumb;
+	} else {
+		if (path == VFE_MSG_OUTPUT_P)
+			outch = &vfe2x_ctrl->prev;
+	}
+	if (outch->ping.ch_paddr[0] && outch->pong.ch_paddr[0]) {
+		/* Configure Preview Ping Pong */
+		CDBG("%s Configure ping/pong address for %d",
+						__func__, path);
+	} else {
+		pr_err("%s ping/pong addr is null!!", __func__);
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static struct buf_info *vfe2x_get_ch(int path)
+{
+	struct buf_info *ch = NULL;
+
+	CDBG("path = %d op_mode = %d\n", path, op_mode);
+	if (op_mode & SNAPSHOT_MASK_MODE) {
+		if (path == VFE_MSG_OUTPUT_T)
+			ch = &vfe2x_ctrl->thumb;
+		else if (path == VFE_MSG_OUTPUT_S)
+			ch = &vfe2x_ctrl->snap;
+	} else {
+		if (path == VFE_MSG_OUTPUT_P)
+			ch = &vfe2x_ctrl->prev;
+	}
+
+	BUG_ON(ch == NULL);
+	return ch;
+}
+
+static long msm_vfe_subdev_ioctl(struct v4l2_subdev *sd,
+			unsigned int subdev_cmd, void *arg)
+{
+	struct msm_isp_cmd vfecmd;
+	struct msm_camvfe_params *vfe_params =
+		(struct msm_camvfe_params *)arg;
+	struct msm_vfe_cfg_cmd *cmd = vfe_params->vfe_cfg;
+	struct table_cmd *table_pending;
+	long rc = 0;
+	void *data = vfe_params->data;
+
+	struct msm_pmem_region *regptr;
+	unsigned char buf[256];
+
+	struct vfe_stats_ack sack;
+	struct axidata *axid;
+	uint32_t i;
+	uint32_t header = 0;
+	uint32_t queue = 0;
+	struct vfe_stats_we_cfg *scfg = NULL;
+	struct vfe_stats_af_cfg *sfcfg = NULL;
+
+	struct axiout *axio = NULL;
+	void   *cmd_data = NULL;
+	void   *cmd_data_alloc = NULL;
+	unsigned long flags;
+	struct msm_free_buf *free_buf = NULL;
+	struct vfe_outputack fack;
+
+	CDBG("msm_vfe_subdev_ioctl is called\n");
+	if (cmd->cmd_type != CMD_FRAME_BUF_RELEASE &&
+	    cmd->cmd_type != CMD_STATS_BUF_RELEASE &&
+	    cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE &&
+		cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
+		cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
+		cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
+		cmd->cmd_type != CMD_VFE_BUFFER_RELEASE) {
+		if (copy_from_user(&vfecmd,
+				(void __user *)(cmd->value),
+				sizeof(vfecmd))) {
+			pr_err("copy_from_user in msm_vfe_subdev_ioctl fail\n");
+			return -EFAULT;
+		}
+	}
+
+	switch (cmd->cmd_type) {
+	case CMD_VFE_BUFFER_RELEASE: {
+		if (!(vfe2x_ctrl->vfe_started) || op_mode == 1)
+			return 0;
+		if (op_mode & SNAPSHOT_MASK_MODE) {
+			free_buf = vfe2x_check_free_buffer(
+					VFE_MSG_OUTPUT_IRQ,
+					VFE_MSG_OUTPUT_T);
+		} else {
+			free_buf = vfe2x_check_free_buffer(
+					VFE_MSG_OUTPUT_IRQ,
+					VFE_MSG_OUTPUT_P);
+			if (free_buf) {
+				fack.header = VFE_OUTPUT2_ACK;
+
+				fack.output2newybufferaddress =
+						(void *)(free_buf->ch_paddr[0]);
+
+				fack.output2newcbcrbufferaddress =
+						(void *)(free_buf->ch_paddr[1]);
+
+				cmd_data = &fack;
+				vfecmd.length = sizeof(fack) - 4;
+				queue = QDSP_CMDQUEUE;
+			}
+		}
+	}
+	break;
+	case CMD_CONFIG_PING_ADDR: {
+		int path = *((int *)cmd->value);
+		struct buf_info *outch = vfe2x_get_ch(path);
+		outch->ping = *((struct msm_free_buf *)data);
+	}
+		return 0;
+	case CMD_CONFIG_PONG_ADDR: {
+		int path = *((int *)cmd->value);
+		struct buf_info *outch = vfe2x_get_ch(path);
+		outch->pong = *((struct msm_free_buf *)data);
+	}
+		return 0;
+
+	case CMD_CONFIG_FREE_BUF_ADDR: {
+		int path = *((int *)cmd->value);
+		struct buf_info *outch = vfe2x_get_ch(path);
+		outch->free_buf = *((struct msm_free_buf *)data);
+	}
+		return 0;
+
+	case CMD_STATS_AEC_AWB_ENABLE:
+	case CMD_STATS_AXI_CFG: {
+		axid = data;
+		if (!axid) {
+			rc = -EFAULT;
+			goto config_failure;
+		}
+
+		scfg =
+			kmalloc(sizeof(struct vfe_stats_we_cfg),
+				GFP_ATOMIC);
+		if (!scfg) {
+			rc = -ENOMEM;
+			goto config_failure;
+		}
+
+		if (copy_from_user((char *)scfg + 4,
+					(void __user *)(vfecmd.value),
+					vfecmd.length)) {
+
+			rc = -EFAULT;
+			goto config_done;
+		}
+
+		CDBG("STATS_ENABLE: bufnum = %d, enabling = %d\n",
+			axid->bufnum1, scfg->wb_expstatsenable);
+
+		header = cmds_map[vfecmd.id].vfe_id;
+		queue = cmds_map[vfecmd.id].queue;
+		if (header == -1 && queue == -1) {
+			rc = -EFAULT;
+			goto config_failure;
+		}
+		*(uint32_t *)scfg = header;
+		if (axid->bufnum1 > 0) {
+			regptr = axid->region;
+
+			for (i = 0; i < axid->bufnum1; i++) {
+
+				CDBG("STATS_ENABLE, phy = 0x%lx\n",
+					regptr->paddr);
+
+				scfg->wb_expstatoutputbuffer[i] =
+					(void *)regptr->paddr;
+				regptr++;
+			}
+
+			cmd_data = scfg;
+
+		} else {
+			rc = -EINVAL;
+			goto config_done;
+		}
+	}
+		break;
+	case CMD_STATS_AF_ENABLE:
+	case CMD_STATS_AF_AXI_CFG: {
+		axid = data;
+		if (!axid) {
+			rc = -EFAULT;
+			goto config_failure;
+		}
+
+		sfcfg =
+			kmalloc(sizeof(struct vfe_stats_af_cfg),
+				GFP_ATOMIC);
+
+		if (!sfcfg) {
+			rc = -ENOMEM;
+			goto config_failure;
+		}
+
+		if (copy_from_user((char *)sfcfg + 4,
+					(void __user *)(vfecmd.value),
+					vfecmd.length)) {
+
+			rc = -EFAULT;
+			goto config_done;
+		}
+
+		CDBG("AF_ENABLE: bufnum = %d, enabling = %d\n",
+			axid->bufnum1, sfcfg->af_enable);
+
+		header = cmds_map[vfecmd.id].vfe_id;
+		queue = cmds_map[vfecmd.id].queue;
+		if (header == -1 && queue == -1) {
+			rc = -EFAULT;
+			goto config_failure;
+		}
+		*(uint32_t *)sfcfg = header;
+		if (axid->bufnum1 > 0) {
+			regptr = &axid->region[0];
+
+			for (i = 0; i < axid->bufnum1; i++) {
+
+				CDBG("STATS_ENABLE, phy = 0x%lx\n",
+					regptr->paddr);
+
+				sfcfg->af_outbuf[i] =
+					(void *)regptr->paddr;
+
+				regptr++;
+			}
+
+			cmd_data = sfcfg;
+
+		} else {
+			rc = -EINVAL;
+			goto config_done;
+		}
+	}
+		break;
+	case CMD_SNAP_BUF_RELEASE:
+		break;
+	case CMD_STATS_BUF_RELEASE: {
+		CDBG("vfe_7x_config: CMD_STATS_BUF_RELEASE\n");
+		if (!data) {
+			rc = -EFAULT;
+			goto config_failure;
+		}
+
+		sack.header = VFE_STATS_WB_EXP_ACK;
+		sack.bufaddr = (void *)*(uint32_t *)data;
+
+		queue  = QDSP_CMDQUEUE;
+		vfecmd.length = sizeof(struct vfe_stats_ack) - 4;
+		cmd_data = &sack;
+	}
+		break;
+	case CMD_STATS_AF_BUF_RELEASE: {
+		CDBG("vfe_7x_config: CMD_STATS_AF_BUF_RELEASE\n");
+		if (!data) {
+			rc = -EFAULT;
+			goto config_failure;
+		}
+
+		sack.header = VFE_STATS_AUTOFOCUS_ACK;
+		sack.bufaddr = (void *)*(uint32_t *)data;
+
+		queue  = QDSP_CMDQUEUE;
+		vfecmd.length = sizeof(struct vfe_stats_ack) - 4;
+		cmd_data = &sack;
+	}
+		break;
+	case CMD_GENERAL:
+	case CMD_STATS_DISABLE: {
+		CDBG("CMD_GENERAL:%d %d\n", vfecmd.id, vfecmd.length);
+		if (vfecmd.id == VFE_CMD_OPERATION_CFG) {
+			if (copy_from_user(&vfe2x_ctrl->start_cmd,
+						(void __user *)(vfecmd.value),
+							vfecmd.length))
+				rc = -EFAULT;
+			op_mode = vfe2x_ctrl->start_cmd.mode_of_operation;
+			return rc;
+		}
+		if (vfecmd.length > 256 - 4) {
+			cmd_data_alloc =
+			cmd_data = kmalloc(vfecmd.length + 4, GFP_ATOMIC);
+			if (!cmd_data) {
+				rc = -ENOMEM;
+				goto config_failure;
+			}
+		} else
+			cmd_data = buf;
+
+		if (copy_from_user(((char *)cmd_data) + 4,
+					(void __user *)(vfecmd.value),
+					vfecmd.length)) {
+
+			rc = -EFAULT;
+			goto config_done;
+		}
+		header = cmds_map[vfecmd.id].vfe_id;
+		queue = cmds_map[vfecmd.id].queue;
+		if (header == -1 && queue == -1) {
+			rc = -EFAULT;
+			goto config_done;
+		}
+		CDBG("%s %s\n", cmds_map[vfecmd.id].isp_id_name,
+			cmds_map[vfecmd.id].vfe_id_name);
+		*(uint32_t *)cmd_data = header;
+		if (queue == QDSP_CMDQUEUE) {
+			switch (vfecmd.id) {
+			case VFE_CMD_RESET:
+				msm_adsp_enable(qcam_mod);
+				msm_adsp_enable(vfe_mod);
+				msm_camio_vfe_blk_reset();
+				vfestopped = 0;
+				break;
+			case VFE_CMD_START:
+			case VFE_CMD_CAPTURE:
+				spin_lock_irqsave(&vfe2x_ctrl->table_lock,
+									flags);
+				if (!list_empty(&vfe2x_ctrl->table_q)) {
+					vfe2x_ctrl->start_pending = 1;
+					spin_unlock_irqrestore(
+						&vfe2x_ctrl->table_lock,
+								flags);
+					return 0;
+				}
+				spin_unlock_irqrestore(&vfe2x_ctrl->table_lock,
+									flags);
+				vfecmd.length = sizeof(vfe2x_ctrl->start_cmd);
+				memcpy(((char *)cmd_data) + 4,
+					&vfe2x_ctrl->start_cmd,
+					sizeof(vfe2x_ctrl->start_cmd));
+				if (op_mode & SNAPSHOT_MASK_MODE)
+					msm_camio_set_perf_lvl(S_CAPTURE);
+				else
+					msm_camio_set_perf_lvl(S_PREVIEW);
+				vfestopped = 0;
+				break;
+			case VFE_CMD_STOP:
+				vfestopped = 1;
+				vfe2x_ctrl->vfe_started = 0;
+				goto config_send;
+
+			default:
+				break;
+			}
+		} /* QDSP_CMDQUEUE */
+	}
+		break;
+	case CMD_AXI_CFG_PREVIEW: {
+		CDBG("CMD_AXI_CFG_PREVIEW\n");
+		raw_mode = 0;
+		axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
+		if (!axio) {
+			pr_err("NULL axio\n");
+			rc = -ENOMEM;
+			goto config_failure;
+		}
+
+		if (copy_from_user((char *)axio + 4,
+					(void __user *)(vfecmd.value),
+					sizeof(struct axiout))) {
+			pr_err("copy_from_user failed\n");
+			rc = -EFAULT;
+			goto config_done;
+		}
+		rc = vfe2x_configure_pingpong_buffers(VFE_MSG_V2X_PREVIEW,
+							VFE_MSG_OUTPUT_P);
+		if (rc < 0) {
+			pr_err("%s error configuring pingpong buffers"
+				" for preview", __func__);
+			rc = -EINVAL;
+			goto config_done;
+		}
+
+		free_buf = vfe2x_check_free_buffer(
+					VFE_MSG_OUTPUT_IRQ,
+					VFE_MSG_OUTPUT_P);
+		header = cmds_map[vfecmd.id].vfe_id;
+		queue = cmds_map[vfecmd.id].queue;
+		if (header == -1 && queue == -1) {
+			rc = -EFAULT;
+			goto config_done;
+		}
+		*(uint32_t *)axio = header;
+		vfe_7x_config_axi(OUTPUT_2, &vfe2x_ctrl->prev, axio);
+		cmd_data = axio;
+	}
+		break;
+	case CMD_RAW_PICT_AXI_CFG: {
+		CDBG("CMD_RAW_PICT_AXI_CFG:%d\n", op_mode);
+		raw_mode = 1;
+		axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
+		if (!axio) {
+			rc = -ENOMEM;
+			goto config_failure;
+		}
+
+		if (copy_from_user((char *)axio + 4,
+					(void __user *)(vfecmd.value),
+					sizeof(struct axiout))) {
+			rc = -EFAULT;
+			goto config_done;
+		}
+		header = cmds_map[vfecmd.id].vfe_id;
+		queue = cmds_map[vfecmd.id].queue;
+		rc = vfe2x_configure_pingpong_buffers(VFE_MSG_V2X_CAPTURE,
+							VFE_MSG_OUTPUT_S);
+		if (rc < 0) {
+			pr_err("%s error configuring pingpong buffers"
+				" for preview", __func__);
+			rc = -EINVAL;
+			goto config_done;
+		}
+		if (header == -1 && queue == -1) {
+			rc = -EFAULT;
+			goto config_done;
+		}
+		*(uint32_t *)axio = header;
+		vfe_7x_config_axi(OUTPUT_1_AND_2, &vfe2x_ctrl->snap, axio);
+		cmd_data = axio;
+	}
+		break;
+	case CMD_AXI_CFG_SNAP: {
+		raw_mode = 0;
+		CDBG("CMD_AXI_CFG_SNAP :%d\n", op_mode);
+		axio = kmalloc(sizeof(struct axiout), GFP_ATOMIC);
+		if (!axio) {
+			rc = -ENOMEM;
+			goto config_failure;
+		}
+
+		if (copy_from_user((char *)axio + 4,
+					(void __user *)(vfecmd.value),
+					sizeof(struct axiout))) {
+			rc = -EFAULT;
+			goto config_done;
+		}
+		header = cmds_map[vfecmd.id].vfe_id;
+		queue = cmds_map[vfecmd.id].queue;
+		rc = vfe2x_configure_pingpong_buffers(VFE_MSG_V2X_CAPTURE,
+							VFE_MSG_OUTPUT_S);
+		if (rc < 0) {
+			pr_err("%s error configuring pingpong buffers"
+				" for preview", __func__);
+			rc = -EINVAL;
+			goto config_done;
+		}
+		if (header == -1 && queue == -1) {
+			rc = -EFAULT;
+			goto config_done;
+		}
+		*(uint32_t *)axio = header;
+		vfe_7x_config_axi(OUTPUT_1_AND_2, &vfe2x_ctrl->snap, axio);
+		rc = vfe2x_configure_pingpong_buffers(VFE_MSG_V2X_CAPTURE,
+							VFE_MSG_OUTPUT_T);
+		if (rc < 0) {
+			pr_err("%s error configuring pingpong buffers"
+				" for preview", __func__);
+			rc = -EINVAL;
+			goto config_done;
+		}
+		vfe_7x_config_axi(OUTPUT_1, &vfe2x_ctrl->thumb, axio);
+		cmd_data = axio;
+	}
+		break;
+	default:
+		break;
+	}
+
+	if (vfestopped)
+		goto config_done;
+
+config_send:
+	CDBG("send adsp command = %d\n", *(uint32_t *)cmd_data);
+	if (queue == QDSP_TABLEQUEUE &&
+			vfe2x_ctrl->tableack_pending) {
+		table_pending = kzalloc(sizeof(struct table_cmd), GFP_ATOMIC);
+		if (!table_pending) {
+			rc = -ENOMEM;
+			goto config_done;
+		}
+		table_pending->cmd = kzalloc(vfecmd.length + 4, GFP_ATOMIC);
+		if (!table_pending->cmd) {
+			kfree(table_pending);
+			rc = -ENOMEM;
+			goto config_done;
+		}
+		memcpy(table_pending->cmd, cmd_data, vfecmd.length + 4);
+		table_pending->queue = queue;
+		table_pending->size = vfecmd.length + 4;
+		spin_lock_irqsave(&vfe2x_ctrl->table_lock, flags);
+		list_add_tail(&table_pending->list, &vfe2x_ctrl->table_q);
+		spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
+	} else {
+		if (queue == QDSP_TABLEQUEUE) {
+			spin_lock_irqsave(&vfe2x_ctrl->table_lock, flags);
+			rc = msm_adsp_write(vfe_mod, queue,
+				cmd_data, vfecmd.length + 4);
+			vfe2x_ctrl->tableack_pending = 1;
+			spin_unlock_irqrestore(&vfe2x_ctrl->table_lock, flags);
+		} else {
+			if (*(uint32_t *)cmd_data == VFE_OUTPUT2_ACK) {
+				uint32_t *ptr = cmd_data;
+				CDBG("%x %x %x\n", ptr[0], ptr[1], ptr[2]);
+			}
+			rc = msm_adsp_write(vfe_mod, queue,
+				cmd_data, vfecmd.length + 4);
+			CDBG("%x\n", vfecmd.length + 4);
+		}
+	}
+
+config_done:
+	kfree(cmd_data_alloc);
+
+config_failure:
+	kfree(scfg);
+	kfree(axio);
+	return rc;
+}
+
+static struct msm_cam_clk_info vfe2x_clk_info[] = {
+	{"vfe_clk", 192000000},
+};
+
+int msm_vfe_subdev_init(struct v4l2_subdev *sd, void *data,
+	struct platform_device *pdev)
+{
+	int rc = 0;
+	v4l2_set_subdev_hostdata(sd, data);
+	vfe_syncdata = data;
+
+	spin_lock_init(&vfe2x_ctrl->sd_notify_lock);
+	spin_lock_init(&vfe2x_ctrl->table_lock);
+	spin_lock_init(&vfe2x_ctrl->vfe_msg_lock);
+	init_waitqueue_head(&stopevent.wait);
+	INIT_LIST_HEAD(&vfe2x_ctrl->table_q);
+	INIT_LIST_HEAD(&vfe2x_ctrl->vfe_msg_q);
+	stopevent.timeout = 200;
+	stopevent.state = 0;
+	vfe2x_ctrl->vfe_started = 0;
+
+
+	CDBG("msm_cam_clk_enable: enable vfe_clk\n");
+	rc = msm_cam_clk_enable(&vfe2x_ctrl->pdev->dev, vfe2x_clk_info,
+			vfe2x_ctrl->vfe_clk, ARRAY_SIZE(vfe2x_clk_info), 1);
+	if (rc < 0)
+		return rc;
+
+	msm_camio_set_perf_lvl(S_INIT);
+
+	/* TODO : check is it required */
+	extlen = sizeof(struct vfe_frame_extra);
+
+	extdata = kmalloc(extlen, GFP_ATOMIC);
+	if (!extdata) {
+		rc = -ENOMEM;
+		goto init_fail;
+	}
+
+	rc = msm_adsp_get("QCAMTASK", &qcam_mod, &vfe_7x_sync, NULL);
+	if (rc) {
+		rc = -EBUSY;
+		goto get_qcam_fail;
+	}
+
+	rc = msm_adsp_get("VFETASK", &vfe_mod, &vfe_7x_sync, NULL);
+	if (rc) {
+		rc = -EBUSY;
+		goto get_vfe_fail;
+	}
+	return 0;
+
+get_vfe_fail:
+	msm_adsp_put(qcam_mod);
+get_qcam_fail:
+	kfree(extdata);
+init_fail:
+	extlen = 0;
+	return rc;
+}
+
+int msm_vpe_subdev_init(struct v4l2_subdev *sd, void *data,
+	struct platform_device *pdev)
+{
+	return 0;
+}
+
+void msm_vpe_subdev_release(struct platform_device *pdev)
+{
+	return;
+}
+
+void msm_vfe_subdev_release(struct platform_device *pdev)
+{
+	msm_cam_clk_enable(&vfe2x_ctrl->pdev->dev, vfe2x_clk_info,
+			vfe2x_ctrl->vfe_clk, ARRAY_SIZE(vfe2x_clk_info), 0);
+	vfe_syncdata = NULL;
+
+	msm_adsp_disable(qcam_mod);
+	msm_adsp_disable(vfe_mod);
+
+	msm_adsp_put(qcam_mod);
+	msm_adsp_put(vfe_mod);
+
+	kfree(extdata);
+	msm_camio_set_perf_lvl(S_EXIT);
+	return;
+}
+
+static const struct v4l2_subdev_core_ops msm_vfe_subdev_core_ops = {
+	.ioctl = msm_vfe_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_vfe_subdev_ops = {
+	.core = &msm_vfe_subdev_core_ops,
+};
+
+static int __devinit vfe2x_probe(struct platform_device *pdev)
+{
+	CDBG("%s: device id = %d\n", __func__, pdev->id);
+	vfe2x_ctrl = kzalloc(sizeof(struct vfe2x_ctrl_type), GFP_KERNEL);
+	if (!vfe2x_ctrl) {
+		pr_err("%s: no enough memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	v4l2_subdev_init(&vfe2x_ctrl->subdev, &msm_vfe_subdev_ops);
+	snprintf(vfe2x_ctrl->subdev.name,
+			 sizeof(vfe2x_ctrl->subdev.name), "vfe2.x");
+	v4l2_set_subdevdata(&vfe2x_ctrl->subdev, vfe2x_ctrl);
+	platform_set_drvdata(pdev, &vfe2x_ctrl->subdev);
+
+	vfe2x_ctrl->pdev = pdev;
+	return 0;
+}
+
+static struct platform_driver vfe2x_driver = {
+	.probe = vfe2x_probe,
+	.driver = {
+		.name = MSM_VFE_DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_vfe2x_init_module(void)
+{
+	return platform_driver_register(&vfe2x_driver);
+}
+
+static void __exit msm_vfe2x_exit_module(void)
+{
+	platform_driver_unregister(&vfe2x_driver);
+}
+
+module_init(msm_vfe2x_init_module);
+module_exit(msm_vfe2x_exit_module);
+MODULE_DESCRIPTION("VFE 2.x driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.h b/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
new file mode 100644
index 0000000..0f7fb60
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.h
@@ -0,0 +1,385 @@
+/* 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_VFE7X_H__
+#define __MSM_VFE7X_H__
+#include <media/msm_camera.h>
+#include <mach/camera.h>
+#include <linux/list.h>
+#include "msm.h"
+
+struct cmd_id_map {
+	uint32_t isp_id;
+	uint32_t vfe_id;
+	uint32_t queue;
+	char isp_id_name[64];
+	char vfe_id_name[64];
+} __packed;
+
+struct msg_id_map {
+	uint32_t vfe_id;
+	uint32_t isp_id;
+} __packed;
+
+struct table_cmd {
+	struct list_head list;
+	void *cmd;
+	int size;
+	int queue;
+} __packed;
+
+struct vfe_msg {
+	struct list_head list;
+	void *cmd;
+	int len;
+	int id;
+} __packed;
+
+struct buf_info {
+	/* Buffer */
+	struct msm_free_buf ping;
+	struct msm_free_buf pong;
+	struct msm_free_buf free_buf;
+} __packed;
+
+struct vfe_cmd_start {
+	uint32_t input_source:1;
+	uint32_t mode_of_operation:1;
+	uint32_t snap_number:4;
+	uint32_t /* reserved */ : 26;
+
+	/* Image Pipeline Modules */
+	uint32_t blacklevel_correction_enable:1;
+	uint32_t lens_rolloff_correction_enable:1;
+	uint32_t white_balance_enable:1;
+	uint32_t rgb_gamma_enable:1;
+	uint32_t luma_noise_reductionpath_enable:1;
+	uint32_t adaptive_spatialfilter_enable:1;
+	uint32_t chroma_subsample_enable:1;
+	uint32_t /* reserved */ : 25;
+
+	/* The dimension fed to the statistics module */
+	uint32_t last_pixel:12;
+	uint32_t /* reserved */ : 4;
+	uint32_t last_line:12;
+	uint32_t /* reserved */ : 4;
+} __packed;
+
+struct vfe2x_ctrl_type {
+	struct buf_info prev;
+	struct buf_info snap;
+	struct buf_info raw;
+	struct buf_info thumb;
+
+	spinlock_t  table_lock;
+	struct list_head table_q;
+	uint32_t tableack_pending;
+	uint32_t vfeFrameId;
+
+	spinlock_t vfe_msg_lock;
+	struct list_head vfe_msg_q;
+
+	struct vfe_cmd_start start_cmd;
+	uint32_t start_pending;
+	uint32_t vfe_started;
+
+	/* v4l2 subdev */
+	struct v4l2_subdev subdev;
+	struct platform_device *pdev;
+	struct clk *vfe_clk[3];
+	spinlock_t  sd_notify_lock;
+} __packed;
+
+struct vfe_frame_extra {
+	uint32_t	bl_evencol:23;
+	uint32_t	rvd1:9;
+	uint32_t	bl_oddcol:23;
+	uint32_t	rvd2:9;
+
+	uint32_t	d_dbpc_stats_hot:16;
+	uint32_t	d_dbpc_stats_cold:16;
+
+	uint32_t	d_dbpc_stats_0_hot:10;
+	uint32_t	rvd3:6;
+	uint32_t	d_dbpc_stats_0_cold:10;
+	uint32_t	rvd4:6;
+	uint32_t	d_dbpc_stats_1_hot:10;
+	uint32_t	rvd5:6;
+	uint32_t	d_dbpc_stats_1_cold:10;
+	uint32_t	rvd6:6;
+
+	uint32_t	asf_max_edge;
+
+	uint32_t	e_y_wm_pm_stats_0:21;
+	uint32_t	rvd7:11;
+	uint32_t	e_y_wm_pm_stats_1_bl:8;
+	uint32_t	rvd8:8;
+	uint32_t	e_y_wm_pm_stats_1_nl:12;
+	uint32_t	rvd9:4;
+
+	uint32_t	e_cbcr_wm_pm_stats_0:21;
+	uint32_t	rvd10:11;
+	uint32_t	e_cbcr_wm_pm_stats_1_bl:8;
+	uint32_t	rvd11:8;
+	uint32_t	e_cbcr_wm_pm_stats_1_nl:12;
+	uint32_t	rvd12:4;
+
+	uint32_t	v_y_wm_pm_stats_0:21;
+	uint32_t	rvd13:11;
+	uint32_t	v_y_wm_pm_stats_1_bl:8;
+	uint32_t	rvd14:8;
+	uint32_t	v_y_wm_pm_stats_1_nl:12;
+	uint32_t	rvd15:4;
+
+	uint32_t	v_cbcr_wm_pm_stats_0:21;
+	uint32_t	rvd16:11;
+	uint32_t	v_cbcr_wm_pm_stats_1_bl:8;
+	uint32_t	rvd17:8;
+	uint32_t	v_cbcr_wm_pm_stats_1_nl:12;
+	uint32_t	rvd18:4;
+
+	uint32_t      frame_id;
+} __packed;
+
+struct vfe_endframe {
+	uint32_t      y_address;
+	uint32_t      cbcr_address;
+
+	struct vfe_frame_extra extra;
+} __packed;
+
+struct vfe_outputack {
+	uint32_t  header;
+	void      *output2newybufferaddress;
+	void      *output2newcbcrbufferaddress;
+} __packed;
+
+struct vfe_stats_ack {
+	uint32_t header;
+	/* MUST BE 64 bit ALIGNED */
+	void     *bufaddr;
+} __packed;
+
+/* AXI Output Config Command sent to DSP */
+struct axiout {
+	uint32_t            cmdheader:32;
+	int                 outputmode:3;
+	uint8_t             format:2;
+	uint32_t            /* reserved */ : 27;
+
+	/* AXI Output 1 Y Configuration, Part 1 */
+	uint32_t            out1yimageheight:12;
+	uint32_t            /* reserved */ : 4;
+	uint32_t            out1yimagewidthin64bitwords:10;
+	uint32_t            /* reserved */ : 6;
+
+	/* AXI Output 1 Y Configuration, Part 2 */
+	uint8_t             out1yburstlen:2;
+	uint32_t            out1ynumrows:12;
+	uint32_t            out1yrowincin64bitincs:12;
+	uint32_t            /* reserved */ : 6;
+
+	/* AXI Output 1 CbCr Configuration, Part 1 */
+	uint32_t            out1cbcrimageheight:12;
+	uint32_t            /* reserved */ : 4;
+	uint32_t            out1cbcrimagewidthin64bitwords:10;
+	uint32_t            /* reserved */ : 6;
+
+	/* AXI Output 1 CbCr Configuration, Part 2 */
+	uint8_t             out1cbcrburstlen:2;
+	uint32_t            out1cbcrnumrows:12;
+	uint32_t            out1cbcrrowincin64bitincs:12;
+	uint32_t            /* reserved */ : 6;
+
+	/* AXI Output 2 Y Configuration, Part 1 */
+	uint32_t            out2yimageheight:12;
+	uint32_t            /* reserved */ : 4;
+	uint32_t            out2yimagewidthin64bitwords:10;
+	uint32_t            /* reserved */ : 6;
+
+	/* AXI Output 2 Y Configuration, Part 2 */
+	uint8_t             out2yburstlen:2;
+	uint32_t            out2ynumrows:12;
+	uint32_t            out2yrowincin64bitincs:12;
+	uint32_t            /* reserved */ : 6;
+
+	/* AXI Output 2 CbCr Configuration, Part 1 */
+	uint32_t            out2cbcrimageheight:12;
+	uint32_t            /* reserved */ : 4;
+	uint32_t            out2cbcrimagewidtein64bitwords:10;
+	uint32_t            /* reserved */ : 6;
+
+	/* AXI Output 2 CbCr Configuration, Part 2 */
+	uint8_t             out2cbcrburstlen:2;
+	uint32_t            out2cbcrnumrows:12;
+	uint32_t            out2cbcrrowincin64bitincs:12;
+	uint32_t            /* reserved */ : 6;
+
+	/* Address configuration:
+	 * output1 phisycal address */
+	unsigned long   output1buffer1_y_phy;
+	unsigned long   output1buffer1_cbcr_phy;
+	unsigned long   output1buffer2_y_phy;
+	unsigned long   output1buffer2_cbcr_phy;
+	unsigned long   output1buffer3_y_phy;
+	unsigned long   output1buffer3_cbcr_phy;
+	unsigned long   output1buffer4_y_phy;
+	unsigned long   output1buffer4_cbcr_phy;
+	unsigned long   output1buffer5_y_phy;
+	unsigned long   output1buffer5_cbcr_phy;
+	unsigned long   output1buffer6_y_phy;
+	unsigned long   output1buffer6_cbcr_phy;
+	unsigned long   output1buffer7_y_phy;
+	unsigned long   output1buffer7_cbcr_phy;
+	unsigned long   output1buffer8_y_phy;
+	unsigned long   output1buffer8_cbcr_phy;
+
+	/* output2 phisycal address */
+	unsigned long   output2buffer1_y_phy;
+	unsigned long   output2buffer1_cbcr_phy;
+	unsigned long   output2buffer2_y_phy;
+	unsigned long   output2buffer2_cbcr_phy;
+	unsigned long   output2buffer3_y_phy;
+	unsigned long   output2buffer3_cbcr_phy;
+	unsigned long   output2buffer4_y_phy;
+	unsigned long   output2buffer4_cbcr_phy;
+	unsigned long   output2buffer5_y_phy;
+	unsigned long   output2buffer5_cbcr_phy;
+	unsigned long   output2buffer6_y_phy;
+	unsigned long   output2buffer6_cbcr_phy;
+	unsigned long   output2buffer7_y_phy;
+	unsigned long   output2buffer7_cbcr_phy;
+	unsigned long   output2buffer8_y_phy;
+	unsigned long   output2buffer8_cbcr_phy;
+} __packed;
+
+struct vfe_stats_we_cfg {
+	uint32_t       header;
+
+	/* White Balance/Exposure Statistic Selection */
+	uint8_t        wb_expstatsenable:1;
+	uint8_t        wb_expstatbuspriorityselection:1;
+	unsigned int   wb_expstatbuspriorityvalue:4;
+	unsigned int   /* reserved */ : 26;
+
+	/* White Balance/Exposure Statistic Configuration, Part 1 */
+	uint8_t        exposurestatregions:1;
+	uint8_t        exposurestatsubregions:1;
+	unsigned int   /* reserved */ : 14;
+
+	unsigned int   whitebalanceminimumy:8;
+	unsigned int   whitebalancemaximumy:8;
+
+	/* White Balance/Exposure Statistic Configuration, Part 2 */
+	uint8_t wb_expstatslopeofneutralregionline[
+		NUM_WB_EXP_NEUTRAL_REGION_LINES];
+
+	/* White Balance/Exposure Statistic Configuration, Part 3 */
+	unsigned int   wb_expstatcrinterceptofneutralregionline2:12;
+	unsigned int   /* reserved */ : 4;
+	unsigned int   wb_expstatcbinterceptofneutralreginnline1:12;
+	unsigned int    /* reserved */ : 4;
+
+	/* White Balance/Exposure Statistic Configuration, Part 4 */
+	unsigned int   wb_expstatcrinterceptofneutralregionline4:12;
+	unsigned int   /* reserved */ : 4;
+	unsigned int   wb_expstatcbinterceptofneutralregionline3:12;
+	unsigned int   /* reserved */ : 4;
+
+	/* White Balance/Exposure Statistic Output Buffer Header */
+	unsigned int   wb_expmetricheaderpattern:8;
+	unsigned int   /* reserved */ : 24;
+
+	/* White Balance/Exposure Statistic Output Buffers-MUST
+	* BE 64 bit ALIGNED */
+	void  *wb_expstatoutputbuffer[NUM_WB_EXP_STAT_OUTPUT_BUFFERS];
+} __packed;
+
+struct vfe_stats_af_cfg {
+	uint32_t header;
+
+	/* Autofocus Statistic Selection */
+	uint8_t       af_enable:1;
+	uint8_t       af_busprioritysel:1;
+	unsigned int  af_buspriorityval:4;
+	unsigned int  /* reserved */ : 26;
+
+	/* Autofocus Statistic Configuration, Part 1 */
+	unsigned int  af_singlewinvoffset:12;
+	unsigned int  /* reserved */ : 4;
+	unsigned int  af_singlewinhoffset:12;
+	unsigned int  /* reserved */ : 3;
+	uint8_t       af_winmode:1;
+
+	/* Autofocus Statistic Configuration, Part 2 */
+	unsigned int  af_singglewinvh:11;
+	unsigned int  /* reserved */ : 5;
+	unsigned int  af_singlewinhw:11;
+	unsigned int  /* reserved */ : 5;
+
+	/* Autofocus Statistic Configuration, Parts 3-6 */
+	uint8_t       af_multiwingrid[NUM_AUTOFOCUS_MULTI_WINDOW_GRIDS];
+
+	/* Autofocus Statistic Configuration, Part 7 */
+	signed int    af_metrichpfcoefa00:5;
+	signed int    af_metrichpfcoefa04:5;
+	unsigned int  af_metricmaxval:11;
+	uint8_t       af_metricsel:1;
+	unsigned int  /* reserved */ : 10;
+
+	/* Autofocus Statistic Configuration, Part 8 */
+	signed int    af_metrichpfcoefa20:5;
+	signed int    af_metrichpfcoefa21:5;
+	signed int    af_metrichpfcoefa22:5;
+	signed int    af_metrichpfcoefa23:5;
+	signed int    af_metrichpfcoefa24:5;
+	unsigned int  /* reserved */ : 7;
+
+	/* Autofocus Statistic Output Buffer Header */
+	unsigned int  af_metrichp:8;
+	unsigned int  /* reserved */ : 24;
+
+	/* Autofocus Statistic Output Buffers - MUST BE 64 bit ALIGNED!!! */
+	void *af_outbuf[NUM_AF_STAT_OUTPUT_BUFFERS];
+} __packed; /* VFE_StatsAutofocusConfigCmdType */
+
+struct msm_camera_frame_msg {
+	unsigned long   output_y_address;
+	unsigned long   output_cbcr_address;
+
+	unsigned int    blacklevelevenColumn:23;
+	uint16_t        reserved1:9;
+	unsigned int    blackleveloddColumn:23;
+	uint16_t        reserved2:9;
+
+	uint16_t        greendefectpixelcount:8;
+	uint16_t        reserved3:8;
+	uint16_t        redbluedefectpixelcount:8;
+	uint16_t        reserved4:8;
+} __packed;
+
+/* New one for 7k */
+struct msm_vfe_command_7k {
+	uint16_t queue;
+	uint16_t length;
+	void     *value;
+};
+
+struct stop_event {
+	wait_queue_head_t wait;
+	int state;
+	int timeout;
+};
+
+static struct msm_free_buf *vfe2x_check_free_buffer(int id, int path);
+
+#endif /* __MSM_VFE7X_H__ */
diff --git a/drivers/media/video/msm/sensors/Makefile b/drivers/media/video/msm/sensors/Makefile
index 7b22592..a9b7bc6 100644
--- a/drivers/media/video/msm/sensors/Makefile
+++ b/drivers/media/video/msm/sensors/Makefile
@@ -6,3 +6,6 @@
 obj-$(CONFIG_IMX074) += imx074_v4l2.o
 obj-$(CONFIG_MT9M114) += mt9m114_v4l2.o
 obj-$(CONFIG_OV2720) += ov2720.o
+obj-$(CONFIG_S5K4E1) += s5k4e1_v4l2.o
+obj-$(CONFIG_MT9E013) += mt9e013_v4l2.o
+obj-$(CONFIG_WEBCAM_OV9726) += ov9726_v4l2.o
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index d31de14..227e606 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.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
@@ -172,6 +172,42 @@
 	return 0;
 }
 
+int32_t msm_sensor_setting1(struct msm_sensor_ctrl_t *s_ctrl,
+			int update_type, int res)
+{
+	int32_t rc = 0;
+	static int csi_config;
+
+	s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
+	msleep(30);
+	if (update_type == MSM_SENSOR_REG_INIT) {
+		CDBG("Register INIT\n");
+		s_ctrl->curr_csi_params = NULL;
+		msm_sensor_enable_debugfs(s_ctrl);
+		msm_sensor_write_init_settings(s_ctrl);
+		csi_config = 0;
+	} else if (update_type == MSM_SENSOR_UPDATE_PERIODIC) {
+		CDBG("PERIODIC : %d\n", res);
+		msm_sensor_write_conf_array(
+			s_ctrl->sensor_i2c_client,
+			s_ctrl->msm_sensor_reg->mode_settings, res);
+		msleep(30);
+		if (!csi_config) {
+			s_ctrl->curr_csic_params = s_ctrl->csic_params[res];
+			CDBG("CSI config in progress\n");
+			v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
+				NOTIFY_CSIC_CFG,
+				s_ctrl->curr_csic_params);
+			CDBG("CSI config is done\n");
+			mb();
+			msleep(30);
+			csi_config = 1;
+		}
+		s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
+		msleep(50);
+	}
+	return rc;
+}
 int32_t msm_sensor_setting(struct msm_sensor_ctrl_t *s_ctrl,
 			int update_type, int res)
 {
@@ -532,6 +568,8 @@
 probe_fail:
 	CDBG("%s_i2c_probe failed\n", client->name);
 power_down:
+	if (rc > 0)
+		rc = 0;
 	s_ctrl->func_tbl->sensor_power_down(s_ctrl);
 	return rc;
 }
diff --git a/drivers/media/video/msm/sensors/msm_sensor.h b/drivers/media/video/msm/sensors/msm_sensor.h
index e06f628..ba366e6 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.h
+++ b/drivers/media/video/msm/sensors/msm_sensor.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -158,6 +158,8 @@
 	struct mutex *msm_sensor_mutex;
 	struct msm_camera_csi2_params *curr_csi_params;
 	struct msm_camera_csi2_params **csi_params;
+	struct msm_camera_csi_params **csic_params;
+	struct msm_camera_csi_params *curr_csic_params;
 
 	struct v4l2_subdev sensor_v4l2_subdev;
 	struct v4l2_subdev_info *sensor_v4l2_subdev_info;
@@ -218,6 +220,9 @@
 int32_t msm_sensor_setting(struct msm_sensor_ctrl_t *s_ctrl,
 			int update_type, int res);
 
+int32_t msm_sensor_setting1(struct msm_sensor_ctrl_t *s_ctrl,
+			int update_type, int res);
+
 int msm_sensor_enable_debugfs(struct msm_sensor_ctrl_t *s_ctrl);
 
 long msm_sensor_subdev_ioctl(struct v4l2_subdev *sd,
diff --git a/drivers/media/video/msm/sensors/mt9e013_v4l2.c b/drivers/media/video/msm/sensors/mt9e013_v4l2.c
new file mode 100644
index 0000000..924cbc9
--- /dev/null
+++ b/drivers/media/video/msm/sensors/mt9e013_v4l2.c
@@ -0,0 +1,507 @@
+/* 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 "msm_sensor.h"
+#define SENSOR_NAME "mt9e013"
+#define PLATFORM_DRIVER_NAME "msm_camera_mt9e013"
+#define mt9e013_obj mt9e013_##obj
+
+DEFINE_MUTEX(mt9e013_mut);
+static struct msm_sensor_ctrl_t mt9e013_s_ctrl;
+
+static struct msm_camera_i2c_reg_conf mt9e013_groupon_settings[] = {
+	{0x0104, 0x01},
+};
+
+static struct msm_camera_i2c_reg_conf mt9e013_groupoff_settings[] = {
+	{0x0104, 0x00},
+};
+
+static struct msm_camera_i2c_reg_conf mt9e013_prev_settings[] = {
+	{0x0300, 0x0004},/*VT_PIX_CLK_DIV*/
+	{0x0302, 0x0001},/*VT_SYS_CLK_DIV*/
+	{0x0304, 0x0002},/*PRE_PLL_CLK_DIV*/
+	{0x0306, 0x003A},/*PLL_MULTIPLIER*/
+	{0x0308, 0x000A},/*OP_PIX_CLK_DIV*/
+	{0x030A, 0x0001},/*OP_SYS_CLK_DIV*/
+	/*Output Size (1632x1224)*/
+	{0x0344, 0x0008},/*X_ADDR_START*/
+	{0x0348, 0x0CC9},/*X_ADDR_END*/
+	{0x0346, 0x0008},/*Y_ADDR_START*/
+	{0x034A, 0x0999},/*Y_ADDR_END*/
+	{0x034C, 0x0660},/*X_OUTPUT_SIZE*/
+	{0x034E, 0x04C8},/*Y_OUTPUT_SIZE*/
+	{0x306E, 0xFCB0},/*DATAPATH_SELECT*/
+	{0x3040, 0x04C3},/*READ_MODE*/
+	{0x3178, 0x0000},/*ANALOG_CONTROL5*/
+	{0x3ED0, 0x1E24},/*DAC_LD_4_5*/
+	{0x0400, 0x0002},/*SCALING_MODE*/
+	{0x0404, 0x0010},/*SCALE_M*/
+	/*Timing configuration*/
+	{0x0342, 0x1018},/*LINE_LENGTH_PCK*/
+	{0x0340, 0x055B},/*FRAME_LENGTH_LINES*/
+	{0x0202, 0x0557},/*COARSE_INTEGRATION_TIME*/
+	{0x3014, 0x0846},/*FINE_INTEGRATION_TIME_*/
+	{0x3010, 0x0130},/*FINE_CORRECTION*/
+};
+
+static struct msm_camera_i2c_reg_conf mt9e013_snap_settings[] = {
+	{0x0300, 0x0004},/*VT_PIX_CLK_DIV*/
+	{0x0302, 0x0001},/*VT_SYS_CLK_DIV*/
+	{0x0304, 0x0002},/*PRE_PLL_CLK_DIV*/
+	{0x0306, 0x003A},/*PLL_MULTIPLIER*/
+	{0x0308, 0x000A},/*OP_PIX_CLK_DIV*/
+	{0x030A, 0x0001},/*OP_SYS_CLK_DIV*/
+	/*Output Size (3264x2448)*/
+	{0x0344, 0x0000},/*X_ADDR_START */
+	{0x0348, 0x0CCF},/*X_ADDR_END*/
+	{0x0346, 0x0000},/*Y_ADDR_START */
+	{0x034A, 0x099F},/*Y_ADDR_END*/
+	{0x034C, 0x0CD0},/*X_OUTPUT_SIZE*/
+	{0x034E, 0x09A0},/*Y_OUTPUT_SIZE*/
+	{0x306E, 0xFC80},/*DATAPATH_SELECT*/
+	{0x3040, 0x0041},/*READ_MODE*/
+	{0x3178, 0x0000},/*ANALOG_CONTROL5*/
+	{0x3ED0, 0x1E24},/*DAC_LD_4_5*/
+	{0x0400, 0x0000},/*SCALING_MODE*/
+	{0x0404, 0x0010},/*SCALE_M*/
+	/*Timing configuration*/
+	{0x0342, 0x13F8},/*LINE_LENGTH_PCK*/
+	{0x0340, 0x0A2F},/*FRAME_LENGTH_LINES*/
+	{0x0202, 0x0A1F},/*COARSE_INTEGRATION_TIME*/
+	{0x3014, 0x03F6},/*FINE_INTEGRATION_TIME_ */
+	{0x3010, 0x0078},/*FINE_CORRECTION*/
+};
+
+static struct msm_camera_i2c_reg_conf mt9e013_hfr60_settings[] = {
+	{0x0300, 0x0005},/*VT_PIX_CLK_DIV*/
+	{0x0302, 0x0001},/*VT_SYS_CLK_DIV*/
+	{0x0304, 0x0002},/*PRE_PLL_CLK_DIV*/
+	{0x0306, 0x0029},/*PLL_MULTIPLIER*/
+	{0x0308, 0x000A},/*OP_PIX_CLK_DIV*/
+	{0x030A, 0x0001},/*OP_SYS_CLK_DIV*/
+	{0x0344, 0x0008},/*X_ADDR_START*/
+	{0x0348, 0x0685},/*X_ADDR_END*/
+	{0x0346, 0x013a},/*Y_ADDR_START*/
+	{0x034A, 0x055B},/*Y_ADDR_END*/
+	{0x034C, 0x0340},/*X_OUTPUT_SIZE*/
+	{0x034E, 0x0212},/*Y_OUTPUT_SIZE*/
+	{0x306E, 0xFC80},/*DATAPATH_SELECT*/
+	{0x3040, 0x00C3},/*READ_MODE*/
+	{0x3178, 0x0000},/*ANALOG_CONTROL5*/
+	{0x3ED0, 0x1E24},/*DAC_LD_4_5*/
+	{0x0400, 0x0000},/*SCALING_MODE*/
+	{0x0404, 0x0010},/*SCALE_M*/
+	/*Timing configuration*/
+	{0x0342, 0x0970},/*LINE_LENGTH_PCK*/
+	{0x0340, 0x02A1},/*FRAME_LENGTH_LINES*/
+	{0x0202, 0x02A1},/*COARSE_INTEGRATION_TIME*/
+	{0x3014, 0x03F6},/*FINE_INTEGRATION_TIME_*/
+	{0x3010, 0x0078},/*FINE_CORRECTION*/
+};
+
+static struct msm_camera_i2c_reg_conf mt9e013_hfr90_settings[] = {
+	{0x0300, 0x0005},/*VT_PIX_CLK_DIV*/
+	{0x0302, 0x0001},/*VT_SYS_CLK_DIV*/
+	{0x0304, 0x0002},/*PRE_PLL_CLK_DIV*/
+	{0x0306, 0x003D},/*PLL_MULTIPLIER*/
+	{0x0308, 0x000A},/*OP_PIX_CLK_DIV*/
+	{0x030A, 0x0001},/*OP_SYS_CLK_DIV*/
+	{0x0344, 0x0008},/*X_ADDR_START*/
+	{0x0348, 0x0685},/*X_ADDR_END*/
+	{0x0346, 0x013a},/*Y_ADDR_START*/
+	{0x034A, 0x055B},/*Y_ADDR_END*/
+	{0x034C, 0x0340},/*X_OUTPUT_SIZE*/
+	{0x034E, 0x0212},/*Y_OUTPUT_SIZE*/
+	{0x306E, 0xFC80},/*DATAPATH_SELECT*/
+	{0x3040, 0x00C3},/*READ_MODE*/
+	{0x3178, 0x0000},/*ANALOG_CONTROL5*/
+	{0x3ED0, 0x1E24},/*DAC_LD_4_5*/
+	{0x0400, 0x0000},/*SCALING_MODE*/
+	{0x0404, 0x0010},/*SCALE_M*/
+	/*Timing configuration*/
+	{0x0342, 0x0970},/*LINE_LENGTH_PCK*/
+	{0x0340, 0x02A1},/*FRAME_LENGTH_LINES*/
+	{0x0202, 0x02A1},/*COARSE_INTEGRATION_TIME*/
+	{0x3014, 0x03F6},/*FINE_INTEGRATION_TIME_*/
+	{0x3010, 0x0078},/*FINE_CORRECTION*/
+};
+
+static struct msm_camera_i2c_reg_conf mt9e013_hfr120_settings[] = {
+	{0x0300, 0x0005},/*VT_PIX_CLK_DIV*/
+	{0x0302, 0x0001},/*VT_SYS_CLK_DIV*/
+	{0x0304, 0x0002},/*PRE_PLL_CLK_DIV*/
+	{0x0306, 0x0052},/*PLL_MULTIPLIER*/
+	{0x0308, 0x000A},/*OP_PIX_CLK_DIV*/
+	{0x030A, 0x0001},/*OP_SYS_CLK_DIV*/
+	{0x0344, 0x0008},/*X_ADDR_START*/
+	{0x0348, 0x0685},/*X_ADDR_END*/
+	{0x0346, 0x013a},/*Y_ADDR_START*/
+	{0x034A, 0x055B},/*Y_ADDR_END*/
+	{0x034C, 0x0340},/*X_OUTPUT_SIZE*/
+	{0x034E, 0x0212},/*Y_OUTPUT_SIZE*/
+	{0x306E, 0xFC80},/*DATAPATH_SELECT*/
+	{0x3040, 0x00C3},/*READ_MODE*/
+	{0x3178, 0x0000},/*ANALOG_CONTROL5*/
+	{0x3ED0, 0x1E24},/*DAC_LD_4_5*/
+	{0x0400, 0x0000},/*SCALING_MODE*/
+	{0x0404, 0x0010},/*SCALE_M*/
+	/*Timing configuration*/
+	{0x0342, 0x0970},/*LINE_LENGTH_PCK*/
+	{0x0340, 0x02A1},/*FRAME_LENGTH_LINES*/
+	{0x0202, 0x02A1},/*COARSE_INTEGRATION_TIME*/
+	{0x3014, 0x03F6},/*FINE_INTEGRATION_TIME_*/
+	{0x3010, 0x0078},/*FINE_CORRECTION*/
+};
+
+static struct msm_camera_i2c_reg_conf mt9e013_recommend_settings[] = {
+	/*Disable embedded data*/
+	{0x3064, 0x7800},/*SMIA_TEST*/
+	/*configure 2-lane MIPI*/
+	{0x31AE, 0x0202},/*SERIAL_FORMAT*/
+	{0x31B8, 0x0E3F},/*MIPI_TIMING_2*/
+	/*set data to RAW10 format*/
+	{0x0112, 0x0A0A},/*CCP_DATA_FORMAT*/
+	{0x30F0, 0x8000},/*VCM CONTROL*/
+
+	{0x3044, 0x0590},
+	{0x306E, 0xFC80},
+	{0x30B2, 0xC000},
+	{0x30D6, 0x0800},
+	{0x316C, 0xB42F},
+	{0x316E, 0x869C},
+	{0x3170, 0x210E},
+	{0x317A, 0x010E},
+	{0x31E0, 0x1FB9},
+	{0x31E6, 0x07FC},
+	{0x37C0, 0x0000},
+	{0x37C2, 0x0000},
+	{0x37C4, 0x0000},
+	{0x37C6, 0x0000},
+	{0x3E02, 0x8801},
+	{0x3E04, 0x2301},
+	{0x3E06, 0x8449},
+	{0x3E08, 0x6841},
+	{0x3E0A, 0x400C},
+	{0x3E0C, 0x1001},
+	{0x3E0E, 0x2103},
+	{0x3E10, 0x4B41},
+	{0x3E12, 0x4B26},
+	{0x3E16, 0x8802},
+	{0x3E18, 0x84FF},
+	{0x3E1A, 0x8601},
+	{0x3E1C, 0x8401},
+	{0x3E1E, 0x840A},
+	{0x3E20, 0xFF00},
+	{0x3E22, 0x8401},
+	{0x3E24, 0x00FF},
+	{0x3E26, 0x0088},
+	{0x3E28, 0x2E8A},
+	{0x3E32, 0x8801},
+	{0x3E34, 0x4024},
+	{0x3E38, 0x8469},
+	{0x3E3C, 0x2301},
+	{0x3E3E, 0x3E25},
+	{0x3E40, 0x1C01},
+	{0x3E42, 0x8486},
+	{0x3E44, 0x8401},
+	{0x3E46, 0x00FF},
+	{0x3E48, 0x8401},
+	{0x3E4A, 0x8601},
+	{0x3E4C, 0x8402},
+	{0x3E4E, 0x00FF},
+	{0x3E50, 0x6623},
+	{0x3E52, 0x8340},
+	{0x3E54, 0x00FF},
+	{0x3E56, 0x4A42},
+	{0x3E58, 0x2203},
+	{0x3E5A, 0x674D},
+	{0x3E5C, 0x3F25},
+	{0x3E5E, 0x846A},
+	{0x3E60, 0x4C01},
+	{0x3E62, 0x8401},
+	{0x3E66, 0x3901},
+	{0x3ECC, 0x00EB},
+	{0x3ED0, 0x1E24},
+	{0x3ED4, 0xAFC4},
+	{0x3ED6, 0x909B},
+	{0x3ED8, 0x0006},
+	{0x3EDA, 0xCFC6},
+	{0x3EDC, 0x4FE4},
+	{0x3EE0, 0x2424},
+	{0x3EE2, 0x9797},
+	{0x3EE4, 0xC100},
+	{0x3EE6, 0x0540}
+};
+
+static struct v4l2_subdev_info mt9e013_subdev_info[] = {
+	{
+	.code   = V4L2_MBUS_FMT_SBGGR10_1X10,
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	.fmt    = 1,
+	.order    = 0,
+	},
+	/* more can be supported, to be added later */
+};
+
+static struct msm_camera_i2c_conf_array mt9e013_init_conf[] = {
+	{&mt9e013_recommend_settings[0],
+	ARRAY_SIZE(mt9e013_recommend_settings), 0, MSM_CAMERA_I2C_WORD_DATA}
+};
+
+static struct msm_camera_i2c_conf_array mt9e013_confs[] = {
+	{&mt9e013_snap_settings[0],
+	ARRAY_SIZE(mt9e013_snap_settings), 0, MSM_CAMERA_I2C_WORD_DATA},
+	{&mt9e013_prev_settings[0],
+	ARRAY_SIZE(mt9e013_prev_settings), 0, MSM_CAMERA_I2C_WORD_DATA},
+	{&mt9e013_hfr60_settings[0],
+	ARRAY_SIZE(mt9e013_hfr60_settings), 0, MSM_CAMERA_I2C_WORD_DATA},
+	{&mt9e013_hfr90_settings[0],
+	ARRAY_SIZE(mt9e013_hfr90_settings), 0, MSM_CAMERA_I2C_WORD_DATA},
+	{&mt9e013_hfr120_settings[0],
+	ARRAY_SIZE(mt9e013_hfr120_settings), 0, MSM_CAMERA_I2C_WORD_DATA},
+};
+
+static struct msm_sensor_output_info_t mt9e013_dimensions[] = {
+	{
+		.x_output = 0xCD0,
+		.y_output = 0x9A0,
+		.line_length_pclk = 0x13F8,
+		.frame_length_lines = 0xA2F,
+		.vt_pixel_clk = 174000000,
+		.op_pixel_clk = 174000000,
+		.binning_factor = 1,
+	},
+	{
+		.x_output = 0x660,
+		.y_output = 0x4C8,
+		.line_length_pclk = 0x1018,
+		.frame_length_lines = 0x55B,
+		.vt_pixel_clk = 174000000,
+		.op_pixel_clk = 174000000,
+		.binning_factor = 1,
+	},
+	{
+		.x_output = 0x340,
+		.y_output = 0x212,
+		.line_length_pclk = 0x970,
+		.frame_length_lines = 0x2A1,
+		.vt_pixel_clk = 98400000,
+		.op_pixel_clk = 98400000,
+		.binning_factor = 1,
+	},
+	{
+		.x_output = 0x340,
+		.y_output = 0x212,
+		.line_length_pclk = 0x970,
+		.frame_length_lines = 0x2A1,
+		.vt_pixel_clk = 146400000,
+		.op_pixel_clk = 146400000,
+		.binning_factor = 1,
+	},
+	{
+		.x_output = 0x340,
+		.y_output = 0x212,
+		.line_length_pclk = 0x970,
+		.frame_length_lines = 0x2A1,
+		.vt_pixel_clk = 196800000,
+		.op_pixel_clk = 196800000,
+		.binning_factor = 1,
+	},
+};
+
+static struct msm_camera_csi_params mt9e013_csi_params = {
+	.data_format = CSI_10BIT,
+	.lane_cnt    = 2,
+	.lane_assign = 0xe4,
+	.dpcm_scheme = 0,
+	.settle_cnt  = 0x18,
+};
+
+static struct msm_camera_csi_params *mt9e013_csi_params_array[] = {
+	&mt9e013_csi_params,
+	&mt9e013_csi_params,
+	&mt9e013_csi_params,
+	&mt9e013_csi_params,
+	&mt9e013_csi_params,
+};
+
+static struct msm_sensor_output_reg_addr_t mt9e013_reg_addr = {
+	.x_output = 0x34C,
+	.y_output = 0x34E,
+	.line_length_pclk = 0x342,
+	.frame_length_lines = 0x340,
+};
+
+static struct msm_sensor_id_info_t mt9e013_id_info = {
+	.sensor_id_reg_addr = 0x0,
+	.sensor_id = 0x4B00,
+};
+
+static struct msm_sensor_exp_gain_info_t mt9e013_exp_gain_info = {
+	.coarse_int_time_addr = 0x202,
+	.global_gain_addr = 0x305E,
+	.vert_offset = 0,
+};
+
+static int32_t mt9e013_write_exp_gain(struct msm_sensor_ctrl_t *s_ctrl,
+		uint16_t gain, uint32_t line)
+{
+	uint32_t fl_lines;
+	fl_lines =
+		(s_ctrl->curr_frame_length_lines * s_ctrl->fps_divider) / Q10;
+
+	s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->global_gain_addr, gain | 0x1000,
+		MSM_CAMERA_I2C_WORD_DATA);
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr, line,
+		MSM_CAMERA_I2C_WORD_DATA);
+	s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
+	return 0;
+}
+
+static int32_t mt9e013_write_exp_snapshot_gain(struct msm_sensor_ctrl_t *s_ctrl,
+		uint16_t gain, uint32_t line)
+{
+	uint32_t fl_lines;
+	fl_lines =
+		(s_ctrl->curr_frame_length_lines * s_ctrl->fps_divider) / Q10;
+
+	s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->global_gain_addr, gain | 0x1000,
+		MSM_CAMERA_I2C_WORD_DATA);
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr, line,
+		MSM_CAMERA_I2C_WORD_DATA);
+	s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		0x301A, (0x065C|0x2), MSM_CAMERA_I2C_WORD_DATA);
+
+	return 0;
+}
+static void mt9e013_start_stream(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		0x301A, 0x8250, MSM_CAMERA_I2C_WORD_DATA);
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		0x301A, 0x8650, MSM_CAMERA_I2C_WORD_DATA);
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		0x301A, 0x8658, MSM_CAMERA_I2C_WORD_DATA);
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		0x0104, 0x00, MSM_CAMERA_I2C_BYTE_DATA);
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		0x301A, 0x065C, MSM_CAMERA_I2C_WORD_DATA);
+}
+
+static void mt9e013_stop_stream(struct msm_sensor_ctrl_t *s_ctrl)
+{
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		0x301A, 0x0058, MSM_CAMERA_I2C_WORD_DATA);
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		0x301A, 0x0050, MSM_CAMERA_I2C_WORD_DATA);
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		0x0104, 0x01, MSM_CAMERA_I2C_BYTE_DATA);
+}
+
+static const struct i2c_device_id mt9e013_i2c_id[] = {
+	{SENSOR_NAME, (kernel_ulong_t)&mt9e013_s_ctrl},
+	{ }
+};
+
+static struct i2c_driver mt9e013_i2c_driver = {
+	.id_table = mt9e013_i2c_id,
+	.probe  = msm_sensor_i2c_probe,
+	.driver = {
+		.name = SENSOR_NAME,
+	},
+};
+
+static struct msm_camera_i2c_client mt9e013_sensor_i2c_client = {
+	.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+static int __init msm_sensor_init_module(void)
+{
+	return i2c_add_driver(&mt9e013_i2c_driver);
+}
+
+static struct v4l2_subdev_core_ops mt9e013_subdev_core_ops = {
+	.ioctl = msm_sensor_subdev_ioctl,
+	.s_power = msm_sensor_power,
+};
+
+static struct v4l2_subdev_video_ops mt9e013_subdev_video_ops = {
+	.enum_mbus_fmt = msm_sensor_v4l2_enum_fmt,
+};
+
+static struct v4l2_subdev_ops mt9e013_subdev_ops = {
+	.core = &mt9e013_subdev_core_ops,
+	.video  = &mt9e013_subdev_video_ops,
+};
+
+static struct msm_sensor_fn_t mt9e013_func_tbl = {
+	.sensor_start_stream = mt9e013_start_stream,
+	.sensor_stop_stream = mt9e013_stop_stream,
+	.sensor_group_hold_on = msm_sensor_group_hold_on,
+	.sensor_group_hold_off = msm_sensor_group_hold_off,
+	.sensor_set_fps = msm_sensor_set_fps,
+	.sensor_write_exp_gain = mt9e013_write_exp_gain,
+	.sensor_write_snapshot_exp_gain = mt9e013_write_exp_snapshot_gain,
+	.sensor_setting = msm_sensor_setting1,
+	.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
+	.sensor_mode_init = msm_sensor_mode_init,
+	.sensor_get_output_info = msm_sensor_get_output_info,
+	.sensor_config = msm_sensor_config,
+	.sensor_power_up = msm_sensor_power_up,
+	.sensor_power_down = msm_sensor_power_down,
+};
+
+static struct msm_sensor_reg_t mt9e013_regs = {
+	.default_data_type = MSM_CAMERA_I2C_BYTE_DATA,
+	.group_hold_on_conf = mt9e013_groupon_settings,
+	.group_hold_on_conf_size = ARRAY_SIZE(mt9e013_groupon_settings),
+	.group_hold_off_conf = mt9e013_groupoff_settings,
+	.group_hold_off_conf_size =
+		ARRAY_SIZE(mt9e013_groupoff_settings),
+	.init_settings = &mt9e013_init_conf[0],
+	.init_size = ARRAY_SIZE(mt9e013_init_conf),
+	.mode_settings = &mt9e013_confs[0],
+	.output_settings = &mt9e013_dimensions[0],
+	.num_conf = ARRAY_SIZE(mt9e013_confs),
+};
+
+static struct msm_sensor_ctrl_t mt9e013_s_ctrl = {
+	.msm_sensor_reg = &mt9e013_regs,
+	.sensor_i2c_client = &mt9e013_sensor_i2c_client,
+	.sensor_i2c_addr = 0x6C,
+	.sensor_output_reg_addr = &mt9e013_reg_addr,
+	.sensor_id_info = &mt9e013_id_info,
+	.sensor_exp_gain_info = &mt9e013_exp_gain_info,
+	.cam_mode = MSM_SENSOR_MODE_INVALID,
+	.csic_params = &mt9e013_csi_params_array[0],
+	.msm_sensor_mutex = &mt9e013_mut,
+	.sensor_i2c_driver = &mt9e013_i2c_driver,
+	.sensor_v4l2_subdev_info = mt9e013_subdev_info,
+	.sensor_v4l2_subdev_info_size = ARRAY_SIZE(mt9e013_subdev_info),
+	.sensor_v4l2_subdev_ops = &mt9e013_subdev_ops,
+	.func_tbl = &mt9e013_func_tbl,
+};
+
+module_init(msm_sensor_init_module);
+MODULE_DESCRIPTION("Aptina 8MP Bayer sensor driver");
+MODULE_LICENSE("GPL v2");
+
+
diff --git a/drivers/media/video/msm/sensors/ov9726_v4l2.c b/drivers/media/video/msm/sensors/ov9726_v4l2.c
new file mode 100644
index 0000000..e345717
--- /dev/null
+++ b/drivers/media/video/msm/sensors/ov9726_v4l2.c
@@ -0,0 +1,280 @@
+/* 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 "msm_sensor.h"
+#define SENSOR_NAME "ov9726"
+#define PLATFORM_DRIVER_NAME "msm_camera_ov9726"
+#define ov9726_obj ov9726_##obj
+
+DEFINE_MUTEX(ov9726_mut);
+static struct msm_sensor_ctrl_t ov9726_s_ctrl;
+
+static struct msm_camera_i2c_reg_conf ov9726_start_settings[] = {
+	{0x0100, 0x01},
+};
+
+static struct msm_camera_i2c_reg_conf ov9726_stop_settings[] = {
+	{0x0100, 0x00},
+};
+
+static struct msm_camera_i2c_reg_conf ov9726_groupon_settings[] = {
+	{0x0104, 0x01},
+};
+
+static struct msm_camera_i2c_reg_conf ov9726_groupoff_settings[] = {
+	{0x0104, 0x00},
+};
+
+static struct msm_camera_i2c_reg_conf ov9726_prev_settings[] = {
+};
+
+static struct msm_camera_i2c_reg_conf ov9726_recommend_settings[] = {
+	{0x0103, 0x01}, /* SOFTWARE_RESET */
+	{0x3026, 0x00}, /* OUTPUT_SELECT01 */
+	{0x3027, 0x00}, /* OUTPUT_SELECT02 */
+	{0x3002, 0xe8}, /* IO_CTRL00 */
+	{0x3004, 0x03}, /* IO_CTRL01 */
+	{0x3005, 0xff}, /* IO_CTRL02 */
+	{0x3703, 0x42},
+	{0x3704, 0x10},
+	{0x3705, 0x45},
+	{0x3603, 0xaa},
+	{0x3632, 0x2f},
+	{0x3620, 0x66},
+	{0x3621, 0xc0},
+	{0x0340, 0x03}, /* FRAME_LENGTH_LINES_HI */
+	{0x0341, 0xC1}, /* FRAME_LENGTH_LINES_LO */
+	{0x0342, 0x06}, /* LINE_LENGTH_PCK_HI */
+	{0x0343, 0x80}, /* LINE_LENGTH_PCK_LO */
+	{0x0202, 0x03}, /* COARSE_INTEGRATION_TIME_HI */
+	{0x0203, 0x43}, /* COARSE_INTEGRATION_TIME_LO */
+	{0x3833, 0x04},
+	{0x3835, 0x02},
+	{0x4702, 0x04},
+	{0x4704, 0x00}, /* DVP_CTRL01 */
+	{0x4706, 0x08},
+	{0x5052, 0x01},
+	{0x3819, 0x6e},
+	{0x3817, 0x94},
+	{0x3a18, 0x00}, /* AEC_GAIN_CEILING_HI */
+	{0x3a19, 0x7f}, /* AEC_GAIN_CEILING_LO */
+	{0x404e, 0x7e},
+	{0x3631, 0x52},
+	{0x3633, 0x50},
+	{0x3630, 0xd2},
+	{0x3604, 0x08},
+	{0x3601, 0x40},
+	{0x3602, 0x14},
+	{0x3610, 0xa0},
+	{0x3612, 0x20},
+	{0x034c, 0x05}, /* X_OUTPUT_SIZE_HI */
+	{0x034d, 0x10}, /* X_OUTPUT_SIZE_LO */
+	{0x034e, 0x03}, /* Y_OUTPUT_SIZE_HI */
+	{0x034f, 0x28}, /* Y_OUTPUT_SIZE_LO */
+	{0x0340, 0x03}, /* FRAME_LENGTH_LINES_HI */
+	{0x0341, 0xC1}, /* FRAME_LENGTH_LINES_LO */
+	{0x0342, 0x06}, /* LINE_LENGTH_PCK_HI */
+	{0x0343, 0x80}, /* LINE_LENGTH_PCK_LO */
+	{0x0202, 0x03}, /* COARSE_INTEGRATION_TIME_HI */
+	{0x0203, 0x43}, /* COARSE_INTEGRATION_TIME_LO */
+	{0x0303, 0x01}, /* VT_SYS_CLK_DIV_LO */
+	{0x3002, 0x00}, /* IO_CTRL00 */
+	{0x3004, 0x00}, /* IO_CTRL01 */
+	{0x3005, 0x00}, /* IO_CTRL02 */
+	{0x4801, 0x0f}, /* MIPI_CTRL01 */
+	{0x4803, 0x05}, /* MIPI_CTRL03 */
+	{0x4601, 0x16}, /* VFIFO_READ_CONTROL */
+	{0x3014, 0x05}, /* SC_CMMN_MIPI / SC_CTRL00 */
+	{0x3104, 0x80},
+	{0x0305, 0x04}, /* PRE_PLL_CLK_DIV_LO */
+	{0x0307, 0x64}, /* PLL_MULTIPLIER_LO */
+	{0x300c, 0x02},
+	{0x300d, 0x20},
+	{0x300e, 0x01},
+	{0x3010, 0x01},
+	{0x460e, 0x81}, /* VFIFO_CONTROL00 */
+	{0x0101, 0x01}, /* IMAGE_ORIENTATION */
+	{0x3707, 0x14},
+	{0x3622, 0x9f},
+	{0x5047, 0x3D}, /* ISP_CTRL47 */
+	{0x4002, 0x45}, /* BLC_CTRL02 */
+	{0x5000, 0x06}, /* ISP_CTRL0 */
+	{0x5001, 0x00}, /* ISP_CTRL1 */
+	{0x3406, 0x00}, /* AWB_MANUAL_CTRL */
+	{0x3503, 0x13}, /* AEC_ENABLE */
+	{0x4005, 0x18}, /* BLC_CTRL05 */
+	{0x4837, 0x21},
+	{0x0100, 0x01}, /* MODE_SELECT */
+	{0x3a0f, 0x64}, /* AEC_CTRL0F */
+	{0x3a10, 0x54}, /* AEC_CTRL10 */
+	{0x3a11, 0xc2}, /* AEC_CTRL11 */
+	{0x3a1b, 0x64}, /* AEC_CTRL1B */
+	{0x3a1e, 0x54}, /* AEC_CTRL1E */
+	{0x3a1a, 0x05}, /* AEC_DIFF_MAX */
+};
+
+static struct v4l2_subdev_info ov9726_subdev_info[] = {
+	{
+	.code   = V4L2_MBUS_FMT_SBGGR10_1X10,
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	.fmt    = 1,
+	.order    = 0,
+	},
+	/* more can be supported, to be added later */
+};
+
+static struct msm_camera_i2c_conf_array ov9726_init_conf[] = {
+	{&ov9726_recommend_settings[0],
+	ARRAY_SIZE(ov9726_recommend_settings), 0, MSM_CAMERA_I2C_BYTE_DATA}
+};
+
+static struct msm_camera_i2c_conf_array ov9726_confs[] = {
+	{&ov9726_prev_settings[0],
+	ARRAY_SIZE(ov9726_prev_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+};
+
+static struct msm_sensor_output_info_t ov9726_dimensions[] = {
+	{
+		.x_output = 0x510, /* 1296 */
+		.y_output = 0x328, /* 808 */
+		.line_length_pclk = 0x680, /* 1664 */
+		.frame_length_lines = 0x3C1, /* 961 */
+		.vt_pixel_clk = 320000000,
+		.op_pixel_clk = 320000000,
+		.binning_factor = 1,
+	},
+};
+
+static struct msm_camera_csi_params ov9726_csi_params = {
+	       .data_format = CSI_10BIT,
+	       .lane_cnt    = 1,
+	       .lane_assign = 0xe4,
+	       .dpcm_scheme = 0,
+	       .settle_cnt  = 7,
+};
+
+static struct msm_camera_csi_params *ov9726_csi_params_array[] = {
+	&ov9726_csi_params,
+};
+
+static struct msm_sensor_output_reg_addr_t ov9726_reg_addr = {
+	.x_output = 0x034c,
+	.y_output = 0x034e,
+	.line_length_pclk = 0x0342,
+	.frame_length_lines = 0x0340,
+};
+
+static struct msm_sensor_id_info_t ov9726_id_info = {
+	.sensor_id_reg_addr = 0x0000,
+	.sensor_id = 0x9726,
+};
+
+static struct msm_sensor_exp_gain_info_t ov9726_exp_gain_info = {
+	.coarse_int_time_addr = 0x0202,
+	.global_gain_addr = 0x0204,
+	.vert_offset = 6,
+};
+
+static const struct i2c_device_id ov9726_i2c_id[] = {
+	{SENSOR_NAME, (kernel_ulong_t)&ov9726_s_ctrl},
+	{ }
+};
+
+static struct i2c_driver ov9726_i2c_driver = {
+	.id_table = ov9726_i2c_id,
+	.probe  = msm_sensor_i2c_probe,
+	.driver = {
+		.name = SENSOR_NAME,
+	},
+};
+
+static struct msm_camera_i2c_client ov9726_sensor_i2c_client = {
+	.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+static int __init msm_sensor_init_module(void)
+{
+	return i2c_add_driver(&ov9726_i2c_driver);
+}
+
+static struct v4l2_subdev_core_ops ov9726_subdev_core_ops = {
+	.ioctl = msm_sensor_subdev_ioctl,
+	.s_power = msm_sensor_power,
+};
+
+static struct v4l2_subdev_video_ops ov9726_subdev_video_ops = {
+	.enum_mbus_fmt = msm_sensor_v4l2_enum_fmt,
+};
+
+static struct v4l2_subdev_ops ov9726_subdev_ops = {
+	.core = &ov9726_subdev_core_ops,
+	.video  = &ov9726_subdev_video_ops,
+};
+
+static struct msm_sensor_fn_t ov9726_func_tbl = {
+	.sensor_start_stream = msm_sensor_start_stream,
+	.sensor_stop_stream = msm_sensor_stop_stream,
+	.sensor_group_hold_on = msm_sensor_group_hold_on,
+	.sensor_group_hold_off = msm_sensor_group_hold_off,
+	.sensor_set_fps = msm_sensor_set_fps,
+	.sensor_write_exp_gain = msm_sensor_write_exp_gain1,
+	.sensor_write_snapshot_exp_gain = msm_sensor_write_exp_gain1,
+	.sensor_setting = msm_sensor_setting1,
+	.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
+	.sensor_mode_init = msm_sensor_mode_init,
+	.sensor_get_output_info = msm_sensor_get_output_info,
+	.sensor_config = msm_sensor_config,
+	.sensor_power_up = msm_sensor_power_up,
+	.sensor_power_down = msm_sensor_power_down,
+};
+
+static struct msm_sensor_reg_t ov9726_regs = {
+	.default_data_type = MSM_CAMERA_I2C_BYTE_DATA,
+	.start_stream_conf = ov9726_start_settings,
+	.start_stream_conf_size = ARRAY_SIZE(ov9726_start_settings),
+	.stop_stream_conf = ov9726_stop_settings,
+	.stop_stream_conf_size = ARRAY_SIZE(ov9726_stop_settings),
+	.group_hold_on_conf = ov9726_groupon_settings,
+	.group_hold_on_conf_size = ARRAY_SIZE(ov9726_groupon_settings),
+	.group_hold_off_conf = ov9726_groupoff_settings,
+	.group_hold_off_conf_size =
+		ARRAY_SIZE(ov9726_groupoff_settings),
+	.init_settings = &ov9726_init_conf[0],
+	.init_size = ARRAY_SIZE(ov9726_init_conf),
+	.mode_settings = &ov9726_confs[0],
+	.output_settings = &ov9726_dimensions[0],
+	.num_conf = ARRAY_SIZE(ov9726_confs),
+};
+
+static struct msm_sensor_ctrl_t ov9726_s_ctrl = {
+	.msm_sensor_reg = &ov9726_regs,
+	.sensor_i2c_client = &ov9726_sensor_i2c_client,
+	.sensor_i2c_addr = 0x20,
+	.sensor_output_reg_addr = &ov9726_reg_addr,
+	.sensor_id_info = &ov9726_id_info,
+	.sensor_exp_gain_info = &ov9726_exp_gain_info,
+	.cam_mode = MSM_SENSOR_MODE_INVALID,
+	.csic_params = &ov9726_csi_params_array[0],
+	.msm_sensor_mutex = &ov9726_mut,
+	.sensor_i2c_driver = &ov9726_i2c_driver,
+	.sensor_v4l2_subdev_info = ov9726_subdev_info,
+	.sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov9726_subdev_info),
+	.sensor_v4l2_subdev_ops = &ov9726_subdev_ops,
+	.func_tbl = &ov9726_func_tbl,
+};
+
+module_init(msm_sensor_init_module);
+MODULE_DESCRIPTION("Omnivision WXGA Bayer sensor driver");
+MODULE_LICENSE("GPL v2");
+
+
diff --git a/drivers/media/video/msm/sensors/s5k4e1_v4l2.c b/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
new file mode 100644
index 0000000..1f99119
--- /dev/null
+++ b/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
@@ -0,0 +1,503 @@
+/* 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 "msm_sensor.h"
+#define SENSOR_NAME "s5k4e1"
+#define PLATFORM_DRIVER_NAME "msm_camera_s5k4e1"
+#define s5k4e1_obj s5k4e1_##obj
+#define MSB                             1
+#define LSB                             0
+
+DEFINE_MUTEX(s5k4e1_mut);
+static struct msm_sensor_ctrl_t s5k4e1_s_ctrl;
+
+static struct msm_camera_i2c_reg_conf s5k4e1_start_settings[] = {
+	{0x0100, 0x01},
+};
+
+static struct msm_camera_i2c_reg_conf s5k4e1_stop_settings[] = {
+	{0x0100, 0x00},
+};
+
+static struct msm_camera_i2c_reg_conf s5k4e1_groupon_settings[] = {
+	{0x0104, 0x01},
+};
+
+static struct msm_camera_i2c_reg_conf s5k4e1_groupoff_settings[] = {
+	{0x0104, 0x00},
+};
+
+static struct msm_camera_i2c_reg_conf s5k4e1_prev_settings[] = {
+	/* output size (1304 x 980) */
+	{0x30A9, 0x02},/* Horizontal Binning On */
+	{0x300E, 0xEB},/* Vertical Binning On */
+	{0x0387, 0x03},/* y_odd_inc 03(10b AVG) */
+	{0x0344, 0x00},/* x_addr_start 0 */
+	{0x0345, 0x00},
+	{0x0348, 0x0A},/* x_addr_end 2607 */
+	{0x0349, 0x2F},
+	{0x0346, 0x00},/* y_addr_start 0 */
+	{0x0347, 0x00},
+	{0x034A, 0x07},/* y_addr_end 1959 */
+	{0x034B, 0xA7},
+	{0x0380, 0x00},/* x_even_inc 1 */
+	{0x0381, 0x01},
+	{0x0382, 0x00},/* x_odd_inc 1 */
+	{0x0383, 0x01},
+	{0x0384, 0x00},/* y_even_inc 1 */
+	{0x0385, 0x01},
+	{0x0386, 0x00},/* y_odd_inc 3 */
+	{0x0387, 0x03},
+	{0x034C, 0x05},/* x_output_size 1304 */
+	{0x034D, 0x18},
+	{0x034E, 0x03},/* y_output_size 980 */
+	{0x034F, 0xd4},
+	{0x30BF, 0xAB},/* outif_enable[7], data_type[5:0](2Bh = bayer 10bit} */
+	{0x30C0, 0xA0},/* video_offset[7:4] 3260%12 */
+	{0x30C8, 0x06},/* video_data_length 1600 = 1304 * 1.25 */
+	{0x30C9, 0x5E},
+	/* Timing Configuration */
+	{0x0202, 0x03},
+	{0x0203, 0x14},
+	{0x0204, 0x00},
+	{0x0205, 0x80},
+	{0x0340, 0x03},/* Frame Length */
+	{0x0341, 0xE0},
+	{0x0342, 0x0A},/* 2738  Line Length */
+	{0x0343, 0xB2},
+};
+
+static struct msm_camera_i2c_reg_conf s5k4e1_snap_settings[] = {
+	/*Output Size (2608x1960)*/
+	{0x30A9, 0x03},/* Horizontal Binning Off */
+	{0x300E, 0xE8},/* Vertical Binning Off */
+	{0x0387, 0x01},/* y_odd_inc */
+	{0x034C, 0x0A},/* x_output size */
+	{0x034D, 0x30},
+	{0x034E, 0x07},/* y_output size */
+	{0x034F, 0xA8},
+	{0x30BF, 0xAB},/* outif_enable[7], data_type[5:0](2Bh = bayer 10bit} */
+	{0x30C0, 0x80},/* video_offset[7:4] 3260%12 */
+	{0x30C8, 0x0C},/* video_data_length 3260 = 2608 * 1.25 */
+	{0x30C9, 0xBC},
+	/*Timing configuration*/
+	{0x0202, 0x06},
+	{0x0203, 0x28},
+	{0x0204, 0x00},
+	{0x0205, 0x80},
+	{0x0340, 0x07},/* Frame Length */
+	{0x0341, 0xB4},
+	{0x0342, 0x0A},/* 2738 Line Length */
+	{0x0343, 0xB2},
+};
+
+static struct msm_camera_i2c_reg_conf s5k4e1_recommend_settings[] = {
+	/* Reset setting */
+	{0x0103, 0x01},
+	/* MIPI settings */
+	{0x30BD, 0x00},/* SEL_CCP[0] */
+	{0x3084, 0x15},/* SYNC Mode */
+	{0x30BE, 0x1A},/* M_PCLKDIV_AUTO[4], M_DIV_PCLK[3:0] */
+	{0x30C1, 0x01},/* pack video enable [0] */
+	{0x30EE, 0x02},/* DPHY enable [ 1] */
+	{0x3111, 0x86},/* Embedded data off [5] */
+
+	/* REC Settings */
+	/*CDS timing setting ... */
+	{0x3000, 0x05},
+	{0x3001, 0x03},
+	{0x3002, 0x08},
+	{0x3003, 0x0A},
+	{0x3004, 0x50},
+	{0x3005, 0x0E},
+	{0x3006, 0x5E},
+	{0x3007, 0x00},
+	{0x3008, 0x78},
+	{0x3009, 0x78},
+	{0x300A, 0x50},
+	{0x300B, 0x08},
+	{0x300C, 0x14},
+	{0x300D, 0x00},
+	{0x300E, 0xE8},
+	{0x300F, 0x82},
+	{0x301B, 0x77},
+
+	/* CDS option setting ... */
+	{0x3010, 0x00},
+	{0x3011, 0x3A},
+	{0x3029, 0x04},
+	{0x3012, 0x30},
+	{0x3013, 0xA0},
+	{0x3014, 0x00},
+	{0x3015, 0x00},
+	{0x3016, 0x30},
+	{0x3017, 0x94},
+	{0x3018, 0x70},
+	{0x301D, 0xD4},
+	{0x3021, 0x02},
+	{0x3022, 0x24},
+	{0x3024, 0x40},
+	{0x3027, 0x08},
+
+	/* Pixel option setting ...   */
+	{0x301C, 0x04},
+	{0x30D8, 0x3F},
+	{0x302B, 0x01},
+
+	{0x3070, 0x5F},
+	{0x3071, 0x00},
+	{0x3080, 0x04},
+	{0x3081, 0x38},
+
+	/* PLL settings */
+	{0x0305, 0x04},
+	{0x0306, 0x00},
+	{0x0307, 0x44},
+	{0x30B5, 0x00},
+	{0x30E2, 0x01},/* num lanes[1:0] = 2 */
+	{0x30F1, 0xB0},
+};
+
+static struct v4l2_subdev_info s5k4e1_subdev_info[] = {
+	{
+	.code   = V4L2_MBUS_FMT_SGRBG10_1X10,
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	.fmt    = 1,
+	.order    = 0,
+	},
+	/* more can be supported, to be added later */
+};
+
+static struct msm_camera_i2c_conf_array s5k4e1_init_conf[] = {
+	{&s5k4e1_recommend_settings[0],
+	ARRAY_SIZE(s5k4e1_recommend_settings), 0, MSM_CAMERA_I2C_BYTE_DATA}
+};
+
+static struct msm_camera_i2c_conf_array s5k4e1_confs[] = {
+	{&s5k4e1_snap_settings[0],
+	ARRAY_SIZE(s5k4e1_snap_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+	{&s5k4e1_prev_settings[0],
+	ARRAY_SIZE(s5k4e1_prev_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+};
+
+static struct msm_sensor_output_info_t s5k4e1_dimensions[] = {
+	{
+		.x_output = 0xA30,
+		.y_output = 0x7A8,
+		.line_length_pclk = 0xAB2,
+		.frame_length_lines = 0x7B4,
+		.vt_pixel_clk = 816000000,
+		.op_pixel_clk = 816000000,
+		.binning_factor = 0,
+	},
+	{
+		.x_output = 0x518,
+		.y_output = 0x3D4,
+		.line_length_pclk = 0xAB2,
+		.frame_length_lines = 0x3E0,
+		.vt_pixel_clk = 816000000,
+		.op_pixel_clk = 816000000,
+		.binning_factor = 1,
+	},
+};
+
+static struct msm_camera_csi_params s5k4e1_csi_params = {
+	.data_format = CSI_10BIT,
+	.lane_cnt    = 1,
+	.lane_assign = 0xe4,
+	.dpcm_scheme = 0,
+	.settle_cnt  = 24,
+};
+
+static struct msm_camera_csi_params *s5k4e1_csi_params_array[] = {
+	&s5k4e1_csi_params,
+	&s5k4e1_csi_params,
+};
+
+static struct msm_sensor_output_reg_addr_t s5k4e1_reg_addr = {
+	.x_output = 0x034C,
+	.y_output = 0x034E,
+	.line_length_pclk = 0x0342,
+	.frame_length_lines = 0x0340,
+};
+
+static struct msm_sensor_id_info_t s5k4e1_id_info = {
+	.sensor_id_reg_addr = 0x0000,
+	.sensor_id = 0x4E10,
+};
+
+static struct msm_sensor_exp_gain_info_t s5k4e1_exp_gain_info = {
+	.coarse_int_time_addr = 0x0202,
+	.global_gain_addr = 0x0204,
+	.vert_offset = 4,
+};
+
+static inline uint8_t s5k4e1_byte(uint16_t word, uint8_t offset)
+{
+	return word >> (offset * BITS_PER_BYTE);
+}
+
+static int32_t s5k4e1_write_prev_exp_gain(struct msm_sensor_ctrl_t *s_ctrl,
+						uint16_t gain, uint32_t line)
+{
+	uint16_t max_legal_gain = 0x0200;
+	int32_t rc = 0;
+	static uint32_t fl_lines, offset;
+
+	pr_info("s5k4e1_write_prev_exp_gain :%d %d\n", gain, line);
+	offset = s_ctrl->sensor_exp_gain_info->vert_offset;
+	if (gain > max_legal_gain) {
+		CDBG("Max legal gain Line:%d\n", __LINE__);
+		gain = max_legal_gain;
+	}
+
+	/* Analogue Gain */
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->global_gain_addr,
+		s5k4e1_byte(gain, MSB),
+		MSM_CAMERA_I2C_BYTE_DATA);
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->global_gain_addr + 1,
+		s5k4e1_byte(gain, LSB),
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	if (line > (s_ctrl->curr_frame_length_lines - offset)) {
+		fl_lines = line + offset;
+		s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
+		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+			s_ctrl->sensor_output_reg_addr->frame_length_lines,
+			s5k4e1_byte(fl_lines, MSB),
+			MSM_CAMERA_I2C_BYTE_DATA);
+		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+			s_ctrl->sensor_output_reg_addr->frame_length_lines + 1,
+			s5k4e1_byte(fl_lines, LSB),
+			MSM_CAMERA_I2C_BYTE_DATA);
+		/* Coarse Integration Time */
+		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+			s_ctrl->sensor_exp_gain_info->coarse_int_time_addr,
+			s5k4e1_byte(line, MSB),
+			MSM_CAMERA_I2C_BYTE_DATA);
+		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+			s_ctrl->sensor_exp_gain_info->coarse_int_time_addr + 1,
+			s5k4e1_byte(line, LSB),
+			MSM_CAMERA_I2C_BYTE_DATA);
+		s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
+	} else if (line < (fl_lines - offset)) {
+		fl_lines = line + offset;
+		if (fl_lines < s_ctrl->curr_frame_length_lines)
+			fl_lines = s_ctrl->curr_frame_length_lines;
+
+		s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
+		/* Coarse Integration Time */
+		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+			s_ctrl->sensor_exp_gain_info->coarse_int_time_addr,
+			s5k4e1_byte(line, MSB),
+			MSM_CAMERA_I2C_BYTE_DATA);
+		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+			s_ctrl->sensor_exp_gain_info->coarse_int_time_addr + 1,
+			s5k4e1_byte(line, LSB),
+			MSM_CAMERA_I2C_BYTE_DATA);
+		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+			s_ctrl->sensor_output_reg_addr->frame_length_lines,
+			s5k4e1_byte(fl_lines, MSB),
+			MSM_CAMERA_I2C_BYTE_DATA);
+		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+			s_ctrl->sensor_output_reg_addr->frame_length_lines + 1,
+			s5k4e1_byte(fl_lines, LSB),
+			MSM_CAMERA_I2C_BYTE_DATA);
+		s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
+	} else {
+		fl_lines = line+4;
+		s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
+		/* Coarse Integration Time */
+		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+			s_ctrl->sensor_exp_gain_info->coarse_int_time_addr,
+			s5k4e1_byte(line, MSB),
+			MSM_CAMERA_I2C_BYTE_DATA);
+		msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+			s_ctrl->sensor_exp_gain_info->coarse_int_time_addr + 1,
+			s5k4e1_byte(line, LSB),
+			MSM_CAMERA_I2C_BYTE_DATA);
+		s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
+	}
+	return rc;
+}
+
+static int32_t s5k4e1_write_pict_exp_gain(struct msm_sensor_ctrl_t *s_ctrl,
+		uint16_t gain, uint32_t line)
+{
+	uint16_t max_legal_gain = 0x0200;
+	uint16_t min_ll_pck = 0x0AB2;
+	uint32_t ll_pck, fl_lines;
+	uint32_t ll_ratio;
+	uint8_t gain_msb, gain_lsb;
+	uint8_t intg_time_msb, intg_time_lsb;
+	uint8_t ll_pck_msb, ll_pck_lsb;
+
+	if (gain > max_legal_gain) {
+		CDBG("Max legal gain Line:%d\n", __LINE__);
+		gain = max_legal_gain;
+	}
+
+	gain = 32;
+	line = 1465;
+	pr_info("s5k4e1_write_exp_gain : gain = %d line = %d\n", gain, line);
+	line = (uint32_t) (line * s_ctrl->fps_divider);
+	fl_lines = s_ctrl->curr_frame_length_lines * s_ctrl->fps_divider / Q10;
+	ll_pck = s_ctrl->curr_line_length_pclk;
+
+	if (fl_lines < (line / Q10))
+		ll_ratio = (line / (fl_lines - 4));
+	else
+		ll_ratio = Q10;
+
+	ll_pck = ll_pck * ll_ratio / Q10;
+	line = line / ll_ratio;
+	if (ll_pck < min_ll_pck)
+		ll_pck = min_ll_pck;
+
+	gain_msb = (uint8_t) ((gain & 0xFF00) >> 8);
+	gain_lsb = (uint8_t) (gain & 0x00FF);
+
+	intg_time_msb = (uint8_t) ((line & 0xFF00) >> 8);
+	intg_time_lsb = (uint8_t) (line & 0x00FF);
+
+	ll_pck_msb = (uint8_t) ((ll_pck & 0xFF00) >> 8);
+	ll_pck_lsb = (uint8_t) (ll_pck & 0x00FF);
+
+	s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->global_gain_addr,
+		gain_msb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->global_gain_addr + 1,
+		gain_lsb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_output_reg_addr->line_length_pclk,
+		ll_pck_msb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_output_reg_addr->line_length_pclk + 1,
+		ll_pck_lsb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+
+	/* Coarse Integration Time */
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr,
+		intg_time_msb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+	msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+		s_ctrl->sensor_exp_gain_info->coarse_int_time_addr + 1,
+		intg_time_lsb,
+		MSM_CAMERA_I2C_BYTE_DATA);
+	s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
+
+	return 0;
+}
+
+static const struct i2c_device_id s5k4e1_i2c_id[] = {
+	{SENSOR_NAME, (kernel_ulong_t)&s5k4e1_s_ctrl},
+	{ }
+};
+
+static struct i2c_driver s5k4e1_i2c_driver = {
+	.id_table = s5k4e1_i2c_id,
+	.probe  = msm_sensor_i2c_probe,
+	.driver = {
+		.name = SENSOR_NAME,
+	},
+};
+
+static struct msm_camera_i2c_client s5k4e1_sensor_i2c_client = {
+	.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+static int __init msm_sensor_init_module(void)
+{
+	return i2c_add_driver(&s5k4e1_i2c_driver);
+}
+
+static struct v4l2_subdev_core_ops s5k4e1_subdev_core_ops = {
+	.ioctl = msm_sensor_subdev_ioctl,
+	.s_power = msm_sensor_power,
+};
+
+static struct v4l2_subdev_video_ops s5k4e1_subdev_video_ops = {
+	.enum_mbus_fmt = msm_sensor_v4l2_enum_fmt,
+};
+
+static struct v4l2_subdev_ops s5k4e1_subdev_ops = {
+	.core = &s5k4e1_subdev_core_ops,
+	.video  = &s5k4e1_subdev_video_ops,
+};
+
+static struct msm_sensor_fn_t s5k4e1_func_tbl = {
+	.sensor_start_stream = msm_sensor_start_stream,
+	.sensor_stop_stream = msm_sensor_stop_stream,
+	.sensor_group_hold_on = msm_sensor_group_hold_on,
+	.sensor_group_hold_off = msm_sensor_group_hold_off,
+	.sensor_set_fps = msm_sensor_set_fps,
+	.sensor_write_exp_gain = s5k4e1_write_prev_exp_gain,
+	.sensor_write_snapshot_exp_gain = s5k4e1_write_pict_exp_gain,
+	.sensor_setting = msm_sensor_setting1,
+	.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
+	.sensor_mode_init = msm_sensor_mode_init,
+	.sensor_get_output_info = msm_sensor_get_output_info,
+	.sensor_config = msm_sensor_config,
+	.sensor_power_up = msm_sensor_power_up,
+	.sensor_power_down = msm_sensor_power_down,
+};
+
+static struct msm_sensor_reg_t s5k4e1_regs = {
+	.default_data_type = MSM_CAMERA_I2C_BYTE_DATA,
+	.start_stream_conf = s5k4e1_start_settings,
+	.start_stream_conf_size = ARRAY_SIZE(s5k4e1_start_settings),
+	.stop_stream_conf = s5k4e1_stop_settings,
+	.stop_stream_conf_size = ARRAY_SIZE(s5k4e1_stop_settings),
+	.group_hold_on_conf = s5k4e1_groupon_settings,
+	.group_hold_on_conf_size = ARRAY_SIZE(s5k4e1_groupon_settings),
+	.group_hold_off_conf = s5k4e1_groupoff_settings,
+	.group_hold_off_conf_size =
+		ARRAY_SIZE(s5k4e1_groupoff_settings),
+	.init_settings = &s5k4e1_init_conf[0],
+	.init_size = ARRAY_SIZE(s5k4e1_init_conf),
+	.mode_settings = &s5k4e1_confs[0],
+	.output_settings = &s5k4e1_dimensions[0],
+	.num_conf = ARRAY_SIZE(s5k4e1_confs),
+};
+
+static struct msm_sensor_ctrl_t s5k4e1_s_ctrl = {
+	.msm_sensor_reg = &s5k4e1_regs,
+	.sensor_i2c_client = &s5k4e1_sensor_i2c_client,
+	.sensor_i2c_addr = 0x6C,
+	.sensor_output_reg_addr = &s5k4e1_reg_addr,
+	.sensor_id_info = &s5k4e1_id_info,
+	.sensor_exp_gain_info = &s5k4e1_exp_gain_info,
+	.cam_mode = MSM_SENSOR_MODE_INVALID,
+	.csic_params = &s5k4e1_csi_params_array[0],
+	.msm_sensor_mutex = &s5k4e1_mut,
+	.sensor_i2c_driver = &s5k4e1_i2c_driver,
+	.sensor_v4l2_subdev_info = s5k4e1_subdev_info,
+	.sensor_v4l2_subdev_info_size = ARRAY_SIZE(s5k4e1_subdev_info),
+	.sensor_v4l2_subdev_ops = &s5k4e1_subdev_ops,
+	.func_tbl = &s5k4e1_func_tbl,
+};
+
+module_init(msm_sensor_init_module);
+MODULE_DESCRIPTION("Samsung 5MP Bayer sensor driver");
+MODULE_LICENSE("GPL v2");
+
+
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c
index fa30ef2..2c99a7f 100644
--- a/drivers/mfd/pm8921-core.c
+++ b/drivers/mfd/pm8921-core.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -42,6 +42,7 @@
 #define PM8921_VERSION_MASK	0xFFF0
 #define PM8921_VERSION_VALUE	0x06F0
 #define PM8922_VERSION_VALUE	0x0AF0
+#define PM8917_VERSION_VALUE	0x12F0
 #define PM8921_REVISION_MASK	0x000F
 
 #define REG_PM8921_PON_CNTRL_3	0x01D
@@ -116,6 +117,9 @@
 	else if ((pmic->rev_registers & PM8921_VERSION_MASK)
 			== PM8922_VERSION_VALUE)
 		version = PM8XXX_VERSION_8922;
+	else if ((pmic->rev_registers & PM8921_VERSION_MASK)
+			== PM8917_VERSION_VALUE)
+		version = PM8XXX_VERSION_8917;
 
 	return version;
 }
@@ -138,7 +142,7 @@
 	.pmic_get_revision	= pm8921_get_revision,
 };
 
-static const struct resource gpio_cell_resources[] __devinitconst = {
+static struct resource gpio_cell_resources[] = {
 	[0] = {
 		.start = PM8921_IRQ_BLOCK_BIT(PM8921_GPIO_BLOCK_START, 0),
 		.end   = PM8921_IRQ_BLOCK_BIT(PM8921_GPIO_BLOCK_START, 0)
@@ -167,7 +171,7 @@
 	.num_resources	= ARRAY_SIZE(adc_cell_resources),
 };
 
-static const struct resource mpp_cell_resources[] __devinitconst = {
+static struct resource mpp_cell_resources[] = {
 	{
 		.start	= PM8921_IRQ_BLOCK_BIT(PM8921_MPP_BLOCK_START, 0),
 		.end	= PM8921_IRQ_BLOCK_BIT(PM8921_MPP_BLOCK_START, 0)
@@ -545,7 +549,14 @@
 	}
 
 	if (pdata->gpio_pdata) {
-		pdata->gpio_pdata->gpio_cdata.ngpios = PM8921_NR_GPIOS;
+		if (version == PM8XXX_VERSION_8917) {
+			gpio_cell_resources[0].end = gpio_cell_resources[0].end
+							+ PM8917_NR_GPIOS
+							- PM8921_NR_GPIOS;
+			pdata->gpio_pdata->gpio_cdata.ngpios = PM8917_NR_GPIOS;
+		} else {
+			pdata->gpio_pdata->gpio_cdata.ngpios = PM8921_NR_GPIOS;
+		}
 		gpio_cell.platform_data = pdata->gpio_pdata;
 		gpio_cell.pdata_size = sizeof(struct pm8xxx_gpio_platform_data);
 		ret = mfd_add_devices(pmic->dev, 0, &gpio_cell, 1,
@@ -557,7 +568,14 @@
 	}
 
 	if (pdata->mpp_pdata) {
-		pdata->mpp_pdata->core_data.nmpps = PM8921_NR_MPPS;
+		if (version == PM8XXX_VERSION_8917) {
+			mpp_cell_resources[0].end = mpp_cell_resources[0].end
+							+ PM8917_NR_MPPS
+							- PM8921_NR_MPPS;
+			pdata->mpp_pdata->core_data.nmpps = PM8917_NR_MPPS;
+		} else {
+			pdata->mpp_pdata->core_data.nmpps = PM8921_NR_MPPS;
+		}
 		pdata->mpp_pdata->core_data.base_addr = REG_MPP_BASE;
 		mpp_cell.platform_data = pdata->mpp_pdata;
 		mpp_cell.pdata_size = sizeof(struct pm8xxx_mpp_platform_data);
@@ -665,12 +683,6 @@
 		goto bail;
 	}
 
-	ret = mfd_add_devices(pmic->dev, 0, &pwm_cell, 1, NULL, 0);
-	if (ret) {
-		pr_err("Failed to add pwm subdevice ret=%d\n", ret);
-		goto bail;
-	}
-
 	if (pdata->misc_pdata) {
 		misc_cell.platform_data = pdata->misc_pdata;
 		misc_cell.pdata_size = sizeof(struct pm8xxx_misc_platform_data);
@@ -682,16 +694,6 @@
 		}
 	}
 
-	if (pdata->leds_pdata) {
-		leds_cell.platform_data = pdata->leds_pdata;
-		leds_cell.pdata_size = sizeof(struct pm8xxx_led_platform_data);
-		ret = mfd_add_devices(pmic->dev, 0, &leds_cell, 1, NULL, 0);
-		if (ret) {
-			pr_err("Failed to add leds subdevice ret=%d\n", ret);
-			goto bail;
-		}
-	}
-
 	ret = mfd_add_devices(pmic->dev, 0, &thermal_alarm_cell, 1, NULL,
 				irq_base);
 	if (ret) {
@@ -708,16 +710,37 @@
 		goto bail;
 	}
 
-	if (pdata->vibrator_pdata) {
-		vibrator_cell.platform_data = pdata->vibrator_pdata;
-		vibrator_cell.pdata_size =
-				sizeof(struct pm8xxx_vibrator_platform_data);
-		ret = mfd_add_devices(pmic->dev, 0, &vibrator_cell, 1, NULL, 0);
+	if (version != PM8XXX_VERSION_8917) {
+		ret = mfd_add_devices(pmic->dev, 0, &pwm_cell, 1, NULL, 0);
 		if (ret) {
-			pr_err("Failed to add vibrator subdevice ret=%d\n",
-									ret);
+			pr_err("Failed to add pwm subdevice ret=%d\n", ret);
 			goto bail;
 		}
+
+		if (pdata->leds_pdata) {
+			leds_cell.platform_data = pdata->leds_pdata;
+			leds_cell.pdata_size =
+				sizeof(struct pm8xxx_led_platform_data);
+			ret = mfd_add_devices(pmic->dev, 0, &leds_cell,
+					      1, NULL, 0);
+			if (ret) {
+				pr_err("Failed to add leds subdevice ret=%d\n",
+						ret);
+				goto bail;
+			}
+		}
+
+		if (pdata->vibrator_pdata) {
+			vibrator_cell.platform_data = pdata->vibrator_pdata;
+			vibrator_cell.pdata_size =
+				sizeof(struct pm8xxx_vibrator_platform_data);
+			ret = mfd_add_devices(pmic->dev, 0, &vibrator_cell,
+					      1, NULL, 0);
+			if (ret) {
+				pr_err("Failed to add vibrator ret=%d\n", ret);
+				goto bail;
+			}
+		}
 	}
 
 	if (pdata->ccadc_pdata) {
@@ -768,6 +791,11 @@
 	[PM8XXX_REVISION_8922_2p0]	= "2.0",
 };
 
+static const char * const pm8917_rev_names[] = {
+	[PM8XXX_REVISION_8917_TEST]	= "test",
+	[PM8XXX_REVISION_8917_1p0]	= "1.0",
+};
+
 static int __devinit pm8921_probe(struct platform_device *pdev)
 {
 	const struct pm8921_platform_data *pdata = pdev->dev.platform_data;
@@ -823,9 +851,14 @@
 		if (revision >= 0 && revision < ARRAY_SIZE(pm8922_rev_names))
 			revision_name = pm8922_rev_names[revision];
 		pr_info("PMIC version: PM8922 rev %s\n", revision_name);
+	} else if (version == PM8XXX_VERSION_8917) {
+		if (revision >= 0 && revision < ARRAY_SIZE(pm8917_rev_names))
+			revision_name = pm8917_rev_names[revision];
+		pr_info("PMIC version: PM8917 rev %s\n", revision_name);
 	} else {
 		WARN_ON(version != PM8XXX_VERSION_8921
-			&& version != PM8XXX_VERSION_8922);
+			&& version != PM8XXX_VERSION_8922
+			&& version != PM8XXX_VERSION_8917);
 	}
 
 	/* Log human readable restart reason */
diff --git a/drivers/net/wireless/libra/qcomwlan_pwrif.c b/drivers/net/wireless/libra/qcomwlan_pwrif.c
index 6dd603c..8268f24 100644
--- a/drivers/net/wireless/libra/qcomwlan_pwrif.c
+++ b/drivers/net/wireless/libra/qcomwlan_pwrif.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -69,6 +69,15 @@
 		1300000,
 		1250000,
 	};
+	static const int vregs_qwlan_peek_current[] = {
+		4000,
+		150000,
+		200000,
+		0,
+		32000,
+		130000,
+		0,
+	};
 	static const bool vregs_is_pin_controlled_default[] = {
 		1,
 		1,
@@ -180,6 +189,15 @@
 			}
 		}
 		if (on && !wlan_on) {
+			if (vregs_qwlan_peek_current[i]) {
+				rc = regulator_set_optimum_mode(vregs_qwlan[i],
+						vregs_qwlan_peek_current[i]);
+				if (rc < 0)
+					pr_err("vreg %s set optimum mode"
+						" failed to %d (%d)\n",
+						vregs_qwlan_name[i], rc,
+						 vregs_qwlan_peek_current[i]);
+			}
 			rc = regulator_enable(vregs_qwlan[i]);
 			if (rc < 0) {
 				pr_err("vreg %s enable failed (%d)\n",
@@ -195,6 +213,26 @@
 				}
 			}
 		} else if (!on && wlan_on) {
+
+			if (vregs_qwlan_peek_current[i]) {
+				/* For legacy reasons we pass 1mA current to
+				 * put regulator in LPM mode.
+				 */
+				rc = regulator_set_optimum_mode(vregs_qwlan[i],
+									 1000);
+				if (rc < 0)
+					pr_info("vreg %s set optimum mode"
+								"failed (%d)\n",
+						vregs_qwlan_name[i], rc);
+				rc = regulator_set_voltage(vregs_qwlan[i], 0 ,
+							vregs_qwlan_val_max[i]);
+				if (rc)
+					pr_err("regulator_set_voltage(%s)"
+								"failed (%d)\n",
+						vregs_qwlan_name[i], rc);
+
+			}
+
 			if (vregs_is_pin_controlled[i]) {
 				rc = regulator_disable(vregs_pc_qwlan[i]);
 				if (rc < 0) {
@@ -202,13 +240,16 @@
 						vregs_qwlan_pc_name[i], rc);
 					goto vreg_fail;
 				}
+				regulator_put(vregs_pc_qwlan[i]);
 			}
+
 			rc = regulator_disable(vregs_qwlan[i]);
 			if (rc < 0) {
 				pr_err("vreg %s disable failed (%d)\n",
 						vregs_qwlan_name[i], rc);
 				goto vreg_fail;
 			}
+			regulator_put(vregs_qwlan[i]);
 		}
 	}
 	if (on) {
diff --git a/drivers/net/wireless/wcnss/wcnss_riva.c b/drivers/net/wireless/wcnss/wcnss_riva.c
index fe6abf2..f6997ac 100644
--- a/drivers/net/wireless/wcnss/wcnss_riva.c
+++ b/drivers/net/wireless/wcnss/wcnss_riva.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
@@ -22,6 +22,7 @@
 #include <linux/semaphore.h>
 #include <linux/list.h>
 #include <linux/slab.h>
+#include <linux/clk.h>
 #include <mach/msm_xo.h>
 #include <mach/msm_iomap.h>
 
@@ -79,10 +80,15 @@
 };
 
 
-static int configure_iris_xo(bool use_48mhz_xo, int on)
+static int configure_iris_xo(struct device *dev, bool use_48mhz_xo, int on)
 {
 	u32 reg = 0;
 	int rc = 0;
+	struct clk *cxo = clk_get(dev, "cxo");
+	if (IS_ERR(cxo)) {
+		pr_err("Couldn't get cxo clock\n");
+		return PTR_ERR(cxo);
+	}
 
 	if (on) {
 		msm_riva_base = ioremap(MSM_RIVA_PHYS, SZ_256);
@@ -92,6 +98,11 @@
 		}
 
 		/* Enable IRIS XO */
+		rc = clk_prepare_enable(cxo);
+		if (rc) {
+			pr_err("cxo enable failed\n");
+			goto fail;
+		}
 		writel_relaxed(0, RIVA_PMU_CFG);
 		reg = readl_relaxed(RIVA_PMU_CFG);
 		reg |= RIVA_PMU_CFG_GC_BUS_MUX_SEL_TOP |
@@ -119,6 +130,7 @@
 		reg &= ~(RIVA_PMU_CFG_GC_BUS_MUX_SEL_TOP |
 				RIVA_PMU_CFG_IRIS_XO_CFG);
 		writel_relaxed(reg, RIVA_PMU_CFG);
+		clk_disable_unprepare(cxo);
 
 		if (!use_48mhz_xo) {
 			wlan_clock = msm_xo_get(MSM_XO_TCXO_A2, id);
@@ -148,12 +160,14 @@
 	/* Add some delay for XO to settle */
 	msleep(20);
 
+	clk_put(cxo);
 	return rc;
 
 msm_xo_vote_fail:
 	msm_xo_put(wlan_clock);
 
 fail:
+	clk_put(cxo);
 	return rc;
 }
 
@@ -302,13 +316,15 @@
 			goto fail_iris_on;
 
 		/* Configure IRIS XO */
-		rc = configure_iris_xo(cfg->use_48mhz_xo, WCNSS_WLAN_SWITCH_ON);
+		rc = configure_iris_xo(dev, cfg->use_48mhz_xo,
+				WCNSS_WLAN_SWITCH_ON);
 		if (rc)
 			goto fail_iris_xo;
 		up(&riva_power_on_lock);
 
 	} else {
-		configure_iris_xo(cfg->use_48mhz_xo, WCNSS_WLAN_SWITCH_OFF);
+		configure_iris_xo(dev, cfg->use_48mhz_xo,
+				WCNSS_WLAN_SWITCH_OFF);
 		wcnss_iris_vregs_off();
 		wcnss_riva_vregs_off();
 	}
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 787514c..3d739ae 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -2450,7 +2450,7 @@
 		goto free_regs;
 	}
 
-	motg->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "usb");
+	motg->xo_handle = msm_xo_get(MSM_XO_CXO, "usb");
 	if (IS_ERR(motg->xo_handle)) {
 		dev_err(&pdev->dev, "%s not able to get the handle "
 			"to vote for TCXO D0 buffer\n", __func__);
diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig
index 448194a..f261931 100644
--- a/drivers/video/msm/Kconfig
+++ b/drivers/video/msm/Kconfig
@@ -93,6 +93,10 @@
 	bool
 	default n
 
+config FB_MSM_LVDS
+	bool
+	default n
+
 config FB_MSM_OVERLAY
 	depends on FB_MSM_MDP40 && ANDROID_PMEM
 	bool "MDP4 overlay support"
@@ -247,6 +251,11 @@
 	select FB_MSM_LCDC_PANEL
 	default n
 
+config FB_MSM_LVDS_CHIMEI_WXGA
+	bool
+	select FB_MSM_LVDS
+	default n
+
 config FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT
 	bool
 	select FB_MSM_MIPI_DSI_TOSHIBA
@@ -389,6 +398,12 @@
 	---help---
 	  Support for LCDC Samsung OLED PT (480x800) panel
 
+config FB_MSM_LVDS_CHIMEI_WXGA_PANEL
+        bool "LVDS Chimei WXGA Panel"
+        select FB_MSM_LVDS_CHIMEI_WXGA
+        ---help---
+          Support for LVDS Chimei WXGA(1366x768) panel
+
 config FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
 	depends on FB_MSM_LCDC_HW
 	bool "MDDI Panel Auto Detect + LCDC Prism WVGA"
diff --git a/drivers/video/msm/Makefile b/drivers/video/msm/Makefile
index dc02da4..2d40b15 100644
--- a/drivers/video/msm/Makefile
+++ b/drivers/video/msm/Makefile
@@ -56,6 +56,9 @@
 # LCDC
 obj-$(CONFIG_FB_MSM_LCDC) += lcdc.o
 
+# LVDS
+obj-$(CONFIG_FB_MSM_LVDS) += lvds.o
+
 # MDDI
 msm_mddi-objs := mddi.o mddihost.o mddihosti.o
 obj-$(CONFIG_FB_MSM_MDDI) += msm_mddi.o
@@ -143,6 +146,7 @@
 obj-$(CONFIG_FB_MSM_LCDC_SAMSUNG_OLED_PT) += lcdc_samsung_oled_pt.o
 obj-$(CONFIG_FB_MSM_HDMI_ADV7520_PANEL) += adv7520.o
 obj-$(CONFIG_FB_MSM_LCDC_ST15_WXGA) += lcdc_st15.o
+obj-$(CONFIG_FB_MSM_LVDS_CHIMEI_WXGA) += lvds_chimei_wxga.o
 obj-$(CONFIG_FB_MSM_HDMI_MSM_PANEL) += hdmi_msm.o
 obj-$(CONFIG_FB_MSM_EXT_INTERFACE_COMMON) += external_common.o
 
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index fc6054f..b5fcf0d 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -726,15 +726,6 @@
 		DEV_DBG("%s: ignored, probe failed\n", __func__);
 		return;
 	}
-#ifdef CONFIG_SUSPEND
-	mutex_lock(&hdmi_msm_state_mutex);
-	if (hdmi_msm_state->pm_suspended) {
-		mutex_unlock(&hdmi_msm_state_mutex);
-		DEV_WARN("%s: ignored, pm_suspended\n", __func__);
-		return;
-	}
-	mutex_unlock(&hdmi_msm_state_mutex);
-#endif
 
 	DEV_DBG("%s:Got interrupt\n", __func__);
 	/* HPD_INT_STATUS[0x0250] */
@@ -839,15 +830,6 @@
 static void hdcp_deauthenticate(void);
 static void hdmi_msm_hdcp_reauth_work(struct work_struct *work)
 {
-#ifdef CONFIG_SUSPEND
-	mutex_lock(&hdmi_msm_state_mutex);
-	if (hdmi_msm_state->pm_suspended) {
-		mutex_unlock(&hdmi_msm_state_mutex);
-		DEV_WARN("HDCP: deauthenticating skipped, pm_suspended\n");
-		return;
-	}
-	mutex_unlock(&hdmi_msm_state_mutex);
-#endif
 
 	/* Don't process recursive actions */
 	mutex_lock(&hdmi_msm_state_mutex);
@@ -873,15 +855,6 @@
 
 static void hdmi_msm_hdcp_work(struct work_struct *work)
 {
-#ifdef CONFIG_SUSPEND
-	mutex_lock(&hdmi_msm_state_mutex);
-	if (hdmi_msm_state->pm_suspended) {
-		mutex_unlock(&hdmi_msm_state_mutex);
-		DEV_WARN("HDCP: Re-enable skipped, pm_suspended\n");
-		return;
-	}
-	mutex_unlock(&hdmi_msm_state_mutex);
-#endif
 
 	/* Only re-enable if cable still connected */
 	mutex_lock(&external_common_state_hpd_mutex);
@@ -917,15 +890,6 @@
 		DEV_DBG("ISR ignored, probe failed\n");
 		return IRQ_HANDLED;
 	}
-#ifdef CONFIG_SUSPEND
-	mutex_lock(&hdmi_msm_state_mutex);
-	if (hdmi_msm_state->pm_suspended) {
-		mutex_unlock(&hdmi_msm_state_mutex);
-		DEV_WARN("ISR ignored, pm_suspended\n");
-		return IRQ_HANDLED;
-	}
-	mutex_unlock(&hdmi_msm_state_mutex);
-#endif
 
 	/* Process HPD Interrupt */
 	/* HDMI_HPD_INT_STATUS[0x0250] */
@@ -3956,7 +3920,6 @@
 	disable_irq(hdmi_msm_state->irq);
 
 	hdmi_msm_set_mode(FALSE);
-	HDMI_OUTP_ND(0x0308, 0x7F); /*0b01111111*/
 	hdmi_msm_state->hpd_initialized = FALSE;
 	hdmi_msm_state->pd->cec_power(0);
 	hdmi_msm_state->pd->enable_5v(0);
@@ -4035,15 +3998,6 @@
 
 	if (!hdmi_msm_state || !hdmi_msm_state->hdmi_app_clk || !MSM_HDMI_BASE)
 		return -ENODEV;
-#ifdef CONFIG_SUSPEND
-	mutex_lock(&hdmi_msm_state_mutex);
-	if (hdmi_msm_state->pm_suspended) {
-		mutex_unlock(&hdmi_msm_state_mutex);
-		DEV_WARN("%s: ignored, pm_suspended\n", __func__);
-		return -ENODEV;
-	}
-	mutex_unlock(&hdmi_msm_state_mutex);
-#endif
 
 	DEV_INFO("power: ON (%dx%d %d)\n", mfd->var_xres, mfd->var_yres,
 		mfd->var_pixclock);
@@ -4095,15 +4049,6 @@
 {
 	if (!hdmi_msm_state->hdmi_app_clk)
 		return -ENODEV;
-#ifdef CONFIG_SUSPEND
-	mutex_lock(&hdmi_msm_state_mutex);
-	if (hdmi_msm_state->pm_suspended) {
-		mutex_unlock(&hdmi_msm_state_mutex);
-		DEV_WARN("%s: ignored, pm_suspended\n", __func__);
-		return -ENODEV;
-	}
-	mutex_unlock(&hdmi_msm_state_mutex);
-#endif
 
 #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
 	mutex_lock(&hdmi_msm_state_mutex);
@@ -4369,71 +4314,10 @@
 	return rc;
 }
 
-
-#ifdef CONFIG_SUSPEND
-static int hdmi_msm_device_pm_suspend(struct device *dev)
-{
-	mutex_lock(&hdmi_msm_state_mutex);
-	if (hdmi_msm_state->pm_suspended) {
-		mutex_unlock(&hdmi_msm_state_mutex);
-		return 0;
-	}
-
-	DEV_DBG("pm_suspend\n");
-
-	del_timer(&hdmi_msm_state->hpd_state_timer);
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
-	del_timer(&hdmi_msm_state->hdcp_timer);
-#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
-
-	disable_irq(hdmi_msm_state->irq);
-	if (external_common_state->hpd_feature_on)
-		hdmi_msm_clk(0);
-
-	hdmi_msm_state->pm_suspended = TRUE;
-	mutex_unlock(&hdmi_msm_state_mutex);
-
-	hdmi_msm_powerdown_phy();
-	hdmi_msm_state->pd->enable_5v(0);
-	hdmi_msm_state->pd->core_power(0, 1);
-	return 0;
-}
-
-static int hdmi_msm_device_pm_resume(struct device *dev)
-{
-	mutex_lock(&hdmi_msm_state_mutex);
-	if (!hdmi_msm_state->pm_suspended) {
-		mutex_unlock(&hdmi_msm_state_mutex);
-		return 0;
-	}
-
-	DEV_DBG("pm_resume\n");
-
-	hdmi_msm_state->pd->core_power(1, 1);
-	hdmi_msm_state->pd->enable_5v(1);
-	if (external_common_state->hpd_feature_on)
-		hdmi_msm_clk(1);
-
-	hdmi_msm_state->pm_suspended = FALSE;
-	mutex_unlock(&hdmi_msm_state_mutex);
-	enable_irq(hdmi_msm_state->irq);
-	return 0;
-}
-#else
-#define hdmi_msm_device_pm_suspend	NULL
-#define hdmi_msm_device_pm_resume	NULL
-#endif
-
-static const struct dev_pm_ops hdmi_msm_device_pm_ops = {
-	.suspend = hdmi_msm_device_pm_suspend,
-	.resume = hdmi_msm_device_pm_resume,
-};
-
 static struct platform_driver this_driver = {
 	.probe = hdmi_msm_probe,
 	.remove = hdmi_msm_remove,
 	.driver.name = "hdmi_msm",
-	.driver.pm = &hdmi_msm_device_pm_ops,
 };
 
 static struct msm_fb_panel_data hdmi_msm_panel_data = {
diff --git a/drivers/video/msm/lvds.c b/drivers/video/msm/lvds.c
new file mode 100644
index 0000000..7ef437c
--- /dev/null
+++ b/drivers/video/msm/lvds.c
@@ -0,0 +1,235 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <mach/hardware.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <mach/clk.h>
+
+#include "msm_fb.h"
+
+static int lvds_probe(struct platform_device *pdev);
+static int lvds_remove(struct platform_device *pdev);
+
+static int lvds_off(struct platform_device *pdev);
+static int lvds_on(struct platform_device *pdev);
+
+static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
+static int pdev_list_cnt;
+
+static struct clk *lvds_clk;
+
+static struct platform_driver lvds_driver = {
+	.probe = lvds_probe,
+	.remove = lvds_remove,
+	.suspend = NULL,
+	.resume = NULL,
+	.shutdown = NULL,
+	.driver = {
+		   .name = "lvds",
+		   },
+};
+
+static struct lcdc_platform_data *lvds_pdata;
+
+static int lvds_off(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct msm_fb_data_type *mfd;
+
+	mfd = platform_get_drvdata(pdev);
+	ret = panel_next_off(pdev);
+
+	clk_disable(lvds_clk);
+
+	if (lvds_pdata && lvds_pdata->lcdc_power_save)
+		lvds_pdata->lcdc_power_save(0);
+
+	if (lvds_pdata && lvds_pdata->lcdc_gpio_config)
+		ret = lvds_pdata->lcdc_gpio_config(0);
+
+#ifdef CONFIG_MSM_BUS_SCALING
+	mdp_bus_scale_update_request(0);
+#endif
+
+	return ret;
+}
+
+static int lvds_on(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct msm_fb_data_type *mfd;
+	unsigned long panel_pixclock_freq = 0;
+	mfd = platform_get_drvdata(pdev);
+
+	if (lvds_pdata && lvds_pdata->lcdc_get_clk)
+		panel_pixclock_freq = lvds_pdata->lcdc_get_clk();
+
+	if (!panel_pixclock_freq)
+		panel_pixclock_freq = mfd->fbi->var.pixclock;
+#ifdef CONFIG_MSM_BUS_SCALING
+	mdp_bus_scale_update_request(2);
+#endif
+	mfd = platform_get_drvdata(pdev);
+
+	mfd->fbi->var.pixclock = clk_round_rate(lvds_clk,
+					mfd->fbi->var.pixclock);
+	ret = clk_set_rate(lvds_clk, mfd->fbi->var.pixclock);
+	if (ret) {
+		pr_err("%s: Can't set lvds clock to rate %u\n",
+			__func__, mfd->fbi->var.pixclock);
+		goto out;
+	}
+
+	clk_enable(lvds_clk);
+
+	if (lvds_pdata && lvds_pdata->lcdc_power_save)
+		lvds_pdata->lcdc_power_save(1);
+	if (lvds_pdata && lvds_pdata->lcdc_gpio_config)
+		ret = lvds_pdata->lcdc_gpio_config(1);
+
+	ret = panel_next_on(pdev);
+
+out:
+	return ret;
+}
+
+static int lvds_probe(struct platform_device *pdev)
+{
+	struct msm_fb_data_type *mfd;
+	struct fb_info *fbi;
+	struct platform_device *mdp_dev = NULL;
+	struct msm_fb_panel_data *pdata = NULL;
+	int rc;
+
+	if (pdev->id == 0) {
+		lvds_pdata = pdev->dev.platform_data;
+		return 0;
+	}
+
+	mfd = platform_get_drvdata(pdev);
+
+	if (!mfd)
+		return -ENODEV;
+
+	if (mfd->key != MFD_KEY)
+		return -EINVAL;
+
+	if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
+		return -ENOMEM;
+
+	mdp_dev = platform_device_alloc("mdp", pdev->id);
+	if (!mdp_dev)
+		return -ENOMEM;
+
+	/*
+	 * link to the latest pdev
+	 */
+	mfd->pdev = mdp_dev;
+	mfd->dest = DISPLAY_LCDC;
+
+	/*
+	 * alloc panel device data
+	 */
+	if (platform_device_add_data
+	    (mdp_dev, pdev->dev.platform_data,
+	     sizeof(struct msm_fb_panel_data))) {
+		pr_err("lvds_probe: platform_device_add_data failed!\n");
+		platform_device_put(mdp_dev);
+		return -ENOMEM;
+	}
+	/*
+	 * data chain
+	 */
+	pdata = (struct msm_fb_panel_data *)mdp_dev->dev.platform_data;
+	pdata->on = lvds_on;
+	pdata->off = lvds_off;
+	pdata->next = pdev;
+
+	/*
+	 * get/set panel specific fb info
+	 */
+	mfd->panel_info = pdata->panel_info;
+
+	if (mfd->index == 0)
+		mfd->fb_imgType = MSMFB_DEFAULT_TYPE;
+	else
+		mfd->fb_imgType = MDP_RGB_565;
+
+	fbi = mfd->fbi;
+	fbi->var.pixclock = clk_round_rate(lvds_clk,
+					mfd->panel_info.clk_rate);
+	fbi->var.left_margin = mfd->panel_info.lcdc.h_back_porch;
+	fbi->var.right_margin = mfd->panel_info.lcdc.h_front_porch;
+	fbi->var.upper_margin = mfd->panel_info.lcdc.v_back_porch;
+	fbi->var.lower_margin = mfd->panel_info.lcdc.v_front_porch;
+	fbi->var.hsync_len = mfd->panel_info.lcdc.h_pulse_width;
+	fbi->var.vsync_len = mfd->panel_info.lcdc.v_pulse_width;
+
+	/*
+	 * set driver data
+	 */
+	platform_set_drvdata(mdp_dev, mfd);
+	/*
+	 * register in mdp driver
+	 */
+	rc = platform_device_add(mdp_dev);
+	if (rc)
+		goto lvds_probe_err;
+
+	pdev_list[pdev_list_cnt++] = pdev;
+
+	return 0;
+
+lvds_probe_err:
+	platform_device_put(mdp_dev);
+	return rc;
+}
+
+static int lvds_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static int lvds_register_driver(void)
+{
+	return platform_driver_register(&lvds_driver);
+}
+
+static int __init lvds_driver_init(void)
+{
+	lvds_clk = clk_get(NULL, "lvds_clk");
+	if (IS_ERR(lvds_clk)) {
+		pr_err("Couldnt find lvds_clk\n");
+		return -EINVAL;
+	}
+
+	return lvds_register_driver();
+}
+
+module_init(lvds_driver_init);
diff --git a/drivers/video/msm/lvds_chimei_wxga.c b/drivers/video/msm/lvds_chimei_wxga.c
new file mode 100644
index 0000000..2c6b6d4
--- /dev/null
+++ b/drivers/video/msm/lvds_chimei_wxga.c
@@ -0,0 +1,124 @@
+/* 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 "msm_fb.h"
+
+static struct msm_panel_common_pdata *cm_pdata;
+static struct platform_device *cm_fbpdev;
+
+static int lvds_chimei_panel_on(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static int lvds_chimei_panel_off(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static void lvds_chimei_set_backlight(struct msm_fb_data_type *mfd)
+{
+}
+
+static int __devinit lvds_chimei_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+
+	if (pdev->id == 0) {
+		cm_pdata = pdev->dev.platform_data;
+		if (cm_pdata == NULL)
+			pr_err("%s: no PWM gpio specified\n", __func__);
+		return 0;
+	}
+
+	cm_fbpdev = msm_fb_add_device(pdev);
+	if (!cm_fbpdev) {
+		dev_err(&pdev->dev, "failed to add msm_fb device\n");
+		rc = -ENODEV;
+		goto probe_exit;
+	}
+
+probe_exit:
+	return rc;
+}
+
+static struct platform_driver this_driver = {
+	.probe  = lvds_chimei_probe,
+	.driver = {
+		.name   = "lvds_chimei_wxga",
+	},
+};
+
+static struct msm_fb_panel_data lvds_chimei_panel_data = {
+	.on = lvds_chimei_panel_on,
+	.off = lvds_chimei_panel_off,
+	.set_backlight = lvds_chimei_set_backlight,
+};
+
+static struct platform_device this_device = {
+	.name   = "lvds_chimei_wxga",
+	.id	= 1,
+	.dev	= {
+		.platform_data = &lvds_chimei_panel_data,
+	}
+};
+
+static int __init lvds_chimei_wxga_init(void)
+{
+	int ret;
+	struct msm_panel_info *pinfo;
+
+	if (msm_fb_detect_client("lvds_chimei_wxga"))
+		return 0;
+
+	ret = platform_driver_register(&this_driver);
+	if (ret)
+		return ret;
+
+	pinfo = &lvds_chimei_panel_data.panel_info;
+	pinfo->xres = 320;
+	pinfo->yres = 240;
+	MSM_FB_SINGLE_MODE_PANEL(pinfo);
+	pinfo->type = LVDS_PANEL;
+	pinfo->pdest = DISPLAY_1;
+	pinfo->wait_cycle = 0;
+	pinfo->bpp = 24;
+	pinfo->fb_num = 2;
+	pinfo->clk_rate = 75000000;
+	pinfo->bl_max = 15;
+	pinfo->bl_min = 1;
+
+	/*
+	 * this panel is operated by de,
+	 * vsycn and hsync are ignored
+	 */
+	pinfo->lcdc.h_back_porch = 0;
+	pinfo->lcdc.h_front_porch = 194;
+	pinfo->lcdc.h_pulse_width = 40;
+	pinfo->lcdc.v_back_porch = 0;
+	pinfo->lcdc.v_front_porch = 38;
+	pinfo->lcdc.v_pulse_width = 20;
+	pinfo->lcdc.border_clr = 0xffff00;
+	pinfo->lcdc.underflow_clr = 0xff;
+	pinfo->lcdc.hsync_skew = 0;
+	pinfo->lvds.channel_mode = LVDS_SINGLE_CHANNEL_MODE;
+	pinfo->lcdc.xres_pad = 1046;
+	pinfo->lcdc.yres_pad = 528;
+
+	ret = platform_device_register(&this_device);
+	if (ret)
+		platform_driver_unregister(&this_driver);
+
+	return ret;
+}
+
+module_init(lvds_chimei_wxga_init);
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index b39e81c..f27bd49 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -1562,6 +1562,7 @@
 #endif
 	case HDMI_PANEL:
 	case LCDC_PANEL:
+	case LVDS_PANEL:
 		pdata->on = mdp_lcdc_on;
 		pdata->off = mdp_lcdc_off;
 		mfd->hw_refresh = TRUE;
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 88582e4..5f5d632 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -188,9 +188,9 @@
 	dsi_underflow_clr = mfd->panel_info.lcdc.underflow_clr;
 	dsi_hsync_skew = mfd->panel_info.lcdc.hsync_skew;
 	dsi_width = mfd->panel_info.xres +
-		mfd->panel_info.mipi.xres_pad;
+		mfd->panel_info.lcdc.xres_pad;
 	dsi_height = mfd->panel_info.yres +
-		mfd->panel_info.mipi.yres_pad;
+		mfd->panel_info.lcdc.yres_pad;
 	dsi_bpp = mfd->panel_info.bpp;
 
 	hsync_period = hsync_pulse_width + h_back_porch + dsi_width
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index 5ad6de3f..ebde23b 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -45,6 +45,73 @@
 static struct mdp4_overlay_pipe *lcdc_pipe;
 static struct completion lcdc_comp;
 
+static void lvds_init(struct msm_fb_data_type *mfd)
+{
+	unsigned int lvds_intf, lvds_phy_cfg0;
+
+	if (mfd->panel_info.bpp == 24) {
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_3_TO_0 */
+		MDP_OUTP(MDP_BASE +  0xc2014, 0x03040508);
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_6_TO_4 */
+		MDP_OUTP(MDP_BASE +  0xc2018, 0x00000102);
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_3_TO_0 */
+		MDP_OUTP(MDP_BASE +  0xc201c, 0x0c0d1011);
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_6_TO_4 */
+		MDP_OUTP(MDP_BASE +  0xc2020, 0x00090a0b);
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_3_TO_0 */
+		MDP_OUTP(MDP_BASE +  0xc2024, 0x1518191a);
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */
+		MDP_OUTP(MDP_BASE +  0xc2028, 0x00121314);
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_3_TO_0 */
+		MDP_OUTP(MDP_BASE +  0xc202c, 0x0f16171b);
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_6_TO_4 */
+		MDP_OUTP(MDP_BASE +  0xc2030, 0x0006070e);
+
+		if (mfd->panel_info.lvds.channel_mode ==
+			LVDS_DUAL_CHANNEL_MODE) {
+			lvds_intf = 0x0001ff80;
+			lvds_phy_cfg0 = BIT(6) | BIT(7);
+			if (mfd->panel_info.lvds.channel_swap)
+				lvds_intf |= BIT(4);
+		} else {
+			lvds_intf = 0x00010f84;
+			lvds_phy_cfg0 = BIT(6);
+		}
+	} else if (mfd->panel_info.bpp == 18) {
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_3_TO_0 */
+		MDP_OUTP(MDP_BASE +  0xc2014, 0x03040508);
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_6_TO_4 */
+		MDP_OUTP(MDP_BASE +  0xc2018, 0x00000102);
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_3_TO_0 */
+		MDP_OUTP(MDP_BASE +  0xc201c, 0x0c0d1011);
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_6_TO_4 */
+		MDP_OUTP(MDP_BASE +  0xc2020, 0x00090a0b);
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_3_TO_0 */
+		MDP_OUTP(MDP_BASE +  0xc2024, 0x1518191a);
+		/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */
+		MDP_OUTP(MDP_BASE +  0xc2028, 0x00121314);
+
+		if (mfd->panel_info.lvds.channel_mode ==
+			LVDS_DUAL_CHANNEL_MODE) {
+			lvds_intf = 0x00017788;
+			lvds_phy_cfg0 = BIT(6) | BIT(7);
+			if (mfd->panel_info.lvds.channel_swap)
+				lvds_intf |= BIT(4);
+		} else {
+			lvds_intf = 0x0001078c;
+			lvds_phy_cfg0 = BIT(6);
+		}
+	}
+
+	/* MDP_LVDSPHY_CFG0 */
+	MDP_OUTP(MDP_BASE +  0xc3100, lvds_phy_cfg0);
+	/* MDP_LCDC_LVDS_INTF_CTL */
+	MDP_OUTP(MDP_BASE +  0xc2000, lvds_intf);
+	lvds_phy_cfg0 |= BIT(4);
+	/* MDP_LVDSPHY_CFG0, enable serialization */
+	MDP_OUTP(MDP_BASE +  0xc3100, lvds_phy_cfg0);
+}
+
 int mdp_lcdc_on(struct platform_device *pdev)
 {
 	int lcdc_width;
@@ -165,8 +232,8 @@
 	lcdc_underflow_clr = mfd->panel_info.lcdc.underflow_clr;
 	lcdc_hsync_skew = mfd->panel_info.lcdc.hsync_skew;
 
-	lcdc_width = var->xres;
-	lcdc_height = var->yres;
+	lcdc_width = var->xres + mfd->panel_info.lcdc.xres_pad;
+	lcdc_height = var->yres + mfd->panel_info.lcdc.yres_pad;
 	lcdc_bpp = mfd->panel_info.bpp;
 
 	hsync_period =
@@ -237,6 +304,9 @@
 #endif
 	mdp_histogram_ctrl(TRUE);
 
+	if (mfd->panel.type == LVDS_PANEL)
+		lvds_init(mfd);
+
 	ret = panel_next_on(pdev);
 	if (ret == 0) {
 		/* enable LCDC block */
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index 40056f0..a4a5b06 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -2556,23 +2556,23 @@
 		return 0;
 
 	if (!buf->size) {
-		pr_err("%s:%d In valid size", __func__, __LINE__);
+		pr_err("%s:%d In valid size\n", __func__, __LINE__);
 		return -EINVAL;
 	}
 
 	if (!IS_ERR_OR_NULL(mfd->iclient)) {
-		pr_info("%s:%d ion based allocation", __func__, __LINE__);
+		pr_info("%s:%d ion based allocation\n", __func__, __LINE__);
 		buf->ihdl = ion_alloc(mfd->iclient, buf->size, 4,
 			(1 << mfd->mem_hid));
 		if (!IS_ERR_OR_NULL(buf->ihdl)) {
 			if (ion_phys(mfd->iclient, buf->ihdl,
 				&addr, &len)) {
-				pr_err("%s:%d: ion_phys map failed",
+				pr_err("%s:%d: ion_phys map failed\n",
 					__func__, __LINE__);
 				return -ENOMEM;
 			}
 		} else {
-			pr_err("%s:%d: ion_alloc failed", __func__,
+			pr_err("%s:%d: ion_alloc failed\n", __func__,
 				__LINE__);
 			return -ENOMEM;
 		}
@@ -2602,14 +2602,18 @@
 		buf = mfd->ov1_wb_buf;
 
 	if (!IS_ERR_OR_NULL(mfd->iclient)) {
-		if (!IS_ERR_OR_NULL(buf->ihdl))
+		if (!IS_ERR_OR_NULL(buf->ihdl)) {
 			ion_free(mfd->iclient, buf->ihdl);
-		buf->ihdl = NULL;
-		pr_info("%s:%d free writeback imem", __func__, __LINE__);
+			pr_info("%s:%d free writeback imem\n", __func__,
+				__LINE__);
+			buf->ihdl = NULL;
+		}
 	} else {
-		if (buf->phys_addr)
+		if (buf->phys_addr) {
 			free_contiguous_memory_by_paddr(buf->phys_addr);
-		pr_info("%s:%d free writeback pmem", __func__, __LINE__);
+			pr_info("%s:%d free writeback pmem\n", __func__,
+				__LINE__);
+		}
 	}
 	buf->phys_addr = 0;
 }
diff --git a/drivers/video/msm/mdp4_wfd_writeback_panel.c b/drivers/video/msm/mdp4_wfd_writeback_panel.c
index 32b0669..40ffb65 100644
--- a/drivers/video/msm/mdp4_wfd_writeback_panel.c
+++ b/drivers/video/msm/mdp4_wfd_writeback_panel.c
@@ -37,8 +37,8 @@
 static struct msm_fb_panel_data writeback_msm_panel_data = {
 	.panel_info = {
 		.type = WRITEBACK_PANEL,
-		.xres = 800,
-		.yres = 480,
+		.xres = 1280,
+		.yres = 720,
 		.pdest = DISPLAY_3,
 		.wait_cycle = 0,
 		.bpp = 24,
diff --git a/drivers/video/msm/mipi_dsi.c b/drivers/video/msm/mipi_dsi.c
index aa210f1..f319072 100644
--- a/drivers/video/msm/mipi_dsi.c
+++ b/drivers/video/msm/mipi_dsi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -196,8 +196,8 @@
 
 	mipi  = &mfd->panel_info.mipi;
 	if (mfd->panel_info.type == MIPI_VIDEO_PANEL) {
-		dummy_xres = mfd->panel_info.mipi.xres_pad;
-		dummy_yres = mfd->panel_info.mipi.yres_pad;
+		dummy_xres = mfd->panel_info.lcdc.xres_pad;
+		dummy_yres = mfd->panel_info.lcdc.yres_pad;
 
 		if (mdp_rev >= MDP_REV_41) {
 			MIPI_OUTP(MIPI_DSI_BASE + 0x20,
@@ -539,8 +539,8 @@
 
 	if (mfd->panel_info.type == MIPI_VIDEO_PANEL &&
 		!mfd->panel_info.clk_rate) {
-		h_period += mfd->panel_info.mipi.xres_pad;
-		v_period += mfd->panel_info.mipi.yres_pad;
+		h_period += mfd->panel_info.lcdc.xres_pad;
+		v_period += mfd->panel_info.lcdc.yres_pad;
 
 		if (lanes > 0) {
 			mfd->panel_info.clk_rate =
diff --git a/drivers/video/msm/mipi_toshiba_video_wsvga_pt.c b/drivers/video/msm/mipi_toshiba_video_wsvga_pt.c
index 2c02490..48bdb1d 100644
--- a/drivers/video/msm/mipi_toshiba_video_wsvga_pt.c
+++ b/drivers/video/msm/mipi_toshiba_video_wsvga_pt.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
@@ -49,8 +49,8 @@
 	 * include dummy(pad) data of 200 clk in addition to
 	 * width and porch/sync width values
 	 */
-	pinfo.mipi.xres_pad = 200;
-	pinfo.mipi.yres_pad = 0;
+	pinfo.lcdc.xres_pad = 200;
+	pinfo.lcdc.yres_pad = 0;
 
 	pinfo.type = MIPI_VIDEO_PANEL;
 	pinfo.pdest = DISPLAY_1;
diff --git a/drivers/video/msm/msm_dss_io_8960.c b/drivers/video/msm/msm_dss_io_8960.c
index 52a10ab..3b000ec 100644
--- a/drivers/video/msm/msm_dss_io_8960.c
+++ b/drivers/video/msm/msm_dss_io_8960.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -643,9 +643,6 @@
 
 	HDMI_OUTP(HDMI_PHY_REG_0, 0x1B);
 	HDMI_OUTP(HDMI_PHY_REG_1, 0xf2);
-	HDMI_OUTP(HDMI_PHY_REG_2, 0x7F);
-	HDMI_OUTP(HDMI_PHY_REG_2, 0x3F);
-	HDMI_OUTP(HDMI_PHY_REG_2, 0x1F);
 
 	offset = HDMI_PHY_REG_4;
 	while (offset <= HDMI_PHY_REG_11) {
@@ -653,12 +650,7 @@
 		offset += 0x4;
 	}
 
-	HDMI_OUTP(HDMI_PHY_REG_12, HDMI_INP(HDMI_PHY_REG_12) | PWRDN_B);
-	msleep(100);
-
 	HDMI_OUTP(HDMI_PHY_REG_3, 0x20);
-	HDMI_OUTP(HDMI_PHY_REG_12, 0x81);
-	HDMI_OUTP(HDMI_PHY_REG_2, 0x81);
 }
 
 void hdmi_msm_powerdown_phy(void)
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 89ccbb9..bdfadd5 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -270,6 +270,9 @@
 	case HDMI_PANEL:
 		ret = snprintf(buf, PAGE_SIZE, "hdmi panel\n");
 		break;
+	case LVDS_PANEL:
+		ret = snprintf(buf, PAGE_SIZE, "lvds panel\n");
+		break;
 	case DTV_PANEL:
 		ret = snprintf(buf, PAGE_SIZE, "dtv panel\n");
 		break;
@@ -603,10 +606,42 @@
 	return 0;
 }
 
+static int msm_fb_ext_suspend(struct device *dev)
+{
+	struct msm_fb_data_type *mfd = dev_get_drvdata(dev);
+	int ret = 0;
+
+	if ((!mfd) || (mfd->key != MFD_KEY))
+		return 0;
+
+	if (mfd->panel_info.type == HDMI_PANEL ||
+		mfd->panel_info.type == DTV_PANEL)
+		ret = msm_fb_suspend_sub(mfd);
+
+	return ret;
+}
+
+static int msm_fb_ext_resume(struct device *dev)
+{
+	struct msm_fb_data_type *mfd = dev_get_drvdata(dev);
+	int ret = 0;
+
+	if ((!mfd) || (mfd->key != MFD_KEY))
+		return 0;
+
+	if (mfd->panel_info.type == HDMI_PANEL ||
+		mfd->panel_info.type == DTV_PANEL)
+		ret = msm_fb_resume_sub(mfd);
+
+	return ret;
+}
+
 static struct dev_pm_ops msm_fb_dev_pm_ops = {
 	.runtime_suspend = msm_fb_runtime_suspend,
 	.runtime_resume = msm_fb_runtime_resume,
 	.runtime_idle = msm_fb_runtime_idle,
+	.suspend = msm_fb_ext_suspend,
+	.resume = msm_fb_ext_resume,
 };
 
 static struct platform_driver msm_fb_driver = {
diff --git a/drivers/video/msm/msm_fb_panel.c b/drivers/video/msm/msm_fb_panel.c
index d8eaea2..8640116 100644
--- a/drivers/video/msm/msm_fb_panel.c
+++ b/drivers/video/msm/msm_fb_panel.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -106,6 +106,10 @@
 		snprintf(dev_name, sizeof(dev_name), "lcdc");
 		break;
 
+	case LVDS_PANEL:
+		snprintf(dev_name, sizeof(dev_name), "lvds");
+		break;
+
 	case DTV_PANEL:
 		snprintf(dev_name, sizeof(dev_name), "dtv");
 		break;
diff --git a/drivers/video/msm/msm_fb_panel.h b/drivers/video/msm/msm_fb_panel.h
index d66d802..903c865 100644
--- a/drivers/video/msm/msm_fb_panel.h
+++ b/drivers/video/msm/msm_fb_panel.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -38,6 +38,7 @@
 #define MIPI_VIDEO_PANEL	8	/* MIPI */
 #define MIPI_CMD_PANEL		9	/* MIPI */
 #define WRITEBACK_PANEL		10	/* Wifi display */
+#define LVDS_PANEL		11	/* LVDS */
 
 /* panel class */
 typedef enum {
@@ -77,6 +78,10 @@
 	__u32 border_clr;
 	__u32 underflow_clr;
 	__u32 hsync_skew;
+	/* Pad width */
+	uint32 xres_pad;
+	/* Pad height */
+	uint32 yres_pad;
 };
 
 struct mddi_panel_info {
@@ -127,10 +132,17 @@
 	char no_max_pkt_size;
 	/* Clock required during LP commands */
 	char force_clk_lane_hs;
-	/* Pad width */
-	uint32 xres_pad;
-	/* Pad height */
-	uint32 yres_pad;
+};
+
+enum lvds_mode {
+	LVDS_SINGLE_CHANNEL_MODE,
+	LVDS_DUAL_CHANNEL_MODE,
+};
+
+struct lvds_panel_info {
+	enum lvds_mode channel_mode;
+	/* Channel swap in dual mode */
+	char channel_swap;
 };
 
 struct msm_panel_info {
@@ -156,8 +168,8 @@
 	struct mddi_panel_info mddi;
 	struct lcd_panel_info lcd;
 	struct lcdc_panel_info lcdc;
-
 	struct mipi_panel_info mipi;
+	struct lvds_panel_info lvds;
 };
 
 #define MSM_FB_SINGLE_MODE_PANEL(pinfo)		\
diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c
index 980ec21..8a2f534 100644
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -804,6 +804,7 @@
 	u32 len = 0, flags = 0;
 	struct file *file;
 	int rc = 0;
+	unsigned long ionflag;
 
 	if (!client_ctx || !mv_data)
 		return false;
@@ -838,10 +839,18 @@
 			ERR("%s(): get_ION_handle failed\n", __func__);
 			goto ion_error;
 		}
+		rc = ion_handle_get_flags(client_ctx->user_ion_client,
+					client_ctx->h264_mv_ion_handle,
+					&ionflag);
+		if (rc) {
+			ERR("%s():get_ION_flags fail\n",
+					 __func__);
+			goto ion_error;
+		}
 		vcd_h264_mv_buffer->kernel_virtual_addr = (u8 *) ion_map_kernel(
 			client_ctx->user_ion_client,
 			client_ctx->h264_mv_ion_handle,
-			0);
+			ionflag);
 		if (!vcd_h264_mv_buffer->kernel_virtual_addr) {
 			ERR("%s(): get_ION_kernel virtual addr failed\n",
 				 __func__);
@@ -1651,6 +1660,7 @@
 	{
 		struct vdec_seqheader seq_header;
 		struct vcd_sequence_hdr vcd_seq_hdr;
+		unsigned long ionflag;
 		DBG("VDEC_IOCTL_SET_SEQUENCE_HEADER\n");
 		if (copy_from_user(&vdec_msg, arg, sizeof(vdec_msg))) {
 			ERR("Copy from user vdec_msg failed\n");
@@ -1681,9 +1691,19 @@
 				ERR("%s(): get_ION_handle failed\n", __func__);
 				return false;
 			}
+			rc = ion_handle_get_flags(client_ctx->user_ion_client,
+						client_ctx->seq_hdr_ion_handle,
+						&ionflag);
+			if (rc) {
+				ERR("%s():get_ION_flags fail\n",
+							 __func__);
+				ion_free(client_ctx->user_ion_client,
+					client_ctx->seq_hdr_ion_handle);
+				return false;
+			}
 			ker_vaddr = (unsigned long) ion_map_kernel(
 				client_ctx->user_ion_client,
-				client_ctx->seq_hdr_ion_handle, 0);
+				client_ctx->seq_hdr_ion_handle, ionflag);
 			if (!ker_vaddr) {
 				ERR("%s():get_ION_kernel virtual addr fail\n",
 							 __func__);
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.c b/drivers/video/msm/vidc/common/enc/venc_internal.c
index 1dbd170..47b0f66 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.c
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.c
@@ -1710,6 +1710,7 @@
 	size_t ion_len = -1;
 	unsigned long phy_addr;
 	int rc = -1;
+	unsigned long ionflag;
 	if (!client_ctx || !venc_recon) {
 		pr_err("%s() Invalid params", __func__);
 		return false;
@@ -1749,10 +1750,18 @@
 			ERR("%s(): get_ION_handle failed\n", __func__);
 			goto ion_error;
 		}
+		rc = ion_handle_get_flags(client_ctx->user_ion_client,
+					client_ctx->recon_buffer_ion_handle[i],
+					&ionflag);
+		if (rc) {
+			ERR("%s():get_ION_flags fail\n",
+				 __func__);
+			goto ion_error;
+		}
 		control->kernel_virtual_addr = (u8 *) ion_map_kernel(
 			client_ctx->user_ion_client,
 			client_ctx->recon_buffer_ion_handle[i],
-			0);
+			ionflag);
 		if (!control->kernel_virtual_addr) {
 			ERR("%s(): get_ION_kernel virtual addr fail\n",
 				 __func__);
diff --git a/drivers/video/msm/vidc/common/init/vidc_init.c b/drivers/video/msm/vidc/common/init/vidc_init.c
index 1709cc2..f65f835 100644
--- a/drivers/video/msm/vidc/common/init/vidc_init.c
+++ b/drivers/video/msm/vidc/common/init/vidc_init.c
@@ -459,6 +459,7 @@
 	struct msm_mapped_buffer *mapped_buffer = NULL;
 	size_t ion_len;
 	struct ion_handle *buff_ion_handle = NULL;
+	unsigned long ionflag;
 
 	if (!client_ctx || !length)
 		return false;
@@ -507,11 +508,18 @@
 				 __func__);
 				goto ion_error;
 			}
+			if (ion_handle_get_flags(client_ctx->user_ion_client,
+						buff_ion_handle,
+						&ionflag)) {
+				ERR("%s():ION flags fail\n",
+				 __func__);
+				goto ion_error;
+			}
 			*kernel_vaddr = (unsigned long)
 				ion_map_kernel(
 				client_ctx->user_ion_client,
 				buff_ion_handle,
-				0);
+				ionflag);
 			if (!(*kernel_vaddr)) {
 				ERR("%s():ION virtual addr fail\n",
 				 __func__);
diff --git a/include/linux/i2c/tsc2007.h b/include/linux/i2c/tsc2007.h
index 195e904..f439ebd 100644
--- a/include/linux/i2c/tsc2007.h
+++ b/include/linux/i2c/tsc2007.h
@@ -13,6 +13,10 @@
 	int	fuzzx; /* fuzz factor for X, Y and pressure axes */
 	int	fuzzy;
 	int	fuzzz;
+	u16	min_x;
+	u16	min_y;
+	u16	max_x;
+	u16	max_y;
 	unsigned long irq_flags;
 	bool	invert_x;
 	bool	invert_y;
diff --git a/include/linux/mfd/pm8xxx/core.h b/include/linux/mfd/pm8xxx/core.h
index 5ed615b..e7bf820 100644
--- a/include/linux/mfd/pm8xxx/core.h
+++ b/include/linux/mfd/pm8xxx/core.h
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -28,6 +28,7 @@
 	PM8XXX_VERSION_8018,
 	PM8XXX_VERSION_8922,
 	PM8XXX_VERSION_8038,
+	PM8XXX_VERSION_8917,
 };
 
 /* PMIC version specific silicon revisions */
@@ -68,6 +69,9 @@
 #define PM8XXX_REVISION_8038_2p0	2
 #define PM8XXX_REVISION_8038_2p1	3
 
+#define PM8XXX_REVISION_8917_TEST	0
+#define PM8XXX_REVISION_8917_1p0	1
+
 struct pm8xxx_drvdata {
 	int			(*pmic_readb) (const struct device *dev,
 						u16 addr, u8 *val);
diff --git a/include/linux/mfd/pm8xxx/pm8921.h b/include/linux/mfd/pm8xxx/pm8921.h
index 35792d5..ee1216d 100644
--- a/include/linux/mfd/pm8xxx/pm8921.h
+++ b/include/linux/mfd/pm8xxx/pm8921.h
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -40,8 +40,10 @@
 #define PM8921_NR_IRQS		256
 
 #define PM8921_NR_GPIOS		44
+#define PM8917_NR_GPIOS		38
 
 #define PM8921_NR_MPPS		12
+#define PM8917_NR_MPPS		10
 
 #define PM8921_GPIO_BLOCK_START	24
 #define PM8921_MPP_BLOCK_START	16
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index a984943..d905b22 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -401,6 +401,7 @@
 #define CMD_CONFIG_FREE_BUF_ADDR 48
 #define CMD_AXI_CFG_ZSL_ALL_CHNLS 49
 #define CMD_AXI_CFG_VIDEO_ALL_CHNLS 50
+#define CMD_VFE_BUFFER_RELEASE 51
 
 /* vfe config command: config command(from config thread)*/
 struct msm_vfe_cfg_cmd {
diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h
index 4694b78..dae4a12 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -41,6 +41,7 @@
 #define MSG_ID_BUS_OVERFLOW             36
 #define MSG_ID_SOF_ACK                  37
 #define MSG_ID_STOP_REC_ACK             38
+#define MSG_ID_STATS_AWB_AEC            39
 
 /* ISP command IDs */
 #define VFE_CMD_DUMMY_0                                 0
@@ -172,6 +173,13 @@
 #define VFE_CMD_GET_RGB_G_TABLE                         126
 #define VFE_CMD_GET_LA_TABLE                            127
 #define VFE_CMD_DEMOSAICV3_UPDATE                       128
+#define VFE_CMD_ACTIVE_REGION_CFG                       129
+#define VFE_CMD_COLOR_PROCESSING_CONFIG                 130
+#define VFE_CMD_STATS_WB_AEC_CONFIG                     131
+#define VFE_CMD_STATS_WB_AEC_UPDATE                     132
+#define VFE_CMD_Y_GAMMA_CONFIG                          133
+#define VFE_CMD_SCALE_OUTPUT1_CONFIG                    134
+#define VFE_CMD_SCALE_OUTPUT2_CONFIG                    135
 
 struct msm_isp_cmd {
 	int32_t  id;
@@ -179,7 +187,6 @@
 	void     *value;
 };
 
-
 #define VPE_CMD_DUMMY_0                                 0
 #define VPE_CMD_INIT                                    1
 #define VPE_CMD_DEINIT                                  2
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index d8d9c64..177e1d8 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -615,7 +615,7 @@
 	if (afe_validate_port(port_id) < 0)
 		return -EINVAL;
 
-	pr_info("%s port_id=%d index %d\n", __func__, port_id, index);
+	pr_debug("%s port_id=%d index %d\n", __func__, port_id, index);
 
 	if (!(atomic_read(&this_adm.copp_cnt[index]))) {
 		pr_err("%s: copp count for port[%d]is 0\n", __func__, port_id);
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
index a214529..302ef57 100644
--- a/sound/soc/msm/qdsp6/q6afe.c
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -386,7 +386,7 @@
 		ret = -EINVAL;
 		return ret;
 	}
-	pr_info("%s: %d %d\n", __func__, port_id, rate);
+	pr_debug("%s: %d %d\n", __func__, port_id, rate);
 
 	if ((port_id == RT_PROXY_DAI_001_RX) ||
 		(port_id == RT_PROXY_DAI_002_TX))
@@ -1428,7 +1428,7 @@
 		ret = -EINVAL;
 		goto fail_cmd;
 	}
-	pr_info("%s: port_id=%d\n", __func__, port_id);
+	pr_debug("%s: port_id=%d\n", __func__, port_id);
 	port_id = afe_convert_virtual_to_portid(port_id);
 
 	stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -1466,7 +1466,7 @@
 		ret = -EINVAL;
 		goto fail_cmd;
 	}
-	pr_info("%s: port_id=%d\n", __func__, port_id);
+	pr_debug("%s: port_id=%d\n", __func__, port_id);
 	port_id = afe_convert_virtual_to_portid(port_id);
 
 	stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,