Merge "V4L2: msm: Add events for video codecs." into msm-3.4
diff --git a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
index a33d833..d8784db 100644
--- a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
+++ b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
@@ -40,6 +40,7 @@
 - qcom,saw2-spm-cmd-ret: The Retention command sequence
 - qcom,saw2-spm-cmd-spc: The Standalone PC command sequence
 - qcom,saw2-spm-cmd-pc: The Power Collapse command sequence
+- qcom,saw2-spm-cmd-gdhs: L2 GDHS command sequence
 
 Example:
 	qcom,spm@f9089000 {
@@ -56,11 +57,11 @@
 		qcom,saw2-avs-dly= <0>;
 		qcom,saw2-spm-dly= <0x20000400>;
 		qcom,saw2-spm-ctl = <0x1>;
-		qcom,spm-cmd-wfi = [03 0b 0f];
-		qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
 				a0 b0 03 68 70 3b 92 a0 b0
 				82 2b 50 10 30 02 22 30 0f];
-		qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+		qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
 				a0 b0 82 10 30 02 22 30 0f];
 	};
 
diff --git a/arch/arm/boot/dts/msm9625.dts b/arch/arm/boot/dts/msm9625.dts
index b7b8be2..6c007fb 100644
--- a/arch/arm/boot/dts/msm9625.dts
+++ b/arch/arm/boot/dts/msm9625.dts
@@ -41,6 +41,15 @@
 		clock-frequency = <5000000>;
 	};
 
+	qcom,sps@f9980000 {
+		compatible = "qcom,msm_sps";
+		reg = <0xf9984000 0x15000>,
+		      <0xf9999000 0xb000>,
+		      <0xfe800000 0x4800>;
+		interrupts = <0 94 0>;
+		qcom,device-type = <2>;
+	};
+
 	serial@f991f000 {
 		compatible = "qcom,msm-lsuart-v14";
 		reg = <0xf991f000 0x1000>;
diff --git a/arch/arm/boot/dts/msmcopper-regulator.dtsi b/arch/arm/boot/dts/msmcopper-regulator.dtsi
index 0d0c587..a926aa3 100644
--- a/arch/arm/boot/dts/msmcopper-regulator.dtsi
+++ b/arch/arm/boot/dts/msmcopper-regulator.dtsi
@@ -155,7 +155,7 @@
 			};
 
 			pm8941_l13: regulator@4c00 {
-				regulator-min-microvolt = <2950000>;
+				regulator-min-microvolt = <1800000>;
 				regulator-max-microvolt = <2950000>;
 				qcom,enable-time = <200>;
 				qcom,pull-down-enable = <1>;
diff --git a/arch/arm/boot/dts/msmcopper_pm.dtsi b/arch/arm/boot/dts/msmcopper_pm.dtsi
index 0da3200..79cb95c 100644
--- a/arch/arm/boot/dts/msmcopper_pm.dtsi
+++ b/arch/arm/boot/dts/msmcopper_pm.dtsi
@@ -27,11 +27,11 @@
 		qcom,saw2-avs-dly= <0>;
 		qcom,saw2-spm-dly= <0x20000400>;
 		qcom,saw2-spm-ctl = <0x1>;
-		qcom,spm-cmd-wfi = [03 0b 0f];
-		qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
 				a0 b0 03 68 70 3b 92 a0 b0
 				82 2b 50 10 30 02 22 30 0f];
-		qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+		qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
 				a0 b0 82 10 30 02 22 30 0f];
 	};
 
@@ -49,11 +49,11 @@
 		qcom,saw2-avs-dly= <0>;
 		qcom,saw2-spm-dly= <0x20000400>;
 		qcom,saw2-spm-ctl = <0x1>;
-		qcom,spm-cmd-wfi = [03 0b 0f];
-		qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
 				a0 b0 03 68 70 3b 92 a0 b0
 				82 2b 50 10 30 02 22 30 0f];
-		qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+		qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
 				a0 b0 82 10 30 02 22 30 0f];
 	};
 
@@ -71,11 +71,11 @@
 		qcom,saw2-avs-dly= <0>;
 		qcom,saw2-spm-dly= <0x20000400>;
 		qcom,saw2-spm-ctl = <0x1>;
-		qcom,spm-cmd-wfi = [03 0b 0f];
-		qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
 				a0 b0 03 68 70 3b 92 a0 b0
 				82 2b 50 10 30 02 22 30 0f];
-		qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+		qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
 				a0 b0 82 10 30 02 22 30 0f];
 	};
 
@@ -93,11 +93,11 @@
 		qcom,saw2-avs-dly= <0>;
 		qcom,saw2-spm-dly= <0x20000400>;
 		qcom,saw2-spm-ctl = <0x1>;
-		qcom,spm-cmd-wfi = [03 0b 0f];
-		qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+		qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+		qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
 				a0 b0 03 68 70 3b 92 a0 b0
 				82 2b 50 10 30 02 22 30 0f];
-		qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+		qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
 				a0 b0 82 10 30 02 22 30 0f];
 	};
 
@@ -123,12 +123,12 @@
 		qcom,vctl-timeout-us = <50>;
 		qcom,vctl-port = <0x0>; /* TODO: */
 		qcom,phase-port = <0x1>; /* TODO: */
-		qcom,spm-cmd-ret = [0b 00 20 03 22 00 0f];
-		qcom,spm-cmd-spc = [00 20 32 60 70 80 42 03
-				78 80 44 22 50 3b 60 02 32
-				50 0f];
-		qcom,spm-cmd-pc = [00 10 32 60 70 80 b0 11 42
-				07 01 b0 78 80 12 44 a0 50
+		qcom,saw2-spm-cmd-ret = [0b 00 20 03 22 00 0f];
+		qcom,saw2-spm-cmd-gdhs =  [00 20 32 60 70 80 0b 42 07
+				      78 80 44 22 50 3b 60 02 32
+				      50 0f];
+		qcom,saw2-spm-cmd-pc = [00 10 32 60 70 80 b0 11 0b
+				42 07 01 b0 78 80 12 44 a0 50
 				3b 60 02 32 a0 50 0f];
 	};
 
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
index 49fae4a..f6764d4 100644
--- a/arch/arm/configs/msm-copper_defconfig
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -10,7 +10,6 @@
 CONFIG_CGROUP_CPUACCT=y
 CONFIG_RESOURCE_COUNTERS=y
 CONFIG_CGROUP_SCHED=y
-# CONFIG_FAIR_GROUP_SCHED is not set
 CONFIG_RT_GROUP_SCHED=y
 CONFIG_NAMESPACES=y
 # CONFIG_UTS_NS is not set
@@ -75,15 +74,26 @@
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_PM_RUNTIME=y
 CONFIG_NET=y
+CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
 CONFIG_IPV6=y
 CONFIG_IPV6_PRIVACY=y
 CONFIG_IPV6_ROUTER_PREF=y
 CONFIG_IPV6_ROUTE_INFO=y
 CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
 CONFIG_IPV6_MIP6=y
 CONFIG_IPV6_MULTIPLE_TABLES=y
 CONFIG_IPV6_SUBTREES=y
@@ -98,9 +108,13 @@
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_LOGGING=y
 CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
 CONFIG_NETDEVICES=y
 CONFIG_KS8851=m
 # CONFIG_MSM_RMNET is not set
+CONFIG_DUMMY=y
 CONFIG_INPUT_EVDEV=y
 CONFIG_INPUT_EVBUG=m
 CONFIG_INPUT_JOYSTICK=y
@@ -174,6 +188,7 @@
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_NLS_CODEPAGE_437=y
@@ -198,6 +213,7 @@
 CONFIG_CRYPTO_MD4=y
 CONFIG_CRYPTO_MD5=y
 CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=y
 CONFIG_CRYPTO_AES=y
 CONFIG_CRYPTO_ARC4=y
 CONFIG_CRYPTO_DES=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 1e45f66..bb3554b 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -85,6 +85,9 @@
 CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_DYNAMIC_DEBUG=y
 CONFIG_DEBUG_USER=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_BAMDMA=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
 CONFIG_KEYS=y
 CONFIG_CRYPTO_AUTHENC=y
 CONFIG_CRYPTO_CBC=y
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 3554b56..304520b 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -242,6 +242,9 @@
 	select SPARSE_IRQ
 	select MSM_RPM_SMD
 	select REGULATOR
+	select MSM_QDSP6_APR
+	select MSM_QDSP6V2_CODECS
+	select MSM_AUDIO_QDSP6V2 if SND_SOC
 
 config ARCH_FSM9XXX
 	bool "FSM9XXX"
@@ -2173,6 +2176,15 @@
 	  used by audio driver to configure QDSP6's
 	  ASM, ADM and AFE.
 
+config MSM_QDSP6V2_CODECS
+	bool "Audio QDSP6V2 APR support"
+	depends on MSM_SMD
+	help
+	  Enable Audio codecs with APR IPC protocol support between
+	  application processor and QDSP6 for B-family. APR is
+	  used by audio driver to configure QDSP6's
+	  ASM, ADM and AFE.
+
 config MSM_AUDIO_QDSP6
         bool "QDSP6 HW Audio support"
         select SND_SOC_MSM_QDSP6_INTF
@@ -2181,6 +2193,16 @@
           Enable HW audio support in QDSP6.
           QDSP6 can support HW encoder & decoder and audio processing
 
+config MSM_AUDIO_QDSP6V2
+        bool "QDSP6V2 HW Audio support"
+        select SND_SOC_MSM_QDSP6V2_INTF
+        help
+          Enable HW audio support in QDSP6V2.
+          QDSP6V2 can support HW encoder & decoder and
+          audio processing. It will enable support for
+          AAC, AMRNB, AMRWB, EVRC, MP3, QCELP among
+          others.
+
 config MSM_ULTRASOUND
 	bool "MSM ultrasound support"
 	depends on MSM_AUDIO_QDSP6
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 3043b78..6034fe9 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -155,6 +155,7 @@
 obj-$(CONFIG_MSM_QDSP6) += qdsp6/
 obj-$(CONFIG_MSM8X60_AUDIO) += qdsp6v2/
 obj-$(CONFIG_MSM_AUDIO_QDSP6) += qdsp6v2/
+obj-$(CONFIG_MSM_AUDIO_QDSP6V2) += qdsp6v2/
 obj-$(CONFIG_MSM_HW3D) += hw3d.o
 obj-$(CONFIG_PM) += pm-boot.o
 obj-$(CONFIG_MSM_PM8X60) += pm-8x60.o pm-data.o
@@ -331,6 +332,7 @@
 obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60-vcm.o
 endif
 obj-$(CONFIG_MSM_OCMEM) += ocmem.o ocmem_allocator.o ocmem_notifier.o
+obj-$(CONFIG_MSM_OCMEM) += ocmem_sched.o ocmem_api.o
 
 obj-$(CONFIG_ARCH_MSM7X27) += gpiomux-7x27.o gpiomux-v1.o gpiomux.o
 obj-$(CONFIG_ARCH_MSM7X30) += gpiomux-7x30.o gpiomux-v1.o gpiomux.o
diff --git a/arch/arm/mach-msm/acpuclock-9615.c b/arch/arm/mach-msm/acpuclock-9615.c
index 8882f41..24b81b9 100644
--- a/arch/arm/mach-msm/acpuclock-9615.c
+++ b/arch/arm/mach-msm/acpuclock-9615.c
@@ -39,7 +39,6 @@
 #define REG_CLKDIV_1	(MSM_APCS_GLB_BASE + 0x14)
 #define REG_CLKOUTSEL	(MSM_APCS_GLB_BASE + 0x18)
 
-#define MAX_VDD_CPU	1150000
 #define MAX_VDD_MEM	1150000
 
 enum clk_src {
@@ -111,12 +110,12 @@
 static uint32_t bus_perf_client;
 
 static struct clkctl_acpu_speed acpu_freq_tbl[] = {
-	{ 0,  19200, SRC_CXO,  0, 0,  950000, 1050000, 0 },
-	{ 1, 138000, SRC_PLL0, 6, 1,  950000, 1050000, 2 },
-	{ 1, 276000, SRC_PLL0, 6, 0, 1050000, 1050000, 2 },
-	{ 1, 384000, SRC_PLL8, 3, 0, 1150000, 1150000, 4 },
+	{ 0,  19200, SRC_CXO,  0, 0, RPM_VREG_CORNER_LOW,     1050000, 0 },
+	{ 1, 138000, SRC_PLL0, 6, 1, RPM_VREG_CORNER_LOW,     1050000, 2 },
+	{ 1, 276000, SRC_PLL0, 6, 0, RPM_VREG_CORNER_NOMINAL, 1050000, 2 },
+	{ 1, 384000, SRC_PLL8, 3, 0, RPM_VREG_CORNER_HIGH,    1150000, 4 },
 	/* The row below may be changed at runtime depending on hw rev. */
-	{ 1, 440000, SRC_PLL9, 2, 0, 1150000, 1150000, 4 },
+	{ 1, 440000, SRC_PLL9, 2, 0, RPM_VREG_CORNER_HIGH,    1150000, 4 },
 	{ 0 }
 };
 
@@ -171,8 +170,8 @@
 		return rc;
 	}
 
-	rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8018_S1, RPM_VREG_VOTER1,
-				  vdd_cpu, MAX_VDD_CPU, 0);
+	rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8018_VDD_DIG_CORNER,
+			RPM_VREG_VOTER1, vdd_cpu, RPM_VREG_CORNER_HIGH, 0);
 	if (rc)
 		pr_err("vdd_cpu increase failed (%d)\n", rc);
 
@@ -185,8 +184,9 @@
 	int ret;
 
 	/* Update CPU voltage. */
-	ret = rpm_vreg_set_voltage(RPM_VREG_ID_PM8018_S1, RPM_VREG_VOTER1,
-				  vdd_cpu, MAX_VDD_CPU, 0);
+	ret = rpm_vreg_set_voltage(RPM_VREG_ID_PM8018_VDD_DIG_CORNER,
+		RPM_VREG_VOTER1, vdd_cpu, RPM_VREG_CORNER_HIGH, 0);
+
 	if (ret) {
 		pr_err("vdd_cpu decrease failed (%d)\n", ret);
 		return;
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index 2d1f787..c37491d 100644
--- a/arch/arm/mach-msm/board-8064-camera.c
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -334,17 +334,11 @@
 static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
 	{
 		.csid_core = 0,
-		.is_csiphy = 1,
-		.is_csid   = 1,
-		.is_ispif  = 1,
 		.is_vpe    = 1,
 		.cam_bus_scale_table = &cam_bus_client_pdata,
 	},
 	{
 		.csid_core = 1,
-		.is_csiphy = 1,
-		.is_csid   = 1,
-		.is_ispif  = 1,
 		.is_vpe    = 1,
 		.cam_bus_scale_table = &cam_bus_client_pdata,
 	},
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index bef5cdc..fc886ed 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -364,6 +364,7 @@
 static struct pm8xxx_ccadc_platform_data
 apq8064_pm8xxx_ccadc_pdata = {
 	.r_sense		= 10,
+	.calib_delay_ms		= 600000,
 };
 
 static struct pm8921_bms_platform_data
@@ -372,7 +373,6 @@
 	.r_sense		= 10,
 	.i_test			= 2500,
 	.v_failure		= 3000,
-	.calib_delay_ms		= 600000,
 	.max_voltage_uv		= MAX_VOLTAGE_MV * 1000,
 };
 
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
index e7f0e68..6ee315c 100644
--- a/arch/arm/mach-msm/board-8930-camera.c
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -342,17 +342,11 @@
 static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
 	{
 		.csid_core = 0,
-		.is_csiphy = 1,
-		.is_csid   = 1,
-		.is_ispif  = 1,
 		.is_vpe    = 1,
 		.cam_bus_scale_table = &cam_bus_client_pdata,
 	},
 	{
 		.csid_core = 1,
-		.is_csiphy = 1,
-		.is_csid   = 1,
-		.is_ispif  = 1,
 		.is_vpe    = 1,
 		.cam_bus_scale_table = &cam_bus_client_pdata,
 	},
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index 188cf39..e6a13b1 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -328,6 +328,7 @@
 
 static struct pm8xxx_ccadc_platform_data pm8xxx_ccadc_pdata = {
 	.r_sense		= 10,
+	.calib_delay_ms		= 600000,
 };
 
 static struct pm8xxx_misc_platform_data pm8xxx_misc_pdata = {
@@ -343,7 +344,6 @@
 	.r_sense		= 10,
 	.i_test			= 2500,
 	.v_failure		= 3000,
-	.calib_delay_ms		= 600000,
 	.max_voltage_uv		= MAX_VOLTAGE_MV * 1000,
 };
 
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator.c
index cb8903c..5bee8a2 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator.c
@@ -485,7 +485,7 @@
 	RPM_LDO(L15,	 0, 1, 0, 1800000, 2950000, NULL,      0, 0),
 	RPM_LDO(L17,	 0, 1, 0, 1800000, 2950000, NULL,      0, 0),
 	RPM_LDO(L18,	 0, 1, 0, 1800000, 1800000, NULL,      0, 0),
-	RPM_LDO(L20,	 1, 1, 0, 1200000, 1200000, "8038_s2", 10000, 10000),
+	RPM_LDO(L20,	 1, 1, 0, 1250000, 1250000, "8038_s2", 10000, 10000),
 	RPM_LDO(L21,	 0, 1, 0, 1900000, 1900000, "8038_s4", 0, 0),
 	RPM_LDO(L22,	 1, 1, 0, 1850000, 2950000, NULL,      10000, 10000),
 	RPM_LDO(L23,	 1, 1, 1, 1800000, 1800000, "8038_s4", 0, 0),
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 338cb84..8df37f7 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -786,13 +786,13 @@
 	{
 		.name = "VDDD_CDC_D",
 		.min_uV = 1200000,
-		.max_uV = 1200000,
+		.max_uV = 1250000,
 		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
 	},
 	{
 		.name = "CDC_VDDA_A_1P2V",
 		.min_uV = 1200000,
-		.max_uV = 1200000,
+		.max_uV = 1250000,
 		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
 	},
 	},
@@ -850,13 +850,13 @@
 	{
 		.name = "VDDD_CDC_D",
 		.min_uV = 1200000,
-		.max_uV = 1200000,
+		.max_uV = 1250000,
 		.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
 	},
 	{
 		.name = "CDC_VDDA_A_1P2V",
 		.min_uV = 1200000,
-		.max_uV = 1200000,
+		.max_uV = 1250000,
 		.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
 	},
 	},
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index 9c25b78..b6c03a4 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -399,25 +399,16 @@
 static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
 	{
 		.csid_core = 0,
-		.is_csiphy = 1,
-		.is_csid   = 1,
-		.is_ispif  = 1,
 		.is_vpe    = 1,
 		.cam_bus_scale_table = &cam_bus_client_pdata,
 	},
 	{
 		.csid_core = 1,
-		.is_csiphy = 1,
-		.is_csid   = 1,
-		.is_ispif  = 1,
 		.is_vpe    = 1,
 		.cam_bus_scale_table = &cam_bus_client_pdata,
 	},
 	{
 		.csid_core = 2,
-		.is_csiphy = 1,
-		.is_csid   = 1,
-		.is_ispif  = 1,
 		.is_vpe    = 1,
 		.cam_bus_scale_table = &cam_bus_client_pdata,
 	},
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index 977dbb2..19564e9 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -442,9 +442,8 @@
 	.r_sense		= 10,
 	.i_test			= 2500,
 	.v_failure		= 3000,
-	.calib_delay_ms		= 600000,
 	.max_voltage_uv		= MAX_VOLTAGE_MV * 1000,
-	.rconn_mohm		= 30,
+	.rconn_mohm		= 18,
 };
 
 #define	PM8921_LC_LED_MAX_CURRENT	4	/* I = 4mA */
@@ -567,6 +566,7 @@
 
 static struct pm8xxx_ccadc_platform_data pm8xxx_ccadc_pdata = {
 	.r_sense		= 10,
+	.calib_delay_ms		= 600000,
 };
 
 /**
diff --git a/arch/arm/mach-msm/board-9615-regulator.c b/arch/arm/mach-msm/board-9615-regulator.c
index 1122ed9..2561def 100644
--- a/arch/arm/mach-msm/board-9615-regulator.c
+++ b/arch/arm/mach-msm/board-9615-regulator.c
@@ -69,9 +69,6 @@
 };
 VREG_CONSUMERS(S1) = {
 	REGULATOR_SUPPLY("8018_s1",		NULL),
-	REGULATOR_SUPPLY("HSUSB_VDDCX",		"msm_otg"),
-	REGULATOR_SUPPLY("HSIC_VDDCX",		"msm_hsic_peripheral"),
-	REGULATOR_SUPPLY("HSIC_VDDCX",		"msm_hsic_host"),
 };
 VREG_CONSUMERS(S2) = {
 	REGULATOR_SUPPLY("8018_s2",		NULL),
@@ -117,6 +114,11 @@
 	REGULATOR_SUPPLY("ext_2p95v",		NULL),
 	REGULATOR_SUPPLY("sdc_vdd",		"msm_sdcc.1"),
 };
+VREG_CONSUMERS(VDD_DIG_CORNER) = {
+	REGULATOR_SUPPLY("hsusb_vdd_dig",	"msm_otg"),
+	REGULATOR_SUPPLY("hsic_vdd_dig",	"msm_hsic_peripheral"),
+	REGULATOR_SUPPLY("hsic_vdd_dig",	"msm_hsic_host"),
+};
 
 #define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
 			 _apply_uV, _pull_down, _always_on, _supply_regulator, \
@@ -262,6 +264,16 @@
 		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
 		 _supply_regulator, 0)
 
+#define RPM_CORNER(_id, _always_on, _sleep_selectable, _min_uV, _max_uV, \
+		_supply_regulator) \
+	RPM_INIT(_id, _min_uV, _max_uV, 0, REGULATOR_CHANGE_VOLTAGE \
+		 | REGULATOR_CHANGE_STATUS, 0, _max_uV, 0, 0, 0, \
+		 RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_9615_NONE, \
+		 RPM_VREG_FORCE_MODE_9615_NONE, \
+		 RPM_VREG_FORCE_MODE_9615_NONE, RPM_VREG_POWER_MODE_9615_PWM, \
+		 RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
+		 _supply_regulator, 0)
+
 /* Pin control initialization */
 #define RPM_PC_INIT(_id, _always_on, _pin_fn, _pin_ctrl, _supply_regulator) \
 	{ \
@@ -331,6 +343,10 @@
 
 	/*	ID    a_on pd ss		    supply */
 	RPM_VS(LVS1,    0, 1, 0,		    "8018_s3"),
+
+	/*	   ID            a_on ss min_corner  max_corner  supply */
+	RPM_CORNER(VDD_DIG_CORNER, 0, 1, RPM_VREG_CORNER_NONE,
+		RPM_VREG_CORNER_HIGH, NULL),
 };
 
 int msm_pm8018_regulator_pdata_len __devinitdata =
@@ -342,5 +358,5 @@
 	.num_regulators		= ARRAY_SIZE(msm_rpm_regulator_init_data),
 	.version		= RPM_VREG_VERSION_9615,
 	.vreg_id_vdd_mem	= RPM_VREG_ID_PM8018_L9,
-	.vreg_id_vdd_dig	= RPM_VREG_ID_PM8018_S1,
+	.vreg_id_vdd_dig	= RPM_VREG_ID_PM8018_VDD_DIG_CORNER,
 };
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index 614cfe2..4dda0b7 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -46,6 +46,7 @@
 #include "clock.h"
 #include "devices.h"
 #include "spm.h"
+#include "modem_notifier.h"
 
 #define MSM_KERNEL_EBI1_MEM_SIZE	0x280000
 #ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
@@ -457,6 +458,7 @@
  */
 void __init msm_copper_add_drivers(void)
 {
+	msm_init_modem_notifier_list();
 	msm_smd_init();
 	msm_rpm_driver_init();
 	rpm_regulator_smd_driver_init();
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index 2873fc0..38bdeca 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -125,14 +125,12 @@
 struct msm_camera_device_platform_data msm_camera_device_data_csi1[] = {
 	{
 		.csid_core = 1,
-		.is_csic = 1,
 		.ioclk = {
 			.vfe_clk_rate = 192000000,
 		},
 	},
 	{
 		.csid_core = 1,
-		.is_csic = 1,
 		.ioclk = {
 			.vfe_clk_rate = 266667000,
 		},
@@ -142,14 +140,12 @@
 struct msm_camera_device_platform_data msm_camera_device_data_csi0[] = {
 	{
 		.csid_core = 0,
-		.is_csic = 1,
 		.ioclk = {
 			.vfe_clk_rate = 192000000,
 		},
 	},
 	{
 		.csid_core = 0,
-		.is_csic = 1,
 		.ioclk = {
 			.vfe_clk_rate = 266667000,
 		},
diff --git a/arch/arm/mach-msm/board-msm7627a-display.c b/arch/arm/mach-msm/board-msm7627a-display.c
index 8740186..3da68ad 100644
--- a/arch/arm/mach-msm/board-msm7627a-display.c
+++ b/arch/arm/mach-msm/board-msm7627a-display.c
@@ -577,90 +577,98 @@
 };
 #endif
 
-static int evb_backlight_control(int level)
+static int evb_backlight_control(int level, int mode)
 {
 
 	int i = 0;
-	int remainder;
+	int remainder, ret = 0;
+
 	/* device address byte = 0x72 */
-	gpio_set_value(96, 0);
-	udelay(67);
-	gpio_set_value(96, 1);
-	udelay(33);
-	gpio_set_value(96, 0);
-	udelay(33);
-	gpio_set_value(96, 1);
-	udelay(67);
-	gpio_set_value(96, 0);
-	udelay(33);
-	gpio_set_value(96, 1);
-	udelay(67);
-	gpio_set_value(96, 0);
-	udelay(33);
-	gpio_set_value(96, 1);
-	udelay(67);
-	gpio_set_value(96, 0);
-	udelay(67);
-	gpio_set_value(96, 1);
-	udelay(33);
-	gpio_set_value(96, 0);
-	udelay(67);
-	gpio_set_value(96, 1);
-	udelay(33);
-	gpio_set_value(96, 0);
-	udelay(33);
-	gpio_set_value(96, 1);
-	udelay(67);
-	gpio_set_value(96, 0);
-	udelay(67);
-	gpio_set_value(96, 1);
-	udelay(33);
+	if (!mode) {
+		gpio_set_value(96, 0);
+		udelay(67);
+		gpio_set_value(96, 1);
+		udelay(33);
+		gpio_set_value(96, 0);
+		udelay(33);
+		gpio_set_value(96, 1);
+		udelay(67);
+		gpio_set_value(96, 0);
+		udelay(33);
+		gpio_set_value(96, 1);
+		udelay(67);
+		gpio_set_value(96, 0);
+		udelay(33);
+		gpio_set_value(96, 1);
+		udelay(67);
+		gpio_set_value(96, 0);
+		udelay(67);
+		gpio_set_value(96, 1);
+		udelay(33);
+		gpio_set_value(96, 0);
+		udelay(67);
+		gpio_set_value(96, 1);
+		udelay(33);
+		gpio_set_value(96, 0);
+		udelay(33);
+		gpio_set_value(96, 1);
+		udelay(67);
+		gpio_set_value(96, 0);
+		udelay(67);
+		gpio_set_value(96, 1);
+		udelay(33);
 
-	/* t-EOS and t-start */
-	gpio_set_value(96, 0);
-	ndelay(4200);
-	gpio_set_value(96, 1);
-	ndelay(9000);
+		/* t-EOS and t-start */
+		gpio_set_value(96, 0);
+		ndelay(4200);
+		gpio_set_value(96, 1);
+		ndelay(9000);
 
-	/* data byte */
-	/* RFA = 0 */
-	gpio_set_value(96, 0);
-	udelay(67);
-	gpio_set_value(96, 1);
-	udelay(33);
+		/* data byte */
+		/* RFA = 0 */
+		gpio_set_value(96, 0);
+		udelay(67);
+		gpio_set_value(96, 1);
+		udelay(33);
 
-	/* Address bits */
-	gpio_set_value(96, 0);
-	udelay(67);
-	gpio_set_value(96, 1);
-	udelay(33);
-	gpio_set_value(96, 0);
-	udelay(67);
-	gpio_set_value(96, 1);
-	udelay(33);
+		/* Address bits */
+		gpio_set_value(96, 0);
+		udelay(67);
+		gpio_set_value(96, 1);
+		udelay(33);
+		gpio_set_value(96, 0);
+		udelay(67);
+		gpio_set_value(96, 1);
+		udelay(33);
 
-	/* Data bits */
-	for (i = 0; i < 5; i++) {
-		remainder = (level) & (16);
-		if (remainder) {
-			gpio_set_value(96, 0);
-			udelay(33);
-			gpio_set_value(96, 1);
-			udelay(67);
-		} else {
-			gpio_set_value(96, 0);
-			udelay(67);
-			gpio_set_value(96, 1);
-			udelay(33);
+		/* Data bits */
+		for (i = 0; i < 5; i++) {
+			remainder = (level) & (16);
+			if (remainder) {
+				gpio_set_value(96, 0);
+				udelay(33);
+				gpio_set_value(96, 1);
+				udelay(67);
+			} else {
+				gpio_set_value(96, 0);
+				udelay(67);
+				gpio_set_value(96, 1);
+				udelay(33);
+			}
+			level = level << 1;
 		}
-		level = level << 1;
+
+		/* t-EOS */
+		gpio_set_value(96, 0);
+		ndelay(12000);
+		gpio_set_value(96, 1);
+	} else {
+		ret = pmapp_disp_backlight_set_brightness(level);
+		 if (ret)
+			pr_err("%s: can't set lcd backlight!\n", __func__);
 	}
 
-	/* t-EOS */
-	gpio_set_value(96, 0);
-	ndelay(12000);
-	gpio_set_value(96, 1);
-	return 0;
+	return ret;
 }
 
 static int mipi_NT35510_rotate_panel(void)
@@ -685,7 +693,7 @@
 };
 
 static struct msm_panel_common_pdata mipi_NT35510_pdata = {
-	.pmic_backlight = evb_backlight_control,
+	.backlight    = evb_backlight_control,
 	.rotate_panel = mipi_NT35510_rotate_panel,
 };
 
@@ -698,7 +706,7 @@
 };
 
 static struct msm_panel_common_pdata mipi_NT35516_pdata = {
-	.pmic_backlight = evb_backlight_control,
+	.backlight = evb_backlight_control,
 };
 
 static struct platform_device mipi_dsi_NT35516_panel_device = {
@@ -1141,6 +1149,7 @@
 	static struct regulator *gpio_reg_2p85v, *gpio_reg_1p8v;
 
 	if (!qrd3_dsi_gpio_initialized) {
+		pmapp_disp_backlight_init();
 		rc = gpio_request(GPIO_QRD3_LCD_BACKLIGHT_EN,
 			"qrd3_gpio_bkl_en");
 		if (rc < 0)
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 7ac0c9a..010d9ec 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -880,7 +880,6 @@
 static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
 	{
 		.csid_core = 0,
-		.is_csic = 1,
 		.is_vpe    = 1,
 		.ioclk = {
 			.vfe_clk_rate =	153600000,
diff --git a/arch/arm/mach-msm/board-msm8x60-camera.c b/arch/arm/mach-msm/board-msm8x60-camera.c
index 32d5530..cd95630 100644
--- a/arch/arm/mach-msm/board-msm8x60-camera.c
+++ b/arch/arm/mach-msm/board-msm8x60-camera.c
@@ -361,7 +361,6 @@
 static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
 	{
 		.csid_core = 0,
-		.is_csic = 1,
 		.is_vpe    = 1,
 		.cam_bus_scale_table = &cam_bus_client_pdata,
 		.ioclk = {
@@ -370,7 +369,6 @@
 	},
 	{
 		.csid_core = 1,
-		.is_csic = 1,
 		.is_vpe    = 1,
 		.cam_bus_scale_table = &cam_bus_client_pdata,
 		.ioclk = {
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 102f6ac..54c8fbd 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -2604,7 +2604,7 @@
 #define MSM_FB_EXT_BUF_SIZE  \
 		(roundup((720 * 576 * 2), 4096) * 2) /* 2 bpp x 2 pages */
 #else
-#define MSM_FB_EXT_BUFT_SIZE	0
+#define MSM_FB_EXT_BUF_SIZE	0
 #endif
 
 /* Note: must be multiple of 4096 */
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index 834deb6..a2e0bc9 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -187,15 +187,15 @@
 
 static int set_vdd_dig(struct clk_vdd_class *vdd_class, int level)
 {
-	static const int vdd_uv[] = {
-		[VDD_DIG_NONE]    =       0,
-		[VDD_DIG_LOW]     =  945000,
-		[VDD_DIG_NOMINAL] = 1050000,
-		[VDD_DIG_HIGH]    = 1150000
+	static const int vdd_corner[] = {
+		[VDD_DIG_NONE]    = RPM_VREG_CORNER_NONE,
+		[VDD_DIG_LOW]     = RPM_VREG_CORNER_LOW,
+		[VDD_DIG_NOMINAL] = RPM_VREG_CORNER_NOMINAL,
+		[VDD_DIG_HIGH]    = RPM_VREG_CORNER_HIGH,
 	};
 
-	return rpm_vreg_set_voltage(RPM_VREG_ID_PM8018_S1, RPM_VREG_VOTER3,
-				    vdd_uv[level], vdd_uv[VDD_DIG_HIGH], 1);
+	return rpm_vreg_set_voltage(RPM_VREG_ID_PM8018_VDD_DIG_CORNER,
+		RPM_VREG_VOTER3, vdd_corner[level], RPM_VREG_CORNER_HIGH, 1);
 }
 
 static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig);
diff --git a/arch/arm/mach-msm/clock-copper.c b/arch/arm/mach-msm/clock-copper.c
index 6ddf1a0..99443a5 100644
--- a/arch/arm/mach-msm/clock-copper.c
+++ b/arch/arm/mach-msm/clock-copper.c
@@ -3998,7 +3998,6 @@
 
 static struct branch_clk audio_core_lpaif_codec_spkr_ebit_clk = {
 	.cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_EBIT_CBCR,
-	.parent = &audio_core_lpaif_codec_spkr_clk_src.c,
 	.has_sibling = 1,
 	.base = &virt_bases[LPASS_BASE],
 	.c = {
@@ -4012,7 +4011,7 @@
 	.cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_IBIT_CBCR,
 	.parent = &audio_core_lpaif_codec_spkr_clk_src.c,
 	.has_sibling = 1,
-	.max_div = 16,
+	.max_div = 15,
 	.base = &virt_bases[LPASS_BASE],
 	.c = {
 		.dbg_name = "audio_core_lpaif_codec_spkr_clk_src",
@@ -4035,7 +4034,6 @@
 
 static struct branch_clk audio_core_lpaif_pri_ebit_clk = {
 	.cbcr_reg = AUDIO_CORE_LPAIF_PRI_EBIT_CBCR,
-	.parent = &audio_core_lpaif_pri_clk_src.c,
 	.has_sibling = 1,
 	.base = &virt_bases[LPASS_BASE],
 	.c = {
@@ -4049,7 +4047,7 @@
 	.cbcr_reg = AUDIO_CORE_LPAIF_PRI_IBIT_CBCR,
 	.parent = &audio_core_lpaif_pri_clk_src.c,
 	.has_sibling = 1,
-	.max_div = 16,
+	.max_div = 15,
 	.base = &virt_bases[LPASS_BASE],
 	.c = {
 		.dbg_name = "audio_core_lpaif_pri_ibit_clk",
@@ -4072,7 +4070,6 @@
 
 static struct branch_clk audio_core_lpaif_sec_ebit_clk = {
 	.cbcr_reg = AUDIO_CORE_LPAIF_SEC_EBIT_CBCR,
-	.parent = &audio_core_lpaif_sec_clk_src.c,
 	.has_sibling = 1,
 	.base = &virt_bases[LPASS_BASE],
 	.c = {
@@ -4086,7 +4083,7 @@
 	.cbcr_reg = AUDIO_CORE_LPAIF_SEC_IBIT_CBCR,
 	.parent = &audio_core_lpaif_sec_clk_src.c,
 	.has_sibling = 1,
-	.max_div = 16,
+	.max_div = 15,
 	.base = &virt_bases[LPASS_BASE],
 	.c = {
 		.dbg_name = "audio_core_lpaif_sec_ibit_clk",
@@ -4109,7 +4106,6 @@
 
 static struct branch_clk audio_core_lpaif_ter_ebit_clk = {
 	.cbcr_reg = AUDIO_CORE_LPAIF_TER_EBIT_CBCR,
-	.parent = &audio_core_lpaif_ter_clk_src.c,
 	.has_sibling = 1,
 	.base = &virt_bases[LPASS_BASE],
 	.c = {
@@ -4123,7 +4119,7 @@
 	.cbcr_reg = AUDIO_CORE_LPAIF_TER_IBIT_CBCR,
 	.parent = &audio_core_lpaif_ter_clk_src.c,
 	.has_sibling = 1,
-	.max_div = 16,
+	.max_div = 15,
 	.base = &virt_bases[LPASS_BASE],
 	.c = {
 		.dbg_name = "audio_core_lpaif_ter_ibit_clk",
@@ -4146,7 +4142,6 @@
 
 static struct branch_clk audio_core_lpaif_quad_ebit_clk = {
 	.cbcr_reg = AUDIO_CORE_LPAIF_QUAD_EBIT_CBCR,
-	.parent = &audio_core_lpaif_quad_clk_src.c,
 	.has_sibling = 1,
 	.base = &virt_bases[LPASS_BASE],
 	.c = {
@@ -4160,7 +4155,7 @@
 	.cbcr_reg = AUDIO_CORE_LPAIF_QUAD_IBIT_CBCR,
 	.parent = &audio_core_lpaif_quad_clk_src.c,
 	.has_sibling = 1,
-	.max_div = 16,
+	.max_div = 15,
 	.base = &virt_bases[LPASS_BASE],
 	.c = {
 		.dbg_name = "audio_core_lpaif_quad_ibit_clk",
@@ -4171,7 +4166,6 @@
 
 static struct branch_clk audio_core_lpaif_pcm0_ebit_clk = {
 	.cbcr_reg = AUDIO_CORE_LPAIF_PCM0_EBIT_CBCR,
-	.parent = &audio_core_lpaif_pcm0_clk_src.c,
 	.has_sibling = 1,
 	.base = &virt_bases[LPASS_BASE],
 	.c = {
@@ -4185,7 +4179,6 @@
 	.cbcr_reg = AUDIO_CORE_LPAIF_PCM0_IBIT_CBCR,
 	.parent = &audio_core_lpaif_pcm0_clk_src.c,
 	.has_sibling = 1,
-	.max_div = 16,
 	.base = &virt_bases[LPASS_BASE],
 	.c = {
 		.dbg_name = "audio_core_lpaif_pcm0_ibit_clk",
@@ -4210,7 +4203,6 @@
 	.cbcr_reg = AUDIO_CORE_LPAIF_PCM1_IBIT_CBCR,
 	.parent = &audio_core_lpaif_pcm1_clk_src.c,
 	.has_sibling = 1,
-	.max_div = 16,
 	.base = &virt_bases[LPASS_BASE],
 	.c = {
 		.dbg_name = "audio_core_lpaif_pcm1_ibit_clk",
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 4677a1c..f13c266 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -1035,6 +1035,7 @@
 		MSM_RPM_MAP(9615, CXO_BUFFERS, CXO_BUFFERS, 1),
 		MSM_RPM_MAP(9615, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
 		MSM_RPM_MAP(9615, HDMI_SWITCH, HDMI_SWITCH, 1),
+		MSM_RPM_MAP(9615, VOLTAGE_CORNER, VOLTAGE_CORNER, 1),
 	},
 	.target_status = {
 		MSM_RPM_STATUS_ID_MAP(9615, VERSION_MAJOR),
@@ -1100,6 +1101,7 @@
 		MSM_RPM_STATUS_ID_MAP(9615, CXO_BUFFERS),
 		MSM_RPM_STATUS_ID_MAP(9615, USB_OTG_SWITCH),
 		MSM_RPM_STATUS_ID_MAP(9615, HDMI_SWITCH),
+		MSM_RPM_STATUS_ID_MAP(9615, VOLTAGE_CORNER),
 	},
 	.target_ctrl_id = {
 		MSM_RPM_CTRL_MAP(9615, VERSION_MAJOR),
@@ -1280,17 +1282,17 @@
 		[MSM_RPMRS_VDD_MEM_MAX]         = 1150000,
 	},
 	.vdd_dig_levels = {
-		[MSM_RPMRS_VDD_DIG_RET_LOW]     = 500000,
-		[MSM_RPMRS_VDD_DIG_RET_HIGH]    = 750000,
-		[MSM_RPMRS_VDD_DIG_ACTIVE]      = 950000,
-		[MSM_RPMRS_VDD_DIG_MAX]         = 1150000,
+		[MSM_RPMRS_VDD_DIG_RET_LOW]     = 0,
+		[MSM_RPMRS_VDD_DIG_RET_HIGH]    = 0,
+		[MSM_RPMRS_VDD_DIG_ACTIVE]      = 1,
+		[MSM_RPMRS_VDD_DIG_MAX]         = 3,
 	},
 	.vdd_mask = 0x7FFFFF,
 	.rpmrs_target_id = {
 		[MSM_RPMRS_ID_PXO_CLK]          = MSM_RPM_ID_CXO_CLK,
 		[MSM_RPMRS_ID_L2_CACHE_CTL]     = MSM_RPM_ID_LAST,
-		[MSM_RPMRS_ID_VDD_DIG_0]        = MSM_RPM_ID_PM8018_S1_0,
-		[MSM_RPMRS_ID_VDD_DIG_1]        = MSM_RPM_ID_PM8018_S1_1,
+		[MSM_RPMRS_ID_VDD_DIG_0]        = MSM_RPM_ID_VOLTAGE_CORNER,
+		[MSM_RPMRS_ID_VDD_DIG_1]        = MSM_RPM_ID_LAST,
 		[MSM_RPMRS_ID_VDD_MEM_0]        = MSM_RPM_ID_PM8018_L9_0,
 		[MSM_RPMRS_ID_VDD_MEM_1]        = MSM_RPM_ID_PM8018_L9_1,
 		[MSM_RPMRS_ID_RPM_CTL]          = MSM_RPM_ID_RPM_CTL,
diff --git a/arch/arm/mach-msm/headsmp.S b/arch/arm/mach-msm/headsmp.S
index 50d2060..e5ad312 100644
--- a/arch/arm/mach-msm/headsmp.S
+++ b/arch/arm/mach-msm/headsmp.S
@@ -27,10 +27,6 @@
 	sub	r4, r4, r5		@ determine virtual/phys offsets
 	add	r6, r6, r4		@ apply
 pen:
-	wfe
-	dsb				@ ensure subsequent access is
-					@ after event
-
 	ldr	r7, [r6]		@ pen_rel has cpu to remove from reset
 	cmp	r7, r0			@ are we lucky?
 	bne	pen
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 8c1d5b7..be254f6 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -61,10 +61,6 @@
 	struct msm_camera_io_ext ioext;
 	struct msm_camera_io_clk ioclk;
 	uint8_t csid_core;
-	uint8_t is_csiphy;
-	uint8_t is_csic;
-	uint8_t is_csid;
-	uint8_t is_ispif;
 	uint8_t is_vpe;
 	struct msm_bus_scale_pdata *cam_bus_scale_table;
 };
@@ -389,6 +385,7 @@
 	int (*backlight_level)(int level, int max, int min);
 	int (*pmic_backlight)(int level);
 	int (*rotate_panel)(void);
+	int (*backlight) (int level, int mode);
 	int (*panel_num)(void);
 	void (*panel_config_gpio)(int);
 	int (*vga_switch)(int select_vga);
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index 87e7de1..d8543f3 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -114,52 +114,6 @@
 	STEREO_RAW_SNAP_STARTED,
 };
 
-enum msm_ispif_intftype {
-	PIX0,
-	RDI0,
-	PIX1,
-	RDI1,
-	PIX2,
-	RDI2,
-};
-
-enum msm_ispif_vc {
-	VC0,
-	VC1,
-	VC2,
-	VC3,
-};
-
-enum msm_ispif_cid {
-	CID0,
-	CID1,
-	CID2,
-	CID3,
-	CID4,
-	CID5,
-	CID6,
-	CID7,
-	CID8,
-	CID9,
-	CID10,
-	CID11,
-	CID12,
-	CID13,
-	CID14,
-	CID15,
-};
-
-struct msm_ispif_params {
-	uint8_t intftype;
-	uint16_t cid_mask;
-	uint8_t csid;
-};
-
-struct msm_ispif_params_list {
-	uint32_t len;
-	struct msm_ispif_params params[3];
-};
-
 struct msm_vpe_phy_info {
 	uint32_t sbuf_phy;
 	uint32_t planar0_off;
@@ -172,12 +126,6 @@
 	uint32_t frame_id;
 };
 
-struct msm_camera_csid_vc_cfg {
-	uint8_t cid;
-	uint8_t dt;
-	uint8_t decode_format;
-};
-
 struct msm_camera_csid_lut_params {
 	uint8_t num_cid;
 	struct msm_camera_csid_vc_cfg *vc_cfg;
@@ -209,18 +157,6 @@
 #define VFE31_OUTPUT_MODE_P_ALL_CHNLS (0x1 << 5)
 #endif
 
-#define CSI_EMBED_DATA 0x12
-#define CSI_RESERVED_DATA_0 0x13
-#define CSI_YUV422_8  0x1E
-#define CSI_RAW8    0x2A
-#define CSI_RAW10   0x2B
-#define CSI_RAW12   0x2C
-
-#define CSI_DECODE_6BIT 0
-#define CSI_DECODE_8BIT 1
-#define CSI_DECODE_10BIT 2
-#define CSI_DECODE_DPCM_10_8_10 5
-
 struct msm_vfe_phy_info {
 	uint32_t sbuf_phy;
 	uint32_t planar0_off;
diff --git a/arch/arm/mach-msm/include/mach/msm_hdmi_audio.h b/arch/arm/mach-msm/include/mach/msm_hdmi_audio.h
index 57e794f..2455e93 100644
--- a/arch/arm/mach-msm/include/mach/msm_hdmi_audio.h
+++ b/arch/arm/mach-msm/include/mach/msm_hdmi_audio.h
@@ -36,7 +36,16 @@
 int hdmi_audio_packet_enable(bool on);
 void hdmi_msm_audio_sample_rate_reset(int rate);
 int hdmi_msm_audio_get_sample_rate(void);
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
 int hdmi_msm_audio_info_setup(bool enabled, u32 num_of_channels,
 	u32 channel_allocation, u32 level_shift, bool down_mix);
-
+#else
+static inline int hdmi_msm_audio_info_setup(bool enabled,
+	u32 num_of_channels, u32 channel_allocation, u32 level_shift,
+	bool down_mix)
+{
+	return 0;
+}
+#endif
 #endif /* __MSM_HDMI_AUDIO_H*/
diff --git a/arch/arm/mach-msm/include/mach/msm_smsm.h b/arch/arm/mach-msm/include/mach/msm_smsm.h
index fbb8502..e19f39d 100644
--- a/arch/arm/mach-msm/include/mach/msm_smsm.h
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.h
@@ -95,7 +95,7 @@
 #define SMSM_WLAN_TX_RINGS_EMPTY 0x00000200
 #define SMSM_WLAN_TX_ENABLE	0x00000400
 
-#define SMSM_ERR_SRV_READY         0x00008000
+#define SMSM_SUBSYS2AP_STATUS         0x00008000
 
 #ifdef CONFIG_MSM_SMD
 void *smem_alloc(unsigned id, unsigned size);
diff --git a/arch/arm/mach-msm/include/mach/ocmem.h b/arch/arm/mach-msm/include/mach/ocmem.h
index bf7c338..b0475ed 100644
--- a/arch/arm/mach-msm/include/mach/ocmem.h
+++ b/arch/arm/mach-msm/include/mach/ocmem.h
@@ -41,7 +41,7 @@
 };
 
 struct ocmem_map_list {
-	int num_chunks;
+	unsigned num_chunks;
 	struct ocmem_chunk chunks[OCMEM_MAX_CHUNKS];
 };
 
@@ -84,9 +84,14 @@
 
 int ocmem_notifier_unregister(void *notif_hndl, struct notifier_block *nb);
 
+/* Obtain the maximum quota for the client */
+unsigned long get_max_quota(int client_id);
+
 /* Allocation APIs */
 struct ocmem_buf *ocmem_allocate(int client_id, unsigned long size);
 
+struct ocmem_buf *ocmem_allocate_nowait(int client_id, unsigned long size);
+
 struct ocmem_buf *ocmem_allocate_nb(int client_id, unsigned long size);
 
 struct ocmem_buf *ocmem_allocate_range(int client_id, unsigned long min,
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index dd3a318..dd976ea 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -24,6 +24,9 @@
 #define OCMEM_PHYS_BASE 0xFEC00000
 #define OCMEM_PHYS_SIZE 0x180000
 
+#define TO_OCMEM 0x1
+#define TO_DDR 0x2
+
 struct ocmem_zone;
 
 struct ocmem_zone_ops {
@@ -45,6 +48,19 @@
 	struct ocmem_zone_ops *z_ops;
 };
 
+enum op_code {
+	SCHED_NOP = 0x0,
+	SCHED_ALLOCATE,
+	SCHED_FREE,
+	SCHED_GROW,
+	SCHED_SHRINK,
+	SCHED_MAP,
+	SCHED_UNMAP,
+	SCHED_EVICT,
+	SCHED_RESTORE,
+	SCHED_DUMP,
+};
+
 struct ocmem_req {
 	struct rw_semaphore rw_sem;
 	/* Chain in sched queue */
@@ -60,6 +76,8 @@
 	/* reverse pointers */
 	struct ocmem_zone *zone;
 	struct ocmem_buf *buffer;
+	struct ocmem_map_list *mlist;
+	enum op_code op;
 	unsigned long state;
 	/* Request assignments */
 	unsigned long req_start;
@@ -73,7 +91,41 @@
 	struct ocmem_req *req;
 };
 
+static inline struct ocmem_buf *handle_to_buffer(struct ocmem_handle *handle)
+{
+	if (handle)
+		return &handle->buffer;
+	else
+		return NULL;
+}
+
+static inline struct ocmem_handle *buffer_to_handle(struct ocmem_buf *buffer)
+{
+	if (buffer)
+		return container_of(buffer, struct ocmem_handle, buffer);
+	else
+		return NULL;
+}
+
+static inline struct ocmem_req *handle_to_req(struct ocmem_handle *handle)
+{
+	if (handle)
+		return handle->req;
+	else
+		return NULL;
+}
+
+static inline struct ocmem_handle *req_to_handle(struct ocmem_req *req)
+{
+	if (req && req->buffer)
+		return container_of(req->buffer, struct ocmem_handle, buffer);
+	else
+		return NULL;
+}
+
 struct ocmem_zone *get_zone(unsigned);
+unsigned long offset_to_phys(unsigned long);
+unsigned long phys_to_offset(unsigned long);
 unsigned long allocate_head(struct ocmem_zone *, unsigned long);
 int free_head(struct ocmem_zone *, unsigned long, unsigned long);
 unsigned long allocate_tail(struct ocmem_zone *, unsigned long);
@@ -82,4 +134,12 @@
 int ocmem_notifier_init(void);
 int check_notifier(int);
 int dispatch_notification(int, enum ocmem_notif_type, struct ocmem_buf *);
+
+int ocmem_sched_init(void);
+int process_allocate(int, struct ocmem_handle *, unsigned long, unsigned long,
+			unsigned long, bool, bool);
+int process_free(int, struct ocmem_handle *);
+int process_xfer(int, struct ocmem_handle *, struct ocmem_map_list *,
+			int direction);
+unsigned long process_quota(int);
 #endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/audio_acdb.h b/arch/arm/mach-msm/include/mach/qdsp6v2/audio_acdb.h
index a55dee6..65cf647 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/audio_acdb.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/audio_acdb.h
@@ -14,8 +14,11 @@
 #define _AUDIO_ACDB_H
 
 #include <linux/msm_audio_acdb.h>
+#ifdef CONFIG_ARCH_MSMCOPPER
+#include <sound/q6adm-v2.h>
+#else
 #include <sound/q6adm.h>
-
+#endif
 enum {
 	RX_CAL,
 	TX_CAL,
diff --git a/arch/arm/mach-msm/include/mach/rpm-9615.h b/arch/arm/mach-msm/include/mach/rpm-9615.h
index 6ae7bae..4ca5eea 100644
--- a/arch/arm/mach-msm/include/mach/rpm-9615.h
+++ b/arch/arm/mach-msm/include/mach/rpm-9615.h
@@ -72,8 +72,9 @@
 	MSM_RPM_9615_SEL_CXO_BUFFERS				= 81,
 	MSM_RPM_9615_SEL_USB_OTG_SWITCH				= 82,
 	MSM_RPM_9615_SEL_HDMI_SWITCH				= 83,
+	MSM_RPM_9615_SEL_VOLTAGE_CORNER				= 87,
 
-	MSM_RPM_9615_SEL_LAST = MSM_RPM_9615_SEL_HDMI_SWITCH,
+	MSM_RPM_9615_SEL_LAST = MSM_RPM_9615_SEL_VOLTAGE_CORNER,
 };
 
 /* RPM resource (4 byte) word ID enum */
@@ -162,8 +163,9 @@
 	MSM_RPM_9615_ID_CXO_BUFFERS				= 105,
 	MSM_RPM_9615_ID_USB_OTG_SWITCH				= 106,
 	MSM_RPM_9615_ID_HDMI_SWITCH				= 107,
+	MSM_RPM_9615_ID_VOLTAGE_CORNER				= 109,
 
-	MSM_RPM_9615_ID_LAST = MSM_RPM_9615_ID_HDMI_SWITCH,
+	MSM_RPM_9615_ID_LAST = MSM_RPM_9615_ID_VOLTAGE_CORNER,
 };
 
 /* RPM status ID enum */
@@ -231,8 +233,9 @@
 	MSM_RPM_9615_STATUS_ID_CXO_BUFFERS			= 60,
 	MSM_RPM_9615_STATUS_ID_USB_OTG_SWITCH			= 61,
 	MSM_RPM_9615_STATUS_ID_HDMI_SWITCH			= 62,
+	MSM_RPM_9615_STATUS_ID_VOLTAGE_CORNER			= 64,
 
-	MSM_RPM_9615_STATUS_ID_LAST = MSM_RPM_9615_STATUS_ID_HDMI_SWITCH,
+	MSM_RPM_9615_STATUS_ID_LAST = MSM_RPM_9615_STATUS_ID_VOLTAGE_CORNER,
 };
 
 #endif /* __ARCH_ARM_MACH_MSM_RPM_9615_H */
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator-9615.h b/arch/arm/mach-msm/include/mach/rpm-regulator-9615.h
index f5fa8ca..6a7fae5 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator-9615.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator-9615.h
@@ -107,7 +107,8 @@
 	RPM_VREG_ID_PM8018_S4,
 	RPM_VREG_ID_PM8018_S5,
 	RPM_VREG_ID_PM8018_LVS1,
-	RPM_VREG_ID_PM8018_MAX_REAL = RPM_VREG_ID_PM8018_LVS1,
+	RPM_VREG_ID_PM8018_VDD_DIG_CORNER,
+	RPM_VREG_ID_PM8018_MAX_REAL = RPM_VREG_ID_PM8018_VDD_DIG_CORNER,
 
 	/* The following are IDs for regulator devices to enable pin control. */
 	RPM_VREG_ID_PM8018_L2_PC,
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index c15e8b1..c0bff63 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -472,19 +472,19 @@
 	return port_ptr;
 }
 
+/*
+ * Should be called with local_ports_lock locked
+ */
 static struct msm_ipc_port *msm_ipc_router_lookup_local_port(uint32_t port_id)
 {
 	int key = (port_id & (LP_HASH_SIZE - 1));
 	struct msm_ipc_port *port_ptr;
 
-	mutex_lock(&local_ports_lock);
 	list_for_each_entry(port_ptr, &local_ports[key], list) {
 		if (port_ptr->this_port.port_id == port_id) {
-			mutex_unlock(&local_ports_lock);
 			return port_ptr;
 		}
 	}
-	mutex_unlock(&local_ports_lock);
 	return NULL;
 }
 
@@ -1432,16 +1432,19 @@
 	resume_tx_node_id = hdr->dst_node_id;
 	resume_tx_port_id = hdr->dst_port_id;
 
+	rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
+						      hdr->src_port_id);
+
+	mutex_lock(&local_ports_lock);
 	port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
 	if (!port_ptr) {
 		pr_err("%s: No local port id %08x\n", __func__,
 			hdr->dst_port_id);
+		mutex_unlock(&local_ports_lock);
 		release_pkt(pkt);
 		goto process_done;
 	}
 
-	rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
-						      hdr->src_port_id);
 	if (!rport_ptr) {
 		rport_ptr = msm_ipc_router_create_remote_port(
 							hdr->src_node_id,
@@ -1449,6 +1452,7 @@
 		if (!rport_ptr) {
 			pr_err("%s: Remote port %08x:%08x creation failed\n",
 				__func__, hdr->src_node_id, hdr->src_port_id);
+			mutex_unlock(&local_ports_lock);
 			goto process_done;
 		}
 	}
@@ -1459,7 +1463,9 @@
 		list_add_tail(&pkt->list, &port_ptr->port_rx_q);
 		wake_up(&port_ptr->port_rx_wait_q);
 		mutex_unlock(&port_ptr->port_rx_q_lock);
+		mutex_unlock(&local_ports_lock);
 	} else {
+		mutex_lock(&port_ptr->port_rx_q_lock);
 		src_addr = kmalloc(sizeof(struct msm_ipc_port_addr),
 				   GFP_KERNEL);
 		if (src_addr) {
@@ -1467,8 +1473,10 @@
 			src_addr->port_id = hdr->src_port_id;
 		}
 		skb_pull(head_skb, IPC_ROUTER_HDR_SIZE);
+		mutex_unlock(&local_ports_lock);
 		port_ptr->notify(MSM_IPC_ROUTER_READ_CB, pkt->pkt_fragment_q,
 				 src_addr, port_ptr->priv);
+		mutex_unlock(&port_ptr->port_rx_q_lock);
 		pkt->pkt_fragment_q = NULL;
 		src_addr = NULL;
 		release_pkt(pkt);
@@ -1628,9 +1636,11 @@
 	hdr->dst_port_id = port_id;
 	pkt->length += IPC_ROUTER_HDR_SIZE;
 
+	mutex_lock(&local_ports_lock);
 	port_ptr = msm_ipc_router_lookup_local_port(port_id);
 	if (!port_ptr) {
 		pr_err("%s: Local port %d not present\n", __func__, port_id);
+		mutex_unlock(&local_ports_lock);
 		release_pkt(pkt);
 		return -ENODEV;
 	}
@@ -1640,6 +1650,7 @@
 	list_add_tail(&pkt->list, &port_ptr->port_rx_q);
 	wake_up(&port_ptr->port_rx_wait_q);
 	mutex_unlock(&port_ptr->port_rx_q_lock);
+	mutex_unlock(&local_ports_lock);
 
 	return pkt->length;
 }
@@ -1932,6 +1943,10 @@
 		return -EINVAL;
 
 	if (port_ptr->type == SERVER_PORT || port_ptr->type == CLIENT_PORT) {
+		mutex_lock(&local_ports_lock);
+		list_del(&port_ptr->list);
+		mutex_unlock(&local_ports_lock);
+
 		if (port_ptr->type == SERVER_PORT) {
 			msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
 			msg.srv.service = port_ptr->port_name.service;
@@ -1950,6 +1965,10 @@
 		}
 		broadcast_ctl_msg(&msg);
 		broadcast_ctl_msg_locally(&msg);
+	} else if (port_ptr->type == CONTROL_PORT) {
+		mutex_lock(&control_ports_lock);
+		list_del(&port_ptr->list);
+		mutex_unlock(&control_ports_lock);
 	}
 
 	mutex_lock(&port_ptr->port_rx_q_lock);
@@ -1969,17 +1988,6 @@
 			msm_ipc_router_destroy_server(server,
 				port_ptr->this_port.node_id,
 				port_ptr->this_port.port_id);
-		mutex_lock(&local_ports_lock);
-		list_del(&port_ptr->list);
-		mutex_unlock(&local_ports_lock);
-	} else if (port_ptr->type == CLIENT_PORT) {
-		mutex_lock(&local_ports_lock);
-		list_del(&port_ptr->list);
-		mutex_unlock(&local_ports_lock);
-	} else if (port_ptr->type == CONTROL_PORT) {
-		mutex_lock(&control_ports_lock);
-		list_del(&port_ptr->list);
-		mutex_unlock(&control_ports_lock);
 	}
 
 	wake_lock_destroy(&port_ptr->port_rx_wake_lock);
diff --git a/arch/arm/mach-msm/modem_notifier.c b/arch/arm/mach-msm/modem_notifier.c
index d92098b..2f4f6af 100644
--- a/arch/arm/mach-msm/modem_notifier.c
+++ b/arch/arm/mach-msm/modem_notifier.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-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
@@ -193,8 +193,15 @@
 }
 #endif
 
-static int __init init_modem_notifier_list(void)
+int __init msm_init_modem_notifier_list(void)
 {
+	static bool registered;
+
+	if (registered)
+		return 0;
+
+	registered = true;
+
 	srcu_init_notifier_head(&modem_notifier_list);
 	modem_notifier_debugfs_init();
 #if defined(DEBUG)
@@ -210,4 +217,4 @@
 
 	return 0;
 }
-module_init(init_modem_notifier_list);
+module_init(msm_init_modem_notifier_list);
diff --git a/arch/arm/mach-msm/modem_notifier.h b/arch/arm/mach-msm/modem_notifier.h
index 1bd2d6d..e39c163 100644
--- a/arch/arm/mach-msm/modem_notifier.h
+++ b/arch/arm/mach-msm/modem_notifier.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-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
@@ -30,5 +30,6 @@
 extern void modem_queue_start_reset_notify(void);
 extern void modem_queue_end_reset_notify(void);
 extern void modem_queue_smsm_init_notify(void);
+extern int __init msm_init_modem_notifier_list(void);
 
 #endif /* _MODEM_NOTIFIER_H */
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
index ddfc906..ae1d6f2 100644
--- a/arch/arm/mach-msm/ocmem.c
+++ b/arch/arm/mach-msm/ocmem.c
@@ -97,6 +97,25 @@
 	return -EINVAL;
 }
 
+inline unsigned long phys_to_offset(unsigned long addr)
+{
+	if (!ocmem_pdata)
+		return 0;
+	if (addr < ocmem_pdata->base ||
+		addr > (ocmem_pdata->base + ocmem_pdata->size))
+		return 0;
+	return addr - ocmem_pdata->base;
+}
+
+inline unsigned long offset_to_phys(unsigned long offset)
+{
+	if (!ocmem_pdata)
+		return 0;
+	if (offset > ocmem_pdata->size)
+		return 0;
+	return offset + ocmem_pdata->base;
+}
+
 static struct ocmem_plat_data *parse_static_config(struct platform_device *pdev)
 {
 	struct ocmem_plat_data *pdata = NULL;
@@ -276,6 +295,8 @@
 	if (ocmem_notifier_init())
 		return -EBUSY;
 
+	if (ocmem_sched_init())
+		return -EBUSY;
 	dev_info(dev, "initialized successfully\n");
 	return 0;
 }
diff --git a/arch/arm/mach-msm/ocmem_api.c b/arch/arm/mach-msm/ocmem_api.c
new file mode 100644
index 0000000..bed13de
--- /dev/null
+++ b/arch/arm/mach-msm/ocmem_api.c
@@ -0,0 +1,327 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <mach/ocmem_priv.h>
+
+static inline int check_id(int id)
+{
+	return (id < OCMEM_CLIENT_MAX && id >= OCMEM_GRAPHICS);
+}
+
+static struct ocmem_handle *generate_handle(void)
+{
+	struct ocmem_handle *handle = NULL;
+
+	handle = kzalloc(sizeof(struct ocmem_handle), GFP_KERNEL);
+	if (!handle) {
+		pr_err("ocmem: Unable to generate buffer handle\n");
+		return NULL;
+	}
+	mutex_init(&handle->handle_mutex);
+	return handle;
+}
+
+static int free_handle(struct ocmem_handle *handle)
+{
+	if (!handle)
+		return -EINVAL;
+
+	mutex_destroy(&handle->handle_mutex);
+	kfree(handle);
+	handle = NULL;
+	return 0;
+}
+
+static int __ocmem_free(int id, struct ocmem_buf *buf)
+{
+	int ret = 0;
+	struct ocmem_handle *handle = buffer_to_handle(buf);
+
+	if (!handle)
+		return -EINVAL;
+
+	mutex_lock(&handle->handle_mutex);
+	ret = process_free(id, handle);
+	mutex_unlock(&handle->handle_mutex);
+
+	if (ret)
+		return -EINVAL;
+
+	free_handle(handle);
+	return 0;
+}
+
+static struct ocmem_buf *__ocmem_allocate_range(int id, unsigned long min,
+		unsigned long max, unsigned long step, bool block, bool wait)
+{
+	struct ocmem_handle *handle = NULL;
+	int ret = 0;
+
+	handle = generate_handle();
+	if (!handle) {
+		pr_err("ocmem: Unable to generate handle\n");
+		return NULL;
+	}
+
+	mutex_lock(&handle->handle_mutex);
+	ret = process_allocate(id, handle, min, max, step, block, wait);
+	mutex_unlock(&handle->handle_mutex);
+	if (ret) {
+		pr_err("ocmem allocation failed\n");
+		free_handle(handle);
+		return NULL;
+	} else
+		return handle_to_buffer(handle);
+}
+
+struct ocmem_buf *ocmem_allocate(int client_id, unsigned long size)
+{
+	bool can_block = false;
+	bool can_wait = true;
+
+	if (!check_id(client_id)) {
+		pr_err("ocmem: Invalid client id: %d\n", client_id);
+		return NULL;
+	}
+
+	if (size < OCMEM_MIN_ALLOC) {
+		pr_err("ocmem: requested size %lx must be at least %x\n",
+				size, OCMEM_MIN_ALLOC);
+		return NULL;
+	}
+
+	if (!IS_ALIGNED(size, OCMEM_MIN_ALIGN)) {
+		pr_err("ocmem: Invalid alignment, size must be %x aligned\n",
+				OCMEM_MIN_ALIGN);
+		return NULL;
+	}
+
+	return __ocmem_allocate_range(client_id, size, size,
+					size, can_block, can_wait);
+}
+
+struct ocmem_buf *ocmem_allocate_nowait(int client_id, unsigned long size)
+{
+	bool can_block = false;
+	bool can_wait = false;
+
+	if (!check_id(client_id)) {
+		pr_err("ocmem: Invalid client id: %d\n", client_id);
+		return NULL;
+	}
+
+	if (size < OCMEM_MIN_ALLOC) {
+		pr_err("ocmem: requested size %lx must be at least %x\n",
+				size, OCMEM_MIN_ALLOC);
+		return NULL;
+	}
+
+	if (!IS_ALIGNED(size, OCMEM_MIN_ALIGN)) {
+		pr_err("ocmem: Invalid alignment, size must be %x aligned\n",
+				OCMEM_MIN_ALIGN);
+		return NULL;
+	}
+	return __ocmem_allocate_range(client_id, size, size,
+					size, can_block, can_wait);
+}
+
+struct ocmem_buf *ocmem_allocate_range(int client_id, unsigned long min,
+		unsigned long goal, unsigned long step)
+{
+	bool can_block = true;
+	bool can_wait = false;
+
+	if (!check_id(client_id)) {
+		pr_err("ocmem: Invalid client id: %d\n", client_id);
+		return NULL;
+	}
+
+	/* Asynchronous API requires notifier registration */
+	if (!check_notifier(client_id)) {
+		pr_err("ocmem: No notifier registered for client %d\n",
+				client_id);
+		return NULL;
+	}
+
+	if (min < OCMEM_MIN_ALLOC) {
+		pr_err("ocmem: requested min size %lx must be at least %x\n",
+				min, OCMEM_MIN_ALLOC);
+		return NULL;
+	}
+
+	if (!IS_ALIGNED(min | goal | step, OCMEM_MIN_ALIGN)) {
+		pr_err("ocmem: Invalid alignment, args must be %x aligned\n",
+				OCMEM_MIN_ALIGN);
+		return NULL;
+	}
+
+	return __ocmem_allocate_range(client_id, min, goal,
+				step, can_block, can_wait);
+}
+
+struct ocmem_buf *ocmem_allocate_nb(int client_id, unsigned long size)
+{
+	bool can_block = true;
+	bool can_wait = false;
+
+	if (!check_id(client_id)) {
+		pr_err("ocmem: Invalid client id: %d\n", client_id);
+		return NULL;
+	}
+
+	/* Asynchronous API requires notifier registration */
+	if (!check_notifier(client_id)) {
+		pr_err("ocmem: No notifier registered for client %d\n",
+				client_id);
+		return NULL;
+	}
+
+	if (size < OCMEM_MIN_ALLOC) {
+		pr_err("ocmem: requested size %lx must be at least %x\n",
+				size, OCMEM_MIN_ALLOC);
+		return NULL;
+	}
+
+	if (!IS_ALIGNED(size, OCMEM_MIN_ALIGN)) {
+		pr_err("ocmem: Invalid alignment, args must be %x aligned\n",
+				OCMEM_MIN_ALIGN);
+		return NULL;
+	}
+
+	return __ocmem_allocate_range(client_id, 0, size, size,
+						can_block, can_wait);
+
+}
+
+int ocmem_free(int client_id, struct ocmem_buf *buffer)
+{
+	if (!check_id(client_id)) {
+		pr_err("ocmem: Invalid client id: %d\n", client_id);
+		return -EINVAL;
+	}
+
+	if (!buffer) {
+		pr_err("ocmem: Invalid buffer\n");
+		return -EINVAL;
+	}
+
+	return __ocmem_free(client_id, buffer);
+}
+
+int pre_validate_chunk_list(struct ocmem_map_list *list)
+{
+	int i = 0;
+	struct ocmem_chunk *chunks;
+
+	if (!list)
+		return -EINVAL;
+
+	if (list->num_chunks > OCMEM_MAX_CHUNKS || list->num_chunks == 0)
+		return -EINVAL;
+
+	chunks = list->chunks;
+
+	if (!chunks)
+		return -EINVAL;
+
+	for (i = 0; i < list->num_chunks; i++) {
+		if (!chunks[i].ddr_paddr ||
+			chunks[i].size < MIN_CHUNK_SIZE)
+			return -EINVAL;
+	}
+	return 0;
+}
+
+int ocmem_map(int client_id, struct ocmem_buf *buffer,
+			struct ocmem_map_list *list)
+{
+	int ret = 0;
+	struct ocmem_handle *handle = NULL;
+
+	if (!check_id(client_id)) {
+		pr_err("ocmem: Invalid client id: %d\n", client_id);
+		return -EINVAL;
+	}
+
+	/* Asynchronous API requires notifier registration */
+	if (!check_notifier(client_id)) {
+		pr_err("ocmem: No notifier registered for client %d\n",
+				client_id);
+		return -EINVAL;
+	}
+
+	if (!buffer) {
+		pr_err("ocmem: Invalid buffer\n");
+		return -EINVAL;
+	}
+
+	if (!pre_validate_chunk_list(list))
+		return -EINVAL;
+
+	handle = buffer_to_handle(buffer);
+
+	if (!handle)
+		return -EINVAL;
+
+	mutex_lock(&handle->handle_mutex);
+	ret = process_xfer(client_id, handle, list, TO_OCMEM);
+	mutex_unlock(&handle->handle_mutex);
+	return ret;
+}
+
+int ocmem_unmap(int client_id, struct ocmem_buf *buffer,
+			struct ocmem_map_list *list)
+{
+
+	int ret = 0;
+	struct ocmem_handle *handle = NULL;
+
+	if (!check_id(client_id)) {
+		pr_err("ocmem: Invalid client id: %d\n", client_id);
+		return -EINVAL;
+	}
+
+	/* Asynchronous API requires notifier registration */
+	if (!check_notifier(client_id)) {
+		pr_err("ocmem: No notifier registered for client %d\n",
+				client_id);
+		return -EINVAL;
+	}
+
+	if (!buffer) {
+		pr_err("ocmem: Invalid buffer\n");
+		return -EINVAL;
+	}
+
+	if (!pre_validate_chunk_list(list))
+		return -EINVAL;
+
+	handle = buffer_to_handle(buffer);
+
+	if (!handle)
+		return -EINVAL;
+
+	mutex_lock(&handle->handle_mutex);
+	ret = process_xfer(client_id, handle, list, TO_DDR);
+	mutex_unlock(&handle->handle_mutex);
+	return ret;
+}
+
+unsigned long get_max_quota(int client_id)
+{
+	if (!check_id(client_id)) {
+		pr_err("ocmem: Invalid client id: %d\n", client_id);
+		return 0x0;
+	}
+	return process_quota(client_id);
+}
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
new file mode 100644
index 0000000..10a267c
--- /dev/null
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -0,0 +1,1255 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/rbtree.h>
+#include <linux/idr.h>
+#include <linux/genalloc.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <mach/ocmem_priv.h>
+
+enum request_states {
+	R_FREE = 0x0,	/* request is not allocated */
+	R_PENDING,	/* request has a pending operation */
+	R_ALLOCATED,	/* request has been allocated */
+	R_MUST_GROW,	/* request must grow as a part of pending operation */
+	R_MUST_SHRINK,	/* request must shrink as a part of pending operation */
+	R_MUST_MAP,	/* request must be mapped before being used */
+	R_MUST_UNMAP,	/* request must be unmapped when not being used */
+	R_MAPPED,	/* request is mapped and actively used by client */
+	R_UNMAPPED,	/* request is not mapped, so it's not in active use */
+	R_EVICTED,	/* request is evicted and must be restored */
+};
+
+#define SET_STATE(x, val) (set_bit((val), &(x)->state))
+#define CLEAR_STATE(x, val) (clear_bit((val), &(x)->state))
+#define TEST_STATE(x, val) (test_bit((val), &(x)->state))
+
+enum op_res {
+	OP_COMPLETE = 0x0,
+	OP_RESCHED,
+	OP_PARTIAL,
+	OP_FAIL = ~0x0,
+};
+
+/* Represents various client priorities */
+/* Note: More than one client can share a priority level */
+enum client_prio {
+	MIN_PRIO = 0x0,
+	NO_PRIO = MIN_PRIO,
+	PRIO_SENSORS = 0x1,
+	PRIO_BLAST = 0x1,
+	PRIO_LP_AUDIO = 0x1,
+	PRIO_HP_AUDIO = 0x2,
+	PRIO_VOICE = 0x3,
+	PRIO_GFX_GROWTH = 0x4,
+	PRIO_VIDEO = 0x5,
+	PRIO_GFX = 0x6,
+	PRIO_OCMEM = 0x7,
+	MAX_OCMEM_PRIO = PRIO_OCMEM + 1,
+};
+
+static struct list_head sched_queue[MAX_OCMEM_PRIO];
+static struct mutex sched_queue_mutex;
+
+/* The duration in msecs before a pending operation is scheduled
+ * This allows an idle window between use case boundaries where various
+ * hardware state changes can occur. The value will be tweaked on actual
+ * hardware.
+*/
+#define SCHED_DELAY 10
+
+/* OCMEM Operational modes */
+enum ocmem_client_modes {
+	OCMEM_PERFORMANCE = 1,
+	OCMEM_PASSIVE,
+	OCMEM_LOW_POWER,
+	OCMEM_MODE_MAX = OCMEM_LOW_POWER
+};
+
+/* OCMEM Addressing modes */
+enum ocmem_interconnects {
+	OCMEM_BLOCKED = 0,
+	OCMEM_PORT = 1,
+	OCMEM_OCMEMNOC = 2,
+	OCMEM_SYSNOC = 3,
+};
+
+/**
+ * Primary OCMEM Arbitration Table
+ **/
+struct ocmem_table {
+	int client_id;
+	int priority;
+	int mode;
+	int hw_interconnect;
+} ocmem_client_table[OCMEM_CLIENT_MAX] = {
+	{OCMEM_GRAPHICS, PRIO_GFX, OCMEM_PERFORMANCE, OCMEM_PORT},
+	{OCMEM_VIDEO, PRIO_VIDEO, OCMEM_PERFORMANCE, OCMEM_OCMEMNOC},
+	{OCMEM_CAMERA, NO_PRIO, OCMEM_PERFORMANCE, OCMEM_OCMEMNOC},
+	{OCMEM_HP_AUDIO, PRIO_HP_AUDIO, OCMEM_PASSIVE, OCMEM_BLOCKED},
+	{OCMEM_VOICE, PRIO_VOICE, OCMEM_PASSIVE, OCMEM_BLOCKED},
+	{OCMEM_LP_AUDIO, PRIO_LP_AUDIO, OCMEM_LOW_POWER, OCMEM_SYSNOC},
+	{OCMEM_SENSORS, PRIO_SENSORS, OCMEM_LOW_POWER, OCMEM_SYSNOC},
+	{OCMEM_BLAST, PRIO_BLAST, OCMEM_LOW_POWER, OCMEM_SYSNOC},
+};
+
+static struct rb_root sched_tree;
+static struct mutex sched_mutex;
+
+/* A region represents a continuous interval in OCMEM address space */
+struct ocmem_region {
+	/* Chain in Interval Tree */
+	struct rb_node region_rb;
+	/* Hash map of requests */
+	struct idr region_idr;
+	unsigned long r_start;
+	unsigned long r_end;
+	unsigned long r_sz;
+	/* Highest priority of all requests served by this region */
+	int max_prio;
+};
+
+/* Is OCMEM tightly coupled to the client ?*/
+static inline int is_tcm(int id)
+{
+	if (ocmem_client_table[id].hw_interconnect == OCMEM_PORT ||
+		ocmem_client_table[id].hw_interconnect == OCMEM_OCMEMNOC)
+		return 1;
+	else
+		return 0;
+}
+
+static inline int is_blocked(int id)
+{
+	return ocmem_client_table[id].hw_interconnect == OCMEM_BLOCKED ? 1 : 0;
+}
+
+/* Returns the address that can be used by a device core to access OCMEM */
+static unsigned long device_address(int id, unsigned long addr)
+{
+	int hw_interconnect = ocmem_client_table[id].hw_interconnect;
+	unsigned long ret_addr = 0x0;
+
+	switch (hw_interconnect) {
+	case OCMEM_PORT:
+		ret_addr = phys_to_offset(addr);
+		break;
+	case OCMEM_OCMEMNOC:
+	case OCMEM_SYSNOC:
+		ret_addr = addr;
+		break;
+	case OCMEM_BLOCKED:
+		ret_addr = 0x0;
+		break;
+	}
+	return ret_addr;
+}
+
+/* Returns the address as viewed by the core */
+static unsigned long core_address(int id, unsigned long addr)
+{
+	int hw_interconnect = ocmem_client_table[id].hw_interconnect;
+	unsigned long ret_addr = 0x0;
+
+	switch (hw_interconnect) {
+	case OCMEM_PORT:
+		ret_addr = offset_to_phys(addr);
+		break;
+	case OCMEM_OCMEMNOC:
+	case OCMEM_SYSNOC:
+		ret_addr = addr;
+		break;
+	case OCMEM_BLOCKED:
+		ret_addr = 0x0;
+		break;
+	}
+	return ret_addr;
+}
+
+static int insert_region(struct ocmem_region *region)
+{
+
+	struct rb_root *root = &sched_tree;
+	struct rb_node **p = &root->rb_node;
+	struct rb_node *parent = NULL;
+	struct ocmem_region *tmp = NULL;
+	unsigned long addr = region->r_start;
+
+	while (*p) {
+		parent = *p;
+		tmp = rb_entry(parent, struct ocmem_region, region_rb);
+
+		if (tmp->r_end > addr) {
+			if (tmp->r_start <= addr)
+				break;
+			p =  &(*p)->rb_left;
+		} else if (tmp->r_end <= addr)
+			p = &(*p)->rb_right;
+	}
+	rb_link_node(&region->region_rb, parent, p);
+	rb_insert_color(&region->region_rb, root);
+	return 0;
+}
+
+static int remove_region(struct ocmem_region *region)
+{
+	struct rb_root *root = &sched_tree;
+	rb_erase(&region->region_rb, root);
+	return 0;
+}
+
+static struct ocmem_req *ocmem_create_req(void)
+{
+	struct ocmem_req *p = NULL;
+
+	p =  kzalloc(sizeof(struct ocmem_req), GFP_KERNEL);
+	if (!p)
+		return NULL;
+
+	INIT_LIST_HEAD(&p->zone_list);
+	INIT_LIST_HEAD(&p->sched_list);
+	init_rwsem(&p->rw_sem);
+	SET_STATE(p, R_FREE);
+	return p;
+}
+
+static int ocmem_destroy_req(struct ocmem_req *req)
+{
+	kfree(req);
+	return 0;
+}
+
+static struct ocmem_region *create_region(void)
+{
+	struct ocmem_region *p = NULL;
+
+	p =  kzalloc(sizeof(struct ocmem_region), GFP_KERNEL);
+	if (!p)
+		return NULL;
+	idr_init(&p->region_idr);
+	p->r_start = p->r_end = p->r_sz = 0x0;
+	p->max_prio = NO_PRIO;
+	return p;
+}
+
+static int destroy_region(struct ocmem_region *region)
+{
+	kfree(region);
+	return 0;
+}
+
+static int attach_req(struct ocmem_region *region, struct ocmem_req *req)
+{
+	int ret, id;
+
+	while (1) {
+		if (idr_pre_get(&region->region_idr, GFP_KERNEL) == 0)
+			return -ENOMEM;
+
+		ret = idr_get_new_above(&region->region_idr, req, 1, &id);
+
+		if (ret != -EAGAIN)
+			break;
+	}
+
+	if (!ret) {
+		req->req_id = id;
+		pr_debug("ocmem: request %p(id:%d) attached to region %p\n",
+				req, id, region);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int detach_req(struct ocmem_region *region, struct ocmem_req *req)
+{
+	idr_remove(&region->region_idr, req->req_id);
+	return 0;
+}
+
+static int populate_region(struct ocmem_region *region, struct ocmem_req *req)
+{
+	region->r_start = req->req_start;
+	region->r_end = req->req_end;
+	region->r_sz =  req->req_end - req->req_start + 1;
+	return 0;
+}
+
+static int region_req_count(int id, void *ptr, void *data)
+{
+	int *count = data;
+	*count = *count + 1;
+	return 0;
+}
+
+static int req_count(struct ocmem_region *region)
+{
+	int count = 0;
+	idr_for_each(&region->region_idr, region_req_count, &count);
+	return count;
+}
+
+static int compute_max_prio(int id, void *ptr, void *data)
+{
+	int *max = data;
+	struct ocmem_req *req = ptr;
+
+	if (req->prio > *max)
+		*max = req->prio;
+	return 0;
+}
+
+static int update_region_prio(struct ocmem_region *region)
+{
+	int max_prio;
+	if (req_count(region) != 0) {
+		idr_for_each(&region->region_idr, compute_max_prio, &max_prio);
+		region->max_prio = max_prio;
+	} else {
+		region->max_prio = NO_PRIO;
+	}
+	pr_debug("ocmem: Updating prio of region %p as %d\n",
+			region, max_prio);
+
+	return 0;
+}
+
+static struct ocmem_region *find_region(unsigned long addr)
+{
+	struct ocmem_region *region = NULL;
+	struct rb_node *rb_node = NULL;
+
+	rb_node = sched_tree.rb_node;
+
+	while (rb_node) {
+		struct ocmem_region *tmp_region = NULL;
+		tmp_region = rb_entry(rb_node, struct ocmem_region, region_rb);
+
+		if (tmp_region->r_end > addr) {
+			region = tmp_region;
+			if (tmp_region->r_start <= addr)
+				break;
+			rb_node = rb_node->rb_left;
+		} else {
+			rb_node = rb_node->rb_right;
+		}
+	}
+	return region;
+}
+
+static struct ocmem_region *find_region_intersection(unsigned long start,
+					unsigned long end)
+{
+
+	struct ocmem_region *region = NULL;
+	region = find_region(start);
+	if (region && end <= region->r_start)
+		region = NULL;
+	return region;
+}
+
+static struct ocmem_region *find_region_match(unsigned long start,
+					unsigned long end)
+{
+
+	struct ocmem_region *region = NULL;
+	region = find_region(start);
+	if (region && start == region->r_start && end == region->r_end)
+		return region;
+	return NULL;
+}
+
+static struct ocmem_req *find_req_match(int owner, struct ocmem_region *region)
+{
+	struct ocmem_req *req = NULL;
+
+	if (!region)
+		return NULL;
+
+	req = idr_find(&region->region_idr, owner);
+
+	return req;
+}
+
+/* Must be called with req->sem held */
+static inline int is_mapped(struct ocmem_req *req)
+{
+	return TEST_STATE(req, R_MAPPED);
+}
+
+/* Must be called with sched_mutex held */
+static int __sched_unmap(struct ocmem_req *req)
+{
+	struct ocmem_req *matched_req = NULL;
+	struct ocmem_region *matched_region = NULL;
+
+	matched_region = find_region_match(req->req_start, req->req_end);
+	matched_req = find_req_match(req->req_id, matched_region);
+
+	if (!matched_region || !matched_req) {
+		pr_err("Could not find backing region for req");
+		goto invalid_op_error;
+	}
+
+	if (matched_req != req) {
+		pr_err("Request does not match backing req");
+		goto invalid_op_error;
+	}
+
+	if (!is_mapped(req)) {
+		pr_err("Request is not currently mapped");
+		goto invalid_op_error;
+	}
+
+	/* Update the request state */
+	CLEAR_STATE(req, R_MAPPED);
+	SET_STATE(req, R_MUST_MAP);
+
+	return OP_COMPLETE;
+
+invalid_op_error:
+	return OP_FAIL;
+}
+
+/* Must be called with sched_mutex held */
+static int __sched_map(struct ocmem_req *req)
+{
+	struct ocmem_req *matched_req = NULL;
+	struct ocmem_region *matched_region = NULL;
+
+	matched_region = find_region_match(req->req_start, req->req_end);
+	matched_req = find_req_match(req->req_id, matched_region);
+
+	if (!matched_region || !matched_req) {
+		pr_err("Could not find backing region for req");
+		goto invalid_op_error;
+	}
+
+	if (matched_req != req) {
+		pr_err("Request does not match backing req");
+		goto invalid_op_error;
+	}
+
+	/* Update the request state */
+	CLEAR_STATE(req, R_MUST_MAP);
+	SET_STATE(req, R_MAPPED);
+
+	return OP_COMPLETE;
+
+invalid_op_error:
+	return OP_FAIL;
+}
+
+static int do_map(struct ocmem_req *req)
+{
+	int rc = 0;
+
+	mutex_lock(&sched_mutex);
+	rc = __sched_map(req);
+	mutex_unlock(&sched_mutex);
+
+	if (rc == OP_FAIL)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int do_unmap(struct ocmem_req *req)
+{
+	int rc = 0;
+
+	mutex_lock(&sched_mutex);
+	rc = __sched_unmap(req);
+	mutex_unlock(&sched_mutex);
+
+	if (rc == OP_FAIL)
+		return -EINVAL;
+
+	return 0;
+}
+
+/* process map is a wrapper where power control will be added later */
+static int process_map(struct ocmem_req *req, unsigned long start,
+				unsigned long end)
+{
+	return do_map(req);
+}
+
+/* process unmap is a wrapper where power control will be added later */
+static int process_unmap(struct ocmem_req *req, unsigned long start,
+				unsigned long end)
+{
+	return do_unmap(req);
+}
+
+static int __sched_grow(struct ocmem_req *req, bool can_block)
+{
+	unsigned long min = req->req_min;
+	unsigned long max = req->req_max;
+	unsigned long step = req->req_step;
+	int owner = req->owner;
+	unsigned long curr_sz = 0;
+	unsigned long growth_sz = 0;
+	unsigned long curr_start = 0;
+	enum client_prio prio = req->prio;
+	unsigned long alloc_addr = 0x0;
+	bool retry;
+	struct ocmem_region *spanned_r = NULL;
+	struct ocmem_region *overlap_r = NULL;
+
+	struct ocmem_req *matched_req = NULL;
+	struct ocmem_region *matched_region = NULL;
+
+	struct ocmem_zone *zone = get_zone(owner);
+	struct ocmem_region *region = NULL;
+
+	matched_region = find_region_match(req->req_start, req->req_end);
+	matched_req = find_req_match(req->req_id, matched_region);
+
+	if (!matched_region || !matched_req) {
+		pr_err("Could not find backing region for req");
+		goto invalid_op_error;
+	}
+
+	if (matched_req != req) {
+		pr_err("Request does not match backing req");
+		goto invalid_op_error;
+	}
+
+	curr_sz = matched_req->req_sz;
+	curr_start = matched_req->req_start;
+	growth_sz = matched_req->req_max - matched_req->req_sz;
+
+	pr_debug("Attempting to grow req %p from %lx to %lx\n",
+			req, matched_req->req_sz, matched_req->req_max);
+
+	retry = false;
+
+	pr_debug("ocmem: GROW: growth size %lx\n", growth_sz);
+
+retry_next_step:
+
+	spanned_r = NULL;
+	overlap_r = NULL;
+
+	spanned_r = find_region(zone->z_head);
+	overlap_r = find_region_intersection(zone->z_head,
+				zone->z_head + growth_sz);
+
+	if (overlap_r == NULL) {
+		/* no conflicting regions, schedule this region */
+		zone->z_ops->free(zone, curr_start, curr_sz);
+		alloc_addr = zone->z_ops->allocate(zone, curr_sz + growth_sz);
+
+		if (alloc_addr < 0) {
+			pr_err("ocmem: zone allocation operation failed\n");
+			goto internal_error;
+		}
+
+		curr_sz += growth_sz;
+		/* Detach the region from the interval tree */
+		/* This is to guarantee that any change in size
+		 * causes the tree to be rebalanced if required */
+
+		detach_req(matched_region, req);
+		if (req_count(matched_region) == 0) {
+			remove_region(matched_region);
+			region = matched_region;
+		} else {
+			region = create_region();
+			if (!region) {
+				pr_err("ocmem: Unable to create region\n");
+				goto region_error;
+			}
+		}
+
+		/* update the request */
+		req->req_start = alloc_addr;
+		/* increment the size to reflect new length */
+		req->req_sz = curr_sz;
+		req->req_end = alloc_addr + req->req_sz - 1;
+
+		/* update request state */
+		CLEAR_STATE(req, R_MUST_GROW);
+		SET_STATE(req, R_ALLOCATED);
+		SET_STATE(req, R_MUST_MAP);
+		req->op = SCHED_MAP;
+
+		/* update the region with new req */
+		attach_req(region, req);
+		populate_region(region, req);
+		update_region_prio(region);
+
+		/* update the tree with new region */
+		if (insert_region(region)) {
+			pr_err("ocmem: Failed to insert the region\n");
+			goto region_error;
+		}
+
+		if (retry) {
+			SET_STATE(req, R_MUST_GROW);
+			SET_STATE(req, R_PENDING);
+			req->op = SCHED_GROW;
+			return OP_PARTIAL;
+		}
+	} else if (spanned_r != NULL && overlap_r != NULL) {
+		/* resolve conflicting regions based on priority */
+		if (overlap_r->max_prio < prio) {
+			/* Growth cannot be triggered unless a previous
+			 * client of lower priority was evicted */
+			pr_err("ocmem: Invalid growth scheduled\n");
+			/* This is serious enough to fail */
+			BUG();
+			return OP_FAIL;
+		} else if (overlap_r->max_prio > prio) {
+			if (min == max) {
+				/* Cannot grow at this time, try later */
+				SET_STATE(req, R_PENDING);
+				SET_STATE(req, R_MUST_GROW);
+				return OP_RESCHED;
+			} else {
+			/* Try to grow in steps */
+				growth_sz -= step;
+				/* We are OOM at this point so need to retry */
+				if (growth_sz <= curr_sz) {
+					SET_STATE(req, R_PENDING);
+					SET_STATE(req, R_MUST_GROW);
+					return OP_RESCHED;
+				}
+				retry = true;
+				pr_debug("ocmem: Attempting with reduced size %lx\n",
+						growth_sz);
+				goto retry_next_step;
+			}
+		} else {
+			pr_err("ocmem: grow: New Region %p Existing %p\n",
+				matched_region, overlap_r);
+			pr_err("ocmem: Undetermined behavior\n");
+			/* This is serious enough to fail */
+			BUG();
+		}
+	} else if (spanned_r == NULL && overlap_r != NULL) {
+		goto err_not_supported;
+	}
+
+	return OP_COMPLETE;
+
+err_not_supported:
+	pr_err("ocmem: Scheduled unsupported operation\n");
+	return OP_FAIL;
+region_error:
+	zone->z_ops->free(zone, alloc_addr, curr_sz);
+	detach_req(region, req);
+	update_region_prio(region);
+	/* req is going to be destroyed by the caller anyways */
+internal_error:
+	destroy_region(region);
+invalid_op_error:
+	return OP_FAIL;
+}
+
+/* Must be called with sched_mutex held */
+static int __sched_free(struct ocmem_req *req)
+{
+	int owner = req->owner;
+	int ret = 0;
+
+	struct ocmem_req *matched_req = NULL;
+	struct ocmem_region *matched_region = NULL;
+
+	struct ocmem_zone *zone = get_zone(owner);
+
+	BUG_ON(!zone);
+
+	matched_region = find_region_match(req->req_start, req->req_end);
+	matched_req = find_req_match(req->req_id, matched_region);
+
+	if (!matched_region || !matched_req)
+		goto invalid_op_error;
+	if (matched_req != req)
+		goto invalid_op_error;
+
+	ret = zone->z_ops->free(zone,
+		matched_req->req_start, matched_req->req_sz);
+
+	if (ret < 0)
+		goto err_op_fail;
+
+	detach_req(matched_region, matched_req);
+	update_region_prio(matched_region);
+	if (req_count(matched_region) == 0) {
+		remove_region(matched_region);
+		destroy_region(matched_region);
+	}
+
+	/* Update the request */
+	req->req_start = 0x0;
+	req->req_sz = 0x0;
+	req->req_end = 0x0;
+	SET_STATE(req, R_FREE);
+	return OP_COMPLETE;
+invalid_op_error:
+	pr_err("ocmem: free: Failed to find matching region\n");
+err_op_fail:
+	pr_err("ocmem: free: Failed\n");
+	return OP_FAIL;
+}
+
+/* Must be called with sched_mutex held */
+static int __sched_allocate(struct ocmem_req *req, bool can_block,
+				bool can_wait)
+{
+	unsigned long min = req->req_min;
+	unsigned long max = req->req_max;
+	unsigned long step = req->req_step;
+	int owner = req->owner;
+	unsigned long sz = max;
+	enum client_prio prio = req->prio;
+	unsigned long alloc_addr = 0x0;
+	bool retry;
+
+	struct ocmem_region *spanned_r = NULL;
+	struct ocmem_region *overlap_r = NULL;
+
+	struct ocmem_zone *zone = get_zone(owner);
+	struct ocmem_region *region = NULL;
+
+	BUG_ON(!zone);
+
+	if (min > (zone->z_end - zone->z_start)) {
+		pr_err("ocmem: requested minimum size exceeds quota\n");
+		goto invalid_op_error;
+	}
+
+	if (max > (zone->z_end - zone->z_start)) {
+		pr_err("ocmem: requested maximum size exceeds quota\n");
+		goto invalid_op_error;
+	}
+
+	if (min > zone->z_free) {
+			pr_err("ocmem: out of memory for zone %d\n", owner);
+			goto invalid_op_error;
+	}
+
+	region = create_region();
+
+	if (!region) {
+		pr_err("ocmem: Unable to create region\n");
+		goto invalid_op_error;
+	}
+
+	retry = false;
+
+	pr_debug("ocmem: ALLOCATE: request size %lx\n", sz);
+
+retry_next_step:
+
+	spanned_r = NULL;
+	overlap_r = NULL;
+
+	spanned_r = find_region(zone->z_head);
+	overlap_r = find_region_intersection(zone->z_head, zone->z_head + sz);
+
+	if (overlap_r == NULL) {
+		/* no conflicting regions, schedule this region */
+		alloc_addr = zone->z_ops->allocate(zone, sz);
+
+		if (alloc_addr < 0) {
+			pr_err("Zone Allocation operation failed\n");
+			goto internal_error;
+		}
+
+		/* update the request */
+		req->req_start = alloc_addr;
+		req->req_end = alloc_addr + sz - 1;
+		req->req_sz = sz;
+		req->zone = zone;
+
+		/* update request state */
+		CLEAR_STATE(req, R_FREE);
+		SET_STATE(req, R_ALLOCATED);
+		SET_STATE(req, R_MUST_MAP);
+		req->op = SCHED_NOP;
+
+		/* attach the request to the region */
+		attach_req(region, req);
+		populate_region(region, req);
+		update_region_prio(region);
+
+		/* update the tree with new region */
+		if (insert_region(region)) {
+			pr_err("ocmem: Failed to insert the region\n");
+			zone->z_ops->free(zone, alloc_addr, sz);
+			detach_req(region, req);
+			update_region_prio(region);
+			/* req will be destroyed by the caller */
+			goto internal_error;
+		}
+
+		if (retry) {
+			SET_STATE(req, R_MUST_GROW);
+			SET_STATE(req, R_PENDING);
+			req->op = SCHED_GROW;
+			return OP_PARTIAL;
+		}
+	} else if (spanned_r != NULL && overlap_r != NULL) {
+		/* resolve conflicting regions based on priority */
+		if (overlap_r->max_prio < prio) {
+			if (min == max) {
+				pr_err("ocmem: Requires eviction support\n");
+				goto err_not_supported;
+			} else {
+			/* Try to allocate atleast >= 'min' immediately */
+				sz -= step;
+				if (sz < min)
+					goto err_out_of_mem;
+				retry = true;
+				pr_debug("ocmem: Attempting with reduced size %lx\n",
+						sz);
+				goto retry_next_step;
+			}
+		} else if (overlap_r->max_prio > prio) {
+			if (can_block == true) {
+				SET_STATE(req, R_PENDING);
+				SET_STATE(req, R_MUST_GROW);
+				return OP_RESCHED;
+			} else {
+				if (min == max) {
+					pr_err("Cannot allocate %lx synchronously\n",
+							sz);
+					goto err_out_of_mem;
+				} else {
+					sz -= step;
+					if (sz < min)
+						goto err_out_of_mem;
+					retry = true;
+					pr_debug("ocmem: Attempting reduced size %lx\n",
+							sz);
+					goto retry_next_step;
+				}
+			}
+		} else {
+			pr_err("ocmem: Undetermined behavior\n");
+			pr_err("ocmem: New Region %p Existing %p\n", region,
+					overlap_r);
+			/* This is serious enough to fail */
+			BUG();
+		}
+	} else if (spanned_r == NULL && overlap_r != NULL)
+		goto err_not_supported;
+
+	return OP_COMPLETE;
+
+err_not_supported:
+	pr_err("ocmem: Scheduled unsupported operation\n");
+	return OP_FAIL;
+
+err_out_of_mem:
+	pr_err("ocmem: Out of memory during allocation\n");
+internal_error:
+	destroy_region(region);
+invalid_op_error:
+	return OP_FAIL;
+}
+
+static int sched_enqueue(struct ocmem_req *priv)
+{
+	struct ocmem_req *next = NULL;
+	mutex_lock(&sched_queue_mutex);
+	list_add_tail(&priv->sched_list, &sched_queue[priv->owner]);
+	pr_debug("enqueued req %p\n", priv);
+	list_for_each_entry(next, &sched_queue[priv->owner], sched_list) {
+		pr_debug("pending requests for client %p\n", next);
+	}
+	mutex_unlock(&sched_queue_mutex);
+	return 0;
+}
+
+static struct ocmem_req *ocmem_fetch_req(void)
+{
+	int i;
+	struct ocmem_req *req = NULL;
+	struct ocmem_req *next = NULL;
+
+	mutex_lock(&sched_queue_mutex);
+	for (i = MIN_PRIO; i < MAX_OCMEM_PRIO; i++) {
+		if (list_empty(&sched_queue[i]))
+			continue;
+		list_for_each_entry_safe(req, next, &sched_queue[i], sched_list)
+		{
+			if (req) {
+				pr_debug("ocmem: Fetched pending request %p\n",
+									req);
+				list_del(&req->sched_list);
+			break;
+			}
+		}
+	}
+	mutex_unlock(&sched_queue_mutex);
+	return req;
+}
+
+int process_xfer(int id, struct ocmem_handle *handle,
+		struct ocmem_map_list *list, int direction)
+{
+
+	return 0;
+}
+
+unsigned long process_quota(int id)
+{
+	struct ocmem_zone *zone = NULL;
+
+	if (is_blocked(id))
+		return 0;
+
+	zone = get_zone(id);
+
+	if (zone && zone->z_pool)
+		return zone->z_end - zone->z_start;
+	else
+		return 0;
+}
+
+static int do_grow(struct ocmem_req *req)
+{
+	struct ocmem_buf *buffer = NULL;
+	bool can_block = true;
+	int rc = 0;
+
+	down_write(&req->rw_sem);
+	buffer = req->buffer;
+
+	/* Take the scheduler mutex */
+	mutex_lock(&sched_mutex);
+	rc = __sched_grow(req, can_block);
+	mutex_unlock(&sched_mutex);
+
+	if (rc == OP_FAIL)
+		goto err_op_fail;
+
+	if (rc == OP_RESCHED) {
+		pr_debug("ocmem: Enqueue this allocation");
+		sched_enqueue(req);
+	}
+
+	else if (rc == OP_COMPLETE || rc == OP_PARTIAL) {
+		buffer->addr = device_address(req->owner, req->req_start);
+		buffer->len = req->req_sz;
+	}
+
+	up_write(&req->rw_sem);
+	return 0;
+err_op_fail:
+	up_write(&req->rw_sem);
+	return -EINVAL;
+}
+
+static int process_grow(struct ocmem_req *req)
+{
+	int rc = 0;
+
+	/* Attempt to grow the region */
+	rc = do_grow(req);
+
+	if (rc < 0)
+		return -EINVAL;
+
+	/* Map the newly grown region */
+	if (is_tcm(req->owner)) {
+		rc = process_map(req, req->req_start, req->req_end);
+		if (rc < 0)
+			return -EINVAL;
+	}
+
+	/* Notify the client about the buffer growth */
+	rc = dispatch_notification(req->owner, OCMEM_ALLOC_GROW, req->buffer);
+	if (rc < 0) {
+		pr_err("No notifier callback to cater for req %p event: %d\n",
+				req, OCMEM_ALLOC_GROW);
+		BUG();
+	}
+	return 0;
+}
+
+static void ocmem_sched_wk_func(struct work_struct *work);
+DECLARE_DELAYED_WORK(ocmem_sched_thread, ocmem_sched_wk_func);
+
+static int ocmem_schedule_pending(void)
+{
+	schedule_delayed_work(&ocmem_sched_thread,
+				msecs_to_jiffies(SCHED_DELAY));
+	return 0;
+}
+
+static int do_free(struct ocmem_req *req)
+{
+	int rc = 0;
+	struct ocmem_buf *buffer = req->buffer;
+
+	down_write(&req->rw_sem);
+
+	if (is_mapped(req)) {
+		pr_err("ocmem: Buffer needs to be unmapped before free\n");
+		goto err_free_fail;
+	}
+
+	/* Grab the sched mutex */
+	mutex_lock(&sched_mutex);
+	rc = __sched_free(req);
+	mutex_unlock(&sched_mutex);
+
+	switch (rc) {
+
+	case OP_COMPLETE:
+		buffer->addr = 0x0;
+		buffer->len = 0x0;
+		break;
+	case OP_FAIL:
+	default:
+		goto err_free_fail;
+		break;
+	}
+
+	up_write(&req->rw_sem);
+	return 0;
+err_free_fail:
+	up_write(&req->rw_sem);
+	pr_err("ocmem: freeing req %p failed\n", req);
+	return -EINVAL;
+}
+
+int process_free(int id, struct ocmem_handle *handle)
+{
+	struct ocmem_req *req = NULL;
+	struct ocmem_buf *buffer = NULL;
+	int rc = 0;
+
+	if (is_blocked(id)) {
+		pr_err("Client %d cannot request free\n", id);
+		return -EINVAL;
+	}
+
+	req = handle_to_req(handle);
+	buffer = handle_to_buffer(handle);
+
+	if (!req)
+		return -EINVAL;
+
+	if (req->req_start != core_address(id, buffer->addr)) {
+		pr_err("Invalid buffer handle passed for free\n");
+		return -EINVAL;
+	}
+
+	if (is_tcm(req->owner)) {
+		rc = process_unmap(req, req->req_start, req->req_end);
+		if (rc < 0)
+			return -EINVAL;
+	}
+
+	rc = do_free(req);
+
+	if (rc < 0)
+		return -EINVAL;
+
+	ocmem_destroy_req(req);
+	handle->req = NULL;
+
+	ocmem_schedule_pending();
+	return 0;
+}
+
+static int do_allocate(struct ocmem_req *req, bool can_block, bool can_wait)
+{
+	int rc = 0;
+	struct ocmem_buf *buffer = req->buffer;
+
+	down_write(&req->rw_sem);
+
+	/* Take the scheduler mutex */
+	mutex_lock(&sched_mutex);
+	rc = __sched_allocate(req, can_block, can_wait);
+	mutex_unlock(&sched_mutex);
+
+	if (rc == OP_FAIL)
+		goto err_allocate_fail;
+
+	if (rc == OP_RESCHED) {
+		buffer->addr = 0x0;
+		buffer->len = 0x0;
+		pr_debug("ocmem: Enqueuing req %p\n", req);
+		sched_enqueue(req);
+	} else if (rc == OP_PARTIAL) {
+		buffer->addr = device_address(req->owner, req->req_start);
+		buffer->len = req->req_sz;
+		pr_debug("ocmem: Enqueuing req %p\n", req);
+		sched_enqueue(req);
+	} else if (rc == OP_COMPLETE) {
+		buffer->addr = device_address(req->owner, req->req_start);
+		buffer->len = req->req_sz;
+	}
+
+	up_write(&req->rw_sem);
+	return 0;
+err_allocate_fail:
+	up_write(&req->rw_sem);
+	return -EINVAL;
+}
+
+
+int process_allocate(int id, struct ocmem_handle *handle,
+			unsigned long min, unsigned long max,
+			unsigned long step, bool can_block, bool can_wait)
+{
+
+	struct ocmem_req *req = NULL;
+	struct ocmem_buf *buffer = NULL;
+	int rc = 0;
+
+	/* sanity checks */
+	if (is_blocked(id)) {
+		pr_err("Client %d cannot request allocation\n", id);
+		return -EINVAL;
+	}
+
+	if (handle->req != NULL) {
+		pr_err("Invalid handle passed in\n");
+		return -EINVAL;
+	}
+
+	buffer = handle_to_buffer(handle);
+	BUG_ON(buffer == NULL);
+
+	/* prepare a request structure to represent this transaction */
+	req = ocmem_create_req();
+	if (!req)
+		return -ENOMEM;
+
+	req->owner = id;
+	req->req_min = min;
+	req->req_max = max;
+	req->req_step = step;
+	req->prio = ocmem_client_table[id].priority;
+	req->op = SCHED_ALLOCATE;
+	req->buffer = buffer;
+
+	rc = do_allocate(req, can_block, can_wait);
+
+	if (rc < 0)
+		goto do_allocate_error;
+
+	handle->req = req;
+
+	if (is_tcm(id)) {
+		rc = process_map(req, req->req_start, req->req_end);
+		if (rc < 0)
+			goto map_error;
+	}
+
+	return 0;
+
+map_error:
+	handle->req = NULL;
+	do_free(req);
+do_allocate_error:
+	ocmem_destroy_req(req);
+	return -EINVAL;
+}
+
+int process_delayed_allocate(struct ocmem_req *req)
+{
+
+	struct ocmem_handle *handle = NULL;
+	int rc = 0;
+	int id = req->owner;
+
+	handle = req_to_handle(req);
+	BUG_ON(handle == NULL);
+
+	rc = do_allocate(req, true, false);
+
+	if (rc < 0)
+		goto do_allocate_error;
+
+	if (is_tcm(id)) {
+		rc = process_map(req, req->req_start, req->req_end);
+		if (rc < 0)
+			goto map_error;
+	}
+
+	/* Notify the client about the buffer growth */
+	rc = dispatch_notification(id, OCMEM_ALLOC_GROW, req->buffer);
+	if (rc < 0) {
+		pr_err("No notifier callback to cater for req %p event: %d\n",
+				req, OCMEM_ALLOC_GROW);
+		BUG();
+	}
+	return 0;
+
+map_error:
+	handle->req = NULL;
+	do_free(req);
+do_allocate_error:
+	ocmem_destroy_req(req);
+	return -EINVAL;
+}
+
+static void ocmem_sched_wk_func(struct work_struct *work)
+{
+
+	struct ocmem_buf *buffer = NULL;
+	struct ocmem_handle *handle = NULL;
+	struct ocmem_req *req = ocmem_fetch_req();
+
+	if (!req) {
+		pr_debug("No Pending Requests found\n");
+		return;
+	}
+
+	pr_debug("ocmem: sched_wk pending req %p\n", req);
+	handle = req_to_handle(req);
+	buffer = handle_to_buffer(handle);
+	BUG_ON(req->op == SCHED_NOP);
+
+	switch (req->op) {
+	case SCHED_GROW:
+		process_grow(req);
+		break;
+	case SCHED_ALLOCATE:
+		process_delayed_allocate(req);
+		break;
+	default:
+		pr_err("ocmem: Unknown operation encountered\n");
+		break;
+	}
+	return;
+}
+
+int ocmem_sched_init(void)
+{
+	int i = 0;
+	sched_tree = RB_ROOT;
+	mutex_init(&sched_mutex);
+	mutex_init(&sched_queue_mutex);
+	for (i = MIN_PRIO; i < MAX_OCMEM_PRIO; i++)
+		INIT_LIST_HEAD(&sched_queue[i]);
+
+	return 0;
+}
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index b40c0c7..49e63aa 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -202,8 +202,6 @@
 	pen_release = cpu_logical_map(cpu);
 	__cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
 	outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
-	__asm__("sev");
-	mb();
 
 	/*
 	 * Send the secondary CPU a soft interrupt, thereby causing
diff --git a/arch/arm/mach-msm/pm-stats.c b/arch/arm/mach-msm/pm-stats.c
index 936820a..675febb 100644
--- a/arch/arm/mach-msm/pm-stats.c
+++ b/arch/arm/mach-msm/pm-stats.c
@@ -188,18 +188,19 @@
 	int ret;
 	unsigned long flags;
 	unsigned int cpu;
+	size_t len = strnlen(MSM_PM_STATS_RESET, sizeof(MSM_PM_STATS_RESET));
 
 	if (count < sizeof(MSM_PM_STATS_RESET)) {
 		ret = -EINVAL;
 		goto write_proc_failed;
 	}
 
-	if (copy_from_user(buf, buffer, sizeof(MSM_PM_STATS_RESET))) {
+	if (copy_from_user(buf, buffer, len)) {
 		ret = -EFAULT;
 		goto write_proc_failed;
 	}
 
-	if (memcmp(buf, MSM_PM_STATS_RESET, sizeof(MSM_PM_STATS_RESET))) {
+	if (strncmp(buf, MSM_PM_STATS_RESET, len)) {
 		ret = -EINVAL;
 		goto write_proc_failed;
 	}
diff --git a/arch/arm/mach-msm/qdsp6v2/Makefile b/arch/arm/mach-msm/qdsp6v2/Makefile
index cee8f04..2ea1bc9 100644
--- a/arch/arm/mach-msm/qdsp6v2/Makefile
+++ b/arch/arm/mach-msm/qdsp6v2/Makefile
@@ -1,4 +1,3 @@
-obj-y += rtac.o
 ifdef CONFIG_ARCH_MSM8X60
 obj-y += audio_dev_ctl.o
 obj-y += board-msm8x60-audio.o
@@ -13,10 +12,15 @@
 endif
 obj-$(CONFIG_MSM_QDSP6_APR) += apr.o apr_tal.o q6core.o dsp_debug.o
 obj-y += audio_acdb.o
-ifndef CONFIG_ARCH_MSM9615
-obj-y += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o audio_utils.o
-obj-y += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_utils_aio.o
-obj-$(CONFIG_MSM_QDSP6_CODECS) += q6audio_v1.o q6audio_v1_aio.o
-obj-$(CONFIG_MSM_ULTRASOUND) += ultrasound/
-obj-y += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
+ifdef CONFIG_ARCH_MSM9615
+obj-y += rtac.o
 endif
+obj-$(CONFIG_MSM_QDSP6_CODECS) += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o audio_utils.o
+obj-$(CONFIG_MSM_QDSP6_CODECS) += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_utils_aio.o
+obj-$(CONFIG_MSM_QDSP6_CODECS) += rtac.o q6audio_v1.o q6audio_v1_aio.o
+obj-$(CONFIG_MSM_QDSP6_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
+obj-$(CONFIG_MSM_QDSP6V2_CODECS) += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o audio_utils.o
+obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_utils_aio.o
+obj-$(CONFIG_MSM_QDSP6V2_CODECS) += rtac_v2.o q6audio_v2.o q6audio_v2_aio.o
+obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
+obj-$(CONFIG_MSM_ULTRASOUND) += ultrasound/
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_common.h b/arch/arm/mach-msm/qdsp6v2/q6audio_common.h
index e108de5..fc20847 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6audio_common.h
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_common.h
@@ -15,8 +15,13 @@
 #ifndef __Q6_AUDIO_COMMON_H__
 #define __Q6_AUDIO_COMMON_H__
 
+#ifdef CONFIG_ARCH_MSMCOPPER
+#include <sound/apr_audio-v2.h>
+#include <sound/q6asm-v2.h>
+#else
 #include <sound/apr_audio.h>
 #include <sound/q6asm.h>
+#endif
 
 void q6_audio_cb(uint32_t opcode, uint32_t token,
 		uint32_t *payload, void *priv);
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_v2.c b/arch/arm/mach-msm/qdsp6v2/q6audio_v2.c
new file mode 100644
index 0000000..0db1ef4
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_v2.c
@@ -0,0 +1,90 @@
+/* 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/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include "audio_utils.h"
+
+void q6asm_in_cb(uint32_t opcode, uint32_t token,
+		uint32_t *payload, void *priv)
+{
+	struct q6audio_in *audio = (struct q6audio_in *)priv;
+	unsigned long flags;
+
+	pr_debug("%s:session id %d: opcode[0x%x]\n", __func__,
+			audio->ac->session, opcode);
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	switch (opcode) {
+	case ASM_DATA_EVENT_READ_DONE_V2:
+		audio_in_get_dsp_frames(audio, token, payload);
+		break;
+	case ASM_DATA_EVENT_WRITE_DONE_V2:
+		atomic_inc(&audio->in_count);
+		wake_up(&audio->write_wait);
+		break;
+	case ASM_DATA_EVENT_RENDERED_EOS:
+		audio->eos_rsp = 1;
+		wake_up(&audio->read_wait);
+		break;
+	case ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2:
+		break;
+	case ASM_SESSION_EVENTX_OVERFLOW:
+		pr_err("%s:session id %d: ASM_SESSION_EVENT_TX_OVERFLOW\n",
+			__func__, audio->ac->session);
+		break;
+	default:
+		pr_debug("%s:session id %d: Ignore opcode[0x%x]\n", __func__,
+			audio->ac->session, opcode);
+		break;
+	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+void  audio_in_get_dsp_frames(void *priv,
+	uint32_t token,	uint32_t *payload)
+{
+	struct q6audio_in *audio = (struct q6audio_in *)priv;
+	uint32_t index;
+
+	index = token;
+	pr_debug("%s:session id %d: index=%d nr frames=%d offset[%d]\n",
+			__func__, audio->ac->session, token, payload[9],
+			payload[5]);
+	pr_debug("%s:session id %d: timemsw=%d lsw=%d\n", __func__,
+			audio->ac->session, payload[7], payload[6]);
+	pr_debug("%s:session id %d: uflags=0x%8x uid=0x%8x\n", __func__,
+			audio->ac->session, payload[8], payload[10]);
+	pr_debug("%s:session id %d: enc_framesotal_size=0x%8x\n", __func__,
+			audio->ac->session, payload[4]);
+
+	audio->out_frame_info[index][0] = payload[9];
+	audio->out_frame_info[index][1] = payload[5];
+
+	/* statistics of read */
+	atomic_add(payload[4], &audio->in_bytes);
+	atomic_add(payload[9], &audio->in_samples);
+
+	if (atomic_read(&audio->out_count) <= audio->str_cfg.buffer_count) {
+		atomic_inc(&audio->out_count);
+		wake_up(&audio->read_wait);
+	}
+}
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c b/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c
new file mode 100644
index 0000000..aab7b19
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c
@@ -0,0 +1,112 @@
+/* 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/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include "audio_utils_aio.h"
+
+void q6_audio_cb(uint32_t opcode, uint32_t token,
+		uint32_t *payload, void *priv)
+{
+	struct q6audio_aio *audio = (struct q6audio_aio *)priv;
+
+	pr_debug("%s:opcode = %x token = 0x%x\n", __func__, opcode, token);
+	switch (opcode) {
+	case ASM_DATA_EVENT_WRITE_DONE_V2:
+	case ASM_DATA_EVENT_READ_DONE_V2:
+	case ASM_DATA_EVENT_RENDERED_EOS:
+	case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
+	case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
+	case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
+	case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY:
+		audio_aio_cb(opcode, token, payload, audio);
+		break;
+	default:
+		pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
+		break;
+	}
+}
+
+void audio_aio_cb(uint32_t opcode, uint32_t token,
+		uint32_t *payload,  void *priv/*struct q6audio_aio *audio*/)
+{
+	struct q6audio_aio *audio = (struct q6audio_aio *)priv;
+	union msm_audio_event_payload e_payload;
+
+	switch (opcode) {
+	case ASM_DATA_EVENT_WRITE_DONE_V2:
+		pr_debug("%s[%p]:ASM_DATA_EVENT_WRITE_DONE token = 0x%x\n",
+			__func__, audio, token);
+		audio_aio_async_write_ack(audio, token, payload);
+		break;
+	case ASM_DATA_EVENT_READ_DONE_V2:
+		pr_debug("%s[%p]:ASM_DATA_EVENT_READ_DONE token = 0x%x\n",
+			__func__, audio, token);
+		audio_aio_async_read_ack(audio, token, payload);
+		break;
+	case ASM_DATA_EVENT_RENDERED_EOS:
+		/* EOS Handle */
+		pr_debug("%s[%p]:ASM_DATA_CMDRSP_EOS\n", __func__, audio);
+		if (audio->feedback) { /* Non-Tunnel mode */
+			audio->eos_rsp = 1;
+			/* propagate input EOS i/p buffer,
+			after receiving DSP acknowledgement */
+			if (audio->eos_flag &&
+				(audio->eos_write_payload.aio_buf.buf_addr)) {
+				audio_aio_post_event(audio,
+						AUDIO_EVENT_WRITE_DONE,
+						audio->eos_write_payload);
+				memset(&audio->eos_write_payload , 0,
+					sizeof(union msm_audio_event_payload));
+				audio->eos_flag = 0;
+			}
+		} else { /* Tunnel mode */
+			audio->eos_rsp = 1;
+			wake_up(&audio->write_wait);
+			wake_up(&audio->cmd_wait);
+		}
+		break;
+	case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
+	case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
+		pr_debug("%s[%p]:payload0[%x] payloa1d[%x]opcode= 0x%x\n",
+			__func__, audio, payload[0], payload[1], opcode);
+		break;
+	case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
+	case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY:
+
+		pr_debug("%s[%p]: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, payload[0]-sr = %d, payload[1]-chl = %d, payload[2] = %d, payload[3] = %d\n",
+					 __func__, audio, payload[0],
+					 payload[1], payload[2], payload[3]);
+
+		pr_debug("%s[%p]: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, sr(prev) = %d, chl(prev) = %d,",
+				__func__, audio, audio->pcm_cfg.sample_rate,
+				audio->pcm_cfg.channel_count);
+
+		audio->pcm_cfg.sample_rate = payload[0];
+		audio->pcm_cfg.channel_count = payload[1] & 0xFFFF;
+		e_payload.stream_info.chan_info = audio->pcm_cfg.channel_count;
+		e_payload.stream_info.sample_rate = audio->pcm_cfg.sample_rate;
+		audio_aio_post_event(audio, AUDIO_EVENT_STREAM_INFO, e_payload);
+		break;
+	default:
+		break;
+	}
+}
diff --git a/arch/arm/mach-msm/qdsp6v2/rtac.c b/arch/arm/mach-msm/qdsp6v2/rtac.c
index 4ce9b030..8808375 100644
--- a/arch/arm/mach-msm/qdsp6v2/rtac.c
+++ b/arch/arm/mach-msm/qdsp6v2/rtac.c
@@ -22,8 +22,8 @@
 #include <asm/atomic.h>
 #include <mach/qdsp6v2/audio_acdb.h>
 #include <mach/qdsp6v2/rtac.h>
-#include <sound/q6asm.h>
-#include <sound/q6adm.h>
+#include "q6audio_common.h"
+#include <sound/q6afe.h>
 
 #ifndef CONFIG_RTAC
 
@@ -400,10 +400,8 @@
 	memcpy(rtac_adm_buffer, &payload_size, sizeof(u32));
 	if (payload_size != 0) {
 		if (payload_size > rtac_adm_user_buf_size) {
-			pr_err("%s: Buffer set not big enough for "
-				"returned data, buf size = %d, "
-				"ret data = %d\n", __func__,
-				rtac_adm_user_buf_size, payload_size);
+			pr_err("%s: Buffer set not big enough for returned data, buf size = %d,ret data = %d\n",
+				__func__, rtac_adm_user_buf_size, payload_size);
 			goto done;
 		}
 		memcpy(rtac_adm_buffer + sizeof(u32), payload, payload_size);
@@ -414,20 +412,20 @@
 
 u32 send_adm_apr(void *buf, u32 opcode)
 {
-	s32				result;
-	u32				count = 0;
-	u32				bytes_returned = 0;
-	u32				port_index = 0;
-	u32				copp_id;
-	u32				payload_size;
-	struct apr_hdr			adm_params;
+	s32	result;
+	u32	count = 0;
+	u32	bytes_returned = 0;
+	u32	port_index = 0;
+	u32	copp_id;
+	u32	payload_size;
+	struct apr_hdr	adm_params;
 	pr_debug("%s\n", __func__);
 
 	if (copy_from_user(&count, (void *)buf, sizeof(count))) {
-			pr_err("%s: Copy to user failed! buf = 0x%x\n",
-			       __func__, (unsigned int)buf);
-			result = -EFAULT;
-			goto done;
+		pr_err("%s: Copy to user failed! buf = 0x%x\n",
+		       __func__, (unsigned int)buf);
+		result = -EFAULT;
+		goto done;
 	}
 
 	if (count <= 0) {
@@ -443,9 +441,8 @@
 
 
 	if (payload_size > MAX_PAYLOAD_SIZE) {
-
-			pr_err("%s: Invalid payload size = %d\n",
-				__func__, payload_size);
+		pr_err("%s: Invalid payload size = %d\n",
+			__func__, payload_size);
 		goto done;
 	}
 
@@ -521,9 +518,9 @@
 
 	if (rtac_adm_payload_size != 0) {
 		if (copy_to_user(buf, rtac_adm_buffer,
-				rtac_adm_payload_size + sizeof(u32))) {
-			pr_err("%s: Could not copy buffer to user,"
-				"size = %d\n", __func__, payload_size);
+			rtac_adm_payload_size + sizeof(u32))) {
+			pr_err("%s: Could not copy buffer to user, size = %d\n",
+				 __func__, payload_size);
 			goto done;
 		}
 	}
@@ -573,10 +570,8 @@
 	memcpy(rtac_asm_buffer, &payload_size, sizeof(u32));
 	if (payload_size) {
 		if (payload_size > rtac_asm_user_buf_size) {
-			pr_err("%s: Buffer set not big enough for "
-				"returned data, buf size = %d, "
-				"ret data = %d\n", __func__,
-				rtac_asm_user_buf_size, payload_size);
+			pr_err("%s: Buffer set not big enough for returned data, buf size = %d, ret data = %d\n",
+			 __func__, rtac_asm_user_buf_size, payload_size);
 			goto done;
 		}
 		memcpy(rtac_asm_buffer + sizeof(u32), payload, payload_size);
@@ -587,19 +582,19 @@
 
 u32 send_rtac_asm_apr(void *buf, u32 opcode)
 {
-	s32				result;
-	u32				count = 0;
-	u32				bytes_returned = 0;
-	u32				session_id = 0;
-	u32				payload_size;
-	struct apr_hdr			asm_params;
+	s32	result;
+	u32	count = 0;
+	u32	bytes_returned = 0;
+	u32	session_id = 0;
+	u32	payload_size;
+	struct apr_hdr	asm_params;
 	pr_debug("%s\n", __func__);
 
 	if (copy_from_user(&count, (void *)buf, sizeof(count))) {
-			pr_err("%s: Copy to user failed! buf = 0x%x\n",
-			       __func__, (unsigned int)buf);
-			result = -EFAULT;
-			goto done;
+		pr_err("%s: Copy to user failed! buf = 0x%x\n",
+		       __func__, (unsigned int)buf);
+		result = -EFAULT;
+		goto done;
 	}
 
 	if (count <= 0) {
@@ -614,9 +609,8 @@
 	}
 
 	if (payload_size > MAX_PAYLOAD_SIZE) {
-
-			pr_err("%s: Invalid payload size = %d\n",
-				__func__, payload_size);
+		pr_err("%s: Invalid payload size = %d\n",
+			__func__, payload_size);
 		goto done;
 	}
 
@@ -643,7 +637,7 @@
 
 	/* Copy buffer to in-band payload */
 	if (copy_from_user(rtac_asm_buffer + sizeof(asm_params),
-			buf + 3 * sizeof(u32), payload_size)) {
+		buf + 3 * sizeof(u32), payload_size)) {
 		pr_err("%s: Could not copy payload from user buffer\n",
 			__func__);
 		goto err;
@@ -691,9 +685,9 @@
 
 	if (rtac_asm_payload_size != 0) {
 		if (copy_to_user(buf, rtac_asm_buffer,
-				rtac_asm_payload_size + sizeof(u32))) {
-			pr_err("%s: Could not copy buffer to user,"
-				"size = %d\n", __func__, payload_size);
+			rtac_asm_payload_size + sizeof(u32))) {
+			pr_err("%s: Could not copy buffer to user,size = %d\n",
+				 __func__, payload_size);
 			goto done;
 		}
 	}
@@ -715,7 +709,6 @@
 void rtac_set_voice_handle(u32 mode, void *handle)
 {
 	pr_debug("%s\n", __func__);
-
 	mutex_lock(&rtac_voice_apr_mutex);
 	rtac_voice_apr_data[mode].apr_handle = handle;
 	mutex_unlock(&rtac_voice_apr_mutex);
@@ -724,7 +717,7 @@
 bool rtac_make_voice_callback(u32 mode, uint32_t *payload, u32 payload_size)
 {
 	if ((atomic_read(&rtac_voice_apr_data[mode].cmd_state) != 1) ||
-			(mode >= RTAC_VOICE_MODES))
+		(mode >= RTAC_VOICE_MODES))
 		return false;
 
 	pr_debug("%s\n", __func__);
@@ -743,10 +736,8 @@
 	memcpy(rtac_voice_buffer, &payload_size, sizeof(u32));
 	if (payload_size) {
 		if (payload_size > rtac_voice_user_buf_size) {
-			pr_err("%s: Buffer set not big enough for "
-				"returned data, buf size = %d, "
-				"ret data = %d\n", __func__,
-				rtac_voice_user_buf_size, payload_size);
+			pr_err("%s: Buffer set not big enough for returned data, buf size = %d, ret data = %d\n",
+			 __func__, rtac_voice_user_buf_size, payload_size);
 			goto done;
 		}
 		memcpy(rtac_voice_buffer + sizeof(u32), payload, payload_size);
@@ -757,19 +748,19 @@
 
 u32 send_voice_apr(u32 mode, void *buf, u32 opcode)
 {
-	s32				result;
-	u32				count = 0;
-	u32				bytes_returned = 0;
-	u32				payload_size;
-	u16				dest_port;
-	struct apr_hdr			voice_params;
+	s32	result;
+	u32	count = 0;
+	u32	bytes_returned = 0;
+	u32	payload_size;
+	u16	dest_port;
+	struct	apr_hdr	voice_params;
 	pr_debug("%s\n", __func__);
 
 	if (copy_from_user(&count, (void *)buf, sizeof(count))) {
-			pr_err("%s: Copy to user failed! buf = 0x%x\n",
-			       __func__, (unsigned int)buf);
-			result = -EFAULT;
-			goto done;
+		pr_err("%s: Copy to user failed! buf = 0x%x\n",
+		       __func__, (unsigned int)buf);
+		result = -EFAULT;
+		goto done;
 	}
 
 	if (count <= 0) {
@@ -785,7 +776,7 @@
 
 	if (payload_size > MAX_PAYLOAD_SIZE) {
 		pr_err("%s: Invalid payload size = %d\n",
-				__func__, payload_size);
+			__func__, payload_size);
 		goto done;
 	}
 
@@ -812,7 +803,7 @@
 
 	/* Copy buffer to in-band payload */
 	if (copy_from_user(rtac_voice_buffer + sizeof(voice_params),
-			buf + 3 * sizeof(u32), payload_size)) {
+		buf + 3 * sizeof(u32), payload_size)) {
 		pr_err("%s: Could not copy payload from user buffer\n",
 			__func__);
 		goto err;
@@ -860,8 +851,8 @@
 	if (rtac_voice_payload_size != 0) {
 		if (copy_to_user(buf, rtac_voice_buffer,
 				rtac_voice_payload_size + sizeof(u32))) {
-			pr_err("%s: Could not copy buffer to user,"
-				"size = %d\n", __func__, payload_size);
+			pr_err("%s: Could not copy buffer to user,size = %d\n",
+						 __func__, payload_size);
 			goto done;
 		}
 	}
@@ -972,7 +963,7 @@
 	mutex_init(&rtac_adm_mutex);
 	mutex_init(&rtac_adm_apr_mutex);
 
-	rtac_adm_buffer = kmalloc(RTAC_BUF_SIZE, GFP_KERNEL);
+	rtac_adm_buffer = kzalloc(RTAC_BUF_SIZE, GFP_KERNEL);
 	if (rtac_adm_buffer == NULL) {
 		pr_err("%s: Could not allocate payload of size = %d\n",
 			__func__, RTAC_BUF_SIZE);
@@ -987,10 +978,11 @@
 	}
 	mutex_init(&rtac_asm_apr_mutex);
 
-	rtac_asm_buffer = kmalloc(RTAC_BUF_SIZE, GFP_KERNEL);
+	rtac_asm_buffer = kzalloc(RTAC_BUF_SIZE, GFP_KERNEL);
 	if (rtac_asm_buffer == NULL) {
 		pr_err("%s: Could not allocate payload of size = %d\n",
 			__func__, RTAC_BUF_SIZE);
+		kzfree(rtac_adm_buffer);
 		goto nomem;
 	}
 
@@ -1004,10 +996,12 @@
 	mutex_init(&rtac_voice_mutex);
 	mutex_init(&rtac_voice_apr_mutex);
 
-	rtac_voice_buffer = kmalloc(RTAC_BUF_SIZE, GFP_KERNEL);
+	rtac_voice_buffer = kzalloc(RTAC_BUF_SIZE, GFP_KERNEL);
 	if (rtac_voice_buffer == NULL) {
 		pr_err("%s: Could not allocate payload of size = %d\n",
 			__func__, RTAC_BUF_SIZE);
+		kzfree(rtac_adm_buffer);
+		kzfree(rtac_asm_buffer);
 		goto nomem;
 	}
 
diff --git a/arch/arm/mach-msm/qdsp6v2/rtac_v2.c b/arch/arm/mach-msm/qdsp6v2/rtac_v2.c
new file mode 100644
index 0000000..2d0607c
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/rtac_v2.c
@@ -0,0 +1,1019 @@
+/* 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/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/msm_audio_acdb.h>
+#include <asm/atomic.h>
+#include <mach/qdsp6v2/audio_acdb.h>
+#include <mach/qdsp6v2/rtac.h>
+#include "q6audio_common.h"
+#include <sound/q6afe-v2.h>
+
+#ifndef CONFIG_RTAC
+
+void rtac_add_adm_device(u32 port_id, u32 copp_id, u32 path_id, u32 popp_id) {}
+void rtac_remove_adm_device(u32 port_id) {}
+void rtac_remove_popp_from_adm_devices(u32 popp_id) {}
+void rtac_set_adm_handle(void *handle) {}
+bool rtac_make_adm_callback(uint32_t *payload, u32 payload_size)
+	{return false; }
+void rtac_set_asm_handle(u32 session_id, void *handle) {}
+bool rtac_make_asm_callback(u32 session_id, uint32_t *payload,
+	u32 payload_size) {return false; }
+void rtac_add_voice(u32 cvs_handle, u32 cvp_handle, u32 rx_afe_port,
+	u32 tx_afe_port, u32 session_id) {}
+void rtac_remove_voice(u32 cvs_handle) {}
+void rtac_set_voice_handle(u32 mode, void *handle) {}
+bool rtac_make_voice_callback(u32 mode, uint32_t *payload,
+		u32 payload_size) {return false; }
+
+#else
+
+#define VOICE_CMD_SET_PARAM		0x00011006
+#define VOICE_CMD_GET_PARAM		0x00011007
+#define VOICE_EVT_GET_PARAM_ACK		0x00011008
+
+/* Max size of payload (buf size - apr header) */
+#define MAX_PAYLOAD_SIZE		4076
+#define RTAC_MAX_ACTIVE_DEVICES		4
+#define RTAC_MAX_ACTIVE_VOICE_COMBOS	2
+#define RTAC_MAX_ACTIVE_POPP		8
+#define RTAC_BUF_SIZE			4096
+
+#define TIMEOUT_MS	1000
+
+/* APR data */
+struct rtac_apr_data {
+	void			*apr_handle;
+	atomic_t		cmd_state;
+	wait_queue_head_t	cmd_wait;
+};
+
+static struct rtac_apr_data	rtac_adm_apr_data;
+static struct rtac_apr_data	rtac_asm_apr_data[SESSION_MAX+1];
+static struct rtac_apr_data	rtac_voice_apr_data[RTAC_VOICE_MODES];
+
+
+/* ADM info & APR */
+struct rtac_adm_data {
+	uint32_t	topology_id;
+	uint32_t	afe_port;
+	uint32_t	copp;
+	uint32_t	num_of_popp;
+	uint32_t	popp[RTAC_MAX_ACTIVE_POPP];
+};
+
+struct rtac_adm {
+	uint32_t		num_of_dev;
+	struct rtac_adm_data	device[RTAC_MAX_ACTIVE_DEVICES];
+};
+static struct rtac_adm		rtac_adm_data;
+static u32			rtac_adm_payload_size;
+static u32			rtac_adm_user_buf_size;
+static u8			*rtac_adm_buffer;
+
+
+/* ASM APR */
+static u32			rtac_asm_payload_size;
+static u32			rtac_asm_user_buf_size;
+static u8			*rtac_asm_buffer;
+
+
+/* Voice info & APR */
+struct rtac_voice_data {
+	uint32_t	tx_topology_id;
+	uint32_t	rx_topology_id;
+	uint32_t	tx_afe_port;
+	uint32_t	rx_afe_port;
+	uint16_t	cvs_handle;
+	uint16_t	cvp_handle;
+};
+
+struct rtac_voice {
+	uint32_t		num_of_voice_combos;
+	struct rtac_voice_data	voice[RTAC_MAX_ACTIVE_VOICE_COMBOS];
+};
+
+static struct rtac_voice	rtac_voice_data;
+static u32			rtac_voice_payload_size;
+static u32			rtac_voice_user_buf_size;
+static u8			*rtac_voice_buffer;
+static u32			voice_session_id[RTAC_MAX_ACTIVE_VOICE_COMBOS];
+
+
+struct mutex			rtac_adm_mutex;
+struct mutex			rtac_adm_apr_mutex;
+struct mutex			rtac_asm_apr_mutex;
+struct mutex			rtac_voice_mutex;
+struct mutex			rtac_voice_apr_mutex;
+
+static int rtac_open(struct inode *inode, struct file *f)
+{
+	pr_debug("%s\n", __func__);
+	return 0;
+}
+
+static int rtac_release(struct inode *inode, struct file *f)
+{
+	pr_debug("%s\n", __func__);
+	return 0;
+}
+
+/* ADM Info */
+void add_popp(u32 dev_idx, u32 port_id, u32 popp_id)
+{
+	u32 i = 0;
+
+	for (; i < rtac_adm_data.device[dev_idx].num_of_popp; i++)
+		if (rtac_adm_data.device[dev_idx].popp[i] == popp_id)
+			goto done;
+
+	if (rtac_adm_data.device[dev_idx].num_of_popp ==
+			RTAC_MAX_ACTIVE_POPP) {
+		pr_err("%s, Max POPP!\n", __func__);
+		goto done;
+	}
+	rtac_adm_data.device[dev_idx].popp[
+		rtac_adm_data.device[dev_idx].num_of_popp++] = popp_id;
+done:
+	return;
+}
+
+void rtac_add_adm_device(u32 port_id, u32 copp_id, u32 path_id, u32 popp_id)
+{
+	u32 i = 0;
+	pr_debug("%s: port_id = %d, popp_id = %d\n", __func__, port_id,
+		popp_id);
+
+	mutex_lock(&rtac_adm_mutex);
+	if (rtac_adm_data.num_of_dev == RTAC_MAX_ACTIVE_DEVICES) {
+		pr_err("%s, Can't add anymore RTAC devices!\n", __func__);
+		goto done;
+	}
+
+	/* Check if device already added */
+	if (rtac_adm_data.num_of_dev != 0) {
+		for (; i < rtac_adm_data.num_of_dev; i++) {
+			if (rtac_adm_data.device[i].afe_port == port_id) {
+				add_popp(i, port_id, popp_id);
+				goto done;
+			}
+			if (rtac_adm_data.device[i].num_of_popp ==
+						RTAC_MAX_ACTIVE_POPP) {
+				pr_err("%s, Max POPP!\n", __func__);
+				goto done;
+			}
+		}
+	}
+
+	/* Add device */
+	rtac_adm_data.num_of_dev++;
+
+	if (path_id == ADM_PATH_PLAYBACK)
+		rtac_adm_data.device[i].topology_id =
+						get_adm_rx_topology();
+	else
+		rtac_adm_data.device[i].topology_id =
+						get_adm_tx_topology();
+	rtac_adm_data.device[i].afe_port = port_id;
+	rtac_adm_data.device[i].copp = copp_id;
+	rtac_adm_data.device[i].popp[
+		rtac_adm_data.device[i].num_of_popp++] = popp_id;
+done:
+	mutex_unlock(&rtac_adm_mutex);
+	return;
+}
+
+static void shift_adm_devices(u32 dev_idx)
+{
+	for (; dev_idx < rtac_adm_data.num_of_dev; dev_idx++) {
+		memcpy(&rtac_adm_data.device[dev_idx],
+			&rtac_adm_data.device[dev_idx + 1],
+			sizeof(rtac_adm_data.device[dev_idx]));
+		memset(&rtac_adm_data.device[dev_idx + 1], 0,
+			   sizeof(rtac_adm_data.device[dev_idx]));
+	}
+}
+
+static void shift_popp(u32 copp_idx, u32 popp_idx)
+{
+	for (; popp_idx < rtac_adm_data.device[copp_idx].num_of_popp;
+							popp_idx++) {
+		memcpy(&rtac_adm_data.device[copp_idx].popp[popp_idx],
+			&rtac_adm_data.device[copp_idx].popp[popp_idx + 1],
+			sizeof(uint32_t));
+		memset(&rtac_adm_data.device[copp_idx].popp[popp_idx + 1], 0,
+			   sizeof(uint32_t));
+	}
+}
+
+void rtac_remove_adm_device(u32 port_id)
+{
+	s32 i;
+	pr_debug("%s: port_id = %d\n", __func__, port_id);
+
+	mutex_lock(&rtac_adm_mutex);
+	/* look for device */
+	for (i = 0; i < rtac_adm_data.num_of_dev; i++) {
+		if (rtac_adm_data.device[i].afe_port == port_id) {
+			memset(&rtac_adm_data.device[i], 0,
+				   sizeof(rtac_adm_data.device[i]));
+			rtac_adm_data.num_of_dev--;
+
+			if (rtac_adm_data.num_of_dev >= 1) {
+				shift_adm_devices(i);
+				break;
+			}
+		}
+	}
+
+	mutex_unlock(&rtac_adm_mutex);
+	return;
+}
+
+void rtac_remove_popp_from_adm_devices(u32 popp_id)
+{
+	s32 i, j;
+	pr_debug("%s: popp_id = %d\n", __func__, popp_id);
+
+	mutex_lock(&rtac_adm_mutex);
+
+	for (i = 0; i < rtac_adm_data.num_of_dev; i++) {
+		for (j = 0; j < rtac_adm_data.device[i].num_of_popp; j++) {
+			if (rtac_adm_data.device[i].popp[j] == popp_id) {
+				rtac_adm_data.device[i].popp[j] = 0;
+				rtac_adm_data.device[i].num_of_popp--;
+				shift_popp(i, j);
+			}
+		}
+	}
+
+	mutex_unlock(&rtac_adm_mutex);
+}
+
+/* Voice Info */
+static void set_rtac_voice_data(int idx, u32 cvs_handle, u32 cvp_handle,
+					u32 rx_afe_port, u32 tx_afe_port,
+					u32 session_id)
+{
+	rtac_voice_data.voice[idx].tx_topology_id = get_voice_tx_topology();
+	rtac_voice_data.voice[idx].rx_topology_id = get_voice_rx_topology();
+	rtac_voice_data.voice[idx].tx_afe_port = tx_afe_port;
+	rtac_voice_data.voice[idx].rx_afe_port = rx_afe_port;
+	rtac_voice_data.voice[idx].cvs_handle = cvs_handle;
+	rtac_voice_data.voice[idx].cvp_handle = cvp_handle;
+
+	/* Store session ID for voice RTAC */
+	voice_session_id[idx] = session_id;
+}
+
+void rtac_add_voice(u32 cvs_handle, u32 cvp_handle, u32 rx_afe_port,
+			u32 tx_afe_port, u32 session_id)
+{
+	u32 i = 0;
+	pr_debug("%s\n", __func__);
+	mutex_lock(&rtac_voice_mutex);
+
+	if (rtac_voice_data.num_of_voice_combos ==
+			RTAC_MAX_ACTIVE_VOICE_COMBOS) {
+		pr_err("%s, Can't add anymore RTAC devices!\n", __func__);
+		goto done;
+	}
+
+	/* Check if device already added */
+	if (rtac_voice_data.num_of_voice_combos != 0) {
+		for (; i < rtac_voice_data.num_of_voice_combos; i++) {
+			if (rtac_voice_data.voice[i].cvs_handle ==
+							cvs_handle) {
+				set_rtac_voice_data(i, cvs_handle, cvp_handle,
+					rx_afe_port, tx_afe_port,
+					session_id);
+				goto done;
+			}
+		}
+	}
+
+	/* Add device */
+	rtac_voice_data.num_of_voice_combos++;
+	set_rtac_voice_data(i, cvs_handle, cvp_handle,
+				rx_afe_port, tx_afe_port,
+				session_id);
+done:
+	mutex_unlock(&rtac_voice_mutex);
+	return;
+}
+
+static void shift_voice_devices(u32 idx)
+{
+	for (; idx < rtac_voice_data.num_of_voice_combos - 1; idx++) {
+		memcpy(&rtac_voice_data.voice[idx],
+			&rtac_voice_data.voice[idx + 1],
+			sizeof(rtac_voice_data.voice[idx]));
+		voice_session_id[idx] = voice_session_id[idx + 1];
+	}
+}
+
+void rtac_remove_voice(u32 cvs_handle)
+{
+	u32 i = 0;
+	pr_debug("%s\n", __func__);
+
+	mutex_lock(&rtac_voice_mutex);
+	/* look for device */
+	for (i = 0; i < rtac_voice_data.num_of_voice_combos; i++) {
+		if (rtac_voice_data.voice[i].cvs_handle == cvs_handle) {
+			shift_voice_devices(i);
+			rtac_voice_data.num_of_voice_combos--;
+			memset(&rtac_voice_data.voice[
+				rtac_voice_data.num_of_voice_combos], 0,
+				sizeof(rtac_voice_data.voice
+				[rtac_voice_data.num_of_voice_combos]));
+			voice_session_id[rtac_voice_data.num_of_voice_combos]
+				= 0;
+			break;
+		}
+	}
+	mutex_unlock(&rtac_voice_mutex);
+	return;
+}
+
+static int get_voice_index(u32 cvs_handle)
+{
+	u32 i;
+
+	for (i = 0; i < rtac_voice_data.num_of_voice_combos; i++) {
+		if (rtac_voice_data.voice[i].cvs_handle == cvs_handle)
+			return i;
+	}
+
+	pr_err("%s: No voice index for CVS handle %d found returning 0\n",
+	       __func__, cvs_handle);
+	return 0;
+}
+
+
+/* ADM APR */
+void rtac_set_adm_handle(void *handle)
+{
+	pr_debug("%s: handle = %d\n", __func__, (unsigned int)handle);
+
+	mutex_lock(&rtac_adm_apr_mutex);
+	rtac_adm_apr_data.apr_handle = handle;
+	mutex_unlock(&rtac_adm_apr_mutex);
+}
+
+bool rtac_make_adm_callback(uint32_t *payload, u32 payload_size)
+{
+	pr_debug("%s:cmd_state = %d\n", __func__,
+			atomic_read(&rtac_adm_apr_data.cmd_state));
+	if (atomic_read(&rtac_adm_apr_data.cmd_state) != 1)
+		return false;
+
+	/* Offset data for in-band payload */
+	rtac_copy_adm_payload_to_user(payload, payload_size);
+	atomic_set(&rtac_adm_apr_data.cmd_state, 0);
+	wake_up(&rtac_adm_apr_data.cmd_wait);
+	return true;
+}
+
+void rtac_copy_adm_payload_to_user(void *payload, u32 payload_size)
+{
+	pr_debug("%s\n", __func__);
+	rtac_adm_payload_size = payload_size;
+
+	memcpy(rtac_adm_buffer, &payload_size, sizeof(u32));
+	if (payload_size != 0) {
+		if (payload_size > rtac_adm_user_buf_size) {
+			pr_err("%s: Buffer set not big enough for returned data, buf size = %d, ret data = %d\n",
+			 __func__, rtac_adm_user_buf_size, payload_size);
+			goto done;
+		}
+		memcpy(rtac_adm_buffer + sizeof(u32), payload, payload_size);
+	}
+done:
+	return;
+}
+
+u32 send_adm_apr(void *buf, u32 opcode)
+{
+	s32	result;
+	u32	count = 0;
+	u32	bytes_returned = 0;
+	u32	port_index = 0;
+	u32	copp_id;
+	u32	payload_size;
+	struct apr_hdr	adm_params;
+	pr_debug("%s\n", __func__);
+
+	if (copy_from_user(&count, (void *)buf, sizeof(count))) {
+		pr_err("%s: Copy to user failed! buf = 0x%x\n",
+		       __func__, (unsigned int)buf);
+		result = -EFAULT;
+		goto done;
+	}
+
+	if (count <= 0) {
+		pr_err("%s: Invalid buffer size = %d\n", __func__, count);
+		goto done;
+	}
+
+	if (copy_from_user(&payload_size, buf + sizeof(u32), sizeof(u32))) {
+		pr_err("%s: Could not copy payload size from user buffer\n",
+			__func__);
+		goto done;
+	}
+
+
+	if (payload_size > MAX_PAYLOAD_SIZE) {
+		pr_err("%s: Invalid payload size = %d\n",
+			__func__, payload_size);
+		goto done;
+	}
+
+	if (copy_from_user(&copp_id, buf + 2 * sizeof(u32), sizeof(u32))) {
+		pr_err("%s: Could not copy port id from user buffer\n",
+			__func__);
+		goto done;
+	}
+
+	for (port_index = 0; port_index < AFE_MAX_PORTS; port_index++) {
+		if (adm_get_copp_id(port_index) == copp_id)
+			break;
+	}
+	if (port_index >= AFE_MAX_PORTS) {
+		pr_err("%s: Could not find port index for copp = %d\n",
+		       __func__, copp_id);
+		goto done;
+	}
+
+	mutex_lock(&rtac_adm_apr_mutex);
+	if (rtac_adm_apr_data.apr_handle == NULL) {
+		pr_err("%s: APR not initialized\n", __func__);
+		goto err;
+	}
+
+	/* Set globals for copy of returned payload */
+	rtac_adm_user_buf_size = count;
+	/* Copy buffer to in-band payload */
+	if (copy_from_user(rtac_adm_buffer + sizeof(adm_params),
+			buf + 3 * sizeof(u32), payload_size)) {
+		pr_err("%s: Could not copy payload from user buffer\n",
+			__func__);
+		goto err;
+	}
+
+	/* Pack header */
+	adm_params.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+		APR_HDR_LEN(20), APR_PKT_VER);
+	adm_params.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+		payload_size);
+	adm_params.src_svc = APR_SVC_ADM;
+	adm_params.src_domain = APR_DOMAIN_APPS;
+	adm_params.src_port = copp_id;
+	adm_params.dest_svc = APR_SVC_ADM;
+	adm_params.dest_domain = APR_DOMAIN_ADSP;
+	adm_params.dest_port = copp_id;
+	adm_params.token = copp_id;
+	adm_params.opcode = opcode;
+
+	memcpy(rtac_adm_buffer, &adm_params, sizeof(adm_params));
+	atomic_set(&rtac_adm_apr_data.cmd_state, 1);
+
+	pr_debug("%s: Sending RTAC command size = %d\n",
+		__func__, adm_params.pkt_size);
+
+	result = apr_send_pkt(rtac_adm_apr_data.apr_handle,
+		(uint32_t *)rtac_adm_buffer);
+	if (result < 0) {
+		pr_err("%s: Set params failed port = %d, copp = %d\n",
+			__func__, port_index, copp_id);
+		goto err;
+	}
+	/* Wait for the callback */
+	result = wait_event_timeout(rtac_adm_apr_data.cmd_wait,
+		(atomic_read(&rtac_adm_apr_data.cmd_state) == 0),
+		msecs_to_jiffies(TIMEOUT_MS));
+	mutex_unlock(&rtac_adm_apr_mutex);
+	if (!result) {
+		pr_err("%s: Set params timed out port = %d, copp = %d\n",
+			__func__, port_index, copp_id);
+		goto done;
+	}
+
+	if (rtac_adm_payload_size != 0) {
+		if (copy_to_user(buf, rtac_adm_buffer,
+			rtac_adm_payload_size + sizeof(u32))) {
+			pr_err("%s: Could not copy buffer to user,size = %d\n",
+				__func__, payload_size);
+			goto done;
+		}
+	}
+
+	/* Return data written for SET & data read for GET */
+	if (opcode == ADM_CMD_GET_PP_PARAMS_V5)
+		bytes_returned = rtac_adm_payload_size;
+	else
+		bytes_returned = payload_size;
+done:
+	return bytes_returned;
+err:
+	mutex_unlock(&rtac_adm_apr_mutex);
+	return bytes_returned;
+}
+
+
+/* ASM APR */
+void rtac_set_asm_handle(u32 session_id, void *handle)
+{
+	pr_debug("%s\n", __func__);
+
+	mutex_lock(&rtac_asm_apr_mutex);
+	rtac_asm_apr_data[session_id].apr_handle = handle;
+	mutex_unlock(&rtac_asm_apr_mutex);
+}
+
+bool rtac_make_asm_callback(u32 session_id, uint32_t *payload,
+	u32 payload_size)
+{
+	if (atomic_read(&rtac_asm_apr_data[session_id].cmd_state) != 1)
+		return false;
+
+	pr_debug("%s\n", __func__);
+	/* Offset data for in-band payload */
+	rtac_copy_asm_payload_to_user(payload, payload_size);
+	atomic_set(&rtac_asm_apr_data[session_id].cmd_state, 0);
+	wake_up(&rtac_asm_apr_data[session_id].cmd_wait);
+	return true;
+}
+
+void rtac_copy_asm_payload_to_user(void *payload, u32 payload_size)
+{
+	pr_debug("%s\n", __func__);
+	rtac_asm_payload_size = payload_size;
+
+	memcpy(rtac_asm_buffer, &payload_size, sizeof(u32));
+	if (payload_size) {
+		if (payload_size > rtac_asm_user_buf_size) {
+			pr_err("%s: Buffer set not big enough for returned data, buf size = %d, ret data = %d\n",
+			 __func__, rtac_asm_user_buf_size, payload_size);
+			goto done;
+		}
+		memcpy(rtac_asm_buffer + sizeof(u32), payload, payload_size);
+	}
+done:
+	return;
+}
+
+u32 send_rtac_asm_apr(void *buf, u32 opcode)
+{
+	s32	result;
+	u32	count = 0;
+	u32	bytes_returned = 0;
+	u32	session_id = 0;
+	u32	payload_size;
+	struct apr_hdr		asm_params;
+	pr_debug("%s\n", __func__);
+
+	if (copy_from_user(&count, (void *)buf, sizeof(count))) {
+		pr_err("%s: Copy to user failed! buf = 0x%x\n",
+		       __func__, (unsigned int)buf);
+		result = -EFAULT;
+		goto done;
+	}
+
+	if (count <= 0) {
+		pr_err("%s: Invalid buffer size = %d\n", __func__, count);
+		goto done;
+	}
+
+	if (copy_from_user(&payload_size, buf + sizeof(u32), sizeof(u32))) {
+		pr_err("%s: Could not copy payload size from user buffer\n",
+			__func__);
+		goto done;
+	}
+
+	if (payload_size > MAX_PAYLOAD_SIZE) {
+		pr_err("%s: Invalid payload size = %d\n",
+			__func__, payload_size);
+		goto done;
+	}
+
+	if (copy_from_user(&session_id, buf + 2 * sizeof(u32), sizeof(u32))) {
+		pr_err("%s: Could not copy session id from user buffer\n",
+			__func__);
+		goto done;
+	}
+	if (session_id > (SESSION_MAX + 1)) {
+		pr_err("%s: Invalid Session = %d\n", __func__, session_id);
+		goto done;
+	}
+
+	mutex_lock(&rtac_asm_apr_mutex);
+	if (session_id < SESSION_MAX+1) {
+		if (rtac_asm_apr_data[session_id].apr_handle == NULL) {
+			pr_err("%s: APR not initialized\n", __func__);
+			goto err;
+		}
+	}
+
+	/* Set globals for copy of returned payload */
+	rtac_asm_user_buf_size = count;
+
+	/* Copy buffer to in-band payload */
+	if (copy_from_user(rtac_asm_buffer + sizeof(asm_params),
+			buf + 3 * sizeof(u32), payload_size)) {
+		pr_err("%s: Could not copy payload from user buffer\n",
+			__func__);
+		goto err;
+	}
+
+	/* Pack header */
+	asm_params.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+		APR_HDR_LEN(20), APR_PKT_VER);
+	asm_params.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+		payload_size);
+	asm_params.src_svc = q6asm_get_apr_service_id(session_id);
+	asm_params.src_domain = APR_DOMAIN_APPS;
+	asm_params.src_port = (session_id << 8) | 0x0001;
+	asm_params.dest_svc = APR_SVC_ASM;
+	asm_params.dest_domain = APR_DOMAIN_ADSP;
+	asm_params.dest_port = (session_id << 8) | 0x0001;
+	asm_params.token = session_id;
+	asm_params.opcode = opcode;
+
+	memcpy(rtac_asm_buffer, &asm_params, sizeof(asm_params));
+	if (session_id < SESSION_MAX+1)
+		atomic_set(&rtac_asm_apr_data[session_id].cmd_state, 1);
+
+	pr_debug("%s: Sending RTAC command size = %d, session_id=%d\n",
+		__func__, asm_params.pkt_size, session_id);
+
+	result = apr_send_pkt(rtac_asm_apr_data[session_id].apr_handle,
+				(uint32_t *)rtac_asm_buffer);
+	if (result < 0) {
+		pr_err("%s: Set params failed session = %d\n",
+			__func__, session_id);
+		goto err;
+	}
+
+	/* Wait for the callback */
+	result = wait_event_timeout(rtac_asm_apr_data[session_id].cmd_wait,
+		(atomic_read(&rtac_asm_apr_data[session_id].cmd_state) == 0),
+		5 * HZ);
+	mutex_unlock(&rtac_asm_apr_mutex);
+	if (!result) {
+		pr_err("%s: Set params timed out session = %d\n",
+			__func__, session_id);
+		goto done;
+	}
+
+	if (rtac_asm_payload_size != 0) {
+		if (copy_to_user(buf, rtac_asm_buffer,
+			rtac_asm_payload_size + sizeof(u32))) {
+			pr_err("%s: Could not copy buffer to user,size = %d\n",
+				 __func__, payload_size);
+			goto done;
+		}
+	}
+
+	/* Return data written for SET & data read for GET */
+	if (opcode == ASM_STREAM_CMD_GET_PP_PARAMS_V2)
+		bytes_returned = rtac_asm_payload_size;
+	else
+		bytes_returned = payload_size;
+done:
+	return bytes_returned;
+err:
+	mutex_unlock(&rtac_asm_apr_mutex);
+	return bytes_returned;
+}
+
+
+/* Voice APR */
+void rtac_set_voice_handle(u32 mode, void *handle)
+{
+	pr_debug("%s\n", __func__);
+
+	mutex_lock(&rtac_voice_apr_mutex);
+	rtac_voice_apr_data[mode].apr_handle = handle;
+	mutex_unlock(&rtac_voice_apr_mutex);
+}
+
+bool rtac_make_voice_callback(u32 mode, uint32_t *payload, u32 payload_size)
+{
+	if ((atomic_read(&rtac_voice_apr_data[mode].cmd_state) != 1) ||
+		(mode >= RTAC_VOICE_MODES))
+		return false;
+
+	pr_debug("%s\n", __func__);
+	/* Offset data for in-band payload */
+	rtac_copy_voice_payload_to_user(payload, payload_size);
+	atomic_set(&rtac_voice_apr_data[mode].cmd_state, 0);
+	wake_up(&rtac_voice_apr_data[mode].cmd_wait);
+	return true;
+}
+
+void rtac_copy_voice_payload_to_user(void *payload, u32 payload_size)
+{
+	pr_debug("%s\n", __func__);
+	rtac_voice_payload_size = payload_size;
+
+	memcpy(rtac_voice_buffer, &payload_size, sizeof(u32));
+	if (payload_size) {
+		if (payload_size > rtac_voice_user_buf_size) {
+			pr_err("%s: Buffer set not big enough for returned data, buf size = %d, ret data = %d\n",
+			 __func__, rtac_voice_user_buf_size, payload_size);
+			goto done;
+		}
+		memcpy(rtac_voice_buffer + sizeof(u32), payload, payload_size);
+	}
+done:
+	return;
+}
+
+u32 send_voice_apr(u32 mode, void *buf, u32 opcode)
+{
+	s32	result;
+	u32	count = 0;
+	u32	bytes_returned = 0;
+	u32	payload_size;
+	u16	dest_port;
+	struct apr_hdr		voice_params;
+	pr_debug("%s\n", __func__);
+
+	if (copy_from_user(&count, (void *)buf, sizeof(count))) {
+		pr_err("%s: Copy to user failed! buf = 0x%x\n",
+		       __func__, (unsigned int)buf);
+		result = -EFAULT;
+		goto done;
+	}
+
+	if (count <= 0) {
+		pr_err("%s: Invalid buffer size = %d\n", __func__, count);
+		goto done;
+	}
+
+	if (copy_from_user(&payload_size, buf + sizeof(u32), sizeof(u32))) {
+		pr_err("%s: Could not copy payload size from user buffer\n",
+			__func__);
+		goto done;
+	}
+
+	if (payload_size > MAX_PAYLOAD_SIZE) {
+		pr_err("%s: Invalid payload size = %d\n",
+				__func__, payload_size);
+		goto done;
+	}
+
+	if (copy_from_user(&dest_port, buf + 2 * sizeof(u32), sizeof(u32))) {
+		pr_err("%s: Could not copy port id from user buffer\n",
+			__func__);
+		goto done;
+	}
+
+	if ((mode != RTAC_CVP) && (mode != RTAC_CVS)) {
+		pr_err("%s: Invalid Mode for APR, mode = %d\n",
+			__func__, mode);
+		goto done;
+	}
+
+	mutex_lock(&rtac_voice_apr_mutex);
+	if (rtac_voice_apr_data[mode].apr_handle == NULL) {
+		pr_err("%s: APR not initialized\n", __func__);
+		goto err;
+	}
+
+	/* Set globals for copy of returned payload */
+	rtac_voice_user_buf_size = count;
+
+	/* Copy buffer to in-band payload */
+	if (copy_from_user(rtac_voice_buffer + sizeof(voice_params),
+			buf + 3 * sizeof(u32), payload_size)) {
+		pr_err("%s: Could not copy payload from user buffer\n",
+			__func__);
+		goto err;
+	}
+
+	/* Pack header */
+	voice_params.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+		APR_HDR_LEN(20), APR_PKT_VER);
+	voice_params.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+		payload_size);
+	voice_params.src_svc = 0;
+	voice_params.src_domain = APR_DOMAIN_APPS;
+	voice_params.src_port = voice_session_id[
+					get_voice_index(dest_port)];
+	voice_params.dest_svc = 0;
+	voice_params.dest_domain = APR_DOMAIN_MODEM;
+	voice_params.dest_port = dest_port;
+	voice_params.token = 0;
+	voice_params.opcode = opcode;
+
+	memcpy(rtac_voice_buffer, &voice_params, sizeof(voice_params));
+	atomic_set(&rtac_voice_apr_data[mode].cmd_state, 1);
+
+	pr_debug("%s: Sending RTAC command size = %d, opcode = %x\n",
+		__func__, voice_params.pkt_size, opcode);
+
+	result = apr_send_pkt(rtac_voice_apr_data[mode].apr_handle,
+					(uint32_t *)rtac_voice_buffer);
+	if (result < 0) {
+		pr_err("%s: apr_send_pkt failed opcode = %x\n",
+			__func__, opcode);
+		goto err;
+	}
+	/* Wait for the callback */
+	result = wait_event_timeout(rtac_voice_apr_data[mode].cmd_wait,
+		(atomic_read(&rtac_voice_apr_data[mode].cmd_state) == 0),
+		msecs_to_jiffies(TIMEOUT_MS));
+	mutex_unlock(&rtac_voice_apr_mutex);
+	if (!result) {
+		pr_err("%s: apr_send_pkt timed out opcode = %x\n",
+			__func__, opcode);
+		goto done;
+	}
+
+	if (rtac_voice_payload_size != 0) {
+		if (copy_to_user(buf, rtac_voice_buffer,
+			rtac_voice_payload_size + sizeof(u32))) {
+			pr_err("%s: Could not copy buffer to user, size = %d\n",
+				 __func__, payload_size);
+			goto done;
+		}
+	}
+
+	/* Return data written for SET & data read for GET */
+	if (opcode == VOICE_CMD_GET_PARAM)
+		bytes_returned = rtac_voice_payload_size;
+	else
+		bytes_returned = payload_size;
+done:
+	return bytes_returned;
+err:
+	mutex_unlock(&rtac_voice_apr_mutex);
+	return bytes_returned;
+}
+
+
+
+static long rtac_ioctl(struct file *f,
+		unsigned int cmd, unsigned long arg)
+{
+	s32 result = 0;
+	pr_debug("%s\n", __func__);
+
+	if (arg == 0) {
+		pr_err("%s: No data sent to driver!\n", __func__);
+		result = -EFAULT;
+		goto done;
+	}
+
+	switch (cmd) {
+	case AUDIO_GET_RTAC_ADM_INFO:
+		if (copy_to_user((void *)arg, &rtac_adm_data,
+						sizeof(rtac_adm_data)))
+			pr_err("%s: Could not copy to userspace!\n", __func__);
+		else
+			result = sizeof(rtac_adm_data);
+		break;
+	case AUDIO_GET_RTAC_VOICE_INFO:
+		if (copy_to_user((void *)arg, &rtac_voice_data,
+						sizeof(rtac_voice_data)))
+			pr_err("%s: Could not copy to userspace!\n", __func__);
+		else
+			result = sizeof(rtac_voice_data);
+		break;
+	case AUDIO_GET_RTAC_ADM_CAL:
+		result = send_adm_apr((void *)arg, ADM_CMD_GET_PP_PARAMS_V5);
+		break;
+	case AUDIO_SET_RTAC_ADM_CAL:
+		result = send_adm_apr((void *)arg, ADM_CMD_SET_PP_PARAMS_V5);
+		break;
+	case AUDIO_GET_RTAC_ASM_CAL:
+		result = send_rtac_asm_apr((void *)arg,
+			ASM_STREAM_CMD_GET_PP_PARAMS_V2);
+		break;
+	case AUDIO_SET_RTAC_ASM_CAL:
+		result = send_rtac_asm_apr((void *)arg,
+			ASM_STREAM_CMD_SET_PP_PARAMS_V2);
+		break;
+	case AUDIO_GET_RTAC_CVS_CAL:
+		result = send_voice_apr(RTAC_CVS, (void *)arg,
+			VOICE_CMD_GET_PARAM);
+		break;
+	case AUDIO_SET_RTAC_CVS_CAL:
+		result = send_voice_apr(RTAC_CVS, (void *)arg,
+			VOICE_CMD_SET_PARAM);
+		break;
+	case AUDIO_GET_RTAC_CVP_CAL:
+		result = send_voice_apr(RTAC_CVP, (void *)arg,
+			VOICE_CMD_GET_PARAM);
+		break;
+	case AUDIO_SET_RTAC_CVP_CAL:
+		result = send_voice_apr(RTAC_CVP, (void *)arg,
+			VOICE_CMD_SET_PARAM);
+		break;
+	default:
+		pr_err("%s: Invalid IOCTL, command = %d!\n",
+		       __func__, cmd);
+	}
+done:
+	return result;
+}
+
+
+static const struct file_operations rtac_fops = {
+	.owner = THIS_MODULE,
+	.open = rtac_open,
+	.release = rtac_release,
+	.unlocked_ioctl = rtac_ioctl,
+};
+
+struct miscdevice rtac_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_rtac",
+	.fops	= &rtac_fops,
+};
+
+static int __init rtac_init(void)
+{
+	int i = 0;
+	pr_debug("%s\n", __func__);
+
+	/* ADM */
+	memset(&rtac_adm_data, 0, sizeof(rtac_adm_data));
+	rtac_adm_apr_data.apr_handle = NULL;
+	atomic_set(&rtac_adm_apr_data.cmd_state, 0);
+	init_waitqueue_head(&rtac_adm_apr_data.cmd_wait);
+	mutex_init(&rtac_adm_mutex);
+	mutex_init(&rtac_adm_apr_mutex);
+
+	rtac_adm_buffer = kzalloc(RTAC_BUF_SIZE, GFP_KERNEL);
+	if (rtac_adm_buffer == NULL) {
+		pr_err("%s: Could not allocate payload of size = %d\n",
+			__func__, RTAC_BUF_SIZE);
+		goto nomem;
+	}
+
+	/* ASM */
+	for (i = 0; i < SESSION_MAX+1; i++) {
+		rtac_asm_apr_data[i].apr_handle = NULL;
+		atomic_set(&rtac_asm_apr_data[i].cmd_state, 0);
+		init_waitqueue_head(&rtac_asm_apr_data[i].cmd_wait);
+	}
+	mutex_init(&rtac_asm_apr_mutex);
+
+	rtac_asm_buffer = kzalloc(RTAC_BUF_SIZE, GFP_KERNEL);
+	if (rtac_asm_buffer == NULL) {
+		pr_err("%s: Could not allocate payload of size = %d\n",
+			__func__, RTAC_BUF_SIZE);
+		kzfree(rtac_adm_buffer);
+		goto nomem;
+	}
+
+	/* Voice */
+	memset(&rtac_voice_data, 0, sizeof(rtac_voice_data));
+	for (i = 0; i < RTAC_VOICE_MODES; i++) {
+		rtac_voice_apr_data[i].apr_handle = NULL;
+		atomic_set(&rtac_voice_apr_data[i].cmd_state, 0);
+		init_waitqueue_head(&rtac_voice_apr_data[i].cmd_wait);
+	}
+	mutex_init(&rtac_voice_mutex);
+	mutex_init(&rtac_voice_apr_mutex);
+
+	rtac_voice_buffer = kzalloc(RTAC_BUF_SIZE, GFP_KERNEL);
+	if (rtac_voice_buffer == NULL) {
+		pr_err("%s: Could not allocate payload of size = %d\n",
+			__func__, RTAC_BUF_SIZE);
+		kzfree(rtac_adm_buffer);
+		kzfree(rtac_asm_buffer);
+		goto nomem;
+	}
+
+	return misc_register(&rtac_misc);
+nomem:
+	return -ENOMEM;
+}
+
+module_init(rtac_init);
+
+MODULE_DESCRIPTION("MSM 8x60 Real-Time Audio Calibration driver");
+MODULE_LICENSE("GPL v2");
+
+#endif
diff --git a/arch/arm/mach-msm/rpm-regulator-9615.c b/arch/arm/mach-msm/rpm-regulator-9615.c
index 23c0ee3..82ac3d8 100644
--- a/arch/arm/mach-msm/rpm-regulator-9615.c
+++ b/arch/arm/mach-msm/rpm-regulator-9615.c
@@ -50,6 +50,11 @@
 	.hpm		= REQUEST_MEMBER(0, 0x00000C00, 10),
 };
 
+static struct rpm_vreg_parts corner_parts = {
+	.request_len	= 1,
+	.uV		= REQUEST_MEMBER(0, 0x00000003,  0),
+};
+
 /* Physically available PMIC regulator voltage setpoint ranges */
 static struct vreg_range pldo_ranges[] = {
 	VOLTAGE_RANGE( 750000, 1487500, 12500),
@@ -72,16 +77,22 @@
 	VOLTAGE_RANGE(1500000, 3075000, 25000),
 };
 
+static struct vreg_range corner_ranges[] = {
+	VOLTAGE_RANGE(RPM_VREG_CORNER_NONE, RPM_VREG_CORNER_HIGH, 1),
+};
+
 static struct vreg_set_points pldo_set_points = SET_POINTS(pldo_ranges);
 static struct vreg_set_points nldo_set_points = SET_POINTS(nldo_ranges);
 static struct vreg_set_points nldo1200_set_points = SET_POINTS(nldo1200_ranges);
 static struct vreg_set_points smps_set_points = SET_POINTS(smps_ranges);
+static struct vreg_set_points corner_set_points = SET_POINTS(corner_ranges);
 
 static struct vreg_set_points *all_set_points[] = {
 	&pldo_set_points,
 	&nldo_set_points,
 	&nldo1200_set_points,
 	&smps_set_points,
+	&corner_set_points,
 };
 
 #define LDO(_id, _name, _name_pc, _ranges, _hpm_min_load) \
@@ -127,6 +138,19 @@
 		.rdesc_pc.name	 = _name_pc, \
 	}
 
+#define CORNER(_id, _rpm_id, _name, _ranges) \
+	[RPM_VREG_ID_PM8018_##_id] = { \
+		.req = { \
+			[0] = { .id = MSM_RPM_ID_##_rpm_id, }, \
+			[1] = { .id = -1, }, \
+		}, \
+		.type		 = RPM_REGULATOR_TYPE_CORNER, \
+		.set_points	 = &_ranges##_set_points, \
+		.part		 = &corner_parts, \
+		.id		 = RPM_VREG_ID_PM8018_##_id, \
+		.rdesc.name	 = _name, \
+	}
+
 static struct vreg vregs[] = {
 	LDO(L2,   "8018_l2",   "8018_l2_pc",  pldo,     LDO_50),
 	LDO(L3,   "8018_l3",   "8018_l3_pc",  pldo,     LDO_50),
@@ -149,6 +173,8 @@
 	SMPS(S5,  "8018_s5",   "8018_s5_pc",  smps,     SMPS_1500),
 
 	LVS(LVS1, "8018_lvs1", "8018_lvs1_pc"),
+
+	CORNER(VDD_DIG_CORNER, VOLTAGE_CORNER, "vdd_dig_corner", corner),
 };
 
 static const char *pin_control_label[] = {
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 2980811..6e81be6 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -282,14 +282,22 @@
 		uint32_t notify_rpm;
 	};
 
-	struct mode_of mode_of_data[] = {
-		{"qcom,spm-cmd-wfi", MSM_SPM_MODE_CLOCK_GATING, 0},
-		{"qcom,spm-cmd-ret", MSM_SPM_MODE_POWER_RETENTION, 0},
-		{"qcom,spm-cmd-spc", MSM_SPM_MODE_POWER_COLLAPSE, 0},
-		{"qcom,spm-cmd-pc", MSM_SPM_MODE_POWER_COLLAPSE, 1},
+	struct mode_of of_cpu_modes[] = {
+		{"qcom,saw2-spm-cmd-wfi", MSM_SPM_MODE_CLOCK_GATING, 0},
+		{"qcom,saw2-spm-cmd-ret", MSM_SPM_MODE_POWER_RETENTION, 0},
+		{"qcom,saw2-spm-cmd-spc", MSM_SPM_MODE_POWER_COLLAPSE, 0},
+		{"qcom,saw2-spm-cmd-pc", MSM_SPM_MODE_POWER_COLLAPSE, 1},
 	};
 
-	BUG_ON(ARRAY_SIZE(mode_of_data) > MSM_SPM_MODE_NR);
+	struct mode_of of_l2_modes[] = {
+		{"qcom,saw2-spm-cmd-ret", MSM_SPM_L2_MODE_RETENTION, 1},
+		{"qcom,saw2-spm-cmd-gdhs", MSM_SPM_L2_MODE_GDHS, 1},
+		{"qcom,saw2-spm-cmd-pc", MSM_SPM_L2_MODE_POWER_COLLAPSE, 1},
+	};
+
+	struct mode_of *mode_of_data;
+	int num_modes;
+
 	memset(&spm_data, 0, sizeof(struct msm_spm_platform_data));
 	memset(&modes, 0,
 		(MSM_SPM_MODE_NR - 2) * sizeof(struct msm_spm_seq_entry));
@@ -339,7 +347,22 @@
 		spm_data.reg_init_values[spm_of_data[i].id] = val;
 	}
 
-	for (i = 0; i < ARRAY_SIZE(mode_of_data); i++) {
+	/*
+	 * Device with id 0..NR_CPUS are SPM for apps cores
+	 * Device with id 0xFFFF is for L2 SPM.
+	 */
+	if (cpu >= 0 && cpu < num_possible_cpus()) {
+		mode_of_data = of_cpu_modes;
+		num_modes = ARRAY_SIZE(of_cpu_modes);
+		dev = &per_cpu(msm_cpu_spm_device, cpu);
+
+	} else {
+		mode_of_data = of_l2_modes;
+		num_modes = ARRAY_SIZE(of_l2_modes);
+		dev = &msm_spm_l2_device;
+	}
+
+	for (i = 0; i < num_modes; i++) {
 		key = mode_of_data[i].key;
 		modes[mode_count].cmd =
 			(uint8_t *)of_get_property(node, key, &len);
@@ -353,16 +376,8 @@
 	spm_data.modes = modes;
 	spm_data.num_modes = mode_count;
 
-	/*
-	 * Device with id 0..NR_CPUS are SPM for apps cores
-	 * Device with id 0xFFFF is for L2 SPM.
-	 */
-	if (cpu >= 0 && cpu < num_possible_cpus())
-		dev = &per_cpu(msm_cpu_spm_device, cpu);
-	else
-		dev = &msm_spm_l2_device;
-
 	ret = msm_spm_dev_init(dev, &spm_data);
+
 	if (ret < 0)
 		pr_warn("%s():failed core-id:%u ret:%d\n", __func__, cpu, ret);
 
diff --git a/arch/arm/mach-msm/wcnss-ssr-8960.c b/arch/arm/mach-msm/wcnss-ssr-8960.c
index 266c8b4..793ef7f 100644
--- a/arch/arm/mach-msm/wcnss-ssr-8960.c
+++ b/arch/arm/mach-msm/wcnss-ssr-8960.c
@@ -30,11 +30,7 @@
 #define MODULE_NAME			"wcnss_8960"
 #define MAX_BUF_SIZE			0x51
 
-static void riva_smsm_cb_fn(struct work_struct *);
-static DECLARE_WORK(riva_smsm_cb_work, riva_smsm_cb_fn);
 
-static void riva_fatal_fn(struct work_struct *);
-static DECLARE_WORK(riva_fatal_work, riva_fatal_fn);
 
 static struct delayed_work cancel_vote_work;
 static void *riva_ramdump_dev;
@@ -42,14 +38,6 @@
 static int ss_restart_inprogress;
 static int enable_riva_ssr;
 
-static void riva_smsm_cb_fn(struct work_struct *work)
-{
-	if (!enable_riva_ssr)
-		panic(MODULE_NAME ": SMSM reset request received from Riva");
-	else
-		subsystem_restart("riva");
-}
-
 static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
 					uint32_t new_state)
 {
@@ -58,60 +46,62 @@
 	unsigned smem_reset_size;
 	unsigned size;
 
+	riva_crash = true;
+
+	pr_err("%s: smsm state changed\n", MODULE_NAME);
+
 	if (!(new_state & SMSM_RESET))
 		return;
 
-	riva_crash = true;
-	pr_err("%s: smsm state changed to smsm reset\n", MODULE_NAME);
-
-	smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_WCNSS0,
-		&smem_reset_size);
-
-	if (!smem_reset_reason || !smem_reset_size) {
-		pr_err("%s: wcnss subsystem failure reason: %s\n", __func__,
-				"(unknown, smem_get_entry failed)");
-	} else if (!smem_reset_reason[0]) {
-		pr_err("%s: wcnss subsystem failure reason: %s\n", __func__,
-				"(unknown, init string found)");
-	} else {
-		size = smem_reset_size < MAX_BUF_SIZE ? smem_reset_size :
-				(MAX_BUF_SIZE - 1);
-		memcpy(buffer, smem_reset_reason, size);
-		buffer[size] = '\0';
-		pr_err("%s: wcnss subsystem failure reason: %s\n", __func__,
-				buffer);
-		memset(smem_reset_reason, 0, smem_reset_size);
-		wmb();
-	}
-
 	if (ss_restart_inprogress) {
 		pr_err("%s: Ignoring smsm reset req, restart in progress\n",
 						MODULE_NAME);
 		return;
 	}
-	ss_restart_inprogress = true;
-	schedule_work(&riva_smsm_cb_work);
-}
 
-static void riva_fatal_fn(struct work_struct *work)
-{
 	if (!enable_riva_ssr)
-		panic(MODULE_NAME ": Watchdog bite received from Riva");
-	else
-		subsystem_restart("riva");
+		panic(MODULE_NAME ": SMSM reset request received from Riva");
+
+	smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_WCNSS0,
+			&smem_reset_size);
+
+	if (!smem_reset_reason || !smem_reset_size) {
+		pr_err("%s: wcnss subsystem failure reason: %s\n",
+				__func__, "(unknown, smem_get_entry failed)");
+	} else if (!smem_reset_reason[0]) {
+		pr_err("%s: wcnss subsystem failure reason: %s\n",
+				__func__, "(unknown, init string found)");
+	} else {
+		size = smem_reset_size < MAX_BUF_SIZE ? smem_reset_size :
+			(MAX_BUF_SIZE - 1);
+		memcpy(buffer, smem_reset_reason, size);
+		buffer[size] = '\0';
+		pr_err("%s: wcnss subsystem failure reason: %s\n",
+				__func__, buffer);
+		memset(smem_reset_reason, 0, smem_reset_size);
+		wmb();
+	}
+
+	ss_restart_inprogress = true;
+	subsystem_restart("riva");
 }
 
 static irqreturn_t riva_wdog_bite_irq_hdlr(int irq, void *dev_id)
 {
-	int ret;
+	riva_crash = true;
 
 	if (ss_restart_inprogress) {
 		pr_err("%s: Ignoring riva bite irq, restart in progress\n",
 						MODULE_NAME);
 		return IRQ_HANDLED;
 	}
+
+	if (!enable_riva_ssr)
+		panic(MODULE_NAME ": Watchdog bite received from Riva");
+
 	ss_restart_inprogress = true;
-	ret = schedule_work(&riva_fatal_work);
+	subsystem_restart("riva");
+
 	return IRQ_HANDLED;
 }
 
@@ -229,8 +219,8 @@
 	ret = smsm_state_cb_register(SMSM_WCNSS_STATE, SMSM_RESET,
 					smsm_state_cb_hdlr, 0);
 	if (ret < 0) {
-		pr_err("%s: Unable to register smsm callback for Riva Reset!"
-				" (%d)\n", MODULE_NAME, ret);
+		pr_err("%s: Unable to register smsm callback for Riva Reset! %d\n",
+				MODULE_NAME, ret);
 		goto out;
 	}
 	ret = request_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ,
@@ -238,8 +228,8 @@
 				"riva_wdog", NULL);
 
 	if (ret < 0) {
-		pr_err("%s: Unable to register for Riva bite interrupt"
-				" (%d)\n", MODULE_NAME, ret);
+		pr_err("%s: Unable to register for Riva bite interrupt (%d)\n",
+				MODULE_NAME, ret);
 		goto out;
 	}
 	ret = riva_restart_init();
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 600e04f..e258072 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2409,30 +2409,29 @@
 
 static void a3xx_cp_callback(struct adreno_device *adreno_dev, int irq)
 {
-	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+	struct kgsl_device *device = &adreno_dev->dev;
 
 	if (irq == A3XX_INT_CP_RB_INT) {
 		unsigned int context_id;
-		kgsl_sharedmem_readl(&adreno_dev->dev.memstore,
-				&context_id,
+		kgsl_sharedmem_readl(&device->memstore, &context_id,
 				KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
 					current_context));
 		if (context_id < KGSL_MEMSTORE_MAX) {
-			kgsl_sharedmem_writel(&rb->device->memstore,
+			kgsl_sharedmem_writel(&device->memstore,
 					KGSL_MEMSTORE_OFFSET(context_id,
 						ts_cmp_enable), 0);
 			wmb();
 		}
-		KGSL_CMD_WARN(rb->device, "ringbuffer rb interrupt\n");
+		KGSL_CMD_WARN(device, "ringbuffer rb interrupt\n");
 	}
 
-	wake_up_interruptible_all(&rb->device->wait_queue);
+	wake_up_interruptible_all(&device->wait_queue);
 
 	/* Schedule work to free mem and issue ibs */
-	queue_work(rb->device->work_queue, &rb->device->ts_expired_ws);
+	queue_work(device->work_queue, &device->ts_expired_ws);
 
-	atomic_notifier_call_chain(&rb->device->ts_notifier_list,
-				   rb->device->id, NULL);
+	atomic_notifier_call_chain(&device->ts_notifier_list,
+				   device->id, NULL);
 }
 
 #define A3XX_IRQ_CALLBACK(_c) { .func = _c }
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index e789733..81de64f 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2523,7 +2523,7 @@
 	}
 
 	status = kgsl_allocate_contiguous(&device->memstore,
-		sizeof(struct kgsl_devmemstore));
+		KGSL_MEMSTORE_SIZE);
 
 	if (status != 0) {
 		KGSL_DRV_ERR(device, "kgsl_allocate_contiguous failed %d\n",
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 67da5ea..9ed6cca 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -7,7 +7,6 @@
 obj-$(CONFIG_MSM_CAMERA) += io/
 ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
   EXTRA_CFLAGS += -Idrivers/media/video/msm/csi
-  EXTRA_CFLAGS += -Idrivers/media/video/msm/io
   EXTRA_CFLAGS += -Idrivers/media/video/msm/eeprom
   EXTRA_CFLAGS += -Idrivers/media/video/msm/sensors
   EXTRA_CFLAGS += -Idrivers/media/video/msm/actuators
diff --git a/drivers/media/video/msm/csi/Makefile b/drivers/media/video/msm/csi/Makefile
index e5d5966..f7cb408 100644
--- a/drivers/media/video/msm/csi/Makefile
+++ b/drivers/media/video/msm/csi/Makefile
@@ -1,6 +1,7 @@
 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
-obj-$(CONFIG_ARCH_MSM8X60) += msm_csic.o
-obj-$(CONFIG_ARCH_MSM7X30) += msm_csic.o
+obj-$(CONFIG_ARCH_MSM8960) += msm_csi2_register.o msm_csiphy.o msm_csid.o msm_ispif.o
+obj-$(CONFIG_ARCH_MSM7X27A) += msm_csic_register.o msm_csic.o
+obj-$(CONFIG_ARCH_MSM8X60) += msm_csic_register.o msm_csic.o
+obj-$(CONFIG_ARCH_MSM7X30) += msm_csic_register.o msm_csic.o
+
diff --git a/drivers/media/video/msm/csi/msm_csi2_register.c b/drivers/media/video/msm/csi/msm_csi2_register.c
new file mode 100644
index 0000000..7b85ded
--- /dev/null
+++ b/drivers/media/video/msm/csi/msm_csi2_register.c
@@ -0,0 +1,67 @@
+/* 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/device.h>
+#include "msm.h"
+#include "msm_csi_register.h"
+
+int msm_csi_register_subdevs(struct msm_cam_media_controller *p_mctl,
+	int core_index,
+	int (*msm_mctl_subdev_match_core)(struct device *, void *))
+{
+	int rc = -ENODEV;
+	struct device_driver *driver;
+	struct device *dev;
+
+	/* 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;
+
+	p_mctl->csiphy_sdev = dev_get_drvdata(dev);
+
+	/* register csid subdev */
+	driver = driver_find(MSM_CSID_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;
+
+	p_mctl->csid_sdev = dev_get_drvdata(dev);
+
+	/* 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;
+
+	p_mctl->ispif_sdev = dev_get_drvdata(dev);
+	rc = 0;
+	return rc;
+out:
+	p_mctl->ispif_sdev = NULL;
+	return rc;
+}
+
diff --git a/drivers/media/video/msm/csi/msm_csi_register.h b/drivers/media/video/msm/csi/msm_csi_register.h
new file mode 100644
index 0000000..578b609
--- /dev/null
+++ b/drivers/media/video/msm/csi/msm_csi_register.h
@@ -0,0 +1,16 @@
+/* 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.
+ *
+ */
+
+int msm_csi_register_subdevs(struct msm_cam_media_controller *p_mctl,
+	int core_index,
+	int (*msm_mctl_subdev_match_core)(struct device *, void *));
diff --git a/drivers/media/video/msm/csi/msm_csic_register.c b/drivers/media/video/msm/csi/msm_csic_register.c
new file mode 100644
index 0000000..7ccaff2
--- /dev/null
+++ b/drivers/media/video/msm/csi/msm_csic_register.c
@@ -0,0 +1,45 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/device.h>
+#include "msm.h"
+#include "msm_csi_register.h"
+
+int msm_csi_register_subdevs(struct msm_cam_media_controller *p_mctl,
+	int core_index,
+	int (*msm_mctl_subdev_match_core)(struct device *, void *))
+{
+	int rc = -ENODEV;
+	struct device_driver *driver;
+	struct device *dev;
+
+	driver = driver_find(MSM_CSIC_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;
+
+	p_mctl->csic_sdev = dev_get_drvdata(dev);
+
+	rc = 0;
+	p_mctl->ispif_sdev = NULL;
+	return rc;
+
+out:
+	p_mctl->ispif_sdev = NULL;
+	return rc;
+}
+
diff --git a/drivers/media/video/msm/csi/msm_ispif.c b/drivers/media/video/msm/csi/msm_ispif.c
index 23982dd..be97091 100644
--- a/drivers/media/video/msm/csi/msm_ispif.c
+++ b/drivers/media/video/msm/csi/msm_ispif.c
@@ -571,16 +571,51 @@
 	}
 }
 
+static long msm_ispif_cmd(struct v4l2_subdev *sd, void *arg)
+{
+	long rc = 0;
+	struct ispif_cfg_data cdata;
+
+	if (copy_from_user(&cdata, (void *)arg, sizeof(struct ispif_cfg_data)))
+		return -EFAULT;
+	CDBG("%s cfgtype = %d\n", __func__, cdata.cfgtype);
+	switch (cdata.cfgtype) {
+	case ISPIF_INIT:
+		CDBG("%s csid_version = %x\n", __func__,
+			cdata.cfg.csid_version);
+		rc = msm_ispif_init(&cdata.cfg.csid_version);
+		break;
+	case ISPIF_SET_CFG:
+		CDBG("%s len = %d, intftype = %d,.cid_mask = %d, csid = %d\n",
+			__func__,
+			cdata.cfg.ispif_params.len,
+			cdata.cfg.ispif_params.params[0].intftype,
+			cdata.cfg.ispif_params.params[0].cid_mask,
+			cdata.cfg.ispif_params.params[0].csid);
+		rc = msm_ispif_config(&cdata.cfg.ispif_params);
+		break;
+
+	case ISPIF_SET_ON_FRAME_BOUNDARY:
+	case ISPIF_SET_OFF_FRAME_BOUNDARY:
+	case ISPIF_SET_OFF_IMMEDIATELY:
+		rc = msm_ispif_subdev_video_s_stream(sd, cdata.cfg.cmd);
+		break;
+	case ISPIF_RELEASE:
+		msm_ispif_release(sd);
+		break;
+	default:
+		break;
+	}
+
+	return rc;
+}
+
 static long msm_ispif_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd,
 								void *arg)
 {
 	switch (cmd) {
 	case VIDIOC_MSM_ISPIF_CFG:
-		return msm_ispif_config((struct msm_ispif_params_list *)arg);
-	case VIDIOC_MSM_ISPIF_INIT:
-		return msm_ispif_init((uint32_t *)arg);
-	case VIDIOC_MSM_ISPIF_RELEASE:
-		msm_ispif_release(sd);
+		return msm_ispif_cmd(sd, arg);
 	default:
 		return -ENOIOCTLCMD;
 	}
diff --git a/drivers/media/video/msm/csi/msm_ispif.h b/drivers/media/video/msm/csi/msm_ispif.h
index 8f1dd12..7b301ba 100644
--- a/drivers/media/video/msm/csi/msm_ispif.h
+++ b/drivers/media/video/msm/csi/msm_ispif.h
@@ -43,25 +43,7 @@
 };
 
 #define VIDIOC_MSM_ISPIF_CFG \
-	_IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct msm_ispif_params)
-
-#define VIDIOC_MSM_ISPIF_INIT \
-	_IO('V', BASE_VIDIOC_PRIVATE + 2)
-
-#define VIDIOC_MSM_ISPIF_RELEASE \
-	_IOWR('V', BASE_VIDIOC_PRIVATE + 3, struct v4l2_subdev*)
-
-#define ISPIF_STREAM(intf, action) (((intf)<<ISPIF_S_STREAM_SHIFT)+(action))
-#define ISPIF_ON_FRAME_BOUNDARY	(0x01 << 0)
-#define ISPIF_OFF_FRAME_BOUNDARY    (0x01 << 1)
-#define ISPIF_OFF_IMMEDIATELY       (0x01 << 2)
-#define ISPIF_S_STREAM_SHIFT	4
-
-
-#define PIX_0 (0x01 << 0)
-#define RDI_0 (0x01 << 1)
-#define PIX_1 (0x01 << 2)
-#define RDI_1 (0x01 << 3)
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 18, struct ispif_cfg_data*)
 
 void msm_ispif_vfe_get_cid(uint8_t intftype, char *cids, int *num);
 
diff --git a/drivers/media/video/msm/flash.c b/drivers/media/video/msm/flash.c
index 7c4021d..54c59f8 100644
--- a/drivers/media/video/msm/flash.c
+++ b/drivers/media/video/msm/flash.c
@@ -17,15 +17,16 @@
 #include <linux/pwm.h>
 #include <linux/pmic8058-pwm.h>
 #include <linux/hrtimer.h>
-#include <linux/i2c.h>
 #include <linux/export.h>
 #include <mach/pmic.h>
 #include <mach/camera.h>
 #include <mach/gpio.h>
+#include "msm_camera_i2c.h"
 
 struct i2c_client *sx150x_client;
 struct timer_list timer_flash;
 static struct msm_camera_sensor_info *sensor_data;
+static struct msm_camera_i2c_client i2c_client;
 enum msm_cam_flash_stat{
 	MSM_CAM_FLASH_OFF,
 	MSM_CAM_FLASH_ON,
@@ -33,47 +34,6 @@
 
 static struct i2c_client *sc628a_client;
 
-static int32_t flash_i2c_txdata(struct i2c_client *client,
-		unsigned char *txdata, int length)
-{
-	struct i2c_msg msg[] = {
-		{
-			.addr = client->addr >> 1,
-			.flags = 0,
-			.len = length,
-			.buf = txdata,
-		},
-	};
-	if (i2c_transfer(client->adapter, msg, 1) < 0) {
-		CDBG("flash_i2c_txdata faild 0x%x\n", client->addr >> 1);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static int32_t flash_i2c_write_b(struct i2c_client *client,
-	uint8_t baddr, uint8_t bdata)
-{
-	int32_t rc = -EFAULT;
-	unsigned char buf[2];
-	if (!client)
-		return  -ENOTSUPP;
-
-	memset(buf, 0, sizeof(buf));
-	buf[0] = baddr;
-	buf[1] = bdata;
-
-	rc = flash_i2c_txdata(client, buf, 2);
-	if (rc < 0) {
-		CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
-				baddr, bdata);
-	}
-	usleep_range(4000, 5000);
-
-	return rc;
-}
-
 static const struct i2c_device_id sc628a_i2c_id[] = {
 	{"sc628a", 0},
 	{ }
@@ -128,8 +88,10 @@
 	}
 
 	tps61310_client = client;
-
-	rc = flash_i2c_write_b(tps61310_client, 0x01, 0x00);
+	i2c_client.client = tps61310_client;
+	i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+	rc = msm_camera_i2c_write(&i2c_client, 0x01, 0x00,
+		MSM_CAMERA_I2C_BYTE_DATA);
 	if (rc < 0) {
 		tps61310_client = NULL;
 		goto probe_failure;
@@ -431,10 +393,18 @@
 		break;
 
 	case MSM_CAMERA_LED_OFF:
-		if (sc628a_client)
-			rc = flash_i2c_write_b(sc628a_client, 0x02, 0x00);
-		if (tps61310_client)
-			rc = flash_i2c_write_b(tps61310_client, 0x01, 0x00);
+		if (sc628a_client) {
+			i2c_client.client = sc628a_client;
+			i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+			rc = msm_camera_i2c_write(&i2c_client, 0x02, 0x00,
+				MSM_CAMERA_I2C_BYTE_DATA);
+		}
+		if (tps61310_client) {
+			i2c_client.client = tps61310_client;
+			i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+			rc = msm_camera_i2c_write(&i2c_client, 0x01, 0x00,
+				MSM_CAMERA_I2C_BYTE_DATA);
+		}
 		gpio_set_value_cansleep(external->led_en, 0);
 		gpio_set_value_cansleep(external->led_flash_en, 0);
 		break;
@@ -443,20 +413,36 @@
 		gpio_set_value_cansleep(external->led_en, 1);
 		gpio_set_value_cansleep(external->led_flash_en, 1);
 		usleep_range(2000, 3000);
-		if (sc628a_client)
-			rc = flash_i2c_write_b(sc628a_client, 0x02, 0x06);
-		if (tps61310_client)
-			rc = flash_i2c_write_b(tps61310_client, 0x01, 0x86);
+		if (sc628a_client) {
+			i2c_client.client = sc628a_client;
+			i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+			rc = msm_camera_i2c_write(&i2c_client, 0x02, 0x06,
+				MSM_CAMERA_I2C_BYTE_DATA);
+		}
+		if (tps61310_client) {
+			i2c_client.client = tps61310_client;
+			i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+			rc = msm_camera_i2c_write(&i2c_client, 0x01, 0x86,
+				MSM_CAMERA_I2C_BYTE_DATA);
+		}
 		break;
 
 	case MSM_CAMERA_LED_HIGH:
 		gpio_set_value_cansleep(external->led_en, 1);
 		gpio_set_value_cansleep(external->led_flash_en, 1);
 		usleep_range(2000, 3000);
-		if (sc628a_client)
-			rc = flash_i2c_write_b(sc628a_client, 0x02, 0x49);
-		if (tps61310_client)
-			rc = flash_i2c_write_b(tps61310_client, 0x01, 0x8B);
+		if (sc628a_client) {
+			i2c_client.client = sc628a_client;
+			i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+			rc = msm_camera_i2c_write(&i2c_client, 0x02, 0x49,
+				MSM_CAMERA_I2C_BYTE_DATA);
+		}
+		if (tps61310_client) {
+			i2c_client.client = tps61310_client;
+			i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+			rc = msm_camera_i2c_write(&i2c_client, 0x01, 0x8B,
+				MSM_CAMERA_I2C_BYTE_DATA);
+		}
 		break;
 
 	default:
diff --git a/drivers/media/video/msm/io/Makefile b/drivers/media/video/msm/io/Makefile
index 64df7fb..611eecd 100644
--- a/drivers/media/video/msm/io/Makefile
+++ b/drivers/media/video/msm/io/Makefile
@@ -1,9 +1,9 @@
 GCC_VERSION      := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
 
-obj-$(CONFIG_MSM_CAMERA)   += msm_camera_io_util.o
 EXTRA_CFLAGS += -Idrivers/media/video/msm
+obj-$(CONFIG_MSM_CAMERA)   += msm_camera_io_util.o msm_camera_i2c.o
 ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
-  obj-$(CONFIG_MSM_CAMERA) += msm_camera_i2c.o msm_camera_i2c_mux.o
+  obj-$(CONFIG_MSM_CAMERA) += msm_camera_i2c_mux.o
   obj-$(CONFIG_ARCH_MSM7X27A) += msm_io_7x27a_v4l2.o
   obj-$(CONFIG_ARCH_MSM8X60) += msm_io_vfe31_v4l2.o
   obj-$(CONFIG_ARCH_MSM7X30) += msm_io_vfe31_v4l2.o
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 42330b4..7bc6cff 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -146,13 +146,11 @@
 
 /* message id for v4l2_subdev_notify*/
 enum msm_camera_v4l2_subdev_notify {
-	NOTIFY_CID_CHANGE, /* arg = msm_camera_csid_params */
 	NOTIFY_ISP_MSG_EVT, /* arg = enum ISP_MESSAGE_ID */
 	NOTIFY_VFE_MSG_OUT, /* arg = struct isp_msg_output */
 	NOTIFY_VFE_MSG_STATS,  /* arg = struct isp_msg_stats */
 	NOTIFY_VFE_MSG_COMP_STATS, /* arg = struct msm_stats_buf */
 	NOTIFY_VFE_BUF_EVT, /* arg = struct msm_vfe_resp */
-	NOTIFY_ISPIF_STREAM, /* arg = enable parameter for s_stream */
 	NOTIFY_PCLK_CHANGE, /* arg = pclk */
 	NOTIFY_CSIPHY_CFG, /* arg = msm_camera_csiphy_params */
 	NOTIFY_CSID_CFG, /* arg = msm_camera_csid_params */
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index ed6c493..cdfad3b 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -39,6 +39,7 @@
 #include "msm_vpe.h"
 #include "msm_vfe32.h"
 #include "msm_camera_eeprom.h"
+#include "msm_csi_register.h"
 
 #ifdef CONFIG_MSM_CAMERA_DEBUG
 #define D(fmt, args...) pr_debug("msm_mctl: " fmt, ##args)
@@ -47,7 +48,6 @@
 #endif
 
 #define MSM_V4L2_SWFI_LATENCY 3
-
 /* VFE required buffer number for streaming */
 static struct msm_isp_color_fmt msm_isp_formats[] = {
 	{
@@ -162,6 +162,8 @@
 	info.mount_angle = sdata->sensor_platform_info->mount_angle;
 	info.actuator_enabled = sdata->actuator_info ? 1 : 0;
 	info.strobe_flash_enabled = sdata->strobe_flash_data ? 1 : 0;
+	info.ispif_supported = mctl->ispif_sdev ? 1 : 0;
+
 	/* copy back to user space */
 	if (copy_to_user((void *)arg,
 				&info,
@@ -400,6 +402,10 @@
 		else
 			rc = p_mctl->isp_sdev->isp_config(p_mctl, cmd, arg);
 		break;
+	case MSM_CAM_IOCTL_ISPIF_IO_CFG:
+		rc = v4l2_subdev_call(p_mctl->ispif_sdev,
+			core, ioctl, VIDIOC_MSM_ISPIF_CFG, argp);
+		break;
 	default:
 		/* ISP config*/
 		D("%s:%d: go to default. Calling msm_isp_config\n",
@@ -435,62 +441,12 @@
 		(struct msm_camera_sensor_info *) s_ctrl->sensordata;
 	struct msm_camera_device_platform_data *pdata = sinfo->pdata;
 
-	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,
+	rc = msm_csi_register_subdevs(p_mctl, core_index,
 				msm_mctl_subdev_match_core);
-		if (!dev)
+
+	if (rc < 0)
 			goto out;
 
-		p_mctl->csiphy_sdev = dev_get_drvdata(dev);
-	}
-
-	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,
-				msm_mctl_subdev_match_core);
-		if (!dev)
-			goto out;
-
-		p_mctl->csic_sdev = dev_get_drvdata(dev);
-	}
-
-	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, (void *)core_index,
-				msm_mctl_subdev_match_core);
-		if (!dev)
-			goto out;
-
-		p_mctl->csid_sdev = dev_get_drvdata(dev);
-	}
-
-	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;
-
-		p_mctl->ispif_sdev = dev_get_drvdata(dev);
-	}
-
 	/* register vfe subdev */
 	driver = driver_find(MSM_VFE_DRV_NAME, &platform_bus_type);
 	if (!driver)
@@ -568,6 +524,7 @@
 	mutex_lock(&p_mctl->lock);
 	/* open sub devices - once only*/
 	if (!p_mctl->opencnt) {
+		struct msm_sensor_csi_info csi_info;
 		uint32_t csid_version;
 		wake_lock(&p_mctl->wake_lock);
 
@@ -594,7 +551,7 @@
 			goto act_power_up_failed;
 		}
 
-		if (camdev->is_csiphy) {
+		if (p_mctl->csiphy_sdev) {
 			rc = v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
 				VIDIOC_MSM_CSIPHY_INIT, NULL);
 			if (rc < 0) {
@@ -604,7 +561,7 @@
 			}
 		}
 
-		if (camdev->is_csid) {
+		if (p_mctl->csid_sdev) {
 			rc = v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl,
 				VIDIOC_MSM_CSID_INIT, &csid_version);
 			if (rc < 0) {
@@ -612,9 +569,10 @@
 					__func__, rc);
 				goto csid_init_failed;
 			}
+			csi_info.is_csic = 0;
 		}
 
-		if (camdev->is_csic) {
+		if (p_mctl->csic_sdev) {
 			rc = v4l2_subdev_call(p_mctl->csic_sdev, core, ioctl,
 				VIDIOC_MSM_CSIC_INIT, &csid_version);
 			if (rc < 0) {
@@ -622,6 +580,16 @@
 					__func__, rc);
 				goto csic_init_failed;
 			}
+			csi_info.is_csic = 1;
+		}
+
+		csi_info.csid_version = csid_version;
+		rc = v4l2_subdev_call(p_mctl->sensor_sdev, core, ioctl,
+				VIDIOC_MSM_SENSOR_CSID_INFO, &csi_info);
+		if (rc < 0) {
+			pr_err("%s: sensor csi version failed %d\n",
+			__func__, rc);
+			goto msm_csi_version;
 		}
 
 		/* ISP first*/
@@ -655,15 +623,6 @@
 			}
 		}
 
-		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 ispif_init_failed;
-			}
-		}
 
 		pm_qos_add_request(&p_mctl->pm_qos_req_list,
 			PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
@@ -679,11 +638,6 @@
 
 	return rc;
 
-ispif_init_failed:
-	if (camdev->is_vpe)
-		if (v4l2_subdev_call(p_mctl->vpe_sdev, core, ioctl,
-			VIDIOC_MSM_VPE_RELEASE, NULL) < 0)
-			pr_err("%s: vpe release failed %d\n", __func__, rc);
 vpe_init_failed:
 	if (p_mctl->axi_sdev)
 		if (v4l2_subdev_call(p_mctl->axi_sdev, core, ioctl,
@@ -692,18 +646,19 @@
 axi_init_failed:
 	if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_release)
 		p_mctl->isp_sdev->isp_release(p_mctl, p_mctl->isp_sdev->sd);
+msm_csi_version:
 isp_open_failed:
-	if (camdev->is_csic)
+	if (p_mctl->csic_sdev)
 		if (v4l2_subdev_call(p_mctl->csic_sdev, core, ioctl,
 			VIDIOC_MSM_CSIC_RELEASE, NULL) < 0)
 			pr_err("%s: csic release failed %d\n", __func__, rc);
 csic_init_failed:
-	if (camdev->is_csid)
+	if (p_mctl->csid_sdev)
 		if (v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl,
 			VIDIOC_MSM_CSID_RELEASE, NULL) < 0)
 			pr_err("%s: csid release failed %d\n", __func__, rc);
 csid_init_failed:
-	if (camdev->is_csiphy)
+	if (p_mctl->csiphy_sdev)
 		if (v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
 			VIDIOC_MSM_CSIPHY_RELEASE, NULL) < 0)
 			pr_err("%s: csiphy release failed %d\n", __func__, rc);
@@ -733,12 +688,7 @@
 	v4l2_subdev_call(p_mctl->sensor_sdev, core, ioctl,
 		VIDIOC_MSM_SENSOR_RELEASE, NULL);
 
-	if (camdev->is_ispif) {
-		v4l2_subdev_call(p_mctl->ispif_sdev, core, ioctl,
-			VIDIOC_MSM_ISPIF_RELEASE, NULL);
-	}
-
-	if (camdev->is_csic) {
+	if (p_mctl->csic_sdev) {
 		v4l2_subdev_call(p_mctl->csic_sdev, core, ioctl,
 			VIDIOC_MSM_CSIC_RELEASE, NULL);
 	}
@@ -757,12 +707,12 @@
 		p_mctl->isp_sdev->isp_release(p_mctl,
 			p_mctl->isp_sdev->sd);
 
-	if (camdev->is_csid) {
+	if (p_mctl->csid_sdev) {
 		v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl,
 			VIDIOC_MSM_CSID_RELEASE, NULL);
 	}
 
-	if (camdev->is_csiphy) {
+	if (p_mctl->csiphy_sdev) {
 		v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
 			VIDIOC_MSM_CSIPHY_RELEASE, NULL);
 	}
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
index 135ad20..893fc06 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
@@ -1264,6 +1264,16 @@
 				vfestopped = 1;
 				spin_lock_irqsave(&vfe2x_ctrl->table_lock,
 						flags);
+				if (op_mode & SNAPSHOT_MASK_MODE) {
+					vfe2x_ctrl->stop_pending = 0;
+					vfe2x_send_isp_msg(vfe2x_ctrl,
+						msgs_map[MSG_STOP_ACK].
+						isp_id);
+					spin_unlock_irqrestore(
+							&vfe2x_ctrl->table_lock,
+							flags);
+					return 0;
+				}
 				if ((!list_empty(&vfe2x_ctrl->table_q)) ||
 						vfe2x_ctrl->tableack_pending) {
 					CDBG("stop pending\n");
diff --git a/drivers/media/video/msm/sensors/imx074_v4l2.c b/drivers/media/video/msm/sensors/imx074_v4l2.c
index 7e41418..3d23337 100644
--- a/drivers/media/video/msm/sensors/imx074_v4l2.c
+++ b/drivers/media/video/msm/sensors/imx074_v4l2.c
@@ -277,6 +277,7 @@
 	.sensor_power_up = msm_sensor_power_up,
 	.sensor_power_down = msm_sensor_power_down,
 	.sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines,
+	.sensor_get_csi_params = msm_sensor_get_csi_params,
 };
 
 static struct msm_sensor_reg_t imx074_regs = {
diff --git a/drivers/media/video/msm/sensors/imx091.c b/drivers/media/video/msm/sensors/imx091.c
index 70c3f6e..49442e9 100644
--- a/drivers/media/video/msm/sensors/imx091.c
+++ b/drivers/media/video/msm/sensors/imx091.c
@@ -304,6 +304,7 @@
 	.sensor_power_up = msm_sensor_power_up,
 	.sensor_power_down = msm_sensor_power_down,
 	.sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines,
+	.sensor_get_csi_params = msm_sensor_get_csi_params,
 };
 
 static struct msm_sensor_reg_t imx091_regs = {
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index 76981b0..8ab3963 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -246,9 +246,6 @@
 {
 	int32_t rc = 0;
 
-	v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
-		NOTIFY_ISPIF_STREAM, (void *)ISPIF_STREAM(
-		PIX_0, ISPIF_OFF_IMMEDIATELY));
 	s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
 	msleep(30);
 	if (update_type == MSM_SENSOR_REG_INIT) {
@@ -268,8 +265,6 @@
 			v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
 				NOTIFY_CSID_CFG,
 				&s_ctrl->curr_csi_params->csid_params);
-			v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
-						NOTIFY_CID_CHANGE, NULL);
 			mb();
 			v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
 				NOTIFY_CSIPHY_CFG,
@@ -281,9 +276,6 @@
 		v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
 			NOTIFY_PCLK_CHANGE, &s_ctrl->msm_sensor_reg->
 			output_settings[res].op_pixel_clk);
-		v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
-			NOTIFY_ISPIF_STREAM, (void *)ISPIF_STREAM(
-			PIX_0, ISPIF_ON_FRAME_BOUNDARY));
 		s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
 		msleep(30);
 	}
@@ -303,7 +295,7 @@
 			s_ctrl->msm_sensor_reg->
 			output_settings[res].line_length_pclk;
 
-		if (s_ctrl->sensordata->pdata->is_csic ||
+		if (s_ctrl->is_csic ||
 			!s_ctrl->sensordata->csi_if)
 			rc = s_ctrl->func_tbl->sensor_csi_setting(s_ctrl,
 				MSM_SENSOR_UPDATE_PERIODIC, res);
@@ -330,7 +322,7 @@
 		s_ctrl->curr_res = MSM_SENSOR_INVALID_RES;
 		s_ctrl->cam_mode = mode;
 
-		if (s_ctrl->sensordata->pdata->is_csic ||
+		if (s_ctrl->is_csic ||
 			!s_ctrl->sensordata->csi_if)
 			rc = s_ctrl->func_tbl->sensor_csi_setting(s_ctrl,
 				MSM_SENSOR_REG_INIT, 0);
@@ -383,11 +375,32 @@
 		return s_ctrl->func_tbl->sensor_config(s_ctrl, argp);
 	case VIDIOC_MSM_SENSOR_RELEASE:
 		return msm_sensor_release(s_ctrl);
+	case VIDIOC_MSM_SENSOR_CSID_INFO: {
+		struct msm_sensor_csi_info *csi_info =
+			(struct msm_sensor_csi_info *)arg;
+		s_ctrl->csid_version = csi_info->csid_version;
+		s_ctrl->is_csic = csi_info->is_csic;
+		return 0;
+	}
 	default:
 		return -ENOIOCTLCMD;
 	}
 }
 
+int32_t msm_sensor_get_csi_params(struct msm_sensor_ctrl_t *s_ctrl,
+		struct csi_lane_params_t *sensor_output_info)
+{
+	sensor_output_info->csi_lane_assign = s_ctrl->sensordata->
+		sensor_platform_info->csi_lane_params->csi_lane_assign;
+	sensor_output_info->csi_lane_mask = s_ctrl->sensordata->
+		sensor_platform_info->csi_lane_params->csi_lane_mask;
+	sensor_output_info->csi_if = s_ctrl->sensordata->csi_if;
+	sensor_output_info->csid_core = s_ctrl->sensordata->
+			pdata[0].csid_core;
+	sensor_output_info->csid_version = s_ctrl->csid_version;
+	return 0;
+}
+
 int32_t msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void __user *argp)
 {
 	struct sensor_cfg_data cdata;
@@ -489,6 +502,37 @@
 				rc = -EFAULT;
 			break;
 
+		case CFG_START_STREAM:
+			if (s_ctrl->func_tbl->sensor_start_stream == NULL) {
+				rc = -EFAULT;
+				break;
+			}
+			s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
+			break;
+
+		case CFG_STOP_STREAM:
+			if (s_ctrl->func_tbl->sensor_stop_stream == NULL) {
+				rc = -EFAULT;
+				break;
+			}
+			s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
+			break;
+
+		case CFG_GET_CSI_PARAMS:
+			if (s_ctrl->func_tbl->sensor_get_csi_params == NULL) {
+				rc = -EFAULT;
+				break;
+			}
+			rc = s_ctrl->func_tbl->sensor_get_csi_params(
+				s_ctrl,
+				&cdata.cfg.csi_lane_params);
+
+			if (copy_to_user((void *)argp,
+				&cdata,
+				sizeof(struct sensor_cfg_data)))
+				rc = -EFAULT;
+			break;
+
 		default:
 			rc = -EFAULT;
 			break;
diff --git a/drivers/media/video/msm/sensors/msm_sensor.h b/drivers/media/video/msm/sensors/msm_sensor.h
index 7ade827..7697a79 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.h
+++ b/drivers/media/video/msm/sensors/msm_sensor.h
@@ -137,6 +137,13 @@
 	int32_t (*sensor_match_id)(struct msm_sensor_ctrl_t *s_ctrl);
 	int (*sensor_adjust_frame_lines)
 		(struct msm_sensor_ctrl_t *s_ctrl, uint16_t res);
+	int32_t (*sensor_get_csi_params)(struct msm_sensor_ctrl_t *,
+		struct csi_lane_params_t *);
+};
+
+struct msm_sensor_csi_info {
+	uint32_t csid_version;
+	uint8_t is_csic;
 };
 
 struct msm_sensor_ctrl_t {
@@ -152,6 +159,8 @@
 	struct msm_sensor_reg_t *msm_sensor_reg;
 	struct msm_sensor_v4l2_ctrl_info_t *msm_sensor_v4l2_ctrl_info;
 	uint16_t num_v4l2_ctrl;
+	uint32_t csid_version;
+	uint8_t is_csic;
 
 	uint16_t curr_line_length_pclk;
 	uint16_t curr_frame_length_lines;
@@ -241,6 +250,9 @@
 long msm_sensor_subdev_ioctl(struct v4l2_subdev *sd,
 			unsigned int cmd, void *arg);
 
+int32_t msm_sensor_get_csi_params(struct msm_sensor_ctrl_t *s_ctrl,
+		struct csi_lane_params_t *sensor_output_info);
+
 struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd);
 
 #if defined(CONFIG_OV5647)
@@ -253,4 +265,7 @@
 #define VIDIOC_MSM_SENSOR_RELEASE \
 	_IO('V', BASE_VIDIOC_PRIVATE + 11)
 
+#define VIDIOC_MSM_SENSOR_CSID_INFO\
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 12, struct msm_sensor_csi_info *)
+
 #endif
diff --git a/drivers/media/video/msm/sensors/mt9e013_v4l2.c b/drivers/media/video/msm/sensors/mt9e013_v4l2.c
index e6e2d52..69a5498 100644
--- a/drivers/media/video/msm/sensors/mt9e013_v4l2.c
+++ b/drivers/media/video/msm/sensors/mt9e013_v4l2.c
@@ -472,6 +472,7 @@
 	.sensor_config = msm_sensor_config,
 	.sensor_power_up = msm_sensor_power_up,
 	.sensor_power_down = msm_sensor_power_down,
+	.sensor_get_csi_params = msm_sensor_get_csi_params,
 };
 
 static struct msm_sensor_reg_t mt9e013_regs = {
diff --git a/drivers/media/video/msm/sensors/mt9m114_v4l2.c b/drivers/media/video/msm/sensors/mt9m114_v4l2.c
index 2184806..806bcc2 100644
--- a/drivers/media/video/msm/sensors/mt9m114_v4l2.c
+++ b/drivers/media/video/msm/sensors/mt9m114_v4l2.c
@@ -1268,6 +1268,7 @@
 	.sensor_config = msm_sensor_config,
 	.sensor_power_up = msm_sensor_power_up,
 	.sensor_power_down = msm_sensor_power_down,
+	.sensor_get_csi_params = msm_sensor_get_csi_params,
 };
 
 static struct msm_sensor_reg_t mt9m114_regs = {
diff --git a/drivers/media/video/msm/sensors/ov2720.c b/drivers/media/video/msm/sensors/ov2720.c
index 40867fb..03f1af1 100644
--- a/drivers/media/video/msm/sensors/ov2720.c
+++ b/drivers/media/video/msm/sensors/ov2720.c
@@ -784,6 +784,7 @@
 	.sensor_power_up = msm_sensor_power_up,
 	.sensor_power_down = msm_sensor_power_down,
 	.sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines,
+	.sensor_get_csi_params = msm_sensor_get_csi_params,
 };
 
 static struct msm_sensor_reg_t ov2720_regs = {
diff --git a/drivers/media/video/msm/sensors/ov5647_v4l2.c b/drivers/media/video/msm/sensors/ov5647_v4l2.c
index 9dfbf8d..eab0899 100644
--- a/drivers/media/video/msm/sensors/ov5647_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov5647_v4l2.c
@@ -815,6 +815,7 @@
 	.sensor_config = msm_sensor_config,
 	.sensor_power_up = ov5647_sensor_power_up,
 	.sensor_power_down = ov5647_sensor_power_down,
+	.sensor_get_csi_params = msm_sensor_get_csi_params,
 };
 
 static struct msm_sensor_reg_t ov5647_regs = {
diff --git a/drivers/media/video/msm/sensors/ov7692_v4l2.c b/drivers/media/video/msm/sensors/ov7692_v4l2.c
index 8c94e3b..a6af770 100644
--- a/drivers/media/video/msm/sensors/ov7692_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov7692_v4l2.c
@@ -909,6 +909,7 @@
 	.sensor_config = msm_sensor_config,
 	.sensor_power_up = ov7692_sensor_power_up,
 	.sensor_power_down = ov7692_sensor_power_down,
+	.sensor_get_csi_params = msm_sensor_get_csi_params,
 };
 
 static struct msm_sensor_reg_t ov7692_regs = {
diff --git a/drivers/media/video/msm/sensors/ov9726_v4l2.c b/drivers/media/video/msm/sensors/ov9726_v4l2.c
index 61c693e..27a8b38 100644
--- a/drivers/media/video/msm/sensors/ov9726_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov9726_v4l2.c
@@ -236,6 +236,7 @@
 	.sensor_config = msm_sensor_config,
 	.sensor_power_up = msm_sensor_power_up,
 	.sensor_power_down = msm_sensor_power_down,
+	.sensor_get_csi_params = msm_sensor_get_csi_params,
 };
 
 static struct msm_sensor_reg_t ov9726_regs = {
diff --git a/drivers/media/video/msm/sensors/s5k3l1yx.c b/drivers/media/video/msm/sensors/s5k3l1yx.c
index 1d7da0d..d7aeb74 100644
--- a/drivers/media/video/msm/sensors/s5k3l1yx.c
+++ b/drivers/media/video/msm/sensors/s5k3l1yx.c
@@ -653,6 +653,7 @@
 	.sensor_power_up = msm_sensor_power_up,
 	.sensor_power_down = msm_sensor_power_down,
 	.sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines,
+	.sensor_get_csi_params = msm_sensor_get_csi_params,
 };
 
 static struct msm_sensor_reg_t s5k3l1yx_regs = {
diff --git a/drivers/media/video/msm/sensors/s5k4e1_v4l2.c b/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
index 2d25824..e90390e 100644
--- a/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
+++ b/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
@@ -487,6 +487,7 @@
 	.sensor_config = msm_sensor_config,
 	.sensor_power_up = msm_sensor_power_up,
 	.sensor_power_down = msm_sensor_power_down,
+	.sensor_get_csi_params = msm_sensor_get_csi_params,
 };
 
 static struct msm_sensor_reg_t s5k4e1_regs = {
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index cb59737..fc1e713 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -1365,9 +1365,7 @@
 	struct msm_camera_device_platform_data *camdev;
 	uint8_t csid_core = 0;
 
-	if (notification == NOTIFY_CID_CHANGE ||
-		notification == NOTIFY_ISPIF_STREAM ||
-		notification == NOTIFY_PCLK_CHANGE ||
+	if (notification == NOTIFY_PCLK_CHANGE ||
 		notification == NOTIFY_CSIPHY_CFG ||
 		notification == NOTIFY_CSID_CFG ||
 		notification == NOTIFY_CSIC_CFG) {
@@ -1378,30 +1376,6 @@
 	}
 
 	switch (notification) {
-	case NOTIFY_CID_CHANGE:
-		/* reconfig the ISPIF*/
-		if (g_server_dev.ispif_device) {
-			struct msm_ispif_params_list ispif_params;
-			ispif_params.len = 1;
-			ispif_params.params[0].intftype = PIX0;
-			ispif_params.params[0].cid_mask = 0x0001;
-			ispif_params.params[0].csid = csid_core;
-
-			rc = v4l2_subdev_call(
-				g_server_dev.ispif_device, core, ioctl,
-				VIDIOC_MSM_ISPIF_CFG, &ispif_params);
-			if (rc < 0)
-				return;
-		}
-		break;
-	case NOTIFY_ISPIF_STREAM:
-		/* call ISPIF stream on/off */
-		rc = v4l2_subdev_call(g_server_dev.ispif_device, video,
-				s_stream, (int)arg);
-		if (rc < 0)
-			return;
-
-		break;
 	case NOTIFY_ISP_MSG_EVT:
 	case NOTIFY_VFE_MSG_OUT:
 	case NOTIFY_VFE_MSG_STATS:
diff --git a/drivers/media/video/msm_vidc/vidc_hal.c b/drivers/media/video/msm_vidc/vidc_hal.c
index 1f33c2c..13a319d9 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.c
+++ b/drivers/media/video/msm_vidc/vidc_hal.c
@@ -84,8 +84,8 @@
 	{
 		struct hfi_cmd_session_release_buffer_packet *pkt =
 			(struct hfi_cmd_session_release_buffer_packet *)packet;
-		if ((pkt->buffer_type == HAL_BUFFER_OUTPUT) ||
-			(pkt->buffer_type == HAL_BUFFER_OUTPUT2)) {
+		if ((pkt->buffer_type == HFI_BUFFER_OUTPUT) ||
+			(pkt->buffer_type == HFI_BUFFER_OUTPUT2)) {
 			struct hfi_buffer_info *buff;
 			buff = (struct hfi_buffer_info *) pkt->rg_buffer_info;
 			buff->buffer_addr -= HFI_VIRTIO_FW_BIAS;
@@ -824,8 +824,7 @@
 	}
 
 	HAL_MSG_INFO("IN func: %s, with property id: %d", __func__, ptype);
-	pkt->size = sizeof(struct hfi_cmd_session_set_property_packet)
-		- sizeof(u32);
+	pkt->size = sizeof(struct hfi_cmd_session_set_property_packet);
 	pkt->packet_type = HFI_CMD_SESSION_SET_PROPERTY;
 	pkt->session_id = (u32) session;
 	pkt->num_properties = 1;
diff --git a/drivers/media/video/msm_vidc/vidc_hal.h b/drivers/media/video/msm_vidc/vidc_hal.h
index 166ed0d..15441f4 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.h
+++ b/drivers/media/video/msm_vidc/vidc_hal.h
@@ -1153,7 +1153,7 @@
 	enum HFI_COMMAND packet_type;
 	u32 session_id;
 	u32 num_properties;
-	u32 rg_property_data[1];
+	u32 rg_property_data[0];
 };
 
 struct hfi_cmd_session_get_property_packet {
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index eba80c5..e9ccbc7 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -4940,9 +4940,10 @@
 	mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
 	mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
 	mmc->ocr_avail = plat->ocr_mask;
+	mmc->clkgate_delay = MSM_MMC_CLK_GATE_DELAY;
+
 	mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
 	mmc->caps |= plat->mmc_bus_width;
-
 	mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
 	mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
 
@@ -5404,6 +5405,49 @@
 #endif
 
 #ifdef CONFIG_PM
+#ifdef CONFIG_MMC_CLKGATE
+static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
+{
+	struct mmc_host *mmc = host->mmc;
+	unsigned long flags;
+
+	mmc_host_clk_hold(mmc);
+	spin_lock_irqsave(&mmc->clk_lock, flags);
+	mmc->clk_old = mmc->ios.clock;
+	mmc->ios.clock = 0;
+	mmc->clk_gated = true;
+	spin_unlock_irqrestore(&mmc->clk_lock, flags);
+	mmc_set_ios(mmc);
+	mmc_host_clk_release(mmc);
+}
+
+static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
+{
+	struct mmc_host *mmc = host->mmc;
+
+	mmc_host_clk_hold(mmc);
+	mmc->ios.clock = host->clk_rate;
+	mmc_set_ios(mmc);
+	mmc_host_clk_release(mmc);
+}
+#else
+static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
+{
+	struct mmc_host *mmc = host->mmc;
+
+	mmc->ios.clock = 0;
+	mmc_set_ios(mmc);
+}
+
+static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
+{
+	struct mmc_host *mmc = host->mmc;
+
+	mmc->ios.clock = host->clk_rate;
+	mmc_set_ios(mmc);
+}
+#endif
+
 static int
 msmsdcc_runtime_suspend(struct device *dev)
 {
@@ -5450,21 +5494,12 @@
 			spin_unlock_irqrestore(&host->lock, flags);
 			if (mmc->card && mmc_card_sdio(mmc->card) &&
 				mmc->ios.clock) {
-#ifdef CONFIG_MMC_CLKGATE
 				/*
 				 * If SDIO function driver doesn't want
 				 * to power off the card, atleast turn off
 				 * clocks to allow deep sleep (TCXO shutdown).
 				 */
-				mmc_host_clk_hold(mmc);
-				spin_lock_irqsave(&mmc->clk_lock, flags);
-				mmc->clk_old = mmc->ios.clock;
-				mmc->ios.clock = 0;
-				mmc->clk_gated = true;
-				spin_unlock_irqrestore(&mmc->clk_lock, flags);
-				mmc_set_ios(mmc);
-				mmc_host_clk_release(mmc);
-#endif
+				msmsdcc_gate_clock(host);
 			}
 		}
 		host->sdcc_suspending = 0;
@@ -5493,10 +5528,7 @@
 	if (mmc) {
 		if (mmc->card && mmc_card_sdio(mmc->card) &&
 				mmc_card_keep_power(mmc)) {
-			mmc_host_clk_hold(mmc);
-			mmc->ios.clock = host->clk_rate;
-			mmc_set_ios(mmc);
-			mmc_host_clk_release(mmc);
+			msmsdcc_ungate_clock(host);
 		}
 
 		mmc_resume_host(mmc);
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index 2222337..5531f06 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -212,10 +212,10 @@
 #define NR_SG		128
 
 #define MSM_MMC_IDLE_TIMEOUT	5000 /* msecs */
+#define MSM_MMC_CLK_GATE_DELAY	200 /* msecs */
 
 /* Set the request timeout to 10secs */
 #define MSM_MMC_REQ_TIMEOUT	10000 /* msecs */
-#define MSM_MMC_DISABLE_TIMEOUT        200 /* msecs */
 
 /*
  * Controller HW limitations
diff --git a/drivers/net/usb/rmnet_usb_ctrl.c b/drivers/net/usb/rmnet_usb_ctrl.c
index 23ba900..c2085c9 100644
--- a/drivers/net/usb/rmnet_usb_ctrl.c
+++ b/drivers/net/usb/rmnet_usb_ctrl.c
@@ -174,6 +174,8 @@
 			goto resubmit_int_urb;
 		}
 
+		usb_mark_last_busy(udev);
+
 		if (!dev->resp_available) {
 			dev->resp_available = true;
 			wake_up(&dev->open_wait_queue);
@@ -261,6 +263,7 @@
 
 resubmit_int_urb:
 	/*re-submit int urb to check response available*/
+	usb_mark_last_busy(udev);
 	status = usb_submit_urb(dev->inturb, GFP_ATOMIC);
 	if (status)
 		dev_err(dev->devicep, "%s: Error re-submitting Int URB %d\n",
@@ -796,6 +799,7 @@
 			 dev->intbuf, wMaxPacketSize,
 			 notification_available_cb, dev, interval);
 
+	usb_mark_last_busy(udev);
 	return rmnet_usb_ctrl_start_rx(dev);
 }
 
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index 23efb00..15e7f3f 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -13,7 +13,8 @@
 config SPS
 	bool "SPS support"
 	depends on (HAS_IOMEM && (ARCH_MSM8960 || ARCH_MSM8X60 \
-			|| ARCH_APQ8064 || ARCH_MSM9615 || ARCH_MSMCOPPER))
+			|| ARCH_APQ8064 || ARCH_MSM9615 \
+			|| ARCH_MSM9625 || ARCH_MSMCOPPER))
 	select GENERIC_ALLOCATOR
 	default n
 	help
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index fbaea09..1329f6c 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -79,6 +79,8 @@
  */
 static struct sps_drv *sps;
 
+u32 d_type;
+
 static void sps_device_de_init(void);
 
 #ifdef CONFIG_DEBUG_FS
@@ -1443,11 +1445,6 @@
 {
 	SPS_DBG("sps:%s.", __func__);
 
-	if (h == NULL) {
-		SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
-		return SPS_ERROR;
-	}
-
 	if (sps == NULL)
 		return -ENODEV;
 
@@ -1461,6 +1458,11 @@
 		return SPS_ERROR;
 	}
 
+	if (h == NULL)
+		SPS_DBG("sps:allocate pipe memory before setup pipe");
+	else
+		SPS_DBG("sps:allocate pipe memory for pipe %d", h->pipe_index);
+
 	mem_buffer->phys_base = sps_mem_alloc_io(mem_buffer->size);
 	if (mem_buffer->phys_base == SPS_ADDR_INVALID) {
 		SPS_ERR("sps:invalid address of allocated memory");
@@ -1481,16 +1483,16 @@
 {
 	SPS_DBG("sps:%s.", __func__);
 
-	if (h == NULL) {
-		SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
-		return SPS_ERROR;
-	}
-
 	if (mem_buffer == NULL || mem_buffer->phys_base == SPS_ADDR_INVALID) {
 		SPS_ERR("sps:invalid memory to free");
 		return SPS_ERROR;
 	}
 
+	if (h == NULL)
+		SPS_DBG("sps:free pipe memory.");
+	else
+		SPS_DBG("sps:free pipe memory for pipe %d.", h->pipe_index);
+
 	sps_mem_free_io(mem_buffer->phys_base, mem_buffer->size);
 
 	return 0;
@@ -1928,13 +1930,20 @@
 
 	if (of_property_read_u32((&pdev->dev)->of_node,
 				"qcom,bam-dma-res-pipes",
-				&sps->bamdma_restricted_pipes)) {
-		SPS_ERR("sps:Fail to get restricted bamdma pipes.\n");
-		return -EINVAL;
-	} else
+				&sps->bamdma_restricted_pipes))
+		SPS_DBG("sps:No restricted bamdma pipes on this target.\n");
+	else
 		SPS_DBG("sps:bamdma_restricted_pipes=0x%x.",
 			sps->bamdma_restricted_pipes);
 
+	if (of_property_read_u32((&pdev->dev)->of_node,
+				"qcom,device-type",
+				&d_type)) {
+		d_type = 1;
+		SPS_DBG("sps:default device type.\n");
+	} else
+		SPS_DBG("sps:device type is %d.", d_type);
+
 	resource  = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (resource) {
 		sps->bamdma_bam_phys_base = resource->start;
@@ -1959,6 +1968,16 @@
 		return -ENODEV;
 	}
 
+	resource = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	if (resource) {
+		sps->pipemem_phys_base = resource->start;
+		sps->pipemem_size = resource_size(resource);
+		SPS_DBG("sps:pipemem.base=0x%x,size=0x%x.",
+			sps->pipemem_phys_base,
+			sps->pipemem_size);
+	} else
+		SPS_DBG("sps:No pipe memory on this target.\n");
+
 	resource  = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (resource) {
 		sps->bamdma_irq = resource->start;
@@ -1985,6 +2004,7 @@
 		} else
 			SPS_DBG("sps:get data from device tree.");
 	} else {
+		d_type = 0;
 		if (get_platform_data(pdev)) {
 			SPS_ERR("sps:Fail to get platform data.");
 			return -ENODEV;
@@ -2008,17 +2028,18 @@
 		goto device_create_err;
 	}
 
-	sps->dfab_clk = clk_get(sps->dev, "dfab_clk");
-	if (IS_ERR(sps->dfab_clk)) {
-		SPS_ERR("sps:fail to get dfab_clk.");
-		goto clk_err;
-	} else {
-		ret = clk_set_rate(sps->dfab_clk, 64000000);
-		if (ret) {
-			SPS_ERR("sps:failed to set dfab_clk rate. "
-					"ret=%d", ret);
-			clk_put(sps->dfab_clk);
+	if (!d_type) {
+		sps->dfab_clk = clk_get(sps->dev, "dfab_clk");
+		if (IS_ERR(sps->dfab_clk)) {
+			SPS_ERR("sps:fail to get dfab_clk.");
 			goto clk_err;
+		} else {
+			ret = clk_set_rate(sps->dfab_clk, 64000000);
+			if (ret) {
+				SPS_ERR("sps:failed to set dfab_clk rate.");
+				clk_put(sps->dfab_clk);
+				goto clk_err;
+			}
 		}
 	}
 
@@ -2047,22 +2068,26 @@
 		}
 	}
 
-	ret = clk_prepare_enable(sps->dfab_clk);
-	if (ret) {
-		SPS_ERR("sps:failed to enable dfab_clk. ret=%d", ret);
-		goto clk_err;
+	if (!d_type) {
+		ret = clk_prepare_enable(sps->dfab_clk);
+		if (ret) {
+			SPS_ERR("sps:failed to enable dfab_clk. ret=%d", ret);
+			goto clk_err;
+		}
 	}
 #endif
 	ret = sps_device_init();
 	if (ret) {
 		SPS_ERR("sps:sps_device_init err.");
 #ifdef CONFIG_SPS_SUPPORT_BAMDMA
-		clk_disable_unprepare(sps->dfab_clk);
+		if (!d_type)
+			clk_disable_unprepare(sps->dfab_clk);
 #endif
 		goto sps_device_init_err;
 	}
 #ifdef CONFIG_SPS_SUPPORT_BAMDMA
-	clk_disable_unprepare(sps->dfab_clk);
+	if (!d_type)
+		clk_disable_unprepare(sps->dfab_clk);
 #endif
 	sps->is_ready = true;
 
@@ -2089,7 +2114,8 @@
 	class_destroy(sps->dev_class);
 	sps_device_de_init();
 
-	clk_put(sps->dfab_clk);
+	if (!d_type)
+		clk_put(sps->dfab_clk);
 	clk_put(sps->pmem_clk);
 	clk_put(sps->bamdma_clk);
 
diff --git a/drivers/platform/msm/sps/sps_mem.c b/drivers/platform/msm/sps/sps_mem.c
index 1b19b12..fa22f1c 100644
--- a/drivers/platform/msm/sps/sps_mem.c
+++ b/drivers/platform/msm/sps/sps_mem.c
@@ -104,31 +104,30 @@
  */
 int sps_mem_init(u32 pipemem_phys_base, u32 pipemem_size)
 {
-#ifndef CONFIG_SPS_SUPPORT_NDP_BAM
 	int res;
-#endif
+
 	/* 2^8=128. The desc-fifo and data-fifo minimal allocation. */
 	int min_alloc_order = 8;
 
-#ifndef CONFIG_SPS_SUPPORT_NDP_BAM
-	iomem_phys = pipemem_phys_base;
-	iomem_size = pipemem_size;
+	if ((d_type == 0) || (d_type == 2)) {
+		iomem_phys = pipemem_phys_base;
+		iomem_size = pipemem_size;
 
-	if (iomem_phys == 0) {
-		SPS_ERR("sps:Invalid Pipe-Mem address");
-		return SPS_ERROR;
-	} else {
-		iomem_virt = ioremap(iomem_phys, iomem_size);
-		if (!iomem_virt) {
-			SPS_ERR("sps:Failed to IO map pipe memory.\n");
-			return -ENOMEM;
+		if (iomem_phys == 0) {
+			SPS_ERR("sps:Invalid Pipe-Mem address");
+			return SPS_ERROR;
+		} else {
+			iomem_virt = ioremap(iomem_phys, iomem_size);
+			if (!iomem_virt) {
+				SPS_ERR("sps:Failed to IO map pipe memory.\n");
+				return -ENOMEM;
+			}
 		}
-	}
 
-	iomem_offset = 0;
-	SPS_DBG("sps:sps_mem_init.iomem_phys=0x%x,iomem_virt=0x%x.",
-		iomem_phys, (u32) iomem_virt);
-#endif
+		iomem_offset = 0;
+		SPS_DBG("sps:sps_mem_init.iomem_phys=0x%x,iomem_virt=0x%x.",
+			iomem_phys, (u32) iomem_virt);
+	}
 
 	pool = gen_pool_create(min_alloc_order, nid);
 
@@ -137,11 +136,11 @@
 		return -ENOMEM;
 	}
 
-#ifndef CONFIG_SPS_SUPPORT_NDP_BAM
-	res = gen_pool_add(pool, (u32) iomem_virt, iomem_size, nid);
-	if (res)
-		return res;
-#endif
+	if ((d_type == 0) || (d_type == 2)) {
+		res = gen_pool_add(pool, (u32) iomem_virt, iomem_size, nid);
+		if (res)
+			return res;
+	}
 
 	return 0;
 }
diff --git a/drivers/platform/msm/sps/spsi.h b/drivers/platform/msm/sps/spsi.h
index e8ab832..5a141ca 100644
--- a/drivers/platform/msm/sps/spsi.h
+++ b/drivers/platform/msm/sps/spsi.h
@@ -40,6 +40,8 @@
 /* "Clear" value for the connection parameter struct */
 #define SPSRM_CLEAR     0xcccccccc
 
+extern u32 d_type;
+
 #ifdef CONFIG_DEBUG_FS
 extern u8 debugfs_record_enabled;
 extern u8 logging_option;
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index b0439bc..73c042d 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -100,8 +100,6 @@
 	struct sf_lut		*rbatt_sf_lut;
 	int			delta_rbatt_mohm;
 	struct work_struct	calib_hkadc_work;
-	struct delayed_work	calib_ccadc_work;
-	unsigned int		calib_delay_ms;
 	unsigned int		revision;
 	unsigned int		xoadc_v0625_usb_present;
 	unsigned int		xoadc_v0625_usb_absent;
@@ -1604,18 +1602,6 @@
 	schedule_work(&the_chip->calib_hkadc_work);
 }
 
-static void calibrate_ccadc_work(struct work_struct *work)
-{
-	struct pm8921_bms_chip *chip = container_of(work,
-				struct pm8921_bms_chip, calib_ccadc_work.work);
-
-	pm8xxx_calib_ccadc();
-	calib_hkadc(chip);
-	schedule_delayed_work(&chip->calib_ccadc_work,
-			round_jiffies_relative(msecs_to_jiffies
-			(chip->calib_delay_ms)));
-}
-
 int pm8921_bms_get_vsense_avg(int *result)
 {
 	int rc = -EINVAL;
@@ -2601,7 +2587,6 @@
 	chip->r_sense = pdata->r_sense;
 	chip->i_test = pdata->i_test;
 	chip->v_failure = pdata->v_failure;
-	chip->calib_delay_ms = pdata->calib_delay_ms;
 	chip->max_voltage_uv = pdata->max_voltage_uv;
 	chip->batt_type = pdata->battery_type;
 	chip->rconn_mohm = pdata->rconn_mohm;
@@ -2655,11 +2640,6 @@
 	}
 	check_initial_ocv(chip);
 
-	INIT_DELAYED_WORK(&chip->calib_ccadc_work, calibrate_ccadc_work);
-	/* begin calibration only on chips > 2.0 */
-	if (chip->revision >= PM8XXX_REVISION_8921_2p0)
-		schedule_delayed_work(&chip->calib_ccadc_work, 0);
-
 	/* initial hkadc calibration */
 	schedule_work(&chip->calib_hkadc_work);
 	/* enable the vbatt reading interrupts for scheduling hkadc calib */
diff --git a/drivers/power/pm8xxx-ccadc.c b/drivers/power/pm8xxx-ccadc.c
index ce72a5b..ef31575 100644
--- a/drivers/power/pm8xxx-ccadc.c
+++ b/drivers/power/pm8xxx-ccadc.c
@@ -70,8 +70,10 @@
 	u16			ccadc_offset;
 	int			ccadc_gain_uv;
 	unsigned int		revision;
+	unsigned int		calib_delay_ms;
 	int			eoc_irq;
 	int			r_sense;
+	struct delayed_work	calib_ccadc_work;
 };
 
 static struct pm8xxx_ccadc_chip *the_chip;
@@ -334,6 +336,11 @@
 	u16 result;
 	int i, rc;
 
+	if (!the_chip) {
+		pr_err("chip not initialized\n");
+		return;
+	}
+
 	rc = pm8xxx_readb(the_chip->dev->parent,
 					ADC_ARB_SECP_CNTRL, &sec_cntrl);
 	if (rc < 0) {
@@ -473,6 +480,17 @@
 }
 EXPORT_SYMBOL(pm8xxx_calib_ccadc);
 
+static void calibrate_ccadc_work(struct work_struct *work)
+{
+	struct pm8xxx_ccadc_chip *chip = container_of(work,
+			struct pm8xxx_ccadc_chip, calib_ccadc_work.work);
+
+	pm8xxx_calib_ccadc();
+	schedule_delayed_work(&chip->calib_ccadc_work,
+			round_jiffies_relative(msecs_to_jiffies
+			(chip->calib_delay_ms)));
+}
+
 static irqreturn_t pm8921_bms_ccadc_eoc_handler(int irq, void *data)
 {
 	u8 data_msb, data_lsb;
@@ -671,6 +689,7 @@
 	chip->revision = pm8xxx_get_revision(chip->dev->parent);
 	chip->eoc_irq = res->start;
 	chip->r_sense = pdata->r_sense;
+	chip->calib_delay_ms = pdata->calib_delay_ms;
 
 	calib_ccadc_read_offset_and_gain(chip,
 					&chip->ccadc_gain_uv,
@@ -682,6 +701,10 @@
 		pr_err("failed to request %d irq rc= %d\n", chip->eoc_irq, rc);
 		goto free_chip;
 	}
+
+	INIT_DELAYED_WORK(&chip->calib_ccadc_work, calibrate_ccadc_work);
+	schedule_delayed_work(&chip->calib_ccadc_work, 0);
+
 	disable_irq_nosync(chip->eoc_irq);
 
 	platform_set_drvdata(pdev, chip);
diff --git a/drivers/power/smb349.c b/drivers/power/smb349.c
index 4c07285..ffc92d5 100644
--- a/drivers/power/smb349.c
+++ b/drivers/power/smb349.c
@@ -86,11 +86,11 @@
 
 	int			en_n_gpio;
 	int			chg_susp_gpio;
-	struct dentry			*dent;
-	spinlock_t			lock;
-	struct work_struct			hwinit_work;
+	struct dentry		*dent;
+	spinlock_t		lock;
 
-	struct power_supply			dc_psy;
+	struct work_struct	chg_work;
+	struct power_supply	dc_psy;
 };
 
 struct chg_ma_limit_entry {
@@ -244,7 +244,7 @@
 {
 	int addr = (int)data;
 	int ret;
-	u8 temp;
+	u8 temp = 0;
 
 	ret = smb349_read_reg(the_smb349_chg->client, addr, &temp);
 	if (ret) {
@@ -445,16 +445,17 @@
 static int smb349_stop_charging(struct smb349_struct *smb349_chg)
 {
 	unsigned long flags;
-
-	if (smb349_chg->charging)
-		gpio_set_value_cansleep(smb349_chg->en_n_gpio, 0);
+	int rc = 0;
 
 	spin_lock_irqsave(&smb349_chg->lock, flags);
 	pr_debug("stop charging %d\n", smb349_chg->charging);
 	smb349_chg->charging = 0;
 	spin_unlock_irqrestore(&smb349_chg->lock, flags);
-	power_supply_changed(&smb349_chg->dc_psy);
-	return 0;
+
+	if (smb349_chg->charging)
+		rc = schedule_work(&smb349_chg->chg_work);
+
+	return rc;
 }
 
 static int smb349_start_charging(struct smb349_struct *smb349_chg)
@@ -463,21 +464,14 @@
 	int rc;
 
 	rc = 0;
-	if (!smb349_chg->charging) {
-		gpio_set_value_cansleep(smb349_chg->en_n_gpio, 1);
-		/*
-		 * Write non-default values, charger chip reloads from
-		 * non-volatile memory if it was in suspend mode
-		 *
-		 */
-		rc = schedule_work(&smb349_chg->hwinit_work);
-	}
-
 	spin_lock_irqsave(&smb349_chg->lock, flags);
 	pr_debug("start charging %d\n", smb349_chg->charging);
 	smb349_chg->charging = 1;
 	spin_unlock_irqrestore(&smb349_chg->lock, flags);
-	power_supply_changed(&smb349_chg->dc_psy);
+
+	if (!smb349_chg->charging)
+		rc = schedule_work(&smb349_chg->chg_work);
+
 	return rc;
 }
 
@@ -522,15 +516,25 @@
 	return 0;
 }
 
-static void hwinit_worker(struct work_struct *work)
+static void chg_worker(struct work_struct *work)
 {
-	int ret;
 	struct smb349_struct *smb349_chg = container_of(work,
-				struct smb349_struct, hwinit_work);
+				struct smb349_struct, chg_work);
+	int ret = 0;
 
-	ret = smb349_hwinit(smb349_chg);
+	gpio_set_value_cansleep(smb349_chg->en_n_gpio, smb349_chg->charging);
+
+	/*
+	 * Write non-default values, charger chip reloads from
+	 * non-volatile memory if it was in suspend mode
+	 *
+	 */
+	if (smb349_chg->charging)
+		ret = smb349_hwinit(smb349_chg);
 	if (ret)
 		pr_err("Failed to re-initilaze registers\n");
+
+	power_supply_changed(&smb349_chg->dc_psy);
 }
 
 static int __devinit smb349_init_ext_chg(struct smb349_struct *smb349_chg)
@@ -614,7 +618,7 @@
 	the_smb349_chg = smb349_chg;
 
 	create_debugfs_entries(smb349_chg);
-	INIT_WORK(&smb349_chg->hwinit_work, hwinit_worker);
+	INIT_WORK(&smb349_chg->chg_work, chg_worker);
 
 	pr_info("OK connector present = %d\n", smb349_chg->present);
 	return 0;
@@ -634,7 +638,7 @@
 	const struct smb349_platform_data *pdata;
 	struct smb349_struct *smb349_chg = i2c_get_clientdata(client);
 
-	flush_work(&smb349_chg->hwinit_work);
+	flush_work(&smb349_chg->chg_work);
 	pdata = client->dev.platform_data;
 	power_supply_unregister(&smb349_chg->dc_psy);
 	gpio_free(pdata->en_n_gpio);
diff --git a/drivers/tty/n_smux.c b/drivers/tty/n_smux.c
index 65bcb08..d03b4b4 100644
--- a/drivers/tty/n_smux.c
+++ b/drivers/tty/n_smux.c
@@ -78,6 +78,11 @@
 			pr_info(x);  \
 } while (0)
 
+#define SMUX_PWR(x...) do {                              \
+	if (smux_debug_mask & MSM_SMUX_POWER_INFO) \
+			pr_info(x);  \
+} while (0)
+
 #define SMUX_LOG_PKT_RX(pkt) do { \
 	if (smux_debug_mask & MSM_SMUX_PKT) \
 			smux_log_pkt(pkt, 1); \
@@ -448,6 +453,7 @@
 		pkt =  list_first_entry(&smux.power_queue,
 						struct smux_pkt_t,
 						list);
+		list_del(&pkt->list);
 		SMUX_DBG("%s: emptying power queue pkt=%p\n",
 				__func__, pkt);
 		smux_free_pkt(pkt);
@@ -1005,7 +1011,6 @@
 	pkt->hdr.cmd = SMUX_CMD_BYTE;
 	pkt->hdr.flags = ch;
 	pkt->hdr.lcid = SMUX_BROADCAST_LCID;
-	pkt->hdr.flags = ch;
 
 	list_add_tail(&pkt->list, &smux.power_queue);
 	queue_work(smux_tx_wq, &smux_tx_work);
@@ -1601,7 +1606,7 @@
 		/* local sleep request ack */
 		if (smux.power_state == SMUX_PWR_TURNING_OFF) {
 			/* Power-down complete, turn off UART */
-			SMUX_DBG("%s: Power %d->%d\n", __func__,
+			SMUX_PWR("%s: Power %d->%d\n", __func__,
 					smux.power_state, SMUX_PWR_OFF_FLUSH);
 			smux.power_state = SMUX_PWR_OFF_FLUSH;
 			queue_work(smux_tx_wq, &smux_inactivity_work);
@@ -1625,7 +1630,7 @@
 			|| smux.power_state == SMUX_PWR_TURNING_OFF) {
 			ack_pkt = smux_alloc_pkt();
 			if (ack_pkt) {
-				SMUX_DBG("%s: Power %d->%d\n", __func__,
+				SMUX_PWR("%s: Power %d->%d\n", __func__,
 						smux.power_state,
 						SMUX_PWR_TURNING_OFF_FLUSH);
 
@@ -1658,24 +1663,44 @@
  */
 static int smux_dispatch_rx_pkt(struct smux_pkt_t *pkt)
 {
-	int ret;
+	int ret = -ENXIO;
 
 	SMUX_LOG_PKT_RX(pkt);
 
 	switch (pkt->hdr.cmd) {
 	case SMUX_CMD_OPEN_LCH:
+		if (smux_assert_lch_id(pkt->hdr.lcid)) {
+			pr_err("%s: invalid channel id %d\n",
+					__func__, pkt->hdr.lcid);
+			break;
+		}
 		ret = smux_handle_rx_open_cmd(pkt);
 		break;
 
 	case SMUX_CMD_DATA:
+		if (smux_assert_lch_id(pkt->hdr.lcid)) {
+			pr_err("%s: invalid channel id %d\n",
+					__func__, pkt->hdr.lcid);
+			break;
+		}
 		ret = smux_handle_rx_data_cmd(pkt);
 		break;
 
 	case SMUX_CMD_CLOSE_LCH:
+		if (smux_assert_lch_id(pkt->hdr.lcid)) {
+			pr_err("%s: invalid channel id %d\n",
+					__func__, pkt->hdr.lcid);
+			break;
+		}
 		ret = smux_handle_rx_close_cmd(pkt);
 		break;
 
 	case SMUX_CMD_STATUS:
+		if (smux_assert_lch_id(pkt->hdr.lcid)) {
+			pr_err("%s: invalid channel id %d\n",
+					__func__, pkt->hdr.lcid);
+			break;
+		}
 		ret = smux_handle_rx_status_cmd(pkt);
 		break;
 
@@ -1705,7 +1730,6 @@
 static int smux_deserialize(unsigned char *data, int len)
 {
 	struct smux_pkt_t recv;
-	uint8_t lcid;
 
 	smux_init_pkt(&recv);
 
@@ -1720,12 +1744,6 @@
 		return -EINVAL;
 	}
 
-	lcid = recv.hdr.lcid;
-	if (smux_assert_lch_id(lcid)) {
-		pr_err("%s: invalid channel id %d\n", __func__, lcid);
-		return -ENXIO;
-	}
-
 	if (recv.hdr.payload_len)
 		recv.payload = data + sizeof(struct smux_hdr_t);
 
@@ -1743,7 +1761,7 @@
 	if (smux.power_state == SMUX_PWR_OFF
 		|| smux.power_state == SMUX_PWR_TURNING_ON) {
 		/* wakeup system */
-		SMUX_DBG("%s: Power %d->%d\n", __func__,
+		SMUX_PWR("%s: Power %d->%d\n", __func__,
 				smux.power_state, SMUX_PWR_ON);
 		smux.power_state = SMUX_PWR_ON;
 		queue_work(smux_tx_wq, &smux_wakeup_work);
@@ -1767,7 +1785,7 @@
 	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
 	if (smux.power_state == SMUX_PWR_TURNING_ON) {
 		/* received response to wakeup request */
-		SMUX_DBG("%s: Power %d->%d\n", __func__,
+		SMUX_PWR("%s: Power %d->%d\n", __func__,
 				smux.power_state, SMUX_PWR_ON);
 		smux.power_state = SMUX_PWR_ON;
 		queue_work(smux_tx_wq, &smux_tx_work);
@@ -2201,7 +2219,7 @@
 				/* start power-down sequence */
 				pkt = smux_alloc_pkt();
 				if (pkt) {
-					SMUX_DBG("%s: Power %d->%d\n", __func__,
+					SMUX_PWR("%s: Power %d->%d\n", __func__,
 						smux.power_state,
 						SMUX_PWR_TURNING_OFF);
 					smux.power_state = SMUX_PWR_TURNING_OFF;
@@ -2228,9 +2246,9 @@
 
 	if (smux.power_state == SMUX_PWR_OFF_FLUSH) {
 		/* ready to power-down the UART */
-		smux.power_state = SMUX_PWR_OFF;
-		SMUX_DBG("%s: Power %d->%d\n", __func__,
+		SMUX_PWR("%s: Power %d->%d\n", __func__,
 				smux.power_state, SMUX_PWR_OFF);
+		smux.power_state = SMUX_PWR_OFF;
 
 		/* if data is pending, schedule a new wakeup */
 		if (!list_empty(&smux.lch_tx_ready_list) ||
@@ -2455,7 +2473,7 @@
 			   !list_empty(&smux.power_queue)) {
 				/* data to transmit, do wakeup */
 				smux.pwr_wakeup_delay_us = 1;
-				SMUX_DBG("%s: Power %d->%d\n", __func__,
+				SMUX_PWR("%s: Power %d->%d\n", __func__,
 						smux.power_state,
 						SMUX_PWR_TURNING_ON);
 				smux.power_state = SMUX_PWR_TURNING_ON;
@@ -2492,7 +2510,7 @@
 			if (smux.power_state == SMUX_PWR_TURNING_OFF_FLUSH &&
 				pkt->hdr.cmd == SMUX_CMD_PWR_CTL &&
 				(pkt->hdr.flags & SMUX_CMD_PWR_CTL_ACK)) {
-				SMUX_DBG("%s: Power %d->%d\n", __func__,
+				SMUX_PWR("%s: Power %d->%d\n", __func__,
 						smux.power_state,
 						SMUX_PWR_OFF_FLUSH);
 				smux.power_state = SMUX_PWR_OFF_FLUSH;
@@ -3106,24 +3124,39 @@
 	unsigned long flags;
 	int power_off_uart = 0;
 
-	if (code != SUBSYS_AFTER_SHUTDOWN)
+	if (code == SUBSYS_BEFORE_SHUTDOWN) {
+		SMUX_DBG("%s: ssr - before shutdown\n", __func__);
+		mutex_lock(&smux.mutex_lha0);
+		smux.in_reset = 1;
+		mutex_unlock(&smux.mutex_lha0);
 		return NOTIFY_DONE;
+	} else if (code != SUBSYS_AFTER_SHUTDOWN) {
+		return NOTIFY_DONE;
+	}
+	SMUX_DBG("%s: ssr - after shutdown\n", __func__);
 
 	/* Cleanup channels */
+	mutex_lock(&smux.mutex_lha0);
 	smux_lch_purge();
+	if (smux.tty)
+		tty_driver_flush_buffer(smux.tty);
 
 	/* Power-down UART */
 	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
 	if (smux.power_state != SMUX_PWR_OFF) {
-		SMUX_DBG("%s: SSR - turning off UART\n", __func__);
+		SMUX_PWR("%s: SSR - turning off UART\n", __func__);
 		smux.power_state = SMUX_PWR_OFF;
 		power_off_uart = 1;
 	}
+	smux.powerdown_enabled = 0;
 	spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
 
 	if (power_off_uart)
 		smux_uart_power_off();
 
+	smux.in_reset = 0;
+	mutex_unlock(&smux.mutex_lha0);
+
 	return NOTIFY_DONE;
 }
 
@@ -3173,7 +3206,7 @@
 	/* power-down the UART if we are idle */
 	spin_lock_irqsave(&smux.tx_lock_lha2, flags);
 	if (smux.power_state == SMUX_PWR_OFF) {
-		SMUX_DBG("%s: powering off uart\n", __func__);
+		SMUX_PWR("%s: powering off uart\n", __func__);
 		smux.power_state = SMUX_PWR_OFF_FLUSH;
 		spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
 		queue_work(smux_tx_wq, &smux_inactivity_work);
@@ -3227,6 +3260,7 @@
 	if (smux.power_state == SMUX_PWR_OFF)
 		power_up_uart = 1;
 	smux.power_state = SMUX_PWR_OFF;
+	smux.powerdown_enabled = 0;
 	spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
 
 	if (power_up_uart)
@@ -3371,7 +3405,7 @@
 		return ret;
 	}
 
-	subsys_notif_register_notifier("qsc", &ssr_notifier);
+	subsys_notif_register_notifier("external_modem", &ssr_notifier);
 
 	ret = lch_init();
 	if (ret != 0) {
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index 4a65177..5735534 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -628,8 +628,8 @@
 		break;
 	}
 
-	/* Set timeout to be ~100x the character transmit time */
-	msm_hsl_port->tx_timeout = 1000000000 / baud;
+	/* Set timeout to be ~600x the character transmit time */
+	msm_hsl_port->tx_timeout = (1000000000 / baud) * 6;
 
 	vid = msm_hsl_port->ver_id;
 	msm_hsl_write(port, baud_code, regmap[vid][UARTDM_CSR]);
diff --git a/drivers/tty/smux_loopback.c b/drivers/tty/smux_loopback.c
index bf6d50b..c4374bb 100644
--- a/drivers/tty/smux_loopback.c
+++ b/drivers/tty/smux_loopback.c
@@ -174,13 +174,15 @@
 		}
 
 		lcid = pkt->hdr.lcid;
-		if (smux_assert_lch_id(lcid)) {
-			pr_err("%s: invalid channel id %d\n", __func__, lcid);
-			return;
-		}
 
 		switch (pkt->hdr.cmd) {
 		case SMUX_CMD_OPEN_LCH:
+			if (smux_assert_lch_id(lcid)) {
+				pr_err("%s: invalid channel id %d\n",
+						__func__, lcid);
+				break;
+			}
+
 			if (pkt->hdr.flags & SMUX_CMD_OPEN_ACK)
 				break;
 
@@ -207,6 +209,12 @@
 			break;
 
 		case SMUX_CMD_CLOSE_LCH:
+			if (smux_assert_lch_id(lcid)) {
+				pr_err("%s: invalid channel id %d\n",
+						__func__, lcid);
+				break;
+			}
+
 			if (pkt->hdr.flags == SMUX_CMD_CLOSE_ACK)
 				break;
 
@@ -232,6 +240,12 @@
 			break;
 
 		case SMUX_CMD_DATA:
+			if (smux_assert_lch_id(lcid)) {
+				pr_err("%s: invalid channel id %d\n",
+						__func__, lcid);
+				break;
+			}
+
 			/* Echo back received data */
 			smux_init_pkt(&reply_pkt);
 			reply_pkt.hdr.lcid = lcid;
@@ -245,6 +259,12 @@
 			break;
 
 		case SMUX_CMD_STATUS:
+			if (smux_assert_lch_id(lcid)) {
+				pr_err("%s: invalid channel id %d\n",
+						__func__, lcid);
+				break;
+			}
+
 			/* Echo back received status */
 			smux_init_pkt(&reply_pkt);
 			reply_pkt.hdr.lcid = lcid;
@@ -260,7 +280,7 @@
 		case SMUX_CMD_PWR_CTL:
 			/* reply with ack */
 			smux_init_pkt(&reply_pkt);
-			reply_pkt.hdr.lcid = lcid;
+			reply_pkt.hdr.lcid = SMUX_BROADCAST_LCID;
 			reply_pkt.hdr.cmd = SMUX_CMD_PWR_CTL;
 			reply_pkt.hdr.flags = SMUX_CMD_PWR_CTL_ACK;
 			reply_pkt.hdr.payload_len = 0;
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index d8f741f..742beef 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -3,7 +3,6 @@
 	depends on (USB && USB_GADGET)
 	select USB_OTG_UTILS
 	select USB_GADGET_DUALSPEED
-	select USB_GADGET_SUPERSPEED
 	select USB_XHCI_PLATFORM
 	help
 	  Say Y or M here if your system has a Dual Role SuperSpeed
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 81ce143..5a79cae 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -82,6 +82,12 @@
 
 #define DBM_MAX_EPS		4
 
+/* DBM TRB configurations */
+#define DBM_TRB_BIT		0x80000000
+#define DBM_TRB_DATA_SRC	0x40000000
+#define DBM_TRB_DMA		0x20000000
+#define DBM_TRB_EP_NUM(ep)	(ep<<24)
+
 struct dwc3_msm_req_complete {
 	struct list_head list_item;
 	struct usb_request *req;
@@ -507,19 +513,12 @@
 */
 static int __dwc3_msm_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
 {
-	struct dwc3_trb_hw *trb_hw;
-	struct dwc3_trb_hw *trb_link_hw;
-	struct dwc3_trb trb;
+	struct dwc3_trb *trb;
+	struct dwc3_trb *trb_link;
 	struct dwc3_gadget_ep_cmd_params params;
 	u32 cmd;
 	int ret = 0;
 
-	if ((req->request.udc_priv & MSM_IS_FINITE_TRANSFER) &&
-	    (req->request.length > 0)) {
-		/* Map the request to a DMA. */
-		dwc3_map_buffer_to_dma(req);
-	}
-
 	/* We push the request to the dep->req_queued list to indicate that
 	 * this request is issued with start transfer. The request will be out
 	 * from this list in 2 cases. The first is that the transfer will be
@@ -531,31 +530,26 @@
 	list_add_tail(&req->list, &dep->req_queued);
 
 	/* First, prepare a normal TRB, point to the fake buffer */
-	trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
+	trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
 	dep->free_slot++;
-	memset(&trb, 0, sizeof(trb));
+	memset(trb, 0, sizeof(*trb));
 
-	req->trb = trb_hw;
-
-	trb.bplh = req->request.dma;
-	trb.lst = 0;
-	trb.trbctl = DWC3_TRBCTL_NORMAL;
-	trb.length = req->request.length;
-	trb.hwo = true;
-
-	dwc3_trb_to_hw(&trb, trb_hw);
-	req->trb_dma = dep->trb_pool_dma;
+	req->trb = trb;
+	req->trb_dma = dwc3_trb_dma_offset(dep, trb);
+	trb->bph = DBM_TRB_BIT | DBM_TRB_DATA_SRC |
+		   DBM_TRB_DMA | DBM_TRB_EP_NUM(dep->number);
+	trb->size = DWC3_TRB_SIZE_LENGTH(req->request.length);
+	trb->ctrl = DWC3_TRBCTL_NORMAL | DWC3_TRB_CTRL_HWO | DWC3_TRB_CTRL_CHN;
 
 	/* Second, prepare a Link TRB that points to the first TRB*/
-	trb_link_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
+	trb_link = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
 	dep->free_slot++;
-	memset(&trb, 0, sizeof(trb));
 
-	trb.bplh = dep->trb_pool_dma;
-	trb.trbctl = DWC3_TRBCTL_LINK_TRB;
-	trb.hwo = true;
-
-	dwc3_trb_to_hw(&trb, trb_link_hw);
+	trb_link->bpl = lower_32_bits(req->trb_dma);
+	trb_link->bph = DBM_TRB_BIT | DBM_TRB_DATA_SRC |
+			DBM_TRB_DMA | DBM_TRB_EP_NUM(dep->number);
+	trb_link->size = 0;
+	trb_link->ctrl = DWC3_TRBCTL_LINK_TRB | DWC3_TRB_CTRL_HWO;
 
 	/*
 	 * Now start the transfer
@@ -570,7 +564,6 @@
 			"%s: failed to send STARTTRANSFER command\n",
 			__func__);
 
-		dwc3_unmap_buffer_from_dma(req);
 		list_del(&req->list);
 		return ret;
 	}
@@ -1115,7 +1108,7 @@
 		goto disable_hs_ldo;
 	}
 
-	dwc3 = platform_device_alloc("dwc3-msm", -1);
+	dwc3 = platform_device_alloc("dwc3", -1);
 	if (!dwc3) {
 		dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
 		ret = -ENODEV;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 5255fe9..a988c43 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -313,7 +313,7 @@
 	} while (1);
 }
 
-static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
+dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
 		struct dwc3_trb *trb)
 {
 	u32		offset = (char *) trb - (char *) dep->trb_pool;
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index a860008..662682e 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -111,6 +111,8 @@
 int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
 int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
 		unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
+dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
+		struct dwc3_trb *trb);
 
 /**
  * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 14b07e5..95f11c1 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -506,6 +506,32 @@
 	  dynamically linked module called "ci13xxx_msm_hsic" and force all
 	  gadget drivers to also be dynamically linked.
 
+config USB_DWC3_MSM
+	tristate "DesignWare USB3.0 (DRD) Controller for MSM"
+	depends on ARCH_MSM
+	select USB_DWC3
+	select USB_GADGET_DUALSPEED
+	select USB_GADGET_SELECTED
+	help
+	  The DesignWare USB3.0 controller is a SuperSpeed USB3.0 Controller
+	  integrated into the Qualcomm MSM chipset series, supporting host,
+	  device and otg modes of operation. For more information please
+	  refer to http://www.qualcomm.com/chipsets.
+
+config USB_DWC3_OMAP
+	tristate "DesignWare USB3.0 (DRD) Controller for OMAP"
+	depends on ARCH_OMAP
+	select USB_DWC3
+	select USB_GADGET_DUALSPEED
+	select USB_GADGET_SUPERSPEED
+	select USB_GADGET_SELECTED
+	help
+	  DesignWare USB3.0 controller is a SuperSpeed USB3.0 Controller
+	  which can be configured for peripheral-only, host-only, hub-only
+	  and Dual-Role operation. This Controller was first integrated into
+	  the OMAP5 series of processors. More information about the OMAP5
+	  version of this controller, refer to http://www.ti.com/omap5.
+
 #
 # LAST -- dummy/emulated controller
 #
@@ -556,8 +582,15 @@
 
 # Selected by UDC drivers that support super-speed opperation
 config USB_GADGET_SUPERSPEED
-	bool
+	bool "Operate as superspeed"
+	depends on USB_GADGET
 	depends on USB_GADGET_DUALSPEED
+	default n
+	help
+	 When a superspeed peripheral controller is selected
+	 (for example DesignWare USB3.0 controller), use this flag to
+	 indicate if the device should operate in superspeed(=y)
+	 or not.
 
 #
 # USB Gadget Drivers
diff --git a/drivers/usb/gadget/ci13xxx_msm_hsic.c b/drivers/usb/gadget/ci13xxx_msm_hsic.c
index 39d4720..30b45eb 100644
--- a/drivers/usb/gadget/ci13xxx_msm_hsic.c
+++ b/drivers/usb/gadget/ci13xxx_msm_hsic.c
@@ -30,16 +30,16 @@
 #include <mach/clk.h>
 #include <mach/msm_iomap.h>
 #include <mach/msm_xo.h>
+#include <mach/rpm-regulator.h>
 
 #include "ci13xxx_udc.c"
 
 #define MSM_USB_BASE	(mhsic->regs)
 
 #define ULPI_IO_TIMEOUT_USEC			(10 * 1000)
-#define USB_PHY_VDD_DIG_VOL_SUSP_MIN	500000 /* uV */
+#define USB_PHY_VDD_DIG_VOL_NONE		0 /*uV */
 #define USB_PHY_VDD_DIG_VOL_MIN			1045000 /* uV */
 #define USB_PHY_VDD_DIG_VOL_MAX			1320000 /* uV */
-#define USB_PHY_VDD_DIG_LOAD			49360	/* uA */
 #define LINK_RESET_TIMEOUT_USEC			(250 * 1000)
 #define PHY_SUSPEND_TIMEOUT_USEC		(500 * 1000)
 #define PHY_RESUME_TIMEOUT_USEC			(100 * 1000)
@@ -66,38 +66,56 @@
 	struct workqueue_struct *wq;
 	struct work_struct	suspend_w;
 	struct msm_hsic_peripheral_platform_data *pdata;
+	enum usb_vdd_type	vdd_type;
+};
+
+static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
+		{   /* VDD_CX CORNER Voting */
+			[VDD_NONE]	= RPM_VREG_CORNER_NONE,
+			[VDD_MIN]	= RPM_VREG_CORNER_NOMINAL,
+			[VDD_MAX]	= RPM_VREG_CORNER_HIGH,
+		},
+		{   /* VDD_CX Voltage Voting */
+			[VDD_NONE]	= USB_PHY_VDD_DIG_VOL_NONE,
+			[VDD_MIN]	= USB_PHY_VDD_DIG_VOL_MIN,
+			[VDD_MAX]	= USB_PHY_VDD_DIG_VOL_MAX,
+		},
 };
 
 static int msm_hsic_init_vddcx(struct msm_hsic_per *mhsic, int init)
 {
 	int ret = 0;
+	int none_vol, min_vol, max_vol;
+
+	if (!mhsic->hsic_vddcx) {
+		mhsic->vdd_type = VDDCX_CORNER;
+		mhsic->hsic_vddcx = devm_regulator_get(mhsic->dev,
+			"hsic_vdd_dig");
+		if (IS_ERR(mhsic->hsic_vddcx)) {
+			mhsic->hsic_vddcx = devm_regulator_get(mhsic->dev,
+				"HSIC_VDDCX");
+			if (IS_ERR(mhsic->hsic_vddcx)) {
+				dev_err(mhsic->dev, "unable to get hsic vddcx\n");
+				return PTR_ERR(mhsic->hsic_vddcx);
+			}
+			mhsic->vdd_type = VDDCX;
+		}
+	}
+
+	none_vol = vdd_val[mhsic->vdd_type][VDD_NONE];
+	min_vol = vdd_val[mhsic->vdd_type][VDD_MIN];
+	max_vol = vdd_val[mhsic->vdd_type][VDD_MAX];
 
 	if (!init)
 		goto disable_reg;
 
-	mhsic->hsic_vddcx = regulator_get(mhsic->dev, "HSIC_VDDCX");
-	if (IS_ERR(mhsic->hsic_vddcx)) {
-		dev_err(mhsic->dev, "unable to get hsic vddcx\n");
-		return PTR_ERR(mhsic->hsic_vddcx);
-	}
-
-	ret = regulator_set_voltage(mhsic->hsic_vddcx,
-			USB_PHY_VDD_DIG_VOL_MIN,
-			USB_PHY_VDD_DIG_VOL_MAX);
+	ret = regulator_set_voltage(mhsic->hsic_vddcx, min_vol, max_vol);
 	if (ret) {
 		dev_err(mhsic->dev, "unable to set the voltage"
 				"for hsic vddcx\n");
 		goto reg_set_voltage_err;
 	}
 
-	ret = regulator_set_optimum_mode(mhsic->hsic_vddcx,
-				USB_PHY_VDD_DIG_LOAD);
-	if (ret < 0) {
-		pr_err("%s: Unable to set optimum mode of the regulator:"
-					"VDDCX\n", __func__);
-		goto reg_optimum_mode_err;
-	}
-
 	ret = regulator_enable(mhsic->hsic_vddcx);
 	if (ret) {
 		dev_err(mhsic->dev, "unable to enable hsic vddcx\n");
@@ -109,12 +127,8 @@
 disable_reg:
 	regulator_disable(mhsic->hsic_vddcx);
 reg_enable_err:
-	regulator_set_optimum_mode(mhsic->hsic_vddcx, 0);
-reg_optimum_mode_err:
-	regulator_set_voltage(mhsic->hsic_vddcx, 0,
-				USB_PHY_VDD_DIG_VOL_MIN);
+	regulator_set_voltage(mhsic->hsic_vddcx, none_vol, max_vol);
 reg_set_voltage_err:
-	regulator_put(mhsic->hsic_vddcx);
 
 	return ret;
 
@@ -323,6 +337,7 @@
 {
 	int cnt = 0, ret;
 	u32 val;
+	int none_vol, max_vol;
 
 	if (atomic_read(&mhsic->in_lpm)) {
 		dev_dbg(mhsic->dev, "%s called while in lpm\n", __func__);
@@ -378,11 +393,12 @@
 		dev_err(mhsic->dev, "%s failed to devote for TCXO %d\n"
 				, __func__, ret);
 
-	ret = regulator_set_voltage(mhsic->hsic_vddcx,
-				USB_PHY_VDD_DIG_VOL_SUSP_MIN,
-				USB_PHY_VDD_DIG_VOL_MAX);
+	none_vol = vdd_val[mhsic->vdd_type][VDD_NONE];
+	max_vol = vdd_val[mhsic->vdd_type][VDD_MAX];
+
+	ret = regulator_set_voltage(mhsic->hsic_vddcx, none_vol, max_vol);
 	if (ret < 0)
-		dev_err(mhsic->dev, "unable to set vddcx voltage: min:0.5v max:1.32v\n");
+		dev_err(mhsic->dev, "unable to set vddcx voltage for VDD MIN\n");
 
 	if (device_may_wakeup(mhsic->dev))
 		enable_irq_wake(mhsic->irq);
@@ -400,6 +416,7 @@
 {
 	int cnt = 0, ret;
 	unsigned temp;
+	int min_vol, max_vol;
 
 	if (!atomic_read(&mhsic->in_lpm)) {
 		dev_dbg(mhsic->dev, "%s called while not in lpm\n", __func__);
@@ -407,12 +424,14 @@
 	}
 
 	wake_lock(&mhsic->wlock);
-	ret = regulator_set_voltage(mhsic->hsic_vddcx,
-				USB_PHY_VDD_DIG_VOL_MIN,
-				USB_PHY_VDD_DIG_VOL_MAX);
+
+	min_vol = vdd_val[mhsic->vdd_type][VDD_MIN];
+	max_vol = vdd_val[mhsic->vdd_type][VDD_MAX];
+
+	ret = regulator_set_voltage(mhsic->hsic_vddcx, min_vol, max_vol);
 	if (ret < 0)
 		dev_err(mhsic->dev,
-				"unable to set vddcx voltage: min:1.045v max:1.32v\n");
+			"unable to set nominal vddcx voltage (no VDD MIN)\n");
 
 	ret = msm_xo_mode_vote(mhsic->xo_handle, MSM_XO_MODE_ON);
 	if (ret)
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index fb86874..8cdc2e9 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -1720,6 +1720,7 @@
 			if (!mReq->req.no_interrupt)
 				mReq->ptr->token |= MSM_ETD_IOC;
 		}
+		mReq->req.dma = 0;
 	}
 
 	mReq->ptr->page[0]  = mReq->req.dma;
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 5ed16cc..a6b7dee 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -30,16 +30,19 @@
 #include <linux/wakelock.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
-#include <mach/msm_bus.h>
 
 #include <linux/usb/msm_hsusb_hw.h>
 #include <linux/usb/msm_hsusb.h>
 #include <linux/gpio.h>
+#include <linux/spinlock.h>
+
+#include <mach/msm_bus.h>
 #include <mach/clk.h>
 #include <mach/msm_iomap.h>
 #include <mach/msm_xo.h>
 #include <linux/spinlock.h>
 #include <linux/cpu.h>
+#include <mach/rpm-regulator.h>
 
 #define MSM_USB_BASE (hcd->regs)
 
@@ -62,6 +65,7 @@
 	atomic_t		pm_usage_cnt;
 	uint32_t		bus_perf_client;
 	uint32_t		wakeup_int_cnt;
+	enum usb_vdd_type	vdd_type;
 };
 
 static bool debug_bus_voting_enabled = true;
@@ -254,43 +258,59 @@
 
 #define ULPI_IO_TIMEOUT_USEC	(10 * 1000)
 
-#define USB_PHY_VDD_DIG_VOL_SUSP_MIN	500000 /* uV */
+#define USB_PHY_VDD_DIG_VOL_NONE	0 /*uV */
 #define USB_PHY_VDD_DIG_VOL_MIN		1000000 /* uV */
 #define USB_PHY_VDD_DIG_VOL_MAX		1320000 /* uV */
-#define USB_PHY_VDD_DIG_LOAD		49360	/* uA */
 
 #define HSIC_DBG1_REG		0x38
 
+static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
+		{   /* VDD_CX CORNER Voting */
+			[VDD_NONE]	= RPM_VREG_CORNER_NONE,
+			[VDD_MIN]	= RPM_VREG_CORNER_NOMINAL,
+			[VDD_MAX]	= RPM_VREG_CORNER_HIGH,
+		},
+		{   /* VDD_CX Voltage Voting */
+			[VDD_NONE]	= USB_PHY_VDD_DIG_VOL_NONE,
+			[VDD_MIN]	= USB_PHY_VDD_DIG_VOL_MIN,
+			[VDD_MAX]	= USB_PHY_VDD_DIG_VOL_MAX,
+		},
+};
+
 static int msm_hsic_init_vddcx(struct msm_hsic_hcd *mehci, int init)
 {
 	int ret = 0;
+	int none_vol, min_vol, max_vol;
+
+	if (!mehci->hsic_vddcx) {
+		mehci->vdd_type = VDDCX_CORNER;
+		mehci->hsic_vddcx = devm_regulator_get(mehci->dev,
+			"hsic_vdd_dig");
+		if (IS_ERR(mehci->hsic_vddcx)) {
+			mehci->hsic_vddcx = devm_regulator_get(mehci->dev,
+				"HSIC_VDDCX");
+			if (IS_ERR(mehci->hsic_vddcx)) {
+				dev_err(mehci->dev, "unable to get hsic vddcx\n");
+				return PTR_ERR(mehci->hsic_vddcx);
+			}
+			mehci->vdd_type = VDDCX;
+		}
+	}
+
+	none_vol = vdd_val[mehci->vdd_type][VDD_NONE];
+	min_vol = vdd_val[mehci->vdd_type][VDD_MIN];
+	max_vol = vdd_val[mehci->vdd_type][VDD_MAX];
 
 	if (!init)
 		goto disable_reg;
 
-	mehci->hsic_vddcx = devm_regulator_get(mehci->dev, "HSIC_VDDCX");
-	if (IS_ERR(mehci->hsic_vddcx)) {
-		dev_err(mehci->dev, "unable to get hsic vddcx\n");
-		return PTR_ERR(mehci->hsic_vddcx);
-	}
-
-	ret = regulator_set_voltage(mehci->hsic_vddcx,
-			USB_PHY_VDD_DIG_VOL_MIN,
-			USB_PHY_VDD_DIG_VOL_MAX);
+	ret = regulator_set_voltage(mehci->hsic_vddcx, min_vol, max_vol);
 	if (ret) {
 		dev_err(mehci->dev, "unable to set the voltage"
 				"for hsic vddcx\n");
 		return ret;
 	}
 
-	ret = regulator_set_optimum_mode(mehci->hsic_vddcx,
-				USB_PHY_VDD_DIG_LOAD);
-	if (ret < 0) {
-		pr_err("%s: Unable to set optimum mode of the regulator:"
-					"VDDCX\n", __func__);
-		goto reg_optimum_mode_err;
-	}
-
 	ret = regulator_enable(mehci->hsic_vddcx);
 	if (ret) {
 		dev_err(mehci->dev, "unable to enable hsic vddcx\n");
@@ -302,10 +322,8 @@
 disable_reg:
 	regulator_disable(mehci->hsic_vddcx);
 reg_enable_err:
-	regulator_set_optimum_mode(mehci->hsic_vddcx, 0);
-reg_optimum_mode_err:
-	regulator_set_voltage(mehci->hsic_vddcx, 0,
-				USB_PHY_VDD_DIG_VOL_MIN);
+	regulator_set_voltage(mehci->hsic_vddcx, none_vol, max_vol);
+
 	return ret;
 
 }
@@ -528,6 +546,7 @@
 	struct usb_hcd *hcd = hsic_to_hcd(mehci);
 	int cnt = 0, ret;
 	u32 val;
+	int none_vol, max_vol;
 
 	if (atomic_read(&mehci->in_lpm)) {
 		dev_dbg(mehci->dev, "%s called in lpm\n", __func__);
@@ -593,11 +612,12 @@
 	clk_disable_unprepare(mehci->cal_clk);
 	clk_disable_unprepare(mehci->ahb_clk);
 
-	ret = regulator_set_voltage(mehci->hsic_vddcx,
-				USB_PHY_VDD_DIG_VOL_SUSP_MIN,
-				USB_PHY_VDD_DIG_VOL_MAX);
+	none_vol = vdd_val[mehci->vdd_type][VDD_NONE];
+	max_vol = vdd_val[mehci->vdd_type][VDD_MAX];
+
+	ret = regulator_set_voltage(mehci->hsic_vddcx, none_vol, max_vol);
 	if (ret < 0)
-		dev_err(mehci->dev, "unable to set vddcx voltage: min:0.5v max:1.3v\n");
+		dev_err(mehci->dev, "unable to set vddcx voltage for VDD MIN\n");
 
 	if (mehci->bus_perf_client && debug_bus_voting_enabled) {
 		ret = msm_bus_scale_client_update_request(
@@ -626,6 +646,7 @@
 	struct usb_hcd *hcd = hsic_to_hcd(mehci);
 	int cnt = 0, ret;
 	unsigned temp;
+	int min_vol, max_vol;
 
 	if (!atomic_read(&mehci->in_lpm)) {
 		dev_dbg(mehci->dev, "%s called in !in_lpm\n", __func__);
@@ -648,11 +669,12 @@
 				   "bus bandwidth %d\n", __func__, ret);
 	}
 
-	ret = regulator_set_voltage(mehci->hsic_vddcx,
-				USB_PHY_VDD_DIG_VOL_MIN,
-				USB_PHY_VDD_DIG_VOL_MAX);
+	min_vol = vdd_val[mehci->vdd_type][VDD_MIN];
+	max_vol = vdd_val[mehci->vdd_type][VDD_MAX];
+
+	ret = regulator_set_voltage(mehci->hsic_vddcx, min_vol, max_vol);
 	if (ret < 0)
-		dev_err(mehci->dev, "unable to set vddcx voltage: min:1v max:1.3v\n");
+		dev_err(mehci->dev, "unable to set nominal vddcx voltage (no VDD MIN)\n");
 
 	clk_prepare_enable(mehci->core_clk);
 	clk_prepare_enable(mehci->phy_clk);
diff --git a/drivers/usb/misc/diag_bridge.c b/drivers/usb/misc/diag_bridge.c
index 37b4e53..8b762a2 100644
--- a/drivers/usb/misc/diag_bridge.c
+++ b/drivers/usb/misc/diag_bridge.c
@@ -428,7 +428,7 @@
 
 	dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
 
-	platform_device_del(dev->pdev);
+	platform_device_unregister(dev->pdev);
 	dev->ifc = NULL;
 	diag_bridge_debugfs_cleanup();
 	kref_put(&dev->kref, diag_bridge_delete);
diff --git a/drivers/usb/misc/mdm_ctrl_bridge.c b/drivers/usb/misc/mdm_ctrl_bridge.c
index 044af3a..e685233 100644
--- a/drivers/usb/misc/mdm_ctrl_bridge.c
+++ b/drivers/usb/misc/mdm_ctrl_bridge.c
@@ -703,7 +703,7 @@
 free_inturb:
 	usb_free_urb(dev->inturb);
 pdev_del:
-	platform_device_del(dev->pdev);
+	platform_device_unregister(dev->pdev);
 nomem:
 	kfree(dev);
 
@@ -716,7 +716,7 @@
 
 	dev_dbg(&dev->intf->dev, "%s:\n", __func__);
 
-	platform_device_del(dev->pdev);
+	platform_device_unregister(dev->pdev);
 
 	kfree(dev->in_ctlreq);
 	kfree(dev->readbuf);
diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c
index 26be973..db2f40a 100644
--- a/drivers/usb/misc/mdm_data_bridge.c
+++ b/drivers/usb/misc/mdm_data_bridge.c
@@ -918,12 +918,12 @@
 		return -EINVAL;
 	}
 
-	udev = interface_to_usbdev(iface);
-	usb_get_dev(udev);
-
 	if (!test_bit(iface_num, &id->driver_info))
 		return -ENODEV;
 
+	udev = interface_to_usbdev(iface);
+	usb_get_dev(udev);
+
 	numends = iface->cur_altsetting->desc.bNumEndpoints;
 	for (i = 0; i < numends; i++) {
 		endpoint = iface->cur_altsetting->endpoint + i;
@@ -965,7 +965,7 @@
 	return 0;
 
 free_data_bridge:
-	platform_device_del(__dev[ch_id]->pdev);
+	platform_device_unregister(__dev[ch_id]->pdev);
 	usb_set_intfdata(iface, NULL);
 	kfree(__dev[ch_id]);
 	__dev[ch_id] = NULL;
@@ -989,7 +989,7 @@
 
 	ch_id--;
 	ctrl_bridge_disconnect(ch_id);
-	platform_device_del(dev->pdev);
+	platform_device_unregister(dev->pdev);
 	usb_set_intfdata(intf, NULL);
 	__dev[ch_id] = NULL;
 
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 61fbac0..c0f9346 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -87,13 +87,6 @@
 #endif
 }
 
-enum usb_vdd_value {
-	VDD_NONE = 0,
-	VDD_MIN,
-	VDD_MAX,
-	VDD_VAL_MAX,
-};
-
 static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
 		{  /* VDD_CX CORNER Voting */
 			[VDD_NONE]	= RPM_VREG_CORNER_NONE,
diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h
index de8d490..9811a82 100644
--- a/drivers/usb/serial/usb-wwan.h
+++ b/drivers/usb/serial/usb-wwan.h
@@ -53,6 +53,7 @@
 	u8 *out_buffer[N_OUT_URB];
 	unsigned long out_busy;	/* Bit vector of URBs in use */
 	int opened;
+	struct usb_anchor submitted;
 	struct usb_anchor delayed;
 
 	/* Settings for the port */
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 519af39..0c58554 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -252,10 +252,12 @@
 		} else {
 			intfdata->in_flight++;
 			spin_unlock_irqrestore(&intfdata->susp_lock, flags);
+			usb_anchor_urb(this_urb, &portdata->submitted);
 			err = usb_submit_urb(this_urb, GFP_ATOMIC);
 			if (err) {
 				dbg("usb_submit_urb %p (write bulk) failed "
 				    "(%d)", this_urb, err);
+				usb_unanchor_urb(this_urb);
 				clear_bit(i, &portdata->out_busy);
 				spin_lock_irqsave(&intfdata->susp_lock, flags);
 				intfdata->in_flight--;
@@ -281,6 +283,7 @@
 {
 	int err;
 	int endpoint;
+	struct usb_wwan_port_private *portdata;
 	struct usb_serial_port *port;
 	struct tty_struct *tty;
 	unsigned char *data = urb->transfer_buffer;
@@ -290,6 +293,7 @@
 
 	endpoint = usb_pipeendpoint(urb->pipe);
 	port = urb->context;
+	portdata = usb_get_serial_port_data(port);
 
 	if (status) {
 		dbg("%s: nonzero status: %d on endpoint %02x.",
@@ -308,8 +312,10 @@
 
 		/* Resubmit urb so we continue receiving */
 		if (status != -ESHUTDOWN) {
+			usb_anchor_urb(urb, &portdata->submitted);
 			err = usb_submit_urb(urb, GFP_ATOMIC);
 			if (err) {
+				usb_unanchor_urb(urb);
 				if (err != -EPERM) {
 					printk(KERN_ERR "%s: resubmit read urb failed. "
 						"(%d)", __func__, err);
@@ -418,8 +424,10 @@
 		urb = portdata->in_urbs[i];
 		if (!urb)
 			continue;
+		usb_anchor_urb(urb, &portdata->submitted);
 		err = usb_submit_urb(urb, GFP_KERNEL);
 		if (err) {
+			usb_unanchor_urb(urb);
 			dbg("%s: submit urb %d failed (%d) %d",
 			    __func__, i, err, urb->transfer_buffer_length);
 		}
@@ -551,6 +559,7 @@
 			return 1;
 		}
 		init_usb_anchor(&portdata->delayed);
+		init_usb_anchor(&portdata->submitted);
 
 		for (j = 0; j < N_IN_URB; j++) {
 			buffer = kmalloc(IN_BUFLEN, GFP_KERNEL);
@@ -590,7 +599,7 @@
 
 static void stop_read_write_urbs(struct usb_serial *serial)
 {
-	int i, j;
+	int i;
 	struct usb_serial_port *port;
 	struct usb_wwan_port_private *portdata;
 
@@ -598,10 +607,7 @@
 	for (i = 0; i < serial->num_ports; ++i) {
 		port = serial->port[i];
 		portdata = usb_get_serial_port_data(port);
-		for (j = 0; j < N_IN_URB; j++)
-			usb_kill_urb(portdata->in_urbs[j]);
-		for (j = 0; j < N_OUT_URB; j++)
-			usb_kill_urb(portdata->out_urbs[j]);
+		usb_kill_anchored_urbs(&portdata->submitted);
 	}
 }
 
@@ -694,10 +700,12 @@
 	portdata = usb_get_serial_port_data(port);
 	data = port->serial->private;
 	while ((urb = usb_get_from_anchor(&portdata->delayed))) {
+		usb_anchor_urb(urb, &portdata->submitted);
 		err = usb_submit_urb(urb, GFP_ATOMIC);
 		if (!err) {
 			data->in_flight++;
 		} else {
+			usb_unanchor_urb(urb);
 			/* we have to throw away the rest */
 			do {
 				unbusy_queued_urb(urb, portdata);
@@ -736,33 +744,32 @@
 
 	spin_lock_irq(&intfdata->susp_lock);
 	intfdata->suspended = 0;
-	spin_unlock_irq(&intfdata->susp_lock);
-
 	for (i = 0; i < serial->num_ports; i++) {
 		/* walk all ports */
 		port = serial->port[i];
 		portdata = usb_get_serial_port_data(port);
 
 		/* skip closed ports */
-		spin_lock_irq(&intfdata->susp_lock);
-		if (!portdata->opened) {
-			spin_unlock_irq(&intfdata->susp_lock);
+		if (!portdata->opened)
 			continue;
-		}
 
 		for (j = 0; j < N_IN_URB; j++) {
 			urb = portdata->in_urbs[j];
+			usb_anchor_urb(urb, &portdata->submitted);
 			err = usb_submit_urb(urb, GFP_ATOMIC);
 			if (err < 0) {
 				err("%s: Error %d for bulk URB %d",
 				    __func__, err, i);
+				usb_unanchor_urb(urb);
+				intfdata->suspended = 1;
 				spin_unlock_irq(&intfdata->susp_lock);
 				goto err_out;
 			}
 		}
 		play_delayed(port);
-		spin_unlock_irq(&intfdata->susp_lock);
 	}
+	spin_unlock_irq(&intfdata->susp_lock);
+
 err_out:
 	return err;
 }
diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig
index 7777154..7e078ab 100644
--- a/drivers/video/msm/Kconfig
+++ b/drivers/video/msm/Kconfig
@@ -84,6 +84,16 @@
 	  Support for MSM MDP HW revision 4.0
 	  Say Y here if this is msm7x30 variant platform.
 
+config FB_MSM_MDSS
+	bool "MDSS HW"
+	---help---
+	The Mobile Display Sub System (MDSS) driver supports devices which
+	contain MDSS hardware block.
+
+	The MDSS driver implements frame buffer interface to provide access to
+	the display hardware and provide a way for users to display graphics
+	on connected display panels.
+
 config FB_MSM_MDP_NONE
 	bool "MDP HW None"
 	---help---
@@ -936,4 +946,8 @@
 	default n
 	---help---
 	  Support for EBI2 panel auto detect
+
+if FB_MSM_MDSS
+	source "drivers/video/msm/mdss/Kconfig"
+endif
 endif
diff --git a/drivers/video/msm/Makefile b/drivers/video/msm/Makefile
index e4a0948..a0f9e02 100644
--- a/drivers/video/msm/Makefile
+++ b/drivers/video/msm/Makefile
@@ -1,10 +1,12 @@
+ifeq ($(CONFIG_FB_MSM_MDSS),y)
+obj-y += mdss/
+else
 obj-y := msm_fb.o
 
 obj-$(CONFIG_FB_MSM_LOGO) += logo.o
 obj-$(CONFIG_FB_BACKLIGHT) += msm_fb_bl.o
 
 ifeq ($(CONFIG_FB_MSM_MDP_HW),y)
-
 # MDP
 obj-y += mdp.o
 
@@ -182,15 +184,15 @@
 obj-$(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) += mdp4_wfd_writeback_panel.o
 obj-$(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) += mdp4_wfd_writeback.o
 obj-$(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) += mdp4_overlay_writeback.o
-
-obj-$(CONFIG_MSM_VIDC_1080P) += vidc/
-obj-$(CONFIG_MSM_VIDC_720P) += vidc/
 else
 obj-$(CONFIG_FB_MSM_EBI2) += ebi2_host.o
 obj-$(CONFIG_FB_MSM_EBI2) += ebi2_lcd.o
 obj-y += msm_fb_panel.o
 obj-$(CONFIG_FB_MSM_EBI2_EPSON_S1D_QVGA_PANEL) += ebi2_epson_s1d_qvga.o
 endif
+endif
 
+obj-$(CONFIG_MSM_VIDC_1080P) += vidc/
+obj-$(CONFIG_MSM_VIDC_720P) += vidc/
 clean:
 	rm *.o .*cmd
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index aa19bdd..03243ac 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -4531,7 +4531,6 @@
 	hdmi_msm_state->hpd_state_timer.data = (uint32)NULL;
 
 	hdmi_msm_state->hpd_state_timer.expires = 0xffffffffL;
-	add_timer(&hdmi_msm_state->hpd_state_timer);
 
 #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
 	init_timer(&hdmi_msm_state->hdcp_timer);
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index e76d8b2..55d2b3e 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -88,6 +88,7 @@
 struct workqueue_struct *mdp_vsync_wq;	/*mdp vsync wq */
 
 struct workqueue_struct *mdp_hist_wq;	/*mdp histogram wq */
+bool mdp_pp_initialized = FALSE;
 
 static struct workqueue_struct *mdp_pipe_ctrl_wq; /* mdp mdp pipe ctrl wq */
 static struct delayed_work mdp_pipe_ctrl_worker;
@@ -219,10 +220,28 @@
 	mutex_unlock(&mdp_hist_lut_list_mutex);
 }
 
-static int mdp_hist_lut_init(void)
+static int mdp_hist_lut_destroy(void)
 {
 	struct mdp_hist_lut_mgmt *temp;
 	struct list_head *pos, *q;
+
+	mutex_lock(&mdp_hist_lut_list_mutex);
+	list_for_each_safe(pos, q, &mdp_hist_lut_list) {
+		temp = list_entry(pos, struct mdp_hist_lut_mgmt, list);
+		list_del(pos);
+		kfree(temp);
+	}
+	mutex_unlock(&mdp_hist_lut_list_mutex);
+	return 0;
+}
+
+static int mdp_hist_lut_init(void)
+{
+	struct mdp_hist_lut_mgmt *temp;
+
+	if (mdp_pp_initialized)
+		return -EEXIST;
+
 	INIT_LIST_HEAD(&mdp_hist_lut_list);
 
 	if (mdp_rev >= MDP_REV_30) {
@@ -253,13 +272,7 @@
 	return 0;
 
 exit_list:
-	mutex_lock(&mdp_hist_lut_list_mutex);
-	list_for_each_safe(pos, q, &mdp_hist_lut_list) {
-		temp = list_entry(pos, struct mdp_hist_lut_mgmt, list);
-		list_del(pos);
-		kfree(temp);
-	}
-	mutex_unlock(&mdp_hist_lut_list_mutex);
+	mdp_hist_lut_destroy();
 exit:
 	pr_err("Failed initializing histogram LUT memory\n");
 	return -ENOMEM;
@@ -682,10 +695,30 @@
 	kfree(mgmt->c0);
 }
 
+static int mdp_histogram_destroy(void)
+{
+	struct mdp_hist_mgmt *temp;
+	int i;
+
+	for (i = 0; i < MDP_HIST_MGMT_MAX; i++) {
+		temp = mdp_hist_mgmt_array[i];
+		if (!temp)
+			continue;
+		mdp_hist_del_mgmt(temp);
+		kfree(temp);
+		mdp_hist_mgmt_array[i] = NULL;
+	}
+	return 0;
+}
+
 static int mdp_histogram_init(void)
 {
 	struct mdp_hist_mgmt *temp;
 	int i, ret;
+
+	if (mdp_pp_initialized)
+		return -EEXIST;
+
 	mdp_hist_wq = alloc_workqueue("mdp_hist_wq",
 					WQ_NON_REENTRANT | WQ_UNBOUND, 0);
 
@@ -731,14 +764,7 @@
 	return 0;
 
 exit_list:
-	for (i = 0; i < MDP_HIST_MGMT_MAX; i++) {
-		temp = mdp_hist_mgmt_array[i];
-		if (!temp)
-			continue;
-		mdp_hist_del_mgmt(temp);
-		kfree(temp);
-		mdp_hist_mgmt_array[i] = NULL;
-	}
+	mdp_histogram_destroy();
 exit:
 	return -ENOMEM;
 }
@@ -2256,6 +2282,7 @@
 	/* initialize Post Processing data*/
 	mdp_hist_lut_init();
 	mdp_histogram_init();
+	mdp_pp_initialized = TRUE;
 
 	/* add panel data */
 	if (platform_device_add_data
@@ -2657,6 +2684,12 @@
 {
 	if (footswitch != NULL)
 		regulator_put(footswitch);
+
+	/*free post processing memory*/
+	mdp_histogram_destroy();
+	mdp_hist_lut_destroy();
+	mdp_pp_initialized = FALSE;
+
 	iounmap(msm_mdp_base);
 	pm_runtime_disable(&pdev->dev);
 #ifdef CONFIG_MSM_BUS_SCALING
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index 511edb6..e60b24e 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -836,5 +836,12 @@
 	unsigned long srcp0_addr, unsigned long srcp0_size,
 	unsigned long srcp1_addr, unsigned long srcp1_size);
 
+#ifdef CONFIG_FB_MSM_DTV
 void mdp_vid_quant_set(void);
+#else
+static inline void mdp_vid_quant_set(void)
+{
+	/* empty */
+}
+#endif
 #endif /* MDP_H */
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 16fede1..1557eed 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -446,6 +446,7 @@
 			struct mdp4_overlay_pipe *pipe);
 void mdp4_dma_e_done_dtv(void);
 void mdp4_overlay_dtv_wait4vsync(void);
+void mdp4_dtv_base_swap(struct mdp4_overlay_pipe *pipe);
 #else
 static inline void mdp4_overlay_dtv_start(void)
 {
@@ -488,6 +489,10 @@
 {
 	return;
 }
+static inline void mdp4_dtv_base_swap(struct mdp4_overlay_pipe *pipe)
+{
+	/* empty */
+}
 #endif
 
 void mdp4_dtv_set_black_screen(void);
@@ -505,7 +510,6 @@
 			struct mdp4_overlay_pipe *pipe);
 int mdp4_overlay_dtv_unset(struct msm_fb_data_type *mfd,
 			struct mdp4_overlay_pipe *pipe);
-void mdp4_dtv_base_swap(struct mdp4_overlay_pipe *pipe);
 void mdp4_dtv_overlay(struct msm_fb_data_type *mfd);
 int mdp4_dtv_on(struct platform_device *pdev);
 int mdp4_dtv_off(struct platform_device *pdev);
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index aa1795f..fe31f93 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -676,10 +676,12 @@
 	if (!change)
 		return;
 
-	mdp4_overlay_dtv_wait4dmae(mfd);
+	if (dtv_enabled) {
+		mdp4_overlay_dtv_wait4dmae(mfd);
+		MDP_OUTP(MDP_BASE + DTV_BASE, 0);	/* stop dtv */
+		msleep(20);
+	}
 
-	MDP_OUTP(MDP_BASE + DTV_BASE, 0);	/* stop dtv */
-	msleep(20);
 	mdp4_overlayproc_cfg(dtv_pipe);
 	mdp4_overlay_dmae_xy(dtv_pipe);
 	MDP_OUTP(MDP_BASE + DTV_BASE, 1);	/* start dtv */
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index 8410592..fd6d365 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -551,9 +551,12 @@
 	if (!change)
 		return;
 
-	mdp4_overlay_lcdc_wait4event(mfd, INTR_DMA_P_DONE);
-	MDP_OUTP(MDP_BASE + LCDC_BASE, 0);	/* stop lcdc */
-	msleep(20);
+	if (lcdc_enabled) {
+		mdp4_overlay_lcdc_wait4event(mfd, INTR_DMA_P_DONE);
+		MDP_OUTP(MDP_BASE + LCDC_BASE, 0);	/* stop lcdc */
+		msleep(20);
+	}
+
 	mdp4_overlayproc_cfg(lcdc_pipe);
 	mdp4_overlay_dmap_xy(lcdc_pipe);
 	if (lcdc_pipe->blt_addr) {
diff --git a/drivers/video/msm/mdss/Kconfig b/drivers/video/msm/mdss/Kconfig
new file mode 100644
index 0000000..30351a3
--- /dev/null
+++ b/drivers/video/msm/mdss/Kconfig
@@ -0,0 +1,5 @@
+config FB_MSM_MDSS_WRITEBACK
+	bool "MDSS Writeback Panel"
+	---help---
+	The MDSS Writeback Panel provides support for routing the output of
+	MDSS frame buffer driver and MDP processing to memory.
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
new file mode 100644
index 0000000..2a61f07
--- /dev/null
+++ b/drivers/video/msm/mdss/Makefile
@@ -0,0 +1,6 @@
+mdss-mdp-objs := mdss_mdp.o mdss_mdp_ctl.o mdss_mdp_pipe.o mdss_mdp_util.o
+mdss-mdp-objs += mdss_mdp_intf_writeback.o
+mdss-mdp-objs += mdss_mdp_overlay.o
+obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp.o
+obj-$(CONFIG_FB_MSM_MDSS) += mdss_fb.o
+obj-$(CONFIG_FB_MSM_MDSS_WRITEBACK) += mdss_wb.o
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
new file mode 100644
index 0000000..aaf6690
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss.h
@@ -0,0 +1,63 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef MDSS_H
+#define MDSS_H
+
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+
+#define MDSS_REG_WRITE(addr, val) writel_relaxed(val, mdss_reg_base + addr)
+#define MDSS_REG_READ(addr) readl_relaxed(mdss_reg_base + addr)
+
+extern unsigned char *mdss_reg_base;
+
+struct mdss_res_type {
+	u32 rev;
+	u32 mdp_rev;
+	struct clk *mdp_clk;
+	struct clk *mdp_pclk;
+	struct clk *mdp_lut_clk;
+	struct clk *vsync_clk;
+	struct regulator *fs;
+
+	struct workqueue_struct *clk_ctrl_wq;
+	struct delayed_work clk_ctrl_worker;
+
+	u32 irq;
+	u32 irq_mask;
+	u32 irq_ena;
+	u32 irq_buzy;
+
+	u32 clk_ena;
+	u32 suspend;
+	u32 timeout;
+
+	u32 fs_ena;
+	u32 vsync_ena;
+
+	u32 intf;
+	u32 eintf_ena;
+	u32 prim_ptype;
+	u32 res_init;
+	u32 pdev_lcnt;
+	u32 bus_hdl;
+
+	u32 smp_mb_cnt;
+	u32 smp_mb_size;
+	u32 *pipe_type_map;
+	u32 *mixer_type_map;
+};
+extern struct mdss_res_type *mdss_res;
+#endif /* MDSS_H */
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
new file mode 100644
index 0000000..0fedb6c
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -0,0 +1,1231 @@
+/*
+ * Core MDSS framebuffer driver.
+ *
+ * Copyright (C) 2007 Google Incorporated
+ * Copyright (c) 2008-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
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/android_pmem.h>
+#include <linux/bootmem.h>
+#include <linux/console.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/leds.h>
+#include <linux/memory.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/msm_mdp.h>
+#include <linux/proc_fs.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+
+#include <mach/board.h>
+
+#include "mdss_fb.h"
+#include "mdss_mdp.h"
+
+#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
+#define MDSS_FB_NUM 3
+#else
+#define MDSS_FB_NUM 2
+#endif
+
+#define MAX_FBI_LIST 32
+static struct fb_info *fbi_list[MAX_FBI_LIST];
+static int fbi_list_index;
+
+static u32 mdss_fb_pseudo_palette[16] = {
+	0x00000000, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
+};
+
+static int mdss_fb_register(struct msm_fb_data_type *mfd);
+static int mdss_fb_open(struct fb_info *info, int user);
+static int mdss_fb_release(struct fb_info *info, int user);
+static int mdss_fb_pan_display(struct fb_var_screeninfo *var,
+			       struct fb_info *info);
+static int mdss_fb_check_var(struct fb_var_screeninfo *var,
+			     struct fb_info *info);
+static int mdss_fb_set_par(struct fb_info *info);
+static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info,
+			     int op_enable);
+static int mdss_fb_suspend_sub(struct msm_fb_data_type *mfd);
+static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
+			 unsigned long arg);
+static int mdss_fb_mmap(struct fb_info *info, struct vm_area_struct *vma);
+
+#define MAX_BACKLIGHT_BRIGHTNESS 255
+static int lcd_backlight_registered;
+
+static void mdss_fb_set_bl_brightness(struct led_classdev *led_cdev,
+				      enum led_brightness value)
+{
+	struct msm_fb_data_type *mfd = dev_get_drvdata(led_cdev->dev->parent);
+	int bl_lvl;
+
+	if (value > MAX_BACKLIGHT_BRIGHTNESS)
+		value = MAX_BACKLIGHT_BRIGHTNESS;
+
+	/* This maps android backlight level 0 to 255 into
+	   driver backlight level 0 to bl_max with rounding */
+	bl_lvl = (2 * value * mfd->panel_info.bl_max + MAX_BACKLIGHT_BRIGHTNESS)
+		 /(2 * MAX_BACKLIGHT_BRIGHTNESS);
+
+	if (!bl_lvl && value)
+		bl_lvl = 1;
+
+	mdss_fb_set_backlight(mfd, bl_lvl);
+}
+
+static struct led_classdev backlight_led = {
+	.name           = "lcd-backlight",
+	.brightness     = MAX_BACKLIGHT_BRIGHTNESS,
+	.brightness_set = mdss_fb_set_bl_brightness,
+};
+
+static ssize_t mdss_fb_get_type(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	ssize_t ret = 0;
+	struct fb_info *fbi = dev_get_drvdata(dev);
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+
+	switch (mfd->panel_info.type) {
+	case NO_PANEL:
+		ret = snprintf(buf, PAGE_SIZE, "no panel\n");
+		break;
+	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;
+	case MIPI_VIDEO_PANEL:
+		ret = snprintf(buf, PAGE_SIZE, "mipi dsi video panel\n");
+		break;
+	case MIPI_CMD_PANEL:
+		ret = snprintf(buf, PAGE_SIZE, "mipi dsi cmd panel\n");
+		break;
+	case WRITEBACK_PANEL:
+		ret = snprintf(buf, PAGE_SIZE, "writeback panel\n");
+		break;
+	default:
+		ret = snprintf(buf, PAGE_SIZE, "unknown panel\n");
+		break;
+	}
+
+	return ret;
+}
+
+static DEVICE_ATTR(mdss_fb_type, S_IRUGO, mdss_fb_get_type, NULL);
+static struct attribute *mdss_fb_attrs[] = {
+	&dev_attr_mdss_fb_type.attr,
+	NULL,
+};
+
+static struct attribute_group mdss_fb_attr_group = {
+	.attrs = mdss_fb_attrs,
+};
+
+static int mdss_fb_create_sysfs(struct msm_fb_data_type *mfd)
+{
+	int rc;
+
+	rc = sysfs_create_group(&mfd->fbi->dev->kobj, &mdss_fb_attr_group);
+	if (rc)
+		pr_err("sysfs group creation failed, rc=%d\n", rc);
+	return rc;
+}
+
+static void mdss_fb_remove_sysfs(struct msm_fb_data_type *mfd)
+{
+	sysfs_remove_group(&mfd->fbi->dev->kobj, &mdss_fb_attr_group);
+}
+
+static int mdss_fb_probe(struct platform_device *pdev)
+{
+	struct msm_fb_data_type *mfd = NULL;
+	struct mdss_panel_data *pdata;
+	struct fb_info *fbi;
+	int rc;
+
+	if (fbi_list_index >= MAX_FBI_LIST)
+		return -ENOMEM;
+
+	pdata = dev_get_platdata(&pdev->dev);
+	if (!pdata)
+		return -ENODEV;
+
+	/*
+	 * alloc framebuffer info + par data
+	 */
+	fbi = framebuffer_alloc(sizeof(struct msm_fb_data_type), &pdev->dev);
+	if (fbi == NULL) {
+		pr_err("can't allocate framebuffer info data!\n");
+		return -ENOMEM;
+	}
+
+	mfd = (struct msm_fb_data_type *)fbi->par;
+	mfd->key = MFD_KEY;
+	mfd->fbi = fbi;
+	mfd->panel_info = pdata->panel_info;
+	mfd->panel.type = pdata->panel_info.type;
+	mfd->panel.id = mfd->index;
+	mfd->fb_page = MDSS_FB_NUM;
+	mfd->index = fbi_list_index;
+	mfd->mdp_fb_page_protection = MDP_FB_PAGE_PROTECTION_WRITECOMBINE;
+	mfd->panel_info.frame_count = 0;
+	mfd->bl_level = 0;
+	mfd->fb_imgType = MDP_RGBA_8888;
+	mfd->iclient = msm_ion_client_create(-1, pdev->name);
+	if (IS_ERR(mfd->iclient))
+		mfd->iclient = NULL;
+
+	mfd->pdev = pdev;
+
+	mutex_init(&mfd->lock);
+
+	fbi_list[fbi_list_index++] = fbi;
+
+	platform_set_drvdata(pdev, mfd);
+
+	rc = mdss_fb_register(mfd);
+	if (rc)
+		return rc;
+
+	rc = pm_runtime_set_active(mfd->fbi->dev);
+	if (rc < 0)
+		pr_err("pm_runtime: fail to set active.\n");
+	pm_runtime_enable(mfd->fbi->dev);
+
+	/* android supports only one lcd-backlight/lcd for now */
+	if (!lcd_backlight_registered) {
+		if (led_classdev_register(&pdev->dev, &backlight_led))
+			pr_err("led_classdev_register failed\n");
+		else
+			lcd_backlight_registered = 1;
+	}
+
+	mdss_fb_create_sysfs(mfd);
+
+	return 0;
+}
+
+static int mdss_fb_remove(struct platform_device *pdev)
+{
+	struct msm_fb_data_type *mfd;
+
+	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
+
+	mdss_fb_remove_sysfs(mfd);
+
+	pm_runtime_disable(mfd->fbi->dev);
+
+	if (!mfd)
+		return -ENODEV;
+
+	if (mfd->key != MFD_KEY)
+		return -EINVAL;
+
+	if (mdss_fb_suspend_sub(mfd))
+		pr_err("msm_fb_remove: can't stop the device %d\n",
+			    mfd->index);
+
+	/* remove /dev/fb* */
+	unregister_framebuffer(mfd->fbi);
+
+	if (lcd_backlight_registered) {
+		lcd_backlight_registered = 0;
+		led_classdev_unregister(&backlight_led);
+	}
+
+	return 0;
+}
+
+static int mdss_fb_suspend_sub(struct msm_fb_data_type *mfd)
+{
+	int ret = 0;
+
+	if ((!mfd) || (mfd->key != MFD_KEY))
+		return 0;
+
+	/*
+	 * suspend this channel
+	 */
+	mfd->suspend.op_enable = mfd->op_enable;
+	mfd->suspend.panel_power_on = mfd->panel_power_on;
+
+	if (mfd->op_enable) {
+		ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, mfd->fbi,
+				mfd->suspend.op_enable);
+		if (ret) {
+			pr_warn("can't turn off display!\n");
+			return ret;
+		}
+		mfd->op_enable = false;
+	}
+
+	return 0;
+}
+
+#if defined(CONFIG_PM)
+static int mdss_fb_resume_sub(struct msm_fb_data_type *mfd)
+{
+	int ret = 0;
+
+	if ((!mfd) || (mfd->key != MFD_KEY))
+		return 0;
+
+	/* resume state var recover */
+	mfd->op_enable = mfd->suspend.op_enable;
+
+	if (mfd->suspend.panel_power_on) {
+		ret = mdss_fb_blank_sub(FB_BLANK_UNBLANK, mfd->fbi,
+					mfd->op_enable);
+		if (ret)
+			pr_warn("can't turn on display!\n");
+	}
+
+	return ret;
+}
+
+static int mdss_fb_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct msm_fb_data_type *mfd;
+	int ret = 0;
+
+	pr_debug("mdss_fb_suspend\n");
+
+	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
+
+	if ((!mfd) || (mfd->key != MFD_KEY))
+		return 0;
+
+	console_lock();
+	fb_set_suspend(mfd->fbi, FBINFO_STATE_SUSPENDED);
+
+	ret = mdss_fb_suspend_sub(mfd);
+	if (ret != 0) {
+		pr_err("failed to suspend! %d\n", ret);
+		fb_set_suspend(mfd->fbi, FBINFO_STATE_RUNNING);
+	} else {
+		pdev->dev.power.power_state = state;
+	}
+
+	console_unlock();
+	return ret;
+}
+
+static int mdss_fb_resume(struct platform_device *pdev)
+{
+	/* This resume function is called when interrupt is enabled.
+	 */
+	int ret = 0;
+	struct msm_fb_data_type *mfd;
+
+	pr_debug("mdss_fb_resume\n");
+
+	mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
+
+	if ((!mfd) || (mfd->key != MFD_KEY))
+		return 0;
+
+	console_lock();
+	ret = mdss_fb_resume_sub(mfd);
+	pdev->dev.power.power_state = PMSG_ON;
+	fb_set_suspend(mfd->fbi, FBINFO_STATE_RUNNING);
+	console_unlock();
+
+	return ret;
+}
+#else
+#define mdss_fb_suspend NULL
+#define mdss_fb_resume NULL
+#endif
+
+#if defined(CONFIG_PM) && defined(CONFIG_SUSPEND)
+static int mdss_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 = mdss_fb_suspend_sub(mfd);
+
+	return ret;
+}
+
+static int mdss_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 = mdss_fb_resume_sub(mfd);
+
+	return ret;
+}
+#else
+#define mdss_fb_ext_suspend NULL
+#define mdss_fb_ext_resume NULL
+#endif
+
+static const struct dev_pm_ops mdss_fb_dev_pm_ops = {
+	.suspend = mdss_fb_ext_suspend,
+	.resume = mdss_fb_ext_resume,
+};
+
+static struct platform_driver mdss_fb_driver = {
+	.probe = mdss_fb_probe,
+	.remove = mdss_fb_remove,
+	.suspend = mdss_fb_suspend,
+	.resume = mdss_fb_resume,
+	.shutdown = NULL,
+	.driver = {
+		.name = "mdss_fb",
+		.pm = &mdss_fb_dev_pm_ops,
+	},
+};
+
+static int unset_bl_level, bl_updated;
+static int bl_level_old;
+
+void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl)
+{
+	struct mdss_panel_data *pdata;
+
+	if (!mfd->panel_power_on || !bl_updated) {
+		unset_bl_level = bkl_lvl;
+		return;
+	} else {
+		unset_bl_level = 0;
+	}
+
+	pdata = dev_get_platdata(&mfd->pdev->dev);
+
+	if ((pdata) && (pdata->set_backlight)) {
+		mutex_lock(&mfd->lock);
+		if (bl_level_old == bkl_lvl) {
+			mutex_unlock(&mfd->lock);
+			return;
+		}
+		mfd->bl_level = bkl_lvl;
+		pdata->set_backlight(mfd->bl_level);
+		bl_level_old = mfd->bl_level;
+		mutex_unlock(&mfd->lock);
+	}
+}
+
+void mdss_fb_update_backlight(struct msm_fb_data_type *mfd)
+{
+	struct mdss_panel_data *pdata;
+
+	if (unset_bl_level && !bl_updated) {
+		pdata = dev_get_platdata(&mfd->pdev->dev);
+		if ((pdata) && (pdata->set_backlight)) {
+			mutex_lock(&mfd->lock);
+			mfd->bl_level = unset_bl_level;
+			pdata->set_backlight(mfd->bl_level);
+			bl_level_old = unset_bl_level;
+			mutex_unlock(&mfd->lock);
+			bl_updated = 1;
+		}
+	}
+}
+
+static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info,
+			     int op_enable)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	int ret = 0;
+
+	if (!op_enable)
+		return -EPERM;
+
+	switch (blank_mode) {
+	case FB_BLANK_UNBLANK:
+		if (!mfd->panel_power_on) {
+			msleep(20);
+			ret = mfd->on_fnc(mfd);
+			if (ret == 0)
+				mfd->panel_power_on = true;
+		}
+		break;
+
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_NORMAL:
+	case FB_BLANK_POWERDOWN:
+	default:
+		if (mfd->panel_power_on) {
+			int curr_pwr_state;
+
+			mfd->op_enable = false;
+			curr_pwr_state = mfd->panel_power_on;
+			mfd->panel_power_on = false;
+			bl_updated = 0;
+
+			msleep(20);
+			ret = mfd->off_fnc(mfd);
+			if (ret)
+				mfd->panel_power_on = curr_pwr_state;
+
+			mfd->op_enable = true;
+		}
+		break;
+	}
+
+	return ret;
+}
+
+static int mdss_fb_blank(int blank_mode, struct fb_info *info)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	return mdss_fb_blank_sub(blank_mode, info, mfd->op_enable);
+}
+
+/*
+ * Custom Framebuffer mmap() function for MSM driver.
+ * Differs from standard mmap() function by allowing for customized
+ * page-protection.
+ */
+static int mdss_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+	/* Get frame buffer memory range. */
+	unsigned long start = info->fix.smem_start;
+	u32 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
+	unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+
+	if (off >= len) {
+		/* memory mapped io */
+		off -= len;
+		if (info->var.accel_flags) {
+			mutex_unlock(&info->lock);
+			return -EINVAL;
+		}
+		start = info->fix.mmio_start;
+		len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
+	}
+
+	/* Set VM flags. */
+	start &= PAGE_MASK;
+	if ((vma->vm_end - vma->vm_start + off) > len)
+		return -EINVAL;
+	off += start;
+	vma->vm_pgoff = off >> PAGE_SHIFT;
+	/* This is an IO map - tell maydump to skip this VMA */
+	vma->vm_flags |= VM_IO | VM_RESERVED;
+
+	/* Set VM page protection */
+	if (mfd->mdp_fb_page_protection == MDP_FB_PAGE_PROTECTION_WRITECOMBINE)
+		vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+	else if (mfd->mdp_fb_page_protection ==
+		 MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE)
+		vma->vm_page_prot = pgprot_writethroughcache(vma->vm_page_prot);
+	else if (mfd->mdp_fb_page_protection ==
+		 MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE)
+		vma->vm_page_prot = pgprot_writebackcache(vma->vm_page_prot);
+	else if (mfd->mdp_fb_page_protection ==
+		 MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE)
+		vma->vm_page_prot = pgprot_writebackwacache(vma->vm_page_prot);
+	else
+		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+	/* Remap the frame buffer I/O range */
+	if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+			       vma->vm_end - vma->vm_start,
+			       vma->vm_page_prot))
+		return -EAGAIN;
+
+	return 0;
+}
+
+static struct fb_ops mdss_fb_ops = {
+	.owner = THIS_MODULE,
+	.fb_open = mdss_fb_open,
+	.fb_release = mdss_fb_release,
+	.fb_check_var = mdss_fb_check_var,	/* vinfo check */
+	.fb_set_par = mdss_fb_set_par,	/* set the video mode */
+	.fb_blank = mdss_fb_blank,	/* blank display */
+	.fb_pan_display = mdss_fb_pan_display,	/* pan display */
+	.fb_ioctl = mdss_fb_ioctl,	/* perform fb specific ioctl */
+	.fb_mmap = mdss_fb_mmap,
+};
+
+static u32 mdss_fb_line_length(u32 fb_index, u32 xres, int bpp)
+{
+	/* The adreno GPU hardware requires that the pitch be aligned to
+	   32 pixels for color buffers, so for the cases where the GPU
+	   is writing directly to fb0, the framebuffer pitch
+	   also needs to be 32 pixel aligned */
+
+	if (fb_index == 0)
+		return ALIGN(xres, 32) * bpp;
+	else
+		return xres * bpp;
+}
+
+static int mdss_fb_alloc_fbmem(struct msm_fb_data_type *mfd)
+{
+	void *virt = NULL;
+	unsigned long phys = 0;
+	size_t size;
+
+	size = PAGE_ALIGN(mfd->fbi->fix.line_length * mfd->panel_info.yres);
+	size *= mfd->fb_page;
+
+	if (mfd->index == 0) {
+		virt = dma_alloc_coherent(NULL, size, (dma_addr_t *) &phys,
+				GFP_KERNEL);
+		if (!virt) {
+			pr_err("unable to alloc fb memory size=%u\n", size);
+			return -ENOMEM;
+		}
+
+		pr_info("allocating %u bytes at %p (%lx phys) for fb %d\n",
+			size, virt, phys, mfd->index);
+	} else {
+		pr_debug("no memory allocated for fb%d\n", mfd->index);
+		size = 0;
+	}
+
+	mfd->fbi->screen_base = virt;
+	mfd->fbi->fix.smem_start = phys;
+	mfd->fbi->fix.smem_len = size;
+
+	return 0;
+}
+
+static int mdss_fb_register(struct msm_fb_data_type *mfd)
+{
+	int ret = -ENODEV;
+	int bpp;
+	struct mdss_panel_info *panel_info = &mfd->panel_info;
+	struct fb_info *fbi = mfd->fbi;
+	struct fb_fix_screeninfo *fix;
+	struct fb_var_screeninfo *var;
+	int *id;
+
+	/*
+	 * fb info initialization
+	 */
+	fix = &fbi->fix;
+	var = &fbi->var;
+
+	fix->type_aux = 0;	/* if type == FB_TYPE_INTERLEAVED_PLANES */
+	fix->visual = FB_VISUAL_TRUECOLOR;	/* True Color */
+	fix->ywrapstep = 0;	/* No support */
+	fix->mmio_start = 0;	/* No MMIO Address */
+	fix->mmio_len = 0;	/* No MMIO Address */
+	fix->accel = FB_ACCEL_NONE;/* FB_ACCEL_MSM needes to be added in fb.h */
+
+	var->xoffset = 0,	/* Offset from virtual to visible */
+	var->yoffset = 0,	/* resolution */
+	var->grayscale = 0,	/* No graylevels */
+	var->nonstd = 0,	/* standard pixel format */
+	var->activate = FB_ACTIVATE_VBL,	/* activate it at vsync */
+	var->height = -1,	/* height of picture in mm */
+	var->width = -1,	/* width of picture in mm */
+	var->accel_flags = 0,	/* acceleration flags */
+	var->sync = 0,	/* see FB_SYNC_* */
+	var->rotate = 0,	/* angle we rotate counter clockwise */
+	mfd->op_enable = false;
+
+	switch (mfd->fb_imgType) {
+	case MDP_RGB_565:
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->xpanstep = 1;
+		fix->ypanstep = 1;
+		var->vmode = FB_VMODE_NONINTERLACED;
+		var->blue.offset = 0;
+		var->green.offset = 5;
+		var->red.offset = 11;
+		var->blue.length = 5;
+		var->green.length = 6;
+		var->red.length = 5;
+		var->blue.msb_right = 0;
+		var->green.msb_right = 0;
+		var->red.msb_right = 0;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		bpp = 2;
+		break;
+
+	case MDP_RGB_888:
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->xpanstep = 1;
+		fix->ypanstep = 1;
+		var->vmode = FB_VMODE_NONINTERLACED;
+		var->blue.offset = 0;
+		var->green.offset = 8;
+		var->red.offset = 16;
+		var->blue.length = 8;
+		var->green.length = 8;
+		var->red.length = 8;
+		var->blue.msb_right = 0;
+		var->green.msb_right = 0;
+		var->red.msb_right = 0;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		bpp = 3;
+		break;
+
+	case MDP_ARGB_8888:
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->xpanstep = 1;
+		fix->ypanstep = 1;
+		var->vmode = FB_VMODE_NONINTERLACED;
+		var->blue.offset = 0;
+		var->green.offset = 8;
+		var->red.offset = 16;
+		var->blue.length = 8;
+		var->green.length = 8;
+		var->red.length = 8;
+		var->blue.msb_right = 0;
+		var->green.msb_right = 0;
+		var->red.msb_right = 0;
+		var->transp.offset = 24;
+		var->transp.length = 8;
+		bpp = 4;
+		break;
+
+	case MDP_RGBA_8888:
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->xpanstep = 1;
+		fix->ypanstep = 1;
+		var->vmode = FB_VMODE_NONINTERLACED;
+		var->blue.offset = 8;
+		var->green.offset = 16;
+		var->red.offset = 24;
+		var->blue.length = 8;
+		var->green.length = 8;
+		var->red.length = 8;
+		var->blue.msb_right = 0;
+		var->green.msb_right = 0;
+		var->red.msb_right = 0;
+		var->transp.offset = 0;
+		var->transp.length = 8;
+		bpp = 4;
+		break;
+
+	case MDP_YCRYCB_H2V1:
+		fix->type = FB_TYPE_INTERLEAVED_PLANES;
+		fix->xpanstep = 2;
+		fix->ypanstep = 1;
+		var->vmode = FB_VMODE_NONINTERLACED;
+
+		/* how about R/G/B offset? */
+		var->blue.offset = 0;
+		var->green.offset = 5;
+		var->red.offset = 11;
+		var->blue.length = 5;
+		var->green.length = 6;
+		var->red.length = 5;
+		var->blue.msb_right = 0;
+		var->green.msb_right = 0;
+		var->red.msb_right = 0;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		bpp = 2;
+		break;
+
+	default:
+		pr_err("msm_fb_init: fb %d unkown image type!\n",
+			    mfd->index);
+		return ret;
+	}
+
+	fix->type = panel_info->is_3d_panel;
+	fix->line_length = mdss_fb_line_length(mfd->index, panel_info->xres,
+					       bpp);
+	mfd->var_xres = panel_info->xres;
+	mfd->var_yres = panel_info->yres;
+
+	var->pixclock = mfd->panel_info.clk_rate;
+	mfd->var_pixclock = var->pixclock;
+
+	var->xres = panel_info->xres;
+	var->yres = panel_info->yres;
+	var->xres_virtual = panel_info->xres;
+	var->yres_virtual = panel_info->yres * mfd->fb_page;
+	var->bits_per_pixel = bpp * 8;	/* FrameBuffer color depth */
+
+	/* id field for fb app  */
+
+	id = (int *)&mfd->panel;
+
+	snprintf(fix->id, sizeof(fix->id), "mdssfb_%x", (u32) *id);
+
+	fbi->fbops = &mdss_fb_ops;
+	fbi->flags = FBINFO_FLAG_DEFAULT;
+	fbi->pseudo_palette = mdss_fb_pseudo_palette;
+
+	mfd->ref_cnt = 0;
+	mfd->panel_power_on = false;
+
+	if (mdss_fb_alloc_fbmem(mfd)) {
+		pr_err("unable to allocate framebuffer memory\n");
+		return -ENOMEM;
+	}
+
+	mfd->op_enable = true;
+
+	/* cursor memory allocation */
+	if (mfd->cursor_update) {
+		mfd->cursor_buf = dma_alloc_coherent(NULL, MDSS_MDP_CURSOR_SIZE,
+					(dma_addr_t *) &mfd->cursor_buf_phys,
+					GFP_KERNEL);
+		if (!mfd->cursor_buf)
+			mfd->cursor_update = 0;
+	}
+
+	if (mfd->lut_update) {
+		ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
+		if (ret)
+			pr_err("fb_alloc_cmap() failed!\n");
+	}
+
+	if (register_framebuffer(fbi) < 0) {
+		if (mfd->lut_update)
+			fb_dealloc_cmap(&fbi->cmap);
+
+		if (mfd->cursor_buf)
+			dma_free_coherent(NULL, MDSS_MDP_CURSOR_SIZE,
+					  mfd->cursor_buf,
+					  (dma_addr_t) mfd->cursor_buf_phys);
+
+		mfd->op_enable = false;
+		return -EPERM;
+	}
+
+	pr_info("FrameBuffer[%d] %dx%d size=%d registered successfully!\n",
+		     mfd->index, fbi->var.xres, fbi->var.yres,
+		     fbi->fix.smem_len);
+
+	ret = 0;
+
+	return ret;
+}
+
+static int mdss_fb_open(struct fb_info *info, int user)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	int result;
+
+	result = pm_runtime_get_sync(info->dev);
+
+	if (result < 0)
+		pr_err("pm_runtime: fail to wake up\n");
+
+
+	if (!mfd->ref_cnt) {
+		result = mdss_fb_blank_sub(FB_BLANK_UNBLANK, info,
+					   mfd->op_enable);
+		if (result) {
+			pr_err("mdss_fb_open: can't turn on display!\n");
+			return result;
+		}
+	}
+
+	mfd->ref_cnt++;
+	return 0;
+}
+
+static int mdss_fb_release(struct fb_info *info, int user)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	int ret = 0;
+
+	if (!mfd->ref_cnt) {
+		pr_info("try to close unopened fb %d!\n", mfd->index);
+		return -EINVAL;
+	}
+
+	mfd->ref_cnt--;
+
+	if (!mfd->ref_cnt) {
+		ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info,
+				       mfd->op_enable);
+		if (ret) {
+			pr_err("can't turn off display!\n");
+			return ret;
+		}
+	}
+
+	pm_runtime_put(info->dev);
+	return ret;
+}
+
+static int mdss_fb_pan_display(struct fb_var_screeninfo *var,
+			       struct fb_info *info)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+
+	if ((!mfd->op_enable) || (!mfd->panel_power_on))
+		return -EPERM;
+
+	if (var->xoffset > (info->var.xres_virtual - info->var.xres))
+		return -EINVAL;
+
+	if (var->yoffset > (info->var.yres_virtual - info->var.yres))
+		return -EINVAL;
+
+	if (info->fix.xpanstep)
+		info->var.xoffset =
+		(var->xoffset / info->fix.xpanstep) * info->fix.xpanstep;
+
+	if (info->fix.ypanstep)
+		info->var.yoffset =
+		(var->yoffset / info->fix.ypanstep) * info->fix.ypanstep;
+
+	if (mfd->dma_fnc)
+		mfd->dma_fnc(mfd);
+	else
+		pr_warn("dma function not set for panel type=%d\n",
+				mfd->panel.type);
+
+	mdss_fb_update_backlight(mfd);
+
+	++mfd->panel_info.frame_count;
+	return 0;
+}
+
+static int mdss_fb_check_var(struct fb_var_screeninfo *var,
+			     struct fb_info *info)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	u32 len;
+
+	if (var->rotate != FB_ROTATE_UR)
+		return -EINVAL;
+	if (var->grayscale != info->var.grayscale)
+		return -EINVAL;
+
+	switch (var->bits_per_pixel) {
+	case 16:
+		if ((var->green.offset != 5) ||
+		    !((var->blue.offset == 11)
+		      || (var->blue.offset == 0)) ||
+		    !((var->red.offset == 11)
+		      || (var->red.offset == 0)) ||
+		    (var->blue.length != 5) ||
+		    (var->green.length != 6) ||
+		    (var->red.length != 5) ||
+		    (var->blue.msb_right != 0) ||
+		    (var->green.msb_right != 0) ||
+		    (var->red.msb_right != 0) ||
+		    (var->transp.offset != 0) ||
+		    (var->transp.length != 0))
+			return -EINVAL;
+		break;
+
+	case 24:
+		if ((var->blue.offset != 0) ||
+		    (var->green.offset != 8) ||
+		    (var->red.offset != 16) ||
+		    (var->blue.length != 8) ||
+		    (var->green.length != 8) ||
+		    (var->red.length != 8) ||
+		    (var->blue.msb_right != 0) ||
+		    (var->green.msb_right != 0) ||
+		    (var->red.msb_right != 0) ||
+		    !(((var->transp.offset == 0) &&
+		       (var->transp.length == 0)) ||
+		      ((var->transp.offset == 24) &&
+		       (var->transp.length == 8))))
+			return -EINVAL;
+		break;
+
+	case 32:
+		/* Figure out if the user meant RGBA or ARGB
+		   and verify the position of the RGB components */
+
+		if (var->transp.offset == 24) {
+			if ((var->blue.offset != 0) ||
+			    (var->green.offset != 8) ||
+			    (var->red.offset != 16))
+				return -EINVAL;
+		} else if (var->transp.offset == 0) {
+			if ((var->blue.offset != 8) ||
+			    (var->green.offset != 16) ||
+			    (var->red.offset != 24))
+				return -EINVAL;
+		} else
+			return -EINVAL;
+
+		/* Check the common values for both RGBA and ARGB */
+
+		if ((var->blue.length != 8) ||
+		    (var->green.length != 8) ||
+		    (var->red.length != 8) ||
+		    (var->transp.length != 8) ||
+		    (var->blue.msb_right != 0) ||
+		    (var->green.msb_right != 0) ||
+		    (var->red.msb_right != 0))
+			return -EINVAL;
+
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if ((var->xres_virtual <= 0) || (var->yres_virtual <= 0))
+		return -EINVAL;
+
+	len = var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8);
+	if (len > info->fix.smem_len)
+		return -EINVAL;
+
+	if ((var->xres == 0) || (var->yres == 0))
+		return -EINVAL;
+
+	if ((var->xres > mfd->panel_info.xres) ||
+	    (var->yres > mfd->panel_info.yres))
+		return -EINVAL;
+
+	if (var->xoffset > (var->xres_virtual - var->xres))
+		return -EINVAL;
+
+	if (var->yoffset > (var->yres_virtual - var->yres))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int mdss_fb_set_par(struct fb_info *info)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	struct fb_var_screeninfo *var = &info->var;
+	int old_imgType;
+	int blank = 0;
+
+	old_imgType = mfd->fb_imgType;
+	switch (var->bits_per_pixel) {
+	case 16:
+		if (var->red.offset == 0)
+			mfd->fb_imgType = MDP_BGR_565;
+		else
+			mfd->fb_imgType	= MDP_RGB_565;
+		break;
+
+	case 24:
+		if ((var->transp.offset == 0) && (var->transp.length == 0))
+			mfd->fb_imgType = MDP_RGB_888;
+		else if ((var->transp.offset == 24) &&
+			 (var->transp.length == 8)) {
+			mfd->fb_imgType = MDP_ARGB_8888;
+			info->var.bits_per_pixel = 32;
+		}
+		break;
+
+	case 32:
+		if (var->transp.offset == 24)
+			mfd->fb_imgType = MDP_ARGB_8888;
+		else
+			mfd->fb_imgType	= MDP_RGBA_8888;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if ((mfd->var_pixclock != var->pixclock) ||
+	    (mfd->hw_refresh && ((mfd->fb_imgType != old_imgType) ||
+				 (mfd->var_pixclock != var->pixclock) ||
+				 (mfd->var_xres != var->xres) ||
+				 (mfd->var_yres != var->yres)))) {
+		mfd->var_xres = var->xres;
+		mfd->var_yres = var->yres;
+		mfd->var_pixclock = var->pixclock;
+		blank = 1;
+	}
+	mfd->fbi->fix.line_length = mdss_fb_line_length(mfd->index, var->xres,
+						var->bits_per_pixel / 8);
+
+	if (blank) {
+		mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info, mfd->op_enable);
+		mdss_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable);
+	}
+
+	return 0;
+}
+
+static int mdss_fb_cursor(struct fb_info *info, void __user *p)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	struct fb_cursor cursor;
+	int ret;
+
+	if (!mfd->cursor_update)
+		return -ENODEV;
+
+	ret = copy_from_user(&cursor, p, sizeof(cursor));
+	if (ret)
+		return ret;
+
+	return mfd->cursor_update(info, &cursor);
+}
+
+static int mdss_fb_set_lut(struct fb_info *info, void __user *p)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	struct fb_cmap cmap;
+	int ret;
+
+	if (!mfd->lut_update)
+		return -ENODEV;
+
+	ret = copy_from_user(&cmap, p, sizeof(cmap));
+	if (ret)
+		return ret;
+
+	mfd->lut_update(info, &cmap);
+	return 0;
+}
+
+static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
+			 unsigned long arg)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	void __user *argp = (void __user *)arg;
+	struct mdp_page_protection fb_page_protection;
+	int ret = -ENOSYS;
+
+	switch (cmd) {
+	case MSMFB_CURSOR:
+		ret = mdss_fb_cursor(info, argp);
+		break;
+
+	case MSMFB_SET_LUT:
+		ret = mdss_fb_set_lut(info, argp);
+		break;
+
+	case MSMFB_GET_PAGE_PROTECTION:
+		fb_page_protection.page_protection =
+			mfd->mdp_fb_page_protection;
+		ret = copy_to_user(argp, &fb_page_protection,
+				   sizeof(fb_page_protection));
+		if (ret)
+			return ret;
+		break;
+
+	default:
+		if (mfd->ioctl_handler)
+			ret = mfd->ioctl_handler(mfd, cmd, argp);
+		break;
+	}
+
+	if (ret == -ENOSYS)
+		pr_err("unsupported ioctl (%x)\n", cmd);
+
+	return ret;
+}
+
+int mdss_register_panel(struct mdss_panel_data *pdata)
+{
+	struct platform_device *mdss_fb_dev = NULL;
+	struct msm_fb_data_type *mfd;
+	int rc;
+
+	if (!mdss_res) {
+		pr_err("mdss mdp resources not initialized yet\n");
+		return -ENODEV;
+	}
+
+	mdss_fb_dev = platform_device_alloc("mdss_fb", pdata->panel_info.pdest);
+	if (!mdss_fb_dev) {
+		pr_err("unable to allocate mdss_fb device\n");
+		return -ENOMEM;
+	}
+
+	mdss_fb_dev->dev.platform_data = pdata;
+
+	rc = platform_device_add(mdss_fb_dev);
+	if (rc) {
+		platform_device_put(mdss_fb_dev);
+		pr_err("unable to probe mdss_fb device (%d)\n", rc);
+		return rc;
+	}
+
+	mfd = platform_get_drvdata(mdss_fb_dev);
+	if (!mfd)
+		return -ENODEV;
+	if (mfd->key != MFD_KEY)
+		return -EINVAL;
+
+	mfd->on_fnc = mdss_mdp_ctl_on;
+	mfd->off_fnc = mdss_mdp_ctl_off;
+
+	rc = mdss_mdp_overlay_init(mfd);
+	if (rc)
+		pr_err("unable to init overlay\n");
+
+	return rc;
+}
+EXPORT_SYMBOL(mdss_register_panel);
+
+int mdss_fb_get_phys_info(unsigned long *start, unsigned long *len, int fb_num)
+{
+	struct fb_info *info;
+
+	if (fb_num > MAX_FBI_LIST)
+		return -EINVAL;
+
+	info = fbi_list[fb_num];
+	if (!info)
+		return -ENOENT;
+
+	*start = info->fix.smem_start;
+	*len = info->fix.smem_len;
+	return 0;
+}
+EXPORT_SYMBOL(mdss_fb_get_phys_info);
+
+int __init mdss_fb_init(void)
+{
+	int rc = -ENODEV;
+
+	if (platform_driver_register(&mdss_fb_driver))
+		return rc;
+
+	return 0;
+}
+
+module_init(mdss_fb_init);
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
new file mode 100644
index 0000000..a3f0dbe
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -0,0 +1,98 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef MDSS_FB_H
+#define MDSS_FB_H
+
+#include <linux/ion.h>
+#include <linux/list.h>
+#include <linux/msm_mdp.h>
+#include <linux/types.h>
+
+#include "mdss_mdp.h"
+#include "mdss_panel.h"
+
+#define MSM_FB_DEFAULT_PAGE_SIZE 2
+#define MFD_KEY  0x11161126
+#define MSM_FB_MAX_DEV_LIST 32
+
+#define MSM_FB_ENABLE_DBGFS
+
+#ifndef MAX
+#define  MAX(x, y) (((x) > (y)) ? (x) : (y))
+#endif
+
+#ifndef MIN
+#define  MIN(x, y) (((x) < (y)) ? (x) : (y))
+#endif
+
+struct disp_info_type_suspend {
+	int op_enable;
+	int panel_power_on;
+};
+
+struct msm_fb_data_type {
+	u32 key;
+	u32 index;
+	u32 ref_cnt;
+	u32 fb_page;
+
+	struct panel_id panel;
+	struct mdss_panel_info panel_info;
+
+	u32 dest;
+	struct fb_info *fbi;
+
+	int op_enable;
+	u32 fb_imgType;
+
+	int hw_refresh;
+
+	int overlay_play_enable;
+
+	int panel_power_on;
+	struct disp_info_type_suspend suspend;
+
+	int (*on_fnc) (struct msm_fb_data_type *mfd);
+	int (*off_fnc) (struct msm_fb_data_type *mfd);
+	int (*kickoff_fnc) (struct mdss_mdp_ctl *ctl);
+	int (*ioctl_handler) (struct msm_fb_data_type *mfd, u32 cmd, void *arg);
+	void (*dma_fnc) (struct msm_fb_data_type *mfd);
+	int (*cursor_update) (struct fb_info *info,
+			      struct fb_cursor *cursor);
+	int (*lut_update) (struct fb_info *info,
+			   struct fb_cmap *cmap);
+	int (*do_histogram) (struct fb_info *info,
+			     struct mdp_histogram *hist);
+	void *cursor_buf;
+	void *cursor_buf_phys;
+
+	u32 bl_level;
+	struct mutex lock;
+
+	struct platform_device *pdev;
+
+	u32 var_xres;
+	u32 var_yres;
+	u32 var_pixclock;
+
+	u32 mdp_fb_page_protection;
+	struct ion_client *iclient;
+
+	struct mdss_mdp_ctl *ctl;
+};
+
+int mdss_fb_get_phys_info(unsigned long *start, unsigned long *len, int fb_num);
+void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl);
+void mdss_fb_update_backlight(struct msm_fb_data_type *mfd);
+#endif /* MDSS_FB_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
new file mode 100644
index 0000000..d1847c3
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -0,0 +1,494 @@
+/*
+ * MDSS MDP Interface (used by framebuffer core)
+ *
+ * Copyright (c) 2007-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (C) 2007 Google Incorporated
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/hrtimer.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/memory_alloc.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/spinlock.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+
+#include <mach/board.h>
+#include <mach/clk.h>
+#include <mach/hardware.h>
+
+#include "mdss.h"
+#include "mdss_fb.h"
+#include "mdss_mdp.h"
+
+/* 1.15 mdp clk factor */
+#define MDP_CLK_FACTOR(rate) (((rate) * 23) / 20)
+
+unsigned char *mdss_reg_base;
+
+struct mdss_res_type *mdss_res;
+static struct msm_panel_common_pdata *mdp_pdata;
+
+static DEFINE_SPINLOCK(mdp_lock);
+static DEFINE_MUTEX(mdp_clk_lock);
+static DEFINE_MUTEX(mdp_suspend_mutex);
+
+u32 mdss_mdp_pipe_type_map[MDSS_MDP_MAX_SSPP] = {
+	MDSS_MDP_PIPE_TYPE_VIG,
+	MDSS_MDP_PIPE_TYPE_VIG,
+	MDSS_MDP_PIPE_TYPE_VIG,
+	MDSS_MDP_PIPE_TYPE_RGB,
+	MDSS_MDP_PIPE_TYPE_RGB,
+	MDSS_MDP_PIPE_TYPE_RGB,
+	MDSS_MDP_PIPE_TYPE_DMA,
+	MDSS_MDP_PIPE_TYPE_DMA,
+};
+
+u32 mdss_mdp_mixer_type_map[MDSS_MDP_MAX_LAYERMIXER] = {
+	MDSS_MDP_MIXER_TYPE_INTF,
+	MDSS_MDP_MIXER_TYPE_INTF,
+	MDSS_MDP_MIXER_TYPE_INTF,
+	MDSS_MDP_MIXER_TYPE_WRITEBACK,
+	MDSS_MDP_MIXER_TYPE_WRITEBACK,
+};
+
+irqreturn_t mdss_irq_handler(int mdss_irq, void *ptr)
+{
+	u32 intr = MDSS_MDP_REG_READ(MDSS_REG_HW_INTR_STATUS);
+
+	mdss_res->irq_buzy = true;
+
+	if (intr & MDSS_INTR_MDP)
+		mdss_mdp_isr(mdss_irq, ptr);
+
+	mdss_res->irq_buzy = false;
+
+	return IRQ_HANDLED;
+}
+
+int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num)
+{
+	u32 irq;
+	unsigned long irq_flags;
+	int ret = 0;
+
+	if (intr_type == MDSS_MDP_IRQ_INTF_UNDER_RUN ||
+	    intr_type == MDSS_MDP_IRQ_INTF_VSYNC)
+		intf_num = intf_num << 1;
+
+	irq =  BIT(intr_type + intf_num);
+
+	spin_lock_irqsave(&mdp_lock, irq_flags);
+	if (mdss_res->irq_mask & irq) {
+		pr_warn("MDSS IRQ-0x%x is already set, mask=%x irq=%d\n",
+			irq, mdss_res->irq_mask, mdss_res->irq_ena);
+		ret = -EBUSY;
+	} else {
+		mdss_res->irq_mask |= irq;
+		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_CLEAR, irq);
+		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN, mdss_res->irq_mask);
+		if (!mdss_res->irq_ena) {
+			mdss_res->irq_ena = true;
+			enable_irq(mdss_res->irq);
+		}
+	}
+	spin_unlock_irqrestore(&mdp_lock, irq_flags);
+
+	return ret;
+}
+
+void mdss_mdp_irq_disable(u32 intr_type, u32 intf_num)
+{
+	u32 irq;
+	unsigned long irq_flags;
+
+
+	if (intr_type == MDSS_MDP_IRQ_INTF_UNDER_RUN ||
+	    intr_type == MDSS_MDP_IRQ_INTF_VSYNC)
+		intf_num = intf_num << 1;
+
+	irq = BIT(intr_type + intf_num);
+
+	spin_lock_irqsave(&mdp_lock, irq_flags);
+	if (!(mdss_res->irq_mask & irq)) {
+		pr_warn("MDSS IRQ-%x is NOT set, mask=%x irq=%d\n",
+			irq, mdss_res->irq_mask, mdss_res->irq_ena);
+	} else {
+		mdss_res->irq_mask &= ~irq;
+		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN, mdss_res->irq_mask);
+		if (!mdss_res->irq_mask) {
+			mdss_res->irq_ena = false;
+			disable_irq(mdss_res->irq);
+		}
+	}
+	spin_unlock_irqrestore(&mdp_lock, irq_flags);
+}
+
+void mdss_mdp_irq_disable_nosync(u32 intr_type, u32 intf_num)
+{
+	u32 irq;
+
+	if (intr_type == MDSS_MDP_IRQ_INTF_UNDER_RUN ||
+	    intr_type == MDSS_MDP_IRQ_INTF_VSYNC)
+		intf_num = intf_num << 1;
+
+	irq = BIT(intr_type + intf_num);
+
+	spin_lock(&mdp_lock);
+	if (!(mdss_res->irq_mask & irq)) {
+		pr_warn("MDSS IRQ-%x is NOT set, mask=%x irq=%d\n",
+			irq, mdss_res->irq_mask, mdss_res->irq_ena);
+	} else {
+		mdss_res->irq_mask &= ~irq;
+		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN, mdss_res->irq_mask);
+		if (!mdss_res->irq_mask) {
+			mdss_res->irq_ena = false;
+			disable_irq_nosync(mdss_res->irq);
+		}
+	}
+	spin_unlock(&mdp_lock);
+}
+
+static void mdss_mdp_clk_ctrl_update(int enable)
+{
+	if (mdss_res->clk_ena == enable)
+		return;
+
+	pr_debug("MDP CLKS %s\n", (enable ? "Enable" : "Disable"));
+	mdss_res->clk_ena = enable;
+}
+
+void mdss_mdp_clk_ctrl(int enable, int isr)
+{
+	static atomic_t clk_ref = ATOMIC_INIT(0);
+	static DEFINE_MUTEX(clk_ctrl_lock);
+	int force_off = 0;
+
+	pr_debug("clk enable=%d isr=%d clk_ref=%d\n", enable, isr,
+			atomic_read(&clk_ref));
+	/*
+	 * It is assumed that if isr = TRUE then start = OFF
+	 * if start = ON when isr = TRUE it could happen that the usercontext
+	 * could turn off the clocks while the interrupt is updating the
+	 * power to ON
+	 */
+	WARN_ON(isr == true && enable);
+
+	if (enable) {
+		atomic_inc(&clk_ref);
+	} else if (!atomic_add_unless(&clk_ref, -1, 0)) {
+		pr_debug("master power-off req\n");
+		force_off = 1;
+	}
+
+	if (isr) {
+		/* if it's power off send workqueue to turn off clocks */
+		if (mdss_res->clk_ena && !atomic_read(&clk_ref))
+			queue_delayed_work(mdss_res->clk_ctrl_wq,
+					   &mdss_res->clk_ctrl_worker,
+					   mdss_res->timeout);
+	} else {
+		mutex_lock(&clk_ctrl_lock);
+		if (delayed_work_pending(&mdss_res->clk_ctrl_worker))
+			cancel_delayed_work(&mdss_res->clk_ctrl_worker);
+
+		if (atomic_read(&clk_ref)) {
+			mdss_mdp_clk_ctrl_update(true);
+		} else if (mdss_res->clk_ena) {
+			mutex_lock(&mdp_suspend_mutex);
+			if (force_off || mdss_res->suspend) {
+				mdss_mdp_clk_ctrl_update(false);
+			} else {
+				/* send workqueue to turn off mdp power */
+				queue_delayed_work(mdss_res->clk_ctrl_wq,
+						   &mdss_res->clk_ctrl_worker,
+						   mdss_res->timeout);
+			}
+			mutex_unlock(&mdp_suspend_mutex);
+		}
+		mutex_unlock(&clk_ctrl_lock);
+	}
+}
+
+static void mdss_mdp_clk_ctrl_workqueue_handler(struct work_struct *work)
+{
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+}
+
+static int mdss_mdp_irq_clk_setup(void)
+{
+	int ret;
+
+	ret = request_irq(mdss_res->irq, mdss_irq_handler, IRQF_DISABLED,
+			  "MDSS", 0);
+	if (ret) {
+		pr_err("mdp request_irq() failed!\n");
+		return ret;
+	}
+	disable_irq(mdss_res->irq);
+
+	mdss_res->fs = regulator_get(NULL, "fs_mdp");
+	if (IS_ERR(mdss_res->fs))
+		mdss_res->fs = NULL;
+	else {
+		regulator_enable(mdss_res->fs);
+		mdss_res->fs_ena = true;
+	}
+
+	return 0;
+}
+
+static struct msm_panel_common_pdata *mdss_mdp_populate_pdata(
+	struct device *dev)
+{
+	struct msm_panel_common_pdata *pdata;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		dev_err(dev, "could not allocate memory for pdata\n");
+	return pdata;
+}
+
+static u32 mdss_mdp_res_init(void)
+{
+	u32 rc;
+
+	rc = mdss_mdp_irq_clk_setup();
+	if (rc)
+		return rc;
+
+	mdss_res->clk_ctrl_wq = create_singlethread_workqueue("mdp_clk_wq");
+	INIT_DELAYED_WORK(&mdss_res->clk_ctrl_worker,
+			  mdss_mdp_clk_ctrl_workqueue_handler);
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	mdss_res->rev = MDSS_MDP_REG_READ(MDSS_REG_HW_VERSION);
+	mdss_res->mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	mdss_res->smp_mb_cnt = MDSS_MDP_SMP_MMB_BLOCKS;
+	mdss_res->smp_mb_size = MDSS_MDP_SMP_MMB_SIZE;
+	mdss_res->pipe_type_map = mdss_mdp_pipe_type_map;
+	mdss_res->mixer_type_map = mdss_mdp_mixer_type_map;
+
+	pr_info("mdss_revision=%x\n", mdss_res->rev);
+	pr_info("mdp_hw_revision=%x\n", mdss_res->mdp_rev);
+
+	mdss_res->res_init = true;
+	mdss_res->timeout = HZ/20;
+	mdss_res->clk_ena = false;
+	mdss_res->irq_mask = MDSS_MDP_DEFAULT_INTR_MASK;
+	mdss_res->suspend = false;
+	mdss_res->prim_ptype = NO_PANEL;
+	mdss_res->irq_ena = false;
+
+	return 0;
+}
+
+static int mdss_mdp_probe(struct platform_device *pdev)
+{
+	struct resource *mdss_mdp_mres;
+	struct resource *mdss_mdp_ires;
+	resource_size_t size;
+	int rc;
+
+	if (!mdss_res) {
+		mdss_res = devm_kzalloc(&pdev->dev, sizeof(*mdss_res),
+				GFP_KERNEL);
+		if (mdss_res == NULL)
+			return -ENOMEM;
+	}
+
+	if (pdev->dev.of_node) {
+		pdev->id = 0;
+		mdp_pdata = mdss_mdp_populate_pdata(&pdev->dev);
+		mdss_mdp_mres = platform_get_resource(pdev,
+						IORESOURCE_MEM, 0);
+		mdss_mdp_ires = platform_get_resource(pdev,
+						IORESOURCE_IRQ, 0);
+		if (!mdss_mdp_mres || !mdss_mdp_ires) {
+			pr_err("unable to get the MDSS resources");
+			rc = -ENOMEM;
+			goto probe_done;
+		}
+		mdss_reg_base = ioremap(mdss_mdp_mres->start,
+					resource_size(mdss_mdp_mres));
+
+		pr_info("MDP HW Base phy_Address=0x%x virt=0x%x\n",
+			(int) mdss_mdp_mres->start,
+			(int) mdss_reg_base);
+
+		mdss_res->irq = mdss_mdp_ires->start;
+	} else if ((pdev->id == 0) && (pdev->num_resources > 0)) {
+		mdp_pdata = pdev->dev.platform_data;
+
+		size =  resource_size(&pdev->resource[0]);
+		mdss_reg_base = ioremap(pdev->resource[0].start, size);
+
+		pr_info("MDP HW Base phy_Address=0x%x virt=0x%x\n",
+			(int) pdev->resource[0].start,
+			(int) mdss_reg_base);
+
+		mdss_res->irq = platform_get_irq(pdev, 0);
+		if (mdss_res->irq < 0) {
+			pr_err("can not get mdp irq\n");
+			rc = -ENOMEM;
+			goto probe_done;
+		}
+	}
+
+	if (unlikely(!mdss_reg_base)) {
+		rc = -ENOMEM;
+		goto probe_done;
+	}
+
+	rc = mdss_mdp_res_init();
+	if (rc) {
+		pr_err("unable to initialize mdss mdp resources\n");
+		goto probe_done;
+	}
+
+probe_done:
+	if (IS_ERR_VALUE(rc)) {
+		if (mdss_res) {
+			devm_kfree(&pdev->dev, mdss_res);
+			mdss_res = NULL;
+		}
+	}
+
+	return rc;
+}
+
+void mdss_mdp_footswitch_ctrl(int on)
+{
+	mutex_lock(&mdp_suspend_mutex);
+	if (!mdss_res->suspend || mdss_res->eintf_ena || !mdss_res->fs) {
+		mutex_unlock(&mdp_suspend_mutex);
+		return;
+	}
+
+	if (on && !mdss_res->fs_ena) {
+		pr_debug("Enable MDP FS\n");
+		regulator_enable(mdss_res->fs);
+		mdss_res->fs_ena = true;
+	} else if (!on && mdss_res->fs_ena) {
+		pr_debug("Disable MDP FS\n");
+		regulator_disable(mdss_res->fs);
+		mdss_res->fs_ena = false;
+	}
+	mutex_unlock(&mdp_suspend_mutex);
+}
+
+#ifdef CONFIG_PM
+static void mdss_mdp_suspend_sub(void)
+{
+	cancel_delayed_work(&mdss_res->clk_ctrl_worker);
+
+	flush_workqueue(mdss_res->clk_ctrl_wq);
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	mutex_lock(&mdp_suspend_mutex);
+	mdss_res->suspend = true;
+	mutex_unlock(&mdp_suspend_mutex);
+}
+
+static int mdss_mdp_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	if (pdev->id == 0) {
+		mdss_mdp_suspend_sub();
+		if (mdss_res->clk_ena) {
+			pr_err("MDP suspend failed\n");
+			return -EBUSY;
+		}
+		mdss_mdp_footswitch_ctrl(false);
+	}
+	return 0;
+}
+
+static int mdss_mdp_resume(struct platform_device *pdev)
+{
+	mdss_mdp_footswitch_ctrl(true);
+	mutex_lock(&mdp_suspend_mutex);
+	mdss_res->suspend = false;
+	mutex_unlock(&mdp_suspend_mutex);
+	return 0;
+}
+#else
+#define mdss_mdp_suspend NULL
+#define mdss_mdp_resume NULL
+#endif
+
+static int mdss_mdp_remove(struct platform_device *pdev)
+{
+	if (mdss_res->fs != NULL)
+		regulator_put(mdss_res->fs);
+	iounmap(mdss_reg_base);
+	pm_runtime_disable(&pdev->dev);
+	return 0;
+}
+
+static const struct of_device_id mdss_mdp_dt_match[] = {
+	{ .compatible = "qcom,mdss_mdp",},
+};
+MODULE_DEVICE_TABLE(of, mdss_mdp_dt_match);
+
+static struct platform_driver mdss_mdp_driver = {
+	.probe = mdss_mdp_probe,
+	.remove = mdss_mdp_remove,
+	.suspend = mdss_mdp_suspend,
+	.resume = mdss_mdp_resume,
+	.shutdown = NULL,
+	.driver = {
+		/*
+		 * Driver name must match the device name added in
+		 * platform.c.
+		 */
+		.name = "mdp",
+		.of_match_table = mdss_mdp_dt_match,
+	},
+};
+
+static int mdss_mdp_register_driver(void)
+{
+	return platform_driver_register(&mdss_mdp_driver);
+}
+
+static int __init mdss_mdp_driver_init(void)
+{
+	int ret;
+
+	ret = mdss_mdp_register_driver();
+	if (ret) {
+		pr_err("mdp_register_driver() failed!\n");
+		return ret;
+	}
+
+	return 0;
+
+}
+
+module_init(mdss_mdp_driver_init);
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
new file mode 100644
index 0000000..c65d5a7
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -0,0 +1,294 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef MDSS_MDP_H
+#define MDSS_MDP_H
+
+#include <linux/io.h>
+#include <linux/msm_mdp.h>
+#include <linux/platform_device.h>
+
+#include "mdss.h"
+#include "mdss_mdp_hwio.h"
+
+#define MDSS_MDP_DEFAULT_INTR_MASK 0
+#define MDSS_MDP_CURSOR_WIDTH 64
+#define MDSS_MDP_CURSOR_HEIGHT 64
+#define MDSS_MDP_CURSOR_SIZE (MDSS_MDP_CURSOR_WIDTH*MDSS_MDP_CURSOR_WIDTH*4)
+
+#define MDP_CLK_DEFAULT_RATE	37500000
+#define PHASE_STEP_SHIFT	21
+#define MAX_MIXER_WIDTH		2048
+#define MAX_MIXER_HEIGHT	2048
+#define MAX_IMG_WIDTH		0x3FFF
+#define MAX_IMG_HEIGHT		0x3FFF
+#define MIN_DST_W		10
+#define MIN_DST_H		10
+#define MAX_DST_W		MAX_MIXER_WIDTH
+#define MAX_DST_H		MAX_MIXER_HEIGHT
+#define MAX_PLANES		4
+#define MAX_DOWNSCALE_RATIO	4
+#define MAX_UPSCALE_RATIO	20
+
+#ifdef MDSS_MDP_DEBUG_REG
+static inline void mdss_mdp_reg_write(u32 addr, u32 val)
+{
+	pr_debug("0x%05X = 0x%08X\n", addr, val);
+	MDSS_REG_WRITE(addr, val);
+}
+#define MDSS_MDP_REG_WRITE(addr, val) mdss_mdp_reg_write((u32)addr, (u32)(val))
+static inline u32 mdss_mdp_reg_read(u32 addr)
+{
+	u32 val;
+	val = MDSS_REG_READ(addr);
+	pr_debug("0x%05X = 0x%08X\n", addr, val);
+	return val;
+}
+#define MDSS_MDP_REG_READ(addr) mdss_mdp_reg_read((u32)(addr))
+#else
+#define MDSS_MDP_REG_WRITE(addr, val)	MDSS_REG_WRITE((u32)(addr), (u32)(val))
+#define MDSS_MDP_REG_READ(addr)		MDSS_REG_READ((u32)(addr))
+#endif
+
+enum mdss_mdp_block_power_state {
+	MDP_BLOCK_POWER_OFF,
+	MDP_BLOCK_POWER_ON
+};
+
+enum mdss_mdp_mixer_type {
+	MDSS_MDP_MIXER_TYPE_UNUSED,
+	MDSS_MDP_MIXER_TYPE_INTF,
+	MDSS_MDP_MIXER_TYPE_WRITEBACK,
+};
+
+enum mdss_mdp_mixer_mux {
+	MDSS_MDP_MIXER_MUX_DEFAULT,
+	MDSS_MDP_MIXER_MUX_LEFT,
+	MDSS_MDP_MIXER_MUX_RIGHT,
+};
+
+enum mdss_mdp_pipe_type {
+	MDSS_MDP_PIPE_TYPE_UNUSED,
+	MDSS_MDP_PIPE_TYPE_VIG,
+	MDSS_MDP_PIPE_TYPE_RGB,
+	MDSS_MDP_PIPE_TYPE_DMA,
+};
+
+enum mdss_mdp_block_type {
+	MDSS_MDP_BLOCK_UNUSED,
+	MDSS_MDP_BLOCK_SSPP,
+	MDSS_MDP_BLOCK_MIXER,
+	MDSS_MDP_BLOCK_DSPP,
+	MDSS_MDP_BLOCK_WB,
+	MDSS_MDP_BLOCK_MAX
+};
+
+struct mdss_mdp_ctl {
+	u32 num;
+	u32 ref_cnt;
+
+	u32 intf_num;
+	u32 intf_type;
+
+	u32 opmode;
+	u32 flush_bits;
+
+	u32 play_cnt;
+
+	u16 width;
+	u16 height;
+	u32 dst_format;
+
+	struct msm_fb_data_type *mfd;
+	struct mdss_mdp_mixer *mixer_left;
+	struct mdss_mdp_mixer *mixer_right;
+	struct mutex lock;
+
+	int (*start_fnc) (struct mdss_mdp_ctl *ctl);
+	int (*stop_fnc) (struct mdss_mdp_ctl *ctl);
+	int (*prepare_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
+	int (*display_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
+
+	void *priv_data;
+};
+
+struct mdss_mdp_mixer {
+	u32 num;
+	u32 ref_cnt;
+	u8 type;
+	u8 params_changed;
+
+	u16 width;
+	u16 height;
+	u8 cursor_enabled;
+	u8 rotator_mode;
+
+	struct mdss_mdp_ctl *ctl;
+	struct mdss_mdp_pipe *stage_pipe[MDSS_MDP_MAX_STAGE];
+};
+
+struct mdss_mdp_img_rect {
+	u16 x;
+	u16 y;
+	u16 w;
+	u16 h;
+};
+
+struct mdss_mdp_format_params {
+	u32 format;
+	u8 is_yuv;
+
+	u8 frame_format;
+	u8 chroma_sample;
+	u8 solid_fill;
+	u8 fetch_planes;
+	u8 unpack_align_msb;	/* 0 to LSB, 1 to MSB */
+	u8 unpack_tight;	/* 0 for loose, 1 for tight */
+	u8 unpack_count;	/* 0 = 1 component, 1 = 2 component ... */
+	u8 bpp;
+	u8 alpha_enable;	/*  source has alpha */
+
+	/*
+	 * number of bits for source component,
+	 * 0 = 1 bit, 1 = 2 bits, 2 = 6 bits, 3 = 8 bits
+	 */
+	u8 a_bit;	/* component 3, alpha */
+	u8 r_bit;	/* component 2, R_Cr */
+	u8 b_bit;	/* component 1, B_Cb */
+	u8 g_bit;	/* component 0, G_lumz */
+
+	/*
+	 * unpack pattern
+	 * A = C3, R = C2, B = C1, G = C0
+	 */
+	u8 element3;
+	u8 element2;
+	u8 element1;
+	u8 element0;
+};
+
+struct mdss_mdp_plane_sizes {
+	u32 num_planes;
+	u32 plane_size[MAX_PLANES];
+	u32 total_size;
+	u32 ystride[MAX_PLANES];
+};
+
+struct mdss_mdp_img_data {
+	u32 addr;
+	u32 len;
+	u32 flags;
+	int p_need;
+	struct file *srcp_file;
+	struct ion_handle *srcp_ihdl;
+	struct ion_client *iclient;
+};
+
+struct mdss_mdp_data {
+	u8 num_planes;
+	u8 bwc_enabled;
+	struct mdss_mdp_img_data p[MAX_PLANES];
+};
+
+struct mdss_mdp_pipe {
+	u32 num;
+	u32 type;
+	u32 ndx;
+	atomic_t ref_cnt;
+	u32 play_cnt;
+
+	u32 flags;
+	u32 bwc_mode;
+
+	u16 img_width;
+	u16 img_height;
+	struct mdss_mdp_img_rect src;
+	struct mdss_mdp_img_rect dst;
+
+	struct mdss_mdp_format_params *src_fmt;
+	struct mdss_mdp_plane_sizes src_planes;
+
+	u8 mixer_stage;
+	u8 is_fg;
+	u8 alpha;
+	u32 transp;
+
+	struct msm_fb_data_type *mfd;
+	struct mdss_mdp_mixer *mixer;
+	struct mutex lock;
+
+	struct mdp_overlay req_data;
+	u32 params_changed;
+
+	unsigned long smp[MAX_PLANES];
+};
+
+static inline void mdss_mdp_ctl_write(struct mdss_mdp_ctl *ctl,
+				      u32 reg, u32 val)
+{
+	int offset = MDSS_MDP_REG_CTL_OFFSET(ctl->num);
+	MDSS_MDP_REG_WRITE(offset + reg, val);
+}
+
+static inline u32 mdss_mdp_ctl_read(struct mdss_mdp_ctl *ctl, u32 reg)
+{
+	int offset = MDSS_MDP_REG_CTL_OFFSET(ctl->num);
+	return MDSS_MDP_REG_READ(offset + reg);
+}
+
+irqreturn_t mdss_mdp_isr(int irq, void *ptr);
+int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num);
+void mdss_mdp_irq_disable(u32 intr_type, u32 intf_num);
+void mdss_mdp_irq_disable_nosync(u32 intr_type, u32 intf_num);
+int mdss_mdp_set_intr_callback(u32 intr_type, u32 intf_num,
+			       void (*fnc_ptr)(void *), void *arg);
+
+unsigned long mdss_mdp_get_clk_rate(u32 clk_idx);
+int mdss_mdp_vsync_clk_enable(int enable);
+void mdss_mdp_clk_ctrl(int enable, int isr);
+void mdss_mdp_footswitch_ctrl(int on);
+
+int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd);
+int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl);
+
+int mdss_mdp_ctl_on(struct msm_fb_data_type *mfd);
+int mdss_mdp_ctl_off(struct msm_fb_data_type *mfd);
+
+struct mdss_mdp_mixer *mdss_mdp_mixer_get(struct mdss_mdp_ctl *ctl, int mux);
+struct mdss_mdp_pipe *mdss_mdp_mixer_stage_pipe(struct mdss_mdp_ctl *ctl,
+						int mux, int stage);
+int mdss_mdp_mixer_pipe_update(struct mdss_mdp_pipe *pipe, int params_changed);
+int mdss_mdp_mixer_pipe_unstage(struct mdss_mdp_pipe *pipe);
+int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg);
+
+struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_pnum(u32 pnum);
+struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_locked(u32 type);
+struct mdss_mdp_pipe *mdss_mdp_pipe_get_locked(u32 ndx);
+int mdss_mdp_pipe_lock(struct mdss_mdp_pipe *pipe);
+void mdss_mdp_pipe_unlock(struct mdss_mdp_pipe *pipe);
+
+int mdss_mdp_pipe_destroy(struct mdss_mdp_pipe *pipe);
+int mdss_mdp_pipe_release_all(struct msm_fb_data_type *mfd);
+int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe,
+			     struct mdss_mdp_data *src_data);
+
+int mdss_mdp_data_check(struct mdss_mdp_data *data,
+			struct mdss_mdp_plane_sizes *ps);
+int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h,
+			     struct mdss_mdp_plane_sizes *ps);
+struct mdss_mdp_format_params *mdss_mdp_get_format_params(u32 format);
+int mdss_mdp_put_img(struct mdss_mdp_img_data *data);
+int mdss_mdp_get_img(struct ion_client *iclient, struct msmfb_data *img,
+		     struct mdss_mdp_img_data *data);
+
+#endif /* MDSS_MDP_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
new file mode 100644
index 0000000..d89347e
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -0,0 +1,600 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+
+#include "mdss_fb.h"
+#include "mdss_mdp.h"
+
+static DEFINE_MUTEX(mdss_mdp_ctl_lock);
+static struct mdss_mdp_ctl mdss_mdp_ctl_list[MDSS_MDP_MAX_CTL];
+static struct mdss_mdp_mixer mdss_mdp_mixer_list[MDSS_MDP_MAX_LAYERMIXER];
+
+static struct mdss_mdp_ctl *mdss_mdp_ctl_alloc(void)
+{
+	struct mdss_mdp_ctl *ctl = NULL;
+	int cnum;
+
+	mutex_lock(&mdss_mdp_ctl_lock);
+	for (cnum = 0; cnum < MDSS_MDP_MAX_CTL; cnum++) {
+		if (mdss_mdp_ctl_list[cnum].ref_cnt == 0) {
+			ctl = &mdss_mdp_ctl_list[cnum];
+			ctl->num = cnum;
+			ctl->ref_cnt++;
+			mutex_init(&ctl->lock);
+
+			pr_debug("alloc ctl_num=%d\n", ctl->num);
+			break;
+		}
+	}
+	mutex_unlock(&mdss_mdp_ctl_lock);
+
+	return ctl;
+}
+
+static int mdss_mdp_ctl_free(struct mdss_mdp_ctl *ctl)
+{
+	if (!ctl)
+		return -ENODEV;
+
+	pr_debug("free ctl_num=%d ref_cnt=%d\n", ctl->num, ctl->ref_cnt);
+
+	if (!ctl->ref_cnt) {
+		pr_err("called with ref_cnt=0\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&mdss_mdp_ctl_lock);
+	if (--ctl->ref_cnt == 0)
+		memset(ctl, 0, sizeof(*ctl));
+	mutex_unlock(&mdss_mdp_ctl_lock);
+
+	return 0;
+}
+
+static struct mdss_mdp_mixer *mdss_mdp_mixer_alloc(u32 type)
+{
+	struct mdss_mdp_mixer *mixer = NULL;
+	int mnum;
+
+	mutex_lock(&mdss_mdp_ctl_lock);
+	for (mnum = 0; mnum < MDSS_MDP_MAX_LAYERMIXER; mnum++) {
+		if (type == mdss_res->mixer_type_map[mnum] &&
+		    mdss_mdp_mixer_list[mnum].ref_cnt == 0) {
+			mixer = &mdss_mdp_mixer_list[mnum];
+			mixer->num = mnum;
+			mixer->ref_cnt++;
+			mixer->params_changed++;
+			mixer->type = type;
+
+			pr_debug("mixer_num=%d\n", mixer->num);
+			break;
+		}
+	}
+	mutex_unlock(&mdss_mdp_ctl_lock);
+
+	return mixer;
+}
+
+static int mdss_mdp_mixer_free(struct mdss_mdp_mixer *mixer)
+{
+	if (!mixer)
+		return -ENODEV;
+
+	pr_debug("free mixer_num=%d ref_cnt=%d\n", mixer->num, mixer->ref_cnt);
+
+	if (!mixer->ref_cnt) {
+		pr_err("called with ref_cnt=0\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&mdss_mdp_ctl_lock);
+	if (--mixer->ref_cnt == 0)
+		memset(mixer, 0, sizeof(*mixer));
+	mutex_unlock(&mdss_mdp_ctl_lock);
+
+	return 0;
+}
+
+static int mdss_mdp_ctl_init(struct msm_fb_data_type *mfd)
+{
+	struct mdss_mdp_ctl *ctl;
+	u32 width, height;
+
+	if (!mfd)
+		return -ENODEV;
+
+	width = mfd->fbi->var.xres;
+	height = mfd->fbi->var.yres;
+
+	if (width > (2 * MAX_MIXER_WIDTH)) {
+		pr_err("unsupported resolution\n");
+		return -EINVAL;
+	}
+
+	ctl = mdss_mdp_ctl_alloc();
+
+	if (!ctl) {
+		pr_err("unable to allocate ctl\n");
+		return -ENOMEM;
+	}
+
+	ctl->mfd = mfd;
+	ctl->width = width;
+	ctl->height = height;
+	ctl->dst_format = mfd->panel_info.out_format;
+
+	ctl->mixer_left = mdss_mdp_mixer_alloc(MDSS_MDP_MIXER_TYPE_INTF);
+	if (!ctl->mixer_left) {
+		pr_err("unable to allocate layer mixer\n");
+		mdss_mdp_ctl_free(ctl);
+		return -ENOMEM;
+	}
+
+	ctl->mixer_left->width = MIN(width, MAX_MIXER_WIDTH);
+	ctl->mixer_left->height = height;
+	ctl->mixer_left->ctl = ctl;
+
+	width -= ctl->mixer_left->width;
+
+	if (width) {
+		ctl->mixer_right =
+		mdss_mdp_mixer_alloc(MDSS_MDP_MIXER_TYPE_INTF);
+		if (!ctl->mixer_right) {
+			pr_err("unable to allocate layer mixer\n");
+			mdss_mdp_mixer_free(ctl->mixer_left);
+			mdss_mdp_ctl_free(ctl);
+			return -ENOMEM;
+		}
+		ctl->mixer_right->width = width;
+		ctl->mixer_right->height = height;
+		ctl->mixer_right->ctl = ctl;
+	}
+
+	switch (mfd->panel_info.type) {
+	case WRITEBACK_PANEL:
+		ctl->intf_num = MDSS_MDP_NO_INTF;
+		ctl->opmode = MDSS_MDP_CTL_OP_WFD_MODE;
+		ctl->start_fnc = mdss_mdp_writeback_start;
+		break;
+	default:
+		pr_err("unsupported panel type (%d)\n", mfd->panel_info.type);
+		mdss_mdp_ctl_free(ctl);
+		return -EINVAL;
+
+	}
+
+	ctl->opmode |= (ctl->intf_num << 4);
+
+	if (ctl->mixer_right) {
+		ctl->opmode |= MDSS_MDP_CTL_OP_PACK_3D_ENABLE |
+			       MDSS_MDP_CTL_OP_PACK_3D_H_ROW_INT;
+	}
+
+	mfd->ctl = ctl;
+
+	return 0;
+}
+
+static int mdss_mdp_ctl_destroy(struct msm_fb_data_type *mfd)
+{
+	struct mdss_mdp_ctl *ctl;
+	if (!mfd || !mfd->ctl)
+		return -ENODEV;
+
+	ctl = mfd->ctl;
+	mfd->ctl = NULL;
+
+	if (ctl->mixer_left)
+		mdss_mdp_mixer_free(ctl->mixer_left);
+	if (ctl->mixer_right)
+		mdss_mdp_mixer_free(ctl->mixer_right);
+	mdss_mdp_ctl_free(ctl);
+
+	return 0;
+}
+
+int mdss_mdp_ctl_on(struct msm_fb_data_type *mfd)
+{
+	struct mdss_panel_data *pdata;
+	struct mdss_mdp_ctl *ctl;
+	struct mdss_mdp_mixer *mixer;
+	u32 outsize, temp, off;
+	int ret = 0;
+
+	if (!mfd)
+		return -ENODEV;
+
+	if (mfd->key != MFD_KEY)
+		return -EINVAL;
+
+	pdata = dev_get_platdata(&mfd->pdev->dev);
+	if (!pdata) {
+		pr_err("no panel connected\n");
+		return -ENODEV;
+	}
+
+	if (!mfd->ctl) {
+		if (mdss_mdp_ctl_init(mfd)) {
+			pr_err("unable to initialize ctl\n");
+			return -ENODEV;
+		}
+	}
+	ctl = mfd->ctl;
+
+	mutex_lock(&ctl->lock);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	if (ctl->start_fnc)
+		ret = ctl->start_fnc(ctl);
+	else
+		pr_warn("no start function for ctl=%d type=%d\n", ctl->num,
+				mfd->panel_info.type);
+
+	if (ret) {
+		pr_err("unable to start intf\n");
+		goto start_fail;
+	}
+
+	pr_debug("ctl_num=%d\n", ctl->num);
+
+	mixer = ctl->mixer_left;
+	mixer->params_changed++;
+
+	temp = MDSS_MDP_REG_READ(MDSS_MDP_REG_DISP_INTF_SEL);
+	temp |= (ctl->intf_type << (ctl->intf_num * 8));
+	MDSS_MDP_REG_WRITE(MDSS_MDP_REG_DISP_INTF_SEL, temp);
+
+	outsize = (mixer->height << 16) | mixer->width;
+	off = MDSS_MDP_REG_LM_OFFSET(mixer->num);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_OUT_SIZE, outsize);
+
+	if (ctl->mixer_right) {
+		mixer = ctl->mixer_right;
+		mixer->params_changed++;
+		outsize = (mixer->height << 16) | mixer->width;
+		off = MDSS_MDP_REG_LM_OFFSET(mixer->num);
+		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_OUT_SIZE, outsize);
+		mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_PACK_3D, 0);
+	}
+
+	ret = pdata->on(pdata);
+
+start_fail:
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	mutex_unlock(&ctl->lock);
+
+	return ret;
+}
+
+int mdss_mdp_ctl_off(struct msm_fb_data_type *mfd)
+{
+	struct mdss_panel_data *pdata;
+	struct mdss_mdp_ctl *ctl;
+	int ret = 0;
+
+	if (!mfd)
+		return -ENODEV;
+
+	if (mfd->key != MFD_KEY)
+		return -EINVAL;
+
+	if (!mfd->ctl) {
+		pr_err("ctl not initialized\n");
+		return -ENODEV;
+	}
+
+	pdata = dev_get_platdata(&mfd->pdev->dev);
+	if (!pdata) {
+		pr_err("no panel connected\n");
+		return -ENODEV;
+	}
+
+	ctl = mfd->ctl;
+
+	pr_debug("ctl_num=%d\n", mfd->ctl->num);
+
+	mutex_lock(&ctl->lock);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	if (ctl->stop_fnc)
+		ret = ctl->stop_fnc(ctl);
+	else
+		pr_warn("no stop func for ctl=%d\n", ctl->num);
+
+	if (ret)
+		pr_warn("error powering off intf ctl=%d\n", ctl->num);
+
+	ret = pdata->off(pdata);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	ctl->play_cnt = 0;
+	mutex_unlock(&ctl->lock);
+
+	mdss_mdp_pipe_release_all(mfd);
+
+	if (!mfd->ref_cnt)
+		mdss_mdp_ctl_destroy(mfd);
+
+
+	return ret;
+}
+
+static int mdss_mdp_mixer_setup(struct mdss_mdp_ctl *ctl,
+				struct mdss_mdp_mixer *mixer)
+{
+	struct mdss_mdp_pipe *pipe, *bgpipe = NULL;
+	u32 off, blend_op, blend_stage;
+	u32 mixercfg = 0, blend_color_out = 0, bgalpha = 0;
+	int stage;
+
+	if (!mixer)
+		return -ENODEV;
+
+	pr_debug("setup mixer=%d\n", mixer->num);
+
+	for (stage = MDSS_MDP_STAGE_BASE; stage < MDSS_MDP_MAX_STAGE; stage++) {
+		pipe = mixer->stage_pipe[stage];
+		if (pipe == NULL) {
+			if (stage == MDSS_MDP_STAGE_BASE)
+				mixercfg |= MDSS_MDP_LM_BORDER_COLOR;
+			continue;
+		}
+
+		if (stage != pipe->mixer_stage) {
+			mixer->stage_pipe[stage] = NULL;
+			continue;
+		}
+		mixercfg |= stage << (3 * pipe->num);
+
+		if (stage == MDSS_MDP_STAGE_BASE) {
+			bgpipe = pipe;
+			if (pipe->src_fmt->alpha_enable)
+				bgalpha = 1;
+			continue;
+		}
+
+		blend_stage = stage - MDSS_MDP_STAGE_0;
+		off = MDSS_MDP_REG_LM_OFFSET(mixer->num) +
+		      MDSS_MDP_REG_LM_BLEND_OFFSET(blend_stage);
+
+		if (pipe->is_fg) {
+			bgalpha = 0;
+			if (bgpipe) {
+				mixercfg &= ~(0x7 << (3 * bgpipe->num));
+				mixercfg |= MDSS_MDP_LM_BORDER_COLOR;
+			}
+			blend_op = (MDSS_MDP_BLEND_FG_ALPHA_FG_CONST |
+				    MDSS_MDP_BLEND_BG_ALPHA_BG_CONST);
+			/* keep fg alpha */
+			blend_color_out |= 1 << (blend_stage + 1);
+
+			pr_debug("pnum=%d stg=%d alpha=IS_FG\n", pipe->num,
+					stage);
+		} else if (pipe->src_fmt->alpha_enable) {
+			bgalpha = 0;
+			blend_op = (MDSS_MDP_BLEND_BG_ALPHA_FG_PIXEL |
+				    MDSS_MDP_BLEND_BG_INV_ALPHA);
+			/* keep fg alpha */
+			blend_color_out |= 1 << (blend_stage + 1);
+
+			pr_debug("pnum=%d stg=%d alpha=FG PIXEL\n", pipe->num,
+					stage);
+		} else if (bgalpha) {
+			blend_op = (MDSS_MDP_BLEND_BG_ALPHA_BG_PIXEL |
+				    MDSS_MDP_BLEND_FG_ALPHA_BG_PIXEL |
+				    MDSS_MDP_BLEND_FG_INV_ALPHA);
+			/* keep bg alpha */
+			pr_debug("pnum=%d stg=%d alpha=BG_PIXEL\n", pipe->num,
+					stage);
+		} else {
+			blend_op = (MDSS_MDP_BLEND_FG_ALPHA_FG_CONST |
+				    MDSS_MDP_BLEND_BG_ALPHA_BG_CONST);
+			pr_debug("pnum=%d stg=%d alpha=CONST\n", pipe->num,
+					stage);
+		}
+
+		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_OP_MODE, blend_op);
+		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_BLEND_FG_ALPHA,
+				   pipe->alpha);
+		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_BLEND_BG_ALPHA,
+				   0xFF - pipe->alpha);
+	}
+
+	if (mixer->cursor_enabled)
+		mixercfg |= MDSS_MDP_LM_CURSOR_OUT;
+
+	pr_debug("mixer=%d mixer_cfg=%x\n", mixer->num, mixercfg);
+
+	ctl->flush_bits |= BIT(6) << mixer->num;	/* LAYER_MIXER */
+
+	off = MDSS_MDP_REG_LM_OFFSET(mixer->num);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_OP_MODE, blend_color_out);
+	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_LAYER(mixer->num), mixercfg);
+
+	return 0;
+}
+
+struct mdss_mdp_mixer *mdss_mdp_mixer_get(struct mdss_mdp_ctl *ctl, int mux)
+{
+	struct mdss_mdp_mixer *mixer = NULL;
+	if (!ctl)
+		return NULL;
+
+	switch (mux) {
+	case MDSS_MDP_MIXER_MUX_DEFAULT:
+	case MDSS_MDP_MIXER_MUX_LEFT:
+		mixer = ctl->mixer_left;
+		break;
+	case MDSS_MDP_MIXER_MUX_RIGHT:
+		mixer = ctl->mixer_right;
+		break;
+	}
+
+	return mixer;
+}
+
+struct mdss_mdp_pipe *mdss_mdp_mixer_stage_pipe(struct mdss_mdp_ctl *ctl,
+						int mux, int stage)
+{
+	struct mdss_mdp_pipe *pipe = NULL;
+	struct mdss_mdp_mixer *mixer;
+	if (!ctl)
+		return NULL;
+
+	if (mutex_lock_interruptible(&ctl->lock))
+		return NULL;
+
+	mixer = mdss_mdp_mixer_get(ctl, mux);
+	if (mixer)
+		pipe = mixer->stage_pipe[stage];
+	mutex_unlock(&ctl->lock);
+
+	return pipe;
+}
+
+int mdss_mdp_mixer_pipe_update(struct mdss_mdp_pipe *pipe, int params_changed)
+{
+	struct mdss_mdp_ctl *ctl;
+	struct mdss_mdp_mixer *mixer;
+
+	if (!pipe)
+		return -EINVAL;
+	mixer = pipe->mixer;
+	if (!mixer)
+		return -EINVAL;
+	ctl = mixer->ctl;
+	if (!ctl)
+		return -EINVAL;
+
+	if (pipe->mixer_stage >= MDSS_MDP_MAX_STAGE) {
+		pr_err("invalid mixer stage\n");
+		return -EINVAL;
+	}
+
+	pr_debug("pnum=%x mixer=%d stage=%d\n", pipe->num, mixer->num,
+			pipe->mixer_stage);
+
+	if (mutex_lock_interruptible(&ctl->lock))
+		return -EINTR;
+
+	if (params_changed) {
+		mixer->params_changed++;
+		mixer->stage_pipe[pipe->mixer_stage] = pipe;
+	}
+
+	if (pipe->type == MDSS_MDP_PIPE_TYPE_DMA)
+		ctl->flush_bits |= BIT(pipe->num) << 5;
+	else /* RGB/VIG pipe */
+		ctl->flush_bits |= BIT(pipe->num);
+
+	mutex_unlock(&ctl->lock);
+
+	return 0;
+}
+
+int mdss_mdp_mixer_pipe_unstage(struct mdss_mdp_pipe *pipe)
+{
+	struct mdss_mdp_ctl *ctl;
+	struct mdss_mdp_mixer *mixer;
+
+	if (!pipe)
+		return -EINVAL;
+	mixer = pipe->mixer;
+	if (!mixer)
+		return -EINVAL;
+	ctl = mixer->ctl;
+	if (!ctl)
+		return -EINVAL;
+
+	pr_debug("unstage pnum=%d stage=%d mixer=%d\n", pipe->num,
+			pipe->mixer_stage, mixer->num);
+
+	if (mutex_lock_interruptible(&ctl->lock))
+		return -EINTR;
+
+	mixer->params_changed++;
+	mixer->stage_pipe[pipe->mixer_stage] = NULL;
+
+	mutex_unlock(&ctl->lock);
+
+	return 0;
+}
+
+static int mdss_mdp_mixer_update(struct mdss_mdp_mixer *mixer)
+{
+	mixer->params_changed = 0;
+
+	/* skip mixer setup for rotator */
+	if (!mixer->rotator_mode)
+		mdss_mdp_mixer_setup(mixer->ctl, mixer);
+
+	return 0;
+}
+
+int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg)
+{
+	int mixer1_changed, mixer2_changed;
+	int ret = 0;
+
+	if (!ctl) {
+		pr_err("display function not set\n");
+		return -ENODEV;
+	}
+
+	pr_debug("commit ctl=%d\n", ctl->num);
+
+	if (mutex_lock_interruptible(&ctl->lock))
+		return -EINTR;
+
+	mixer1_changed = (ctl->mixer_left && ctl->mixer_left->params_changed);
+	mixer2_changed = (ctl->mixer_right && ctl->mixer_right->params_changed);
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	if (mixer1_changed || mixer2_changed) {
+		if (ctl->prepare_fnc)
+			ret = ctl->prepare_fnc(ctl, arg);
+		if (ret) {
+			pr_err("error preparing display\n");
+			goto done;
+		}
+
+		if (mixer1_changed)
+			mdss_mdp_mixer_update(ctl->mixer_left);
+		if (mixer2_changed)
+			mdss_mdp_mixer_update(ctl->mixer_right);
+
+		mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_TOP, ctl->opmode);
+		ctl->flush_bits |= BIT(17);	/* CTL */
+	}
+
+	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl->flush_bits);
+	wmb();
+	ctl->flush_bits = 0;
+
+	if (ctl->display_fnc)
+		ret = ctl->display_fnc(ctl, arg); /* kickoff */
+	if (ret)
+		pr_warn("error displaying frame\n");
+
+	ctl->play_cnt++;
+
+done:
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	mutex_unlock(&ctl->lock);
+
+	return ret;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_formats.h b/drivers/video/msm/mdss/mdss_mdp_formats.h
new file mode 100644
index 0000000..07eefc1
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_formats.h
@@ -0,0 +1,328 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef MDSS_MDP_FORMATS_H
+#define MDSS_MDP_FORMATS_H
+
+#include <linux/msm_mdp.h>
+
+#include "mdss_mdp.h"
+
+#define C3_ALPHA	3	/* alpha */
+#define C2_R_Cr		2	/* R/Cr */
+#define C1_B_Cb		1	/* B/Cb */
+#define C0_G_Y		0	/* G/luma */
+
+static struct mdss_mdp_format_params mdss_mdp_format_map[MDP_IMGTYPE_LIMIT] = {
+	[MDP_RGB_565] = {
+		.format = MDP_RGB_565,
+		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+		.a_bit = 0,
+		.r_bit = 1,	/* R, 5 bits */
+		.b_bit = 1,	/* B, 5 bits */
+		.g_bit = 2,	/* G, 6 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 2,
+		.element2 = C2_R_Cr,
+		.element1 = C0_G_Y,
+		.element0 = C1_B_Cb,
+		.bpp = 1,	/* 2 bpp */
+	},
+	[MDP_BGR_565] = {
+		.format = MDP_BGR_565,
+		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+		.a_bit = 0,
+		.r_bit = 1,	/* R, 5 bits */
+		.b_bit = 1,	/* B, 5 bits */
+		.g_bit = 2,	/* G, 6 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 2,
+		.element2 = C1_B_Cb,
+		.element1 = C0_G_Y,
+		.element0 = C2_R_Cr,
+		.bpp = 1,	/* 2 bpp */
+	},
+	[MDP_RGB_888] = {
+		.format = MDP_RGB_888,
+		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+		.a_bit = 0,
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 2,
+		.element2 = C1_B_Cb,
+		.element1 = C0_G_Y,
+		.element0 = C2_R_Cr,
+		.bpp = 2,	/* 3 bpp */
+	},
+	[MDP_XRGB_8888] = {
+		.format = MDP_XRGB_8888,
+		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+		.a_bit = 3,	/* alpha, 4 bits */
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 3,
+		.element3 = C1_B_Cb,
+		.element2 = C0_G_Y,
+		.element1 = C2_R_Cr,
+		.element0 = C3_ALPHA,
+		.bpp = 3,	/* 4 bpp */
+	},
+	[MDP_ARGB_8888] = {
+		.format = MDP_ARGB_8888,
+		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+		.a_bit = 3,	/* alpha, 4 bits */
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 1,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 3,
+		.element3 = C1_B_Cb,
+		.element2 = C0_G_Y,
+		.element1 = C2_R_Cr,
+		.element0 = C3_ALPHA,
+		.bpp = 3,	/* 4 bpp */
+	},
+	[MDP_RGBA_8888] = {
+		.format = MDP_RGBA_8888,
+		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+		.a_bit = 3,	/* alpha, 4 bits */
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 1,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 3,
+		.element3 = C3_ALPHA,
+		.element2 = C1_B_Cb,
+		.element1 = C0_G_Y,
+		.element0 = C2_R_Cr,
+		.bpp = 3,	/* 4 bpp */
+	},
+	[MDP_RGBX_8888] = {
+		.format = MDP_RGBX_8888,
+		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+		.a_bit = 3,
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 3,
+		.element3 = C3_ALPHA,
+		.element2 = C1_B_Cb,
+		.element1 = C0_G_Y,
+		.element0 = C2_R_Cr,
+		.bpp = 3,	/* 4 bpp */
+	},
+	[MDP_BGRA_8888] = {
+		.format = MDP_BGRA_8888,
+		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+		.a_bit = 3,	/* alpha, 4 bits */
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 1,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 3,
+		.element3 = C3_ALPHA,
+		.element2 = C2_R_Cr,
+		.element1 = C0_G_Y,
+		.element0 = C1_B_Cb,
+		.bpp = 3,	/* 4 bpp */
+	},
+	[MDP_YCRYCB_H2V1] = {
+		.format = MDP_YCRYCB_H2V1,
+		.is_yuv = 1,
+		.a_bit = 0,
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 1,	/* 2 */
+		.bpp = 1,	/* 2 bpp */
+		.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+		.chroma_sample = MDSS_MDP_CHROMA_H2V1,
+		.unpack_count = 3,
+		.element3 = C0_G_Y,
+		.element2 = C2_R_Cr,
+		.element1 = C0_G_Y,
+		.element0 = C1_B_Cb,
+	},
+	[MDP_Y_CRCB_H2V1] = {
+		.format = MDP_Y_CRCB_H2V1,
+		.is_yuv = 1,
+		.a_bit = 0,
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 1,	/* 2 */
+		.bpp = 1,	/* 2 bpp */
+		.fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
+		.chroma_sample = MDSS_MDP_CHROMA_H2V1,
+		.element1 = C1_B_Cb,
+		.element0 = C2_R_Cr,
+	},
+	[MDP_Y_CBCR_H2V1] = {
+		.format = MDP_Y_CBCR_H2V1,
+		.is_yuv = 1,
+		.a_bit = 0,
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 1,	/* 2 */
+		.bpp = 1,	/* 2 bpp */
+		.fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
+		.chroma_sample = MDSS_MDP_CHROMA_H2V1,
+		.element1 = C2_R_Cr,
+		.element0 = C1_B_Cb,
+	},
+	[MDP_Y_CRCB_H1V2] = {
+		.format = MDP_Y_CRCB_H1V2,
+		.is_yuv = 1,
+		.a_bit = 0,
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 1,	/* 2 */
+		.bpp = 1,	/* 2 bpp */
+		.fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
+		.chroma_sample = MDSS_MDP_CHROMA_H1V2,
+		.element1 = C1_B_Cb,
+		.element0 = C2_R_Cr,
+	},
+	[MDP_Y_CBCR_H1V2] = {
+		.format = MDP_Y_CBCR_H1V2,
+		.is_yuv = 1,
+		.a_bit = 0,
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 1,	/* 2 */
+		.bpp = 1,	/* 2 bpp */
+		.fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
+		.chroma_sample = MDSS_MDP_CHROMA_H1V2,
+		.element1 = C2_R_Cr,
+		.element0 = C1_B_Cb,
+	},
+	[MDP_Y_CRCB_H2V2] = {
+		.format = MDP_Y_CRCB_H2V2,
+		.is_yuv = 1,
+		.a_bit = 0,
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 1,	/* 2 */
+		.bpp = 1,	/* 2 bpp */
+		.fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
+		.chroma_sample = MDSS_MDP_CHROMA_420,
+		.element1 = C1_B_Cb,
+		.element0 = C2_R_Cr,
+	},
+	[MDP_Y_CBCR_H2V2] = {
+		.format = MDP_Y_CBCR_H2V2,
+		.is_yuv = 1,
+		.a_bit = 0,
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 1,	/* 2 */
+		.bpp = 1,	/* 2 bpp */
+		.fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
+		.chroma_sample = MDSS_MDP_CHROMA_420,
+		.element1 = C2_R_Cr,
+		.element0 = C1_B_Cb,
+	},
+	[MDP_Y_CR_CB_H2V2] = {
+		.format = MDP_Y_CR_CB_H2V2,
+		.is_yuv = 1,
+		.a_bit = 0,
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 1,	/* 2 */
+		.bpp = 1,	/* 2 bpp */
+		.fetch_planes = MDSS_MDP_PLANE_PLANAR,
+		.chroma_sample = MDSS_MDP_CHROMA_420,
+	},
+	[MDP_Y_CB_CR_H2V2] = {
+		.format = MDP_Y_CB_CR_H2V2,
+		.is_yuv = 1,
+		.a_bit = 0,
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 1,	/* 2 */
+		.bpp = 1,	/* 2 bpp */
+		.fetch_planes = MDSS_MDP_PLANE_PLANAR,
+		.chroma_sample = MDSS_MDP_CHROMA_420,
+	},
+	[MDP_Y_CR_CB_GH2V2] = {
+		.format = MDP_Y_CR_CB_GH2V2,
+		.is_yuv = 1,
+		.a_bit = 0,
+		.r_bit = 3,	/* R, 8 bits */
+		.b_bit = 3,	/* B, 8 bits */
+		.g_bit = 3,	/* G, 8 bits */
+		.alpha_enable = 0,
+		.unpack_tight = 1,
+		.unpack_align_msb = 0,
+		.unpack_count = 1,	/* 2 */
+		.bpp = 1,	/* 2 bpp */
+		.fetch_planes = MDSS_MDP_PLANE_PLANAR,
+		.chroma_sample = MDSS_MDP_CHROMA_420,
+	},
+};
+#endif
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
new file mode 100644
index 0000000..4ca1dce
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -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.
+ *
+ */
+
+#ifndef MDSS_MDP_HWIO_H
+#define MDSS_MDP_HWIO_H
+
+#include <linux/bitops.h>
+
+#define MDSS_REG_HW_VERSION				0x0
+#define MDSS_REG_HW_INTR_STATUS				0x10
+
+#define MDSS_INTR_MDP				BIT(0)
+#define MDSS_INTR_DSI0				BIT(4)
+#define MDSS_INTR_DSI1				BIT(5)
+#define MDSS_INTR_HDMI				BIT(8)
+#define MDSS_INTR_EDP				BIT(12)
+
+#define MDSS_MDP_REG_HW_VERSION				0x00100
+#define MDSS_MDP_REG_DISP_INTF_SEL			0x00104
+#define MDSS_MDP_REG_INTR_EN				0x00110
+#define MDSS_MDP_REG_INTR_STATUS			0x00114
+#define MDSS_MDP_REG_INTR_CLEAR				0x00118
+#define MDSS_MDP_REG_HIST_INTR_EN			0x0011C
+#define MDSS_MDP_REG_HIST_INTR_STATUS			0x00120
+#define MDSS_MDP_REG_HIST_INTR_CLEAR			0x00124
+
+#define MDSS_INTF_DSI	0x1
+#define MDSS_INTF_HDMI	0x3
+#define MDSS_INTF_LCDC	0x5
+#define MDSS_INTF_EDP	0x9
+
+#define MDSS_MDP_INTR_WB_0_DONE				BIT(0)
+#define MDSS_MDP_INTR_WB_1_DONE				BIT(1)
+#define MDSS_MDP_INTR_WB_2_DONE				BIT(4)
+#define MDSS_MDP_INTR_PING_PONG_0_DONE			BIT(8)
+#define MDSS_MDP_INTR_PING_PONG_1_DONE			BIT(9)
+#define MDSS_MDP_INTR_PING_PONG_2_DONE			BIT(10)
+#define MDSS_MDP_INTR_PING_PONG_0_RD_PTR		BIT(12)
+#define MDSS_MDP_INTR_PING_PONG_1_RD_PTR		BIT(13)
+#define MDSS_MDP_INTR_PING_PONG_2_RD_PTR		BIT(14)
+#define MDSS_MDP_INTR_PING_PONG_0_WR_PTR		BIT(16)
+#define MDSS_MDP_INTR_PING_PONG_1_WR_PTR		BIT(17)
+#define MDSS_MDP_INTR_PING_PONG_2_WR_PTR		BIT(18)
+#define MDSS_MDP_INTR_PING_PONG_0_AUTOREFRESH_DONE	BIT(20)
+#define MDSS_MDP_INTR_PING_PONG_1_AUTOREFRESH_DONE	BIT(21)
+#define MDSS_MDP_INTR_PING_PONG_2_AUTOREFRESH_DONE	BIT(22)
+#define MDSS_MDP_INTR_INTF_0_UNDERRUN			BIT(24)
+#define MDSS_MDP_INTR_INTF_0_VSYNC			BIT(25)
+#define MDSS_MDP_INTR_INTF_1_UNDERRUN			BIT(26)
+#define MDSS_MDP_INTR_INTF_1_VSYNC			BIT(27)
+#define MDSS_MDP_INTR_INTF_2_UNDERRUN			BIT(28)
+#define MDSS_MDP_INTR_INTF_2_VSYNC			BIT(29)
+#define MDSS_MDP_INTR_INTF_3_UNDERRUN			BIT(30)
+#define MDSS_MDP_INTR_INTF_3_VSYNC			BIT(31)
+
+enum mdss_mdp_intr_type {
+	MDSS_MDP_IRQ_WB_ROT_COMP = 0,
+	MDSS_MDP_IRQ_WB_WFD = 4,
+	MDSS_MDP_IRQ_PING_PONG_COMP = 8,
+	MDSS_MDP_IRQ_PING_PONG_RD_PTR = 12,
+	MDSS_MDP_IRQ_PING_PONG_WR_PTR = 16,
+	MDSS_MDP_IRQ_PING_PONG_AUTO_REF = 20,
+	MDSS_MDP_IRQ_INTF_UNDER_RUN = 24,
+	MDSS_MDP_IRQ_INTF_VSYNC = 25,
+};
+
+enum mdss_mdp_ctl_index {
+	MDSS_MDP_CTL0,
+	MDSS_MDP_CTL1,
+	MDSS_MDP_CTL2,
+	MDSS_MDP_CTL3,
+	MDSS_MDP_CTL4,
+	MDSS_MDP_MAX_CTL
+};
+
+#define MDSS_MDP_REG_CTL_OFFSET(ctl) (0x00600 + ((ctl) * 0x100))
+
+#define MDSS_MDP_REG_CTL_LAYER(lm)			((lm) * 0x004)
+#define MDSS_MDP_REG_CTL_TOP				0x014
+#define MDSS_MDP_REG_CTL_FLUSH				0x018
+#define MDSS_MDP_REG_CTL_START				0x01C
+#define MDSS_MDP_REG_CTL_PACK_3D			0x020
+
+#define MDSS_MDP_CTL_OP_VIDEO_MODE		(0 << 17)
+#define MDSS_MDP_CTL_OP_CMD_MODE		(1 << 17)
+
+#define MDSS_MDP_CTL_OP_ROT0_MODE		0x1
+#define MDSS_MDP_CTL_OP_ROT1_MODE		0x2
+#define MDSS_MDP_CTL_OP_WB0_MODE		0x3
+#define MDSS_MDP_CTL_OP_WB1_MODE		0x4
+#define MDSS_MDP_CTL_OP_WFD_MODE		0x5
+
+#define MDSS_MDP_CTL_OP_PACK_3D_ENABLE		BIT(19)
+#define MDSS_MDP_CTL_OP_PACK_3D_FRAME_INT	(0 << 20)
+#define MDSS_MDP_CTL_OP_PACK_3D_H_ROW_INT	(1 << 20)
+#define MDSS_MDP_CTL_OP_PACK_3D_V_ROW_INT	(2 << 20)
+#define MDSS_MDP_CTL_OP_PACK_3D_COL_INT		(3 << 20)
+
+enum mdss_mdp_sspp_index {
+	MDSS_MDP_SSPP_VIG0,
+	MDSS_MDP_SSPP_VIG1,
+	MDSS_MDP_SSPP_VIG2,
+	MDSS_MDP_SSPP_RGB0,
+	MDSS_MDP_SSPP_RGB1,
+	MDSS_MDP_SSPP_RGB2,
+	MDSS_MDP_SSPP_DMA0,
+	MDSS_MDP_SSPP_DMA1,
+	MDSS_MDP_MAX_SSPP
+};
+
+enum mdss_mdp_sspp_fetch_type {
+	MDSS_MDP_PLANE_INTERLEAVED,
+	MDSS_MDP_PLANE_PLANAR,
+	MDSS_MDP_PLANE_PSEUDO_PLANAR,
+};
+
+enum mdss_mdp_sspp_chroma_samp_type {
+	MDSS_MDP_CHROMA_RGB,
+	MDSS_MDP_CHROMA_H2V1,
+	MDSS_MDP_CHROMA_H1V2,
+	MDSS_MDP_CHROMA_420
+};
+
+#define MDSS_MDP_REG_SSPP_OFFSET(pipe) (0x01200 + ((pipe) * 0x400))
+
+#define MDSS_MDP_REG_SSPP_SRC_SIZE			0x000
+#define MDSS_MDP_REG_SSPP_SRC_IMG_SIZE			0x004
+#define MDSS_MDP_REG_SSPP_SRC_XY			0x008
+#define MDSS_MDP_REG_SSPP_OUT_SIZE			0x00C
+#define MDSS_MDP_REG_SSPP_OUT_XY			0x010
+#define MDSS_MDP_REG_SSPP_SRC0_ADDR			0x014
+#define MDSS_MDP_REG_SSPP_SRC1_ADDR			0x018
+#define MDSS_MDP_REG_SSPP_SRC2_ADDR			0x01C
+#define MDSS_MDP_REG_SSPP_SRC3_ADDR			0x020
+#define MDSS_MDP_REG_SSPP_SRC_YSTRIDE0			0x024
+#define MDSS_MDP_REG_SSPP_SRC_YSTRIDE1			0x028
+#define MDSS_MDP_REG_SSPP_STILE_FRAME_SIZE		0x02C
+#define MDSS_MDP_REG_SSPP_SRC_FORMAT			0x030
+#define MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN		0x034
+
+#define MDSS_MDP_REG_SSPP_SRC_OP_MODE			0x038
+#define MDSS_MDP_OP_DEINTERLACE			BIT(22)
+#define MDSS_MDP_OP_DEINTERLACE_ODD		BIT(23)
+#define MDSS_MDP_OP_FLIP_UD			BIT(14)
+#define MDSS_MDP_OP_FLIP_LR			BIT(13)
+#define MDSS_MDP_OP_BWC_EN			BIT(0)
+#define MDSS_MDP_OP_BWC_LOSSLESS		(0 << 1)
+#define MDSS_MDP_OP_BWC_Q_HIGH			(1 << 1)
+#define MDSS_MDP_OP_BWC_Q_MED			(2 << 1)
+
+#define MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR		0x03C
+#define MDSS_MDP_REG_SSPP_FETCH_CONFIG			0x048
+#define MDSS_MDP_REG_SSPP_VC1_RANGE			0x04C
+
+#define MDSS_MDP_REG_SSPP_CURRENT_SRC0_ADDR		0x0A4
+#define MDSS_MDP_REG_SSPP_CURRENT_SRC1_ADDR		0x0A8
+#define MDSS_MDP_REG_SSPP_CURRENT_SRC2_ADDR		0x0AC
+#define MDSS_MDP_REG_SSPP_CURRENT_SRC3_ADDR		0x0B0
+#define MDSS_MDP_REG_SSPP_LINE_SKIP_STEP_C03		0x0B4
+#define MDSS_MDP_REG_SSPP_LINE_SKIP_STEP_C12		0x0B8
+
+#define MDSS_MDP_REG_VIG_OP_MODE			0x200
+#define MDSS_MDP_REG_VIG_QSEED2_CONFIG			0x204
+#define MDSS_MDP_REG_VIG_QSEED2_C03_PHASESTEPX		0x210
+#define MDSS_MDP_REG_VIG_QSEED2_C03_PHASESTEPY		0x214
+#define MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPX		0x218
+#define MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPY		0x21C
+#define MDSS_MDP_REG_VIG_QSEED2_C03_INIT_PHASEX		0x220
+#define MDSS_MDP_REG_VIG_QSEED2_C03_INIT_PHASEY		0x224
+#define MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEX		0x228
+#define MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEY		0x22C
+
+#define MDSS_MDP_REG_SCALE_CONFIG			0x204
+#define MDSS_MDP_REG_SCALE_PHASE_STEP_X			0x210
+#define MDSS_MDP_REG_SCALE_PHASE_STEP_Y			0x214
+#define MDSS_MDP_REG_SCALE_INIT_PHASE_X			0x220
+#define MDSS_MDP_REG_SCALE_INIT_PHASE_Y			0x224
+
+#define MDSS_MDP_REG_VIG_CSC_0_BASE			0x280
+#define MDSS_MDP_REG_VIG_CSC_1_BASE			0x320
+
+#define MDSS_MDP_SCALE_FILTER_NEAREST		0x0
+#define MDSS_MDP_SCALE_FILTER_BIL		0x1
+#define MDSS_MDP_SCALE_FILTER_PCMN		0x2
+#define MDSS_MDP_SCALE_FILTER_CA		0x3
+#define MDSS_MDP_SCALEY_EN			BIT(1)
+#define MDSS_MDP_SCALEX_EN			BIT(0)
+
+#define MDSS_MDP_NUM_REG_MIXERS 3
+#define MDSS_MDP_NUM_WB_MIXERS 2
+
+enum mdss_mdp_mixer_index {
+	MDSS_MDP_LAYERMIXER0,
+	MDSS_MDP_LAYERMIXER1,
+	MDSS_MDP_LAYERMIXER2,
+	MDSS_MDP_LAYERMIXER3,
+	MDSS_MDP_LAYERMIXER4,
+	MDSS_MDP_MAX_LAYERMIXER
+};
+
+enum mdss_mdp_stage_index {
+	MDSS_MDP_STAGE_UNUSED,
+	MDSS_MDP_STAGE_BASE,
+	MDSS_MDP_STAGE_0,
+	MDSS_MDP_STAGE_1,
+	MDSS_MDP_STAGE_2,
+	MDSS_MDP_STAGE_3,
+	MDSS_MDP_MAX_STAGE
+};
+
+enum mdss_mdp_blend_index {
+	MDSS_MDP_BLEND_STAGE0,
+	MDSS_MDP_BLEND_STAGE1,
+	MDSS_MDP_BLEND_STAGE2,
+	MDSS_MDP_BLEND_STAGE3,
+	MDSS_MDP_MAX_BLEND_STAGE,
+};
+
+#define MDSS_MDP_REG_LM_OFFSET(lm) (0x03200 + ((lm) * 0x400))
+
+#define MDSS_MDP_REG_LM_OP_MODE				0x000
+#define MDSS_MDP_REG_LM_OUT_SIZE			0x004
+#define MDSS_MDP_REG_LM_BORDER_COLOR_0			0x008
+#define MDSS_MDP_REG_LM_BORDER_COLOR_1			0x010
+
+#define MDSS_MDP_REG_LM_BLEND_OFFSET(stage)	(0x20 + ((stage) * 0x30))
+#define MDSS_MDP_REG_LM_BLEND_OP			0x00
+#define MDSS_MDP_REG_LM_BLEND_FG_ALPHA			0x04
+#define MDSS_MDP_REG_LM_BLEND_BG_ALPHA			0x08
+#define MDSS_MDP_REG_LM_BLEND_FG_TRANSP_LOW0		0x0C
+#define MDSS_MDP_REG_LM_BLEND_FG_TRANSP_LOW1		0x10
+#define MDSS_MDP_REG_LM_BLEND_FG_TRANSP_HIGH0		0x14
+#define MDSS_MDP_REG_LM_BLEND_FG_TRANSP_HIGH1		0x18
+#define MDSS_MDP_REG_LM_BLEND_BG_TRANSP_LOW0		0x1C
+#define MDSS_MDP_REG_LM_BLEND_BG_TRANSP_LOW1		0x20
+#define MDSS_MDP_REG_LM_BLEND_BG_TRANSP_HIGH0		0x24
+#define MDSS_MDP_REG_LM_BLEND_BG_TRANSP_HIGH1		0x28
+
+#define MDSS_MDP_REG_LM_CURSOR_IMG_SIZE			0xE0
+#define MDSS_MDP_REG_LM_CURSOR_SIZE			0xE4
+#define MDSS_MDP_REG_LM_CURSOR_XY			0xE8
+#define MDSS_MDP_REG_LM_CURSOR_STRIDE			0xDC
+#define MDSS_MDP_REG_LM_CURSOR_FORMAT			0xEC
+#define MDSS_MDP_REG_LM_CURSOR_BASE_ADDR		0xF0
+#define MDSS_MDP_REG_LM_CURSOR_START_XY			0xF4
+#define MDSS_MDP_REG_LM_CURSOR_BLEND_CONFIG		0xF8
+#define MDSS_MDP_REG_LM_CURSOR_BLEND_PARAM		0xFC
+#define MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_LOW0	0x100
+#define MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_LOW1	0x104
+#define MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_HIGH0	0x108
+#define MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_HIGH1	0x10C
+
+#define MDSS_MDP_LM_BORDER_COLOR		(1 << 24)
+#define MDSS_MDP_LM_CURSOR_OUT			(1 << 25)
+#define MDSS_MDP_BLEND_FG_ALPHA_FG_CONST	(0 << 0)
+#define MDSS_MDP_BLEND_FG_ALPHA_BG_CONST	(1 << 0)
+#define MDSS_MDP_BLEND_FG_ALPHA_FG_PIXEL	(2 << 0)
+#define MDSS_MDP_BLEND_FG_ALPHA_BG_PIXEL	(3 << 0)
+#define MDSS_MDP_BLEND_FG_INV_ALPHA		(1 << 2)
+#define MDSS_MDP_BLEND_FG_MOD_ALPHA		(1 << 3)
+#define MDSS_MDP_BLEND_FG_INV_MOD_ALPHA		(1 << 4)
+#define MDSS_MDP_BLEND_FG_TRANSP_EN		(1 << 5)
+#define MDSS_MDP_BLEND_BG_ALPHA_FG_CONST	(0 << 8)
+#define MDSS_MDP_BLEND_BG_ALPHA_BG_CONST	(1 << 8)
+#define MDSS_MDP_BLEND_BG_ALPHA_FG_PIXEL	(2 << 8)
+#define MDSS_MDP_BLEND_BG_ALPHA_BG_PIXEL	(3 << 8)
+#define MDSS_MDP_BLEND_BG_INV_ALPHA		(1 << 10)
+#define MDSS_MDP_BLEND_BG_MOD_ALPHA		(1 << 11)
+#define MDSS_MDP_BLEND_BG_INV_MOD_ALPHA		(1 << 12)
+#define MDSS_MDP_BLEND_BG_TRANSP_EN		(1 << 13)
+
+enum mdss_mdp_writeback_index {
+	MDSS_MDP_WRITEBACK0,
+	MDSS_MDP_WRITEBACK1,
+	MDSS_MDP_WRITEBACK2,
+	MDSS_MDP_WRITEBACK3,
+	MDSS_MDP_WRITEBACK4,
+	MDSS_MDP_MAX_WRITEBACK
+};
+
+#define MDSS_MDP_REG_WB_OFFSET(wb)	(0x11100 + ((wb) * 0x2000))
+
+#define MDSS_MDP_REG_WB_DST_FORMAT			0x000
+#define MDSS_MDP_REG_WB_DST_OP_MODE			0x004
+#define MDSS_MDP_REG_WB_DST_PACK_PATTERN		0x008
+#define MDSS_MDP_REG_WB_DST0_ADDR			0x00C
+#define MDSS_MDP_REG_WB_DST1_ADDR			0x010
+#define MDSS_MDP_REG_WB_DST2_ADDR			0x014
+#define MDSS_MDP_REG_WB_DST3_ADDR			0x018
+#define MDSS_MDP_REG_WB_DST_YSTRIDE0			0x01C
+#define MDSS_MDP_REG_WB_DST_YSTRIDE1			0x020
+#define MDSS_MDP_REG_WB_DST_YSTRIDE1			0x020
+#define MDSS_MDP_REG_WB_DST_DITHER_BITDEPTH		0x024
+#define MDSS_MDP_REG_WB_DST_MATRIX_ROW0			0x030
+#define MDSS_MDP_REG_WB_DST_MATRIX_ROW1			0x034
+#define MDSS_MDP_REG_WB_DST_MATRIX_ROW2			0x038
+#define MDSS_MDP_REG_WB_DST_MATRIX_ROW3			0x03C
+#define MDSS_MDP_REG_WB_ROTATION_DNSCALER		0x050
+#define MDSS_MDP_REG_WB_N16_INIT_PHASE_X_C03		0x060
+#define MDSS_MDP_REG_WB_N16_INIT_PHASE_X_C12		0x064
+#define MDSS_MDP_REG_WB_N16_INIT_PHASE_Y_C03		0x068
+#define MDSS_MDP_REG_WB_N16_INIT_PHASE_Y_C12		0x06C
+#define MDSS_MDP_REG_WB_OUT_SIZE			0x074
+#define MDSS_MDP_REG_WB_ALPHA_X_VALUE			0x078
+#define MDSS_MDP_REG_WB_CSC_BASE			0x260
+
+enum mdss_mdp_dspp_index {
+	MDSS_MDP_DSPP0,
+	MDSS_MDP_DSPP1,
+	MDSS_MDP_DSPP2,
+	MDSS_MDP_MAX_DSPP
+};
+
+enum mdss_mpd_intf_index {
+	MDSS_MDP_NO_INTF,
+	MDSS_MDP_INTF0,
+	MDSS_MDP_INTF1,
+	MDSS_MDP_INTF2,
+	MDSS_MDP_INTF3,
+	MDSS_MDP_MAX_INTF
+};
+
+#define MDSS_MDP_REG_INTF_OFFSET(intf)		(0x20F00 + ((intf) * 0x200))
+
+#define MDSS_MDP_REG_INTF_TIMING_ENGINE_EN		0x000
+#define MDSS_MDP_REG_INTF_CONFIG			0x004
+#define MDSS_MDP_REG_INTF_HSYNC_CTL			0x008
+#define MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0		0x00C
+#define MDSS_MDP_REG_INTF_VSYNC_PERIOD_F1		0x010
+#define MDSS_MDP_REG_INTF_VSYNC_PULSE_WIDTH_F0		0x014
+#define MDSS_MDP_REG_INTF_VSYNC_PULSE_WIDTH_F1		0x018
+#define MDSS_MDP_REG_INTF_DISPLAY_V_START_F0		0x01C
+#define MDSS_MDP_REG_INTF_DISPLAY_V_START_F1		0x020
+#define MDSS_MDP_REG_INTF_DISPLAY_V_END_F0		0x024
+#define MDSS_MDP_REG_INTF_DISPLAY_V_END_F1		0x028
+#define MDSS_MDP_REG_INTF_ACTIVE_V_START_F0		0x02C
+#define MDSS_MDP_REG_INTF_ACTIVE_V_START_F1		0x030
+#define MDSS_MDP_REG_INTF_ACTIVE_V_END_F0		0x034
+#define MDSS_MDP_REG_INTF_ACTIVE_V_END_F1		0x038
+#define MDSS_MDP_REG_INTF_DISPLAY_HCTL			0x03C
+#define MDSS_MDP_REG_INTF_ACTIVE_HCTL			0x040
+#define MDSS_MDP_REG_INTF_BORDER_COLOR			0x044
+#define MDSS_MDP_REG_INTF_UNDERFLOW_COLOR		0x048
+#define MDSS_MDP_REG_INTF_HSYNC_SKEW			0x04C
+#define MDSS_MDP_REG_INTF_POLARITY_CTL			0x050
+#define MDSS_MDP_REG_INTF_TEST_CTL			0x054
+#define MDSS_MDP_REG_INTF_TP_COLOR0			0x058
+#define MDSS_MDP_REG_INTF_TP_COLOR1			0x05C
+
+#define MDSS_MDP_REG_INTF_DEFLICKER_CONFIG		0x0F0
+#define MDSS_MDP_REG_INTF_DEFLICKER_STRNG_COEFF		0x0F4
+#define MDSS_MDP_REG_INTF_DEFLICKER_WEAK_COEFF		0x0F8
+
+#define MDSS_MDP_REG_INTF_DSI_CMD_MODE_TRIGGER_EN	0x084
+#define MDSS_MDP_REG_INTF_PANEL_FORMAT			0x090
+#define MDSS_MDP_REG_INTF_TPG_ENABLE			0x100
+#define MDSS_MDP_REG_INTF_TPG_MAIN_CONTROL		0x104
+#define MDSS_MDP_REG_INTF_TPG_VIDEO_CONFIG		0x108
+#define MDSS_MDP_REG_INTF_TPG_COMPONENT_LIMITS		0x10C
+#define MDSS_MDP_REG_INTF_TPG_RECTANGLE			0x110
+#define MDSS_MDP_REG_INTF_TPG_INITIAL_VALUE		0x114
+#define MDSS_MDP_REG_INTF_TPG_BLK_WHITE_PATTERN_FRAMES	0x118
+#define MDSS_MDP_REG_INTF_TPG_RGB_MAPPING		0x11C
+
+#define MDSS_MDP_REG_INTF_FRAME_LINE_COUNT_EN		0x0A8
+#define MDSS_MDP_REG_INTF_FRAME_COUNT			0x0AC
+#define MDSS_MDP_REG_INTF_LINE_COUNT			0x0B0
+
+enum mdss_mdp_pingpong_index {
+	MDSS_MDP_PINGPONG0,
+	MDSS_MDP_PINGPONG1,
+	MDSS_MDP_PINGPONG2,
+	MDSS_MDP_MAX_PINGPONG
+};
+
+#define MDSS_MDP_REG_PP_OFFSET(pp)	(0x21B00 + ((pp) * 0x100))
+
+#define MDSS_MDP_REG_PP_TEAR_CHECK_EN			0x000
+#define MDSS_MDP_REG_PP_SYNC_CONFIG_VSYNC		0x004
+#define MDSS_MDP_REG_PP_SYNC_CONFIG_HEIGHT		0x008
+#define MDSS_MDP_REG_PP_SYNC_WRCOUNT			0x00C
+#define MDSS_MDP_REG_PP_VSYNC_INIT_VAL			0x010
+#define MDSS_MDP_REG_PP_INT_COUNT_VAL			0x014
+#define MDSS_MDP_REG_PP_SYNC_THRESH			0x018
+#define MDSS_MDP_REG_PP_START_POS			0x01C
+#define MDSS_MDP_REG_PP_RD_PTR_IRQ			0x020
+#define MDSS_MDP_REG_PP_WR_PTR_IRQ			0x024
+#define MDSS_MDP_REG_PP_OUT_LINE_COUNT			0x028
+#define MDSS_MDP_REG_PP_LINE_COUNT			0x02C
+#define MDSS_MDP_REG_PP_AUTOREFRESH_CONFIG		0x030
+
+#define MDSS_MDP_REG_SMP_ALLOC_W0			0x00180
+#define MDSS_MDP_REG_SMP_ALLOC_R0			0x00230
+
+#define MDSS_MDP_SMP_MMB_SIZE		4096
+#define MDSS_MDP_SMP_MMB_BLOCKS		22
+
+enum mdss_mdp_smp_client_index {
+	MDSS_MDP_SMP_CLIENT_UNUSED,
+	MDSS_MDP_SMP_CLIENT_VIG0_FETCH_Y,
+	MDSS_MDP_SMP_CLIENT_VIG0_FETCH_CR,
+	MDSS_MDP_SMP_CLIENT_VIG0_FETCH_CB,
+	MDSS_MDP_SMP_CLIENT_VIG1_FETCH_Y,
+	MDSS_MDP_SMP_CLIENT_VIG1_FETCH_CR,
+	MDSS_MDP_SMP_CLIENT_VIG1_FETCH_CB,
+	MDSS_MDP_SMP_CLIENT_VIG2_FETCH_Y,
+	MDSS_MDP_SMP_CLIENT_VIG2_FETCH_CR,
+	MDSS_MDP_SMP_CLIENT_VIG2_FETCH_CB,
+	MDSS_MDP_SMP_CLIENT_DMA0_FETCH_Y,
+	MDSS_MDP_SMP_CLIENT_DMA0_FETCH_CR,
+	MDSS_MDP_SMP_CLIENT_DMA0_FETCH_CB,
+	MDSS_MDP_SMP_CLIENT_DMA1_FETCH_Y,
+	MDSS_MDP_SMP_CLIENT_DMA1_FETCH_CR,
+	MDSS_MDP_SMP_CLIENT_DMA1_FETCH_CB,
+	MDSS_MDP_SMP_CLIENT_RGB0_FETCH,
+	MDSS_MDP_SMP_CLIENT_RGB1_FETCH,
+	MDSS_MDP_SMP_CLIENT_RGB2_FETCH,
+};
+
+#endif /* MDSS_MDP_HWIO_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
new file mode 100644
index 0000000..99d4b4c
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -0,0 +1,300 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include "mdss_fb.h"
+#include "mdss_mdp.h"
+
+#define ROT_BLK_SIZE	128
+
+enum mdss_mdp_writeback_type {
+	MDSS_MDP_WRITEBACK_TYPE_ROTATOR,
+	MDSS_MDP_WRITEBACK_TYPE_LINE,
+	MDSS_MDP_WRITEBACK_TYPE_WFD,
+};
+
+struct mdss_mdp_writeback_ctx {
+	u32 wb_num;
+	u8 ref_cnt;
+	u8 type;
+
+	u32 intr_type;
+	u32 intf_num;
+
+	u32 opmode;
+	u32 format;
+	u16 width;
+	u16 height;
+	u8 rot90;
+
+	struct completion comp;
+	struct mdss_mdp_plane_sizes dst_planes;
+	struct mdss_mdp_data wb_data;
+};
+
+static struct mdss_mdp_writeback_ctx wb_ctx_list[MDSS_MDP_MAX_WRITEBACK] = {
+	{
+		.type = MDSS_MDP_WRITEBACK_TYPE_ROTATOR,
+		.intr_type = MDSS_MDP_IRQ_WB_ROT_COMP,
+		.intf_num = 0,
+	},
+	{
+		.type = MDSS_MDP_WRITEBACK_TYPE_ROTATOR,
+		.intr_type = MDSS_MDP_IRQ_WB_ROT_COMP,
+		.intf_num = 1,
+	},
+	{
+		.type = MDSS_MDP_WRITEBACK_TYPE_LINE,
+		.intr_type = MDSS_MDP_IRQ_WB_ROT_COMP,
+		.intf_num = 0,
+	},
+	{
+		.type = MDSS_MDP_WRITEBACK_TYPE_LINE,
+		.intr_type = MDSS_MDP_IRQ_WB_ROT_COMP,
+		.intf_num = 1,
+	},
+	{
+		.type = MDSS_MDP_WRITEBACK_TYPE_WFD,
+		.intr_type = MDSS_MDP_IRQ_WB_WFD,
+		.intf_num = 0,
+	},
+};
+
+static void *videomemory;
+
+static int mdss_mdp_writeback_addr_setup(struct mdss_mdp_writeback_ctx *ctx,
+					 struct mdss_mdp_data *data)
+{
+	int off, ret;
+
+	if (!data)
+		return -EINVAL;
+
+	pr_debug("wb_num=%d addr=0x%x\n", ctx->wb_num, data->p[0].addr);
+
+	ret = mdss_mdp_data_check(data, &ctx->dst_planes);
+	if (ret)
+		return ret;
+
+	off = MDSS_MDP_REG_WB_OFFSET(ctx->wb_num);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_WB_DST0_ADDR, data->p[0].addr);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_WB_DST1_ADDR, data->p[1].addr);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_WB_DST2_ADDR, data->p[2].addr);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_WB_DST3_ADDR, data->p[3].addr);
+
+	return 0;
+}
+
+static int mdss_mdp_writeback_format_setup(struct mdss_mdp_writeback_ctx *ctx)
+{
+	struct mdss_mdp_format_params *fmt;
+	u32 dst_format, pattern, ystride0, ystride1, outsize, chroma_samp;
+	int off, ret;
+
+	pr_debug("wb_num=%d format=%d\n", ctx->wb_num, ctx->format);
+
+	mdss_mdp_get_plane_sizes(ctx->format, ctx->width, ctx->height,
+				 &ctx->dst_planes);
+
+	fmt = mdss_mdp_get_format_params(ctx->format);
+	if (!fmt) {
+		pr_err("wb format=%d not supported\n", ctx->format);
+		return ret;
+	}
+
+	chroma_samp = fmt->chroma_sample;
+	if (ctx->rot90) {
+		if (chroma_samp == MDSS_MDP_CHROMA_H2V1)
+			chroma_samp = MDSS_MDP_CHROMA_H1V2;
+		else if (chroma_samp == MDSS_MDP_CHROMA_H1V2)
+			chroma_samp = MDSS_MDP_CHROMA_H2V1;
+	}
+
+	dst_format = (chroma_samp << 23) |
+		     (fmt->fetch_planes << 19) |
+		     (fmt->unpack_align_msb << 18) |
+		     (fmt->unpack_tight << 17) |
+		     (fmt->unpack_count << 12) |
+		     (fmt->bpp << 9) |
+		     (fmt->alpha_enable << 8) |
+		     (fmt->a_bit << 6) |
+		     (fmt->r_bit << 4) |
+		     (fmt->b_bit << 2) |
+		     (fmt->g_bit << 0);
+
+	pattern = (fmt->element3 << 24) |
+		  (fmt->element2 << 15) |
+		  (fmt->element1 << 8) |
+		  (fmt->element0 << 0);
+
+	ystride0 = (ctx->dst_planes.ystride[0]) |
+		   (ctx->dst_planes.ystride[1] << 16);
+	ystride1 = (ctx->dst_planes.ystride[2]) |
+		   (ctx->dst_planes.ystride[3] << 16);
+	outsize = (ctx->height << 16) | ctx->width;
+
+	off = MDSS_MDP_REG_WB_OFFSET(ctx->wb_num);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_WB_DST_FORMAT, dst_format);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_WB_DST_OP_MODE, ctx->opmode);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_WB_DST_PACK_PATTERN, pattern);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_WB_DST_YSTRIDE0, ystride0);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_WB_DST_YSTRIDE1, ystride1);
+	MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_WB_OUT_SIZE, outsize);
+
+	return 0;
+}
+
+static int mdss_mdp_writeback_wfd_setup(struct mdss_mdp_ctl *ctl,
+					struct mdss_mdp_writeback_ctx *ctx)
+{
+	struct msm_fb_data_type *mfd;
+	struct fb_info *fbi;
+	int ret;
+	u32 plane_size;
+
+	mfd = ctl->mfd;
+	fbi = mfd->fbi;
+
+	pr_debug("setup ctl=%d\n", ctl->num);
+
+	ctx->opmode = 0;
+	ctx->format = ctl->dst_format;
+	ctx->width = fbi->var.xres;
+	ctx->height = fbi->var.yres;
+
+	plane_size = ctx->width * ctx->height * fbi->var.bits_per_pixel / 8;
+
+	videomemory = (void *) fbi->fix.smem_start + fbi->fix.smem_len -
+		      plane_size;
+
+	ctx->wb_data.num_planes = 1;
+	ctx->wb_data.p[0].addr = (u32) videomemory;
+	ctx->wb_data.p[0].len = plane_size;
+
+	ret = mdss_mdp_writeback_format_setup(ctx);
+	if (ret) {
+		pr_err("format setup failed\n");
+		return ret;
+	}
+
+	ctl->flush_bits |=  BIT(16); /* WB */
+
+	return 0;
+}
+
+static int mdss_mdp_writeback_stop(struct mdss_mdp_ctl *ctl)
+{
+	struct mdss_mdp_writeback_ctx *ctx;
+
+	pr_debug("stop ctl=%d\n", ctl->num);
+
+	ctx = (struct mdss_mdp_writeback_ctx *) ctl->priv_data;
+	if (ctx) {
+		ctl->priv_data = NULL;
+		ctx->ref_cnt--;
+	}
+
+	return 0;
+}
+
+static void mdss_mdp_writeback_intr_done(void *arg)
+{
+	struct mdss_mdp_writeback_ctx *ctx;
+
+	ctx = (struct mdss_mdp_writeback_ctx *) arg;
+	if (!ctx) {
+		pr_err("invalid ctx\n");
+		return;
+	}
+
+	pr_debug("intr wb_num=%d\n", ctx->wb_num);
+
+	mdss_mdp_irq_disable_nosync(ctx->intr_type, ctx->intf_num);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, true);
+
+	complete_all(&ctx->comp);
+}
+
+static int mdss_mdp_writeback_display(struct mdss_mdp_ctl *ctl, void *arg)
+{
+	struct mdss_mdp_writeback_ctx *ctx;
+	struct mdss_mdp_data *wb_data;
+	u32 flush_bits;
+	int ret;
+
+	ctx = (struct mdss_mdp_writeback_ctx *) ctl->priv_data;
+	if (!ctx)
+		return -ENODEV;
+
+	wb_data = &ctx->wb_data;
+
+	ret = mdss_mdp_writeback_addr_setup(ctx, wb_data);
+	if (ret) {
+		pr_err("writeback data setup error ctl=%d\n", ctl->num);
+		return ret;
+	}
+
+	flush_bits = BIT(16); /* WB */
+	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, flush_bits);
+
+	INIT_COMPLETION(ctx->comp);
+	mdss_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
+				   mdss_mdp_writeback_intr_done, ctx);
+	mdss_mdp_irq_enable(ctx->intr_type, ctx->intf_num);
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
+	wmb();
+
+	pr_debug("writeback kickoff wb_num=%d\n", ctx->wb_num);
+	wait_for_completion_interruptible(&ctx->comp);
+
+	return 0;
+}
+
+int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl)
+{
+	struct mdss_mdp_writeback_ctx *ctx;
+	u32 mem_sel;
+	int ret = 0;
+
+	pr_debug("start ctl=%d\n", ctl->num);
+
+	mem_sel = (ctl->opmode & 0xF) - 1;
+	if (mem_sel < MDSS_MDP_MAX_WRITEBACK) {
+		ctx = &wb_ctx_list[mem_sel];
+		if (ctx->ref_cnt) {
+			pr_err("writeback in use %d\n", mem_sel);
+			return -EBUSY;
+		}
+		ctx->ref_cnt++;
+	} else {
+		pr_err("invalid writeback mode %d\n", mem_sel);
+		return -EINVAL;
+	}
+	ctl->priv_data = ctx;
+	ctx->wb_num = ctl->num;	/* wb num should match ctl num */
+
+	init_completion(&ctx->comp);
+
+	if (ctx->type == MDSS_MDP_WRITEBACK_TYPE_WFD)
+		ret = mdss_mdp_writeback_wfd_setup(ctl, ctx);
+	else /* line mode not supported */
+		return -ENOSYS;
+
+	ctl->stop_fnc = mdss_mdp_writeback_stop;
+	ctl->display_fnc = mdss_mdp_writeback_display;
+
+	return ret;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
new file mode 100644
index 0000000..bd4a974
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -0,0 +1,701 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+
+#include "mdss_fb.h"
+#include "mdss_mdp.h"
+
+#define CHECK_BOUNDS(offset, size, max_size) \
+	(((size) > (max_size)) || ((offset) > ((max_size) - (size))))
+
+static int mdss_mdp_overlay_get(struct msm_fb_data_type *mfd,
+				struct mdp_overlay *req)
+{
+	struct mdss_mdp_pipe *pipe;
+
+	pipe = mdss_mdp_pipe_get_locked(req->id);
+	if (pipe == NULL) {
+		pr_err("invalid pipe ndx=%x\n", req->id);
+		return -ENODEV;
+	}
+
+	*req = pipe->req_data;
+	mdss_mdp_pipe_unlock(pipe);
+
+	return 0;
+}
+
+static int mdss_mdp_overlay_req_check(struct msm_fb_data_type *mfd,
+				      struct mdp_overlay *req,
+				      struct mdss_mdp_format_params *fmt)
+{
+	u32 xres, yres;
+	u32 dst_w, dst_h;
+
+	xres = mfd->fbi->var.xres;
+	yres = mfd->fbi->var.yres;
+
+	if (req->z_order >= MDSS_MDP_MAX_STAGE) {
+		pr_err("zorder %d out of range\n", req->z_order);
+		return -ERANGE;
+	}
+
+	if (req->src.width > MAX_IMG_WIDTH ||
+	    req->src.height > MAX_IMG_HEIGHT ||
+	    req->src_rect.w == 0 || req->src_rect.h == 0 ||
+	    req->dst_rect.w < MIN_DST_W || req->dst_rect.h < MIN_DST_H ||
+	    req->dst_rect.w > MAX_DST_W || req->dst_rect.h > MAX_DST_H ||
+	    CHECK_BOUNDS(req->src_rect.x, req->src_rect.w, req->src.width) ||
+	    CHECK_BOUNDS(req->src_rect.y, req->src_rect.h, req->src.height) ||
+	    CHECK_BOUNDS(req->dst_rect.x, req->dst_rect.w, xres) ||
+	    CHECK_BOUNDS(req->dst_rect.y, req->dst_rect.h, yres)) {
+		pr_err("invalid image img_w=%d img_h=%d\n",
+				req->src.width, req->src.height);
+
+		pr_err("\tsrc_rect=%d,%d,%d,%d dst_rect=%d,%d,%d,%d\n",
+		       req->src_rect.x, req->src_rect.y,
+		       req->src_rect.w, req->src_rect.h,
+		       req->dst_rect.x, req->dst_rect.y,
+		       req->dst_rect.w, req->dst_rect.h);
+		return -EINVAL;
+	}
+
+	if (req->flags & MDP_ROT_90) {
+		dst_h = req->dst_rect.w;
+		dst_w = req->dst_rect.h;
+	} else {
+		dst_w = req->dst_rect.w;
+		dst_h = req->dst_rect.h;
+	}
+
+	if ((req->src_rect.w * MAX_UPSCALE_RATIO) < dst_w) {
+		pr_err("too much upscaling Width %d->%d\n",
+		       req->src_rect.w, req->dst_rect.w);
+		return -EINVAL;
+	}
+
+	if ((req->src_rect.h * MAX_UPSCALE_RATIO) < dst_h) {
+		pr_err("too much upscaling. Height %d->%d\n",
+		       req->src_rect.h, req->dst_rect.h);
+		return -EINVAL;
+	}
+
+	if (req->src_rect.w > (dst_w * MAX_DOWNSCALE_RATIO)) {
+		pr_err("too much downscaling. Width %d->%d\n",
+		       req->src_rect.w, req->dst_rect.w);
+		return -EINVAL;
+	}
+
+	if (req->src_rect.h > (dst_h * MAX_DOWNSCALE_RATIO)) {
+		pr_err("too much downscaling. Height %d->%d\n",
+		       req->src_rect.h, req->dst_rect.h);
+		return -EINVAL;
+	}
+
+	if (fmt->is_yuv) {
+		if ((req->src_rect.x & 0x1) || (req->src_rect.y & 0x1) ||
+		    (req->src_rect.w & 0x1) || (req->src_rect.h & 0x1)) {
+			pr_err("invalid odd src resolution\n");
+			return -EINVAL;
+		}
+		if ((req->dst_rect.x & 0x1) || (req->dst_rect.y & 0x1) ||
+		    (req->dst_rect.w & 0x1) || (req->dst_rect.h & 0x1)) {
+			pr_err("invalid odd dst resolution\n");
+			return -EINVAL;
+		}
+
+		if (((req->src_rect.w * (MAX_UPSCALE_RATIO / 2)) < dst_w) &&
+		    (fmt->chroma_sample == MDSS_MDP_CHROMA_420 ||
+		     fmt->chroma_sample == MDSS_MDP_CHROMA_H2V1)) {
+			pr_err("too much YUV upscaling Width %d->%d\n",
+			       req->src_rect.w, req->dst_rect.w);
+			return -EINVAL;
+		}
+
+		if (((req->src_rect.h * (MAX_UPSCALE_RATIO / 2)) < dst_h) &&
+		    (fmt->chroma_sample == MDSS_MDP_CHROMA_420 ||
+		     fmt->chroma_sample == MDSS_MDP_CHROMA_H1V2)) {
+			pr_err("too much YUV upscaling Height %d->%d\n",
+			       req->src_rect.h, req->dst_rect.h);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd,
+				       struct mdp_overlay *req,
+				       struct mdss_mdp_pipe **ppipe)
+{
+	struct mdss_mdp_format_params *fmt;
+	struct mdss_mdp_pipe *pipe;
+	struct mdss_mdp_mixer *mixer = NULL;
+	u32 pipe_type, mixer_mux;
+	int ret;
+
+	if (mfd == NULL || mfd->ctl == NULL)
+		return -ENODEV;
+
+	if (req->flags & MDSS_MDP_RIGHT_MIXER)
+		mixer_mux = MDSS_MDP_MIXER_MUX_RIGHT;
+	else
+		mixer_mux = MDSS_MDP_MIXER_MUX_LEFT;
+
+	pr_debug("pipe ctl=%u req id=%x mux=%d\n", mfd->ctl->num, req->id,
+			mixer_mux);
+
+	if (req->flags & MDP_ROT_90) {
+		pr_err("unsupported inline rotation\n");
+		return -ENOTSUPP;
+	}
+
+	fmt = mdss_mdp_get_format_params(req->src.format);
+	if (!fmt) {
+		pr_err("invalid pipe format %d\n", req->src.format);
+		return -EINVAL;
+	}
+
+	ret = mdss_mdp_overlay_req_check(mfd, req, fmt);
+	if (ret)
+		return ret;
+
+	pipe = mdss_mdp_mixer_stage_pipe(mfd->ctl, mixer_mux, req->z_order);
+	if (pipe && pipe->ndx != req->id) {
+		pr_err("stage %d taken by pnum=%d\n", req->z_order, pipe->num);
+		return -EBUSY;
+	}
+
+
+	if (req->id == MSMFB_NEW_REQUEST) {
+		mixer = mdss_mdp_mixer_get(mfd->ctl, mixer_mux);
+		if (!mixer) {
+			pr_err("unable to get mixer\n");
+			return -ENODEV;
+		}
+
+		if (fmt->is_yuv || (req->flags & MDP_OV_PIPE_SHARE))
+			pipe_type = MDSS_MDP_PIPE_TYPE_VIG;
+		else
+			pipe_type = MDSS_MDP_PIPE_TYPE_RGB;
+
+		pipe = mdss_mdp_pipe_alloc_locked(pipe_type);
+
+		/* VIG pipes can also support RGB format */
+		if (!pipe && pipe_type == MDSS_MDP_PIPE_TYPE_RGB) {
+			pipe_type = MDSS_MDP_PIPE_TYPE_VIG;
+			pipe = mdss_mdp_pipe_alloc_locked(pipe_type);
+		}
+
+		if (pipe == NULL) {
+			pr_err("error allocating pipe\n");
+			return -ENOMEM;
+		}
+
+		pipe->mixer = mixer;
+		pipe->mfd = mfd;
+	} else {
+		pipe = mdss_mdp_pipe_get_locked(req->id);
+		if (pipe == NULL) {
+			pr_err("invalid pipe ndx=%x\n", req->id);
+			return -ENODEV;
+		}
+	}
+
+	pipe->flags = req->flags;
+
+	pipe->img_width = req->src.width & 0x3fff;
+	pipe->img_height = req->src.height & 0x3fff;
+	pipe->src.x = req->src_rect.x;
+	pipe->src.y = req->src_rect.y;
+	pipe->src.w = req->src_rect.w;
+	pipe->src.h = req->src_rect.h;
+	pipe->dst.x = req->dst_rect.x;
+	pipe->dst.y = req->dst_rect.y;
+	pipe->dst.w = req->dst_rect.w;
+	pipe->dst.h = req->dst_rect.h;
+
+	pipe->src_fmt = fmt;
+
+	pipe->mixer_stage = req->z_order;
+	pipe->is_fg = req->is_fg;
+	pipe->alpha = req->alpha;
+	pipe->transp = req->transp_mask;
+
+	pipe->req_data = *req;
+
+	pipe->params_changed++;
+
+	req->id = pipe->ndx;
+
+	*ppipe = pipe;
+
+	mdss_mdp_pipe_unlock(pipe);
+
+	return ret;
+}
+
+static int mdss_mdp_overlay_set(struct msm_fb_data_type *mfd,
+				struct mdp_overlay *req)
+{
+	int ret;
+	struct mdss_mdp_pipe *pipe;
+
+	/* userspace zorder start with stage 0 */
+	req->z_order += MDSS_MDP_STAGE_0;
+
+	ret = mdss_mdp_overlay_pipe_setup(mfd, req, &pipe);
+
+	req->z_order -= MDSS_MDP_STAGE_0;
+
+	return ret;
+}
+
+static int mdss_mdp_overlay_unset(struct msm_fb_data_type *mfd, int ndx)
+{
+	struct mdss_mdp_pipe *pipe;
+	struct mdss_mdp_pipe *cleanup_pipes[MDSS_MDP_MAX_SSPP];
+	int i, ret = 0, clean_cnt = 0;
+	u32 pipe_ndx, unset_ndx = 0;
+
+	if (!mfd || !mfd->ctl)
+		return -ENODEV;
+
+	pr_debug("unset ndx=%x\n", ndx);
+
+	for (i = 0; unset_ndx != ndx && i < MDSS_MDP_MAX_SSPP; i++) {
+		pipe_ndx = BIT(i);
+		if (pipe_ndx & ndx) {
+			unset_ndx |= pipe_ndx;
+			pipe = mdss_mdp_pipe_get_locked(pipe_ndx);
+			if (pipe) {
+				mdss_mdp_mixer_pipe_unstage(pipe);
+				cleanup_pipes[clean_cnt++] = pipe;
+			} else {
+				pr_warn("unknown pipe ndx=%x\n", pipe_ndx);
+			}
+		}
+	}
+
+	if (clean_cnt) {
+		ret = mfd->kickoff_fnc(mfd->ctl);
+
+		for (i = 0; i < clean_cnt; i++)
+			mdss_mdp_pipe_destroy(cleanup_pipes[i]);
+	}
+
+	return ret;
+}
+
+static int mdss_mdp_overlay_play_wait(struct msm_fb_data_type *mfd,
+				      struct msmfb_overlay_data *req)
+{
+	int ret;
+
+	if (!mfd || !mfd->ctl)
+		return -ENODEV;
+
+	ret = mfd->kickoff_fnc(mfd->ctl);
+	if (!ret)
+		pr_err("error displaying\n");
+
+	return ret;
+}
+
+static int mdss_mdp_overlay_queue(struct msmfb_overlay_data *req,
+				  struct mdss_mdp_data *src_data)
+{
+	struct mdss_mdp_pipe *pipe;
+	struct mdss_mdp_ctl *ctl;
+	int ret;
+
+	pipe = mdss_mdp_pipe_get_locked(req->id);
+	if (pipe == NULL) {
+		pr_err("pipe ndx=%x doesn't exist\n", req->id);
+		return -ENODEV;
+	}
+
+	pr_debug("ov queue pnum=%d\n", pipe->num);
+
+	ret = mdss_mdp_pipe_queue_data(pipe, src_data);
+	ctl = pipe->mixer->ctl;
+	mdss_mdp_pipe_unlock(pipe);
+
+	if (ret == 0 && !(pipe->flags & MDP_OV_PLAY_NOWAIT))
+		ret = ctl->mfd->kickoff_fnc(ctl);
+
+
+	return ret;
+}
+
+static int mdss_mdp_overlay_play(struct msm_fb_data_type *mfd,
+				 struct msmfb_overlay_data *req)
+{
+	struct mdss_mdp_data src_data;
+	int ret = 0;
+
+	if (mfd == NULL)
+		return -ENODEV;
+
+	pr_debug("play req id=%x\n", req->id);
+
+	memset(&src_data, 0, sizeof(src_data));
+	mdss_mdp_get_img(mfd->iclient, &req->data, &src_data.p[0]);
+	if (src_data.p[0].len == 0) {
+		pr_err("src data pmem error\n");
+		return -ENOMEM;
+	}
+	src_data.num_planes = 1;
+
+	ret = mdss_mdp_overlay_queue(req, &src_data);
+
+	mdss_mdp_put_img(&src_data.p[0]);
+
+	return ret;
+}
+
+static int mdss_mdp_overlay_get_fb_pipe(struct msm_fb_data_type *mfd,
+					struct mdss_mdp_pipe **ppipe,
+					int mixer_mux)
+{
+	struct mdss_mdp_pipe *pipe;
+
+	pipe = mdss_mdp_mixer_stage_pipe(mfd->ctl, mixer_mux,
+					 MDSS_MDP_STAGE_BASE);
+	if (pipe == NULL) {
+		struct mdp_overlay req;
+		int ret;
+
+		memset(&req, 0, sizeof(req));
+
+		req.id = MSMFB_NEW_REQUEST;
+		req.src.format = mfd->fb_imgType;
+		req.src.height = mfd->fbi->var.yres;
+		req.src.width = mfd->fbi->var.xres;
+		if (mixer_mux == MDSS_MDP_MIXER_MUX_RIGHT) {
+			if (req.src.width <= MAX_MIXER_WIDTH)
+				return -ENODEV;
+
+			req.flags |= MDSS_MDP_RIGHT_MIXER;
+			req.src_rect.x = MAX_MIXER_WIDTH;
+			req.src_rect.w = req.src.width - MAX_MIXER_WIDTH;
+		} else {
+			req.src_rect.x = 0;
+			req.src_rect.w = MIN(req.src.width, MAX_MIXER_WIDTH);
+		}
+
+		req.src_rect.y = 0;
+		req.src_rect.h = req.src.height;
+		req.dst_rect.x = req.src_rect.x;
+		req.dst_rect.y = 0;
+		req.dst_rect.w = req.src_rect.w;
+		req.dst_rect.h = req.src_rect.h;
+		req.z_order = MDSS_MDP_STAGE_BASE;
+
+		pr_debug("allocating base pipe mux=%d\n", mixer_mux);
+
+		ret = mdss_mdp_overlay_pipe_setup(mfd, &req, &pipe);
+		if (ret)
+			return ret;
+
+		pr_debug("ctl=%d pnum=%d\n", mfd->ctl->num, pipe->num);
+	}
+
+	*ppipe = pipe;
+	return 0;
+}
+
+static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd)
+{
+	struct mdss_mdp_data data;
+	struct mdss_mdp_pipe *pipe;
+	struct fb_info *fbi;
+	u32 offset;
+	int bpp, ret;
+
+	if (!mfd)
+		return;
+
+	if (!mfd->ctl || !mfd->panel_power_on)
+		return;
+
+	fbi = mfd->fbi;
+
+	if (fbi->fix.smem_len == 0) {
+		pr_warn("fb memory not allocated\n");
+		return;
+	}
+
+	memset(&data, 0, sizeof(data));
+
+	bpp = fbi->var.bits_per_pixel / 8;
+	offset = fbi->var.xoffset * bpp +
+		 fbi->var.yoffset * fbi->fix.line_length;
+
+	data.p[0].addr = fbi->fix.smem_start + offset;
+	data.p[0].len = fbi->fix.smem_len - offset;
+	data.num_planes = 1;
+
+	ret = mdss_mdp_overlay_get_fb_pipe(mfd, &pipe, MDSS_MDP_MIXER_MUX_LEFT);
+	if (ret) {
+		pr_err("unable to allocate base pipe\n");
+		return;
+	}
+
+	mdss_mdp_pipe_lock(pipe);
+	ret = mdss_mdp_pipe_queue_data(pipe, &data);
+	mdss_mdp_pipe_unlock(pipe);
+	if (ret) {
+		pr_err("unable to queue data\n");
+		return;
+	}
+
+	if (fbi->var.xres > MAX_MIXER_WIDTH) {
+		ret = mdss_mdp_overlay_get_fb_pipe(mfd, &pipe,
+						   MDSS_MDP_MIXER_MUX_RIGHT);
+		if (ret) {
+			pr_err("unable to allocate right base pipe\n");
+			return;
+		}
+		mdss_mdp_pipe_lock(pipe);
+		ret = mdss_mdp_pipe_queue_data(pipe, &data);
+		mdss_mdp_pipe_unlock(pipe);
+		if (ret) {
+			pr_err("unable to queue right data\n");
+			return;
+		}
+	}
+
+	if (fbi->var.activate & FB_ACTIVATE_VBL)
+		mfd->kickoff_fnc(mfd->ctl);
+}
+
+static int mdss_mdp_hw_cursor_update(struct fb_info *info,
+				     struct fb_cursor *cursor)
+{
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	struct mdss_mdp_mixer *mixer;
+	struct fb_image *img = &cursor->image;
+	int calpha_en, transp_en, blendcfg, alpha;
+	int off, ret = 0;
+
+	mixer = mdss_mdp_mixer_get(mfd->ctl, MDSS_MDP_MIXER_MUX_DEFAULT);
+	off = MDSS_MDP_REG_LM_OFFSET(mixer->num);
+
+	if ((img->width > MDSS_MDP_CURSOR_WIDTH) ||
+	    (img->height > MDSS_MDP_CURSOR_HEIGHT) ||
+	    (img->depth != 32))
+		return -EINVAL;
+
+	pr_debug("mixer=%d enable=%x set=%x\n", mixer->num, cursor->enable,
+			cursor->set);
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	blendcfg = MDSS_MDP_REG_READ(off + MDSS_MDP_REG_LM_CURSOR_BLEND_CONFIG);
+
+	if (cursor->set & FB_CUR_SETPOS)
+		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_START_XY,
+				   (img->dy << 16) | img->dx);
+
+	if (cursor->set & FB_CUR_SETIMAGE) {
+		ret = copy_from_user(mfd->cursor_buf, img->data,
+				     img->width * img->height * 4);
+		if (ret)
+			return ret;
+
+		if (img->bg_color == 0xffffffff)
+			transp_en = 0;
+		else
+			transp_en = 1;
+
+		alpha = (img->fg_color & 0xff000000) >> 24;
+
+		if (alpha)
+			calpha_en = 0x0; /* xrgb */
+		else
+			calpha_en = 0x2; /* argb */
+
+		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_SIZE,
+				   (img->height << 16) | img->width);
+		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_STRIDE,
+				   img->width * 4);
+		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_BASE_ADDR,
+				   mfd->cursor_buf_phys);
+
+		wmb();
+
+		blendcfg &= ~0x1;
+		blendcfg |= (transp_en << 3) | (calpha_en << 1);
+		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_BLEND_CONFIG,
+				   blendcfg);
+		if (calpha_en)
+			MDSS_MDP_REG_WRITE(off +
+					   MDSS_MDP_REG_LM_CURSOR_BLEND_PARAM,
+					   alpha);
+
+		if (transp_en) {
+			MDSS_MDP_REG_WRITE(off +
+				   MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_LOW0,
+				   ((img->bg_color & 0xff00) << 8) |
+				   (img->bg_color & 0xff));
+			MDSS_MDP_REG_WRITE(off +
+				   MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_LOW1,
+				   ((img->bg_color & 0xff0000) >> 16));
+			MDSS_MDP_REG_WRITE(off +
+				   MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_HIGH0,
+				   ((img->bg_color & 0xff00) << 8) |
+				   (img->bg_color & 0xff));
+			MDSS_MDP_REG_WRITE(off +
+				   MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_HIGH1,
+				   ((img->bg_color & 0xff0000) >> 16));
+		}
+	}
+
+	if (!cursor->enable != !(blendcfg & 0x1)) {
+		if (cursor->enable)
+			blendcfg |= 0x1;
+		else
+			blendcfg &= ~0x1;
+
+		MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_BLEND_CONFIG,
+				   blendcfg);
+
+		mixer->cursor_enabled = cursor->enable;
+		mixer->params_changed++;
+	}
+
+	mixer->ctl->flush_bits |= BIT(6) << mixer->num;
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	return 0;
+}
+
+static int mdss_mdp_overlay_kickoff(struct mdss_mdp_ctl *ctl)
+{
+	return mdss_mdp_display_commit(ctl, NULL);
+}
+
+static int mdss_mdp_overlay_ioctl_handler(struct msm_fb_data_type *mfd,
+					  u32 cmd, void __user *argp)
+{
+	struct mdp_overlay req;
+	int val, ret = -ENOSYS;
+
+	switch (cmd) {
+	case MSMFB_OVERLAY_GET:
+		ret = copy_from_user(&req, argp, sizeof(req));
+		if (!ret) {
+			ret = mdss_mdp_overlay_get(mfd, &req);
+
+			if (!IS_ERR_VALUE(ret))
+				ret = copy_to_user(argp, &req, sizeof(req));
+		}
+
+		if (ret) {
+			pr_err("OVERLAY_GET failed (%d)\n", ret);
+			ret = -EFAULT;
+		}
+		break;
+
+	case MSMFB_OVERLAY_SET:
+		ret = copy_from_user(&req, argp, sizeof(req));
+		if (!ret) {
+			ret = mdss_mdp_overlay_set(mfd, &req);
+
+			if (!IS_ERR_VALUE(ret))
+				ret = copy_to_user(argp, &req, sizeof(req));
+		}
+		if (ret) {
+			pr_err("OVERLAY_SET failed (%d)\n", ret);
+			ret = -EFAULT;
+		}
+		break;
+
+
+	case MSMFB_OVERLAY_UNSET:
+		if (!IS_ERR_VALUE(copy_from_user(&val, argp, sizeof(val))))
+			ret = mdss_mdp_overlay_unset(mfd, val);
+		break;
+
+	case MSMFB_OVERLAY_PLAY_ENABLE:
+		if (!copy_from_user(&val, argp, sizeof(val))) {
+			mfd->overlay_play_enable = val;
+		} else {
+			pr_err("OVERLAY_PLAY_ENABLE failed (%d)\n", ret);
+			ret = -EFAULT;
+		}
+		break;
+
+	case MSMFB_OVERLAY_PLAY:
+		if (mfd->overlay_play_enable) {
+			struct msmfb_overlay_data data;
+
+			ret = copy_from_user(&data, argp, sizeof(data));
+			if (!ret) {
+				ret = mdss_mdp_overlay_play(mfd, &data);
+				if (!IS_ERR_VALUE(ret))
+					mdss_fb_update_backlight(mfd);
+			}
+
+			if (ret) {
+				pr_err("OVERLAY_PLAY failed (%d)\n", ret);
+				ret = -EFAULT;
+			}
+		} else {
+			ret = 0;
+		}
+		break;
+
+	case MSMFB_OVERLAY_PLAY_WAIT:
+		if (mfd->overlay_play_enable) {
+			struct msmfb_overlay_data data;
+
+			ret = copy_from_user(&data, argp, sizeof(data));
+			if (!ret)
+				ret = mdss_mdp_overlay_play_wait(mfd, &data);
+
+			if (ret) {
+				pr_err("OVERLAY_PLAY_WAIT failed (%d)\n", ret);
+				ret = -EFAULT;
+			}
+		} else {
+			ret = 0;
+		}
+		break;
+	}
+
+	return ret;
+}
+
+int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
+{
+	mfd->on_fnc = mdss_mdp_ctl_on;
+	mfd->off_fnc = mdss_mdp_ctl_off;
+	mfd->hw_refresh = true;
+	mfd->lut_update = NULL;
+	mfd->do_histogram = NULL;
+	mfd->overlay_play_enable = true;
+	mfd->cursor_update = mdss_mdp_hw_cursor_update;
+	mfd->dma_fnc = mdss_mdp_overlay_pan_display;
+	mfd->ioctl_handler = mdss_mdp_overlay_ioctl_handler;
+	mfd->kickoff_fnc = mdss_mdp_overlay_kickoff;
+
+	return 0;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
new file mode 100644
index 0000000..b52cff5
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -0,0 +1,675 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/bitmap.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+
+#include "mdss_mdp.h"
+
+#define SMP_MB_CNT (mdss_res->smp_mb_cnt)
+
+static DEFINE_MUTEX(mdss_mdp_sspp_lock);
+static DECLARE_BITMAP(mdss_mdp_smp_mmb_pool, MDSS_MDP_SMP_MMB_BLOCKS);
+
+static struct mdss_mdp_pipe mdss_mdp_pipe_list[MDSS_MDP_MAX_SSPP];
+
+static u32 mdss_mdp_smp_mmb_reserve(unsigned long *smp, size_t n)
+{
+	u32 i, mmb;
+
+	/* reserve more blocks if needed, but can't free mmb at this point */
+	for (i = bitmap_weight(smp, SMP_MB_CNT); i < n; i++) {
+		if (bitmap_full(mdss_mdp_smp_mmb_pool, SMP_MB_CNT))
+			break;
+
+		mmb = find_first_zero_bit(mdss_mdp_smp_mmb_pool, SMP_MB_CNT);
+		set_bit(mmb, smp);
+		set_bit(mmb, mdss_mdp_smp_mmb_pool);
+	}
+	return i;
+}
+
+static void mdss_mdp_smp_mmb_set(int client_id, unsigned long *smp)
+{
+	u32 mmb, off, data, s;
+
+	for_each_set_bit(mmb, smp, SMP_MB_CNT) {
+		off = (mmb / 3) * 4;
+		s = (mmb % 3) * 8;
+		data = MDSS_MDP_REG_READ(MDSS_MDP_REG_SMP_ALLOC_W0 + off);
+		data &= ~(0xFF << s);
+		data |= client_id << s;
+		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_SMP_ALLOC_W0 + off, data);
+		MDSS_MDP_REG_WRITE(MDSS_MDP_REG_SMP_ALLOC_R0 + off, data);
+	}
+}
+
+static void mdss_mdp_smp_mmb_free(unsigned long *smp)
+{
+	if (!bitmap_empty(smp, SMP_MB_CNT)) {
+		mdss_mdp_smp_mmb_set(MDSS_MDP_SMP_CLIENT_UNUSED, smp);
+		bitmap_andnot(mdss_mdp_smp_mmb_pool, mdss_mdp_smp_mmb_pool,
+			      smp, SMP_MB_CNT);
+		bitmap_zero(smp, SMP_MB_CNT);
+	}
+}
+
+static void mdss_mdp_smp_free(struct mdss_mdp_pipe *pipe)
+{
+	mdss_mdp_smp_mmb_free(&pipe->smp[0]);
+	mdss_mdp_smp_mmb_free(&pipe->smp[1]);
+	mdss_mdp_smp_mmb_free(&pipe->smp[2]);
+}
+
+static int mdss_mdp_smp_reserve(struct mdss_mdp_pipe *pipe)
+{
+	u32 num_blks = 0, reserved = 0;
+	int i;
+
+	if ((pipe->src_planes.num_planes > 1) &&
+	    (pipe->type == MDSS_MDP_PIPE_TYPE_RGB))
+		return -EINVAL;
+
+	mutex_lock(&mdss_mdp_sspp_lock);
+	for (i = 0; i < pipe->src_planes.num_planes; i++) {
+		num_blks = DIV_ROUND_UP(2 * pipe->src_planes.ystride[i],
+					mdss_res->smp_mb_size);
+
+		pr_debug("reserving %d mmb for pnum=%d plane=%d\n",
+				num_blks, pipe->num, i);
+		reserved = mdss_mdp_smp_mmb_reserve(&pipe->smp[i], num_blks);
+
+		if (reserved < num_blks)
+			break;
+	}
+
+	if (reserved < num_blks) {
+		pr_err("insufficient MMB blocks\n");
+		mdss_mdp_smp_free(pipe);
+		return -ENOMEM;
+	}
+	mutex_unlock(&mdss_mdp_sspp_lock);
+
+	return 0;
+}
+
+static int mdss_mdp_smp_alloc(struct mdss_mdp_pipe *pipe)
+{
+	u32 client_id;
+	int i;
+
+	switch (pipe->num) {
+	case MDSS_MDP_SSPP_VIG0:
+		client_id = MDSS_MDP_SMP_CLIENT_VIG0_FETCH_Y;
+		break;
+	case MDSS_MDP_SSPP_VIG1:
+		client_id = MDSS_MDP_SMP_CLIENT_VIG1_FETCH_Y;
+		break;
+	case MDSS_MDP_SSPP_VIG2:
+		client_id = MDSS_MDP_SMP_CLIENT_VIG2_FETCH_Y;
+		break;
+	case MDSS_MDP_SSPP_RGB0:
+		client_id = MDSS_MDP_SMP_CLIENT_RGB0_FETCH;
+		break;
+	case MDSS_MDP_SSPP_RGB1:
+		client_id = MDSS_MDP_SMP_CLIENT_RGB1_FETCH;
+		break;
+	case MDSS_MDP_SSPP_RGB2:
+		client_id = MDSS_MDP_SMP_CLIENT_RGB2_FETCH;
+		break;
+	case MDSS_MDP_SSPP_DMA0:
+		client_id = MDSS_MDP_SMP_CLIENT_DMA0_FETCH_Y;
+		break;
+	case MDSS_MDP_SSPP_DMA1:
+		client_id = MDSS_MDP_SMP_CLIENT_DMA1_FETCH_Y;
+		break;
+	default:
+		pr_err("no valid smp client for pnum=%d\n", pipe->num);
+		return -EINVAL;
+	}
+
+	mutex_lock(&mdss_mdp_sspp_lock);
+	for (i = 0; i < pipe->src_planes.num_planes; i++)
+		mdss_mdp_smp_mmb_set(client_id + i, &pipe->smp[i]);
+	mutex_unlock(&mdss_mdp_sspp_lock);
+	return 0;
+}
+
+void mdss_mdp_pipe_unlock(struct mdss_mdp_pipe *pipe)
+{
+	atomic_dec(&pipe->ref_cnt);
+	mutex_unlock(&pipe->lock);
+}
+
+int mdss_mdp_pipe_lock(struct mdss_mdp_pipe *pipe)
+{
+	if (atomic_inc_not_zero(&pipe->ref_cnt)) {
+		if (mutex_lock_interruptible(&pipe->lock)) {
+			atomic_dec(&pipe->ref_cnt);
+			return -EINTR;
+		}
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static struct mdss_mdp_pipe *mdss_mdp_pipe_init(u32 pnum)
+{
+	struct mdss_mdp_pipe *pipe = NULL;
+
+	if (atomic_read(&mdss_mdp_pipe_list[pnum].ref_cnt) == 0) {
+		pipe = &mdss_mdp_pipe_list[pnum];
+		memset(pipe, 0, sizeof(*pipe));
+
+		mutex_init(&pipe->lock);
+		atomic_set(&pipe->ref_cnt, 1);
+
+		if (mdss_mdp_pipe_lock(pipe) == 0) {
+			pipe->num = pnum;
+			pipe->type = mdss_res->pipe_type_map[pnum];
+			pipe->ndx = BIT(pnum);
+
+			pr_debug("ndx=%x pnum=%d\n", pipe->ndx, pipe->num);
+		} else {
+			atomic_set(&pipe->ref_cnt, 0);
+			pipe = NULL;
+		}
+	}
+	return pipe;
+}
+
+struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_pnum(u32 pnum)
+{
+	struct mdss_mdp_pipe *pipe = NULL;
+	mutex_lock(&mdss_mdp_sspp_lock);
+	if (mdss_res->pipe_type_map[pnum] != MDSS_MDP_PIPE_TYPE_UNUSED)
+		pipe = mdss_mdp_pipe_init(pnum);
+	mutex_unlock(&mdss_mdp_sspp_lock);
+	return pipe;
+}
+
+struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_locked(u32 type)
+{
+	struct mdss_mdp_pipe *pipe = NULL;
+	int pnum;
+
+	mutex_lock(&mdss_mdp_sspp_lock);
+	for (pnum = 0; pnum < MDSS_MDP_MAX_SSPP; pnum++) {
+		if (type == mdss_res->pipe_type_map[pnum]) {
+			pipe = mdss_mdp_pipe_init(pnum);
+			if (pipe)
+				break;
+		}
+	}
+	mutex_unlock(&mdss_mdp_sspp_lock);
+
+	return pipe;
+}
+
+struct mdss_mdp_pipe *mdss_mdp_pipe_get_locked(u32 ndx)
+{
+	struct mdss_mdp_pipe *pipe = NULL;
+	int i;
+
+	if (!ndx)
+		return NULL;
+
+	mutex_lock(&mdss_mdp_sspp_lock);
+	for (i = 0; i < MDSS_MDP_MAX_SSPP; i++) {
+		pipe = &mdss_mdp_pipe_list[i];
+		if (ndx == pipe->ndx)
+			break;
+	}
+	mutex_unlock(&mdss_mdp_sspp_lock);
+
+	if (i == MDSS_MDP_MAX_SSPP)
+		return NULL;
+
+	if (mdss_mdp_pipe_lock(pipe))
+		return NULL;
+
+	if (pipe->ndx != ndx) {
+		mdss_mdp_pipe_unlock(pipe);
+		pipe = NULL;
+	}
+
+	return pipe;
+}
+
+
+static void mdss_mdp_pipe_free(struct mdss_mdp_pipe *pipe)
+{
+	mdss_mdp_smp_free(pipe);
+	pipe->ndx = 0;
+	atomic_dec(&pipe->ref_cnt);
+	mdss_mdp_pipe_unlock(pipe);
+}
+
+int mdss_mdp_pipe_destroy(struct mdss_mdp_pipe *pipe)
+{
+	pr_debug("ndx=%x pnum=%d ref_cnt=%d\n", pipe->ndx, pipe->num,
+			atomic_read(&pipe->ref_cnt));
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	mutex_lock(&mdss_mdp_sspp_lock);
+	mdss_mdp_pipe_free(pipe);
+	mutex_unlock(&mdss_mdp_sspp_lock);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	return 0;
+}
+
+int mdss_mdp_pipe_release_all(struct msm_fb_data_type *mfd)
+{
+	struct mdss_mdp_pipe *pipe;
+	int i;
+
+	if (!mfd)
+		return -ENODEV;
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	mutex_lock(&mdss_mdp_sspp_lock);
+	for (i = 0; i < MDSS_MDP_MAX_SSPP; i++) {
+		pipe = &mdss_mdp_pipe_list[i];
+		if (atomic_read(&pipe->ref_cnt) && pipe->mfd == mfd) {
+			pr_debug("release pnum=%d\n", pipe->num);
+			if (mdss_mdp_pipe_lock(pipe) == 0) {
+				mdss_mdp_mixer_pipe_unstage(pipe);
+				mdss_mdp_pipe_free(pipe);
+			} else {
+				pr_err("unable to lock pipe=%d for release",
+				       pipe->num);
+			}
+		}
+	}
+	mutex_unlock(&mdss_mdp_sspp_lock);
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	return 0;
+}
+
+static inline void mdss_mdp_pipe_write(struct mdss_mdp_pipe *pipe,
+				       u32 reg, u32 val)
+{
+	int offset = MDSS_MDP_REG_SSPP_OFFSET(pipe->num);
+	MDSS_MDP_REG_WRITE(offset + reg, val);
+}
+
+static inline u32 mdss_mdp_pipe_read(struct mdss_mdp_pipe *pipe, u32 reg)
+{
+	int offset = MDSS_MDP_REG_SSPP_OFFSET(pipe->num);
+	return MDSS_MDP_REG_READ(offset + reg);
+}
+
+static int mdss_mdp_leading_zero(u32 num)
+{
+	u32 bit = 0x80000000;
+	int i;
+
+	for (i = 0; i < 32; i++) {
+		if (bit & num)
+			return i;
+		bit >>= 1;
+	}
+
+	return i;
+}
+
+static u32 mdss_mdp_scale_phase_step(int f_num, u32 src, u32 dst)
+{
+	u32 val, s;
+	int n;
+
+	n = mdss_mdp_leading_zero(src);
+	if (n > f_num)
+		n = f_num;
+	s = src << n;	/* maximum to reduce lose of resolution */
+	val = s / dst;
+	if (n < f_num) {
+		n = f_num - n;
+		val <<= n;
+		val |= ((s % dst) << n) / dst;
+	}
+
+	return val;
+}
+
+static int mdss_mdp_scale_setup(struct mdss_mdp_pipe *pipe)
+{
+	u32 scale_config = 0;
+	u32 phasex_step = 0, phasey_step = 0;
+	u32 chroma_sample;
+
+	if (pipe->type == MDSS_MDP_PIPE_TYPE_DMA) {
+		if (!(pipe->flags & MDP_ROT_90) && (pipe->dst.h != pipe->src.h
+						|| pipe->dst.w != pipe->src.w))
+			return -EINVAL;	/* no scaling supported on dma pipes */
+		else
+			return 0;
+	}
+
+	chroma_sample = pipe->src_fmt->chroma_sample;
+
+	if ((pipe->src.h != pipe->dst.h) ||
+	    (chroma_sample == MDSS_MDP_CHROMA_420) ||
+	    (chroma_sample == MDSS_MDP_CHROMA_H1V2)) {
+		pr_debug("scale y - src_h=%d dst_h=%d\n",
+				pipe->src.h, pipe->dst.h);
+
+		if ((pipe->src.h / MAX_DOWNSCALE_RATIO) > pipe->dst.h) {
+			pr_err("too much downscaling height=%d->%d",
+			       pipe->src.h, pipe->dst.h);
+			return -EINVAL;
+		}
+
+		scale_config |= MDSS_MDP_SCALEY_EN;
+
+		if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
+			u32 chr_dst_h = pipe->dst.h;
+			if ((chroma_sample == MDSS_MDP_CHROMA_420) ||
+			    (chroma_sample == MDSS_MDP_CHROMA_H1V2))
+				chr_dst_h *= 2;	/* 2x upsample chroma */
+
+			if (pipe->src.h <= pipe->dst.h)
+				scale_config |= /* G/Y, A */
+					(MDSS_MDP_SCALE_FILTER_BIL << 10) |
+					(MDSS_MDP_SCALE_FILTER_NEAREST << 18);
+			else
+				scale_config |= /* G/Y, A */
+					(MDSS_MDP_SCALE_FILTER_PCMN << 10) |
+					(MDSS_MDP_SCALE_FILTER_NEAREST << 18);
+
+			if (pipe->src.h <= chr_dst_h)
+				scale_config |= /* CrCb */
+					(MDSS_MDP_SCALE_FILTER_BIL << 14);
+			else
+				scale_config |= /* CrCb */
+					(MDSS_MDP_SCALE_FILTER_PCMN << 14);
+
+			phasey_step = mdss_mdp_scale_phase_step(
+				PHASE_STEP_SHIFT, pipe->src.h, chr_dst_h);
+
+			mdss_mdp_pipe_write(pipe,
+					MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPY,
+					phasey_step);
+		} else {
+			if (pipe->src.h <= pipe->dst.h)
+				scale_config |= /* RGB, A */
+					(MDSS_MDP_SCALE_FILTER_BIL << 10) |
+					(MDSS_MDP_SCALE_FILTER_NEAREST << 18);
+			else
+				scale_config |= /* RGB, A */
+					(MDSS_MDP_SCALE_FILTER_PCMN << 10) |
+					(MDSS_MDP_SCALE_FILTER_NEAREST << 18);
+		}
+
+		phasey_step = mdss_mdp_scale_phase_step(
+			PHASE_STEP_SHIFT, pipe->src.h, pipe->dst.h);
+	}
+
+	if ((pipe->src.w != pipe->dst.w) ||
+	    (chroma_sample == MDSS_MDP_CHROMA_420) ||
+	    (chroma_sample == MDSS_MDP_CHROMA_H2V1)) {
+		pr_debug("scale x - src_w=%d dst_w=%d\n",
+				pipe->src.w, pipe->dst.w);
+
+		if ((pipe->src.w / MAX_DOWNSCALE_RATIO) > pipe->dst.w) {
+			pr_err("too much downscaling width=%d->%d",
+			       pipe->src.w, pipe->dst.w);
+			return -EINVAL;
+		}
+
+		scale_config |= MDSS_MDP_SCALEX_EN;
+
+		if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
+			u32 chr_dst_w = pipe->dst.w;
+
+			if ((chroma_sample == MDSS_MDP_CHROMA_420) ||
+			    (chroma_sample == MDSS_MDP_CHROMA_H2V1))
+				chr_dst_w *= 2;	/* 2x upsample chroma */
+
+			if (pipe->src.w <= pipe->dst.w)
+				scale_config |= /* G/Y, A */
+					(MDSS_MDP_SCALE_FILTER_BIL << 8) |
+					(MDSS_MDP_SCALE_FILTER_NEAREST << 16);
+			else
+				scale_config |= /* G/Y, A */
+					(MDSS_MDP_SCALE_FILTER_PCMN << 8) |
+					(MDSS_MDP_SCALE_FILTER_NEAREST << 16);
+
+			if (pipe->src.w <= chr_dst_w)
+				scale_config |= /* CrCb */
+					(MDSS_MDP_SCALE_FILTER_BIL << 12);
+			else
+				scale_config |= /* CrCb */
+					(MDSS_MDP_SCALE_FILTER_PCMN << 12);
+
+			phasex_step = mdss_mdp_scale_phase_step(
+				PHASE_STEP_SHIFT, pipe->src.w, chr_dst_w);
+			mdss_mdp_pipe_write(pipe,
+					MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPX,
+					phasex_step);
+		} else {
+			if (pipe->src.w <= pipe->dst.w)
+				scale_config |= /* RGB, A */
+					(MDSS_MDP_SCALE_FILTER_BIL << 8) |
+					(MDSS_MDP_SCALE_FILTER_NEAREST << 16);
+			else
+				scale_config |= /* RGB, A */
+					(MDSS_MDP_SCALE_FILTER_PCMN << 8) |
+					(MDSS_MDP_SCALE_FILTER_NEAREST << 16);
+		}
+
+		phasex_step = mdss_mdp_scale_phase_step(
+			PHASE_STEP_SHIFT, pipe->src.w, pipe->dst.w);
+	}
+
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SCALE_CONFIG, scale_config);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SCALE_PHASE_STEP_X, phasex_step);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SCALE_PHASE_STEP_Y, phasey_step);
+	return 0;
+}
+
+static int mdss_mdp_image_setup(struct mdss_mdp_pipe *pipe)
+{
+	u32 img_size, src_size, src_xy, dst_size, dst_xy, ystride0, ystride1;
+
+	pr_debug("pnum=%d wh=%dx%d src={%d,%d,%d,%d} dst={%d,%d,%d,%d}\n",
+		   pipe->num, pipe->img_width, pipe->img_height,
+		   pipe->src.x, pipe->src.y, pipe->src.w, pipe->src.h,
+		   pipe->dst.x, pipe->dst.y, pipe->dst.w, pipe->dst.h);
+
+	if (mdss_mdp_scale_setup(pipe))
+		return -EINVAL;
+
+	mdss_mdp_get_plane_sizes(pipe->src_fmt->format, pipe->img_width,
+				 pipe->img_height, &pipe->src_planes);
+
+	img_size = (pipe->img_height << 16) | pipe->img_width;
+	src_size = (pipe->src.h << 16) | pipe->src.w;
+	src_xy = (pipe->src.y << 16) | pipe->src.x;
+	dst_size = (pipe->dst.h << 16) | pipe->dst.w;
+	dst_xy = (pipe->dst.y << 16) | pipe->dst.x;
+	ystride0 =  (pipe->src_planes.ystride[0]) |
+		    (pipe->src_planes.ystride[1] << 16);
+	ystride1 =  (pipe->src_planes.ystride[2]) |
+		    (pipe->src_planes.ystride[3] << 16);
+
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_IMG_SIZE, img_size);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_SIZE, src_size);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_XY, src_xy);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_OUT_SIZE, dst_size);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_OUT_XY, dst_xy);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_YSTRIDE0, ystride0);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_YSTRIDE1, ystride1);
+
+	return 0;
+}
+
+static int mdss_mdp_format_setup(struct mdss_mdp_pipe *pipe)
+{
+	struct mdss_mdp_format_params *fmt;
+	u32 rot90, opmode, chroma_samp;
+
+	fmt = pipe->src_fmt;
+
+	opmode = pipe->bwc_mode;
+	if (pipe->flags & MDP_FLIP_LR)
+		opmode |= MDSS_MDP_OP_FLIP_LR;
+	if (pipe->flags & MDP_FLIP_UD)
+		opmode |= MDSS_MDP_OP_FLIP_UD;
+
+	pr_debug("pnum=%d format=%d opmode=%x\n", pipe->num, fmt->format,
+			opmode);
+
+	rot90 = !!(pipe->flags & MDP_SOURCE_ROTATED_90);
+
+	chroma_samp = fmt->chroma_sample;
+	if (rot90) {
+		if (chroma_samp == MDSS_MDP_CHROMA_H2V1)
+			chroma_samp = MDSS_MDP_CHROMA_H1V2;
+		else if (chroma_samp == MDSS_MDP_CHROMA_H1V2)
+			chroma_samp = MDSS_MDP_CHROMA_H2V1;
+	}
+
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_FORMAT,
+			    (chroma_samp << 23) |
+			    (fmt->fetch_planes << 19) |
+			    (fmt->unpack_align_msb << 18) |
+			    (fmt->unpack_tight << 17) |
+			    (fmt->unpack_count << 12) |
+			    (rot90 << 11) |
+			    (fmt->bpp << 9) |
+			    (fmt->alpha_enable << 8) |
+			    (fmt->a_bit << 6) |
+			    (fmt->r_bit << 4) |
+			    (fmt->b_bit << 2) |
+			    (fmt->g_bit << 0));
+
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN,
+			    (fmt->element3 << 24) |
+			    (fmt->element2 << 16) |
+			    (fmt->element1 << 8) |
+			    (fmt->element0 << 0));
+
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_OP_MODE, opmode);
+
+	return 0;
+}
+
+static int mdss_mdp_vig_setup(struct mdss_mdp_pipe *pipe)
+{
+	u32 opmode = 0;
+
+	pr_debug("pnum=%x\n", pipe->num);
+
+	if (pipe->src_fmt->is_yuv)
+		opmode |= (0 << 19) |	/* DST_DATA=RGB */
+			  (1 << 18) |	/* SRC_DATA=YCBCR */
+			  (1 << 17);	/* CSC_1_EN */
+
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_VIG_OP_MODE, opmode);
+
+	return 0;
+}
+
+static int mdss_mdp_src_addr_setup(struct mdss_mdp_pipe *pipe,
+				   struct mdss_mdp_data *data)
+{
+	int ret;
+
+	pr_debug("pnum=%d\n", pipe->num);
+
+	if (pipe->type != MDSS_MDP_PIPE_TYPE_DMA)
+		data->bwc_enabled = pipe->bwc_mode;
+
+	ret = mdss_mdp_data_check(data, &pipe->src_planes);
+	if (ret)
+		return ret;
+
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC0_ADDR, data->p[0].addr);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC1_ADDR, data->p[1].addr);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC2_ADDR, data->p[2].addr);
+	mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC3_ADDR, data->p[3].addr);
+
+	return 0;
+}
+
+int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe,
+			     struct mdss_mdp_data *src_data)
+{
+	int ret = 0;
+	u32 params_changed;
+
+	if (!pipe) {
+		pr_err("pipe not setup properly for queue\n");
+		return -ENODEV;
+	}
+
+	if (!pipe->mixer) {
+		pr_err("pipe mixer not setup properly for queue\n");
+		return -ENODEV;
+	}
+
+	pr_debug("pnum=%x mixer=%d\n", pipe->num, pipe->mixer->num);
+
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+	params_changed = pipe->params_changed;
+	if (params_changed) {
+		pipe->params_changed = 0;
+
+		ret = mdss_mdp_image_setup(pipe);
+		if (ret) {
+			pr_err("image setup error for pnum=%d\n", pipe->num);
+			goto done;
+		}
+
+		ret = mdss_mdp_format_setup(pipe);
+		if (ret) {
+			pr_err("format %d setup error pnum=%d\n",
+			       pipe->src_fmt->format, pipe->num);
+			goto done;
+		}
+
+		if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG)
+			mdss_mdp_vig_setup(pipe);
+
+		ret = mdss_mdp_smp_reserve(pipe);
+		if (ret) {
+			pr_err("unable to reserve smp for pnum=%d\n",
+			       pipe->num);
+			goto done;
+		}
+
+		mdss_mdp_smp_alloc(pipe);
+	}
+
+	ret = mdss_mdp_src_addr_setup(pipe, src_data);
+	if (ret) {
+		pr_err("addr setup error for pnum=%d\n", pipe->num);
+		goto done;
+	}
+
+	mdss_mdp_mixer_pipe_update(pipe, params_changed);
+
+	pipe->play_cnt++;
+
+done:
+	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	return ret;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
new file mode 100644
index 0000000..25c9ac4
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -0,0 +1,349 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt)	"%s: " fmt, __func__
+
+#include <linux/android_pmem.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/file.h>
+#include <linux/ion.h>
+#include <linux/msm_kgsl.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include "mdss_fb.h"
+#include "mdss_mdp.h"
+#include "mdss_mdp_formats.h"
+
+enum {
+	MDP_INTR_VSYNC_INTF_0,
+	MDP_INTR_VSYNC_INTF_1,
+	MDP_INTR_VSYNC_INTF_2,
+	MDP_INTR_VSYNC_INTF_3,
+	MDP_INTR_PING_PONG_0,
+	MDP_INTR_PING_PONG_1,
+	MDP_INTR_PING_PONG_2,
+	MDP_INTR_WB_0,
+	MDP_INTR_WB_1,
+	MDP_INTR_WB_2,
+	MDP_INTR_MAX,
+};
+
+struct intr_callback {
+	void (*func)(void *);
+	void *arg;
+};
+
+struct intr_callback mdp_intr_cb[MDP_INTR_MAX];
+static DEFINE_SPINLOCK(mdss_mdp_intr_lock);
+
+static int mdss_mdp_intr2index(u32 intr_type, u32 intf_num)
+{
+	int index = -1;
+	switch (intr_type) {
+	case MDSS_MDP_IRQ_INTF_VSYNC:
+		index = MDP_INTR_VSYNC_INTF_0 + intf_num;
+		break;
+	case MDSS_MDP_IRQ_PING_PONG_COMP:
+		index = MDP_INTR_PING_PONG_0 + intf_num;
+		break;
+	case MDSS_MDP_IRQ_WB_ROT_COMP:
+		index = MDP_INTR_WB_0 + intf_num;
+		break;
+	case MDSS_MDP_IRQ_WB_WFD:
+		index = MDP_INTR_WB_2 + intf_num;
+		break;
+	}
+
+	return index;
+}
+
+int mdss_mdp_set_intr_callback(u32 intr_type, u32 intf_num,
+			       void (*fnc_ptr)(void *), void *arg)
+{
+	unsigned long flags;
+	int index, ret;
+
+	index = mdss_mdp_intr2index(intr_type, intf_num);
+	if (index < 0) {
+		pr_warn("invalid intr type=%u intf_num=%u\n",
+				intr_type, intf_num);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&mdss_mdp_intr_lock, flags);
+	if (!mdp_intr_cb[index].func) {
+		mdp_intr_cb[index].func = fnc_ptr;
+		mdp_intr_cb[index].arg = arg;
+		ret = 0;
+	} else {
+		ret = -EBUSY;
+	}
+	spin_unlock_irqrestore(&mdss_mdp_intr_lock, flags);
+
+	return ret;
+}
+
+static inline void mdss_mdp_intr_done(int index)
+{
+	void (*fnc)(void *);
+	void *arg;
+
+	spin_lock(&mdss_mdp_intr_lock);
+	fnc = mdp_intr_cb[index].func;
+	arg = mdp_intr_cb[index].arg;
+	if (fnc != NULL)
+		mdp_intr_cb[index].func = NULL;
+	spin_unlock(&mdss_mdp_intr_lock);
+	if (fnc)
+		fnc(arg);
+}
+
+irqreturn_t mdss_mdp_isr(int irq, void *ptr)
+{
+	u32 isr, mask;
+
+
+	isr = MDSS_MDP_REG_READ(MDSS_MDP_REG_INTR_STATUS);
+	if (isr == 0)
+		goto done;
+
+	pr_devel("isr=%x\n", isr);
+
+	mask = MDSS_MDP_REG_READ(MDSS_MDP_REG_INTR_EN);
+	MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_CLEAR, isr);
+
+	isr &= mask;
+	if (isr == 0)
+		goto done;
+
+	if (isr & MDSS_MDP_INTR_PING_PONG_0_DONE)
+		mdss_mdp_intr_done(MDP_INTR_PING_PONG_0);
+
+	if (isr & MDSS_MDP_INTR_PING_PONG_1_DONE)
+		mdss_mdp_intr_done(MDP_INTR_PING_PONG_1);
+
+	if (isr & MDSS_MDP_INTR_PING_PONG_2_DONE)
+		mdss_mdp_intr_done(MDP_INTR_PING_PONG_2);
+
+	if (isr & MDSS_MDP_INTR_INTF_0_VSYNC)
+		mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_0);
+
+	if (isr & MDSS_MDP_INTR_INTF_1_VSYNC)
+		mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_1);
+
+	if (isr & MDSS_MDP_INTR_INTF_2_VSYNC)
+		mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_2);
+
+	if (isr & MDSS_MDP_INTR_INTF_3_VSYNC)
+		mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_3);
+
+	if (isr & MDSS_MDP_INTR_WB_0_DONE)
+		mdss_mdp_intr_done(MDP_INTR_WB_0);
+
+	if (isr & MDSS_MDP_INTR_WB_1_DONE)
+		mdss_mdp_intr_done(MDP_INTR_WB_1);
+
+	if (isr & MDSS_MDP_INTR_WB_2_DONE)
+		mdss_mdp_intr_done(MDP_INTR_WB_2);
+
+done:
+	return IRQ_HANDLED;
+}
+
+struct mdss_mdp_format_params *mdss_mdp_get_format_params(u32 format)
+{
+	struct mdss_mdp_format_params *fmt = NULL;
+	if (format < MDP_IMGTYPE_LIMIT) {
+		fmt = &mdss_mdp_format_map[format];
+		if (fmt->format != format)
+			fmt = NULL;
+	}
+
+	return fmt;
+}
+
+int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h,
+			     struct mdss_mdp_plane_sizes *ps)
+{
+	struct mdss_mdp_format_params *fmt;
+	int i;
+
+	if (ps == NULL)
+		return -EINVAL;
+
+	if ((w > MAX_IMG_WIDTH) || (h > MAX_IMG_HEIGHT))
+		return -ERANGE;
+
+	fmt = mdss_mdp_get_format_params(format);
+	if (!fmt)
+		return -EINVAL;
+
+	memset(ps, 0, sizeof(struct mdss_mdp_plane_sizes));
+
+	if (fmt->fetch_planes == MDSS_MDP_PLANE_INTERLEAVED) {
+		u32 bpp = fmt->bpp + 1;
+		ps->num_planes = 1;
+		ps->plane_size[0] = w * h * bpp;
+		ps->ystride[0] = w * bpp;
+	} else {
+		u8 hmap[] = { 1, 2, 1, 2 };
+		u8 vmap[] = { 1, 1, 2, 2 };
+		u8 horiz, vert;
+
+		horiz = hmap[fmt->chroma_sample];
+		vert = vmap[fmt->chroma_sample];
+
+		if (format == MDP_Y_CR_CB_GH2V2) {
+			ps->plane_size[0] = ALIGN(w, 16) * h;
+			ps->plane_size[1] = ALIGN(w / horiz, 16) * (h / vert);
+			ps->ystride[0] = ALIGN(w, 16);
+			ps->ystride[1] = ALIGN(w / horiz, 16);
+		} else {
+			ps->plane_size[0] = w * h;
+			ps->plane_size[1] = (w / horiz) * (h / vert);
+			ps->ystride[0] = w;
+			ps->ystride[1] = (w / horiz);
+		}
+
+		if (fmt->fetch_planes == MDSS_MDP_PLANE_PSEUDO_PLANAR) {
+			ps->num_planes = 2;
+			ps->plane_size[1] *= 2;
+			ps->ystride[1] *= 2;
+		} else { /* planar */
+			ps->num_planes = 3;
+			ps->plane_size[2] = ps->plane_size[1];
+			ps->ystride[2] = ps->ystride[1];
+		}
+	}
+
+	for (i = 0; i < ps->num_planes; i++)
+		ps->total_size += ps->plane_size[i];
+
+	return 0;
+}
+
+int mdss_mdp_data_check(struct mdss_mdp_data *data,
+			struct mdss_mdp_plane_sizes *ps)
+{
+	if (!ps)
+		return 0;
+
+	if (!data || data->num_planes == 0)
+		return -ENOMEM;
+
+	if (data->bwc_enabled) {
+		return -EPERM; /* not supported */
+	} else {
+		struct mdss_mdp_img_data *prev, *curr;
+		int i;
+
+		pr_debug("srcp0=%x len=%u frame_size=%u\n", data->p[0].addr,
+				data->p[0].len, ps->total_size);
+
+		for (i = 0; i < ps->num_planes; i++) {
+			curr = &data->p[i];
+			if (i >= data->num_planes) {
+				u32 psize = ps->plane_size[i-1];
+				prev = &data->p[i-1];
+				if (prev->len > psize) {
+					curr->len = prev->len - psize;
+					prev->len = psize;
+				}
+				curr->addr = prev->addr + psize;
+			}
+			if (curr->len < ps->plane_size[i]) {
+				pr_err("insufficient mem=%u p=%d len=%u\n",
+				       curr->len, i, ps->plane_size[i]);
+				return -ENOMEM;
+			}
+			pr_debug("plane[%d] addr=%x len=%u\n", i,
+					curr->addr, curr->len);
+		}
+		data->num_planes = ps->num_planes;
+	}
+
+	return 0;
+}
+
+int mdss_mdp_put_img(struct mdss_mdp_img_data *data)
+{
+	/* only source may use frame buffer */
+	if (data->flags & MDP_MEMORY_ID_TYPE_FB) {
+		fput_light(data->srcp_file, data->p_need);
+		return 0;
+	}
+	if (data->srcp_file) {
+		put_pmem_file(data->srcp_file);
+		data->srcp_file = NULL;
+		return 0;
+	}
+	if (!IS_ERR_OR_NULL(data->srcp_ihdl)) {
+		ion_free(data->iclient, data->srcp_ihdl);
+		data->iclient = NULL;
+		data->srcp_ihdl = NULL;
+		return 0;
+	}
+
+	return -ENOMEM;
+}
+
+int mdss_mdp_get_img(struct ion_client *iclient, struct msmfb_data *img,
+		     struct mdss_mdp_img_data *data)
+{
+	struct file *file;
+	int ret = -EINVAL;
+	int fb_num;
+	unsigned long *start, *len;
+
+	start = (unsigned long *) &data->addr;
+	len = (unsigned long *) &data->len;
+	data->flags = img->flags;
+	data->p_need = 0;
+
+	if (img->flags & MDP_BLIT_SRC_GEM) {
+		data->srcp_file = NULL;
+		ret = kgsl_gem_obj_addr(img->memory_id, (int) img->priv,
+					start, len);
+	} else if (img->flags & MDP_MEMORY_ID_TYPE_FB) {
+		file = fget_light(img->memory_id, &data->p_need);
+		if (file && FB_MAJOR ==
+				MAJOR(file->f_dentry->d_inode->i_rdev)) {
+			data->srcp_file = file;
+			fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
+			ret = mdss_fb_get_phys_info(start, len, fb_num);
+		}
+	} else if (iclient) {
+		data->iclient = iclient;
+		data->srcp_ihdl = ion_import_fd(iclient, img->memory_id);
+		if (IS_ERR_OR_NULL(data->srcp_ihdl))
+			return PTR_ERR(data->srcp_ihdl);
+		ret = ion_phys(iclient, data->srcp_ihdl,
+			       start, (size_t *) len);
+	} else {
+		unsigned long vstart;
+		ret = get_pmem_file(img->memory_id, start, &vstart, len,
+				    &data->srcp_file);
+	}
+
+	if (!ret && (img->offset < data->len)) {
+		data->addr += img->offset;
+		data->len -= img->offset;
+	} else {
+		mdss_mdp_put_img(data);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
new file mode 100644
index 0000000..3fd943d
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -0,0 +1,176 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef MDSS_PANEL_H
+#define MDSS_PANEL_H
+
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+/* panel id type */
+struct panel_id {
+	u16 id;
+	u16 type;
+};
+
+/* panel type list */
+#define NO_PANEL		0xffff	/* No Panel */
+#define MDDI_PANEL		1	/* MDDI */
+#define EBI2_PANEL		2	/* EBI2 */
+#define LCDC_PANEL		3	/* internal LCDC type */
+#define EXT_MDDI_PANEL		4	/* Ext.MDDI */
+#define TV_PANEL		5	/* TV */
+#define HDMI_PANEL		6	/* HDMI TV */
+#define DTV_PANEL		7	/* DTV */
+#define MIPI_VIDEO_PANEL	8	/* MIPI */
+#define MIPI_CMD_PANEL		9	/* MIPI */
+#define WRITEBACK_PANEL		10	/* Wifi display */
+#define LVDS_PANEL		11	/* LVDS */
+#define EDP_PANEL		12	/* LVDS */
+
+/* panel class */
+enum {
+	DISPLAY_LCD = 0,	/* lcd = ebi2/mddi */
+	DISPLAY_LCDC,		/* lcdc */
+	DISPLAY_TV,		/* TV Out */
+	DISPLAY_EXT_MDDI,	/* External MDDI */
+	DISPLAY_WRITEBACK,
+};
+
+/* panel device locaiton */
+enum {
+	DISPLAY_1 = 0,		/* attached as first device */
+	DISPLAY_2,		/* attached on second device */
+	DISPLAY_3,              /* attached on third writeback device */
+	MAX_PHYS_TARGET_NUM,
+};
+
+/* panel info type */
+struct lcd_panel_info {
+	u32 vsync_enable;
+	u32 refx100;
+	u32 v_back_porch;
+	u32 v_front_porch;
+	u32 v_pulse_width;
+	u32 hw_vsync_mode;
+	u32 vsync_notifier_period;
+	u32 rev;
+};
+
+struct lcdc_panel_info {
+	u32 h_back_porch;
+	u32 h_front_porch;
+	u32 h_pulse_width;
+	u32 v_back_porch;
+	u32 v_front_porch;
+	u32 v_pulse_width;
+	u32 border_clr;
+	u32 underflow_clr;
+	u32 hsync_skew;
+	/* Pad width */
+	u32 xres_pad;
+	/* Pad height */
+	u32 yres_pad;
+};
+
+struct mipi_panel_info {
+	char mode;		/* video/cmd */
+	char interleave_mode;
+	char crc_check;
+	char ecc_check;
+	char dst_format;	/* shared by video and command */
+	char data_lane0;
+	char data_lane1;
+	char data_lane2;
+	char data_lane3;
+	char dlane_swap;	/* data lane swap */
+	char rgb_swap;
+	char b_sel;
+	char g_sel;
+	char r_sel;
+	char rx_eot_ignore;
+	char tx_eot_append;
+	char t_clk_post; /* 0xc0, DSI_CLKOUT_TIMING_CTRL */
+	char t_clk_pre;  /* 0xc0, DSI_CLKOUT_TIMING_CTRL */
+	char vc;	/* virtual channel */
+	struct mipi_dsi_phy_ctrl *dsi_phy_db;
+	/* video mode */
+	char pulse_mode_hsa_he;
+	char hfp_power_stop;
+	char hbp_power_stop;
+	char hsa_power_stop;
+	char eof_bllp_power_stop;
+	char bllp_power_stop;
+	char traffic_mode;
+	char frame_rate;
+	/* command mode */
+	char interleave_max;
+	char insert_dcs_cmd;
+	char wr_mem_continue;
+	char wr_mem_start;
+	char te_sel;
+	char stream;	/* 0 or 1 */
+	char mdp_trigger;
+	char dma_trigger;
+	u32 dsi_pclk_rate;
+	/* The packet-size should not bet changed */
+	char no_max_pkt_size;
+	/* Clock required during LP commands */
+	char force_clk_lane_hs;
+};
+
+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 mdss_panel_info {
+	u32 xres;
+	u32 yres;
+	u32 bpp;
+	u32 type;
+	u32 wait_cycle;
+	u32 pdest;
+	u32 bl_max;
+	u32 bl_min;
+	u32 fb_num;
+	u32 clk_rate;
+	u32 clk_min;
+	u32 clk_max;
+	u32 frame_count;
+	u32 is_3d_panel;
+	u32 out_format;
+
+	struct lcd_panel_info lcd;
+	struct lcdc_panel_info lcdc;
+	struct mipi_panel_info mipi;
+	struct lvds_panel_info lvds;
+};
+
+struct mdss_panel_data {
+	struct mdss_panel_info panel_info;
+	void (*set_backlight) (u32 bl_level);
+
+	/* function entry chain */
+	int (*on) (struct mdss_panel_data *pdata);
+	int (*off) (struct mdss_panel_data *pdata);
+};
+
+int mdss_register_panel(struct mdss_panel_data *pdata);
+#endif /* MDSS_PANEL_H */
diff --git a/drivers/video/msm/mdss/mdss_wb.c b/drivers/video/msm/mdss/mdss_wb.c
new file mode 100644
index 0000000..3be4525
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_wb.c
@@ -0,0 +1,111 @@
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/ioctl.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/msm_mdp.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/version.h>
+
+#include "mdss_panel.h"
+
+static int mdss_wb_on(struct mdss_panel_data *pdata)
+{
+	pr_debug("%s\n", __func__);
+	return 0;
+}
+
+static int mdss_wb_off(struct mdss_panel_data *pdata)
+{
+	pr_debug("%s\n", __func__);
+	return 0;
+}
+
+static int mdss_wb_parse_dt(struct platform_device *pdev,
+			    struct mdss_panel_data *pdata)
+{
+	struct device_node *np = pdev->dev.of_node;
+	u32 res[2], tmp;
+	int rc;
+
+	rc = of_property_read_u32_array(np, "qcom,mdss_pan_res", res, 2);
+	pdata->panel_info.xres = (!rc ? res[0] : 1280);
+	pdata->panel_info.yres = (!rc ? res[1] : 720);
+
+	rc = of_property_read_u32(np, "qcom,mdss_pan_bpp", &tmp);
+	pdata->panel_info.bpp = (!rc ? tmp : 24);
+
+	return 0;
+}
+
+static int mdss_wb_probe(struct platform_device *pdev)
+{
+	struct mdss_panel_data *pdata = NULL;
+	int rc = 0;
+
+	if (!pdev->dev.of_node)
+		return -ENODEV;
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	rc = !mdss_wb_parse_dt(pdev, pdata);
+	if (!rc)
+		return rc;
+
+	pdata->panel_info.type = WRITEBACK_PANEL;
+	pdata->panel_info.clk_rate = 74250000;
+	pdata->panel_info.pdest = DISPLAY_3;
+	pdata->panel_info.out_format = MDP_RGB_888;
+
+	pdata->on = mdss_wb_on;
+	pdata->off = mdss_wb_off;
+	pdev->dev.platform_data = pdata;
+
+	rc = mdss_register_panel(pdata);
+	if (rc) {
+		dev_err(&pdev->dev, "unable to register writeback panel\n");
+		return rc;
+	}
+
+	return rc;
+}
+
+static const struct of_device_id mdss_wb_match[] = {
+	{ .compatible = "qcom,mdss_wb", },
+	{ { 0 } }
+};
+
+static struct platform_driver mdss_wb_driver = {
+	.probe = mdss_wb_probe,
+	.driver = {
+		.name = "mdss_wb",
+		.of_match_table = mdss_wb_match,
+	},
+};
+
+static int __init mdss_wb_driver_init(void)
+{
+	int rc = 0;
+	rc = platform_driver_register(&mdss_wb_driver);
+	return rc;
+}
+
+module_init(mdss_wb_driver_init);
diff --git a/drivers/video/msm/mipi_NT35510.c b/drivers/video/msm/mipi_NT35510.c
index edbc952..e605aed 100644
--- a/drivers/video/msm/mipi_NT35510.c
+++ b/drivers/video/msm/mipi_NT35510.c
@@ -19,6 +19,8 @@
 static struct dsi_buf nt35510_tx_buf;
 static struct dsi_buf nt35510_rx_buf;
 
+static int mipi_nt35510_bl_ctrl;
+
 #define NT35510_SLEEP_OFF_DELAY 150
 #define NT35510_DISPLAY_ON_DELAY 150
 
@@ -528,8 +530,63 @@
 	return 0;
 }
 
+static ssize_t mipi_nt35510_wta_bl_ctrl(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	ssize_t ret = strnlen(buf, PAGE_SIZE);
+	int err;
+
+	err =  kstrtoint(buf, 0, &mipi_nt35510_bl_ctrl);
+	if (err)
+		return ret;
+
+	pr_info("%s: bl ctrl set to %d\n", __func__, mipi_nt35510_bl_ctrl);
+
+	return ret;
+}
+
+static DEVICE_ATTR(bl_ctrl, S_IWUSR, NULL, mipi_nt35510_wta_bl_ctrl);
+
+static struct attribute *mipi_nt35510_fs_attrs[] = {
+	&dev_attr_bl_ctrl.attr,
+	NULL,
+};
+
+static struct attribute_group mipi_nt35510_fs_attr_group = {
+	.attrs = mipi_nt35510_fs_attrs,
+};
+
+static int mipi_nt35510_create_sysfs(struct platform_device *pdev)
+{
+	int rc;
+	struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
+
+	if (!mfd) {
+		pr_err("%s: mfd not found\n", __func__);
+		return -ENODEV;
+	}
+	if (!mfd->fbi) {
+		pr_err("%s: mfd->fbi not found\n", __func__);
+		return -ENODEV;
+	}
+	if (!mfd->fbi->dev) {
+		pr_err("%s: mfd->fbi->dev not found\n", __func__);
+		return -ENODEV;
+	}
+	rc = sysfs_create_group(&mfd->fbi->dev->kobj,
+		&mipi_nt35510_fs_attr_group);
+	if (rc) {
+		pr_err("%s: sysfs group creation failed, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	return 0;
+}
+
 static int __devinit mipi_nt35510_lcd_probe(struct platform_device *pdev)
 {
+	struct platform_device *pthisdev = NULL;
 	pr_debug("%s\n", __func__);
 
 	if (pdev->id == 0) {
@@ -539,7 +596,8 @@
 		return 0;
 	}
 
-	msm_fb_add_device(pdev);
+	pthisdev = msm_fb_add_device(pdev);
+	mipi_nt35510_create_sysfs(pthisdev);
 
 	return 0;
 }
@@ -551,6 +609,8 @@
 	},
 };
 
+static int old_bl_level;
+
 static void mipi_nt35510_set_backlight(struct msm_fb_data_type *mfd)
 {
 	int bl_level;
@@ -558,11 +618,33 @@
 	bl_level = mfd->bl_level;
 
 	if (mipi_nt35510_pdata->bl_lock) {
-		spin_lock_irqsave(&mipi_nt35510_pdata->bl_spinlock, flags);
-		mipi_nt35510_pdata->pmic_backlight(bl_level);
-		spin_unlock_irqrestore(&mipi_nt35510_pdata->bl_spinlock, flags);
-	} else
-		mipi_nt35510_pdata->pmic_backlight(bl_level);
+		if (!mipi_nt35510_bl_ctrl) {
+			/* Level received is of range 1 to bl_max,
+			   We need to convert the levels to 1
+			   to 31 */
+			bl_level = (2 * bl_level * 31 + mfd->panel_info.bl_max)
+					/(2 * mfd->panel_info.bl_max);
+			if (bl_level == old_bl_level)
+				return;
+
+			if (bl_level == 0)
+				mipi_nt35510_pdata->backlight(0, 1);
+
+			if (old_bl_level == 0)
+				mipi_nt35510_pdata->backlight(50, 1);
+
+			spin_lock_irqsave(&mipi_nt35510_pdata->bl_spinlock,
+						flags);
+			mipi_nt35510_pdata->backlight(bl_level, 0);
+			spin_unlock_irqrestore(&mipi_nt35510_pdata->bl_spinlock,
+						flags);
+			old_bl_level = bl_level;
+		} else {
+			mipi_nt35510_pdata->backlight(bl_level, 1);
+		}
+	} else {
+		mipi_nt35510_pdata->backlight(bl_level, mipi_nt35510_bl_ctrl);
+	}
 }
 
 static struct msm_fb_panel_data nt35510_panel_data = {
diff --git a/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c b/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c
index f052e93..1524ce6 100644
--- a/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c
+++ b/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c
@@ -56,7 +56,7 @@
 	pinfo.lcdc.border_clr = 0;	/* blk */
 	pinfo.lcdc.underflow_clr = 0xff;	/* blue */
 	pinfo.lcdc.hsync_skew = 0;
-	pinfo.bl_max = 31;
+	pinfo.bl_max = 255;
 	pinfo.bl_min = 1;
 	pinfo.fb_num = 2;
 
diff --git a/drivers/video/msm/mipi_NT35510_video_wvga_pt.c b/drivers/video/msm/mipi_NT35510_video_wvga_pt.c
index 4e97d99..8a364ba 100644
--- a/drivers/video/msm/mipi_NT35510_video_wvga_pt.c
+++ b/drivers/video/msm/mipi_NT35510_video_wvga_pt.c
@@ -59,7 +59,7 @@
 	delayed from VSYNC active edge */
 	pinfo.lcdc.hsync_skew = 0;
 	pinfo.clk_rate = 499000000;
-	pinfo.bl_max = 31;
+	pinfo.bl_max = 255;
 	pinfo.bl_min = 1;
 	pinfo.fb_num = 2;
 
diff --git a/drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c b/drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c
index 7f5ac70..2ebfad4 100644
--- a/drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c
+++ b/drivers/video/msm/mipi_renesas_cmd_fwvga_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
@@ -93,7 +93,7 @@
 	pinfo.lcdc.border_clr = 0;	/* blk */
 	pinfo.lcdc.underflow_clr = 0xff;	/* blue */
 	pinfo.lcdc.hsync_skew = 0;
-	pinfo.bl_max = 100;
+	pinfo.bl_max = 255;
 	pinfo.bl_min = 1;
 	pinfo.fb_num = 2;
 
diff --git a/drivers/video/msm/mipi_renesas_video_fwvga_pt.c b/drivers/video/msm/mipi_renesas_video_fwvga_pt.c
index e826773..144d9ff 100644
--- a/drivers/video/msm/mipi_renesas_video_fwvga_pt.c
+++ b/drivers/video/msm/mipi_renesas_video_fwvga_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
@@ -105,7 +105,7 @@
 	pinfo.lcdc.border_clr = 0;	/* blk */
 	pinfo.lcdc.underflow_clr = 0xff;	/* blue */
 	pinfo.lcdc.hsync_skew = 0;
-	pinfo.bl_max = 100;
+	pinfo.bl_max = 255;
 	pinfo.bl_min = 1;
 	pinfo.fb_num = 2;
 
diff --git a/drivers/video/msm/mipi_toshiba.h b/drivers/video/msm/mipi_toshiba.h
index 4107161..dd446b9 100644
--- a/drivers/video/msm/mipi_toshiba.h
+++ b/drivers/video/msm/mipi_toshiba.h
@@ -21,7 +21,7 @@
 int mipi_toshiba_device_register(struct msm_panel_info *pinfo,
 					u32 channel, u32 panel);
 
-#define MIPI_TOSHIBA_PWM_FREQ_HZ 3921
+#define MIPI_TOSHIBA_PWM_FREQ_HZ 300
 #define MIPI_TOSHIBA_PWM_PERIOD_USEC (USEC_PER_SEC / MIPI_TOSHIBA_PWM_FREQ_HZ)
 #define MIPI_TOSHIBA_PWM_LEVEL 255
 #define MIPI_TOSHIBA_PWM_DUTY_LEVEL \
diff --git a/drivers/video/msm/mipi_truly_tft540960_1_e.c b/drivers/video/msm/mipi_truly_tft540960_1_e.c
index e465d46..98b24b1 100644
--- a/drivers/video/msm/mipi_truly_tft540960_1_e.c
+++ b/drivers/video/msm/mipi_truly_tft540960_1_e.c
@@ -19,6 +19,8 @@
 static struct dsi_buf truly_tx_buf;
 static struct dsi_buf truly_rx_buf;
 
+static int mipi_truly_bl_ctrl;
+
 #define TRULY_CMD_DELAY 0
 #define MIPI_SETTING_DELAY 10
 #define TRULY_SLEEP_OFF_DELAY 150
@@ -720,8 +722,64 @@
 	return 0;
 }
 
+static ssize_t mipi_truly_wta_bl_ctrl(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	ssize_t ret = strnlen(buf, PAGE_SIZE);
+	int err;
+
+	err =  kstrtoint(buf, 0, &mipi_truly_bl_ctrl);
+	if (err)
+		return ret;
+
+	pr_info("%s: bl ctrl set to %d\n", __func__, mipi_truly_bl_ctrl);
+
+	return ret;
+}
+
+static DEVICE_ATTR(bl_ctrl, S_IWUSR, NULL, mipi_truly_wta_bl_ctrl);
+
+static struct attribute *mipi_truly_fs_attrs[] = {
+	&dev_attr_bl_ctrl.attr,
+	NULL,
+};
+
+static struct attribute_group mipi_truly_fs_attr_group = {
+	.attrs = mipi_truly_fs_attrs,
+};
+
+static int mipi_truly_create_sysfs(struct platform_device *pdev)
+{
+	int rc;
+	struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
+
+	if (!mfd) {
+		pr_err("%s: mfd not found\n", __func__);
+		return -ENODEV;
+	}
+	if (!mfd->fbi) {
+		pr_err("%s: mfd->fbi not found\n", __func__);
+		return -ENODEV;
+	}
+	if (!mfd->fbi->dev) {
+		pr_err("%s: mfd->fbi->dev not found\n", __func__);
+		return -ENODEV;
+	}
+	rc = sysfs_create_group(&mfd->fbi->dev->kobj,
+		&mipi_truly_fs_attr_group);
+	if (rc) {
+		pr_err("%s: sysfs group creation failed, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+
 static int __devinit mipi_truly_lcd_probe(struct platform_device *pdev)
 {
+	struct platform_device *pthisdev = NULL;
 	int rc = 0;
 
 	if (pdev->id == 0) {
@@ -731,7 +789,8 @@
 		return rc;
 	}
 
-	msm_fb_add_device(pdev);
+	pthisdev = msm_fb_add_device(pdev);
+	mipi_truly_create_sysfs(pthisdev);
 
 	return rc;
 }
@@ -743,6 +802,8 @@
 	},
 };
 
+static int old_bl_level;
+
 static void mipi_truly_set_backlight(struct msm_fb_data_type *mfd)
 {
 	int bl_level;
@@ -750,11 +811,33 @@
 	bl_level = mfd->bl_level;
 
 	if (mipi_truly_pdata->bl_lock) {
-		spin_lock_irqsave(&mipi_truly_pdata->bl_spinlock, flags);
-		mipi_truly_pdata->pmic_backlight(bl_level);
-		spin_unlock_irqrestore(&mipi_truly_pdata->bl_spinlock, flags);
-	} else
-		mipi_truly_pdata->pmic_backlight(bl_level);
+		if (!mipi_truly_bl_ctrl) {
+			/* Level received is of range 1 to bl_max,
+			   We need to convert the levels to 1
+			   to 31 */
+			bl_level = (2 * bl_level * 31 + mfd->panel_info.bl_max)
+					/(2 * mfd->panel_info.bl_max);
+			if (bl_level == old_bl_level)
+				return;
+
+			if (bl_level == 0)
+				mipi_truly_pdata->backlight(0, 1);
+
+			if (old_bl_level == 0)
+				mipi_truly_pdata->backlight(50, 1);
+
+			spin_lock_irqsave(&mipi_truly_pdata->bl_spinlock,
+						flags);
+			mipi_truly_pdata->backlight(bl_level, 0);
+			spin_unlock_irqrestore(&mipi_truly_pdata->bl_spinlock,
+						flags);
+			old_bl_level = bl_level;
+		} else {
+			mipi_truly_pdata->backlight(bl_level, 1);
+		}
+	} else {
+		mipi_truly_pdata->backlight(bl_level, mipi_truly_bl_ctrl);
+	}
 }
 
 static struct msm_fb_panel_data truly_panel_data = {
diff --git a/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c b/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c
index de98177..3423241 100644
--- a/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c
+++ b/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c
@@ -56,7 +56,7 @@
 	pinfo.lcdc.border_clr = 0;	/* blk */
 	pinfo.lcdc.underflow_clr = 0xff;	/* blue */
 	pinfo.lcdc.hsync_skew = 0;
-	pinfo.bl_max = 31;
+	pinfo.bl_max = 255;
 	pinfo.bl_min = 1;
 	pinfo.fb_num = 2;
 
diff --git a/drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c b/drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c
index ea2ff47..3c0c0b7 100644
--- a/drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c
+++ b/drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c
@@ -59,7 +59,7 @@
 	pinfo.lcdc.hsync_skew = 0;
 	pinfo.clk_rate = 699000000;
 	pinfo.lcd.refx100 = 6000; /* FB driver calc FPS based on this value */
-	pinfo.bl_max = 31;
+	pinfo.bl_max = 255;
 	pinfo.bl_min = 1;
 	pinfo.fb_num = 2;
 
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index b71212c..f79a147 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -745,7 +745,8 @@
 		return VCD_ERR_ILLEGAL_PARM;
 	}
 	if (buf_entry->in_use) {
-		VCD_MSG_ERROR("\n Buffer is in use and is not flushed");
+		VCD_MSG_ERROR("Buffer is in use and is not flushed: %p, %d\n",
+			buf_entry, buf_entry->in_use);
 		return VCD_ERR_ILLEGAL_OP;
 	}
 
@@ -1043,6 +1044,7 @@
 {
 	u32 rc = VCD_S_SUCCESS;
 	struct vcd_buffer_entry *buf_entry;
+	struct vcd_buffer_entry *orig_frame = NULL;
 
 	VCD_MSG_LOW("vcd_flush_buffers:");
 
@@ -1066,9 +1068,19 @@
 							 vcd_frame_data),
 						cctxt,
 						cctxt->client_data);
+				orig_frame = vcd_find_buffer_pool_entry(
+						&cctxt->in_buf_pool,
+						buf_entry->virtual);
 				}
 
-			buf_entry->in_use = false;
+			if (orig_frame) {
+				orig_frame->in_use--;
+				if (orig_frame != buf_entry)
+					kfree(buf_entry);
+			} else {
+				buf_entry->in_use = false;
+				VCD_MSG_ERROR("Original frame not found in buffer pool\n");
+			}
 			VCD_BUFFERPOOL_INUSE_DECREMENT(
 				cctxt->in_buf_pool.in_use);
 			buf_entry = NULL;
@@ -3417,7 +3429,7 @@
 	struct vcd_property_slice_delivery_info slice_delivery_info;
 	u32 rc = VCD_S_SUCCESS;
 	prop_hdr.prop_id = VCD_I_SLICE_DELIVERY_MODE;
-	prop_hdr.sz = prop_hdr.sz =
+	prop_hdr.sz =
 		sizeof(struct vcd_property_slice_delivery_info);
 	rc = ddl_get_property(cctxt->ddl_handle, &prop_hdr,
 				&slice_delivery_info);
diff --git a/include/linux/mfd/pm8xxx/ccadc.h b/include/linux/mfd/pm8xxx/ccadc.h
index 23d0fb0..0bd4cc3 100644
--- a/include/linux/mfd/pm8xxx/ccadc.h
+++ b/include/linux/mfd/pm8xxx/ccadc.h
@@ -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
@@ -20,9 +20,11 @@
 /**
  * struct pm8xxx_ccadc_platform_data -
  * @r_sense:		sense resistor value in (mOhms)
+ * @calib_delay_ms:	how often should the adc calculate gain and offset
  */
 struct pm8xxx_ccadc_platform_data {
-	int r_sense;
+	int		r_sense;
+	unsigned int	calib_delay_ms;
 };
 
 #define CCADC_READING_RESOLUTION_N_V1	1085069
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index 537e0b5..90c2d99 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -117,7 +117,6 @@
  * @i_test:		current at which the unusable charger cutoff is to be
  *			calculated or the peak system current (mA)
  * @v_failure:		the voltage at which the battery is considered empty(mV)
- * @calib_delay_ms:	how often should the adc calculate gain and offset
  * @enable_fcc_learning:	if set the driver will learn full charge
  *				capacity of the battery upon end of charge
  */
@@ -127,7 +126,6 @@
 	unsigned int			r_sense;
 	unsigned int			i_test;
 	unsigned int			v_failure;
-	unsigned int			calib_delay_ms;
 	unsigned int			max_voltage_uv;
 	unsigned int			rconn_mohm;
 	int				enable_fcc_learning;
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 71484da..447fbbb 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -253,7 +253,6 @@
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
-#ifdef CONFIG_MMC_CLKGATE
 	int			clk_requests;	/* internal reference counter */
 	unsigned int		clk_delay;	/* number of MCI clk hold cycles */
 	bool			clk_gated;	/* clock gated */
@@ -263,7 +262,6 @@
 	struct mutex		clk_gate_mutex;	/* mutex for clock gating */
 	struct device_attribute clkgate_delay_attr;
 	unsigned long           clkgate_delay;
-#endif
 
 	/* host specific block data */
 	unsigned int		max_seg_size;	/* see blk_queue_max_segment_size */
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index f757fae..8b6351f 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -86,6 +86,8 @@
 	MDP_YCRYCB_H2V1,  /* YCrYCb interleave */
 	MDP_Y_CRCB_H2V1,  /* Y and CrCb, pseduo planer w/ Cr is in MSB */
 	MDP_Y_CBCR_H2V1,   /* Y and CrCb, pseduo planer w/ Cr is in MSB */
+	MDP_Y_CRCB_H1V2,
+	MDP_Y_CBCR_H1V2,
 	MDP_RGBA_8888,    /* ARGB 888 */
 	MDP_BGRA_8888,	  /* ABGR 888 */
 	MDP_RGBX_8888,	  /* RGBX 888 */
@@ -98,10 +100,10 @@
 	MDP_Y_CBCR_H1V1,  /* Y and CbCr, pseduo planer w/ Cb is in MSB */
 	MDP_YCRCB_H1V1,   /* YCrCb interleave */
 	MDP_YCBCR_H1V1,   /* YCbCr interleave */
+	MDP_BGR_565,      /* BGR 565 planer */
 	MDP_IMGTYPE_LIMIT,
 	MDP_RGB_BORDERFILL,	/* border fill pipe */
-	MDP_BGR_565 = MDP_IMGTYPE2_START,      /* BGR 565 planer */
-	MDP_FB_FORMAT,    /* framebuffer format */
+	MDP_FB_FORMAT = MDP_IMGTYPE2_START,    /* framebuffer format */
 	MDP_IMGTYPE_LIMIT2 /* Non valid image type after this enum */
 };
 
@@ -118,6 +120,8 @@
 	NUM_HSIC_PARAM,
 };
 
+#define MDSS_MDP_RIGHT_MIXER		0x100
+
 /* mdp_blit_req flag values */
 #define MDP_ROT_NOP 0
 #define MDP_FLIP_LR 0x1
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index f8329dd..22d4997 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -160,6 +160,16 @@
 };
 
 /**
+ * Used different VDDCX voltage values
+ */
+enum usb_vdd_value {
+	VDD_NONE = 0,
+	VDD_MIN,
+	VDD_MAX,
+	VDD_VAL_MAX,
+};
+
+/**
  * struct msm_otg_platform_data - platform device data
  *              for msm_otg driver.
  * @phy_init_seq: PHY configuration sequence. val, reg pairs
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 271079e..0c9b274 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -190,6 +190,9 @@
 #define MSM_CAM_IOCTL_EEPROM_IO_CFG \
 	_IOW(MSM_CAM_IOCTL_MAGIC, 53, struct msm_eeprom_cfg_data *)
 
+#define MSM_CAM_IOCTL_ISPIF_IO_CFG \
+	_IOR(MSM_CAM_IOCTL_MAGIC, 54, struct ispif_cfg_data *)
+
 struct msm_mctl_pp_cmd {
 	int32_t  id;
 	uint16_t length;
@@ -605,6 +608,7 @@
 
 	struct ion_allocation_data ion_alloc;
 	struct ion_fd_data fd_data;
+	int ion_dev_fd;
 };
 
 enum msm_st_frame_packing {
@@ -796,7 +800,10 @@
 #define CFG_SET_AUTOFLASH             41
 #define CFG_SET_EXPOSURE_COMPENSATION 42
 #define CFG_SET_ISO                   43
-#define CFG_MAX			44
+#define CFG_START_STREAM              44
+#define CFG_STOP_STREAM               45
+#define CFG_GET_CSI_PARAMS            46
+#define CFG_MAX			47
 
 
 #define MOVE_NEAR	0
@@ -1126,6 +1133,112 @@
 	uint16_t index;
 };
 
+struct msm_camera_csid_vc_cfg {
+	uint8_t cid;
+	uint8_t dt;
+	uint8_t decode_format;
+};
+
+struct csi_lane_params_t {
+	uint8_t csi_lane_assign;
+	uint8_t csi_lane_mask;
+	uint8_t csi_if;
+	uint8_t csid_core;
+	uint32_t csid_version;
+};
+
+#define CSI_EMBED_DATA 0x12
+#define CSI_RESERVED_DATA_0 0x13
+#define CSI_YUV422_8  0x1E
+#define CSI_RAW8    0x2A
+#define CSI_RAW10   0x2B
+#define CSI_RAW12   0x2C
+
+#define CSI_DECODE_6BIT 0
+#define CSI_DECODE_8BIT 1
+#define CSI_DECODE_10BIT 2
+#define CSI_DECODE_DPCM_10_8_10 5
+
+#define ISPIF_STREAM(intf, action) (((intf)<<ISPIF_S_STREAM_SHIFT)+(action))
+#define ISPIF_ON_FRAME_BOUNDARY	(0x01 << 0)
+#define ISPIF_OFF_FRAME_BOUNDARY    (0x01 << 1)
+#define ISPIF_OFF_IMMEDIATELY       (0x01 << 2)
+#define ISPIF_S_STREAM_SHIFT	4
+
+
+#define PIX_0 (0x01 << 0)
+#define RDI_0 (0x01 << 1)
+#define PIX_1 (0x01 << 2)
+#define RDI_1 (0x01 << 3)
+#define PIX_2 (0x01 << 4)
+#define RDI_2 (0x01 << 5)
+
+
+enum msm_ispif_intftype {
+	PIX0,
+	RDI0,
+	PIX1,
+	RDI1,
+	PIX2,
+	RDI2,
+	INTF_MAX,
+};
+
+enum msm_ispif_vc {
+	VC0,
+	VC1,
+	VC2,
+	VC3,
+};
+
+enum msm_ispif_cid {
+	CID0,
+	CID1,
+	CID2,
+	CID3,
+	CID4,
+	CID5,
+	CID6,
+	CID7,
+	CID8,
+	CID9,
+	CID10,
+	CID11,
+	CID12,
+	CID13,
+	CID14,
+	CID15,
+};
+
+struct msm_ispif_params {
+	uint8_t intftype;
+	uint16_t cid_mask;
+	uint8_t csid;
+};
+
+struct msm_ispif_params_list {
+	uint32_t len;
+	struct msm_ispif_params params[4];
+};
+
+enum ispif_cfg_type_t {
+	ISPIF_INIT,
+	ISPIF_SET_CFG,
+	ISPIF_SET_ON_FRAME_BOUNDARY,
+	ISPIF_SET_OFF_FRAME_BOUNDARY,
+	ISPIF_SET_OFF_IMMEDIATELY,
+	ISPIF_RELEASE,
+};
+
+struct ispif_cfg_data {
+	enum ispif_cfg_type_t cfgtype;
+	union {
+		uint32_t csid_version;
+		int cmd;
+		struct msm_ispif_params_list ispif_params;
+	} cfg;
+};
+
 struct sensor_cfg_data {
 	int cfgtype;
 	int mode;
@@ -1152,6 +1265,7 @@
 		struct sensor_calib_data calib_info;
 		struct sensor_output_info_t output_info;
 		struct msm_eeprom_data_t eeprom_data;
+		struct csi_lane_params_t csi_lane_params;
 		/* QRD */
 		uint16_t antibanding;
 		uint8_t contrast;
@@ -1409,6 +1523,7 @@
 	uint8_t flash_enabled;
 	uint8_t strobe_flash_enabled;
 	uint8_t actuator_enabled;
+	uint8_t ispif_supported;
 	int8_t total_steps;
 	uint8_t support_3d;
 	enum flash_type flashtype;
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 05e8b06..d5d8541 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -535,7 +535,7 @@
 	unsigned long page_idx;
 	unsigned long combined_idx;
 	unsigned long uninitialized_var(buddy_idx);
-	struct page *buddy;
+	struct page *buddy = NULL;
 
 	if (unlikely(PageCompound(page)))
 		if (unlikely(destroy_compound_page(page, order)))
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index 94bdd27..4193e12 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -1944,10 +1944,12 @@
 	{"LINEOUT2 DAC", NULL, "RX_BIAS"},
 
 	{"LINEOUT2", NULL, "LINEOUT2 PA"},
+	{"LINEOUT2 PA", NULL, "CP"},
 	{"LINEOUT2 PA", NULL, "LINEOUT2 DAC"},
 	{"LINEOUT2 DAC", NULL, "DAC3 MUX"},
 
 	{"LINEOUT1", NULL, "LINEOUT1 PA"},
+	{"LINEOUT2 PA", NULL, "CP"},
 	{"LINEOUT1 PA", NULL, "LINEOUT1 DAC"},
 	{"LINEOUT1 DAC", NULL, "DAC2 MUX"},
 
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 9dcfc1c..7eefe97 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -6129,14 +6129,14 @@
 	int scaled;
 	struct tabla_mbhc_plug_type_cfg *plug_type_ptr;
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
-	const bool vddio = (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV);
-	int num_det = (MBHC_NUM_DCE_PLUG_DETECT + vddio);
+	int num_det = MBHC_NUM_DCE_PLUG_DETECT + 1;
 	enum tabla_mbhc_plug_type plug_type[num_det];
 	s16 mb_v[num_det];
 	s32 mic_mv[num_det];
 	bool inval;
 	bool highdelta;
 	bool ahighv = false, highv;
+	bool gndmicswapped = false;
 
 	/* make sure override is on */
 	WARN_ON(!(snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x04));
@@ -6153,11 +6153,10 @@
 	 * 1st: check if voltage is in invalid range
 	 * 2nd - N-2nd: check voltage range and delta
 	 * N-1st: check voltage range, delta with HPHR GND switch
-	 * Nth: check voltage range with VDDIO switch if micbias V != vddio V*/
+	 * Nth: check voltage range with VDDIO switch */
 	for (i = 0; i < num_det; i++) {
-		gndswitch = (i == (num_det - 1 - vddio));
-		vddioswitch = (vddio && ((i == num_det - 1) ||
-					 (i == num_det - 2)));
+		gndswitch = (i == (num_det - 2));
+		vddioswitch = (i == (num_det - 1)) || (i == (num_det - 2));
 		if (i == 0) {
 			mb_v[i] = tabla_codec_setup_hs_polling(codec);
 			mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
@@ -6183,7 +6182,7 @@
 			 * was done with gndswitch, don't compare with DCE
 			 * with gndswitch */
 			highdelta = tabla_is_inval_ins_delta(codec, scaled,
-					mic_mv[i - !gndswitch - vddioswitch],
+					mic_mv[i - 1],
 					TABLA_MBHC_FAKE_INS_DELTA_SCALED_MV);
 			inval = (tabla_is_inval_ins_range(codec, mic_mv[i],
 							  highhph, &highv) ||
@@ -6198,9 +6197,13 @@
 			 * good headset is detected but HPHR GND switch makes
 			 * delta difference */
 			if (i == (num_det - 2) && highdelta && !ahighv)
-				plug_type[0] = PLUG_TYPE_GND_MIC_SWAP;
-			else if (i == (num_det - 1) && inval)
-				plug_type[0] = PLUG_TYPE_INVALID;
+				gndmicswapped = true;
+			else if (i == (num_det - 1) && inval) {
+				if (gndmicswapped)
+					plug_type[0] = PLUG_TYPE_GND_MIC_SWAP;
+				else
+					plug_type[0] = PLUG_TYPE_INVALID;
+			}
 		}
 		pr_debug("%s: DCE #%d, %04x, V %d, scaled V %d, GND %d, "
 			 "VDDIO %d, inval %d\n", __func__,
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
index 36cbb23..1125d20 100644
--- a/sound/soc/msm/Kconfig
+++ b/sound/soc/msm/Kconfig
@@ -105,6 +105,16 @@
 	help
 	 To add support for SoC audio on MSM8960.
 
+config SND_SOC_MSM_QDSP6V2_INTF
+	bool "SoC Q6 audio driver for MSMCOPPER"
+	depends on MSM_QDSP6_APR
+	help
+	 To add support for SoC audio on MSMCOPPER.
+	 This will enable all the platform specific
+	 interactions towards DSP. It includes asm,
+	 adm and afe interfaces on the DSP.
+
+
 config SND_SOC_VOICE
 	bool "SoC Q6 voice driver for MSM8960"
 	depends on SND_SOC_MSM_QDSP6_INTF
@@ -119,6 +129,15 @@
 	help
 	 To add support for MSM QDSP6 Soc Audio.
 
+config SND_SOC_QDSP6V2
+	tristate "SoC ALSA audio driver for QDSP6V2"
+	select SND_SOC_MSM_QDSP6V2_INTF
+	help
+	 To add support for MSM QDSP6V2 Soc Audio.
+	 This will enable sound soc platform specific
+	 audio drivers. This includes q6asm, q6adm,
+	 q6afe interfaces to DSP using apr.
+
 config SND_SOC_MSM8960
 	tristate "SoC Machine driver for MSM8960 and APQ8064 boards"
 	depends on ARCH_MSM8960 || ARCH_APQ8064
@@ -134,6 +153,20 @@
 	help
 	 To add support for SoC audio on MSM8960 and APQ8064 boards
 
+config SND_SOC_MSM8974
+	tristate "SoC Machine driver for MSMCOPPER boards"
+	depends on ARCH_MSMCOPPER
+	select SND_SOC_QDSP6V2
+	select SND_SOC_MSM_STUB
+	select SND_SOC_MSM_HOSTLESS_PCM
+	select SND_DYNAMIC_MINORS
+	help
+	 To add support for SoC audio on MSMCOPPER.
+	 This will enable sound soc drivers which
+	 interfaces with DSP, also it will enable
+	 the machine drivers and the corresponding
+	 DAI-links.
+
 config SND_SOC_MDM9615
 	tristate "SoC Machine driver for MDM9615 boards"
 	depends on ARCH_MSM9615
diff --git a/sound/soc/msm/mdm9615.c b/sound/soc/msm/mdm9615.c
index 363635f..90d8723 100644
--- a/sound/soc/msm/mdm9615.c
+++ b/sound/soc/msm/mdm9615.c
@@ -39,8 +39,8 @@
 #define MDM9615_SLIM_0_RX_MAX_CHANNELS		2
 #define MDM9615_SLIM_0_TX_MAX_CHANNELS		4
 
-#define BTSCO_RATE_8KHZ 8000
-#define BTSCO_RATE_16KHZ 16000
+#define SAMPLE_RATE_8KHZ 8000
+#define SAMPLE_RATE_16KHZ 16000
 
 #define BOTTOM_SPK_AMP_POS	0x1
 #define BOTTOM_SPK_AMP_NEG	0x2
@@ -261,9 +261,11 @@
 static int mdm9615_slim_0_rx_ch = 1;
 static int mdm9615_slim_0_tx_ch = 1;
 
-static int mdm9615_btsco_rate = BTSCO_RATE_8KHZ;
+static int mdm9615_btsco_rate = SAMPLE_RATE_8KHZ;
 static int mdm9615_btsco_ch = 1;
 
+static int mdm9615_auxpcm_rate = SAMPLE_RATE_8KHZ;
+
 static struct clk *codec_clk;
 static int clk_users;
 
@@ -679,6 +681,11 @@
 		SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
 };
 
+static const char * const auxpcm_rate_text[] = {"rate_8000", "rate_16000"};
+static const struct soc_enum mdm9615_auxpcm_enum[] = {
+		SOC_ENUM_SINGLE_EXT(2, auxpcm_rate_text),
+};
+
 static int mdm9615_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
 	struct snd_ctl_elem_value *ucontrol)
 {
@@ -730,19 +737,49 @@
 {
 	switch (ucontrol->value.integer.value[0]) {
 	case 0:
-		mdm9615_btsco_rate = BTSCO_RATE_8KHZ;
+		mdm9615_btsco_rate = SAMPLE_RATE_8KHZ;
 		break;
 	case 1:
-		mdm9615_btsco_rate = BTSCO_RATE_16KHZ;
+		mdm9615_btsco_rate = SAMPLE_RATE_16KHZ;
 		break;
 	default:
-		mdm9615_btsco_rate = BTSCO_RATE_8KHZ;
+		mdm9615_btsco_rate = SAMPLE_RATE_8KHZ;
 		break;
 	}
 	pr_debug("%s: mdm9615_btsco_rate = %d\n", __func__, mdm9615_btsco_rate);
 	return 0;
 }
 
+static int mdm9615_auxpcm_rate_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	pr_debug("%s: mdm9615_auxpcm_rate  = %d", __func__,
+		mdm9615_auxpcm_rate);
+	ucontrol->value.integer.value[0] = mdm9615_auxpcm_rate;
+	return 0;
+}
+
+static int mdm9615_auxpcm_rate_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		mdm9615_auxpcm_rate = SAMPLE_RATE_8KHZ;
+		break;
+	case 1:
+		mdm9615_auxpcm_rate = SAMPLE_RATE_16KHZ;
+		break;
+	default:
+		mdm9615_auxpcm_rate = SAMPLE_RATE_8KHZ;
+		break;
+	}
+	pr_debug("%s: mdm9615_auxpcm_rate = %d\n"
+		 "ucontrol->value.integer.value[0] = %d\n", __func__,
+		 mdm9615_auxpcm_rate,
+		 (int)ucontrol->value.integer.value[0]);
+	return 0;
+}
+
 static const struct snd_kcontrol_new tabla_mdm9615_controls[] = {
 	SOC_ENUM_EXT("Speaker Function", mdm9615_enum[0], mdm9615_get_spk,
 		mdm9615_set_spk),
@@ -752,6 +789,8 @@
 		mdm9615_slim_0_tx_ch_get, mdm9615_slim_0_tx_ch_put),
 	SOC_ENUM_EXT("Internal BTSCO SampleRate", mdm9615_btsco_enum[0],
 		     mdm9615_btsco_rate_get, mdm9615_btsco_rate_put),
+	SOC_ENUM_EXT("AUX PCM SampleRate", mdm9615_auxpcm_enum[0],
+		mdm9615_auxpcm_rate_get, mdm9615_auxpcm_rate_put),
 };
 
 static void *def_tabla_mbhc_cal(void)
@@ -1554,8 +1593,8 @@
 	struct snd_interval *channels = hw_param_interval(params,
 					SNDRV_PCM_HW_PARAM_CHANNELS);
 
-	/* PCM only supports mono output with 8khz sample rate */
-	rate->min = rate->max = 8000;
+	rate->min = rate->max = mdm9615_auxpcm_rate;
+	/* PCM only supports mono output */
 	channels->min = channels->max = 1;
 
 	return 0;
diff --git a/sound/soc/msm/mpq8064.c b/sound/soc/msm/mpq8064.c
index 9395e8f..4ecd8df 100644
--- a/sound/soc/msm/mpq8064.c
+++ b/sound/soc/msm/mpq8064.c
@@ -1062,7 +1062,8 @@
 		.cpu_dai_name	= "MultiMedia1",
 		.platform_name  = "msm-pcm-dsp",
 		.dynamic = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 		.ignore_suspend = 1,
@@ -1075,7 +1076,8 @@
 		.cpu_dai_name	= "MultiMedia2",
 		.platform_name  = "msm-multi-ch-pcm-dsp",
 		.dynamic = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 		.ignore_suspend = 1,
@@ -1088,7 +1090,8 @@
 		.cpu_dai_name   = "CS-VOICE",
 		.platform_name  = "msm-pcm-voice",
 		.dynamic = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 		.ignore_suspend = 1,
 		.ignore_pmdown_time = 1, /* this dainlink has playback support */
@@ -1102,7 +1105,8 @@
 		.cpu_dai_name	= "VoIP",
 		.platform_name  = "msm-voip-dsp",
 		.dynamic = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 		.ignore_suspend = 1,
@@ -1115,7 +1119,8 @@
 		.cpu_dai_name	= "MultiMedia3",
 		.platform_name  = "msm-pcm-dsp",
 		.dynamic = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 		.ignore_suspend = 1,
@@ -1129,7 +1134,8 @@
 		.cpu_dai_name	= "SLIMBUS0_HOSTLESS",
 		.platform_name  = "msm-pcm-hostless",
 		.dynamic = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 		.ignore_suspend = 1,
 		.ignore_pmdown_time = 1, /* this dainlink has playback support */
@@ -1142,7 +1148,8 @@
 		.cpu_dai_name	= "INT_FM_HOSTLESS",
 		.platform_name  = "msm-pcm-hostless",
 		.dynamic = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 		.ignore_suspend = 1,
 		.ignore_pmdown_time = 1, /* this dainlink has playback support */
@@ -1178,7 +1185,8 @@
 		.cpu_dai_name   = "MultiMedia4",
 		.platform_name  = "msm-compr-dsp",
 		.dynamic = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
 		.codec_dai_name = "snd-soc-dummy-dai",
 		.codec_name = "snd-soc-dummy",
 		.ignore_suspend = 1,
@@ -1191,7 +1199,8 @@
 		.cpu_dai_name = "VOICE_STUB",
 		.platform_name = "msm-pcm-hostless",
 		.dynamic = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 		.ignore_suspend = 1,
 		.ignore_pmdown_time = 1, /* this dainlink has playback support */
@@ -1205,7 +1214,8 @@
 		.cpu_dai_name = "HDMI_HOSTLESS",
 		.platform_name = "msm-pcm-hostless",
 		.dynamic = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 		.ignore_suspend = 1,
 		.ignore_pmdown_time = 1, /* this dainlink has playback support */
@@ -1219,7 +1229,8 @@
 		.cpu_dai_name = "MI2S_TX_HOSTLESS",
 		.platform_name = "msm-pcm-hostless",
 		.dynamic = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 		.ignore_suspend = 1,
 		.codec_dai_name = "snd-soc-dummy-dai",
@@ -1232,7 +1243,8 @@
 		.cpu_dai_name = "SEC_I2S_RX_HOSTLESS",
 		.platform_name = "msm-pcm-hostless",
 		.dynamic = 1,
-		.trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+				SND_SOC_DPCM_TRIGGER_POST},
 		.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
 		.ignore_suspend = 1,
 		.ignore_pmdown_time = 1, /* this dainlink has playback support */
diff --git a/sound/soc/msm/msm-pcm-afe.c b/sound/soc/msm/msm-pcm-afe.c
index 482cbee..5f3cada 100644
--- a/sound/soc/msm/msm-pcm-afe.c
+++ b/sound/soc/msm/msm-pcm-afe.c
@@ -32,6 +32,7 @@
 #include <linux/memory_alloc.h>
 #include <mach/msm_subsystem_map.h>
 #include "msm-pcm-afe.h"
+#include "msm-pcm-q6.h"
 
 #define MIN_PERIOD_SIZE (128 * 2)
 #define MAX_PERIOD_SIZE (128 * 2 * 2 * 6)
@@ -58,6 +59,10 @@
 static enum hrtimer_restart afe_hrtimer_callback(struct hrtimer *hrt);
 static enum hrtimer_restart afe_hrtimer_rec_callback(struct hrtimer *hrt);
 
+static void q6asm_event_handler(uint32_t opcode,
+		uint32_t token, uint32_t *payload, void *priv)
+{
+}
 static enum hrtimer_restart afe_hrtimer_callback(struct hrtimer *hrt)
 {
 	struct pcm_afe_info *prtd =
@@ -319,13 +324,22 @@
 	runtime->hw = msm_afe_hardware;
 	prtd->substream = substream;
 	runtime->private_data = prtd;
-	mutex_unlock(&prtd->lock);
+	prtd->audio_client = q6asm_audio_client_alloc(
+				(app_cb)q6asm_event_handler, prtd);
+	if (!prtd->audio_client) {
+		pr_debug("%s: Could not allocate memory\n", __func__);
+		kfree(prtd);
+		mutex_unlock(&prtd->lock);
+		return -ENOMEM;
+	}
 	hrtimer_init(&prtd->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		prtd->hrt.function = afe_hrtimer_callback;
 	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
 		prtd->hrt.function = afe_hrtimer_rec_callback;
 
+	mutex_unlock(&prtd->lock);
+
 	ret = snd_pcm_hw_constraint_list(runtime, 0,
 				SNDRV_PCM_HW_PARAM_RATE,
 				&constraints_sample_rates);
@@ -348,6 +362,7 @@
 	struct pcm_afe_info *prtd;
 	struct snd_soc_pcm_runtime *rtd = NULL;
 	struct snd_soc_dai *dai = NULL;
+	int dir = IN;
 	int ret = 0;
 
 	pr_debug("%s\n", __func__);
@@ -363,10 +378,12 @@
 	mutex_lock(&prtd->lock);
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		dir = IN;
 		ret =  afe_unregister_get_events(dai->id);
 		if (ret < 0)
 			pr_err("AFE unregister for events failed\n");
 	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		dir = OUT;
 		ret =  afe_unregister_get_events(dai->id);
 		if (ret < 0)
 			pr_err("AFE unregister for events failed\n");
@@ -385,17 +402,14 @@
 	}
 
 	if (dma_buf->area) {
-		if (msm_subsystem_unmap_buffer(prtd->mem_buffer) < 0) {
-			pr_err("%s: unmap buffer failed\n", __func__);
-			prtd->mem_buffer = NULL;
 			dma_buf->area = NULL;
 		}
-	}
 
-	if (dma_buf->addr)
-		free_contiguous_memory_by_paddr(dma_buf->addr);
+	q6asm_audio_client_buf_free_contiguous(dir,
+				prtd->audio_client);
 done:
 	pr_debug("%s: dai->id =%x\n", __func__, dai->id);
+	q6asm_audio_client_free(prtd->audio_client);
 	mutex_unlock(&prtd->lock);
 	prtd->prepared--;
 	kfree(prtd);
@@ -470,57 +484,45 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
 	struct pcm_afe_info *prtd = runtime->private_data;
-	int rc;
-	unsigned int flags = 0;
+	struct audio_buffer *buf;
+	int dir, ret;
 
 	pr_debug("%s:\n", __func__);
 
 	mutex_lock(&prtd->lock);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dir = IN;
+	else
+		dir = OUT;
+	ret = q6asm_audio_client_buf_alloc_contiguous(dir,
+			prtd->audio_client,
+			runtime->hw.period_bytes_min,
+			runtime->hw.periods_max);
+	if (ret < 0) {
+		pr_err("Audio Start: Buffer Allocation failed rc = %d\n", ret);
+		mutex_unlock(&prtd->lock);
+		return -ENOMEM;
+	}
+	buf = prtd->audio_client->port[dir].buf;
 
+	if (buf == NULL || buf[0].data == NULL) {
+		mutex_unlock(&prtd->lock);
+		return -ENOMEM;
+	}
+
+	pr_debug("%s:buf = %p\n", __func__, buf);
 	dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
 	dma_buf->dev.dev = substream->pcm->card->dev;
 	dma_buf->private_data = NULL;
-
-	dma_buf->addr = allocate_contiguous_ebi_nomap(
-				runtime->hw.buffer_bytes_max, SZ_4K);
-	if (!dma_buf->addr) {
+	dma_buf->area = buf[0].data;
+	dma_buf->addr =  buf[0].phys;
+	dma_buf->bytes = runtime->hw.buffer_bytes_max;
+	if (!dma_buf->area) {
 		pr_err("%s:MSM AFE physical memory allocation failed\n",
 							__func__);
 		mutex_unlock(&prtd->lock);
 		return -ENOMEM;
 	}
-
-	flags = MSM_SUBSYSTEM_MAP_KADDR | MSM_SUBSYSTEM_MAP_CACHED;
-
-	prtd->mem_buffer = msm_subsystem_map_buffer(dma_buf->addr,
-				runtime->hw.buffer_bytes_max, flags,
-				NULL, 0);
-	if (IS_ERR((void *) prtd->mem_buffer)) {
-		pr_err("%s: map_buffer failed error = %ld\n", __func__,
-				PTR_ERR((void *)prtd->mem_buffer));
-		free_contiguous_memory_by_paddr(dma_buf->addr);
-		mutex_unlock(&prtd->lock);
-		return -ENOMEM;
-	}
-
-	dma_buf->area = prtd->mem_buffer->vaddr;
-
-	pr_debug("%s: dma_buf->area: 0x%p, dma_buf->addr: 0x%x", __func__,
-			(unsigned int *) dma_buf->area, dma_buf->addr);
-
-	if (!dma_buf->area) {
-		pr_err("%s: Invalid Virtual address\n", __func__);
-		if (prtd->mem_buffer) {
-			msm_subsystem_unmap_buffer(prtd->mem_buffer);
-			prtd->mem_buffer = NULL;
-			dma_buf->area = NULL;
-		}
-		free_contiguous_memory_by_paddr(dma_buf->addr);
-		mutex_unlock(&prtd->lock);
-		return -ENOMEM;
-	}
-
-	dma_buf->bytes = runtime->hw.buffer_bytes_max;
 	memset(dma_buf->area, 0, runtime->hw.buffer_bytes_max);
 	prtd->dma_addr = (u32) dma_buf->addr;
 
@@ -528,11 +530,11 @@
 
 	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
 
-	rc = afe_cmd_memory_map(dma_buf->addr, dma_buf->bytes);
-	if (rc < 0)
+	ret = afe_cmd_memory_map(dma_buf->addr, dma_buf->bytes);
+	if (ret < 0)
 		pr_err("fail to map memory to DSP\n");
 
-	return rc;
+	return ret;
 }
 static snd_pcm_uframes_t msm_afe_pointer(struct snd_pcm_substream *substream)
 {
diff --git a/sound/soc/msm/msm-pcm-afe.h b/sound/soc/msm/msm-pcm-afe.h
index 38026d5..9be11f3 100644
--- a/sound/soc/msm/msm-pcm-afe.h
+++ b/sound/soc/msm/msm-pcm-afe.h
@@ -30,7 +30,7 @@
 	int prepared;
 	struct hrtimer hrt;
 	int poll_time;
-	struct msm_mapped_buffer *mem_buffer;
+	struct audio_client *audio_client;
 };
 
 
diff --git a/sound/soc/msm/msm-pcm-lpa.c b/sound/soc/msm/msm-pcm-lpa.c
index 3cab34f..66a8854 100644
--- a/sound/soc/msm/msm-pcm-lpa.c
+++ b/sound/soc/msm/msm-pcm-lpa.c
@@ -232,10 +232,12 @@
 		pr_debug("SNDRV_PCM_TRIGGER_START\n");
 		q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
 		atomic_set(&prtd->start, 1);
+		atomic_set(&prtd->stop, 0);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 		pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
 		atomic_set(&prtd->start, 0);
+		atomic_set(&prtd->stop, 1);
 		if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
 			break;
 		break;
@@ -323,6 +325,7 @@
 
 	prtd->dsp_cnt = 0;
 	atomic_set(&prtd->pending_buffer, 1);
+	atomic_set(&prtd->stop, 1);
 	runtime->private_data = prtd;
 	lpa_audio.prtd = prtd;
 	lpa_set_volume(lpa_audio.volume);
@@ -366,7 +369,8 @@
 	To issue EOS to dsp, we need to be run state otherwise
 	EOS is not honored.
 	*/
-	if (msm_routing_check_backend_enabled(soc_prtd->dai_link->be_id)) {
+	if (msm_routing_check_backend_enabled(soc_prtd->dai_link->be_id) &&
+		(!atomic_read(&prtd->stop))) {
 		rc = q6asm_run(prtd->audio_client, 0, 0, 0);
 		atomic_set(&prtd->pending_buffer, 0);
 		prtd->cmd_ack = 0;
@@ -386,6 +390,7 @@
 	q6asm_audio_client_buf_free_contiguous(dir,
 				prtd->audio_client);
 
+	atomic_set(&prtd->stop, 1);
 	pr_debug("%s\n", __func__);
 	msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
 		SNDRV_PCM_STREAM_PLAYBACK);
diff --git a/sound/soc/msm/msm-pcm-q6.h b/sound/soc/msm/msm-pcm-q6.h
index e5551ea..9e743a7 100644
--- a/sound/soc/msm/msm-pcm-q6.h
+++ b/sound/soc/msm/msm-pcm-q6.h
@@ -71,6 +71,7 @@
 	int close_ack;
 	int cmd_ack;
 	atomic_t start;
+	atomic_t stop;
 	atomic_t out_count;
 	atomic_t in_count;
 	atomic_t out_needed;
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index e137a66..4e1ce52 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -2316,6 +2316,8 @@
 	{"BE_OUT", NULL, "PCM_RX"},
 	{"PCM_TX", NULL, "BE_IN"},
 	{"BE_OUT", NULL, "SLIMBUS_3_RX"},
+	{"BE_OUT", NULL, "STUB_RX"},
+	{"STUB_TX", NULL, "BE_IN"},
 };
 
 static int msm_pcm_routing_hw_params(struct snd_pcm_substream *substream,
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index d47910b..4678ea4 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -21,7 +21,6 @@
 #include <sound/core.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
-#include <sound/soc-dsp.h>
 #include <sound/pcm.h>
 #include <sound/jack.h>
 #include <asm/mach-types.h>
@@ -123,8 +122,8 @@
 		}
 		ret = pm8xxx_gpio_config(bottom_spk_pamp_gpio, &param);
 		if (ret)
-			pr_err("%s: Failed to configure Bottom Spk Ampl"
-				" gpio %u\n", __func__, bottom_spk_pamp_gpio);
+			pr_err("%s: Failed to configure Bottom Spk Ampl gpio %u\n",
+				__func__, bottom_spk_pamp_gpio);
 		else {
 			pr_debug("%s: enable Bottom spkr amp gpio\n", __func__);
 			gpio_direction_output(bottom_spk_pamp_gpio, 1);
@@ -140,15 +139,15 @@
 		}
 		ret = pm8xxx_gpio_config(top_spk_pamp_gpio, &param);
 		if (ret)
-			pr_err("%s: Failed to configure Top Spk Ampl"
-				" gpio %u\n", __func__, top_spk_pamp_gpio);
+			pr_err("%s: Failed to configure Top Spk Ampl gpio %u\n",
+				__func__, top_spk_pamp_gpio);
 		else {
 			pr_debug("%s: enable Top spkr amp gpio\n", __func__);
 			gpio_direction_output(top_spk_pamp_gpio, 1);
 		}
 	} else {
-		pr_err("%s: ERROR : Invalid External Speaker Ampl GPIO."
-			" gpio = %u\n", __func__, spk_amp_gpio);
+		pr_err("%s: ERROR : Invalid External Speaker Ampl GPIO. gpio = %u\n",
+			__func__, spk_amp_gpio);
 		return;
 	}
 }
@@ -160,8 +159,8 @@
 		if ((msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
 			(msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
 
-			pr_debug("%s() External Bottom Speaker Ampl already "
-				"turned on. spk = 0x%08x\n", __func__, spk);
+			pr_debug("%s() External Bottom Speaker Ampl already turned on. spk = 0x%08x\n",
+						__func__, spk);
 			return;
 		}
 
@@ -171,8 +170,8 @@
 			(msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
 
 			msm_enable_ext_spk_amp_gpio(bottom_spk_pamp_gpio);
-			pr_debug("%s: slepping 4 ms after turning on external "
-				" Bottom Speaker Ampl\n", __func__);
+			pr_debug("%s: slepping 4 ms after turning on external Bottom Speaker Ampl\n",
+							__func__);
 			usleep_range(4000, 4000);
 		}
 
@@ -181,8 +180,8 @@
 		if ((msm_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
 			(msm_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
 
-			pr_debug("%s() External Top Speaker Ampl already"
-				"turned on. spk = 0x%08x\n", __func__, spk);
+			pr_debug("%s() External Top Speaker Ampl already turned on. spk = 0x%08x\n",
+						__func__, spk);
 			return;
 		}
 
@@ -192,8 +191,8 @@
 			(msm_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
 
 			msm_enable_ext_spk_amp_gpio(top_spk_pamp_gpio);
-			pr_debug("%s: sleeping 4 ms after turning on "
-				" external Top Speaker Ampl\n", __func__);
+			pr_debug("%s: sleeping 4 ms after turning on external Top Speaker Ampl\n",
+						__func__);
 			usleep_range(4000, 4000);
 		}
 	} else  {
@@ -215,8 +214,8 @@
 		gpio_free(bottom_spk_pamp_gpio);
 		msm_ext_bottom_spk_pamp = 0;
 
-		pr_debug("%s: sleeping 4 ms after turning off external Bottom"
-			" Speaker Ampl\n", __func__);
+		pr_debug("%s: sleeping 4 ms after turning off external Bottom Speaker Ampl\n",
+					__func__);
 
 		usleep_range(4000, 4000);
 
@@ -229,8 +228,8 @@
 		gpio_free(top_spk_pamp_gpio);
 		msm_ext_top_spk_pamp = 0;
 
-		pr_debug("%s: sleeping 4 ms after turning off external Top"
-			" Spkaker Ampl\n", __func__);
+		pr_debug("%s: sleeping 4 ms after turning off external Top Spkaker Ampl\n",
+					__func__);
 
 		usleep_range(4000, 4000);
 	} else  {
@@ -442,9 +441,9 @@
 	{"MIC BIAS4 External", NULL, "Digital Mic6"},
 };
 
-static const char *spk_function[] = {"Off", "On"};
-static const char *slim0_rx_ch_text[] = {"One", "Two"};
-static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
+static const char *const spk_function[] = {"Off", "On"};
+static const char *const slim0_rx_ch_text[] = {"One", "Two"};
+static const char *const slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
 
 static const struct soc_enum msm_enum[] = {
 	SOC_ENUM_SINGLE_EXT(2, spk_function),
@@ -452,7 +451,7 @@
 	SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
 };
 
-static const char *btsco_rate_text[] = {"8000", "16000"};
+static const char *const btsco_rate_text[] = {"8000", "16000"};
 static const struct soc_enum msm_btsco_enum[] = {
 		SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
 };
@@ -537,21 +536,6 @@
 		msm_btsco_rate_get, msm_btsco_rate_put),
 };
 
-static struct snd_soc_dsp_link lpa_fe_media = {
-	.playback = true,
-	.trigger = {
-		SND_SOC_DSP_TRIGGER_POST,
-		SND_SOC_DSP_TRIGGER_POST
-	},
-};
-static struct snd_soc_dsp_link fe_media = {
-	.playback = true,
-	.capture = true,
-	.trigger = {
-		SND_SOC_DSP_TRIGGER_POST,
-		SND_SOC_DSP_TRIGGER_POST
-	},
-};
 static int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
 					struct snd_pcm_hw_params *params)
 {
@@ -654,7 +638,13 @@
 		.cpu_dai_name	= "MultiMedia1",
 		.platform_name  = "msm-pcm-dsp",
 		.dynamic = 1,
-		.dsp_link = &fe_media,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST},
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
 		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
 	},
 	{
@@ -663,7 +653,13 @@
 		.cpu_dai_name	= "MultiMedia3",
 		.platform_name  = "msm-pcm-lpa",
 		.dynamic = 1,
-		.dsp_link = &lpa_fe_media,
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			SND_SOC_DPCM_TRIGGER_POST},
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.codec_name = "snd-soc-dummy",
+		.ignore_suspend = 1,
+		/* this dainlink has playback support */
+		.ignore_pmdown_time = 1,
 		.be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
 	},
 
@@ -679,6 +675,8 @@
 		.be_id = MSM_BACKEND_DAI_AUXPCM_RX,
 		.be_hw_params_fixup = msm_auxpcm_be_params_fixup,
 		.ops = &msm_auxpcm_be_ops,
+		.ignore_pmdown_time = 1,
+		/* this dainlink has playback support */
 	},
 	{
 		.name = LPASS_BE_AUXPCM_TX,
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index daba79d..7723934 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -139,8 +139,7 @@
 		case ASM_SESSION_CMD_RUN_V2: {
 			if (!atomic_read(&prtd->pending_buffer))
 				break;
-			pr_debug("%s:writing %d bytes"
-				" of buffer[%d] to dsp\n",
+			pr_debug("%s:writing %d bytes of buffer[%d] to dsp\n",
 				__func__, prtd->pcm_count, prtd->out_head);
 			buf = prtd->audio_client->port[IN].buf;
 			pr_debug("%s:writing buffer[%d] from 0x%08x\n",
@@ -367,8 +366,8 @@
 		rc = q6asm_set_volume(compressed_audio.prtd->audio_client,
 								 volume);
 		if (rc < 0) {
-			pr_err("%s: Send Volume command failed"
-					" rc=%d\n", __func__, rc);
+			pr_err("%s: Send Volume command failed rc=%d\n",
+						__func__, rc);
 		}
 	}
 	compressed_audio.volume = volume;
@@ -489,8 +488,8 @@
 			runtime->hw.period_bytes_min,
 			runtime->hw.periods_max);
 	if (ret < 0) {
-		pr_err("Audio Start: Buffer Allocation failed "
-					"rc = %d\n", ret);
+		pr_err("Audio Start: Buffer Allocation failed rc = %d\n",
+						ret);
 		return -ENOMEM;
 	}
 	buf = prtd->audio_client->port[dir].buf;
@@ -535,12 +534,9 @@
 		temp = temp * (runtime->rate/1000);
 		temp = div_u64(temp, 1000);
 		tstamp.sampling_rate = runtime->rate;
-		tstamp.rendered = (size_t)(temp & 0xFFFFFFFF);
-		tstamp.decoded  = (size_t)((temp >> 32) & 0xFFFFFFFF);
 		tstamp.timestamp = timestamp;
-		pr_debug("%s: bytes_consumed:lsb = %d, msb = %d,"
-			"timestamp = %lld,\n",
-			 __func__, tstamp.rendered, tstamp.decoded,
+		pr_debug("%s: bytes_consumed:,timestamp = %lld,\n",
+						__func__,
 			tstamp.timestamp);
 		if (copy_to_user((void *) arg, &tstamp,
 			sizeof(struct snd_compr_tstamp)))
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h
index 2183690..9830300 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h
@@ -15,7 +15,7 @@
 #define _MSM_COMPR_H
 #include <sound/apr_audio-v2.h>
 #include <sound/q6asm-v2.h>
-#include <sound/snd_compress_params.h>
+#include <sound/compress_params.h>
 #include <sound/compress_offload.h>
 #include <sound/compress_driver.h>
 
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
index ee92753..05ef2ce 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
@@ -27,7 +27,7 @@
 #include <asm/dma.h>
 #include <linux/dma-mapping.h>
 #include <linux/android_pmem.h>
-#include <sound/snd_compress_params.h>
+#include <sound/compress_params.h>
 #include <sound/compress_offload.h>
 #include <sound/compress_driver.h>
 #include <sound/timer.h>
@@ -148,8 +148,7 @@
 			if (runtime->status->hw_ptr >=
 				runtime->control->appl_ptr)
 				break;
-			pr_debug("%s:writing %d bytes"
-				" of buffer to dsp\n",
+			pr_debug("%s:writing %d bytes of buffer to dsp\n",
 				__func__, prtd->pcm_count);
 			buf = prtd->audio_client->port[IN].buf;
 			param.paddr = (unsigned long)buf[prtd->out_head].phys;
@@ -340,8 +339,8 @@
 	if (lpa_audio.prtd && lpa_audio.prtd->audio_client) {
 		rc = q6asm_set_volume(lpa_audio.prtd->audio_client, volume);
 		if (rc < 0) {
-			pr_err("%s: Send Volume command failed"
-					" rc=%d\n", __func__, rc);
+			pr_err("%s: Send Volume command failed rc=%d\n",
+					__func__, rc);
 		}
 	}
 	lpa_audio.volume = volume;
@@ -461,8 +460,8 @@
 			runtime->hw.period_bytes_min,
 			runtime->hw.periods_max);
 	if (ret < 0) {
-		pr_err("Audio Start: Buffer Allocation failed "
-					"rc = %d\n", ret);
+		pr_err("Audio Start: Buffer Allocation failed rc = %d\n",
+						ret);
 		return -ENOMEM;
 	}
 	buf = prtd->audio_client->port[dir].buf;
@@ -509,12 +508,9 @@
 		temp = temp * (runtime->rate/1000);
 		temp = div_u64(temp, 1000);
 		tstamp.sampling_rate = runtime->rate;
-		tstamp.rendered = (size_t)(temp & 0xFFFFFFFF);
-		tstamp.decoded  = (size_t)((temp >> 32) & 0xFFFFFFFF);
 		tstamp.timestamp = timestamp;
-		pr_debug("%s: bytes_consumed:lsb = %d, msb = %d,"
-			"timestamp = %lld,\n",
-			__func__, tstamp.rendered, tstamp.decoded,
+		pr_debug("%s: bytes_consumed:timestamp = %lld,\n",
+					__func__,
 			tstamp.timestamp);
 		if (copy_to_user((void *) arg, &tstamp,
 			sizeof(struct snd_compr_tstamp)))